diff --git a/DEPS b/DEPS index 9a16713e..c8ef7dc0 100644 --- a/DEPS +++ b/DEPS
@@ -297,19 +297,19 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': 'ea4e3c5c837c76c6a52dab712aa9c8420d7d44cc', + 'skia_revision': '53d4265d838bd37bdd0f0a0ff937635cf1ff31cf', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': 'dc4ec1925a168f69b72276e6e480a66298c7fdc2', + 'v8_revision': '425ff17f2d485fb23a7f328e59a39ee9ee5b150c', # 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': 'de5c6c791fa08e24f37e5835770afd727e4ffbae', + 'angle_revision': 'dbfab1595b8a92978e8e5d79cc6dec46f592629d', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. - 'swiftshader_revision': 'dcaef10ef0ada8ce283bb1ebc555e81869c64c52', + 'swiftshader_revision': 'eedcf55ec8534140b8c79fd8a1739a50915d4b31', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. @@ -324,7 +324,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Fuchsia sdk # and whatever else without interference from each other. - 'fuchsia_version': 'version:9.20220804.2.1', + 'fuchsia_version': 'version:9.20220805.1.1', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling google-toolbox-for-mac # and whatever else without interference from each other. @@ -376,7 +376,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': '686631a1ab9f06af2834102cab6d02d4bcbaadc4', + 'devtools_frontend_revision': 'f6d21b7784d50b8fe372491be9d7468db6c784ee', # 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. @@ -412,7 +412,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': 'a8bae0fc04155fa21eb50edca022f3ead6050555', + 'dawn_revision': '127288b742e4ff693b06e80da2e6957f0c09f662', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -440,7 +440,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling nearby # and whatever else without interference from each other. - 'nearby_revision': '5b3d4438150cbd4abefde95a2add15de5f634bfd', + 'nearby_revision': '377dc47c9f2a54ec9b4df7dac3d0419a782f37e3', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling securemessage # and whatever else without interference from each other. @@ -460,7 +460,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. - 'libunwind_revision': 'c5d3129a8b4fd25e0ff8e37dd937830db846c44e', + 'libunwind_revision': '47974e9376bba4f11a790f134160813debbd9da5', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -480,7 +480,7 @@ # If you change this, also update the libc++ revision in # //buildtools/deps_revisions.gni. - 'libcxx_revision': 'e3598c2dc07b5a5320fd3fedb8a4afaa95f09142', + 'libcxx_revision': 'a47a05b6a096e53f529c6cec03915b4a0c0bce2c', # GN CIPD package version. 'gn_version': 'git_revision:c8c63300ac8ecb66d8126af5407257209ae59044', @@ -634,7 +634,7 @@ 'packages': [ { 'package': 'chromium/third_party/updater/chrome_mac_universal', - 'version': 'RBRqNIwSXHjdZf4BVjWk8enaKIHw58aQGFDVNozlbWIC', + 'version': 'jGg_naPD5ghuLToPE3ClG72iDs9GqSPF6M1LM2OhVAwC', }, ], }, @@ -645,7 +645,7 @@ 'packages': [ { 'package': 'chromium/third_party/updater/chrome_win_x86', - 'version': 'tqlS-vFYsn2LVSJMwipq84EKLmwKa1XJb760NnpQL2gC', + 'version': 'SEYmLOH4UqiO4plPuX52Olw1fYjReimhu8AGkSu0o6YC', }, ], }, @@ -656,7 +656,7 @@ 'packages': [ { 'package': 'chromium/third_party/updater/chrome_win_x86_64', - 'version': 'RthX5RzppvSV7uq2P6pm2bnv6-dvoHpUIOsZFk57ZMEC', + 'version': 'DlaEyhCmLI4fzB57R1aWxX9QkHXpbYK4ooGqiNLPX5AC', }, ], }, @@ -668,7 +668,7 @@ 'packages': [ { 'package': 'chromium/third_party/updater/chromium_mac_amd64', - 'version': '7MvxvS-pmZP1iAXQoCiLI7nv4UkDiyw8PC1ycwpYWbYC', + 'version': 'ekvYgaz0Q8adDlksn73Gh-sUisY5m76_4lr_0c1woM0C', }, ], }, @@ -680,7 +680,7 @@ 'packages': [ { 'package': 'chromium/third_party/updater/chromium_mac_arm64', - 'version': 'd5lN7fzV07O4-Mu_T8TshrGQtlR9F508p9cdhchcLpYC', + 'version': 'UEHK7zslk3sVEEqwqnRp9i3kNWbv1PiHuTanLbEU64wC', }, ], }, @@ -691,7 +691,7 @@ 'packages': [ { 'package': 'chromium/third_party/updater/chromium_win_x86', - 'version': '8zehx-DVmaf_FplPe23acLAStf3Z7anQ3CY9LXBfvD0C', + 'version': 'cotzeTxkTmIASM9Gv4ZgbdXS8yJTvhEm8foupSnIEdkC', }, ], }, @@ -702,7 +702,7 @@ 'packages': [ { 'package': 'chromium/third_party/updater/chromium_win_x86_64', - 'version': 'KE8JnjZFOyHxUhVdRkm0IMVqlZIaYPnAOI-zxtUD4zUC', + 'version': 'esNCd2d4_kSQlID8kAeNQDJgiTaXuVJ3oiky_Ma2mFUC', }, ], }, @@ -1174,7 +1174,7 @@ # For Linux and Chromium OS. 'src/third_party/cros_system_api': { - 'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + 'f1a5b3427414e1ce4b83d6eb7b4f363ba62f8579', + 'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + 'e6cbdf1d50a8255dff8e787867dab3a2f95dd1c6', 'condition': 'checkout_linux', }, @@ -1573,7 +1573,7 @@ }, 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + 'cb46e0562e45803eddda778f2b9b9ebd84cc7243', + Var('android_git') + '/platform/external/perfetto.git' + '@' + 'c7072e645ea2540075aa10e3c3caa9f3cc168303', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3', @@ -1607,7 +1607,7 @@ }, 'src/third_party/re2/src': - Var('chromium_git') + '/external/github.com/google/re2.git' + '@' + '9a35e22166dd0ebe67f0ab31773cc1680502bf99', + Var('chromium_git') + '/external/github.com/google/re2.git' + '@' + 'a23f85cae66516b22fd35ba7b8f518133e4b68c4', 'src/third_party/r8': { 'packages': [ @@ -1805,7 +1805,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@eb8d8f22bf7e4e8fe878187a6cbebc914827f687', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@bc5a7e369852020571df26319a487debcbd2fc31', 'condition': 'checkout_src_internal', }, @@ -1857,7 +1857,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/projector_app/app', - 'version': 'x9iF0P771nlZSKaUi-tCbf9YA7zjZw8qg_zUvvOpuysC', + 'version': '2RhTW2BBRrFPnmJ_QJKH74XQxJz8GjrUWae3yd8C1AEC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/PRESUBMIT.py b/PRESUBMIT.py index 28b72d8..3da5147a 100644 --- a/PRESUBMIT.py +++ b/PRESUBMIT.py
@@ -5887,23 +5887,24 @@ source_file_filter = lambda f: input_api.FilterSourceFile( f, files_to_check=files_to_check, files_to_skip=files_to_skip) + # Here we list the classes/methods we're monitoring. For the "fyi" cases, + # we add the CL to the watchlist, but we don't omit a warning or have it be + # included in the triage rotation. # Note that since these are are just regular expressions and we don't have # the compiler's AST, we could have spurious matches (e.g. an unrelated class # could have a method named IsInMainFrame). - concerning_class_pattern = input_api.re.compile( + fyi_concerning_class_pattern = input_api.re.compile( r'WebContentsObserver|WebContentsUserData') # A subset of WebContentsObserver overrides where there's particular risk for # confusing tab and page level operations and data (e.g. incorrectly # resetting page state in DidFinishNavigation). - concerning_wco_methods = [ + fyi_concerning_wco_methods = [ 'DidStartNavigation', 'ReadyToCommitNavigation', 'DidFinishNavigation', 'RenderViewReady', 'RenderViewDeleted', 'RenderViewHostChanged', - 'PrimaryMainDocumentElementAvailable', - 'DocumentOnLoadCompletedInPrimaryMainFrame', 'DOMContentLoaded', 'DidFinishLoad', ] @@ -5913,11 +5914,15 @@ concerning_web_contents_methods = [ 'FromRenderFrameHost', 'FromRenderViewHost', + ] + fyi_concerning_web_contents_methods = [ 'GetRenderViewHost', ] concerning_rfh_methods = [ 'GetParent', 'GetMainFrame', + ] + fyi_concerning_rfh_methods = [ 'GetFrameTreeNodeId', ] concerning_rfhi_methods = [ @@ -5931,35 +5936,50 @@ ] concerning_method_pattern = input_api.re.compile(r'(' + r'|'.join( item for sublist in [ - concerning_wco_methods, concerning_nav_handle_methods, + concerning_nav_handle_methods, concerning_web_contents_methods, concerning_rfh_methods, concerning_rfhi_methods, concerning_ftn_methods, concerning_blink_frame_methods, ] for item in sublist) + r')\(') + fyi_concerning_method_pattern = input_api.re.compile(r'(' + r'|'.join( + item for sublist in [ + fyi_concerning_wco_methods, fyi_concerning_web_contents_methods, + fyi_concerning_rfh_methods, + ] for item in sublist) + r')\(') used_apis = set() + used_fyi_methods = False for f in input_api.AffectedFiles(include_deletes=False, file_filter=source_file_filter): for line_num, line in f.ChangedContents(): - class_match = concerning_class_pattern.search(line) - if class_match: - used_apis.add(class_match[0]) + fyi_class_match = fyi_concerning_class_pattern.search(line) + if fyi_class_match: + used_fyi_methods = True + fyi_method_match = fyi_concerning_method_pattern.search(line) + if fyi_method_match: + used_fyi_methods = True method_match = concerning_method_pattern.search(line) if method_match: used_apis.add(method_match[1]) if not used_apis: + if used_fyi_methods: + output_api.AppendCC('mparch-reviews+watchfyi@chromium.org') + return [] output_api.AppendCC('mparch-reviews+watch@chromium.org') message = ('This change uses API(s) that are ambiguous in the presence of ' 'MPArch features such as bfcache, prerendering, and fenced ' 'frames.') - explaination = ( + explanation = ( 'Please double check whether new code assumes that a WebContents only ' - 'contains a single page at a time. For example, it is discouraged to ' - 'reset per-document state in response to the observation of a ' - 'navigation. See this doc [1] and the comments on the individual APIs ' + 'contains a single page at a time. Notably, checking whether a frame ' + 'is the \"main frame\" is not specific enough to determine whether it ' + 'corresponds to the document reflected in the omnibox. A WebContents ' + 'may have additional main frames for prerendered pages, bfcached ' + 'pages, fenced frames, etc. ' + 'See this doc [1] and the comments on the individual APIs ' 'for guidance and this doc [2] for context. The MPArch review ' 'watchlist has been CC\'d on this change to help identify any issues.\n' '[1] https://docs.google.com/document/d/13l16rWTal3o5wce4i0RwdpMP5ESELLKr439Faj2BBRo/edit?usp=sharing\n' @@ -5968,7 +5988,7 @@ return [ output_api.PresubmitNotifyResult(message, items=list(used_apis), - long_text=explaination) + long_text=explanation) ]
diff --git a/PRESUBMIT_test.py b/PRESUBMIT_test.py index 77052c8..5ea2e87 100755 --- a/PRESUBMIT_test.py +++ b/PRESUBMIT_test.py
@@ -4337,40 +4337,31 @@ class MPArchApiUsage(unittest.TestCase): def _assert_notify( - self, expected_uses, msg, local_path, new_contents): + self, expected_uses, expect_fyi, msg, local_path, new_contents): mock_input_api = MockInputApi() mock_output_api = MockOutputApi() mock_input_api.files = [ MockFile(local_path, new_contents), ] result = PRESUBMIT.CheckMPArchApiUsage(mock_input_api, mock_output_api) + + watchlist_email = ('mparch-reviews+watchfyi@chromium.org' + if expect_fyi else 'mparch-reviews+watch@chromium.org') self.assertEqual( - bool(expected_uses), - 'mparch-reviews+watch@chromium.org' in mock_output_api.more_cc, + bool(expected_uses or expect_fyi), + watchlist_email in mock_output_api.more_cc, msg) if expected_uses: self.assertEqual(1, len(result), msg) self.assertEqual(result[0].type, 'notify', msg) self.assertEqual(sorted(result[0].items), sorted(expected_uses), msg) + else: + self.assertEqual(0, len(result), msg) def testNotify(self): self._assert_notify( - ['WebContentsObserver', 'WebContentsUserData'], - 'Introduce WCO and WCUD', - 'chrome/my_feature.h', - ['class MyFeature', - ' : public content::WebContentsObserver,', - ' public content::WebContentsUserData<MyFeature> {};', - ]) - self._assert_notify( - ['DidFinishNavigation'], - 'Introduce WCO override', - 'chrome/my_feature.h', - ['void DidFinishNavigation(', - ' content::NavigationHandle* navigation_handle) override;', - ]) - self._assert_notify( ['IsInMainFrame'], + False, 'Introduce IsInMainFrame', 'chrome/my_feature.cc', ['void DoSomething(content::NavigationHandle* navigation_handle) {', @@ -4380,6 +4371,7 @@ ]) self._assert_notify( ['FromRenderFrameHost'], + False, 'Introduce WC::FromRenderFrameHost', 'chrome/my_feature.cc', ['void DoSomething(content::RenderFrameHost* rfh) {', @@ -4388,9 +4380,29 @@ '}', ]) + def testFyi(self): + self._assert_notify( + [], + True, + 'Introduce WCO and WCUD', + 'chrome/my_feature.h', + ['class MyFeature', + ' : public content::WebContentsObserver,', + ' public content::WebContentsUserData<MyFeature> {};', + ]) + self._assert_notify( + [], + True, + 'Introduce WCO override', + 'chrome/my_feature.h', + ['void DidFinishNavigation(', + ' content::NavigationHandle* navigation_handle) override;', + ]) + def testNoNotify(self): self._assert_notify( [], + False, 'No API usage', 'chrome/my_feature.cc', ['void DoSomething() {', @@ -4401,6 +4413,7 @@ # to share a name with a content API. self._assert_notify( [], + False, 'Uninteresting top level directory', 'third_party/my_dep/my_code.cc', ['bool HasParent(Node* node) {', @@ -4410,10 +4423,11 @@ # We're not concerned with usage in test code. self._assert_notify( [], + False, 'Usage in test code', 'chrome/my_feature_unittest.cc', ['TEST_F(MyFeatureTest, DoesSomething) {', - ' EXPECT_TRUE(web_contents()->GetMainFrame());', + ' EXPECT_TRUE(rfh()->GetMainFrame());', '}', ])
diff --git a/android_webview/browser/aw_browser_context.cc b/android_webview/browser/aw_browser_context.cc index 0fdeccb..be9ffb45 100644 --- a/android_webview/browser/aw_browser_context.cc +++ b/android_webview/browser/aw_browser_context.cc
@@ -310,7 +310,7 @@ } user_pref_service_->Set(cdm::prefs::kMediaDrmStorage, - *(local_state->Get(cdm::prefs::kMediaDrmStorage))); + local_state->GetValue(cdm::prefs::kMediaDrmStorage)); local_state->ClearPref(cdm::prefs::kMediaDrmStorage); }
diff --git a/android_webview/browser/metrics/aw_metrics_service_client.cc b/android_webview/browser/metrics/aw_metrics_service_client.cc index 356c4402f..d29165a 100644 --- a/android_webview/browser/metrics/aw_metrics_service_client.cc +++ b/android_webview/browser/metrics/aw_metrics_service_client.cc
@@ -170,7 +170,7 @@ PrefService* local_state = pref_service(); DCHECK(local_state); cached_package_name_record_ = AppPackageNameLoggingRule::FromDictionary( - *(local_state->Get(prefs::kMetricsAppPackageNameLoggingRule))); + local_state->GetValue(prefs::kMetricsAppPackageNameLoggingRule)); if (cached_package_name_record_.has_value()) { package_name_record_status_ = AppPackageNameLoggingRuleStatus::kNotLoadedUseCache;
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java index 85ae69f..57a3f24 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwContents.java +++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -863,10 +863,15 @@ } }; - private static class AwWindowCoverageTracker { + /** + * Tracks and reports the percentage of coverage of AwContents on the root view. + */ + @VisibleForTesting + public static class AwWindowCoverageTracker { private static final long RECALCULATION_DELAY_MS = 200; - private static final HashMap<View, AwWindowCoverageTracker> sWindowCoverageTrackers = + @VisibleForTesting + public static final Map<View, AwWindowCoverageTracker> sWindowCoverageTrackers = new HashMap<>(); private final View mRootView; @@ -895,21 +900,20 @@ return tracker; } - public boolean trackContents(AwContents contents) { + public void trackContents(AwContents contents) { contents.mAwWindowCoverageTracker = this; - return mAwContentsList.add(contents); + mAwContentsList.add(contents); } - public boolean untrackContents(AwContents contents) { + public void untrackContents(AwContents contents) { contents.mAwWindowCoverageTracker = null; + mAwContentsList.remove(contents); - // If that was the last AwContents, remove ourselves from the static list. + // If that was the last AwContents, remove ourselves from the static map. if (!isTracking()) { if (TRACE) Log.i(TAG, "%s removing " + this, contents); sWindowCoverageTrackers.remove(mRootView); } - - return mAwContentsList.remove(contents); } private boolean isTracking() { @@ -980,7 +984,8 @@ // protective copy. Rect contentRect = new Rect(content.getGlobalVisibleRect()); - // If the intersect method returns true then it has modified contentRect. + // If the intersect method returns true then it may have modified + // contentRect. A Rect with area 0 will not intersect with anything. if (contentRect.intersect(rootVisibleRect)) { contentRects.add(contentRect); schemes.add(AwContentsJni.get().getScheme(content.mNativeAwContents));
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwMetricsIntegrationTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwMetricsIntegrationTest.java index e930243e..794b03a 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/AwMetricsIntegrationTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwMetricsIntegrationTest.java
@@ -570,6 +570,14 @@ RecordHistogram.getHistogramValueCountForTesting(histogramName, 0); Assert.assertNotEquals("There should be at least one sample in a non-zero bucket", zeroBucketSamples, totalSamples); + + TestThreadUtils.runOnUiThreadBlocking(() -> { + Assert.assertEquals( + 1, AwContents.AwWindowCoverageTracker.sWindowCoverageTrackers.size()); + mAwContents.onDetachedFromWindow(); + Assert.assertEquals( + 0, AwContents.AwWindowCoverageTracker.sWindowCoverageTrackers.size()); + }); } finally { embeddedTestServer.stopAndDestroyServer(); }
diff --git a/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebViewChromiumFactory.java b/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebViewChromiumFactory.java index 1ad63938..bf96ec9e 100644 --- a/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebViewChromiumFactory.java +++ b/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebViewChromiumFactory.java
@@ -87,7 +87,7 @@ Features.REQUESTED_WITH_HEADER_CONTROL + Features.DEV_SUFFIX, Features.GET_VARIATIONS_HEADER, Features.ALGORITHMIC_DARKENING, - Features.ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY + Features.DEV_SUFFIX, + Features.ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY, // Add new features above. New features must include `+ Features.DEV_SUFFIX` // when they're initially added (this can be removed in a future CL). The final // feature should have a trailing comma for cleaner diffs.
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index b1334e7..9c4dfbe 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -1559,6 +1559,8 @@ "system/privacy_hub/camera_privacy_switch_controller.h", "system/privacy_hub/microphone_privacy_switch_controller.cc", "system/privacy_hub/microphone_privacy_switch_controller.h", + "system/privacy_hub/privacy_hub_controller.cc", + "system/privacy_hub/privacy_hub_controller.h", "system/privacy_screen/privacy_screen_feature_pod_controller.cc", "system/privacy_screen/privacy_screen_feature_pod_controller.h", "system/privacy_screen/privacy_screen_toast_controller.cc",
diff --git a/ash/components/arc/property/arc_property_bridge_unittest.cc b/ash/components/arc/property/arc_property_bridge_unittest.cc index 7560000..8a91d25 100644 --- a/ash/components/arc/property/arc_property_bridge_unittest.cc +++ b/ash/components/arc/property/arc_property_bridge_unittest.cc
@@ -9,7 +9,7 @@ #include "ash/components/arc/session/arc_bridge_service.h" #include "ash/components/arc/test/connection_holder_util.h" #include "base/metrics/field_trial.h" -#include "base/test/scoped_field_trial_list_resetter.h" +#include "base/test/scoped_feature_list.h" #include "testing/gtest/include/gtest/gtest.h" namespace arc { @@ -53,15 +53,11 @@ ArcPropertyBridgeTest& operator=(const ArcPropertyBridgeTest&) = delete; void SetUp() override { - trial_list_resetter_ = - std::make_unique<base::test::ScopedFieldTrialListResetter>(); - trial_list_ = std::make_unique<base::FieldTrialList>(nullptr); + scoped_feature_list_ = std::make_unique<base::test::ScopedFeatureList>(); + scoped_feature_list_->InitWithEmptyFeatureAndFieldTrialLists(); } - void TearDown() override { - trial_list_ = nullptr; - trial_list_resetter_ = nullptr; - } + void TearDown() override { scoped_feature_list_.reset(); } void CreatePropertyInstance() { instance_ = std::make_unique<FakePropertyInstance>(); @@ -85,9 +81,7 @@ std::unique_ptr<ArcPropertyBridge> property_bridge_; std::unique_ptr<FakePropertyInstance> instance_; - std::unique_ptr<base::test::ScopedFieldTrialListResetter> - trial_list_resetter_; - std::unique_ptr<base::FieldTrialList> trial_list_; + std::unique_ptr<base::test::ScopedFeatureList> scoped_feature_list_; }; TEST_F(ArcPropertyBridgeTest, MinimizeOnBackButtonDefault) {
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc index ba3c8e6..fc10ae7 100644 --- a/ash/constants/ash_features.cc +++ b/ash/constants/ash_features.cc
@@ -680,10 +680,6 @@ const base::Feature kExoOrdinalMotion{"ExoOrdinalMotion", base::FEATURE_DISABLED_BY_DEFAULT}; -// Enable or disable pointer lock for Crostini and Borealis windows. -const base::Feature kExoPointerLock{"ExoPointerLock", - base::FEATURE_ENABLED_BY_DEFAULT}; - // Allows RGB Keyboard to test new animations/patterns. const base::Feature kExperimentalRgbKeyboardPatterns{ "ExperimentalRgbKeyboardPatterns", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h index 81a18bc..cbf5520 100644 --- a/ash/constants/ash_features.h +++ b/ash/constants/ash_features.h
@@ -291,7 +291,6 @@ extern const base::Feature kExoHapticFeedbackSupport; COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kExoLockNotification; COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kExoOrdinalMotion; -COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kExoPointerLock; COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kExperimentalRgbKeyboardPatterns; COMPONENT_EXPORT(ASH_CONSTANTS)
diff --git a/ash/shell.cc b/ash/shell.cc index bb840af..edf21e7 100644 --- a/ash/shell.cc +++ b/ash/shell.cc
@@ -144,8 +144,7 @@ #include "ash/system/power/power_prefs.h" #include "ash/system/power/power_status.h" #include "ash/system/power/video_activity_notifier.h" -#include "ash/system/privacy_hub/camera_privacy_switch_controller.h" -#include "ash/system/privacy_hub/microphone_privacy_switch_controller.h" +#include "ash/system/privacy_hub/privacy_hub_controller.h" #include "ash/system/screen_layout_observer.h" #include "ash/system/screen_security/screen_switch_check_controller.h" #include "ash/system/session/logout_confirmation_controller.h" @@ -629,7 +628,7 @@ hud_display::HUDDisplayView::Destroy(); // Observes `SessionController` and must be destroyed before it. - camera_privacy_switch_controller_.reset(); + privacy_hub_controller_.reset(); for (auto& observer : shell_observers_) observer.OnShellDestroying(); @@ -840,9 +839,6 @@ // controller. dark_light_mode_controller_.reset(); - // Observes `SessionController` and must be destroyed before it. - microphone_privacy_switch_controller_.reset(); - // These members access Shell in their destructors. wallpaper_controller_.reset(); accessibility_controller_.reset(); @@ -1001,11 +997,7 @@ // These controllers call Shell::Get() in their constructors, so they cannot // be in the member initialization list. - // Privacy hub controllers. - // TODO(b/239400029): Move this to the unified privacy hub controller - // after it is created. - camera_privacy_switch_controller_ = - std::make_unique<CameraPrivacySwitchController>(); + privacy_hub_controller_ = std::make_unique<PrivacyHubController>(); touch_devices_controller_ = std::make_unique<TouchDevicesController>(); if (!ash::features::IsBluetoothRevampEnabled()) { bluetooth_power_controller_ = @@ -1050,9 +1042,6 @@ std::make_unique<SnoopingProtectionController>(); } - microphone_privacy_switch_controller_ = - std::make_unique<MicrophonePrivacySwitchController>(); - // Manages lifetime of DiagnosticApp logs. if (features::IsLogControllerForDiagnosticsAppEnabled()) { diagnostics_log_controller_ =
diff --git a/ash/shell.h b/ash/shell.h index d6570b6..51ca95d 100644 --- a/ash/shell.h +++ b/ash/shell.h
@@ -103,7 +103,6 @@ class BluetoothPowerController; class BrightnessControlDelegate; class CalendarController; -class CameraPrivacySwitchController; class CaptureModeController; class ControlVHistogramRecorder; class CrosDisplayConfig; @@ -155,7 +154,6 @@ class MediaControllerImpl; class MessageCenterAshImpl; class MessageCenterController; -class MicrophonePrivacySwitchController; class MouseCursorEventFilter; class MruWindowTracker; class MultiDeviceNotificationPresenter; @@ -179,6 +177,7 @@ class PowerButtonController; class PowerEventObserver; class PowerPrefs; +class PrivacyHubController; class PrivacyScreenController; class ProjectingObserver; class ProjectorControllerImpl; @@ -384,9 +383,6 @@ CalendarController* calendar_controller() { return calendar_controller_.get(); } - CameraPrivacySwitchController* camera_privacy_switch_controller() { - return camera_privacy_switch_controller_.get(); - } CrosDisplayConfig* cros_display_config() { return cros_display_config_.get(); } @@ -512,9 +508,6 @@ MessageCenterController* message_center_controller() { return message_center_controller_.get(); } - MicrophonePrivacySwitchController* microphone_privacy_switch_controller() { - return microphone_privacy_switch_controller_.get(); - } MouseCursorEventFilter* mouse_cursor_filter() { return mouse_cursor_filter_.get(); } @@ -550,6 +543,9 @@ PowerEventObserver* power_event_observer() { return power_event_observer_.get(); } + PrivacyHubController* privacy_hub_controller() { + return privacy_hub_controller_.get(); + } PrivacyScreenController* privacy_screen_controller() { return privacy_screen_controller_.get(); } @@ -802,8 +798,6 @@ std::unique_ptr<BacklightsForcedOffSetter> backlights_forced_off_setter_; std::unique_ptr<BrightnessControlDelegate> brightness_control_delegate_; std::unique_ptr<CalendarController> calendar_controller_; - std::unique_ptr<CameraPrivacySwitchController> - camera_privacy_switch_controller_; std::unique_ptr<CrosDisplayConfig> cros_display_config_; std::unique_ptr<DarkLightModeControllerImpl> dark_light_mode_controller_; std::unique_ptr<DesksController> desks_controller_; @@ -853,6 +847,7 @@ std::unique_ptr<ParentAccessController> parent_access_controller_; std::unique_ptr<PciePeripheralNotificationController> pcie_peripheral_notification_controller_; + std::unique_ptr<PrivacyHubController> privacy_hub_controller_; std::unique_ptr<UsbPeripheralNotificationController> usb_peripheral_notification_controller_; std::unique_ptr<PersistentDesksBarController> @@ -987,12 +982,6 @@ std::unique_ptr<chromeos::SnapController> snap_controller_; - // Privacy hub controllers. - // TODO(b/239400029): Move this to the unified privacy hub controller after it - // is created. - std::unique_ptr<MicrophonePrivacySwitchController> - microphone_privacy_switch_controller_; - // |native_cursor_manager_| is owned by |cursor_manager_|, but we keep a // pointer to vend to test code. NativeCursorManagerAsh* native_cursor_manager_;
diff --git a/ash/system/accessibility/floating_accessibility_controller_unittest.cc b/ash/system/accessibility/floating_accessibility_controller_unittest.cc index 9721a005..21398abe 100644 --- a/ash/system/accessibility/floating_accessibility_controller_unittest.cc +++ b/ash/system/accessibility/floating_accessibility_controller_unittest.cc
@@ -18,6 +18,7 @@ #include "base/callback.h" #include "base/callback_helpers.h" #include "base/strings/stringprintf.h" +#include "base/test/scoped_feature_list.h" namespace ash { @@ -113,6 +114,25 @@ } }; +TEST_F(FloatingAccessibilityControllerTest, ImeButtonNotShowWhenDisabled) { + SetUpVisibleMenu(); + + views::View* button = + GetMenuButton(FloatingAccessibilityView::ButtonId::kIme); + EXPECT_FALSE(button); +} + +TEST_F(FloatingAccessibilityControllerTest, ImeButtonShowWhenEnabled) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(features::kKioskEnableImeButton); + EXPECT_TRUE(base::FeatureList::IsEnabled(features::kKioskEnableImeButton)); + SetUpVisibleMenu(); + + views::View* button = + GetMenuButton(FloatingAccessibilityView::ButtonId::kIme); + EXPECT_TRUE(button); +} + TEST_F(FloatingAccessibilityControllerTest, MenuIsNotShownWhenNotEnabled) { accessibility_controller()->ShowFloatingMenuIfEnabled(); EXPECT_EQ(controller(), nullptr);
diff --git a/ash/system/accessibility/floating_accessibility_view.cc b/ash/system/accessibility/floating_accessibility_view.cc index 12c66ed..590c13a 100644 --- a/ash/system/accessibility/floating_accessibility_view.cc +++ b/ash/system/accessibility/floating_accessibility_view.cc
@@ -9,6 +9,7 @@ #include "ash/public/cpp/system_tray.h" #include "ash/resources/vector_icons/vector_icons.h" #include "ash/root_window_controller.h" +#include "ash/session/session_controller_impl.h" #include "ash/shelf/shelf.h" #include "ash/shell.h" #include "ash/strings/grit/ash_strings.h" @@ -25,6 +26,7 @@ #include "ui/views/border.h" #include "ui/views/controls/separator.h" #include "ui/views/layout/box_layout.h" +#include "ui/views/view.h" namespace ash { @@ -92,7 +94,8 @@ } bool IsKioskImeButtonEnabled() { - return base::FeatureList::IsEnabled(features::kKioskEnableImeButton); + return Shell::Get()->session_controller()->IsRunningInAppMode() && + base::FeatureList::IsEnabled(features::kKioskEnableImeButton); } } // namespace @@ -157,8 +160,19 @@ kAutoclickPositionBottomLeftIcon, IDS_ASH_AUTOCLICK_OPTION_CHANGE_POSITION, /*flip_for_rtl*/ false, kPanelPositionButtonSize, false, /* is_a11y_togglable */ false)); + if (IsKioskImeButtonEnabled()) { - // TODO(b/240928038): Add logic in following CLs. + std::unique_ptr<views::View> ime_button_container = + CreateButtonRowContainer(kUnifiedTopShortcutSpacing); + ime_button_ = + ime_button_container->AddChildView(std::make_unique<FloatingMenuButton>( + base::BindRepeating(&FloatingAccessibilityView::OnImeButtonPressed, + base::Unretained(this)), + kShelfGlobeIcon, IDS_ASH_STATUS_TRAY_IME, + /*flip_for_rtl*/ true)); + + AddChildView(std::move(ime_button_container)); + AddChildView(CreateSeparator()); } AddChildView(std::move(feature_buttons_container)); AddChildView(std::move(tray_button_container)); @@ -171,6 +185,9 @@ dictation_button_->SetID(static_cast<int>(ButtonId::kDictation)); select_to_speak_button_->SetID(static_cast<int>(ButtonId::kSelectToSpeak)); virtual_keyboard_button_->SetID(static_cast<int>(ButtonId::kVirtualKeyboard)); + if (IsKioskImeButtonEnabled()) { + ime_button_->SetID(static_cast<int>(ButtonId::kIme)); + } } FloatingAccessibilityView::~FloatingAccessibilityView() {} @@ -248,6 +265,10 @@ GetDescriptionForMovedToPosition(new_position)); } +void FloatingAccessibilityView::OnImeButtonPressed() { + ime_button_->SetToggled(!ime_button_->GetToggled()); +} + void FloatingAccessibilityView::OnViewVisibilityChanged( views::View* observed_view, views::View* starting_view) {
diff --git a/ash/system/accessibility/floating_accessibility_view.h b/ash/system/accessibility/floating_accessibility_view.h index 6c308ce..7ad560c 100644 --- a/ash/system/accessibility/floating_accessibility_view.h +++ b/ash/system/accessibility/floating_accessibility_view.h
@@ -58,6 +58,7 @@ kDictation = 3, kSelectToSpeak = 4, kVirtualKeyboard = 5, + kIme = 6, }; class Delegate { public: @@ -87,6 +88,7 @@ private: void OnA11yTrayButtonPressed(); void OnPositionButtonPressed(); + void OnImeButtonPressed(); // views::ViewObserver: void OnViewVisibilityChanged(views::View* observed_view, @@ -100,6 +102,8 @@ FloatingMenuButton* a11y_tray_button_ = nullptr; // Button to move the view around corners. FloatingMenuButton* position_button_ = nullptr; + // Button to list all available keyboard languages. + FloatingMenuButton* ime_button_ = nullptr; Delegate* const delegate_; };
diff --git a/ash/system/privacy_hub/camera_privacy_switch_controller.cc b/ash/system/privacy_hub/camera_privacy_switch_controller.cc index 6a3a57f8..fe991ec 100644 --- a/ash/system/privacy_hub/camera_privacy_switch_controller.cc +++ b/ash/system/privacy_hub/camera_privacy_switch_controller.cc
@@ -80,6 +80,7 @@ CameraPrivacySwitchController::GetUserSwitchPreference() { const bool allowed = pref_change_registrar_->prefs()->GetBoolean(prefs::kUserCameraAllowed); + return allowed ? CameraSWPrivacySwitchSetting::kEnabled : CameraSWPrivacySwitchSetting::kDisabled; };
diff --git a/ash/system/privacy_hub/camera_privacy_switch_controller_unittest.cc b/ash/system/privacy_hub/camera_privacy_switch_controller_unittest.cc index 55f8303..8b6febe 100644 --- a/ash/system/privacy_hub/camera_privacy_switch_controller_unittest.cc +++ b/ash/system/privacy_hub/camera_privacy_switch_controller_unittest.cc
@@ -10,6 +10,7 @@ #include "ash/constants/ash_pref_names.h" #include "ash/session/session_controller_impl.h" #include "ash/shell.h" +#include "ash/system/privacy_hub/privacy_hub_controller.h" #include "ash/test/ash_test_base.h" #include "components/prefs/pref_change_registrar.h" #include "components/prefs/pref_service.h" @@ -42,7 +43,8 @@ auto mock_switch = std::make_unique<::testing::NiceMock<MockSwitchAPI>>(); mock_switch_ = mock_switch.get(); - controller_ = Shell::Get()->camera_privacy_switch_controller(); + controller_ = + Shell::Get()->privacy_hub_controller()->CameraControllerForTest(); controller_->SetCameraPrivacySwitchAPIForTest(std::move(mock_switch)); }
diff --git a/ash/system/privacy_hub/microphone_privacy_switch_controller.cc b/ash/system/privacy_hub/microphone_privacy_switch_controller.cc index 5d239e6..aed238b 100644 --- a/ash/system/privacy_hub/microphone_privacy_switch_controller.cc +++ b/ash/system/privacy_hub/microphone_privacy_switch_controller.cc
@@ -36,7 +36,6 @@ base::BindRepeating( &MicrophonePrivacySwitchController::OnPreferenceChanged, base::Unretained(this))); - // Manually set the system input mute state to the value of the user // preference when creating the controller during the browser initialization // after creating the user profile. @@ -44,17 +43,17 @@ } void MicrophonePrivacySwitchController::OnInputMuteChanged(bool mute_on) { - // `pref_change_registrar_` is only initialized after a user logs in. If - // OnInputMuteChanged is called when `pref_change_registrar_` is null, we - // should simply ignore those events. - if (pref_change_registrar_ == nullptr) + // `pref_change_registrar_` is only initialized after a user logs in. + if (pref_change_registrar_ == nullptr) { return; + } + + PrefService* prefs = pref_change_registrar_->prefs(); + DCHECK(prefs); const bool microphone_allowed = !mute_on; - if (pref_change_registrar_->prefs()->GetBoolean( - prefs::kUserMicrophoneAllowed) != microphone_allowed) { - pref_change_registrar_->prefs()->SetBoolean(prefs::kUserMicrophoneAllowed, - microphone_allowed); + if (prefs->GetBoolean(prefs::kUserMicrophoneAllowed) != microphone_allowed) { + prefs->SetBoolean(prefs::kUserMicrophoneAllowed, microphone_allowed); } } @@ -63,6 +62,8 @@ } void MicrophonePrivacySwitchController::SetSystemMute() { + DCHECK(pref_change_registrar_); + const bool microphone_allowed = pref_change_registrar_->prefs()->GetBoolean( prefs::kUserMicrophoneAllowed); const bool microphone_muted = !microphone_allowed;
diff --git a/ash/system/privacy_hub/microphone_privacy_switch_controller.h b/ash/system/privacy_hub/microphone_privacy_switch_controller.h index 5661b2f4..4125bc90 100644 --- a/ash/system/privacy_hub/microphone_privacy_switch_controller.h +++ b/ash/system/privacy_hub/microphone_privacy_switch_controller.h
@@ -7,6 +7,7 @@ #include <memory> +#include "ash/ash_export.h" #include "ash/components/audio/cras_audio_handler.h" #include "ash/public/cpp/session/session_observer.h" #include "components/prefs/pref_change_registrar.h" @@ -15,9 +16,9 @@ // This controller keeps the KUserMicrophoneAllowed preference and the state of // the system input mute in sync. -class MicrophonePrivacySwitchController - : public SessionObserver, - public CrasAudioHandler::AudioObserver { +class ASH_EXPORT MicrophonePrivacySwitchController + : public CrasAudioHandler::AudioObserver, + public SessionObserver { public: MicrophonePrivacySwitchController(); ~MicrophonePrivacySwitchController() override;
diff --git a/ash/system/privacy_hub/privacy_hub_controller.cc b/ash/system/privacy_hub/privacy_hub_controller.cc new file mode 100644 index 0000000..179d59a --- /dev/null +++ b/ash/system/privacy_hub/privacy_hub_controller.cc
@@ -0,0 +1,13 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/system/privacy_hub/privacy_hub_controller.h" + +namespace ash { + +PrivacyHubController::PrivacyHubController() = default; + +PrivacyHubController::~PrivacyHubController() = default; + +} // namespace ash
diff --git a/ash/system/privacy_hub/privacy_hub_controller.h b/ash/system/privacy_hub/privacy_hub_controller.h new file mode 100644 index 0000000..f7c8e3b --- /dev/null +++ b/ash/system/privacy_hub/privacy_hub_controller.h
@@ -0,0 +1,34 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_SYSTEM_PRIVACY_HUB_PRIVACY_HUB_CONTROLLER_H_ +#define ASH_SYSTEM_PRIVACY_HUB_PRIVACY_HUB_CONTROLLER_H_ + +#include "ash/ash_export.h" +#include "ash/system/privacy_hub/camera_privacy_switch_controller.h" +#include "ash/system/privacy_hub/microphone_privacy_switch_controller.h" + +namespace ash { + +class ASH_EXPORT PrivacyHubController { + public: + PrivacyHubController(); + + PrivacyHubController(const PrivacyHubController&) = delete; + PrivacyHubController& operator=(const PrivacyHubController&) = delete; + + ~PrivacyHubController(); + + CameraPrivacySwitchController* CameraControllerForTest() { + return &camera_controller_; + } + + private: + CameraPrivacySwitchController camera_controller_; + MicrophonePrivacySwitchController microphone_controller_; +}; + +} // namespace ash + +#endif // ASH_SYSTEM_PRIVACY_HUB_PRIVACY_HUB_CONTROLLER_H_
diff --git a/ash/webui/camera_app_ui/resources/js/custom_effect.ts b/ash/webui/camera_app_ui/resources/js/custom_effect.ts index c1574ae8e5..5c56f350 100644 --- a/ash/webui/camera_app_ui/resources/js/custom_effect.ts +++ b/ash/webui/camera_app_ui/resources/js/custom_effect.ts
@@ -8,6 +8,7 @@ import {I18nString} from './i18n_string.js'; import * as loadTimeData from './models/load_time_data.js'; import {ChromeHelper} from './mojo/chrome_helper.js'; +import {speakMessage} from './spoken_msg.js'; import * as state from './state.js'; import * as util from './util.js'; @@ -205,6 +206,7 @@ protected readonly anchor: HTMLElement, protected readonly template: DocumentFragment, protected readonly toast: HTMLDivElement, + protected readonly message: string, protected readonly positionInfos: PositionInfos) { this.cancelHandle = setInterval(() => { updatePositions(anchor, positionInfos); @@ -214,6 +216,7 @@ show(): void { document.body.appendChild(this.template); + speakMessage(this.message); } focus(): void { @@ -245,7 +248,7 @@ loadTimeData.getI18nMessage(I18nString.NEW_CONTROL_NAVIGATION, text); toast.setAttribute('aria-label', ariaLabel); - super(anchor, template, toast, [{ + super(anchor, template, toast, text, [{ target: toast, properties: getOffsetProperties(anchor, 'toast'), }]); @@ -276,7 +279,7 @@ const indicatorDot = dom.getFrom(template, '#indicator-dot', HTMLDivElement); - super(anchor, template, toast, [ + super(anchor, template, toast, text, [ { target: toast, properties: getOffsetProperties(anchor, 'toast'),
diff --git a/ash/webui/camera_app_ui/resources/js/spoken_msg.ts b/ash/webui/camera_app_ui/resources/js/spoken_msg.ts index 6258a2a..18af23883 100644 --- a/ash/webui/camera_app_ui/resources/js/spoken_msg.ts +++ b/ash/webui/camera_app_ui/resources/js/spoken_msg.ts
@@ -13,9 +13,18 @@ * @param substitutions The substitutions needed for the given label. */ export function speak(label: I18nString, ...substitutions: string[]): void { + speakMessage(loadTimeData.getI18nMessage(label, ...substitutions)); +} + +/** + * Speaks a message. + * + * @param message The message to speak. + */ +export function speakMessage(message: string): void { // TTS speaks changes of on-screen aria-live elements. Force content changes // and clear content once inactive to avoid stale content being read out. const element = dom.get('#spoken_msg', HTMLElement); element.textContent = ''; // Force reiterate the same message for a11y. - element.textContent = loadTimeData.getI18nMessage(label, ...substitutions); + element.textContent = message; }
diff --git a/base/BUILD.gn b/base/BUILD.gn index 1d915f55..de7ba75 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn
@@ -190,10 +190,17 @@ "allocator/allocator_check.h", "allocator/allocator_extension.cc", "allocator/allocator_extension.h", + "allocator/dispatcher/configuration.h", "allocator/dispatcher/dispatcher.cc", "allocator/dispatcher/dispatcher.h", + "allocator/dispatcher/initializer.h", + "allocator/dispatcher/internal/dispatch_data.cc", + "allocator/dispatcher/internal/dispatch_data.h", + "allocator/dispatcher/internal/dispatcher_internal.h", + "allocator/dispatcher/internal/tools.h", "allocator/dispatcher/reentry_guard.cc", "allocator/dispatcher/reentry_guard.h", + "allocator/dispatcher/subsystem.h", "as_const.h", "at_exit.cc", "at_exit.h", @@ -3043,6 +3050,13 @@ test("base_unittests") { sources = [ + "allocator/dispatcher/dispatcher_unittest.cc", + "allocator/dispatcher/initializer_unittest.cc", + "allocator/dispatcher/internal/dispatcher_internal_unittest.cc", + "allocator/dispatcher/testing/dispatcher_test.cc", + "allocator/dispatcher/testing/dispatcher_test.h", + "allocator/dispatcher/testing/observer_mock.h", + "allocator/dispatcher/testing/tools.h", "as_const_unittest.cc", "at_exit_unittest.cc", "atomicops_unittest.cc",
diff --git a/base/allocator/dispatcher/configuration.h b/base/allocator/dispatcher/configuration.h new file mode 100644 index 0000000..089d3a6 --- /dev/null +++ b/base/allocator/dispatcher/configuration.h
@@ -0,0 +1,24 @@ +// Copyright (c) 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_ALLOCATOR_DISPATCHER_CONFIGURATION_H_ +#define BASE_ALLOCATOR_DISPATCHER_CONFIGURATION_H_ + +#include <cstddef> + +namespace base::allocator::dispatcher::configuration { + +// The maximum number of optional observers that may be present depending on +// command line parameters. +constexpr size_t kMaximumNumberOfOptionalObservers = 4; + +// The total number of observers including mandatory and optional observers. +// Primarily the number of observers affects the performance at allocation time. +// The current value of 4 doesn't have hard evidence. Keep in mind that +// also a single observer can severely impact performance. +constexpr size_t kMaximumNumberOfObservers = 4; + +} // namespace base::allocator::dispatcher::configuration + +#endif // BASE_ALLOCATOR_DISPATCHER_CONFIGURATION_H_ \ No newline at end of file
diff --git a/base/allocator/dispatcher/dispatcher.cc b/base/allocator/dispatcher/dispatcher.cc index 8cf5cc2..9a99878 100644 --- a/base/allocator/dispatcher/dispatcher.cc +++ b/base/allocator/dispatcher/dispatcher.cc
@@ -6,10 +6,18 @@ #include "base/allocator/allocator_shim.h" #include "base/allocator/buildflags.h" +#include "base/allocator/dispatcher/internal/dispatch_data.h" #include "base/allocator/dispatcher/reentry_guard.h" #include "base/allocator/partition_allocator/partition_alloc.h" +#include "base/check.h" +#include "base/dcheck_is_on.h" +#include "base/no_destructor.h" #include "base/sampling_heap_profiler/poisson_allocation_sampler.h" +#if DCHECK_IS_ON() +#include <atomic> +#endif + #if BUILDFLAG(USE_ALLOCATOR_SHIM) namespace base::allocator::dispatcher::allocator_shim_details { namespace { @@ -236,4 +244,93 @@ #endif } +} // namespace base::allocator::dispatcher + +namespace base::allocator::dispatcher { + +// The private implementation of Dispatcher. +struct Dispatcher::Impl { + void Initialize(const internal::DispatchData& dispatch_data) { +#if DCHECK_IS_ON() + DCHECK(!is_initialized_check_flag_.test_and_set()); +#endif + + dispatch_data_ = dispatch_data; + ConnectToEmitters(dispatch_data_); + } + + void Reset() { +#if DCHECK_IS_ON() + DCHECK([&]() { + auto const was_set = is_initialized_check_flag_.test(); + is_initialized_check_flag_.clear(); + return was_set; + }()); +#endif + + DisconnectFromEmitters(dispatch_data_); + dispatch_data_ = {}; + } + + private: + // Connect the hooks to the memory subsystem. In some cases, most notably when + // we have no observers at all, the hooks will be invalid and must NOT be + // connected. This way we prevent notifications although no observers are + // present. + static void ConnectToEmitters(const internal::DispatchData& dispatch_data) { +#if BUILDFLAG(USE_ALLOCATOR_SHIM) + if (auto* const allocator_dispatch = dispatch_data.GetAllocatorDispatch()) { + allocator::InsertAllocatorDispatch(allocator_dispatch); + } +#endif + +#if BUILDFLAG(USE_PARTITION_ALLOC) + { + auto* const allocation_hook = dispatch_data.GetAllocationObserverHook(); + auto* const free_hook = dispatch_data.GetFreeObserverHook(); + if (allocation_hook && free_hook) { + partition_alloc::PartitionAllocHooks::SetObserverHooks(allocation_hook, + free_hook); + } + } +#endif + } + + static void DisconnectFromEmitters(internal::DispatchData& dispatch_data) { +#if BUILDFLAG(USE_ALLOCATOR_SHIM) + if (auto* const allocator_dispatch = dispatch_data.GetAllocatorDispatch()) { + allocator::RemoveAllocatorDispatchForTesting( + allocator_dispatch); // IN-TEST + } +#endif + +#if BUILDFLAG(USE_PARTITION_ALLOC) + partition_alloc::PartitionAllocHooks::SetObserverHooks(nullptr, nullptr); +#endif + } + + // Information on the hooks. + internal::DispatchData dispatch_data_; +#if DCHECK_IS_ON() + // Indicator if the dispatcher has been initialized before. + std::atomic_flag is_initialized_check_flag_ = ATOMIC_FLAG_INIT; +#endif +}; + +Dispatcher::Dispatcher() : impl_(std::make_unique<Impl>()) {} + +Dispatcher::~Dispatcher() = default; + +Dispatcher& Dispatcher::GetInstance() { + static base::NoDestructor<Dispatcher> instance; + return *instance; +} + +void Dispatcher::Initialize(const internal::DispatchData& dispatch_data) { + impl_->Initialize(dispatch_data); +} + +void Dispatcher::ResetForTesting() { + impl_->Reset(); +} } // namespace base::allocator::dispatcher \ No newline at end of file
diff --git a/base/allocator/dispatcher/dispatcher.h b/base/allocator/dispatcher/dispatcher.h index f12a6b2..e4ef8d7c 100644 --- a/base/allocator/dispatcher/dispatcher.h +++ b/base/allocator/dispatcher/dispatcher.h
@@ -5,13 +5,74 @@ #ifndef BASE_ALLOCATOR_DISPATCHER_DISPATCHER_H_ #define BASE_ALLOCATOR_DISPATCHER_DISPATCHER_H_ +#include "base/allocator/dispatcher/internal/dispatcher_internal.h" #include "base/base_export.h" +#include <memory> + namespace base::allocator::dispatcher { void BASE_EXPORT InstallStandardAllocatorHooks(); void BASE_EXPORT RemoveStandardAllocatorHooksForTesting(); +namespace internal { +struct DispatchData; +} + +// Dispatcher serves as the top level instance for managing the dispatch +// mechanism. The class instance manages connections to the various memory +// subsystems such as PartitionAlloc. To keep the public interface as lean as +// possible it uses a pimpl pattern. +class BASE_EXPORT Dispatcher { + public: + static Dispatcher& GetInstance(); + + Dispatcher(); + + // Initialize the dispatch mechanism with the given tuple of observers. The + // observers must be valid (it is only DCHECKed internally at initialization, + // but not verified further) + // If Initialize is called multiple times, the first one wins. All later + // invocations are silently ignored. Initialization is protected from + // concurrent invocations. In case of concurrent accesses, the first one to + // get the lock wins. + // The dispatcher invokes following functions on the observers: + // void OnAllocation(void* address, + // size_t size, + // AllocationSubsystem sub_system, + // const char* type_name); + // void OnFree(void* address); + // + // Note: The dispatcher mechanism does NOT bring systematic protection against + // recursive invocations. That is, observers which allocate memory on the + // heap, i.e. through dynamically allocated containers or by using the + // CHECK-macro, are responsible to break these recursions! + template <typename... ObserverTypes> + void Initialize(const std::tuple<ObserverTypes...>& observers) { + // Get the hooks for running these observers and pass them to further + // initialization + Initialize(internal::GetNotificationHooks(observers)); + } + + // The following functions provide an interface to setup and tear down the + // dispatcher when testing. This must NOT be used from production code since + // the hooks cannot be removed reliably under all circumstances. + template <typename ObserverType> + void InitializeForTesting(ObserverType* observer) { + Initialize(std::make_tuple(observer)); + } + + void ResetForTesting(); + + private: + // structure and pointer to the private implementation. + struct Impl; + std::unique_ptr<Impl> const impl_; + + ~Dispatcher(); + + void Initialize(const internal::DispatchData& dispatch_data); +}; } // namespace base::allocator::dispatcher #endif // BASE_ALLOCATOR_DISPATCHER_DISPATCHER_H_ \ No newline at end of file
diff --git a/base/allocator/dispatcher/dispatcher_unittest.cc b/base/allocator/dispatcher/dispatcher_unittest.cc new file mode 100644 index 0000000..c5cc153 --- /dev/null +++ b/base/allocator/dispatcher/dispatcher_unittest.cc
@@ -0,0 +1,138 @@ +// Copyright (c) 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "testing/gtest/include/gtest/gtest.h" + +#include "base/allocator/buildflags.h" +#include "base/allocator/dispatcher/configuration.h" +#include "base/allocator/dispatcher/dispatcher.h" +#include "base/allocator/dispatcher/testing/dispatcher_test.h" +#include "base/allocator/dispatcher/testing/tools.h" +#include "build/build_config.h" + +#if BUILDFLAG(USE_PARTITION_ALLOC) +#include "base/allocator/partition_allocator/partition_alloc.h" +#endif + +#if BUILDFLAG(USE_ALLOCATOR_SHIM) +#include "base/allocator/allocator_shim.h" +#endif + +#include <tuple> + +namespace base::allocator::dispatcher { +namespace { +using configuration::kMaximumNumberOfObservers; +using configuration::kMaximumNumberOfOptionalObservers; +using partition_alloc::PartitionOptions; +using partition_alloc::ThreadSafePartitionRoot; +using testing::DispatcherTest; + +// A simple observer implementation. Since these tests plug in to Partition +// Allocator and Allocator Shim, implementing an observer with Google Mock +// results in endless recursion. +struct ObserverMock { + void OnAllocation(void* address, + size_t size, + AllocationSubsystem sub_system, + const char* type_name) { + ++on_allocation_calls_; + } + void OnFree(void* address) { ++on_free_calls_; } + + void Reset() { + on_allocation_calls_ = 0; + on_free_calls_ = 0; + } + + size_t GetNumberOnAllocationCalls() const { return on_allocation_calls_; } + size_t GetNumberOnFreeCalls() const { return on_free_calls_; } + + private: + size_t on_allocation_calls_ = 0; + size_t on_free_calls_ = 0; +}; + +struct DispatcherInitializerGuard { + template <typename... Observers> + explicit DispatcherInitializerGuard(std::tuple<Observers*...> observers) { + Dispatcher::GetInstance().Initialize(observers); + } + + ~DispatcherInitializerGuard() { Dispatcher::GetInstance().ResetForTesting(); } +}; + +struct BaseAllocatorDispatcherTest : public DispatcherTest {}; + +template <typename A> +void DoBasicTest(A& allocator) { + // All we want to verify is that the Dispatcher correctly hooks into the + // passed allocator. Therefore, we do not perform an exhaustive test but + // just check some basics. + std::array<ObserverMock, kMaximumNumberOfObservers> observers; + + { + DispatcherInitializerGuard const g( + testing::CreateTupleOfPointers(observers)); + + constexpr size_t size_to_allocate = 1024; + void* const ptr = allocator.Alloc(size_to_allocate); + allocator.Free(ptr); + } + + for (const auto& mock : observers) { + EXPECT_GE(mock.GetNumberOnAllocationCalls(), 1u); + EXPECT_GE(mock.GetNumberOnFreeCalls(), 1u); + } +} + +TEST_F(BaseAllocatorDispatcherTest, VerifyInitialization) { + std::array<ObserverMock, kMaximumNumberOfObservers> observers; + + DispatcherInitializerGuard g(testing::CreateTupleOfPointers(observers)); +} + +#if BUILDFLAG(USE_PARTITION_ALLOC) && !defined(MEMORY_TOOL_REPLACES_ALLOCATOR) +// Don't enable this test when MEMORY_TOOL_REPLACES_ALLOCATOR is defined, +// because it makes PartitionAlloc take a different path that doesn't provide +// notifications to observer hooks. +struct PartitionAllocator { + void* Alloc(size_t size) { return alloc_.AllocWithFlags(0, size, nullptr); } + void Free(void* data) { alloc_.Free(data); } + + private: + ThreadSafePartitionRoot alloc_{{ + PartitionOptions::AlignedAlloc::kDisallowed, + PartitionOptions::ThreadCache::kDisabled, + PartitionOptions::Quarantine::kDisallowed, + PartitionOptions::Cookie::kAllowed, + PartitionOptions::BackupRefPtr::kDisabled, + PartitionOptions::BackupRefPtrZapping::kDisabled, + PartitionOptions::UseConfigurablePool::kNo, + }}; +}; + +TEST_F(BaseAllocatorDispatcherTest, VerifyNotificationUsingPartitionAllocator) { + PartitionAllocator allocator; + DoBasicTest(allocator); +} +#endif + +#if BUILDFLAG(USE_ALLOCATOR_SHIM) && !BUILDFLAG(IS_IOS) +// Don't enable this test when compiling for iOS. For some yet unknown reason +// the test crashes on iOS due to invalid malloc zone. It is yet unclear whether +// this is an incomplete setup or a bug. +struct AllocatorShimAllocator { + void* Alloc(size_t size) { return base::allocator::UncheckedAlloc(size); } + void Free(void* data) { base::allocator::UncheckedFree(data); } +}; + +TEST_F(BaseAllocatorDispatcherTest, VerifyNotificationUsingAllocatorShim) { + AllocatorShimAllocator allocator; + DoBasicTest(allocator); +} +#endif + +} // namespace +} // namespace base::allocator::dispatcher \ No newline at end of file
diff --git a/base/allocator/dispatcher/initializer.h b/base/allocator/dispatcher/initializer.h new file mode 100644 index 0000000..b298815 --- /dev/null +++ b/base/allocator/dispatcher/initializer.h
@@ -0,0 +1,206 @@ +// Copyright (c) 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_ALLOCATOR_DISPATCHER_INITIALIZER_H_ +#define BASE_ALLOCATOR_DISPATCHER_INITIALIZER_H_ + +#include "base/allocator/dispatcher/configuration.h" +#include "base/allocator/dispatcher/dispatcher.h" +#include "base/allocator/dispatcher/internal/tools.h" + +#include <tuple> +#include <utility> + +namespace base::allocator::dispatcher { +namespace internal { + +// Filter the passed observers and perform initialization of the passed +// dispatcher. +template <size_t CurrentIndex, + typename DispatcherType, + typename CheckObserverPredicate, + typename VerifiedObservers, + typename UnverifiedObservers, + size_t... IndicesToSelect> +inline void DoInitialize(DispatcherType& dispatcher, + CheckObserverPredicate check_observer, + const VerifiedObservers& verified_observers, + const UnverifiedObservers& unverified_observers, + std::index_sequence<IndicesToSelect...> indices) { + if constexpr (CurrentIndex < std::tuple_size<UnverifiedObservers>::value) { + // We still have some items left to handle. + if (check_observer(std::get<CurrentIndex>(unverified_observers))) { + // The current observer is valid. Hence, append the index of the current + // item to the set of indices and head on to the next item. + DoInitialize<CurrentIndex + 1>( + dispatcher, check_observer, verified_observers, unverified_observers, + std::index_sequence<IndicesToSelect..., CurrentIndex>{}); + } else { + // The current observer is not valid. Hence, head on to the next item with + // an unaltered list of indices. + DoInitialize<CurrentIndex + 1>(dispatcher, check_observer, + verified_observers, unverified_observers, + indices); + } + } else if constexpr (CurrentIndex == + std::tuple_size<UnverifiedObservers>::value) { + // So we have met the end of the tuple of observers to verify. + // Hence, we extract the additional valid observers, append to the tuple of + // already verified observers and hand over to the dispatcher. + auto observers = std::tuple_cat( + verified_observers, + std::make_tuple(std::get<IndicesToSelect>(unverified_observers)...)); + + // Do a final check that neither the maximum total number of observers nor + // the maximum number of optional observers is exceeded. + static_assert(std::tuple_size<decltype(observers)>::value <= + configuration::kMaximumNumberOfObservers); + static_assert(sizeof...(IndicesToSelect) <= + configuration::kMaximumNumberOfOptionalObservers); + + dispatcher.Initialize(std::move(observers)); + } +} + +} // namespace internal + +// The result of concatenating two tuple-types. +template <typename... tuples> +using TupleCat = decltype(std::tuple_cat(std::declval<tuples>()...)); + +// Initializer collects mandatory and optional observers and initializes the +// passed Dispatcher with only the enabled observers. +// +// In some situations, presence of observers depends on runtime. i.e. command +// line parameters or CPU features. With 3 optional observers we already have 8 +// different combinations. Initializer takes the job of dealing with all +// combinations from the user. It allows users to pass all observers (including +// nullptr for disabled optional observers) and initializes the Dispatcher with +// only the enabled observers. +// +// Since this process results in a combinatoric explosion, Initializer +// distinguishes between optional and mandatory observers. Mandatory observers +// are not included in the filtering process and must always be enabled (not +// nullptr). +// +// To allow the Initializer to track the number and exact type of observers, it +// is implemented as a templated class which holds information on the types in +// the std::tuples passed as template parameters. Therefore, whenever any type +// observer it set, the initializer changes its type to reflect this. +template <typename MandatoryObservers = std::tuple<>, + typename OptionalObservers = std::tuple<>> +struct BASE_EXPORT Initializer { + Initializer() = default; + Initializer(MandatoryObservers mandatory_observers, + OptionalObservers optional_observers) + : mandatory_observers_(std::move(mandatory_observers)), + optional_observers_(std::move(optional_observers)) {} + + // Set the mandatory observers. The number of observers that can be set is + // limited by configuration::maximum_number_of_observers. + template <typename... NewMandatoryObservers, + std::enable_if_t< + internal::LessEqual((sizeof...(NewMandatoryObservers) + + std::tuple_size<OptionalObservers>::value), + configuration::kMaximumNumberOfObservers), + bool> = true> + Initializer<std::tuple<NewMandatoryObservers*...>, OptionalObservers> + SetMandatoryObservers(NewMandatoryObservers*... mandatory_observers) const { + return {std::make_tuple(mandatory_observers...), GetOptionalObservers()}; + } + + // Add mandatory observers. The number of observers that can be added is + // limited by the current number of observers, see + // configuration::maximum_number_of_observers. + template <typename... AdditionalMandatoryObservers, + std::enable_if_t<internal::LessEqual( + std::tuple_size<MandatoryObservers>::value + + sizeof...(AdditionalMandatoryObservers) + + std::tuple_size<OptionalObservers>::value, + configuration::kMaximumNumberOfObservers), + bool> = true> + Initializer<TupleCat<MandatoryObservers, + std::tuple<AdditionalMandatoryObservers*...>>, + OptionalObservers> + AddMandatoryObservers( + AdditionalMandatoryObservers*... additional_mandatory_observers) const { + return {std::tuple_cat(GetMandatoryObservers(), + std::make_tuple(additional_mandatory_observers...)), + GetOptionalObservers()}; + } + + // Set the optional observers. The number of observers that can be set is + // limited by configuration::maximum_number_of_optional_observers as well as + // configuration::maximum_number_of_observers. + template < + typename... NewOptionalObservers, + std::enable_if_t< + internal::LessEqual( + sizeof...(NewOptionalObservers), + configuration::kMaximumNumberOfOptionalObservers) && + internal::LessEqual((sizeof...(NewOptionalObservers) + + std::tuple_size<MandatoryObservers>::value), + configuration::kMaximumNumberOfObservers), + bool> = true> + Initializer<MandatoryObservers, std::tuple<NewOptionalObservers*...>> + SetOptionalObservers(NewOptionalObservers*... optional_observers) const { + return {GetMandatoryObservers(), std::make_tuple(optional_observers...)}; + } + + // Add optional observers. The number of observers that can be added is + // limited by the current number of optional observers, + // configuration::maximum_number_of_optional_observers as well as + // configuration::maximum_number_of_observers. + template < + typename... AdditionalOptionalObservers, + std::enable_if_t< + internal::LessEqual( + std::tuple_size<OptionalObservers>::value + + sizeof...(AdditionalOptionalObservers), + configuration::kMaximumNumberOfOptionalObservers) && + internal::LessEqual((std::tuple_size<OptionalObservers>::value + + sizeof...(AdditionalOptionalObservers) + + std::tuple_size<MandatoryObservers>::value), + configuration::kMaximumNumberOfObservers), + bool> = true> + Initializer< + MandatoryObservers, + TupleCat<OptionalObservers, std::tuple<AdditionalOptionalObservers*...>>> + AddOptionalObservers( + AdditionalOptionalObservers*... additional_optional_observers) const { + return {GetMandatoryObservers(), + std::tuple_cat(GetOptionalObservers(), + std::make_tuple(additional_optional_observers...))}; + } + + // Perform the actual initialization on the passed dispatcher. + // The dispatcher is passed as a template only to provide better testability. + template <typename DispatcherType> + void DoInitialize(DispatcherType& dispatcher) const { + internal::DoInitialize<0>(dispatcher, internal::IsValidObserver{}, + GetMandatoryObservers(), GetOptionalObservers(), + {}); + } + + const MandatoryObservers& GetMandatoryObservers() const { + return mandatory_observers_; + } + + const OptionalObservers& GetOptionalObservers() const { + return optional_observers_; + } + + private: + MandatoryObservers mandatory_observers_; + OptionalObservers optional_observers_; +}; + +// Convenience function for creating an empty Initializer. +inline Initializer<> CreateInitializer() { + return {}; +} + +} // namespace base::allocator::dispatcher + +#endif // BASE_ALLOCATOR_DISPATCHER_INITIALIZER_H_ \ No newline at end of file
diff --git a/base/allocator/dispatcher/initializer_unittest.cc b/base/allocator/dispatcher/initializer_unittest.cc new file mode 100644 index 0000000..cd43ed1 --- /dev/null +++ b/base/allocator/dispatcher/initializer_unittest.cc
@@ -0,0 +1,235 @@ +// Copyright (c) 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "testing/gtest/include/gtest/gtest.h" + +#include "base/allocator/dispatcher/configuration.h" +#include "base/allocator/dispatcher/initializer.h" +#include "base/allocator/dispatcher/testing/observer_mock.h" +#include "base/allocator/dispatcher/testing/tools.h" + +#include <functional> +#include <map> +#include <tuple> + +namespace base::allocator::dispatcher { +namespace testing { + +// A mock Dispatcher for testing. Since Initializer and Dispatcher rely on +// templating, we can't employ GoogleMocks for mocking. The mock dispatcher +// records the number of invocations of Initialize for a given tuple of +// observers. +struct Dispatcher { + Dispatcher() = default; + + ~Dispatcher() { + for (const auto& reset_data : reseter_) { + reset_data.second(); + } + } + + template <typename... Observers> + void Initialize(const std::tuple<Observers*...>& observers) { + ++total_number_of_inits_; + ++(GetInitCounterForObservers(observers)); + } + + size_t GetTotalInitCounter() const { return total_number_of_inits_; } + + template <typename... Observers> + size_t& GetInitCounterForObservers( + const std::tuple<Observers*...>& observers) { + static std::map<std::tuple<Observers*...>, size_t> + observer_init_counter_map; + reseter_[&observer_init_counter_map] = []() { + observer_init_counter_map.clear(); + }; + return observer_init_counter_map[observers]; + } + + size_t total_number_of_inits_ = 0; + std::map<void*, std::function<void()>> reseter_; +}; +} // namespace testing + +using testing::ObserverMock; + +struct BaseAllocatorDispatcherInitializerTest : public ::testing::Test {}; + +TEST_F(BaseAllocatorDispatcherInitializerTest, VerifyEmptyInitializer) { + const auto initializer = CreateInitializer(); + + EXPECT_EQ(initializer.GetOptionalObservers(), std::make_tuple()); + EXPECT_EQ(initializer.GetMandatoryObservers(), std::make_tuple()); +} + +TEST_F(BaseAllocatorDispatcherInitializerTest, VerifySettingOptionalObservers) { + ObserverMock<int> optional_observer_1; + ObserverMock<float> optional_observer_2; + ObserverMock<size_t> optional_observer_3; + + auto initializer_1 = CreateInitializer().SetOptionalObservers( + &optional_observer_1, &optional_observer_2); + EXPECT_EQ(initializer_1.GetOptionalObservers(), + std::make_tuple(&optional_observer_1, &optional_observer_2)); + EXPECT_EQ(initializer_1.GetMandatoryObservers(), std::make_tuple()); + + auto initializer_2 = initializer_1.SetOptionalObservers(&optional_observer_3); + EXPECT_EQ(initializer_2.GetOptionalObservers(), + std::make_tuple(&optional_observer_3)); + EXPECT_EQ(initializer_2.GetMandatoryObservers(), std::make_tuple()); + + auto initializer_3 = initializer_2.SetOptionalObservers(); + EXPECT_EQ(initializer_3.GetOptionalObservers(), std::make_tuple()); + EXPECT_EQ(initializer_3.GetMandatoryObservers(), std::make_tuple()); +} + +TEST_F(BaseAllocatorDispatcherInitializerTest, VerifyAddingOptionalObservers) { + ObserverMock<int> optional_observer_1; + ObserverMock<float> optional_observer_2; + ObserverMock<size_t> optional_observer_3; + + auto initializer_1 = CreateInitializer().AddOptionalObservers( + &optional_observer_1, &optional_observer_2); + EXPECT_EQ(initializer_1.GetOptionalObservers(), + std::make_tuple(&optional_observer_1, &optional_observer_2)); + EXPECT_EQ(initializer_1.GetMandatoryObservers(), std::make_tuple()); + + auto initializer_2 = initializer_1.AddOptionalObservers(&optional_observer_3); + EXPECT_EQ(initializer_2.GetOptionalObservers(), + std::make_tuple(&optional_observer_1, &optional_observer_2, + &optional_observer_3)); + EXPECT_EQ(initializer_2.GetMandatoryObservers(), std::make_tuple()); + + auto initializer_3 = initializer_2.AddOptionalObservers(); + EXPECT_EQ(initializer_3.GetOptionalObservers(), + std::make_tuple(&optional_observer_1, &optional_observer_2, + &optional_observer_3)); + EXPECT_EQ(initializer_3.GetMandatoryObservers(), std::make_tuple()); + + auto initializer_4 = initializer_3.SetOptionalObservers(); + EXPECT_EQ(initializer_4.GetOptionalObservers(), std::make_tuple()); + EXPECT_EQ(initializer_4.GetMandatoryObservers(), std::make_tuple()); +} + +TEST_F(BaseAllocatorDispatcherInitializerTest, + VerifySettingMandatoryObservers) { + ObserverMock<int> mandatory_observer_1; + ObserverMock<float> mandatory_observer_2; + ObserverMock<size_t> mandatory_observer_3; + + auto initializer_1 = CreateInitializer().SetMandatoryObservers( + &mandatory_observer_1, &mandatory_observer_2); + EXPECT_EQ(initializer_1.GetMandatoryObservers(), + std::make_tuple(&mandatory_observer_1, &mandatory_observer_2)); + EXPECT_EQ(initializer_1.GetOptionalObservers(), std::make_tuple()); + + auto initializer_2 = + initializer_1.SetMandatoryObservers(&mandatory_observer_3); + EXPECT_EQ(initializer_2.GetMandatoryObservers(), + std::make_tuple(&mandatory_observer_3)); + EXPECT_EQ(initializer_2.GetOptionalObservers(), std::make_tuple()); + + auto initializer_3 = initializer_2.SetMandatoryObservers(); + EXPECT_EQ(initializer_3.GetMandatoryObservers(), std::make_tuple()); + EXPECT_EQ(initializer_3.GetOptionalObservers(), std::make_tuple()); +} + +TEST_F(BaseAllocatorDispatcherInitializerTest, VerifyAddingMandatoryObservers) { + ObserverMock<int> mandatory_observer_1; + ObserverMock<float> mandatory_observer_2; + ObserverMock<size_t> mandatory_observer_3; + + auto initializer_1 = CreateInitializer().AddMandatoryObservers( + &mandatory_observer_1, &mandatory_observer_2); + EXPECT_EQ(initializer_1.GetMandatoryObservers(), + std::make_tuple(&mandatory_observer_1, &mandatory_observer_2)); + EXPECT_EQ(initializer_1.GetOptionalObservers(), std::make_tuple()); + + auto initializer_2 = + initializer_1.AddMandatoryObservers(&mandatory_observer_3); + EXPECT_EQ(initializer_2.GetMandatoryObservers(), + std::make_tuple(&mandatory_observer_1, &mandatory_observer_2, + &mandatory_observer_3)); + EXPECT_EQ(initializer_2.GetOptionalObservers(), std::make_tuple()); + + auto initializer_3 = initializer_2.AddMandatoryObservers(); + EXPECT_EQ(initializer_3.GetMandatoryObservers(), + std::make_tuple(&mandatory_observer_1, &mandatory_observer_2, + &mandatory_observer_3)); + EXPECT_EQ(initializer_3.GetOptionalObservers(), std::make_tuple()); + + auto initializer_4 = initializer_3.SetMandatoryObservers(); + EXPECT_EQ(initializer_4.GetMandatoryObservers(), std::make_tuple()); + EXPECT_EQ(initializer_4.GetOptionalObservers(), std::make_tuple()); +} + +TEST_F(BaseAllocatorDispatcherInitializerTest, VerifyBasicInitialization) { + ObserverMock<int> optional_observer_1; + ObserverMock<float> optional_observer_2; + ObserverMock<size_t> mandatory_observer_1; + ObserverMock<double> mandatory_observer_2; + + testing::Dispatcher test_dispatcher; + + CreateInitializer() + .SetMandatoryObservers(&mandatory_observer_1, &mandatory_observer_2) + .SetOptionalObservers(&optional_observer_1, &optional_observer_2) + .DoInitialize(test_dispatcher); + + const auto observer_ptrs = + std::make_tuple(&mandatory_observer_1, &mandatory_observer_2, + &optional_observer_1, &optional_observer_2); + + EXPECT_EQ(1ul, test_dispatcher.GetInitCounterForObservers(observer_ptrs)); +} + +TEST_F(BaseAllocatorDispatcherInitializerTest, + VerifyInitializationWithMandatoryNullObservers) { + ObserverMock<int> optional_observer_1; + ObserverMock<float> optional_observer_2; + ObserverMock<size_t> mandatory_observer; + ObserverMock<double>* mandatory_null_observer = nullptr; + + testing::Dispatcher test_dispatcher; + + CreateInitializer() + .SetMandatoryObservers(&mandatory_observer, mandatory_null_observer) + .SetOptionalObservers(&optional_observer_1, &optional_observer_2) + .DoInitialize(test_dispatcher); + + // For mandatory observers being null we expect them to be passed straight + // down to the dispatcher, which will then perform a check of ALL observers. + const auto valid_observer_ptrs = + std::make_tuple(&mandatory_observer, mandatory_null_observer, + &optional_observer_1, &optional_observer_2); + + EXPECT_EQ(1ul, test_dispatcher.GetTotalInitCounter()); + EXPECT_EQ(1ul, + test_dispatcher.GetInitCounterForObservers(valid_observer_ptrs)); +} + +TEST_F(BaseAllocatorDispatcherInitializerTest, + VerifyInitializationWithOptionalNullObservers) { + ObserverMock<int> optional_observer; + ObserverMock<float>* optional_null_observer = nullptr; + ObserverMock<size_t> mandatory_observer_1; + ObserverMock<double> mandatory_observer_2; + + testing::Dispatcher test_dispatcher; + + CreateInitializer() + .SetMandatoryObservers(&mandatory_observer_1, &mandatory_observer_2) + .SetOptionalObservers(&optional_observer, optional_null_observer) + .DoInitialize(test_dispatcher); + + const auto valid_observer_ptrs = std::make_tuple( + &mandatory_observer_1, &mandatory_observer_2, &optional_observer); + + EXPECT_EQ(1ul, test_dispatcher.GetTotalInitCounter()); + EXPECT_EQ(1ul, + test_dispatcher.GetInitCounterForObservers(valid_observer_ptrs)); +} + +} // namespace base::allocator::dispatcher \ No newline at end of file
diff --git a/base/allocator/dispatcher/internal/dispatch_data.cc b/base/allocator/dispatcher/internal/dispatch_data.cc new file mode 100644 index 0000000..317b9fb --- /dev/null +++ b/base/allocator/dispatcher/internal/dispatch_data.cc
@@ -0,0 +1,41 @@ +// Copyright (c) 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/allocator/dispatcher/internal/dispatch_data.h" + +namespace base::allocator::dispatcher::internal { + +#if BUILDFLAG(USE_PARTITION_ALLOC) + +DispatchData& DispatchData::SetAllocationObserverHooks( + AllocationObserverHook* allocation_observer_hook, + FreeObserverHook* free_observer_hook) { + allocation_observer_hook_ = allocation_observer_hook; + free_observer_hook_ = free_observer_hook; + + return *this; +} + +DispatchData::AllocationObserverHook* DispatchData::GetAllocationObserverHook() + const { + return allocation_observer_hook_; +} + +DispatchData::FreeObserverHook* DispatchData::GetFreeObserverHook() const { + return free_observer_hook_; +} +#endif + +#if BUILDFLAG(USE_ALLOCATOR_SHIM) +DispatchData& DispatchData::SetAllocatorDispatch( + AllocatorDispatch* allocator_dispatch) { + allocator_dispatch_ = allocator_dispatch; + return *this; +} + +AllocatorDispatch* DispatchData::GetAllocatorDispatch() const { + return allocator_dispatch_; +} +#endif +} // namespace base::allocator::dispatcher::internal
diff --git a/base/allocator/dispatcher/internal/dispatch_data.h b/base/allocator/dispatcher/internal/dispatch_data.h new file mode 100644 index 0000000..f724090 --- /dev/null +++ b/base/allocator/dispatcher/internal/dispatch_data.h
@@ -0,0 +1,54 @@ +// Copyright (c) 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_ALLOCATOR_DISPATCHER_INTERNAL_DISPATCH_DATA_H_ +#define BASE_ALLOCATOR_DISPATCHER_INTERNAL_DISPATCH_DATA_H_ + +#include "base/allocator/buildflags.h" +#include "base/base_export.h" +#include "build/build_config.h" + +#if BUILDFLAG(USE_PARTITION_ALLOC) +#include "base/allocator/partition_allocator/partition_alloc.h" +#endif + +#if BUILDFLAG(USE_ALLOCATOR_SHIM) +#include "base/allocator/allocator_shim.h" +#endif + +namespace base::allocator::dispatcher::internal { + +// A simple utility class to pass all the information required to properly hook +// into the memory allocation subsystems from DispatcherImpl to the Dispatcher. +struct BASE_EXPORT DispatchData { +#if BUILDFLAG(USE_PARTITION_ALLOC) + using AllocationObserverHook = + partition_alloc::PartitionAllocHooks::AllocationObserverHook; + using FreeObserverHook = + partition_alloc::PartitionAllocHooks::FreeObserverHook; + + DispatchData& SetAllocationObserverHooks(AllocationObserverHook*, + FreeObserverHook*); + AllocationObserverHook* GetAllocationObserverHook() const; + FreeObserverHook* GetFreeObserverHook() const; + + private: + AllocationObserverHook* allocation_observer_hook_ = nullptr; + FreeObserverHook* free_observer_hook_ = nullptr; + + public: +#endif + +#if BUILDFLAG(USE_ALLOCATOR_SHIM) + DispatchData& SetAllocatorDispatch(AllocatorDispatch* allocator_dispatch); + AllocatorDispatch* GetAllocatorDispatch() const; + + private: + AllocatorDispatch* allocator_dispatch_ = nullptr; +#endif +}; + +} // namespace base::allocator::dispatcher::internal + +#endif \ No newline at end of file
diff --git a/base/allocator/dispatcher/internal/dispatcher_internal.h b/base/allocator/dispatcher/internal/dispatcher_internal.h new file mode 100644 index 0000000..7351ec6b --- /dev/null +++ b/base/allocator/dispatcher/internal/dispatcher_internal.h
@@ -0,0 +1,351 @@ +// Copyright (c) 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_ALLOCATOR_DISPATCHER_INTERNAL_DISPATCHER_INTERNAL_H_ +#define BASE_ALLOCATOR_DISPATCHER_INTERNAL_DISPATCHER_INTERNAL_H_ + +#include "base/allocator/buildflags.h" +#include "base/allocator/dispatcher/configuration.h" +#include "base/allocator/dispatcher/internal/dispatch_data.h" +#include "base/allocator/dispatcher/internal/tools.h" +#include "base/allocator/dispatcher/reentry_guard.h" +#include "base/allocator/dispatcher/subsystem.h" +#include "base/compiler_specific.h" +#include "build/build_config.h" + +#if BUILDFLAG(USE_PARTITION_ALLOC) +#include "base/allocator/partition_allocator/partition_alloc.h" +#endif + +#if BUILDFLAG(USE_ALLOCATOR_SHIM) +#include "base/allocator/allocator_shim.h" +#endif + +#include <tuple> + +namespace base::allocator::dispatcher::internal { + +template <typename CheckObserverPredicate, + typename... ObserverTypes, + size_t... Indices> +void inline PerformObserverCheck(const std::tuple<ObserverTypes...>& observers, + std::index_sequence<Indices...>, + CheckObserverPredicate check_observer) { + ((DCHECK(check_observer(std::get<Indices>(observers)))), ...); +} + +template <typename... ObserverTypes, size_t... Indices> +ALWAYS_INLINE void PerformAllocationNotification( + const std::tuple<ObserverTypes...>& observers, + std::index_sequence<Indices...>, + void* address, + size_t size, + AllocationSubsystem subSystem, + const char* type_name) { + ((std::get<Indices>(observers)->OnAllocation(address, size, subSystem, + type_name)), + ...); +} + +template <typename... ObserverTypes, size_t... Indices> +ALWAYS_INLINE void PerformFreeNotification( + const std::tuple<ObserverTypes...>& observers, + std::index_sequence<Indices...>, + void* address) { + ((std::get<Indices>(observers)->OnFree(address)), ...); +} + +// DispatcherImpl provides hooks into the various memory subsystems. These hooks +// are responsible for dispatching any notification to the observers. +// In order to provide as many information on the exact type of the observer and +// prevent any conditional jumps in the hot allocation path, observers are +// stored in a std::tuple. DispatcherImpl performs a CHECK at initialization +// time to ensure they are valid. +template <typename... ObserverTypes> +struct DispatcherImpl { + using AllObservers = std::index_sequence_for<ObserverTypes...>; + + template <std::enable_if_t< + internal::LessEqual(sizeof...(ObserverTypes), + configuration::kMaximumNumberOfObservers), + bool> = true> + static DispatchData GetNotificationHooks( + std::tuple<ObserverTypes*...> observers) { + s_observers = std::move(observers); + + PerformObserverCheck(s_observers, AllObservers{}, IsValidObserver{}); + + return CreateDispatchData(); + } + + private: + static DispatchData CreateDispatchData() { + return DispatchData() +#if BUILDFLAG(USE_PARTITION_ALLOC) + .SetAllocationObserverHooks(&PartitionAllocatorAllocationHook, + &PartitionAllocatorFreeHook) +#endif +#if BUILDFLAG(USE_ALLOCATOR_SHIM) + .SetAllocatorDispatch(&allocator_dispatch_) +#endif + ; + } + +#if BUILDFLAG(USE_PARTITION_ALLOC) + static void PartitionAllocatorAllocationHook(void* address, + size_t size, + const char* type_name) { + DoNotifyAllocation(address, size, AllocationSubsystem::kPartitionAllocator, + type_name); + } + + static void PartitionAllocatorFreeHook(void* address) { + DoNotifyFree(address); + } +#endif + +#if BUILDFLAG(USE_ALLOCATOR_SHIM) + static void* AllocFn(const AllocatorDispatch* self, + size_t size, + void* context) { + ReentryGuard guard; + void* const address = self->next->alloc_function(self->next, size, context); + if (LIKELY(guard)) { + DoNotifyAllocation(address, size, AllocationSubsystem::kAllocatorShim); + } + return address; + } + + static void* AllocUncheckedFn(const AllocatorDispatch* self, + size_t size, + void* context) { + ReentryGuard guard; + void* const address = + self->next->alloc_unchecked_function(self->next, size, context); + if (LIKELY(guard)) { + DoNotifyAllocation(address, size, AllocationSubsystem::kAllocatorShim); + } + return address; + } + + static void* AllocZeroInitializedFn(const AllocatorDispatch* self, + size_t n, + size_t size, + void* context) { + ReentryGuard guard; + void* const address = self->next->alloc_zero_initialized_function( + self->next, n, size, context); + if (LIKELY(guard)) { + DoNotifyAllocation(address, n * size, + AllocationSubsystem::kAllocatorShim); + } + return address; + } + + static void* AllocAlignedFn(const AllocatorDispatch* self, + size_t alignment, + size_t size, + void* context) { + ReentryGuard guard; + void* const address = self->next->alloc_aligned_function( + self->next, alignment, size, context); + if (LIKELY(guard)) { + DoNotifyAllocation(address, size, AllocationSubsystem::kAllocatorShim); + } + return address; + } + + static void* ReallocFn(const AllocatorDispatch* self, + void* address, + size_t size, + void* context) { + ReentryGuard guard; + // Note: size == 0 actually performs free. + // Note: ReentryGuard prevents from recursions introduced by malloc and + // initialization of thread local storage which happen in the allocation + // path only (please see docs of ReentryGuard for full details). Therefore, + // the DoNotifyFree doesn't need to be guarded. Instead, making it unguarded + // also ensures proper notification. + DoNotifyFree(address); + void* const reallocated_address = + self->next->realloc_function(self->next, address, size, context); + if (LIKELY(guard)) { + DoNotifyAllocation(reallocated_address, size, + AllocationSubsystem::kAllocatorShim); + } + return reallocated_address; + } + + static void FreeFn(const AllocatorDispatch* self, + void* address, + void* context) { + // Note: The RecordFree should be called before free_function (here and in + // other places). That is because observers need to handle the allocation + // being freed before calling free_function, as once the latter is executed + // the address becomes available and can be allocated by another thread. + // That would be racy otherwise. + // Note: The code doesn't need to protect from recursions using + // ReentryGuard, see ReallocFn for details. + DoNotifyFree(address); + self->next->free_function(self->next, address, context); + } + + static size_t GetSizeEstimateFn(const AllocatorDispatch* self, + void* address, + void* context) { + return self->next->get_size_estimate_function(self->next, address, context); + } + + static unsigned BatchMallocFn(const AllocatorDispatch* self, + size_t size, + void** results, + unsigned num_requested, + void* context) { + ReentryGuard guard; + unsigned const num_allocated = self->next->batch_malloc_function( + self->next, size, results, num_requested, context); + if (LIKELY(guard)) { + for (unsigned i = 0; i < num_allocated; ++i) { + DoNotifyAllocation(results[i], size, + AllocationSubsystem::kAllocatorShim); + } + } + return num_allocated; + } + + static void BatchFreeFn(const AllocatorDispatch* self, + void** to_be_freed, + unsigned num_to_be_freed, + void* context) { + // Note: The code doesn't need to protect from recursions using + // ReentryGuard, see ReallocFn for details. + for (unsigned i = 0; i < num_to_be_freed; ++i) { + DoNotifyFree(to_be_freed[i]); + } + self->next->batch_free_function(self->next, to_be_freed, num_to_be_freed, + context); + } + + static void FreeDefiniteSizeFn(const AllocatorDispatch* self, + void* address, + size_t size, + void* context) { + // Note: The code doesn't need to protect from recursions using + // ReentryGuard, see ReallocFn for details. + DoNotifyFree(address); + self->next->free_definite_size_function(self->next, address, size, context); + } + + static void* AlignedMallocFn(const AllocatorDispatch* self, + size_t size, + size_t alignment, + void* context) { + ReentryGuard guard; + void* const address = self->next->aligned_malloc_function( + self->next, size, alignment, context); + if (LIKELY(guard)) { + DoNotifyAllocation(address, size, AllocationSubsystem::kAllocatorShim); + } + return address; + } + + static void* AlignedReallocFn(const AllocatorDispatch* self, + void* address, + size_t size, + size_t alignment, + void* context) { + ReentryGuard guard; + // Note: size == 0 actually performs free. + // Note: DoNotifyFree doesn't need to protect from recursions using + // ReentryGuard, see ReallocFn for details. + // Instead, making it unguarded also ensures proper notification of the free + // portion. + DoNotifyFree(address); + address = self->next->aligned_realloc_function(self->next, address, size, + alignment, context); + if (LIKELY(guard)) { + DoNotifyAllocation(address, size, AllocationSubsystem::kAllocatorShim); + } + return address; + } + + static void AlignedFreeFn(const AllocatorDispatch* self, + void* address, + void* context) { + // Note: The code doesn't need to protect from recursions using + // ReentryGuard, see ReallocFn for details. + DoNotifyFree(address); + self->next->aligned_free_function(self->next, address, context); + } + + static AllocatorDispatch allocator_dispatch_; +#endif + + static ALWAYS_INLINE void DoNotifyAllocation( + void* address, + size_t size, + AllocationSubsystem subSystem, + const char* type_name = nullptr) { + PerformAllocationNotification(s_observers, AllObservers{}, address, size, + subSystem, type_name); + } + + static ALWAYS_INLINE void DoNotifyFree(void* address) { + PerformFreeNotification(s_observers, AllObservers{}, address); + } + + static std::tuple<ObserverTypes*...> s_observers; +}; + +template <typename... ObserverTypes> +std::tuple<ObserverTypes*...> DispatcherImpl<ObserverTypes...>::s_observers; + +#if BUILDFLAG(USE_ALLOCATOR_SHIM) +template <typename... ObserverTypes> +AllocatorDispatch DispatcherImpl<ObserverTypes...>::allocator_dispatch_ = { + &AllocFn, + &AllocUncheckedFn, + &AllocZeroInitializedFn, + &AllocAlignedFn, + &ReallocFn, + &FreeFn, + &GetSizeEstimateFn, + &BatchMallocFn, + &BatchFreeFn, + &FreeDefiniteSizeFn, + &AlignedMallocFn, + &AlignedReallocFn, + &AlignedFreeFn, + nullptr}; +#endif + +// Specialization of DispatcherImpl in case we have no observers to notify. In +// this special case we return a set of null pointers as the Dispatcher must not +// install any hooks at all. +template <> +struct DispatcherImpl<> { + static DispatchData GetNotificationHooks(std::tuple<> /*observers*/) { + return DispatchData() +#if BUILDFLAG(USE_PARTITION_ALLOC) + .SetAllocationObserverHooks(nullptr, nullptr) +#endif +#if BUILDFLAG(USE_ALLOCATOR_SHIM) + .SetAllocatorDispatch(nullptr) +#endif + ; + } +}; + +// A little utility function that helps using DispatcherImpl by providing +// automated type deduction for templates. +template <typename... ObserverTypes> +inline DispatchData GetNotificationHooks( + std::tuple<ObserverTypes*...> observers) { + return DispatcherImpl<ObserverTypes...>::GetNotificationHooks( + std::move(observers)); +} + +} // namespace base::allocator::dispatcher::internal + +#endif // BASE_ALLOCATOR_DISPATCHER_INTERNAL_DISPATCHER_INTERNAL_H_ \ No newline at end of file
diff --git a/base/allocator/dispatcher/internal/dispatcher_internal_unittest.cc b/base/allocator/dispatcher/internal/dispatcher_internal_unittest.cc new file mode 100644 index 0000000..0308295 --- /dev/null +++ b/base/allocator/dispatcher/internal/dispatcher_internal_unittest.cc
@@ -0,0 +1,520 @@ +// Copyright (c) 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/allocator/dispatcher/internal/dispatcher_internal.h" +#include "base/allocator/dispatcher/testing/dispatcher_test.h" +#include "base/allocator/dispatcher/testing/observer_mock.h" +#include "base/allocator/dispatcher/testing/tools.h" +#include "base/dcheck_is_on.h" +#include "testing/gtest/include/gtest/gtest.h" + +#include <tuple> +#include <utility> + +using ::base::allocator::dispatcher::configuration::kMaximumNumberOfObservers; +using ::base::allocator::dispatcher::testing::CreateTupleOfPointers; +using ::base::allocator::dispatcher::testing::DispatcherTest; +using ::testing::_; +using ::testing::InSequence; + +namespace base::allocator::dispatcher::internal { + +namespace { + +struct AllocationEventDispatcherInternalTest : public DispatcherTest { + static void* GetAllocatedAddress() { + return reinterpret_cast<void*>(0x12345678); + } + static unsigned int GetAllocatedSize() { return 35; } + static unsigned int GetEstimatedSize() { return 77; } + static void* GetFreedAddress() { + return reinterpret_cast<void*>(0x876543210); + } + +#if BUILDFLAG(USE_ALLOCATOR_SHIM) + AllocatorDispatch* GetNextAllocatorDispatch() { return &allocator_dispatch_; } + static void* alloc_function(const AllocatorDispatch*, size_t, void*) { + return GetAllocatedAddress(); + } + static void* alloc_unchecked_function(const AllocatorDispatch*, + size_t, + void*) { + return GetAllocatedAddress(); + } + static void* alloc_zero_initialized_function(const AllocatorDispatch*, + size_t, + size_t, + void*) { + return GetAllocatedAddress(); + } + static void* alloc_aligned_function(const AllocatorDispatch*, + size_t, + size_t, + void*) { + return GetAllocatedAddress(); + } + static void* realloc_function(const AllocatorDispatch*, + void*, + size_t, + void*) { + return GetAllocatedAddress(); + } + static size_t get_size_estimate_function(const AllocatorDispatch*, + void*, + void*) { + return GetEstimatedSize(); + } + static unsigned batch_malloc_function(const AllocatorDispatch*, + size_t, + void**, + unsigned num_requested, + void*) { + return num_requested; + } + static void* aligned_malloc_function(const AllocatorDispatch*, + size_t, + size_t, + void*) { + return GetAllocatedAddress(); + } + static void* aligned_realloc_function(const AllocatorDispatch*, + void*, + size_t, + size_t, + void*) { + return GetAllocatedAddress(); + } + + AllocatorDispatch allocator_dispatch_ = { + &alloc_function, + &alloc_unchecked_function, + &alloc_zero_initialized_function, + &alloc_aligned_function, + &realloc_function, + [](const AllocatorDispatch*, void*, void*) {}, + &get_size_estimate_function, + &batch_malloc_function, + [](const AllocatorDispatch*, void**, unsigned, void*) {}, + [](const AllocatorDispatch*, void*, size_t, void*) {}, + &aligned_malloc_function, + &aligned_realloc_function, + [](const AllocatorDispatch*, void*, void*) {}}; +#endif +}; + +} // namespace + +using ::testing::NaggyMock; +using ::testing::StrictMock; + +using ObserverMock = StrictMock<testing::ObserverMock<>>; + +#if defined(GTEST_HAS_DEATH_TEST) && GTEST_HAS_DEATH_TEST && DCHECK_IS_ON() +TEST(AllocationEventDispatcherInternalDeathTest, + VerifyDeathWhenObserverIsNull) { + testing::ObserverMock<int> observer_1; + testing::ObserverMock<float> observer_2; + testing::ObserverMock<size_t>* null_observer = nullptr; + testing::ObserverMock<double> observer_3; + + const auto observer_ptrs = + std::make_tuple(&observer_1, &observer_2, null_observer, &observer_3); + + EXPECT_DEATH({ GetNotificationHooks(observer_ptrs); }, ""); +} +#endif // defined(GTEST_HAS_DEATH_TEST) && GTEST_HAS_DEATH_TEST && + // DCHECK_IS_ON() + +#if BUILDFLAG(USE_PARTITION_ALLOC) +TEST_F(AllocationEventDispatcherInternalTest, + VerifyPartitionAllocatorHooksAreSet) { + std::array<ObserverMock, 1> observers; + + const auto dispatch_data = + GetNotificationHooks(CreateTupleOfPointers(observers)); + + EXPECT_NE(nullptr, dispatch_data.GetAllocationObserverHook()); + EXPECT_NE(nullptr, dispatch_data.GetFreeObserverHook()); +} + +TEST_F(AllocationEventDispatcherInternalTest, + VerifyPartitionAllocatorHooksAreNullWhenNoObservers) { + const auto dispatch_data = GetNotificationHooks(std::make_tuple()); + + EXPECT_EQ(nullptr, dispatch_data.GetAllocationObserverHook()); + EXPECT_EQ(nullptr, dispatch_data.GetFreeObserverHook()); +} + +TEST_F(AllocationEventDispatcherInternalTest, + VerifyPartitionAllocatorAllocationHooksTriggerCorrectly) { + std::array<ObserverMock, kMaximumNumberOfObservers> observers; + + for (auto& mock : observers) { + EXPECT_CALL(mock, OnAllocation(_, _, _, _)).Times(0); + EXPECT_CALL(mock, OnAllocation(this, sizeof(*this), _, _)).Times(1); + EXPECT_CALL(mock, OnFree(_)).Times(0); + } + + const auto dispatch_data = + GetNotificationHooks(CreateTupleOfPointers(observers)); + + dispatch_data.GetAllocationObserverHook()(this, sizeof(*this), nullptr); +} + +TEST_F(AllocationEventDispatcherInternalTest, + VerifyPartitionAllocatorFreeHooksTriggerCorrectly) { + std::array<ObserverMock, kMaximumNumberOfObservers> observers; + + for (auto& mock : observers) { + EXPECT_CALL(mock, OnAllocation(_, _, _, _)).Times(0); + EXPECT_CALL(mock, OnFree(_)).Times(0); + EXPECT_CALL(mock, OnFree(this)).Times(1); + } + + const auto dispatch_data = + GetNotificationHooks(CreateTupleOfPointers(observers)); + + dispatch_data.GetFreeObserverHook()(this); +} +#endif + +#if BUILDFLAG(USE_ALLOCATOR_SHIM) +TEST_F(AllocationEventDispatcherInternalTest, VerifyAllocatorShimDataIsSet) { + std::array<ObserverMock, 1> observers; + + const auto dispatch_data = + GetNotificationHooks(CreateTupleOfPointers(observers)); + const auto* const allocator_dispatch = dispatch_data.GetAllocatorDispatch(); + EXPECT_NE(nullptr, allocator_dispatch); + EXPECT_NE(nullptr, allocator_dispatch->alloc_function); + EXPECT_NE(nullptr, allocator_dispatch->alloc_unchecked_function); + EXPECT_NE(nullptr, allocator_dispatch->alloc_zero_initialized_function); + EXPECT_NE(nullptr, allocator_dispatch->alloc_aligned_function); + EXPECT_NE(nullptr, allocator_dispatch->realloc_function); + EXPECT_NE(nullptr, allocator_dispatch->free_function); + EXPECT_NE(nullptr, allocator_dispatch->get_size_estimate_function); + EXPECT_NE(nullptr, allocator_dispatch->batch_malloc_function); + EXPECT_NE(nullptr, allocator_dispatch->batch_free_function); + EXPECT_NE(nullptr, allocator_dispatch->free_definite_size_function); + EXPECT_NE(nullptr, allocator_dispatch->aligned_malloc_function); + EXPECT_NE(nullptr, allocator_dispatch->aligned_realloc_function); + EXPECT_NE(nullptr, allocator_dispatch->aligned_free_function); +} + +TEST_F(AllocationEventDispatcherInternalTest, + VerifyAllocatorShimDataIsNullWhenNoObservers) { + const auto dispatch_data = GetNotificationHooks(std::make_tuple()); + + EXPECT_EQ(nullptr, dispatch_data.GetAllocatorDispatch()); +} + +TEST_F(AllocationEventDispatcherInternalTest, + VerifyAllocatorShimHooksTriggerCorrectly_alloc_function) { + std::array<ObserverMock, kMaximumNumberOfObservers> observers; + + for (auto& mock : observers) { + EXPECT_CALL(mock, OnAllocation(_, _, _, _)).Times(0); + EXPECT_CALL(mock, OnAllocation(GetAllocatedAddress(), GetAllocatedSize(), + AllocationSubsystem::kAllocatorShim, _)) + .Times(1); + EXPECT_CALL(mock, OnFree(_)).Times(0); + } + + auto const dispatch_data = + GetNotificationHooks(CreateTupleOfPointers(observers)); + + auto* const allocator_dispatch = dispatch_data.GetAllocatorDispatch(); + allocator_dispatch->next = GetNextAllocatorDispatch(); + + auto* const allocated_address = allocator_dispatch->alloc_function( + allocator_dispatch, GetAllocatedSize(), nullptr); + + EXPECT_EQ(allocated_address, GetAllocatedAddress()); +} + +TEST_F(AllocationEventDispatcherInternalTest, + VerifyAllocatorShimHooksTriggerCorrectly_alloc_unchecked_function) { + std::array<ObserverMock, kMaximumNumberOfObservers> observers; + + for (auto& mock : observers) { + EXPECT_CALL(mock, OnAllocation(_, _, _, _)).Times(0); + EXPECT_CALL(mock, OnAllocation(GetAllocatedAddress(), GetAllocatedSize(), + AllocationSubsystem::kAllocatorShim, _)) + .Times(1); + EXPECT_CALL(mock, OnFree(_)).Times(0); + } + + auto const dispatch_data = + GetNotificationHooks(CreateTupleOfPointers(observers)); + + auto* const allocator_dispatch = dispatch_data.GetAllocatorDispatch(); + allocator_dispatch->next = GetNextAllocatorDispatch(); + + auto* const allocated_address = allocator_dispatch->alloc_unchecked_function( + allocator_dispatch, GetAllocatedSize(), nullptr); + + EXPECT_EQ(allocated_address, GetAllocatedAddress()); +} + +TEST_F( + AllocationEventDispatcherInternalTest, + VerifyAllocatorShimHooksTriggerCorrectly_alloc_zero_initialized_function) { + std::array<ObserverMock, kMaximumNumberOfObservers> observers; + constexpr int n = 8; + + for (auto& mock : observers) { + EXPECT_CALL(mock, OnAllocation(_, _, _, _)).Times(0); + EXPECT_CALL(mock, + OnAllocation(GetAllocatedAddress(), n * GetAllocatedSize(), + AllocationSubsystem::kAllocatorShim, _)) + .Times(1); + EXPECT_CALL(mock, OnFree(_)).Times(0); + } + + auto const dispatch_data = + GetNotificationHooks(CreateTupleOfPointers(observers)); + + auto* const allocator_dispatch = dispatch_data.GetAllocatorDispatch(); + allocator_dispatch->next = GetNextAllocatorDispatch(); + + auto* const allocated_address = + allocator_dispatch->alloc_zero_initialized_function( + allocator_dispatch, n, GetAllocatedSize(), nullptr); + + EXPECT_EQ(allocated_address, GetAllocatedAddress()); +} + +TEST_F(AllocationEventDispatcherInternalTest, + VerifyAllocatorShimHooksTriggerCorrectly_alloc_aligned_function) { + std::array<ObserverMock, kMaximumNumberOfObservers> observers; + + for (auto& mock : observers) { + EXPECT_CALL(mock, OnAllocation(_, _, _, _)).Times(0); + EXPECT_CALL(mock, OnAllocation(GetAllocatedAddress(), GetAllocatedSize(), + AllocationSubsystem::kAllocatorShim, _)) + .Times(1); + EXPECT_CALL(mock, OnFree(_)).Times(0); + } + + auto const dispatch_data = + GetNotificationHooks(CreateTupleOfPointers(observers)); + + auto* const allocator_dispatch = dispatch_data.GetAllocatorDispatch(); + allocator_dispatch->next = GetNextAllocatorDispatch(); + + auto* const allocated_address = allocator_dispatch->alloc_aligned_function( + allocator_dispatch, 2048, GetAllocatedSize(), nullptr); + + EXPECT_EQ(allocated_address, GetAllocatedAddress()); +} + +TEST_F(AllocationEventDispatcherInternalTest, + VerifyAllocatorShimHooksTriggerCorrectly_realloc_function) { + std::array<ObserverMock, kMaximumNumberOfObservers> observers; + + for (auto& mock : observers) { + InSequence execution_order; + + EXPECT_CALL(mock, OnFree(GetFreedAddress())).Times(1); + EXPECT_CALL(mock, OnAllocation(GetAllocatedAddress(), GetAllocatedSize(), + AllocationSubsystem::kAllocatorShim, _)) + .Times(1); + } + + auto const dispatch_data = + GetNotificationHooks(CreateTupleOfPointers(observers)); + + auto* const allocator_dispatch = dispatch_data.GetAllocatorDispatch(); + allocator_dispatch->next = GetNextAllocatorDispatch(); + + auto* const allocated_address = allocator_dispatch->realloc_function( + allocator_dispatch, GetFreedAddress(), GetAllocatedSize(), nullptr); + + EXPECT_EQ(allocated_address, GetAllocatedAddress()); +} + +TEST_F(AllocationEventDispatcherInternalTest, + VerifyAllocatorShimHooksTriggerCorrectly_free_function) { + std::array<ObserverMock, kMaximumNumberOfObservers> observers; + + for (auto& mock : observers) { + EXPECT_CALL(mock, OnFree(GetFreedAddress())).Times(1); + EXPECT_CALL(mock, OnAllocation(_, _, _, _)).Times(0); + } + + auto const dispatch_data = + GetNotificationHooks(CreateTupleOfPointers(observers)); + + auto* const allocator_dispatch = dispatch_data.GetAllocatorDispatch(); + allocator_dispatch->next = GetNextAllocatorDispatch(); + + allocator_dispatch->free_function(allocator_dispatch, GetFreedAddress(), + nullptr); +} + +TEST_F(AllocationEventDispatcherInternalTest, + VerifyAllocatorShimHooksTriggerCorrectly_get_size_estimate_function) { + std::array<ObserverMock, kMaximumNumberOfObservers> observers; + + for (auto& mock : observers) { + EXPECT_CALL(mock, OnFree(_)).Times(0); + EXPECT_CALL(mock, OnAllocation(_, _, _, _)).Times(0); + } + + auto const dispatch_data = + GetNotificationHooks(CreateTupleOfPointers(observers)); + + auto* const allocator_dispatch = dispatch_data.GetAllocatorDispatch(); + allocator_dispatch->next = GetNextAllocatorDispatch(); + + auto const estimated_size = allocator_dispatch->get_size_estimate_function( + allocator_dispatch, GetAllocatedAddress(), nullptr); + + EXPECT_EQ(estimated_size, GetEstimatedSize()); +} + +TEST_F(AllocationEventDispatcherInternalTest, + VerifyAllocatorShimHooksTriggerCorrectly_batch_malloc_function) { + constexpr size_t allocation_batch_size = 10; + std::array<ObserverMock, kMaximumNumberOfObservers> observers; + std::array<void*, allocation_batch_size> allocation_batch = {nullptr}; + + for (auto& mock : observers) { + EXPECT_CALL(mock, OnFree(_)).Times(0); + EXPECT_CALL(mock, OnAllocation(nullptr, GetAllocatedSize(), + AllocationSubsystem::kAllocatorShim, _)) + .Times(allocation_batch_size); + } + + auto const dispatch_data = + GetNotificationHooks(CreateTupleOfPointers(observers)); + + auto* const allocator_dispatch = dispatch_data.GetAllocatorDispatch(); + EXPECT_NE(allocator_dispatch->batch_malloc_function, nullptr); + + allocator_dispatch->next = GetNextAllocatorDispatch(); + + auto const number_allocated = allocator_dispatch->batch_malloc_function( + allocator_dispatch, GetAllocatedSize(), allocation_batch.data(), + allocation_batch_size, nullptr); + + EXPECT_EQ(number_allocated, allocation_batch_size); +} + +TEST_F(AllocationEventDispatcherInternalTest, + VerifyAllocatorShimHooksTriggerCorrectly_batch_free_function) { + constexpr size_t allocation_batch_size = 10; + std::array<ObserverMock, kMaximumNumberOfObservers> observers; + std::array<void*, allocation_batch_size> allocation_batch; + allocation_batch.fill(GetFreedAddress()); + + for (auto& mock : observers) { + EXPECT_CALL(mock, OnFree(GetFreedAddress())).Times(allocation_batch_size); + EXPECT_CALL(mock, OnAllocation(_, _, _, _)).Times(0); + } + + auto const dispatch_data = + GetNotificationHooks(CreateTupleOfPointers(observers)); + + auto* const allocator_dispatch = dispatch_data.GetAllocatorDispatch(); + EXPECT_NE(allocator_dispatch->batch_free_function, nullptr); + + allocator_dispatch->next = GetNextAllocatorDispatch(); + + allocator_dispatch->batch_free_function(allocator_dispatch, + allocation_batch.data(), + allocation_batch_size, nullptr); +} + +TEST_F(AllocationEventDispatcherInternalTest, + VerifyAllocatorShimHooksTriggerCorrectly_free_definite_size_function) { + std::array<ObserverMock, kMaximumNumberOfObservers> observers; + + for (auto& mock : observers) { + EXPECT_CALL(mock, OnFree(GetAllocatedAddress())).Times(1); + EXPECT_CALL(mock, OnAllocation(_, _, _, _)).Times(0); + } + + DispatchData const dispatch_data = + GetNotificationHooks(CreateTupleOfPointers(observers)); + + auto* const allocator_dispatch = dispatch_data.GetAllocatorDispatch(); + EXPECT_NE(allocator_dispatch->free_definite_size_function, nullptr); + + allocator_dispatch->next = GetNextAllocatorDispatch(); + + allocator_dispatch->free_definite_size_function( + allocator_dispatch, GetAllocatedAddress(), GetAllocatedSize(), nullptr); +} + +TEST_F(AllocationEventDispatcherInternalTest, + VerifyAllocatorShimHooksTriggerCorrectly_aligned_malloc_function) { + std::array<ObserverMock, kMaximumNumberOfObservers> observers; + + for (auto& mock : observers) { + EXPECT_CALL(mock, OnAllocation(_, _, _, _)).Times(0); + EXPECT_CALL(mock, OnAllocation(GetAllocatedAddress(), GetAllocatedSize(), + AllocationSubsystem::kAllocatorShim, _)) + .Times(1); + EXPECT_CALL(mock, OnFree(_)).Times(0); + } + + auto const dispatch_data = + GetNotificationHooks(CreateTupleOfPointers(observers)); + + auto* const allocator_dispatch = dispatch_data.GetAllocatorDispatch(); + allocator_dispatch->next = GetNextAllocatorDispatch(); + + auto* const allocated_address = allocator_dispatch->aligned_malloc_function( + allocator_dispatch, GetAllocatedSize(), 2048, nullptr); + + EXPECT_EQ(allocated_address, GetAllocatedAddress()); +} + +TEST_F(AllocationEventDispatcherInternalTest, + VerifyAllocatorShimHooksTriggerCorrectly_aligned_realloc_function) { + std::array<ObserverMock, kMaximumNumberOfObservers> observers; + + for (auto& mock : observers) { + InSequence execution_order; + + EXPECT_CALL(mock, OnFree(GetFreedAddress())).Times(1); + EXPECT_CALL(mock, OnAllocation(GetAllocatedAddress(), GetAllocatedSize(), + AllocationSubsystem::kAllocatorShim, _)) + .Times(1); + } + + auto const dispatch_data = + GetNotificationHooks(CreateTupleOfPointers(observers)); + + auto* const allocator_dispatch = dispatch_data.GetAllocatorDispatch(); + allocator_dispatch->next = GetNextAllocatorDispatch(); + + auto* const allocated_address = allocator_dispatch->aligned_realloc_function( + allocator_dispatch, GetFreedAddress(), GetAllocatedSize(), 2048, nullptr); + + EXPECT_EQ(allocated_address, GetAllocatedAddress()); +} + +TEST_F(AllocationEventDispatcherInternalTest, + VerifyAllocatorShimHooksTriggerCorrectly_aligned_free_function) { + std::array<ObserverMock, kMaximumNumberOfObservers> observers; + + for (auto& mock : observers) { + EXPECT_CALL(mock, OnFree(GetFreedAddress())).Times(1); + EXPECT_CALL(mock, OnAllocation(_, _, _, _)).Times(0); + } + + auto const dispatch_data = + GetNotificationHooks(CreateTupleOfPointers(observers)); + + auto* const allocator_dispatch = dispatch_data.GetAllocatorDispatch(); + allocator_dispatch->next = GetNextAllocatorDispatch(); + + allocator_dispatch->aligned_free_function(allocator_dispatch, + GetFreedAddress(), nullptr); +} + +#endif +} // namespace base::allocator::dispatcher::internal
diff --git a/base/allocator/dispatcher/internal/tools.h b/base/allocator/dispatcher/internal/tools.h new file mode 100644 index 0000000..e2e57e88a --- /dev/null +++ b/base/allocator/dispatcher/internal/tools.h
@@ -0,0 +1,29 @@ +// Copyright (c) 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_ALLOCATOR_DISPATCHER_INTERNAL_TOOLS_H_ +#define BASE_ALLOCATOR_DISPATCHER_INTERNAL_TOOLS_H_ + +#include <cstddef> + +namespace base::allocator::dispatcher::internal { + +constexpr bool LessEqual(size_t lhs, size_t rhs) { + return lhs <= rhs; +} + +constexpr bool Equal(size_t lhs, size_t rhs) { + return lhs == rhs; +} + +struct IsValidObserver { + template <typename T> + constexpr bool operator()(T const* ptr) const noexcept { + return ptr != nullptr; + } +}; + +} // namespace base::allocator::dispatcher::internal + +#endif // BASE_ALLOCATOR_DISPATCHER_INTERNAL_DISPATCHER_H_ \ No newline at end of file
diff --git a/base/allocator/dispatcher/reentry_guard.cc b/base/allocator/dispatcher/reentry_guard.cc index 9253245b..7a8bea91 100644 --- a/base/allocator/dispatcher/reentry_guard.cc +++ b/base/allocator/dispatcher/reentry_guard.cc
@@ -9,12 +9,26 @@ #include "build/build_config.h" #if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_ANDROID) - #include <pthread.h> +#endif namespace base::allocator::dispatcher { +#if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_ANDROID) pthread_key_t ReentryGuard::entered_key_ = 0; -} // namespace base::allocator::dispatcher +void ReentryGuard::InitTLSSlot() { + if (entered_key_ == 0) { + int error = pthread_key_create(&entered_key_, nullptr); + CHECK(!error); + } + + DCHECK(entered_key_ != 0); +} + +#else + +void ReentryGuard::InitTLSSlot() {} + #endif +} // namespace base::allocator::dispatcher
diff --git a/base/allocator/dispatcher/reentry_guard.h b/base/allocator/dispatcher/reentry_guard.h index 038e047..e1531a1 100644 --- a/base/allocator/dispatcher/reentry_guard.h +++ b/base/allocator/dispatcher/reentry_guard.h
@@ -25,7 +25,7 @@ // Besides that the implementations of thread_local on macOS and Android // seem to allocate memory lazily on the first access to thread_local variables. // Make use of pthread TLS instead of C++ thread_local there. -struct ReentryGuard { +struct BASE_EXPORT ReentryGuard { ReentryGuard() : allowed_(!pthread_getspecific(entered_key_)) { pthread_setspecific(entered_key_, reinterpret_cast<void*>(true)); } @@ -41,10 +41,7 @@ // order to acquire a low TLS slot number because glibc TLS implementation // will require a malloc call to allocate storage for a higher slot number // (>= PTHREAD_KEY_2NDLEVEL_SIZE == 32). c.f. heap_profiling::InitTLSSlot. - static void Init() { - int error = pthread_key_create(&entered_key_, nullptr); - CHECK(!error); - } + static void InitTLSSlot(); private: static pthread_key_t entered_key_; @@ -58,7 +55,7 @@ struct [[maybe_unused]] BASE_EXPORT ReentryGuard { constexpr explicit operator bool() const noexcept { return true; } - static void Init() {} + static void InitTLSSlot(); }; #endif
diff --git a/base/allocator/dispatcher/subsystem.h b/base/allocator/dispatcher/subsystem.h new file mode 100644 index 0000000..a5dea315 --- /dev/null +++ b/base/allocator/dispatcher/subsystem.h
@@ -0,0 +1,21 @@ +// Copyright (c) 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_ALLOCATOR_DISPATCHER_SUBSYSTEM_H_ +#define BASE_ALLOCATOR_DISPATCHER_SUBSYSTEM_H_ + +namespace base::allocator::dispatcher { + +// Identifiers for the memory subsystem handling the allocation. Some observers +// require more detailed information on who is performing the allocation, i.e. +// SamplingHeapProfiler. +enum class AllocationSubsystem { + // Allocation is handled by PartitionAllocator. + kPartitionAllocator = 1, + // Allocation is handled by AllocatorShims. + kAllocatorShim = 2 +}; +} // namespace base::allocator::dispatcher + +#endif // BASE_ALLOCATOR_DISPATCHER_SUBSYSTEM_H_ \ No newline at end of file
diff --git a/base/allocator/dispatcher/testing/dispatcher_test.cc b/base/allocator/dispatcher/testing/dispatcher_test.cc new file mode 100644 index 0000000..9be5a250 --- /dev/null +++ b/base/allocator/dispatcher/testing/dispatcher_test.cc
@@ -0,0 +1,16 @@ +// Copyright (c) 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/allocator/dispatcher/testing/dispatcher_test.h" +#include "base/allocator/dispatcher/reentry_guard.h" + +namespace base::allocator::dispatcher::testing { + +DispatcherTest::DispatcherTest() { + base::allocator::dispatcher::ReentryGuard::InitTLSSlot(); +} + +DispatcherTest::~DispatcherTest() = default; + +} // namespace base::allocator::dispatcher::testing \ No newline at end of file
diff --git a/base/allocator/dispatcher/testing/dispatcher_test.h b/base/allocator/dispatcher/testing/dispatcher_test.h new file mode 100644 index 0000000..5240d6a3 --- /dev/null +++ b/base/allocator/dispatcher/testing/dispatcher_test.h
@@ -0,0 +1,27 @@ +// Copyright (c) 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_ALLOCATOR_DISPATCHER_TESTING_DISPATCHER_TEST_H_ +#define BASE_ALLOCATOR_DISPATCHER_TESTING_DISPATCHER_TEST_H_ + +#include "testing/gtest/include/gtest/gtest.h" + +namespace base::allocator::dispatcher::testing { + +// DispatcherTest provides some common initialization which most of the +// unittests of the dispatcher require. DispatcherTest should not be used +// directly. Instead, derive your test fixture from it. +struct DispatcherTest : public ::testing::Test { + // Perform some commonly required initialization, at them moment + // - Initialize the TLS slot for the ReentryGuard + DispatcherTest(); + + protected: + // Protected d'tor only to prevent direct usage of this class. + ~DispatcherTest() override; +}; + +} // namespace base::allocator::dispatcher::testing + +#endif // BASE_ALLOCATOR_DISPATCHER_TESTING_DISPATCHER_TEST_H_ \ No newline at end of file
diff --git a/base/allocator/dispatcher/testing/observer_mock.h b/base/allocator/dispatcher/testing/observer_mock.h new file mode 100644 index 0000000..824eb741d --- /dev/null +++ b/base/allocator/dispatcher/testing/observer_mock.h
@@ -0,0 +1,32 @@ +// Copyright (c) 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_ALLOCATOR_DISPATCHER_TESTING_OBSERVER_MOCK_H_ +#define BASE_ALLOCATOR_DISPATCHER_TESTING_OBSERVER_MOCK_H_ + +#include "base/allocator/dispatcher/subsystem.h" +#include "testing/gmock/include/gmock/gmock.h" + +#include <cstddef> + +namespace base::allocator::dispatcher::testing { + +// ObserverMock is a small mock class based on GoogleMock. +// It complies to the interface enforced by the dispatcher. The template +// parameter serves only to create distinct types of observers if required. +template <typename T = void> +struct ObserverMock { + MOCK_METHOD(void, + OnAllocation, + (void* address, + size_t size, + AllocationSubsystem sub_system, + const char* type_name), + ()); + MOCK_METHOD(void, OnFree, (void* address), ()); +}; + +} // namespace base::allocator::dispatcher::testing + +#endif // BASE_ALLOCATOR_DISPATCHER_TESTING_OBSERVER_MOCK_H_ \ No newline at end of file
diff --git a/base/allocator/dispatcher/testing/tools.h b/base/allocator/dispatcher/testing/tools.h new file mode 100644 index 0000000..7ff5a4d --- /dev/null +++ b/base/allocator/dispatcher/testing/tools.h
@@ -0,0 +1,50 @@ +// Copyright (c) 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_ALLOCATOR_DISPATCHER_TESTING_TOOLS_H_ +#define BASE_ALLOCATOR_DISPATCHER_TESTING_TOOLS_H_ + +#include <array> +#include <tuple> +#include <utility> + +namespace base::allocator::dispatcher::testing { + +namespace internal { +template <size_t Size, typename Type, typename... AppendedTypes> +struct DefineTupleFromSingleType { + using type = typename DefineTupleFromSingleType<Size - 1, + Type, + AppendedTypes..., + Type>::type; +}; + +template <typename Type, typename... AppendedTypes> +struct DefineTupleFromSingleType<0, Type, AppendedTypes...> { + using type = std::tuple<AppendedTypes...>; +}; + +} // namespace internal + +template <size_t Size, typename Type> +struct DefineTupleFromSingleType { + using type = typename internal::DefineTupleFromSingleType<Size, Type>::type; +}; + +template <typename Type, size_t Size, size_t... Indices> +typename internal::DefineTupleFromSingleType<Size, Type*>::type +CreateTupleOfPointers(std::array<Type, Size>& items, + std::index_sequence<Indices...>) { + return std::make_tuple((&items[Indices])...); +} + +template <typename Type, size_t Size> +typename internal::DefineTupleFromSingleType<Size, Type*>::type +CreateTupleOfPointers(std::array<Type, Size>& items) { + return CreateTupleOfPointers(items, std::make_index_sequence<Size>{}); +} + +} // namespace base::allocator::dispatcher::testing + +#endif
diff --git a/base/allocator/partition_allocator/partition_alloc_constants.h b/base/allocator/partition_allocator/partition_alloc_constants.h index 0d0cab20..b8f1aa3 100644 --- a/base/allocator/partition_allocator/partition_alloc_constants.h +++ b/base/allocator/partition_allocator/partition_alloc_constants.h
@@ -242,22 +242,20 @@ constexpr size_t kSuperPageOffsetMask = kSuperPageAlignment - 1; constexpr size_t kSuperPageBaseMask = ~kSuperPageOffsetMask; -// GigaCage is split into two pools, one which supports BackupRefPtr (BRP) and -// one that doesn't. +// GigaCage is generally split into two pools, one which supports BackupRefPtr +// (BRP) and one that doesn't. #if defined(PA_HAS_64_BITS_POINTERS) -// The Configurable Pool is only available in 64-bit mode +// The 3rd, Configurable Pool is only available in 64-bit mode. constexpr size_t kNumPools = 3; -#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) -// Special-case macOS. Contrary to other platforms, there is no sandbox limit -// there, meaning that a single renderer could "happily" consume >8GiB. So the -// 8GiB pool size is a regression. Make the limit higher on this platform only -// to be consistent with previous behavior. See crbug.com/1232567 for details. -// -// On Linux, reserving memory is not costly, and we have cases where heaps can -// grow to more than 8GiB without being a memory leak. -constexpr size_t kPoolMaxSize = 16 * kGiB; -#else +// Maximum GigaCage pool size. With exception of Configurable Pool, it is also +// the actual size, unless PA_USE_DYNAMICALLY_SIZED_GIGA_CAGE is set, which +// allows to choose a different size at initialization time for certain +// configurations. +#if BUILDFLAG(IS_ANDROID) +// Special-case Android, which incurs test failures with larger GigaCage. constexpr size_t kPoolMaxSize = 8 * kGiB; +#else +constexpr size_t kPoolMaxSize = 16 * kGiB; #endif #else // defined(PA_HAS_64_BITS_POINTERS) constexpr size_t kNumPools = 2;
diff --git a/base/feature_list.cc b/base/feature_list.cc index 219c297..19707c40 100644 --- a/base/feature_list.cc +++ b/base/feature_list.cc
@@ -106,17 +106,18 @@ return IsStringASCII(name) && name.find_first_of(",<*") == std::string::npos; } -// Splits |first| into two parts by the |separator| where the first part will be +// Splits |text| into two parts by the |separator| where the first part will be // returned updated in |first| and the second part will be returned as |second|. // This function returns false if there is more than one |separator| in |first|. // If there is no |separator| presented in |first|, this function will not // modify |first| and |second|. It's used for splitting the |enable_features| // flag into feature name, field trial name and feature parameters. -bool SplitIntoTwo(const std::string& separator, +bool SplitIntoTwo(StringPiece text, + StringPiece separator, StringPiece* first, std::string* second) { std::vector<StringPiece> parts = - SplitStringPiece(*first, separator, TRIM_WHITESPACE, SPLIT_WANT_ALL); + SplitStringPiece(text, separator, TRIM_WHITESPACE, SPLIT_WANT_ALL); if (parts.size() == 2) { *second = std::string(parts[1]); } else if (parts.size() > 2) { @@ -141,31 +142,21 @@ std::vector<std::string> enable_features_list; std::vector<std::string> force_fieldtrials_list; std::vector<std::string> force_fieldtrial_params_list; - for (auto& enable_feature : + for (const auto& enable_feature : FeatureList::SplitFeatureListString(enable_features)) { - // First, check whether ":" is present. If true, feature parameters were - // set for this feature. - std::string feature_params; - if (!SplitIntoTwo(":", &enable_feature, &feature_params)) - return false; - // Then, check whether "." is present. If true, a group was specified for - // this feature. - std::string group; - if (!SplitIntoTwo(".", &enable_feature, &group)) - return false; - // Finally, check whether "<" is present. If true, a study was specified for - // this feature. + std::string feature_name; std::string study; - if (!SplitIntoTwo("<", &enable_feature, &study)) + std::string group; + std::string feature_params; + if (!FeatureList::ParseEnableFeatureString( + enable_feature, &feature_name, &study, &group, &feature_params)) { return false; + } - const std::string feature_name(enable_feature); // If feature params were set but group and study weren't, associate the // feature and its feature params to a synthetic field trial as the // feature params only make sense when it's combined with a field trial. if (!feature_params.empty()) { - study = study.empty() ? "Study" + feature_name : study; - group = group.empty() ? "Group" + feature_name : group; force_fieldtrials_list.push_back(study + "/" + group); force_fieldtrial_params_list.push_back(study + "." + group + ":" + feature_params); @@ -360,8 +351,10 @@ } void FeatureList::GetFeatureOverrides(std::string* enable_overrides, - std::string* disable_overrides) const { - GetFeatureOverridesImpl(enable_overrides, disable_overrides, false); + std::string* disable_overrides, + bool include_group_name) const { + GetFeatureOverridesImpl(enable_overrides, disable_overrides, false, + include_group_name); } void FeatureList::GetCommandLineFeatureOverrides( @@ -415,6 +408,45 @@ } // static +bool FeatureList::ParseEnableFeatureString(StringPiece enable_feature, + std::string* feature_name, + std::string* study_name, + std::string* group_name, + std::string* params) { + StringPiece first; + // First, check whether ":" is present. If true, feature parameters were + // set for this feature. + std::string feature_params; + if (!SplitIntoTwo(enable_feature, ":", &first, &feature_params)) + return false; + // Then, check whether "." is present. If true, a group was specified for + // this feature. + std::string group; + if (!SplitIntoTwo(first, ".", &first, &group)) + return false; + // Finally, check whether "<" is present. If true, a study was specified for + // this feature. + std::string study; + if (!SplitIntoTwo(first, "<", &first, &study)) + return false; + + std::string enable_feature_name(first); + // If feature params were set but group and study weren't, associate the + // feature and its feature params to a synthetic field trial as the + // feature params only make sense when it's combined with a field trial. + if (!feature_params.empty()) { + study = study.empty() ? "Study" + enable_feature_name : study; + group = group.empty() ? "Group" + enable_feature_name : group; + } + + feature_name->swap(enable_feature_name); + study_name->swap(study); + group_name->swap(group); + params->swap(feature_params); + return true; +} + +// static bool FeatureList::InitializeInstance(const std::string& enable_features, const std::string& disable_features) { return InitializeInstance(enable_features, disable_features, @@ -675,7 +707,8 @@ void FeatureList::GetFeatureOverridesImpl(std::string* enable_overrides, std::string* disable_overrides, - bool command_line_only) const { + bool command_line_only, + bool include_group_name) const { DCHECK(initialized_); // Check that the FieldTrialList this is associated with, if any, is the @@ -715,8 +748,13 @@ target_list->push_back('*'); target_list->append(entry.first); if (entry.second.field_trial) { + auto* const field_trial = entry.second.field_trial; target_list->push_back('<'); - target_list->append(entry.second.field_trial->trial_name()); + target_list->append(field_trial->trial_name()); + if (include_group_name) { + target_list->push_back('.'); + target_list->append(field_trial->GetGroupNameWithoutActivation()); + } } } }
diff --git a/base/feature_list.h b/base/feature_list.h index 04442d2..a4c8d3c 100644 --- a/base/feature_list.h +++ b/base/feature_list.h
@@ -258,12 +258,16 @@ // accepted by InitializeFromCommandLine()) corresponding to features that // have been overridden - either through command-line or via FieldTrials. For // those features that have an associated FieldTrial, the output entry will be - // of the format "FeatureName<TrialName", where "TrialName" is the name of the - // FieldTrial. Features that have overrides with OVERRIDE_USE_DEFAULT will be - // added to |enable_overrides| with a '*' character prefix. Must be called - // only after the instance has been initialized and registered. + // of the format "FeatureName<TrialName" (|include_group_name|=false) or + // "FeatureName<TrialName.GroupName" (if |include_group_name|=true), where + // "TrialName" is the name of the FieldTrial and "GroupName" is the group + // name of the FieldTrial. Features that have overrides with + // OVERRIDE_USE_DEFAULT will be added to |enable_overrides| with a '*' + // character prefix. Must be called only after the instance has been + // initialized and registered. void GetFeatureOverrides(std::string* enable_overrides, - std::string* disable_overrides) const; + std::string* disable_overrides, + bool include_group_names = false) const; // Like GetFeatureOverrides(), but only returns overrides that were specified // explicitly on the command-line, omitting the ones from field trials. @@ -308,6 +312,19 @@ static std::vector<base::StringPiece> SplitFeatureListString( base::StringPiece input); + // Checks and parses the |enable_feature| (e.g. + // FeatureName<Study.Group:Param1/value1/) obtained by applying + // SplitFeatureListString() to the |enable_features| flag, and sets + // |feature_name| to be the feature's name, |study_name| and |group_name| to + // be the field trial name and its group name if the field trial is specified + // or field trial parameters are given, |params| to be the field trial + // parameters if exists. + static bool ParseEnableFeatureString(StringPiece enable_feature, + std::string* feature_name, + std::string* study_name, + std::string* group_name, + std::string* params); + // Initializes and sets an instance of FeatureList with feature overrides via // command-line flags |enable_features| and |disable_features| if one has not // already been set from command-line flags. Returns true if an instance did @@ -441,7 +458,8 @@ // function's comments for more details. void GetFeatureOverridesImpl(std::string* enable_overrides, std::string* disable_overrides, - bool command_line_only) const; + bool command_line_only, + bool include_group_name = false) const; // Verifies that there's only a single definition of a Feature struct for a // given feature name. Keeps track of the first seen Feature struct for each
diff --git a/base/feature_list_unittest.cc b/base/feature_list_unittest.cc index f6fff0e..963480f0 100644 --- a/base/feature_list_unittest.cc +++ b/base/feature_list_unittest.cc
@@ -21,7 +21,6 @@ #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/test/scoped_feature_list.h" -#include "base/test/scoped_field_trial_list_resetter.h" #include "testing/gtest/include/gtest/gtest.h" namespace base { @@ -182,8 +181,9 @@ const auto& test_case = test_cases[i]; SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]", i)); - test::ScopedFieldTrialListResetter resetter; - FieldTrialList field_trial_list(nullptr); + test::ScopedFeatureList outer_scope; + outer_scope.InitWithEmptyFeatureAndFieldTrialLists(); + auto feature_list = std::make_unique<FeatureList>(); FieldTrial* trial1 = FieldTrialList::CreateFieldTrial("TrialExample1", "A"); @@ -402,8 +402,9 @@ test_case.enable_features, test_case.disable_features)); - test::ScopedFieldTrialListResetter resetter; - FieldTrialList field_trial_list(nullptr); + test::ScopedFeatureList outer_scope; + outer_scope.InitWithEmptyFeatureAndFieldTrialLists(); + auto feature_list = std::make_unique<FeatureList>(); feature_list->InitializeFromCommandLine(test_case.enable_features, test_case.disable_features);
diff --git a/base/memory/discardable_memory_backing_field_trial_unittest.cc b/base/memory/discardable_memory_backing_field_trial_unittest.cc index 7d35045..5c6f0a6 100644 --- a/base/memory/discardable_memory_backing_field_trial_unittest.cc +++ b/base/memory/discardable_memory_backing_field_trial_unittest.cc
@@ -7,7 +7,6 @@ #include "base/metrics/field_trial.h" #include "base/metrics/field_trial_params.h" #include "base/test/scoped_feature_list.h" -#include "base/test/scoped_field_trial_list_resetter.h" #include "build/build_config.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/base/metrics/field_trial.cc b/base/metrics/field_trial.cc index 9fef083..df803ae 100644 --- a/base/metrics/field_trial.cc +++ b/base/metrics/field_trial.cc
@@ -90,7 +90,8 @@ // format of the pickle looks like: // TrialName, GroupName, ParamKey1, ParamValue1, ParamKey2, ParamValue2, ... // If there are no parameters, then it just ends at GroupName. -void PickleFieldTrial(const FieldTrial::State& trial_state, Pickle* pickle) { +void PickleFieldTrial(const FieldTrial::PickleState& trial_state, + Pickle* pickle) { WriteStringPair(pickle, *trial_state.trial_name, *trial_state.group_name); // Get field trial params. @@ -122,18 +123,11 @@ return std::min(result, divisor - 1); } -// Separate type from FieldTrial::State so that it can use StringPieces. -struct FieldTrialStringEntry { - StringPiece trial_name; - StringPiece group_name; - bool activated = false; -}; - // Parses the --force-fieldtrials string |trials_string| into |entries|. // Returns true if the string was parsed correctly. On failure, the |entries| // array may end up being partially filled. bool ParseFieldTrialsString(const std::string& trials_string, - std::vector<FieldTrialStringEntry>* entries) { + std::vector<FieldTrial::State>* entries) { const StringPiece trials_string_piece(trials_string); size_t next_item = 0; @@ -148,7 +142,7 @@ if (group_name_end == trials_string.npos) group_name_end = trials_string.length(); - FieldTrialStringEntry entry; + FieldTrial::State entry; // Verify if the trial should be activated or not. if (trials_string[next_item] == kActivationMarker) { // Name cannot be only the indicator. @@ -224,11 +218,11 @@ FieldTrial::EntropyProvider::~EntropyProvider() = default; -FieldTrial::State::State() = default; +FieldTrial::PickleState::PickleState() = default; -FieldTrial::State::State(const State& other) = default; +FieldTrial::PickleState::PickleState(const PickleState& other) = default; -FieldTrial::State::~State() = default; +FieldTrial::PickleState::~PickleState() = default; bool FieldTrial::FieldTrialEntry::GetTrialAndGroupName( StringPiece* trial_name, @@ -437,7 +431,7 @@ return true; } -bool FieldTrial::GetStateWhileLocked(State* field_trial_state, +bool FieldTrial::GetStateWhileLocked(PickleState* field_trial_state, bool include_disabled) { if (!include_disabled && !enable_field_trial_) return false; @@ -607,6 +601,32 @@ } // static +std::vector<FieldTrial::State> FieldTrialList::GetAllFieldTrialStates( + PassKey<test::ScopedFeatureList>) { + std::vector<FieldTrial::State> states; + + if (!global_) + return states; + + AutoLock auto_lock(global_->lock_); + for (const auto& registered : global_->registered_) { + FieldTrial::PickleState trial; + if (!registered.second->GetStateWhileLocked(&trial, true)) + continue; + DCHECK_EQ(std::string::npos, + trial.trial_name->find(kPersistentStringSeparator)); + DCHECK_EQ(std::string::npos, + trial.group_name->find(kPersistentStringSeparator)); + FieldTrial::State entry; + entry.activated = trial.activated; + entry.trial_name = *trial.trial_name; + entry.group_name = *trial.group_name; + states.push_back(std::move(entry)); + } + return states; +} + +// static void FieldTrialList::AllStatesToString(std::string* output, bool include_disabled) { if (!global_) @@ -614,7 +634,7 @@ AutoLock auto_lock(global_->lock_); for (const auto& registered : global_->registered_) { - FieldTrial::State trial; + FieldTrial::PickleState trial; if (!registered.second->GetStateWhileLocked(&trial, include_disabled)) continue; DCHECK_EQ(std::string::npos, @@ -637,7 +657,7 @@ FieldTrialParamAssociator::GetInstance(); std::string output; for (const auto& registered : GetRegisteredTrials()) { - FieldTrial::State trial; + FieldTrial::PickleState trial; if (!registered.second->GetStateWhileLocked(&trial, include_disabled)) continue; DCHECK_EQ(std::string::npos, @@ -693,7 +713,7 @@ void FieldTrialList::GetActiveFieldTrialGroupsFromString( const std::string& trials_string, FieldTrial::ActiveGroups* active_groups) { - std::vector<FieldTrialStringEntry> entries; + std::vector<FieldTrial::State> entries; if (!ParseFieldTrialsString(trials_string, &entries)) return; @@ -744,22 +764,18 @@ if (trials_string.empty() || !global_) return true; - std::vector<FieldTrialStringEntry> entries; + std::vector<FieldTrial::State> entries; if (!ParseFieldTrialsString(trials_string, &entries)) return false; - for (const auto& entry : entries) { - FieldTrial* trial = CreateFieldTrial(entry.trial_name, entry.group_name); - if (!trial) - return false; - if (entry.activated) { - // Call |group()| to mark the trial as "used" and notify observers, if - // any. This is useful to ensure that field trials created in child - // processes are properly reported in crash reports. - trial->group(); - } - } - return true; + return CreateTrialsFromFieldTrialStatesInternal(entries); +} + +// static +bool FieldTrialList::CreateTrialsFromFieldTrialStates( + PassKey<test::ScopedFeatureList>, + const std::vector<FieldTrial::State>& entries) { + return CreateTrialsFromFieldTrialStatesInternal(entries); } // static @@ -1376,7 +1392,7 @@ if (allocator->IsReadonly()) return; - FieldTrial::State trial_state; + FieldTrial::PickleState trial_state; if (!field_trial->GetStateWhileLocked(&trial_state, false)) return; @@ -1465,4 +1481,25 @@ return output; } +// static +bool FieldTrialList::CreateTrialsFromFieldTrialStatesInternal( + const std::vector<FieldTrial::State>& entries) { + DCHECK(global_); + if (entries.empty() || !global_) + return true; + + for (const auto& entry : entries) { + FieldTrial* trial = CreateFieldTrial(entry.trial_name, entry.group_name); + if (!trial) + return false; + if (entry.activated) { + // Call |group()| to mark the trial as "used" and notify observers, if + // any. This is useful to ensure that field trials created in child + // processes are properly reported in crash reports. + trial->group(); + } + } + return true; +} + } // namespace base
diff --git a/base/metrics/field_trial.h b/base/metrics/field_trial.h index aff640a..b9fb6d7 100644 --- a/base/metrics/field_trial.h +++ b/base/metrics/field_trial.h
@@ -77,10 +77,15 @@ #include "base/pickle.h" #include "base/strings/string_piece.h" #include "base/synchronization/lock.h" +#include "base/types/pass_key.h" #include "build/build_config.h" namespace base { +namespace test { +class ScopedFeatureList; +} // namespace test + class FieldTrialList; struct LaunchOptions; @@ -114,6 +119,13 @@ uint32_t randomization_seed) const = 0; }; + // Separate type from FieldTrial::PickleState so that it can use StringPieces. + struct State { + StringPiece trial_name; + StringPiece group_name; + bool activated = false; + }; + // A pair representing a Field Trial and its selected group. struct ActiveGroup { std::string trial_name; @@ -124,14 +136,14 @@ // active. String members are pointers to the underlying strings owned by the // FieldTrial object. Does not use StringPiece to avoid conversions back to // std::string. - struct BASE_EXPORT State { + struct BASE_EXPORT PickleState { raw_ptr<const std::string, DanglingUntriaged> trial_name = nullptr; raw_ptr<const std::string, DanglingUntriaged> group_name = nullptr; bool activated = false; - State(); - State(const State& other); - ~State(); + PickleState(); + PickleState(const PickleState& other); + ~PickleState(); }; // We create one FieldTrialEntry per field trial in shared memory, via @@ -329,7 +341,8 @@ // the trial has not been disabled true is returned and |field_trial_state| // is filled in; otherwise, the result is false and |field_trial_state| is // left untouched. - bool GetStateWhileLocked(State* field_trial_state, bool include_disabled); + bool GetStateWhileLocked(PickleState* field_trial_state, + bool include_disabled); // Returns the group_name. A winner need not have been chosen. const std::string& group_name_internal() const { return group_name_; } @@ -654,6 +667,27 @@ // For testing, sets the global instance to |instance|. static void RestoreInstanceForTesting(FieldTrialList* instance); + // Creates a list of FieldTrial::State for all FieldTrial instances. + // StringPiece members are bound to the lifetime of the corresponding + // FieldTrial. + static std::vector<FieldTrial::State> GetAllFieldTrialStates( + PassKey<test::ScopedFeatureList>); + + // Create FieldTrials from a list of FieldTrial::State. This method is only + // available to ScopedFeatureList for testing. The most typical usescase is: + // (1) AllStatesToFieldTrialStates(&field_trials); + // (2) backup_ = BackupInstanceForTesting(); + // // field_trials depends on backup_'s lifetype. + // (3) field_trial_list_ = new FieldTrialList(); + // (4) CreateTrialsFromFieldTrialStates(field_trials); + // // Copy backup_'s fieldtrials to the new field_trial_list_ while + // // backup_ is alive. + // For resurrestion in another process, need to use AllStatesToString and + // CreateFieldTrialsFromString. + static bool CreateTrialsFromFieldTrialStates( + PassKey<test::ScopedFeatureList>, + const std::vector<FieldTrial::State>& entries); + private: // Allow tests to access our innards for testing purposes. FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest, InstantiateAllocator); @@ -742,6 +776,12 @@ // Returns all the registered trials. static RegistrationMap GetRegisteredTrials(); + // Create field trials from a list of FieldTrial::State. + // CreateTrialsFromString() and CreateTrialsFromFieldTrialStates() use this + // method internally. + static bool CreateTrialsFromFieldTrialStatesInternal( + const std::vector<FieldTrial::State>& entries); + static FieldTrialList* global_; // The singleton of this class. // This will tell us if there is an attempt to register a field
diff --git a/base/metrics/field_trial_unittest.cc b/base/metrics/field_trial_unittest.cc index 91b5907c..a5bbf67 100644 --- a/base/metrics/field_trial_unittest.cc +++ b/base/metrics/field_trial_unittest.cc
@@ -21,7 +21,6 @@ #include "base/test/mock_entropy_provider.h" #include "base/test/multiprocess_test.h" #include "base/test/scoped_feature_list.h" -#include "base/test/scoped_field_trial_list_resetter.h" #include "base/test/task_environment.h" #include "base/test/test_shared_memory_util.h" #include "base/test/test_timeouts.h" @@ -120,16 +119,17 @@ class FieldTrialTest : public ::testing::Test { public: - FieldTrialTest() : trial_list_(nullptr) {} + FieldTrialTest() { + // The test suite instantiates a FieldTrialList but for the purpose of these + // tests it's cleaner to start from scratch. + scoped_feature_list_.InitWithEmptyFeatureAndFieldTrialLists(); + } FieldTrialTest(const FieldTrialTest&) = delete; FieldTrialTest& operator=(const FieldTrialTest&) = delete; private: test::TaskEnvironment task_environment_; - // The test suite instantiates a FieldTrialList but for the purpose of these - // tests it's cleaner to start from scratch. - test::ScopedFieldTrialListResetter trial_list_resetter_; - FieldTrialList trial_list_; + test::ScopedFeatureList scoped_feature_list_; }; // Test registration, and also check that destructors are called for trials. @@ -1104,14 +1104,18 @@ TEST(FieldTrialTestWithoutList, StatesStringFormat) { std::string save_string; + test::ScopedFeatureList scoped_feature_list; // The test suite instantiates a FieldTrialList but for the purpose of these // tests it's cleaner to start from scratch. - test::ScopedFieldTrialListResetter trial_list_resetter_; + scoped_feature_list.InitWithEmptyFeatureAndFieldTrialLists(); // Scoping the first FieldTrialList, as we need another one to test the // importing function. { + test::ScopedFeatureList scoped_feature_list1; + scoped_feature_list1.InitWithNullFeatureAndFieldTrialLists(); FieldTrialList field_trial_list(nullptr); + scoped_refptr<FieldTrial> trial = CreateFieldTrial("Abc", 10, "Default some name", nullptr); trial->AppendGroup("cba", 10); @@ -1127,6 +1131,8 @@ } // Starting with a new blank FieldTrialList. + test::ScopedFeatureList scoped_feature_list2; + scoped_feature_list2.InitWithNullFeatureAndFieldTrialLists(); FieldTrialList field_trial_list(nullptr); ASSERT_TRUE(field_trial_list.CreateTrialsFromString(save_string)); @@ -1141,7 +1147,9 @@ } TEST(FieldTrialDeathTest, OneTimeRandomizedTrialWithoutFieldTrialList) { - test::ScopedFieldTrialListResetter resetter; + test::ScopedFeatureList scoped_feature_list1; + scoped_feature_list1.InitWithNullFeatureAndFieldTrialLists(); + // Trying to instantiate a one-time randomized field trial before the // FieldTrialList is created should crash. EXPECT_DEATH_IF_SUPPORTED( @@ -1153,19 +1161,21 @@ class FieldTrialListTest : public ::testing::Test { public: - FieldTrialListTest() = default; + FieldTrialListTest() { + // The test suite instantiates a FieldTrialList but for the purpose of these + // tests it's cleaner to start from scratch. + scoped_feature_list_.InitWithEmptyFeatureAndFieldTrialLists(); + } private: - // The test suite instantiates a FieldTrialList but for the purpose of these - // tests it's cleaner to start from scratch. - test::ScopedFieldTrialListResetter trial_list_resetter_; + test::ScopedFeatureList scoped_feature_list_; }; #if !BUILDFLAG(IS_IOS) // LaunchOptions is not available on iOS. TEST_F(FieldTrialListTest, TestCopyFieldTrialStateToFlags) { - FieldTrialList field_trial_list(std::make_unique<MockEntropyProvider>()); - + test::ScopedFeatureList scoped_feature_list1; + scoped_feature_list1.InitWithEmptyFeatureAndFieldTrialLists(); std::unique_ptr<FeatureList> feature_list(new FeatureList); feature_list->InitializeFromCommandLine("A,B", "C"); @@ -1173,8 +1183,8 @@ feature_list->RegisterFieldTrialOverride( "MyFeature", FeatureList::OVERRIDE_ENABLE_FEATURE, trial); - test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitWithFeatureList(std::move(feature_list)); + test::ScopedFeatureList scoped_feature_list2; + scoped_feature_list2.InitWithFeatureList(std::move(feature_list)); FilePath test_file_path = FilePath(FILE_PATH_LITERAL("Program")); CommandLine command_line = CommandLine(test_file_path); @@ -1191,18 +1201,21 @@ #endif // !BUILDFLAG(IS_IOS) TEST_F(FieldTrialListTest, InstantiateAllocator) { - FieldTrialList field_trial_list(nullptr); + test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitWithEmptyFeatureAndFieldTrialLists(); + + FieldTrialList* field_trial_list = FieldTrialList::GetInstance(); FieldTrialList::CreateFieldTrial("Trial1", "Group1"); FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded(); - const void* memory = field_trial_list.field_trial_allocator_->data(); - size_t used = field_trial_list.field_trial_allocator_->used(); + const void* memory = field_trial_list->field_trial_allocator_->data(); + size_t used = field_trial_list->field_trial_allocator_->used(); // Ensure that the function is idempotent. FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded(); - const void* new_memory = field_trial_list.field_trial_allocator_->data(); - size_t new_used = field_trial_list.field_trial_allocator_->used(); + const void* new_memory = field_trial_list->field_trial_allocator_->data(); + size_t new_used = field_trial_list->field_trial_allocator_->used(); EXPECT_EQ(memory, new_memory); EXPECT_EQ(used, new_used); } @@ -1214,7 +1227,9 @@ // Scoping the first FieldTrialList, as we need another one to test that it // matches. { - FieldTrialList field_trial_list1(nullptr); + test::ScopedFeatureList scoped_feature_list1; + scoped_feature_list1.InitWithEmptyFeatureAndFieldTrialLists(); + FieldTrialList::CreateFieldTrial("Trial1", "Group1"); FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded(); FieldTrialList::AllStatesToString(&save_string, false); @@ -1222,7 +1237,9 @@ ASSERT_TRUE(shm_region.IsValid()); } - FieldTrialList field_trial_list2(nullptr); + test::ScopedFeatureList scoped_feature_list2; + scoped_feature_list2.InitWithEmptyFeatureAndFieldTrialLists(); + // 4 KiB is enough to hold the trials only created for this test. base::ReadOnlySharedMemoryMapping shm_mapping = shm_region.MapAt(0, 4 << 10); ASSERT_TRUE(shm_mapping.IsValid()); @@ -1236,7 +1253,8 @@ constexpr char kTrialName[] = "trial"; base::ReadOnlySharedMemoryRegion shm_region; { - FieldTrialList field_trial_list1(nullptr); + test::ScopedFeatureList scoped_feature_list1; + scoped_feature_list1.InitWithEmptyFeatureAndFieldTrialLists(); // Create a simulated trial and a real trial and call group() on them, which // should only add the real trial to the field trial allocator. @@ -1258,7 +1276,8 @@ } // Check that there's only one entry in the allocator. - FieldTrialList field_trial_list2(nullptr); + test::ScopedFeatureList scoped_feature_list2; + scoped_feature_list2.InitWithEmptyFeatureAndFieldTrialLists(); // 4 KiB is enough to hold the trials only created for this test. base::ReadOnlySharedMemoryMapping shm_mapping = shm_region.MapAt(0, 4 << 10); ASSERT_TRUE(shm_mapping.IsValid()); @@ -1269,7 +1288,8 @@ } TEST_F(FieldTrialListTest, AssociateFieldTrialParams) { - FieldTrialList field_trial_list(nullptr); + test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitWithEmptyFeatureAndFieldTrialLists(); std::string trial_name("Trial1"); std::string group_name("Group1"); @@ -1305,7 +1325,8 @@ base::ReadOnlySharedMemoryRegion shm_region; { - FieldTrialList field_trial_list1(nullptr); + test::ScopedFeatureList scoped_feature_list1; + scoped_feature_list1.InitWithEmptyFeatureAndFieldTrialLists(); // Create a field trial with some params. FieldTrial* trial = @@ -1336,7 +1357,8 @@ } // Check that we have the trial. - FieldTrialList field_trial_list2(nullptr); + test::ScopedFeatureList scoped_feature_list2; + scoped_feature_list2.InitWithEmptyFeatureAndFieldTrialLists(); // 4 KiB is enough to hold the trials only created for this test. base::ReadOnlySharedMemoryMapping shm_mapping = shm_region.MapAt(0, 4 << 10); ASSERT_TRUE(shm_mapping.IsValid()); @@ -1351,7 +1373,9 @@ std::string group_name("Group1"); // Create a field trial with some params. - FieldTrialList field_trial_list(nullptr); + test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitWithEmptyFeatureAndFieldTrialLists(); + FieldTrialList::CreateFieldTrial(trial_name, group_name); std::map<std::string, std::string> params; params["key1"] = "value1"; @@ -1451,7 +1475,9 @@ // which don't support/implement shared memory configuration. #if !BUILDFLAG(IS_NACL) && !BUILDFLAG(IS_MAC) TEST_F(FieldTrialListTest, CheckReadOnlySharedMemoryRegion) { - FieldTrialList field_trial_list(nullptr); + test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitWithEmptyFeatureAndFieldTrialLists(); + FieldTrialList::CreateFieldTrial("Trial1", "Group1"); FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded();
diff --git a/base/observer_list_types.h b/base/observer_list_types.h index 4bb92b6..3f04cb77 100644 --- a/base/observer_list_types.h +++ b/base/observer_list_types.h
@@ -29,7 +29,6 @@ CheckedObserver(const CheckedObserver&) = delete; CheckedObserver& operator=(const CheckedObserver&) = delete; - protected: virtual ~CheckedObserver(); // Returns whether |this| is in any ObserverList. Subclasses can CHECK() this
diff --git a/base/sampling_heap_profiler/poisson_allocation_sampler.cc b/base/sampling_heap_profiler/poisson_allocation_sampler.cc index f45d6903..521a964 100644 --- a/base/sampling_heap_profiler/poisson_allocation_sampler.cc +++ b/base/sampling_heap_profiler/poisson_allocation_sampler.cc
@@ -190,7 +190,7 @@ // static void PoissonAllocationSampler::Init() { [[maybe_unused]] static bool init_once = []() { - ReentryGuard::Init(); + ReentryGuard::InitTLSSlot(); return true; }(); }
diff --git a/base/task/sequence_manager/sequence_manager.cc b/base/task/sequence_manager/sequence_manager.cc index cbb31946..e51cf57 100644 --- a/base/task/sequence_manager/sequence_manager.cc +++ b/base/task/sequence_manager/sequence_manager.cc
@@ -55,6 +55,13 @@ #if DCHECK_IS_ON() SequenceManager::Settings::Builder& +SequenceManager::Settings::Builder::SetRandomTaskSelectionSeed( + uint64_t random_task_selection_seed_val) { + settings_.random_task_selection_seed = random_task_selection_seed_val; + return *this; +} + +SequenceManager::Settings::Builder& SequenceManager::Settings::Builder::SetTaskLogging( TaskLogging task_execution_logging_val) { settings_.task_execution_logging = task_execution_logging_val;
diff --git a/base/task/sequence_manager/sequence_manager.h b/base/task/sequence_manager/sequence_manager.h index 6bf2b3e..bdaa9f9 100644 --- a/base/task/sequence_manager/sequence_manager.h +++ b/base/task/sequence_manager/sequence_manager.h
@@ -129,6 +129,11 @@ // Like the above but for same thread posting. std::array<TimeDelta, TaskQueue::kQueuePriorityCount> per_priority_same_thread_task_delay; + + // If not zero this seeds a PRNG used by the task selection logic to choose + // a random TaskQueue for a given priority rather than the TaskQueue with + // the oldest EnqueueOrder. + uint64_t random_task_selection_seed = 0; #endif // DCHECK_IS_ON() }; @@ -306,6 +311,11 @@ Builder& SetPerPrioritySameThreadTaskDelay( std::array<TimeDelta, TaskQueue::kQueuePriorityCount> per_priority_same_thread_task_delay); + + // If not zero this seeds a PRNG used by the task selection logic to choose a + // random TaskQueue for a given priority rather than the TaskQueue with the + // oldest EnqueueOrder. + Builder& SetRandomTaskSelectionSeed(uint64_t random_task_selection_seed); #endif // DCHECK_IS_ON() Settings Build();
diff --git a/base/task/sequence_manager/task_queue_selector.cc b/base/task/sequence_manager/task_queue_selector.cc index b258860..727b3d5 100644 --- a/base/task/sequence_manager/task_queue_selector.cc +++ b/base/task/sequence_manager/task_queue_selector.cc
@@ -23,8 +23,12 @@ scoped_refptr<const AssociatedThreadId> associated_thread, const SequenceManager::Settings& settings) : associated_thread_(std::move(associated_thread)), +#if DCHECK_IS_ON() + random_task_selection_(settings.random_task_selection_seed != 0), +#endif delayed_work_queue_sets_("delayed", this, settings), - immediate_work_queue_sets_("immediate", this, settings) {} + immediate_work_queue_sets_("immediate", this, settings) { +} TaskQueueSelector::~TaskQueueSelector() = default; @@ -184,11 +188,21 @@ // but the resulting queue must be the lower one. if (option == SelectTaskOption::kSkipDelayedTask) { WorkQueue* queue = - ChooseImmediateOnlyWithPriority<SetOperationOldest>(priority); +#if DCHECK_IS_ON() + random_task_selection_ + ? ChooseImmediateOnlyWithPriority<SetOperationRandom>(priority) + : +#endif + ChooseImmediateOnlyWithPriority<SetOperationOldest>(priority); return queue; } - WorkQueue* queue = ChooseWithPriority<SetOperationOldest>(priority); + WorkQueue* queue = +#if DCHECK_IS_ON() + random_task_selection_ ? ChooseWithPriority<SetOperationRandom>(priority) + : +#endif + ChooseWithPriority<SetOperationOldest>(priority); // If we have selected a delayed task while having an immediate task of the // same priority, increase the starvation count.
diff --git a/base/task/sequence_manager/task_queue_selector.h b/base/task/sequence_manager/task_queue_selector.h index 27e004b..00fa7090 100644 --- a/base/task/sequence_manager/task_queue_selector.h +++ b/base/task/sequence_manager/task_queue_selector.h
@@ -154,6 +154,16 @@ } }; +#if DCHECK_IS_ON() + struct SetOperationRandom { + static absl::optional<WorkQueueAndTaskOrder> GetWithPriority( + const WorkQueueSets& sets, + TaskQueue::QueuePriority priority) { + return sets.GetRandomQueueAndTaskOrderInSet(priority); + } + }; +#endif // DCHECK_IS_ON() + template <typename SetOperation> WorkQueue* ChooseWithPriority(TaskQueue::QueuePriority priority) const { // Select an immediate work queue if we are starving immediate tasks. @@ -223,6 +233,10 @@ const scoped_refptr<const AssociatedThreadId> associated_thread_; +#if DCHECK_IS_ON() + const bool random_task_selection_ = false; +#endif + // Count of the number of sets (delayed or immediate) for each priority. // Should only contain 0, 1 or 2. std::array<int, TaskQueue::kQueuePriorityCount> non_empty_set_counts_ = {{0}};
diff --git a/base/task/sequence_manager/thread_controller.cc b/base/task/sequence_manager/thread_controller.cc index c666b56e..11d300f 100644 --- a/base/task/sequence_manager/thread_controller.cc +++ b/base/task/sequence_manager/thread_controller.cc
@@ -165,22 +165,9 @@ if (run_levels_.empty()) return; + DCHECK_NE(run_levels_.top().state(), kRunningWorkItem); time_keeper_.RecordEndOfPhase(kIdleWork, lazy_now); - - // This is similar to the logic in OnWorkStarted(). - if (run_levels_.top().state() == kRunningWorkItem) { - // #work-in-work-implies-nested - // While OnIdle() isn't typically thought of as a "work item" it is a way - // to "do work" and, on platforms like Mac which uses an - // |idle_work_source_|, DoIdleWork() can be invoked without DoWork() being - // first invoked at this run-level. We need to create a nested kIdle - // RunLevel or we break - // #done-work-while-not-running-implies-done-nested. - run_levels_.emplace(kIdle, true, time_keeper_, lazy_now); - } else { - // Simply going kIdle at the current run-level. - run_levels_.top().UpdateState(kIdle, lazy_now); - } + run_levels_.top().UpdateState(kIdle, lazy_now); } // static
diff --git a/base/task/sequence_manager/work_queue_sets.cc b/base/task/sequence_manager/work_queue_sets.cc index c84f07b1..279b1f95 100644 --- a/base/task/sequence_manager/work_queue_sets.cc +++ b/base/task/sequence_manager/work_queue_sets.cc
@@ -16,7 +16,12 @@ WorkQueueSets::WorkQueueSets(const char* name, Observer* observer, const SequenceManager::Settings& settings) - : name_(name), observer_(observer) {} + : name_(name), +#if DCHECK_IS_ON() + last_rand_(settings.random_task_selection_seed), +#endif + observer_(observer) { +} WorkQueueSets::~WorkQueueSets() = default; @@ -154,6 +159,23 @@ return WorkQueueAndTaskOrder(*oldest.value, oldest.key); } +#if DCHECK_IS_ON() +absl::optional<WorkQueueAndTaskOrder> +WorkQueueSets::GetRandomQueueAndTaskOrderInSet(size_t set_index) const { + DCHECK_LT(set_index, work_queue_heaps_.size()); + if (work_queue_heaps_[set_index].empty()) + return absl::nullopt; + const OldestTaskOrder& chosen = + work_queue_heaps_[set_index].begin()[static_cast<long>( + Random() % work_queue_heaps_[set_index].size())]; +#if DCHECK_IS_ON() + absl::optional<TaskOrder> key = chosen.value->GetFrontTaskOrder(); + DCHECK(key && chosen.key == *key); +#endif + return WorkQueueAndTaskOrder(*chosen.value, chosen.key); +} +#endif + bool WorkQueueSets::IsSetEmpty(size_t set_index) const { DCHECK_LT(set_index, work_queue_heaps_.size()) << " set_index = " << set_index;
diff --git a/base/task/sequence_manager/work_queue_sets.h b/base/task/sequence_manager/work_queue_sets.h index 0753cd4..37ee627 100644 --- a/base/task/sequence_manager/work_queue_sets.h +++ b/base/task/sequence_manager/work_queue_sets.h
@@ -79,6 +79,12 @@ absl::optional<WorkQueueAndTaskOrder> GetOldestQueueAndTaskOrderInSet( size_t set_index) const; +#if DCHECK_IS_ON() + // O(1) + absl::optional<WorkQueueAndTaskOrder> GetRandomQueueAndTaskOrderInSet( + size_t set_index) const; +#endif + // O(1) bool IsSetEmpty(size_t set_index) const; @@ -121,6 +127,27 @@ TaskQueue::kQueuePriorityCount> work_queue_heaps_; +#if DCHECK_IS_ON() + static inline uint64_t MurmurHash3(uint64_t value) { + value ^= value >> 33; + value *= uint64_t{0xFF51AFD7ED558CCD}; + value ^= value >> 33; + value *= uint64_t{0xC4CEB9FE1A85EC53}; + value ^= value >> 33; + return value; + } + + // This is for a debugging feature which lets us randomize task selection. Its + // not for production use. + // TODO(crbug.com/1350190): Use a seedable PRNG from ::base if one is added. + uint64_t Random() const { + last_rand_ = MurmurHash3(last_rand_); + return last_rand_; + } + + mutable uint64_t last_rand_; +#endif + const raw_ptr<Observer> observer_; };
diff --git a/base/test/BUILD.gn b/base/test/BUILD.gn index dae5e994..76c6ddc 100644 --- a/base/test/BUILD.gn +++ b/base/test/BUILD.gn
@@ -94,8 +94,6 @@ "scoped_command_line.h", "scoped_feature_list.cc", "scoped_feature_list.h", - "scoped_field_trial_list_resetter.cc", - "scoped_field_trial_list_resetter.h", "scoped_mock_clock_override.cc", "scoped_mock_clock_override.h", "scoped_mock_time_message_loop_task_runner.cc",
diff --git a/base/test/scoped_feature_list.cc b/base/test/scoped_feature_list.cc index 4b786fd..8ccc1f0 100644 --- a/base/test/scoped_feature_list.cc +++ b/base/test/scoped_feature_list.cc
@@ -8,46 +8,156 @@ #include <vector> #include "base/check_op.h" +#include "base/containers/contains.h" +#include "base/containers/cxx20_erase_vector.h" #include "base/memory/ptr_util.h" #include "base/metrics/field_trial_param_associator.h" -#include "base/ranges/algorithm.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_piece.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" +#include "base/strings/stringprintf.h" #include "base/test/mock_entropy_provider.h" #include "base/test/task_environment.h" namespace base { namespace test { +// A struct describes ParsedEnableFeatures()' result. +struct ScopedFeatureList::FeatureWithStudyGroup { + FeatureWithStudyGroup(const std::string& feature_name, + const std::string& study_name, + const std::string& group_name, + const std::string& params) + : feature_name(feature_name), + study_name(study_name), + group_name(group_name), + params(params) { + DCHECK(IsValidFeatureName(feature_name)); + DCHECK(IsValidFeatureOrFieldTrialName(study_name)); + DCHECK(IsValidFeatureOrFieldTrialName(group_name)); + } + + explicit FeatureWithStudyGroup(const std::string& feature_name) + : feature_name(feature_name) { + DCHECK(IsValidFeatureName(feature_name)); + } + + ~FeatureWithStudyGroup() = default; + FeatureWithStudyGroup(const FeatureWithStudyGroup& other) = default; + + bool operator==(const FeatureWithStudyGroup& other) const { + return feature_name == other.feature_name && + StudyNameOrDefault() == other.StudyNameOrDefault() && + GroupNameOrDefault() == other.GroupNameOrDefault(); + } + + std::string FeatureName() const { + return StartsWith(feature_name, "*") ? feature_name.substr(1) + : feature_name; + } + + // If |study_name| is empty, returns a default study name for |feature_name|. + // Otherwise, just return |study_name|. + std::string StudyNameOrDefault() const { + return study_name.empty() ? "Study" + FeatureName() : study_name; + } + + // If |group_name| is empty, returns a default group name for |feature_name|. + // Otherwise, just return |group_name|. + std::string GroupNameOrDefault() const { + return group_name.empty() ? "Group" + FeatureName() : group_name; + } + + bool has_params() const { return !params.empty(); } + + std::string ParamsForFeatureList() const { + if (params.empty()) + return ""; + return ":" + params; + } + + static bool IsValidFeatureOrFieldTrialName(const StringPiece& name) { + return IsStringASCII(name) && + name.find_first_of(",<*") == std::string::npos; + } + + static bool IsValidFeatureName(const StringPiece& feature_name) { + return IsValidFeatureOrFieldTrialName( + StartsWith(feature_name, "*") ? feature_name.substr(1) : feature_name); + } + + // When ParseEnableFeatures() gets + // "FeatureName<StudyName.GroupName:Param1/Value1/Param2/Value2", + // a new FeatureWithStudyGroup with: + // - feature_name = "FeatureName" + // - study_name = "StudyName" + // - group_name = "GroupName" + // - params = "Param1/Value1/Param2/Value2" + // will be created and be returned. + const std::string feature_name; + const std::string study_name; + const std::string group_name; + const std::string params; +}; + +struct ScopedFeatureList::Features { + std::vector<FeatureWithStudyGroup> enabled_feature_list; + std::vector<FeatureWithStudyGroup> disabled_feature_list; +}; + namespace { constexpr char kTrialGroup[] = "scoped_feature_list_trial_group"; -std::vector<StringPiece> GetFeatureVector( - const std::vector<Feature>& features) { - std::vector<StringPiece> output; - for (const Feature& feature : features) { - StringPiece name = feature.name; - // Check against special characters used in ParseEnableFeatures function. - DCHECK_EQ(StringPiece(name).find_first_of(":.<,/"), StringPiece::npos) - << ". Invalid feature name " << name << " with reserved characters."; - output.push_back(name); - } +// Checks and parses the |enable_features| flag and appends each parsed +// feature, an instance of FeatureWithStudyGroup, to |parsed_enable_features|. +// Returns true if |enable_features| is parsable, otherwise false. +// The difference between this function and ParseEnabledFeatures() defined in +// feature_list.cc is: +// if "Feature1<Study1.Group1:Param1/Value1/Param2/Value2," + +// "Feature2<Study2.Group2" is given, +// feature_list.cc's one returns strings: +// parsed_enable_features = "Feature1<Study1,Feature2<Study2" +// force_field_trials = "Study1/Group1" +// force_fieldtrial_params = "Study1<Group1:Param1/Value1/Param2/Value2" +// this function returns a vector: +// [0] FeatureWithStudyGroup("Feature1", "Study1", "Group1", +// "Param1/Value1/Param2/Value2") +// [1] FeatureWithStudyGroup("Feature2", "Study2", "Group2", "") +bool ParseEnableFeatures(const std::string& enable_features, + std::vector<ScopedFeatureList::FeatureWithStudyGroup>& + parsed_enable_features) { + for (const auto& enable_feature : + FeatureList::SplitFeatureListString(enable_features)) { + std::string feature_name; + std::string study; + std::string group; + std::string feature_params; + if (!FeatureList::ParseEnableFeatureString( + enable_feature, &feature_name, &study, &group, &feature_params)) { + return false; + } - return output; + parsed_enable_features.emplace_back(feature_name, study, group, + feature_params); + } + return true; } -std::vector<StringPiece> GetFeatureVectorFromFeaturesAndParams( - const std::vector<ScopedFeatureList::FeatureAndParams>& - features_and_params) { - std::vector<StringPiece> output; - for (const auto& entry : features_and_params) { - output.push_back(entry.feature.name); +// Escapes separators used by enable-features command line. +// E.g. Feature '<' Study '.' Group ':' param1 '/' value1 ',' +// ('*' is not a separator. No need to escape it.) +std::string EscapeValue(const std::string& value) { + std::string escaped_str; + for (const auto ch : value) { + if (ch == ',' || ch == '/' || ch == ':' || ch == '<' || ch == '.') { + escaped_str.append(base::StringPrintf("%%%02X", ch)); + } else { + escaped_str.append(1, ch); + } } - - return output; + return escaped_str; } // Extracts a feature name from a feature state string. For example, given @@ -67,22 +177,17 @@ return feature_name; } -struct Features { - std::vector<StringPiece> enabled_feature_list; - std::vector<StringPiece> disabled_feature_list; -}; - // Features in |feature_vector| came from |merged_features| in // OverrideFeatures() and contains linkage with field trial is case when they // have parameters (with '<' simbol). In |feature_name| name is already cleared // with GetFeatureName() and also could be without parameters. -bool ContainsFeature(const std::vector<StringPiece>& feature_vector, - StringPiece feature_name) { - auto iter = - ranges::find_if(feature_vector, [&feature_name](const StringPiece& a) { - return GetFeatureName(a) == feature_name; - }); - return iter != feature_vector.end(); +bool ContainsFeature( + const std::vector<ScopedFeatureList::FeatureWithStudyGroup>& feature_vector, + StringPiece feature_name) { + return Contains(feature_vector, feature_name, + [](const ScopedFeatureList::FeatureWithStudyGroup& a) { + return a.feature_name; + }); } // Merges previously-specified feature overrides with those passed into one of @@ -90,14 +195,12 @@ // overridden to be in the |override_state|. |merged_features| should contain // the enabled and disabled features passed into the Init() method, plus any // overrides merged as a result of previous calls to this function. -void OverrideFeatures(const std::string& features, - FeatureList::OverrideState override_state, - Features* merged_features) { - std::vector<StringPiece> features_list = - SplitStringPiece(features, ",", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY); - - for (StringPiece feature : features_list) { - StringPiece feature_name = GetFeatureName(feature); +void OverrideFeatures( + const std::vector<ScopedFeatureList::FeatureWithStudyGroup>& features_list, + FeatureList::OverrideState override_state, + ScopedFeatureList::Features* merged_features) { + for (const auto& feature : features_list) { + StringPiece feature_name = GetFeatureName(feature.feature_name); if (ContainsFeature(merged_features->enabled_feature_list, feature_name) || ContainsFeature(merged_features->disabled_feature_list, feature_name)) { @@ -114,6 +217,23 @@ } } +// Merges previously-specified feature overrides with those passed into one of +// the Init() methods. |feature_list| should be a string whose format is the +// same as --enable-features or --disable-features command line flag, and +// specifies features overridden to be in the |override_state|. +// |merged_features| should contain the enabled and disabled features passed in +// to the Init() method, plus any overrides merged as a result of previous +// calls to this function. +void OverrideFeatures(const std::string& features_list, + FeatureList::OverrideState override_state, + ScopedFeatureList::Features* merged_features) { + std::vector<ScopedFeatureList::FeatureWithStudyGroup> parsed_features; + bool parse_enable_features_result = + ParseEnableFeatures(features_list, parsed_features); + DCHECK(parse_enable_features_result); + OverrideFeatures(parsed_features, override_state, merged_features); +} + // Hex encode params so that special characters do not break formatting. std::string HexEncodeString(const std::string& input) { return HexEncode(input.data(), input.size()); @@ -129,6 +249,33 @@ return bytes; } +// Returns a command line string suitable to pass to +// FeatureList::InitializeFromCommandLine(). For example, +// {{"Feature1", "Study1", "Group1", "Param1/Value1/"}, {"Feature2"}} returns: +// - |enabled_feature|=true -> "Feature1<Study1.Group1:Param1/Value1/,Feature2" +// - |enabled_feature|=false -> "Feature1<Study1.Group1,Feature2" +std::string CreateCommandLineArgumentFromFeatureList( + const std::vector<ScopedFeatureList::FeatureWithStudyGroup>& feature_list, + bool enable_features) { + std::vector<std::string> features; + for (const auto& feature : feature_list) { + std::string feature_with_study_group = feature.feature_name; + if (feature.has_params() || !feature.study_name.empty()) { + feature_with_study_group += "<"; + feature_with_study_group += feature.StudyNameOrDefault(); + if (feature.has_params() || !feature.group_name.empty()) { + feature_with_study_group += "."; + feature_with_study_group += feature.GroupNameOrDefault(); + } + if (feature.has_params() && enable_features) { + feature_with_study_group += feature.ParamsForFeatureList(); + } + } + features.push_back(feature_with_study_group); + } + return JoinString(features, ","); +} + } // namespace ScopedFeatureList::FeatureAndParams::FeatureAndParams( @@ -174,20 +321,53 @@ if (field_trial_list_) { field_trial_list_.reset(); + } - // Restore params to how they were before. - FieldTrialParamAssociator::GetInstance()->ClearAllParamsForTesting(); + // Restore params to how they were before. + FieldTrialParamAssociator::GetInstance()->ClearAllParamsForTesting(); + if (!original_params_.empty()) { AssociateFieldTrialParamsFromString(original_params_, &HexDecodeString); + } + if (original_field_trial_list_) { FieldTrialList::RestoreInstanceForTesting(original_field_trial_list_); original_field_trial_list_ = nullptr; } + if (original_feature_list_) FeatureList::RestoreInstanceForTesting(std::move(original_feature_list_)); } void ScopedFeatureList::Init() { - InitWithFeaturesImpl({}, {}, {}); + InitWithFeaturesImpl({}, {}, {}, /*keep_existing_states=*/true); +} + +void ScopedFeatureList::InitWithEmptyFeatureAndFieldTrialLists() { + InitWithFeaturesImpl({}, {}, {}, /*keep_existing_states=*/false); +} + +void ScopedFeatureList::InitWithNullFeatureAndFieldTrialLists() { + DCHECK(!init_called_); + + // Back up the current field trial parameters to be restored in Reset(). + original_params_ = FieldTrialList::AllParamsToString(true, &HexEncodeString); + + // Back up the current field trial list, to be restored in Reset(). + original_field_trial_list_ = FieldTrialList::BackupInstanceForTesting(); + + auto* field_trial_param_associator = FieldTrialParamAssociator::GetInstance(); + field_trial_param_associator->ClearAllParamsForTesting(); + field_trial_list_ = nullptr; + + DCHECK(!original_feature_list_); + + // Execution fence required while modifying FeatureList, as in Reset. + TaskEnvironment::ParallelExecutionFence fence( + "ScopedFeatureList must be Init from the test main thread"); + + // Back up the current feature list, to be restored in Reset(). + original_feature_list_ = FeatureList::ClearInstanceForTesting(); + init_called_ = true; } void ScopedFeatureList::InitWithFeatureList( @@ -206,9 +386,16 @@ void ScopedFeatureList::InitFromCommandLine( const std::string& enable_features, const std::string& disable_features) { - std::unique_ptr<FeatureList> feature_list(new FeatureList); - feature_list->InitializeFromCommandLine(enable_features, disable_features); - InitWithFeatureList(std::move(feature_list)); + Features merged_features; + bool parse_enable_features_result = + ParseEnableFeatures(enable_features, + merged_features.enabled_feature_list) && + ParseEnableFeatures(disable_features, + merged_features.disabled_feature_list); + DCHECK(parse_enable_features_result); + return InitWithMergedFeatures(std::move(merged_features), + /*create_associated_field_trials=*/false, + /*keep_existing_states=*/true); } void ScopedFeatureList::InitWithFeatures( @@ -237,80 +424,43 @@ void ScopedFeatureList::InitWithFeaturesImpl( const std::vector<Feature>& enabled_features, const std::vector<FeatureAndParams>& enabled_features_and_params, - const std::vector<Feature>& disabled_features) { + const std::vector<Feature>& disabled_features, + bool keep_existing_states) { DCHECK(!init_called_); DCHECK(enabled_features.empty() || enabled_features_and_params.empty()); Features merged_features; + bool create_associated_field_trials = false; if (!enabled_features_and_params.empty()) { - merged_features.enabled_feature_list = - GetFeatureVectorFromFeaturesAndParams(enabled_features_and_params); + for (const auto& feature : enabled_features_and_params) { + std::string trial_name = "scoped_feature_list_trial_for_"; + trial_name += feature.feature.name; + + // If features.params has 2 params whose values are value1 and value2, + // |params| will be "param1/value1/param2/value2/". + std::string params; + for (const auto& param : feature.params) { + // Add separator from previous param information if it exists. + if (!params.empty()) + params.append(1, '/'); + params.append(EscapeValue(param.first)); + params.append(1, '/'); + params.append(EscapeValue(param.second)); + } + + merged_features.enabled_feature_list.emplace_back( + feature.feature.name, trial_name, kTrialGroup, params); + } + create_associated_field_trials = true; } else { - merged_features.enabled_feature_list = GetFeatureVector(enabled_features); + for (const auto& feature : enabled_features) + merged_features.enabled_feature_list.emplace_back(feature.name); } - merged_features.disabled_feature_list = GetFeatureVector(disabled_features); + for (const auto& feature : disabled_features) + merged_features.disabled_feature_list.emplace_back(feature.name); - std::string current_enabled_features; - std::string current_disabled_features; - const FeatureList* feature_list = FeatureList::GetInstance(); - if (feature_list) { - feature_list->GetFeatureOverrides(¤t_enabled_features, - ¤t_disabled_features); - } - - // Save off the existing field trials and params. - std::string existing_trial_state; - FieldTrialList::AllStatesToString(&existing_trial_state, true); - original_params_ = FieldTrialList::AllParamsToString(true, &HexEncodeString); - - // Back up the current field trial list, to be restored in Reset(). - original_field_trial_list_ = FieldTrialList::BackupInstanceForTesting(); - - // Create a field trial list, to which we'll add trials corresponding to the - // features that have params, before restoring the field trial state from the - // previous instance, further down in this function. - field_trial_list_ = - std::make_unique<FieldTrialList>(std::make_unique<MockEntropyProvider>()); - - // Associate override params. This needs to be done before trial state gets - // restored, as that will activate trials, locking down param association. - auto* field_trial_param_associator = FieldTrialParamAssociator::GetInstance(); - std::vector<std::string> features_with_trial; - auto feature_it = merged_features.enabled_feature_list.begin(); - for (const auto& enabled_feature : enabled_features_and_params) { - const std::string feature_name = enabled_feature.feature.name; - const std::string trial_name = - "scoped_feature_list_trial_for_" + feature_name; - - scoped_refptr<FieldTrial> field_trial_override = - FieldTrialList::CreateFieldTrial(trial_name, kTrialGroup); - DCHECK(field_trial_override); - - field_trial_param_associator->ClearParamsForTesting(trial_name, - kTrialGroup); - bool success = field_trial_param_associator->AssociateFieldTrialParams( - trial_name, kTrialGroup, enabled_feature.params); - DCHECK(success); - - features_with_trial.push_back(feature_name + "<" + trial_name); - *feature_it = features_with_trial.back(); - ++feature_it; - } - // Restore other field trials. Note: We don't need to do anything for params - // here because the param associator already has the right state, which has - // been backed up via |original_params_| to be restored later. - FieldTrialList::CreateTrialsFromString(existing_trial_state); - - OverrideFeatures(current_enabled_features, - FeatureList::OverrideState::OVERRIDE_ENABLE_FEATURE, - &merged_features); - OverrideFeatures(current_disabled_features, - FeatureList::OverrideState::OVERRIDE_DISABLE_FEATURE, - &merged_features); - - std::string enabled = JoinString(merged_features.enabled_feature_list, ","); - std::string disabled = JoinString(merged_features.disabled_feature_list, ","); - InitFromCommandLine(enabled, disabled); + InitWithMergedFeatures(std::move(merged_features), + create_associated_field_trials, keep_existing_states); } void ScopedFeatureList::InitAndEnableFeatureWithParameters( @@ -325,5 +475,105 @@ InitWithFeaturesImpl({}, enabled_features, disabled_features); } +void ScopedFeatureList::InitWithMergedFeatures( + Features&& merged_features, + bool create_associated_field_trials, + bool keep_existing_states) { + DCHECK(!init_called_); + + std::string current_enabled_features; + std::string current_disabled_features; + const FeatureList* feature_list = FeatureList::GetInstance(); + if (feature_list && keep_existing_states) { + feature_list->GetFeatureOverrides(¤t_enabled_features, + ¤t_disabled_features); + } + + std::vector<FieldTrial::State> all_states = + FieldTrialList::GetAllFieldTrialStates(PassKey()); + original_params_ = FieldTrialList::AllParamsToString(true, &HexEncodeString); + + std::vector<ScopedFeatureList::FeatureWithStudyGroup> + parsed_current_enabled_features; + // Check relationship between current enabled features and field trials. + bool parse_enable_features_result = ParseEnableFeatures( + current_enabled_features, parsed_current_enabled_features); + DCHECK(parse_enable_features_result); + + // Back up the current field trial list, to be restored in Reset(). + original_field_trial_list_ = FieldTrialList::BackupInstanceForTesting(); + + // Create a field trial list, to which we'll add trials corresponding to the + // features that have params, before restoring the field trial state from the + // previous instance, further down in this function. + field_trial_list_ = + std::make_unique<FieldTrialList>(std::make_unique<MockEntropyProvider>()); + + auto* field_trial_param_associator = FieldTrialParamAssociator::GetInstance(); + for (const auto& feature : merged_features.enabled_feature_list) { + // If we don't need to create any field trials for the |feature| (i.e. + // unless |create_associated_field_trials|=true or |feature| has any + // params), we can skip the code: EraseIf()...ClearParamsForTesting(). + if (!(create_associated_field_trials || feature.has_params())) + continue; + + // |all_states| contains the existing field trials, and is used to + // restore the field trials into a newly created field trial list with + // FieldTrialList::CreateTrialsFromFieldTrialStates(). + // However |all_states| may have a field trial that's being explicitly + // set through |merged_features.enabled_feature_list|. In this case, + // FieldTrialParamAssociator::AssociateFieldTrialParams() will fail. + // So remove such field trials from |all_states| here. + EraseIf(all_states, [feature](const auto& state) { + return state.trial_name == feature.StudyNameOrDefault(); + }); + + // If |create_associated_field_trials| is true, we want to match the + // behavior of VariationsFieldTrialCreator to always associate a field + // trial, even when there no params. Since + // FeatureList::InitializeFromCommandLine() doesn't associate a field trial + // when there are no params, we do it here. + if (!feature.has_params()) { + scoped_refptr<FieldTrial> field_trial_without_params = + FieldTrialList::CreateFieldTrial(feature.StudyNameOrDefault(), + feature.GroupNameOrDefault()); + DCHECK(field_trial_without_params); + } + + // Re-assigning field trial parameters is not allowed. Clear + // all field trial parameters. + field_trial_param_associator->ClearParamsForTesting( + feature.StudyNameOrDefault(), feature.GroupNameOrDefault()); + } + + if (keep_existing_states) { + // Restore other field trials. Note: We don't need to do anything for params + // here because the param associator already has the right state for these + // restored trials, which has been backed up via |original_params_| to be + // restored later. + FieldTrialList::CreateTrialsFromFieldTrialStates(PassKey(), all_states); + } else { + // No need to keep existing field trials. Instead, clear all parameters. + field_trial_param_associator->ClearAllParamsForTesting(); + } + + // Create enable-features and disable-features arguments. + OverrideFeatures(parsed_current_enabled_features, + FeatureList::OverrideState::OVERRIDE_ENABLE_FEATURE, + &merged_features); + OverrideFeatures(current_disabled_features, + FeatureList::OverrideState::OVERRIDE_DISABLE_FEATURE, + &merged_features); + + std::string enabled = CreateCommandLineArgumentFromFeatureList( + merged_features.enabled_feature_list, /*enable_features=*/true); + std::string disabled = CreateCommandLineArgumentFromFeatureList( + merged_features.disabled_feature_list, /*enable_features=*/false); + + std::unique_ptr<FeatureList> new_feature_list(new FeatureList); + new_feature_list->InitializeFromCommandLine(enabled, disabled); + InitWithFeatureList(std::move(new_feature_list)); +} + } // namespace test } // namespace base
diff --git a/base/test/scoped_feature_list.h b/base/test/scoped_feature_list.h index ce74be7..53fec2e 100644 --- a/base/test/scoped_feature_list.h +++ b/base/test/scoped_feature_list.h
@@ -15,6 +15,7 @@ #include "base/memory/ref_counted.h" #include "base/metrics/field_trial.h" #include "base/metrics/field_trial_params.h" +#include "base/types/pass_key.h" namespace base { namespace test { @@ -42,6 +43,9 @@ // initialization in the test harness's constructor. class ScopedFeatureList final { public: + struct Features; + struct FeatureWithStudyGroup; + // Constructs the instance in a non-initialized state. ScopedFeatureList(); @@ -67,27 +71,40 @@ void Reset(); // Initializes and registers a FeatureList instance without any additional - // enabled or disabled features. Existing state, if any, will be kept. This is - // equivalent to calling InitWithFeatures({}, {}). + // enabled or disabled features. Existing state, if any, will be kept. + // This is equivalent to calling InitWithFeatures({}, {}). void Init(); + // Initializes a FeatureList instance without any additional enabled or + // disabled features. Existing state, if any, will be discarded. + // Using this function is not generally recommended, as doing so in a test + // removes the ability to run the test while passing additional + // --enable-features flags from the command line. + void InitWithEmptyFeatureAndFieldTrialLists(); + + // Initializes a FeatureList instance and FieldTrialLists to be null and + // clear all field trial parameters. + // WARNING: This should not be generally used except for tests that require + // manually instantiating objects like FieldTrialList, for example when + // mocking an EntropyProvider. + void InitWithNullFeatureAndFieldTrialLists(); + // WARNING: This method will reset any globally configured features to their // default values, which can hide feature interaction bugs. Please use // sparingly. https://crbug.com/713390 // Initializes and registers the given FeatureList instance. void InitWithFeatureList(std::unique_ptr<FeatureList> feature_list); - // WARNING: This method will reset any globally configured features to their - // default values, which can hide feature interaction bugs. Please use - // sparingly. https://crbug.com/713390 - // Initializes and registers a FeatureList instance with only the given - // enabled and disabled features (comma-separated names). If feature params - // are provided in the |enable_features|, this also associates features to - // their params. + // Initializes and registers a FeatureList instance based on the current + // FeatureList and overridden with the given enabled features and the + // specified field trial parameters, and the given disabled features + // with the given enabled and disabled features (comma-separated names). + // Note: This creates a scoped global field trial list if there is not + // currently one. void InitFromCommandLine(const std::string& enable_features, const std::string& disable_features); - // Initializes and registers a FeatureList instance based on present + // Initializes and registers a FeatureList instance based on the current // FeatureList and overridden with the given enabled and disabled features. // Any feature overrides already present in the global FeatureList will // continue to apply, unless they conflict with the overrides passed into this @@ -96,11 +113,11 @@ void InitWithFeatures(const std::vector<Feature>& enabled_features, const std::vector<Feature>& disabled_features); - // Initializes and registers a FeatureList instance based on present + // Initializes and registers a FeatureList instance based on the current // FeatureList and overridden with single enabled feature. void InitAndEnableFeature(const Feature& feature); - // Initializes and registers a FeatureList instance based on present + // Initializes and registers a FeatureList instance based on the current // FeatureList and overridden with single enabled feature and associated field // trial parameters. // Note: this creates a scoped global field trial list if there is not @@ -109,7 +126,7 @@ const Feature& feature, const FieldTrialParams& feature_parameters); - // Initializes and registers a FeatureList instance based on present + // Initializes and registers a FeatureList instance based on the current // FeatureList and overridden with the given enabled features and the // specified field trial parameters, and the given disabled features. // Note: This creates a scoped global field trial list if there is not @@ -118,17 +135,19 @@ const std::vector<FeatureAndParams>& enabled_features, const std::vector<Feature>& disabled_features); - // Initializes and registers a FeatureList instance based on present + // Initializes and registers a FeatureList instance based on the current // FeatureList and overridden with single disabled feature. void InitAndDisableFeature(const Feature& feature); - // Initializes and registers a FeatureList instance based on present - // FeatureList and overriden with a single feature either enabled or + // Initializes and registers a FeatureList instance based on the current + // FeatureList and overridden with a single feature either enabled or // disabled depending on |enabled|. void InitWithFeatureState(const Feature& feature, bool enabled); private: - // Initializes and registers a FeatureList instance based on present + using PassKey = PassKey<ScopedFeatureList>; + + // Initializes and registers a FeatureList instance based on the current // FeatureList and overridden with the given enabled and disabled features. // Any feature overrides already present in the global FeatureList will // continue to apply, unless they conflict with the overrides passed into this @@ -139,7 +158,23 @@ void InitWithFeaturesImpl( const std::vector<Feature>& enabled_features, const std::vector<FeatureAndParams>& enabled_features_and_params, - const std::vector<Feature>& disabled_features); + const std::vector<Feature>& disabled_features, + bool keep_existing_states = true); + + // Initializes and registers a FeatureList instance based on the current + // FeatureList and overridden with the given enabled and disabled features. + // Any feature overrides already present in the global FeatureList will + // continue to apply, unless they conflict with the overrides passed into this + // method. + // If |create_associated_field_trials| is true, associated field trials are + // always created independent of feature parameters. If false, field trials + // for features whose parameters are specified will be created. + // If |keep_existing_states| is true, keep all states and override them + // according to the |merged_features|. Otherwise, clear all states and + // newly initialize all states with |merged_features|. + void InitWithMergedFeatures(Features&& merged_features, + bool create_associated_field_trials, + bool keep_existing_states); bool init_called_ = false; std::unique_ptr<FeatureList> original_feature_list_;
diff --git a/base/test/scoped_feature_list_unittest.cc b/base/test/scoped_feature_list_unittest.cc index b0e4e81..b28a2d23 100644 --- a/base/test/scoped_feature_list_unittest.cc +++ b/base/test/scoped_feature_list_unittest.cc
@@ -33,6 +33,16 @@ EXPECT_EQ(disabled_features, actual_disabled_features); } +std::string GetActiveFieldTrialGroupName(const std::string trial_name) { + FieldTrial::ActiveGroups groups; + FieldTrialList::GetActiveFieldTrialGroups(&groups); + for (const auto& group : groups) { + if (group.trial_name == trial_name) + return group.group_name; + } + return std::string(); +} + } // namespace class ScopedFeatureListTest : public testing::Test { @@ -164,21 +174,33 @@ FieldTrialList::CreateFieldTrial("foo", "bar"); const char kParam[] = "param_1"; const char kValue[] = "value_1"; + const char kValue0[] = "value_0"; std::map<std::string, std::string> parameters; parameters[kParam] = kValue; test::ScopedFeatureList feature_list1; - feature_list1.InitFromCommandLine("TestFeature1<foo,TestFeature2", - std::string()); + feature_list1.InitFromCommandLine( + "TestFeature1<foo.bar:param_1/value_0,TestFeature2", std::string()); // Check initial state. ExpectFeatures("TestFeature1<foo,TestFeature2", std::string()); EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1)); EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2)); - EXPECT_EQ(trial.get(), FeatureList::GetFieldTrial(kTestFeature1)); + // ScopedFeatureList always scope features, field trials and their associated + // parameters. So ScopedFeatureList::InitFromCommandLine() creates another + // FieldTrial instance whose trial name, group name and associated parameters + // are the same as |trial|, and changes |kTestFeature1|'s field trial to + // be the newly created one. + EXPECT_NE(trial.get(), FeatureList::GetFieldTrial(kTestFeature1)); EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kTestFeature2)); - EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature1, kParam)); + EXPECT_EQ(kValue0, GetFieldTrialParamValueByFeature(kTestFeature1, kParam)); EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam)); + EXPECT_EQ("bar", GetActiveFieldTrialGroupName("foo")); + + FieldTrial* trial_for_test_feature1 = + FeatureList::GetFieldTrial(kTestFeature1); + EXPECT_EQ("foo", trial_for_test_feature1->trial_name()); + EXPECT_EQ("bar", trial_for_test_feature1->group_name()); { // Override feature with existing field trial. @@ -190,18 +212,43 @@ EXPECT_EQ(kValue, GetFieldTrialParamValueByFeature(kTestFeature1, kParam)); EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam)); EXPECT_NE(trial.get(), FeatureList::GetFieldTrial(kTestFeature1)); + EXPECT_NE(trial_for_test_feature1, + FeatureList::GetFieldTrial(kTestFeature1)); EXPECT_NE(nullptr, FeatureList::GetFieldTrial(kTestFeature1)); EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kTestFeature2)); } + { + // Override feature with existing field trial. + test::ScopedFeatureList feature_list2; + + feature_list2.InitFromCommandLine("TestFeature1<foo.bar2:param_1/value_1", + std::string()); + EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1)); + EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2)); + EXPECT_EQ(kValue, GetFieldTrialParamValueByFeature(kTestFeature1, kParam)); + EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam)); + EXPECT_NE(trial.get(), FeatureList::GetFieldTrial(kTestFeature1)); + EXPECT_NE(trial_for_test_feature1, + FeatureList::GetFieldTrial(kTestFeature1)); + EXPECT_NE(nullptr, FeatureList::GetFieldTrial(kTestFeature1)); + EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kTestFeature2)); + + // foo's active group is now bar2, not bar. + EXPECT_TRUE(FieldTrialList::IsTrialActive("foo")); + EXPECT_EQ("bar2", GetActiveFieldTrialGroupName("foo")); + } + // Check that initial state is restored. ExpectFeatures("TestFeature1<foo,TestFeature2", std::string()); EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1)); EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2)); - EXPECT_EQ(trial.get(), FeatureList::GetFieldTrial(kTestFeature1)); + EXPECT_EQ(trial_for_test_feature1, FeatureList::GetFieldTrial(kTestFeature1)); EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kTestFeature2)); - EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature1, kParam)); + EXPECT_EQ(kValue0, GetFieldTrialParamValueByFeature(kTestFeature1, kParam)); EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam)); + // foo's active group is bar, because initial state is restored. + EXPECT_EQ("bar", GetActiveFieldTrialGroupName("foo")); { // Override feature with no existing field trial. @@ -210,11 +257,11 @@ feature_list2.InitAndEnableFeatureWithParameters(kTestFeature2, parameters); EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1)); EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2)); - EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature1, kParam)); + EXPECT_EQ(kValue0, GetFieldTrialParamValueByFeature(kTestFeature1, kParam)); EXPECT_EQ(kValue, GetFieldTrialParamValueByFeature(kTestFeature2, kParam)); - EXPECT_EQ(trial.get()->trial_name(), + EXPECT_EQ(trial_for_test_feature1->trial_name(), FeatureList::GetFieldTrial(kTestFeature1)->trial_name()); - EXPECT_EQ(trial.get()->group_name(), + EXPECT_EQ(trial_for_test_feature1->group_name(), FeatureList::GetFieldTrial(kTestFeature1)->group_name()); EXPECT_NE(nullptr, FeatureList::GetFieldTrial(kTestFeature2)); } @@ -223,16 +270,129 @@ ExpectFeatures("TestFeature1<foo,TestFeature2", std::string()); EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1)); EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2)); - EXPECT_EQ(trial.get(), FeatureList::GetFieldTrial(kTestFeature1)); + EXPECT_EQ(trial_for_test_feature1, FeatureList::GetFieldTrial(kTestFeature1)); EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kTestFeature2)); - EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature1, kParam)); + EXPECT_EQ(kValue0, GetFieldTrialParamValueByFeature(kTestFeature1, kParam)); EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam)); } +TEST_F(ScopedFeatureListTest, OverrideWithFeatureMultipleParameters) { + const char kParam1[] = "param_1"; + const char kValue1[] = "value_1"; + const char kParam2[] = "param_2"; + const char kValue2[] = "value_2"; + const char kValue3[] = "value_3"; + std::map<std::string, std::string> parameters; + parameters[kParam1] = kValue3; + + test::ScopedFeatureList feature_list1; + feature_list1.InitFromCommandLine( + "TestFeature1<foo.bar:param_1/value_1/param_2/" + "value_2,TestFeature2:param_1/value_2", + std::string()); + + // Check initial state. + ExpectFeatures("TestFeature1<foo,TestFeature2<StudyTestFeature2", + std::string()); + EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1)); + EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2)); + EXPECT_NE(nullptr, FeatureList::GetFieldTrial(kTestFeature1)); + EXPECT_NE(nullptr, FeatureList::GetFieldTrial(kTestFeature2)); + EXPECT_EQ(kValue1, GetFieldTrialParamValueByFeature(kTestFeature1, kParam1)); + EXPECT_EQ(kValue2, GetFieldTrialParamValueByFeature(kTestFeature1, kParam2)); + EXPECT_EQ(kValue2, GetFieldTrialParamValueByFeature(kTestFeature2, kParam1)); + EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam2)); + + FieldTrial* trial = FieldTrialList::Find("foo"); + EXPECT_EQ("bar", trial->GetGroupNameWithoutActivation()); + EXPECT_EQ("bar", GetActiveFieldTrialGroupName("foo")); + + FieldTrial* trial2 = FieldTrialList::Find("StudyTestFeature2"); + EXPECT_EQ("GroupTestFeature2", trial2->GetGroupNameWithoutActivation()); + EXPECT_EQ("GroupTestFeature2", + GetActiveFieldTrialGroupName("StudyTestFeature2")); + + { + // Override feature with existing field trial. + test::ScopedFeatureList feature_list2; + + feature_list2.InitAndEnableFeatureWithParameters(kTestFeature1, parameters); + EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1)); + EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2)); + EXPECT_EQ(kValue3, + GetFieldTrialParamValueByFeature(kTestFeature1, kParam1)); + // param_2 is not set. + EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature1, kParam2)); + EXPECT_EQ(kValue2, + GetFieldTrialParamValueByFeature(kTestFeature2, kParam1)); + EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam2)); + EXPECT_NE(trial, FeatureList::GetFieldTrial(kTestFeature1)); + EXPECT_NE(nullptr, FeatureList::GetFieldTrial(kTestFeature1)); + EXPECT_NE(trial2, FeatureList::GetFieldTrial(kTestFeature2)); + EXPECT_NE(nullptr, FeatureList::GetFieldTrial(kTestFeature2)); + } + + // Check that initial state is restored. + ExpectFeatures("TestFeature1<foo,TestFeature2<StudyTestFeature2", + std::string()); + EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1)); + EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2)); + EXPECT_EQ(trial, FeatureList::GetFieldTrial(kTestFeature1)); + EXPECT_EQ(trial2, FeatureList::GetFieldTrial(kTestFeature2)); + EXPECT_EQ(kValue1, GetFieldTrialParamValueByFeature(kTestFeature1, kParam1)); + EXPECT_EQ(kValue2, GetFieldTrialParamValueByFeature(kTestFeature1, kParam2)); + EXPECT_EQ(kValue2, GetFieldTrialParamValueByFeature(kTestFeature2, kParam1)); + EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam2)); + // foo's active group is bar, because initial state is restored. + EXPECT_EQ("bar", GetActiveFieldTrialGroupName("foo")); + EXPECT_EQ("GroupTestFeature2", + GetActiveFieldTrialGroupName("StudyTestFeature2")); + + { + // Override feature with existing field trial. + test::ScopedFeatureList feature_list2; + + feature_list2.InitFromCommandLine("TestFeature1<foo.bar2:param_2/value_3", + std::string()); + EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1)); + EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2)); + EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature1, kParam1)); + EXPECT_EQ(kValue3, + GetFieldTrialParamValueByFeature(kTestFeature1, kParam2)); + EXPECT_EQ(kValue2, + GetFieldTrialParamValueByFeature(kTestFeature2, kParam1)); + EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam2)); + EXPECT_NE(trial, FeatureList::GetFieldTrial(kTestFeature1)); + EXPECT_NE(nullptr, FeatureList::GetFieldTrial(kTestFeature1)); + EXPECT_EQ("foo", FeatureList::GetFieldTrial(kTestFeature1)->trial_name()); + EXPECT_EQ("bar2", FeatureList::GetFieldTrial(kTestFeature1)->group_name()); + EXPECT_NE(trial2, FeatureList::GetFieldTrial(kTestFeature2)); + EXPECT_NE(nullptr, FeatureList::GetFieldTrial(kTestFeature2)); + + // foo's active group is now bar2, not bar. + EXPECT_TRUE(FieldTrialList::IsTrialActive("foo")); + EXPECT_EQ("bar2", GetActiveFieldTrialGroupName("foo")); + } + + // Check that initial state is restored. + ExpectFeatures("TestFeature1<foo,TestFeature2<StudyTestFeature2", + std::string()); + EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1)); + EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2)); + EXPECT_EQ(trial, FeatureList::GetFieldTrial(kTestFeature1)); + EXPECT_EQ(trial2, FeatureList::GetFieldTrial(kTestFeature2)); + EXPECT_EQ(kValue1, GetFieldTrialParamValueByFeature(kTestFeature1, kParam1)); + EXPECT_EQ(kValue2, GetFieldTrialParamValueByFeature(kTestFeature1, kParam2)); + EXPECT_EQ(kValue2, GetFieldTrialParamValueByFeature(kTestFeature2, kParam1)); + EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam2)); + EXPECT_EQ("bar", GetActiveFieldTrialGroupName("foo")); +} + TEST_F(ScopedFeatureListTest, OverrideMultipleFeaturesWithParameters) { scoped_refptr<FieldTrial> trial1 = FieldTrialList::CreateFieldTrial("foo1", "bar1"); const char kParam[] = "param_1"; + const char kValue0[] = "value_0"; const char kValue1[] = "value_1"; const char kValue2[] = "value_2"; std::map<std::string, std::string> parameters1; @@ -241,8 +401,8 @@ parameters2[kParam] = kValue2; test::ScopedFeatureList feature_list1; - feature_list1.InitFromCommandLine("TestFeature1<foo1,TestFeature2", - std::string()); + feature_list1.InitFromCommandLine( + "TestFeature1<foo1:param_1/value_0,TestFeature2", std::string()); // Check initial state. ExpectFeatures("TestFeature1<foo1,TestFeature2", std::string()); @@ -250,9 +410,21 @@ EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2)); EXPECT_EQ("foo1", FeatureList::GetFieldTrial(kTestFeature1)->trial_name()); EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kTestFeature2)); - EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature1, kParam)); + EXPECT_EQ(kValue0, GetFieldTrialParamValueByFeature(kTestFeature1, kParam)); EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam)); + // InitFromCommandLine() scopes field trials. + FieldTrial* trial = FieldTrialList::Find("foo1"); + // --enable-features will create a group whose name is "Group" + feature + // name if no group name is specified. In this case, the feature name is + // "TestFeature1". So the group name is "GroupTestFeature1". + EXPECT_EQ("GroupTestFeature1", trial->GetGroupNameWithoutActivation()); + EXPECT_NE(trial1.get(), trial); + // Because of "scoped", "bar1" disappears. Instead, "GroupTestFeature1" + // is created and activated. + EXPECT_NE("bar1", GetActiveFieldTrialGroupName("foo1")); + EXPECT_EQ("GroupTestFeature1", GetActiveFieldTrialGroupName("foo1")); + { // Override multiple features with parameters. test::ScopedFeatureList feature_list2; @@ -281,9 +453,9 @@ ExpectFeatures("TestFeature1<foo1,TestFeature2", std::string()); EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1)); EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2)); - EXPECT_EQ(trial1.get(), FeatureList::GetFieldTrial(kTestFeature1)); + EXPECT_EQ(trial, FeatureList::GetFieldTrial(kTestFeature1)); EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kTestFeature2)); - EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature1, kParam)); + EXPECT_EQ(kValue0, GetFieldTrialParamValueByFeature(kTestFeature1, kParam)); EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam)); }
diff --git a/base/test/scoped_field_trial_list_resetter.cc b/base/test/scoped_field_trial_list_resetter.cc deleted file mode 100644 index 0bc657b..0000000 --- a/base/test/scoped_field_trial_list_resetter.cc +++ /dev/null
@@ -1,21 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/test/scoped_field_trial_list_resetter.h" - -#include "base/metrics/field_trial.h" - -namespace base { -namespace test { - -ScopedFieldTrialListResetter::ScopedFieldTrialListResetter() - : original_field_trial_list_( - base::FieldTrialList::BackupInstanceForTesting()) {} - -ScopedFieldTrialListResetter::~ScopedFieldTrialListResetter() { - base::FieldTrialList::RestoreInstanceForTesting(original_field_trial_list_); -} - -} // namespace test -} // namespace base
diff --git a/base/test/scoped_field_trial_list_resetter.h b/base/test/scoped_field_trial_list_resetter.h deleted file mode 100644 index 113b308..0000000 --- a/base/test/scoped_field_trial_list_resetter.h +++ /dev/null
@@ -1,38 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_TEST_SCOPED_FIELD_TRIAL_LIST_RESETTER_H_ -#define BASE_TEST_SCOPED_FIELD_TRIAL_LIST_RESETTER_H_ - -#include "base/memory/raw_ptr.h" - -namespace base { - -class FieldTrialList; - -namespace test { - -// DISCLAIMER: Please use ScopedFeatureList except for advanced cases where -// custom instantiation of FieldTrialList is required. -// -// ScopedFieldTrialListResetter resets the global FieldTrialList instance to -// null, and restores the original state when the class goes out of scope. This -// allows client code to initialize FieldTrialList instances in a custom -// fashion. -class ScopedFieldTrialListResetter final { - public: - ScopedFieldTrialListResetter(); - ScopedFieldTrialListResetter(const ScopedFieldTrialListResetter&) = delete; - ScopedFieldTrialListResetter(ScopedFieldTrialListResetter&&) = delete; - - ~ScopedFieldTrialListResetter(); - - private: - const raw_ptr<base::FieldTrialList> original_field_trial_list_; -}; - -} // namespace test -} // namespace base - -#endif // BASE_TEST_SCOPED_FIELD_TRIAL_LIST_RESETTER_H_
diff --git a/base/test/test_suite.cc b/base/test/test_suite.cc index dfaf349..2b749fb 100644 --- a/base/test/test_suite.cc +++ b/base/test/test_suite.cc
@@ -136,13 +136,12 @@ delete; void OnTestStart(const testing::TestInfo& test_info) override { - field_trial_list_ = std::make_unique<FieldTrialList>( - std::make_unique<MockEntropyProvider>()); - const CommandLine* command_line = CommandLine::ForCurrentProcess(); - // Set up a FeatureList instance, so that code using that API will not hit a - // an error that it's not set. It will be cleared automatically. + // We set up a FeatureList via ScopedFeatureList::InitFromCommandLine(). + // This ensures that code using that API will not hit an error that it's + // not set. It will be cleared by ~ScopedFeatureList(). + // TestFeatureForBrowserTest1 and TestFeatureForBrowserTest2 used in // ContentBrowserTestScopedFeatureListTest to ensure ScopedFeatureList keeps // features from command line. @@ -172,11 +171,9 @@ void OnTestEnd(const testing::TestInfo& test_info) override { scoped_feature_list_.Reset(); - field_trial_list_.reset(); } private: - std::unique_ptr<FieldTrialList> field_trial_list_; test::ScopedFeatureList scoped_feature_list_; };
diff --git a/base/values.cc b/base/values.cc index a45a70d..3da8944 100644 --- a/base/values.cc +++ b/base/values.cc
@@ -1588,10 +1588,6 @@ return Set(path, std::make_unique<Value>(in_value)); } -Value* DictionaryValue::SetDouble(StringPiece path, double in_value) { - return Set(path, std::make_unique<Value>(in_value)); -} - Value* DictionaryValue::SetString(StringPiece path, StringPiece in_value) { return Set(path, std::make_unique<Value>(in_value)); }
diff --git a/base/values.h b/base/values.h index 3c0ee7b..8de97f5 100644 --- a/base/values.h +++ b/base/values.h
@@ -1292,10 +1292,6 @@ // DEPRECATED: prefer `Value::Dict::Set()` (if the path only has one // component, i.e. has no dots), or `Value::Dict::SetByDottedPath()` // otherwise. - Value* SetDouble(StringPiece path, double in_value); - // DEPRECATED: prefer `Value::Dict::Set()` (if the path only has one - // component, i.e. has no dots), or `Value::Dict::SetByDottedPath()` - // otherwise. Value* SetString(StringPiece path, StringPiece in_value); // DEPRECATED: prefer `Value::Dict::Set()` (if the path only has one // component, i.e. has no dots), or `Value::Dict::SetByDottedPath()`
diff --git a/base/values_unittest.cc b/base/values_unittest.cc index 51861891..5b5979d 100644 --- a/base/values_unittest.cc +++ b/base/values_unittest.cc
@@ -1603,13 +1603,6 @@ { DictionaryValue dict; - Value* double_ptr = dict.SetDouble("foo.bar", 3.142); - EXPECT_EQ(Value::Type::DOUBLE, double_ptr->type()); - EXPECT_EQ(3.142, double_ptr->GetDouble()); - } - - { - DictionaryValue dict; Value* string_ptr = dict.SetString("foo.bar", "foo"); EXPECT_EQ(Value::Type::STRING, string_ptr->type()); EXPECT_EQ("foo", string_ptr->GetString());
diff --git a/build/fuchsia/linux_internal.sdk.sha1 b/build/fuchsia/linux_internal.sdk.sha1 index fb02c42..884cfb2 100644 --- a/build/fuchsia/linux_internal.sdk.sha1 +++ b/build/fuchsia/linux_internal.sdk.sha1
@@ -1 +1 @@ -9.20220803.1.1 +9.20220805.1.1
diff --git a/build/lacros/lacros_resource_sizes.py b/build/lacros/lacros_resource_sizes.py index c13b8923..8dfe194 100755 --- a/build/lacros/lacros_resource_sizes.py +++ b/build/lacros/lacros_resource_sizes.py
@@ -105,6 +105,8 @@ title='File: chrome_crashpad_handler'), _Group(paths=['icudtl.dat'], title='File: icudtl.dat'), _Group(paths=['icudtl.dat.hash'], title='File: icudtl.dat.hash'), + _Group(paths=['libEGL.so'], title='File: libEGL.so'), + _Group(paths=['libGLESv2.so'], title='File: libGLESv2.so'), _Group(paths=['nacl_helper'], title='File: nacl_helper'), _Group(paths=['resources.pak'], title='File: resources.pak'), _Group(paths=[
diff --git a/buildtools/deps_revisions.gni b/buildtools/deps_revisions.gni index 5b09a5a..a592fe0 100644 --- a/buildtools/deps_revisions.gni +++ b/buildtools/deps_revisions.gni
@@ -5,5 +5,5 @@ declare_args() { # Used to cause full rebuilds on libc++ rolls. This should be kept in sync # with the libcxx_revision vars in //DEPS. - libcxx_revision = "e3598c2dc07b5a5320fd3fedb8a4afaa95f09142" + libcxx_revision = "a47a05b6a096e53f529c6cec03915b4a0c0bce2c" }
diff --git a/buildtools/third_party/libc++/BUILD.gn b/buildtools/third_party/libc++/BUILD.gn index 4fec8db3..01f5a17 100644 --- a/buildtools/third_party/libc++/BUILD.gn +++ b/buildtools/third_party/libc++/BUILD.gn
@@ -73,7 +73,6 @@ sources = [ "trunk/src/algorithm.cpp", "trunk/src/any.cpp", - "trunk/src/assert.cpp", "trunk/src/atomic.cpp", "trunk/src/barrier.cpp", "trunk/src/bind.cpp", @@ -115,6 +114,7 @@ "trunk/src/valarray.cpp", "trunk/src/variant.cpp", "trunk/src/vector.cpp", + "trunk/src/verbose_abort.cpp", ] include_dirs = [ "trunk/src" ] if (is_win) {
diff --git a/cc/metrics/frame_sequence_tracker_collection.h b/cc/metrics/frame_sequence_tracker_collection.h index f80ca158..f8b023e 100644 --- a/cc/metrics/frame_sequence_tracker_collection.h +++ b/cc/metrics/frame_sequence_tracker_collection.h
@@ -169,7 +169,7 @@ NotifyCustomerTrackerResutlsCallback custom_tracker_results_added_callback_; std::vector<std::unique_ptr<FrameSequenceTracker>> removal_trackers_; - const raw_ptr<CompositorFrameReportingController, DanglingUntriaged> + const raw_ptr<CompositorFrameReportingController> compositor_frame_reporting_controller_; base::flat_map<
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index 23c2ea10..9685623 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc
@@ -405,12 +405,6 @@ scheduling_client_(scheduling_client), task_runner_provider_(task_runner_provider), current_begin_frame_tracker_(FROM_HERE), - compositor_frame_reporting_controller_( - std::make_unique<CompositorFrameReportingController>( - /*should_report_histograms=*/!settings - .single_thread_proxy_scheduler, - /*should_report_ukm=*/!settings.single_thread_proxy_scheduler, - id)), settings_(settings), is_synchronous_single_threaded_(!task_runner_provider->HasImplThread() && !settings_.single_thread_proxy_scheduler), @@ -439,6 +433,12 @@ this, settings_.enable_image_animation_resync), paint_image_generator_client_id_(PaintImage::GetNextGeneratorClientId()), + compositor_frame_reporting_controller_( + std::make_unique<CompositorFrameReportingController>( + /*should_report_histograms=*/!settings + .single_thread_proxy_scheduler, + /*should_report_ukm=*/!settings.single_thread_proxy_scheduler, + id)), frame_trackers_(settings.single_thread_proxy_scheduler, compositor_frame_reporting_controller_.get()), lcd_text_metrics_reporter_(LCDTextMetricsReporter::CreateIfNeeded(this)), @@ -533,7 +533,15 @@ // Clear the UKM Manager so that we do not try to report when the // UKM System has shut down. compositor_frame_reporting_controller_->SetUkmManager(nullptr); - compositor_frame_reporting_controller_ = nullptr; + // `frame_trackers_` holds a pointer to + // `compositor_frame_reporting_controller_`. Setting + // `compositor_frame_reporting_controller_` to nullptr here leads to + // `frame_trackers_` holding a dangling ptr. Don't set to null here and let + // members be destroyed in reverse order of declaration. + // Since `frame_trackers_` is destroyed first, we need to clear the ptr that + // `compositor_frame_reporting_controller_` holds. + compositor_frame_reporting_controller_->SetFrameSequenceTrackerCollection( + nullptr); } InputHandler& LayerTreeHostImpl::GetInputHandler() {
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h index 500737d1..27d46966 100644 --- a/cc/trees/layer_tree_host_impl.h +++ b/cc/trees/layer_tree_host_impl.h
@@ -934,9 +934,6 @@ BeginFrameTracker current_begin_frame_tracker_; - std::unique_ptr<CompositorFrameReportingController> - compositor_frame_reporting_controller_; - private: viz::CompositorFrame GenerateCompositorFrame(FrameData* frame); @@ -1131,8 +1128,12 @@ std::unique_ptr<PageScaleAnimation> page_scale_animation_; - DroppedFrameCounter dropped_frame_counter_; + base::WritableSharedMemoryMapping ukm_smoothness_mapping_; + TotalFrameCounter total_frame_counter_; + // `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_; @@ -1245,6 +1246,10 @@ const PaintImage::GeneratorClientId paint_image_generator_client_id_; + // `compositor_frame_reporting_controller_` has a dependency on + // `dropped_frame_counter_` so it must be declared last and deleted first; + std::unique_ptr<CompositorFrameReportingController> + compositor_frame_reporting_controller_; FrameSequenceTrackerCollection frame_trackers_; // PaintWorklet painting is controlled from the LayerTreeHostImpl, dispatched @@ -1295,8 +1300,6 @@ // DroppedFrameCounter. Currently true when first contentful paint is done. bool is_measuring_smoothness_ = false; - base::WritableSharedMemoryMapping ukm_smoothness_mapping_; - // 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/chrome/VERSION b/chrome/VERSION index c111fbf..8eba71a 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=106 MINOR=0 -BUILD=5221 +BUILD=5222 PATCH=0
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryManager.java b/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryManager.java index a3ee8a9..5688009c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryManager.java
@@ -336,7 +336,7 @@ mToolbar.getMenu() .findItem(R.id.optout_menu_id) .setTitle(R.string.history_clusters_enable_menu_item_label); - if (mContentView == mHistoryClustersCoordinator.getActivityContentView()) { + if (isHistoryClustersUIShowing()) { swapContentView(); } mShowHistoryClustersToggleSupplier.set(false); @@ -503,13 +503,15 @@ private void swapContentView() { if (shouldShowIncognitoPlaceholder()) { return; - } else if (mContentView == mSelectableListLayout && mHistoryClustersCoordinator != null) { - mContentView = mHistoryClustersCoordinator.getActivityContentView(); - mHistoryClustersCoordinator.onToggled(true); - } else { + } else if (isHistoryClustersUIShowing()) { mHistoryClustersCoordinator.onToggled(false); mContentView = mSelectableListLayout; mContentManager.startLoadingItems(); + } else { + assert mHistoryClustersCoordinator + != null : "swapContentView() shouldn't be called if HistoryClusters is off"; + mContentView = mHistoryClustersCoordinator.getActivityContentView(); + mHistoryClustersCoordinator.onToggled(true); } Transition transition = new AutoTransition(); @@ -519,6 +521,11 @@ mContentView.requestFocus(); } + private boolean isHistoryClustersUIShowing() { + return mHistoryClustersCoordinator != null + && mContentView == mHistoryClustersCoordinator.getActivityContentView(); + } + /** * Called when the activity/native page is destroyed. */ @@ -546,7 +553,10 @@ if (shouldShowIncognitoPlaceholder() || mSelectableListLayout == null) { // If Incognito placeholder is shown, the back press should handled by HistoryActivity. return false; + } else if (isHistoryClustersUIShowing()) { + return mHistoryClustersCoordinator.onBackPressed(); } + return mSelectableListLayout.onBackPressed(); }
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 4406786b..dc4a0cf5 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -13378,8 +13378,8 @@ <message name="IDS_PRIVACY_SANDBOX_DIALOG_CONSENT_BODY_HEADER_1" desc="1 of 2 subtitles on the page. We want to write for users who skim the page. That means that the page title, the sub titles, and the button label all work well together as a mini story: 1) Help us build a more private web How? 2) Limit sharing between sites 3) More control over the ads you see 4) Yes, I’ll try it"> Limited sharing between sites </message> - <message name="IDS_PRIVACY_SANDBOX_BUBBLE_NOTICE_DESCRIPTION" desc="The body text of the bubble. * “ad spam”: spam related to web advertising"> - Chrome is exploring ways to limit ad spam, fraud, and sharing between sites. Chrome also <ph name="ESTIMATE_INTERESTS_LINK">$1<ex>estimates your interests</ex></ph> that sites can use to show you ads. You can manage your interests in settings. + <message name="IDS_PRIVACY_SANDBOX_BUBBLE_NOTICE_DESCRIPTION" desc="The body text of the bubble.* “Chrome is finding new ways”: “finding” is meant to convey a work in progress, like “build” in the title. The features are live and functional, but still in beta. So we want a verb that’s stronger than “exploring” but weaker than “launching”. * “reduce tracking”: This used to read “reduce cross-site tracking”, but we’ve dropped “cross-site” because it makes the idea unnecessarily complicated. * “estimate your interests”: Topics of interest include things like “Live comedy” and “Rock music”. Chrome estimates these interests based on the sites users visit. It’s an “estimation”, and we don’t want to suggest that we know with certainty the user’s interests. Avoid words like “guess”, “establish”, “define”, etc. (in place of “estimate”). * “Then” is an important keyword. It suggests some amount of time later. The first step is that interests are generated. Later (minutes or weeks), a different site might request interests."> + Chrome is finding new ways to reduce tracking and keep you even safer as you browse. Chrome also <ph name="ESTIMATE_INTERESTS_LINK">$1<ex>estimates your interests</ex></ph> and enables you to manage them. Then, sites you visit can ask Chrome for your interests to show you ads. </message> <message name="IDS_PRIVACY_SANDBOX_BUBBLE_NOTICE_SETTINGS_LINK" desc="The user can choose “Go to settings” to visit chrome://settings/privacySandbox. If they do, they’ll find the toggle on for Sandbox trials, which include everything they’ve read above. They can leave trials on or turn them off on this page. Choosing “Go to settings”, the user will navigate away from this page and won’t be able to return here."> Go to settings
diff --git a/chrome/app/generated_resources_grd/IDS_PRIVACY_SANDBOX_BUBBLE_NOTICE_DESCRIPTION.png.sha1 b/chrome/app/generated_resources_grd/IDS_PRIVACY_SANDBOX_BUBBLE_NOTICE_DESCRIPTION.png.sha1 index cbacdf0..439bf40 100644 --- a/chrome/app/generated_resources_grd/IDS_PRIVACY_SANDBOX_BUBBLE_NOTICE_DESCRIPTION.png.sha1 +++ b/chrome/app/generated_resources_grd/IDS_PRIVACY_SANDBOX_BUBBLE_NOTICE_DESCRIPTION.png.sha1
@@ -1 +1 @@ -7650a622362ae8d000e8515b206d09d7770d945f \ No newline at end of file +6ba94d5feb79c3f422a4db78e42595211d8a4c3a \ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 4e4bd11..072b536 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -1104,10 +1104,6 @@ "performance_monitor/chrome_browser_main_extra_parts_performance_monitor.h", "performance_monitor/system_monitor.cc", "performance_monitor/system_monitor.h", - "permissions/abusive_origin_notifications_permission_revocation_config.cc", - "permissions/abusive_origin_notifications_permission_revocation_config.h", - "permissions/abusive_origin_permission_revocation_request.cc", - "permissions/abusive_origin_permission_revocation_request.h", "permissions/adaptive_quiet_notification_permission_ui_enabler.cc", "permissions/adaptive_quiet_notification_permission_ui_enabler.h", "permissions/chrome_permissions_client.cc", @@ -1127,6 +1123,8 @@ "permissions/last_tab_standing_tracker_tab_helper.h", "permissions/notifications_engagement_service_factory.cc", "permissions/notifications_engagement_service_factory.h", + "permissions/notifications_permission_revocation_config.cc", + "permissions/notifications_permission_revocation_config.h", "permissions/permission_actions_history_factory.cc", "permissions/permission_actions_history_factory.h", "permissions/permission_auditing_service_factory.cc", @@ -1135,6 +1133,8 @@ "permissions/permission_decision_auto_blocker_factory.h", "permissions/permission_manager_factory.cc", "permissions/permission_manager_factory.h", + "permissions/permission_revocation_request.cc", + "permissions/permission_revocation_request.h", "permissions/prediction_based_permission_ui_selector.cc", "permissions/prediction_based_permission_ui_selector.h", "permissions/prediction_service_factory.cc", @@ -5170,6 +5170,7 @@ "//chrome/browser/ui/quick_answers", "//chrome/browser/ui/webui/chromeos/add_supervision:mojo_bindings", "//chrome/browser/ui/webui/chromeos/audio:mojo_bindings", + "//chrome/browser/ui/webui/chromeos/cloud_upload:mojo_bindings", "//chrome/browser/ui/webui/chromeos/crostini_installer:mojo_bindings", "//chrome/browser/ui/webui/chromeos/crostini_upgrader:mojo_bindings", "//chrome/browser/ui/webui/chromeos/emoji:mojo_bindings", @@ -6009,8 +6010,8 @@ "google/google_update_win.h", "google/switches.cc", "google/switches.h", - "policy/status_provider/updater_status_provider.cc", - "policy/status_provider/updater_status_provider.h", + "policy/status_provider/updater_status_and_value_provider.cc", + "policy/status_provider/updater_status_and_value_provider.h", "win/conflicts/incompatible_applications_updater.cc", "win/conflicts/incompatible_applications_updater.h", "win/conflicts/installed_applications.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 2c4ccf0..a2f9ff6 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -46,7 +46,7 @@ #include "chrome/browser/net/system_network_context_manager.h" #include "chrome/browser/notifications/scheduler/public/features.h" #include "chrome/browser/performance_manager/policies/policy_features.h" -#include "chrome/browser/permissions/abusive_origin_notifications_permission_revocation_config.h" +#include "chrome/browser/permissions/notifications_permission_revocation_config.h" #include "chrome/browser/permissions/quiet_notification_permission_ui_config.h" #include "chrome/browser/predictors/loading_predictor_config.h" #include "chrome/browser/preloading/prefetch/prefetch_proxy/prefetch_proxy_features.h" @@ -6883,9 +6883,6 @@ {"exo-ordinal-motion", flag_descriptions::kExoOrdinalMotionName, flag_descriptions::kExoOrdinalMotionDescription, kOsCrOS, FEATURE_VALUE_TYPE(chromeos::features::kExoOrdinalMotion)}, - {"exo-pointer-lock", flag_descriptions::kExoPointerLockName, - flag_descriptions::kExoPointerLockDescription, kOsCrOS, - FEATURE_VALUE_TYPE(chromeos::features::kExoPointerLock)}, #endif // BUILDFLAG(IS_CHROMEOS_ASH) #if BUILDFLAG(IS_MAC) @@ -7050,7 +7047,11 @@ kOsWin, FEATURE_VALUE_TYPE(features::kRunVideoCaptureServiceInBrowserProcess)}, #endif // BUILDFLAG(IS_WIN) - + {"disruptive-notification-permission-revocation", + flag_descriptions::kDisruptiveNotificationPermissionRevocationName, + flag_descriptions::kDisruptiveNotificationPermissionRevocationDescription, + kOsAll, + FEATURE_VALUE_TYPE(features::kDisruptiveNotificationPermissionRevocation)}, {"double-buffer-compositing", flag_descriptions::kDoubleBufferCompositingName, flag_descriptions::kDoubleBufferCompositingDescription, kOsCrOS,
diff --git a/chrome/browser/ash/borealis/borealis_task.cc b/chrome/browser/ash/borealis/borealis_task.cc index 1e22204..d6efd47 100644 --- a/chrome/browser/ash/borealis/borealis_task.cc +++ b/chrome/browser/ash/borealis/borealis_task.cc
@@ -245,14 +245,6 @@ disk_image->set_writable(true); disk_image->set_do_mount(false); - // TODO(b/161952658): Remove this logging when the exo-pointer-lock is fixed, - // this is only meant to be temporary. - LOG(WARNING) << "Starting Borealis with exo-pointer-lock: " - << (base::FeatureList::IsEnabled( - chromeos::features::kExoPointerLock) - ? "enabled" - : "disabled"); - if (external_disk) { base::ScopedFD fd(external_disk->TakePlatformFile()); request.add_fds(vm_tools::concierge::StartVmRequest::STORAGE);
diff --git a/chrome/browser/ash/chromebox_for_meetings/browser/cfm_browser_service_unittest.cc b/chrome/browser/ash/chromebox_for_meetings/browser/cfm_browser_service_unittest.cc index 0a0b798..6aa73945 100644 --- a/chrome/browser/ash/chromebox_for_meetings/browser/cfm_browser_service_unittest.cc +++ b/chrome/browser/ash/chromebox_for_meetings/browser/cfm_browser_service_unittest.cc
@@ -20,7 +20,6 @@ #include "base/test/bind.h" #include "base/test/mock_callback.h" #include "base/test/scoped_feature_list.h" -#include "base/test/scoped_field_trial_list_resetter.h" #include "base/test/task_environment.h" #include "chromeos/ash/components/dbus/chromebox_for_meetings/fake_cfm_hotline_client.h" #include "components/variations/field_trial_config/field_trial_util.h" @@ -38,7 +37,9 @@ class CfmBrowserServiceTest : public testing::Test { public: - CfmBrowserServiceTest() = default; + CfmBrowserServiceTest() { + scoped_feature_list_.InitWithEmptyFeatureAndFieldTrialLists(); + } CfmBrowserServiceTest(const CfmBrowserServiceTest&) = delete; CfmBrowserServiceTest& operator=(const CfmBrowserServiceTest&) = delete; @@ -102,10 +103,6 @@ protected: base::test::SingleThreadTaskEnvironment task_environment_; - // The test suite instantiates a FieldTrialList but for the purpose of these - // tests it's cleaner to start from scratch. - base::test::ScopedFieldTrialListResetter trial_list_resetter_; - base::FieldTrialList trial_list_{nullptr}; base::test::ScopedFeatureList scoped_feature_list_; FakeCfmServiceContext context_; mojo::Remote<mojom::CfmBrowser> browser_remote_; @@ -135,7 +132,8 @@ ASSERT_TRUE(variations::AssociateParamsFromString(field_trial_parameters)); ASSERT_TRUE(base::FieldTrialList::CreateTrialsFromString(field_trial_states)); - scoped_feature_list_.InitFromCommandLine(enabled_features, disabled_features); + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitFromCommandLine(enabled_features, disabled_features); base::RunLoop run_loop; GetBrowserRemote()->GetVariationsData(base::BindLambdaForTesting(
diff --git a/chrome/browser/ash/crosapi/sharesheet_ash_browsertest.cc b/chrome/browser/ash/crosapi/sharesheet_ash_browsertest.cc index 3e0a7314..71a5fe2 100644 --- a/chrome/browser/ash/crosapi/sharesheet_ash_browsertest.cc +++ b/chrome/browser/ash/crosapi/sharesheet_ash_browsertest.cc
@@ -7,10 +7,12 @@ #include <algorithm> #include <vector> +#include "ash/constants/ash_features.h" #include "base/files/file_util.h" #include "base/run_loop.h" #include "base/strings/utf_string_conversions.h" #include "base/test/bind.h" +#include "base/test/scoped_feature_list.h" #include "base/threading/thread_restrictions.h" #include "base/unguessable_token.h" #include "chrome/browser/apps/app_service/app_service_proxy.h" @@ -25,12 +27,15 @@ #include "chrome/browser/sharesheet/sharesheet_service.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/web_applications/test/app_registration_waiter.h" #include "chrome/browser/web_applications/test/profile_test_helper.h" #include "chrome/browser/web_applications/web_app_id_constants.h" +#include "chrome/common/chrome_features.h" #include "chrome/test/base/ui_test_utils.h" #include "chromeos/components/sharesheet/constants.h" #include "chromeos/crosapi/mojom/app_service_types.mojom.h" #include "components/exo/window_properties.h" +#include "components/services/app_service/public/cpp/app_types.h" #include "components/services/app_service/public/cpp/intent_util.h" #include "content/public/test/browser_test.h" #include "content/public/test/browser_test_utils.h" @@ -112,7 +117,10 @@ class SharesheetAshBrowserTest : public ash::SystemWebAppIntegrationTest { public: - SharesheetAshBrowserTest() = default; + SharesheetAshBrowserTest() { + scoped_feature_list_.InitWithFeatures( + {chromeos::features::kLacrosSupport, features::kWebAppsCrosapi}, {}); + } ~SharesheetAshBrowserTest() override = default; // SystemWebAppIntegrationTest: @@ -120,6 +128,11 @@ SystemWebAppIntegrationTest::SetUpOnMainThread(); WaitForTestSystemAppInstall(); + // When Lacros web apps are enabled, SWAs use kSystemWeb app type. + web_app::AppTypeInitializationWaiter(browser()->profile(), + apps::AppType::kSystemWeb) + .Await(); + // The Sample System Web App will be automatically selected from the // Sharesheet bubble. sharesheet::SharesheetService::SetSelectedAppForTesting( @@ -128,6 +141,9 @@ void TearDownOnMainThread() override { sharesheet::SharesheetService::SetSelectedAppForTesting(std::u16string()); } + + private: + base::test::ScopedFeatureList scoped_feature_list_; }; IN_PROC_BROWSER_TEST_P(SharesheetAshBrowserTest, Success) {
diff --git a/chrome/browser/ash/input_method/assistive_suggester_prefs.cc b/chrome/browser/ash/input_method/assistive_suggester_prefs.cc index 85f5ec9..ebbaf57 100644 --- a/chrome/browser/ash/input_method/assistive_suggester_prefs.cc +++ b/chrome/browser/ash/input_method/assistive_suggester_prefs.cc
@@ -32,7 +32,7 @@ engine_id + ".physicalKeyboardEnableDiacriticsOnLongpress"); // If no preference has been set yet by the user then we can assume the // default preference as enabled. - return diacritics_on_longpress_setting.value_or(false); + return diacritics_on_longpress_setting.value_or(true); } } // namespace input_method
diff --git a/chrome/browser/ash/login/demo_mode/demo_setup_browsertest.cc b/chrome/browser/ash/login/demo_mode/demo_setup_browsertest.cc index 206e481..facba49 100644 --- a/chrome/browser/ash/login/demo_mode/demo_setup_browsertest.cc +++ b/chrome/browser/ash/login/demo_mode/demo_setup_browsertest.cc
@@ -537,8 +537,16 @@ EXPECT_TRUE(StartupUtils::IsDeviceRegistered()); } +// Disabled due to test failure. http://crbug.com/1350365 +#if BUILDFLAG(IS_CHROMEOS_ASH) +#define MAYBE_OnlineSetupFlowSuccessWithCountryCustomization \ + DISABLED_OnlineSetupFlowSuccessWithCountryCustomization +#else +#define MAYBE_OnlineSetupFlowSuccessWithCountryCustomization \ + OnlineSetupFlowSuccessWithCountryCustomization +#endif IN_PROC_BROWSER_TEST_F(DemoSetupArcSupportedTest, - OnlineSetupFlowSuccessWithCountryCustomization) { + MAYBE_OnlineSetupFlowSuccessWithCountryCustomization) { // Simulate successful online setup. enrollment_helper_.ExpectEnrollmentMode( policy::EnrollmentConfig::MODE_ATTESTATION);
diff --git a/chrome/browser/ash/login/enrollment/auto_enrollment_check_screen.cc b/chrome/browser/ash/login/enrollment/auto_enrollment_check_screen.cc index 47aadf7..13008b5 100644 --- a/chrome/browser/ash/login/enrollment/auto_enrollment_check_screen.cc +++ b/chrome/browser/ash/login/enrollment/auto_enrollment_check_screen.cc
@@ -120,7 +120,7 @@ network_portal_detector::GetInstance()->RemoveObserver(this); } -bool AutoEnrollmentCheckScreen::MaybeSkip(WizardContext* context) { +bool AutoEnrollmentCheckScreen::MaybeSkip(WizardContext& context) { // If the decision got made already, don't show the screen at all. if (!policy::AutoEnrollmentTypeChecker::IsEnabled() || IsCompleted()) { RunExitCallback(Result::NOT_APPLICABLE); @@ -142,7 +142,6 @@ return; } UpdateState(); - } void AutoEnrollmentCheckScreen::UpdateState() {
diff --git a/chrome/browser/ash/login/enrollment/auto_enrollment_check_screen.h b/chrome/browser/ash/login/enrollment/auto_enrollment_check_screen.h index e9754ff3..83988c8 100644 --- a/chrome/browser/ash/login/enrollment/auto_enrollment_check_screen.h +++ b/chrome/browser/ash/login/enrollment/auto_enrollment_check_screen.h
@@ -70,7 +70,7 @@ // BaseScreen: void ShowImpl() override; void HideImpl() override; - bool MaybeSkip(WizardContext* context) override; + bool MaybeSkip(WizardContext& context) override; // Runs `exit_callback_` - used to prevent `exit_callback_` from running after // `this` has been destroyed (by wrapping it with a callback bound to a weak
diff --git a/chrome/browser/ash/login/enrollment/enrollment_screen.cc b/chrome/browser/ash/login/enrollment/enrollment_screen.cc index fd03f55..d557efa 100644 --- a/chrome/browser/ash/login/enrollment/enrollment_screen.cc +++ b/chrome/browser/ash/login/enrollment/enrollment_screen.cc
@@ -247,14 +247,14 @@ std::move(callback).Run(); } -bool EnrollmentScreen::MaybeSkip(WizardContext* context) { +bool EnrollmentScreen::MaybeSkip(WizardContext& context) { // TODO(crbug.com/1271134): Logging as "WARNING" to make sure it's preserved // in the logs. LOG(WARNING) << "EnrollmentScreen::MaybeSkip(" << "config_.is_forced = " << config_.is_forced() << ", skip_to_login_for_tests = " - << context->skip_to_login_for_tests << ")."; - if (context->skip_to_login_for_tests && !config_.is_forced()) { + << context.skip_to_login_for_tests << ")."; + if (context.skip_to_login_for_tests && !config_.is_forced()) { exit_callback_.Run(Result::SKIPPED_FOR_TESTS); return true; }
diff --git a/chrome/browser/ash/login/enrollment/enrollment_screen.h b/chrome/browser/ash/login/enrollment/enrollment_screen.h index 4f129174..019d13c 100644 --- a/chrome/browser/ash/login/enrollment/enrollment_screen.h +++ b/chrome/browser/ash/login/enrollment/enrollment_screen.h
@@ -127,7 +127,7 @@ protected: // BaseScreen: - bool MaybeSkip(WizardContext* context) override; + bool MaybeSkip(WizardContext& context) override; void ShowImpl() override; void HideImpl() override; bool HandleAccelerator(LoginAcceleratorAction action) override;
diff --git a/chrome/browser/ash/login/screens/arc_terms_of_service_screen.cc b/chrome/browser/ash/login/screens/arc_terms_of_service_screen.cc index 431493a3..5a81a67 100644 --- a/chrome/browser/ash/login/screens/arc_terms_of_service_screen.cc +++ b/chrome/browser/ash/login/screens/arc_terms_of_service_screen.cc
@@ -139,8 +139,8 @@ } } -bool ArcTermsOfServiceScreen::MaybeSkip(WizardContext* context) { - if (context->skip_post_login_screens_for_tests) { +bool ArcTermsOfServiceScreen::MaybeSkip(WizardContext& context) { + if (context.skip_post_login_screens_for_tests) { exit_callback_.Run(Result::NOT_APPLICABLE); return true; }
diff --git a/chrome/browser/ash/login/screens/arc_terms_of_service_screen.h b/chrome/browser/ash/login/screens/arc_terms_of_service_screen.h index 715cd2c6..3e25376 100644 --- a/chrome/browser/ash/login/screens/arc_terms_of_service_screen.h +++ b/chrome/browser/ash/login/screens/arc_terms_of_service_screen.h
@@ -73,7 +73,7 @@ protected: // BaseScreen: - bool MaybeSkip(WizardContext* context) override; + bool MaybeSkip(WizardContext& context) override; void ShowImpl() override; void HideImpl() override; void OnUserActionDeprecated(const std::string& action_id) override;
diff --git a/chrome/browser/ash/login/screens/assistant_optin_flow_screen.cc b/chrome/browser/ash/login/screens/assistant_optin_flow_screen.cc index da2df576..138c1a0 100644 --- a/chrome/browser/ash/login/screens/assistant_optin_flow_screen.cc +++ b/chrome/browser/ash/login/screens/assistant_optin_flow_screen.cc
@@ -53,8 +53,8 @@ view_->Unbind(); } -bool AssistantOptInFlowScreen::MaybeSkip(WizardContext* context) { - if (context->skip_post_login_screens_for_tests || !g_libassistant_enabled || +bool AssistantOptInFlowScreen::MaybeSkip(WizardContext& context) { + if (context.skip_post_login_screens_for_tests || !g_libassistant_enabled || chrome_user_manager_util::IsPublicSessionOrEphemeralLogin()) { exit_callback_.Run(Result::NOT_APPLICABLE); return true;
diff --git a/chrome/browser/ash/login/screens/assistant_optin_flow_screen.h b/chrome/browser/ash/login/screens/assistant_optin_flow_screen.h index 92b4ccd..4f54460 100644 --- a/chrome/browser/ash/login/screens/assistant_optin_flow_screen.h +++ b/chrome/browser/ash/login/screens/assistant_optin_flow_screen.h
@@ -50,7 +50,7 @@ protected: // BaseScreen: - bool MaybeSkip(WizardContext* context) override; + bool MaybeSkip(WizardContext& context) override; void ShowImpl() override; void HideImpl() override; void OnUserActionDeprecated(const std::string& action_id) override;
diff --git a/chrome/browser/ash/login/screens/base_screen.cc b/chrome/browser/ash/login/screens/base_screen.cc index d43fed8..716dc73b 100644 --- a/chrome/browser/ash/login/screens/base_screen.cc +++ b/chrome/browser/ash/login/screens/base_screen.cc
@@ -33,7 +33,7 @@ wizard_context_ = nullptr; } -bool BaseScreen::MaybeSkip(WizardContext* context) { +bool BaseScreen::MaybeSkip(WizardContext& context) { return false; }
diff --git a/chrome/browser/ash/login/screens/base_screen.h b/chrome/browser/ash/login/screens/base_screen.h index 5c9da84..73dcf84 100644 --- a/chrome/browser/ash/login/screens/base_screen.h +++ b/chrome/browser/ash/login/screens/base_screen.h
@@ -42,7 +42,7 @@ // Returns whether the screen should be skipped i. e. should be exited due to // specific unmet conditions. Returns true if skips the screen. - [[nodiscard]] virtual bool MaybeSkip(WizardContext* context); + [[nodiscard]] virtual bool MaybeSkip(WizardContext& context); // Forwards user action if screen is shown. void HandleUserAction(const base::Value::List& args);
diff --git a/chrome/browser/ash/login/screens/consolidated_consent_screen.cc b/chrome/browser/ash/login/screens/consolidated_consent_screen.cc index 886694ae..6fdea73 100644 --- a/chrome/browser/ash/login/screens/consolidated_consent_screen.cc +++ b/chrome/browser/ash/login/screens/consolidated_consent_screen.cc
@@ -118,8 +118,8 @@ view_ = nullptr; } -bool ConsolidatedConsentScreen::MaybeSkip(WizardContext* context) { - if (context->skip_post_login_screens_for_tests) { +bool ConsolidatedConsentScreen::MaybeSkip(WizardContext& context) { + if (context.skip_post_login_screens_for_tests) { if (features::IsOobeConsolidatedConsentEnabled()) StartupUtils::MarkEulaAccepted(); @@ -132,7 +132,7 @@ policy::BrowserPolicyConnectorAsh* policy_connector = g_browser_process->platform_part()->browser_policy_connector_ash(); - if (!context->is_branded_build || + if (!context.is_branded_build || policy_connector->IsActiveDirectoryManaged() || user_manager::UserManager::Get()->IsLoggedInAsPublicAccount()) { exit_callback_.Run(Result::NOT_APPLICABLE);
diff --git a/chrome/browser/ash/login/screens/consolidated_consent_screen.h b/chrome/browser/ash/login/screens/consolidated_consent_screen.h index 301f93e..1391315 100644 --- a/chrome/browser/ash/login/screens/consolidated_consent_screen.h +++ b/chrome/browser/ash/login/screens/consolidated_consent_screen.h
@@ -86,7 +86,7 @@ protected: // BaseScreen: - bool MaybeSkip(WizardContext* context) override; + bool MaybeSkip(WizardContext& context) override; void ShowImpl() override; void HideImpl() override; void OnUserActionDeprecated(const std::string& action_id) override;
diff --git a/chrome/browser/ash/login/screens/edu_coexistence_login_screen.cc b/chrome/browser/ash/login/screens/edu_coexistence_login_screen.cc index 149733f..164e0c4 100644 --- a/chrome/browser/ash/login/screens/edu_coexistence_login_screen.cc +++ b/chrome/browser/ash/login/screens/edu_coexistence_login_screen.cc
@@ -51,8 +51,8 @@ EduCoexistenceLoginScreen::~EduCoexistenceLoginScreen() {} -bool EduCoexistenceLoginScreen::MaybeSkip(WizardContext* context) { - if (context->skip_post_login_screens_for_tests || +bool EduCoexistenceLoginScreen::MaybeSkip(WizardContext& context) { + if (context.skip_post_login_screens_for_tests || !ProfileManager::GetActiveUserProfile()->IsChild()) { exit_callback_.Run(Result::SKIPPED); return true;
diff --git a/chrome/browser/ash/login/screens/edu_coexistence_login_screen.h b/chrome/browser/ash/login/screens/edu_coexistence_login_screen.h index 5cfe33f..d5732cd3 100644 --- a/chrome/browser/ash/login/screens/edu_coexistence_login_screen.h +++ b/chrome/browser/ash/login/screens/edu_coexistence_login_screen.h
@@ -47,7 +47,7 @@ } private: - bool MaybeSkip(WizardContext* context) override; + bool MaybeSkip(WizardContext& context) override; void ShowImpl() override; void HideImpl() override;
diff --git a/chrome/browser/ash/login/screens/eula_screen.cc b/chrome/browser/ash/login/screens/eula_screen.cc index 115df0a..cea1a35 100644 --- a/chrome/browser/ash/login/screens/eula_screen.cc +++ b/chrome/browser/ash/login/screens/eula_screen.cc
@@ -116,16 +116,16 @@ view_->Unbind(); } -bool EulaScreen::MaybeSkip(WizardContext* context) { +bool EulaScreen::MaybeSkip(WizardContext& context) { // This should be kept in sync with `testapi_shouldSkipEula`. If the logic // became too complicated we need to consider extract and reuse parts of it. - if (!context->is_branded_build) { + if (!context.is_branded_build) { exit_callback_.Run(Result::NOT_APPLICABLE); return true; } - if (StartupUtils::IsEulaAccepted() && !context->is_cloud_ready_update_flow) { + if (StartupUtils::IsEulaAccepted() && !context.is_cloud_ready_update_flow) { const auto* const demo_setup_controller = WizardController::default_controller()->demo_setup_controller(); exit_callback_.Run(demo_setup_controller
diff --git a/chrome/browser/ash/login/screens/eula_screen.h b/chrome/browser/ash/login/screens/eula_screen.h index 45d58d6..2cf2d6c 100644 --- a/chrome/browser/ash/login/screens/eula_screen.h +++ b/chrome/browser/ash/login/screens/eula_screen.h
@@ -80,7 +80,7 @@ private: // BaseScreen: - bool MaybeSkip(WizardContext* context) override; + bool MaybeSkip(WizardContext& context) override; void ShowImpl() override; void HideImpl() override; void OnUserActionDeprecated(const std::string& action_id) override;
diff --git a/chrome/browser/ash/login/screens/family_link_notice_screen.cc b/chrome/browser/ash/login/screens/family_link_notice_screen.cc index 4a198390..83d5e3d8 100644 --- a/chrome/browser/ash/login/screens/family_link_notice_screen.cc +++ b/chrome/browser/ash/login/screens/family_link_notice_screen.cc
@@ -37,9 +37,8 @@ FamilyLinkNoticeScreen::~FamilyLinkNoticeScreen() = default; -bool FamilyLinkNoticeScreen::MaybeSkip(WizardContext* context) { - if (!context->skip_post_login_screens_for_tests && - context->sign_in_as_child && +bool FamilyLinkNoticeScreen::MaybeSkip(WizardContext& context) { + if (!context.skip_post_login_screens_for_tests && context.sign_in_as_child && !ProfileManager::GetActiveUserProfile()->IsChild()) { return false; }
diff --git a/chrome/browser/ash/login/screens/family_link_notice_screen.h b/chrome/browser/ash/login/screens/family_link_notice_screen.h index 1446837..e6d0491 100644 --- a/chrome/browser/ash/login/screens/family_link_notice_screen.h +++ b/chrome/browser/ash/login/screens/family_link_notice_screen.h
@@ -42,7 +42,7 @@ private: // BaseScreen: - bool MaybeSkip(WizardContext* context) override; + bool MaybeSkip(WizardContext& context) override; void ShowImpl() override; void HideImpl() override; void OnUserAction(const base::Value::List& args) override;
diff --git a/chrome/browser/ash/login/screens/fingerprint_setup_screen.cc b/chrome/browser/ash/login/screens/fingerprint_setup_screen.cc index 6c108064..d57918d 100644 --- a/chrome/browser/ash/login/screens/fingerprint_setup_screen.cc +++ b/chrome/browser/ash/login/screens/fingerprint_setup_screen.cc
@@ -119,8 +119,8 @@ FingerprintSetupScreen::~FingerprintSetupScreen() = default; -bool FingerprintSetupScreen::MaybeSkip(WizardContext* context) { - if (context->skip_post_login_screens_for_tests || +bool FingerprintSetupScreen::MaybeSkip(WizardContext& context) { + if (context.skip_post_login_screens_for_tests || !quick_unlock::IsFingerprintEnabled( ProfileManager::GetActiveUserProfile(), quick_unlock::Purpose::kAny) ||
diff --git a/chrome/browser/ash/login/screens/fingerprint_setup_screen.h b/chrome/browser/ash/login/screens/fingerprint_setup_screen.h index 17f7bb3d..7131da5 100644 --- a/chrome/browser/ash/login/screens/fingerprint_setup_screen.h +++ b/chrome/browser/ash/login/screens/fingerprint_setup_screen.h
@@ -77,7 +77,7 @@ protected: // BaseScreen: - bool MaybeSkip(WizardContext* context) override; + bool MaybeSkip(WizardContext& context) override; void ShowImpl() override; void HideImpl() override; void OnUserAction(const base::Value::List& args) override;
diff --git a/chrome/browser/ash/login/screens/gesture_navigation_screen.cc b/chrome/browser/ash/login/screens/gesture_navigation_screen.cc index 1171d16a..de4f66ac 100644 --- a/chrome/browser/ash/login/screens/gesture_navigation_screen.cc +++ b/chrome/browser/ash/login/screens/gesture_navigation_screen.cc
@@ -56,9 +56,9 @@ current_page_ = new_page; } -bool GestureNavigationScreen::MaybeSkip(WizardContext* context) { +bool GestureNavigationScreen::MaybeSkip(WizardContext& context) { AccessibilityManager* accessibility_manager = AccessibilityManager::Get(); - if (context->skip_post_login_screens_for_tests || + if (context.skip_post_login_screens_for_tests || chrome_user_manager_util::IsPublicSessionOrEphemeralLogin() || !features::IsHideShelfControlsInTabletModeEnabled() || ProfileManager::GetActiveUserProfile()->GetPrefs()->GetBoolean(
diff --git a/chrome/browser/ash/login/screens/gesture_navigation_screen.h b/chrome/browser/ash/login/screens/gesture_navigation_screen.h index 7437e87e..49119d0 100644 --- a/chrome/browser/ash/login/screens/gesture_navigation_screen.h +++ b/chrome/browser/ash/login/screens/gesture_navigation_screen.h
@@ -47,7 +47,7 @@ void GesturePageChange(const std::string& new_page); // BaseScreen: - bool MaybeSkip(WizardContext* context) override; + bool MaybeSkip(WizardContext& context) override; protected: // BaseScreen:
diff --git a/chrome/browser/ash/login/screens/hardware_data_collection_screen.cc b/chrome/browser/ash/login/screens/hardware_data_collection_screen.cc index c7b800c..2fc924b 100644 --- a/chrome/browser/ash/login/screens/hardware_data_collection_screen.cc +++ b/chrome/browser/ash/login/screens/hardware_data_collection_screen.cc
@@ -68,16 +68,16 @@ view_ = nullptr; } -bool HWDataCollectionScreen::MaybeSkip(WizardContext* context) { - if (!switches::IsRevenBranding() || !context->is_branded_build) { +bool HWDataCollectionScreen::MaybeSkip(WizardContext& context) { + if (!switches::IsRevenBranding() || !context.is_branded_build) { exit_callback_.Run(Result::NOT_APPLICABLE); return true; } bool is_owner = false; // Taking device ownership can take some time, so we can't rely on it here. // However it can be already checked during ConsolidateConsentScreen. - if (context->is_owner_flow.has_value()) { - is_owner = context->is_owner_flow.value(); + if (context.is_owner_flow.has_value()) { + is_owner = context.is_owner_flow.value(); } else { // If no, check that the device is not managed and user is either already // marked as an owner in user_manager or is the first on the device. @@ -92,7 +92,7 @@ exit_callback_.Run(Result::NOT_APPLICABLE); return true; } - if (context->skip_post_login_screens_for_tests) { + if (context.skip_post_login_screens_for_tests) { // Set a default value if the screen should be shown, but is skipped because // of the test flow. This value is important, as we rely on it during update // flow from CloudReady to Chrome OS Flex and it should be set after owner
diff --git a/chrome/browser/ash/login/screens/hardware_data_collection_screen.h b/chrome/browser/ash/login/screens/hardware_data_collection_screen.h index 234b525..13bb3747 100644 --- a/chrome/browser/ash/login/screens/hardware_data_collection_screen.h +++ b/chrome/browser/ash/login/screens/hardware_data_collection_screen.h
@@ -44,7 +44,7 @@ private: // BaseScreen: - bool MaybeSkip(WizardContext* context) override; + bool MaybeSkip(WizardContext& context) override; void ShowImpl() override; void HideImpl() override; void OnUserActionDeprecated(const std::string& action_id) override;
diff --git a/chrome/browser/ash/login/screens/hid_detection_screen.cc b/chrome/browser/ash/login/screens/hid_detection_screen.cc index c1abb79..4f0ebc0a 100644 --- a/chrome/browser/ash/login/screens/hid_detection_screen.cc +++ b/chrome/browser/ash/login/screens/hid_detection_screen.cc
@@ -237,7 +237,7 @@ weak_ptr_factory_.GetWeakPtr(), std::move(on_check_done))); } -bool HIDDetectionScreen::MaybeSkip(WizardContext* context) { +bool HIDDetectionScreen::MaybeSkip(WizardContext& context) { if (!CanShowScreen()) { // TODO(https://crbug.com/1275960): Introduce Result::SKIPPED. Exit(Result::SKIPPED_FOR_TESTS);
diff --git a/chrome/browser/ash/login/screens/hid_detection_screen.h b/chrome/browser/ash/login/screens/hid_detection_screen.h index 9b986bc..e9a9fdd4 100644 --- a/chrome/browser/ash/login/screens/hid_detection_screen.h +++ b/chrome/browser/ash/login/screens/hid_detection_screen.h
@@ -92,7 +92,7 @@ friend class HIDDetectionScreenChromeboxTest; // BaseScreen: - bool MaybeSkip(WizardContext* context) override; + bool MaybeSkip(WizardContext& context) override; void ShowImpl() override; void HideImpl() override; void OnUserActionDeprecated(const std::string& action_id) override;
diff --git a/chrome/browser/ash/login/screens/locale_switch_screen.cc b/chrome/browser/ash/login/screens/locale_switch_screen.cc index 474e61c..40f7578 100644 --- a/chrome/browser/ash/login/screens/locale_switch_screen.cc +++ b/chrome/browser/ash/login/screens/locale_switch_screen.cc
@@ -59,8 +59,8 @@ LocaleSwitchScreen::~LocaleSwitchScreen() = default; -bool LocaleSwitchScreen::MaybeSkip(WizardContext* wizard_context) { - if (wizard_context->skip_post_login_screens_for_tests) { +bool LocaleSwitchScreen::MaybeSkip(WizardContext& wizard_context) { + if (wizard_context.skip_post_login_screens_for_tests) { exit_callback_.Run(Result::NOT_APPLICABLE); return true; }
diff --git a/chrome/browser/ash/login/screens/locale_switch_screen.h b/chrome/browser/ash/login/screens/locale_switch_screen.h index 8f6a5fb..a63fee38 100644 --- a/chrome/browser/ash/login/screens/locale_switch_screen.h +++ b/chrome/browser/ash/login/screens/locale_switch_screen.h
@@ -52,7 +52,7 @@ // BaseScreen: void ShowImpl() override; void HideImpl() override; - bool MaybeSkip(WizardContext* context) override; + bool MaybeSkip(WizardContext& context) override; void SwitchLocale(std::string locale); void OnLanguageChangedCallback(
diff --git a/chrome/browser/ash/login/screens/marketing_opt_in_screen.cc b/chrome/browser/ash/login/screens/marketing_opt_in_screen.cc index bb58215..8b8163a 100644 --- a/chrome/browser/ash/login/screens/marketing_opt_in_screen.cc +++ b/chrome/browser/ash/login/screens/marketing_opt_in_screen.cc
@@ -105,15 +105,15 @@ } } -bool MarketingOptInScreen::MaybeSkip(WizardContext* context) { - if (context->skip_post_login_screens_for_tests) { +bool MarketingOptInScreen::MaybeSkip(WizardContext& context) { + if (context.skip_post_login_screens_for_tests) { exit_callback_.Run(Result::NOT_APPLICABLE); return true; } Initialize(); if (chrome_user_manager_util::IsPublicSessionOrEphemeralLogin() || - IsCurrentUserManaged() || !context->is_branded_build) { + IsCurrentUserManaged() || !context.is_branded_build) { exit_callback_.Run(Result::NOT_APPLICABLE); return true; }
diff --git a/chrome/browser/ash/login/screens/marketing_opt_in_screen.h b/chrome/browser/ash/login/screens/marketing_opt_in_screen.h index d606b50..a9e1e9f 100644 --- a/chrome/browser/ash/login/screens/marketing_opt_in_screen.h +++ b/chrome/browser/ash/login/screens/marketing_opt_in_screen.h
@@ -80,7 +80,7 @@ protected: // BaseScreen: - bool MaybeSkip(WizardContext* context) override; + bool MaybeSkip(WizardContext& context) override; void ShowImpl() override; void HideImpl() override;
diff --git a/chrome/browser/ash/login/screens/multidevice_setup_screen.cc b/chrome/browser/ash/login/screens/multidevice_setup_screen.cc index ad380dd..5ec50d1 100644 --- a/chrome/browser/ash/login/screens/multidevice_setup_screen.cc +++ b/chrome/browser/ash/login/screens/multidevice_setup_screen.cc
@@ -58,9 +58,9 @@ } } -bool MultiDeviceSetupScreen::MaybeSkip(WizardContext* context) { +bool MultiDeviceSetupScreen::MaybeSkip(WizardContext& context) { // Only attempt the setup flow for non-guest users. - if (context->skip_post_login_screens_for_tests || + if (context.skip_post_login_screens_for_tests || chrome_user_manager_util::IsPublicSessionOrEphemeralLogin()) { exit_callback_.Run(Result::NOT_APPLICABLE); return true;
diff --git a/chrome/browser/ash/login/screens/multidevice_setup_screen.h b/chrome/browser/ash/login/screens/multidevice_setup_screen.h index 301727e..5113209 100644 --- a/chrome/browser/ash/login/screens/multidevice_setup_screen.h +++ b/chrome/browser/ash/login/screens/multidevice_setup_screen.h
@@ -52,7 +52,7 @@ protected: // BaseScreen: - bool MaybeSkip(WizardContext* context) override; + bool MaybeSkip(WizardContext& context) override; void ShowImpl() override; void HideImpl() override; void OnUserAction(const base::Value::List& args) override;
diff --git a/chrome/browser/ash/login/screens/network_screen.cc b/chrome/browser/ash/login/screens/network_screen.cc index c5b39a8..c26f7d38 100644 --- a/chrome/browser/ash/login/screens/network_screen.cc +++ b/chrome/browser/ash/login/screens/network_screen.cc
@@ -73,7 +73,7 @@ } } -bool NetworkScreen::MaybeSkip(WizardContext* context) { +bool NetworkScreen::MaybeSkip(WizardContext& context) { // Skip this screen if the device is connected to Ethernet for the first time // in this session. return UpdateStatusIfConnectedToEthernet();
diff --git a/chrome/browser/ash/login/screens/network_screen.h b/chrome/browser/ash/login/screens/network_screen.h index 7430276..dd6fc91 100644 --- a/chrome/browser/ash/login/screens/network_screen.h +++ b/chrome/browser/ash/login/screens/network_screen.h
@@ -78,7 +78,7 @@ FRIEND_TEST_ALL_PREFIXES(NetworkScreenUnitTest, ContinuesOnlyOnce); // BaseScreen: - bool MaybeSkip(WizardContext* context) override; + bool MaybeSkip(WizardContext& context) override; void ShowImpl() override; void HideImpl() override; void OnUserActionDeprecated(const std::string& action_id) override;
diff --git a/chrome/browser/ash/login/screens/packaged_license_screen.cc b/chrome/browser/ash/login/screens/packaged_license_screen.cc index a959aa4..b3fc9b9 100644 --- a/chrome/browser/ash/login/screens/packaged_license_screen.cc +++ b/chrome/browser/ash/login/screens/packaged_license_screen.cc
@@ -43,7 +43,7 @@ PackagedLicenseScreen::~PackagedLicenseScreen() = default; -bool PackagedLicenseScreen::MaybeSkip(WizardContext* context) { +bool PackagedLicenseScreen::MaybeSkip(WizardContext& context) { policy::EnrollmentConfig config = policy::EnrollmentConfig::GetPrescribedEnrollmentConfig(); // License screen should be shown when device packed with license and other
diff --git a/chrome/browser/ash/login/screens/packaged_license_screen.h b/chrome/browser/ash/login/screens/packaged_license_screen.h index 3e53bc9..fc112dc 100644 --- a/chrome/browser/ash/login/screens/packaged_license_screen.h +++ b/chrome/browser/ash/login/screens/packaged_license_screen.h
@@ -52,7 +52,7 @@ } // BaseScreen - bool MaybeSkip(WizardContext* context) override; + bool MaybeSkip(WizardContext& context) override; protected: // BaseScreen
diff --git a/chrome/browser/ash/login/screens/parental_handoff_screen.cc b/chrome/browser/ash/login/screens/parental_handoff_screen.cc index 1eb98f1..e21d8d6 100644 --- a/chrome/browser/ash/login/screens/parental_handoff_screen.cc +++ b/chrome/browser/ash/login/screens/parental_handoff_screen.cc
@@ -54,8 +54,8 @@ ParentalHandoffScreen::~ParentalHandoffScreen() = default; -bool ParentalHandoffScreen::MaybeSkip(WizardContext* context) { - if (context->skip_post_login_screens_for_tests || +bool ParentalHandoffScreen::MaybeSkip(WizardContext& context) { + if (context.skip_post_login_screens_for_tests || !IsFamilyLinkOobeHandoffEnabled()) { exit_callback_.Run(Result::SKIPPED); return true;
diff --git a/chrome/browser/ash/login/screens/parental_handoff_screen.h b/chrome/browser/ash/login/screens/parental_handoff_screen.h index 8198ac8..6fb6812 100644 --- a/chrome/browser/ash/login/screens/parental_handoff_screen.h +++ b/chrome/browser/ash/login/screens/parental_handoff_screen.h
@@ -39,7 +39,7 @@ private: // BaseScreen: - bool MaybeSkip(WizardContext* context) override; + bool MaybeSkip(WizardContext& context) override; void ShowImpl() override; void HideImpl() override; void OnUserAction(const base::Value::List& args) override;
diff --git a/chrome/browser/ash/login/screens/pin_setup_screen.cc b/chrome/browser/ash/login/screens/pin_setup_screen.cc index bd3a183..9f92281 100644 --- a/chrome/browser/ash/login/screens/pin_setup_screen.cc +++ b/chrome/browser/ash/login/screens/pin_setup_screen.cc
@@ -104,18 +104,18 @@ PinSetupScreen::~PinSetupScreen() = default; -bool PinSetupScreen::SkipScreen(WizardContext* context) { +bool PinSetupScreen::SkipScreen(WizardContext& context) { ClearAuthData(context); exit_callback_.Run(Result::NOT_APPLICABLE); return true; } -bool PinSetupScreen::MaybeSkip(WizardContext* context) { - if (context->skip_post_login_screens_for_tests || ShouldSkipBecauseOfPolicy()) +bool PinSetupScreen::MaybeSkip(WizardContext& context) { + if (context.skip_post_login_screens_for_tests || ShouldSkipBecauseOfPolicy()) return SkipScreen(context); // Just a precaution: - if (!context->extra_factors_auth_session) + if (!context.extra_factors_auth_session) return SkipScreen(context); // If cryptohome takes very long to respond, `has_login_support_` may be null @@ -168,7 +168,7 @@ void PinSetupScreen::HideImpl() { token_lifetime_timeout_.Stop(); - ClearAuthData(context()); + ClearAuthData(*context()); } void PinSetupScreen::OnUserAction(const base::Value::List& args) { @@ -189,8 +189,8 @@ BaseScreen::OnUserAction(args); } -void PinSetupScreen::ClearAuthData(WizardContext* context) { - context->extra_factors_auth_session.reset(); +void PinSetupScreen::ClearAuthData(WizardContext& context) { + context.extra_factors_auth_session.reset(); } void PinSetupScreen::OnHasLoginSupport(bool login_available) { @@ -200,7 +200,7 @@ } void PinSetupScreen::OnTokenTimedOut() { - ClearAuthData(context()); + ClearAuthData(*context()); exit_callback_.Run(Result::TIMED_OUT); }
diff --git a/chrome/browser/ash/login/screens/pin_setup_screen.h b/chrome/browser/ash/login/screens/pin_setup_screen.h index fc36b917..7a0e412a 100644 --- a/chrome/browser/ash/login/screens/pin_setup_screen.h +++ b/chrome/browser/ash/login/screens/pin_setup_screen.h
@@ -65,7 +65,7 @@ protected: // BaseScreen: - bool MaybeSkip(WizardContext* context) override; + bool MaybeSkip(WizardContext& context) override; void ShowImpl() override; void HideImpl() override; void OnUserAction(const base::Value::List& args) override; @@ -81,8 +81,8 @@ base::OneShotTimer token_lifetime_timeout_; - bool SkipScreen(WizardContext* context); - void ClearAuthData(WizardContext* context); + bool SkipScreen(WizardContext& context); + void ClearAuthData(WizardContext& context); void OnHasLoginSupport(bool login_available); void OnTokenTimedOut();
diff --git a/chrome/browser/ash/login/screens/quick_start_screen.cc b/chrome/browser/ash/login/screens/quick_start_screen.cc index 2557b8b4..0c57eb7 100644 --- a/chrome/browser/ash/login/screens/quick_start_screen.cc +++ b/chrome/browser/ash/login/screens/quick_start_screen.cc
@@ -36,7 +36,7 @@ UnbindFromBootstrapController(); } -bool QuickStartScreen::MaybeSkip(WizardContext* context) { +bool QuickStartScreen::MaybeSkip(WizardContext& context) { return false; }
diff --git a/chrome/browser/ash/login/screens/quick_start_screen.h b/chrome/browser/ash/login/screens/quick_start_screen.h index 5994a0e..701a4ab 100644 --- a/chrome/browser/ash/login/screens/quick_start_screen.h +++ b/chrome/browser/ash/login/screens/quick_start_screen.h
@@ -37,7 +37,7 @@ private: // BaseScreen: - bool MaybeSkip(WizardContext* context) override; + bool MaybeSkip(WizardContext& context) override; void ShowImpl() override; void HideImpl() override; void OnUserAction(const base::Value::List& args) override;
diff --git a/chrome/browser/ash/login/screens/recommend_apps_screen.cc b/chrome/browser/ash/login/screens/recommend_apps_screen.cc index c774c5f5..b634289 100644 --- a/chrome/browser/ash/login/screens/recommend_apps_screen.cc +++ b/chrome/browser/ash/login/screens/recommend_apps_screen.cc
@@ -111,7 +111,7 @@ exit_callback_.Run(Result::SELECTED); } -bool RecommendAppsScreen::MaybeSkip(WizardContext* context) { +bool RecommendAppsScreen::MaybeSkip(WizardContext& context) { const user_manager::UserManager* user_manager = user_manager::UserManager::Get(); DCHECK(user_manager->IsUserLoggedIn());
diff --git a/chrome/browser/ash/login/screens/recommend_apps_screen.h b/chrome/browser/ash/login/screens/recommend_apps_screen.h index 1d2629f..ac438d5 100644 --- a/chrome/browser/ash/login/screens/recommend_apps_screen.h +++ b/chrome/browser/ash/login/screens/recommend_apps_screen.h
@@ -67,7 +67,7 @@ void OnParseResponseError() override; // BaseScreen: - bool MaybeSkip(WizardContext* context) override; + bool MaybeSkip(WizardContext& context) override; void set_exit_callback_for_testing(ScreenExitCallback exit_callback) { exit_callback_ = exit_callback;
diff --git a/chrome/browser/ash/login/screens/smart_privacy_protection_screen.cc b/chrome/browser/ash/login/screens/smart_privacy_protection_screen.cc index 6fec768..2999a12b 100644 --- a/chrome/browser/ash/login/screens/smart_privacy_protection_screen.cc +++ b/chrome/browser/ash/login/screens/smart_privacy_protection_screen.cc
@@ -41,11 +41,11 @@ SmartPrivacyProtectionScreen::~SmartPrivacyProtectionScreen() = default; -bool SmartPrivacyProtectionScreen::MaybeSkip(WizardContext* context) { +bool SmartPrivacyProtectionScreen::MaybeSkip(WizardContext& context) { // SmartPrivacyProtectionScreen lets user set two settings simultaneously: // SnoopingProtection and QuickDim. The screen should be skipped if none of // them is enabled. - if (!context->skip_post_login_screens_for_tests && + if (!context.skip_post_login_screens_for_tests && (ash::features::IsSnoopingProtectionEnabled() || ash::features::IsQuickDimEnabled())) { return false;
diff --git a/chrome/browser/ash/login/screens/smart_privacy_protection_screen.h b/chrome/browser/ash/login/screens/smart_privacy_protection_screen.h index abe8c09..16d2e53 100644 --- a/chrome/browser/ash/login/screens/smart_privacy_protection_screen.h +++ b/chrome/browser/ash/login/screens/smart_privacy_protection_screen.h
@@ -43,7 +43,7 @@ private: // BaseScreen: - bool MaybeSkip(WizardContext* context) override; + bool MaybeSkip(WizardContext& context) override; void ShowImpl() override; void HideImpl() override; void OnUserAction(const base::Value::List& args) override;
diff --git a/chrome/browser/ash/login/screens/sync_consent_screen.cc b/chrome/browser/ash/login/screens/sync_consent_screen.cc index 4917b30..e5d7387 100644 --- a/chrome/browser/ash/login/screens/sync_consent_screen.cc +++ b/chrome/browser/ash/login/screens/sync_consent_screen.cc
@@ -149,13 +149,13 @@ view_->Bind(nullptr); } -void SyncConsentScreen::Init(const WizardContext* context) { +void SyncConsentScreen::Init(const WizardContext& context) { if (is_initialized_) return; is_initialized_ = true; user_ = user_manager::UserManager::Get()->GetPrimaryUser(); profile_ = ProfileHelper::Get()->GetProfileByUser(user_); - UpdateScreen(*context); + UpdateScreen(context); } void SyncConsentScreen::Finish(Result result) { @@ -176,8 +176,8 @@ } } -bool SyncConsentScreen::MaybeSkip(WizardContext* context) { - if (context->skip_post_login_screens_for_tests) { +bool SyncConsentScreen::MaybeSkip(WizardContext& context) { + if (context.skip_post_login_screens_for_tests) { exit_callback_.Run(Result::NOT_APPLICABLE); return true; } @@ -201,7 +201,7 @@ } void SyncConsentScreen::ShowImpl() { - Init(context()); + Init(*context()); if (behavior_ != SyncScreenBehavior::kShow) { syncer::SyncService* service = GetSyncService(profile_);
diff --git a/chrome/browser/ash/login/screens/sync_consent_screen.h b/chrome/browser/ash/login/screens/sync_consent_screen.h index d6cc3a11..22dff03f 100644 --- a/chrome/browser/ash/login/screens/sync_consent_screen.h +++ b/chrome/browser/ash/login/screens/sync_consent_screen.h
@@ -97,7 +97,7 @@ ~SyncConsentScreen() override; // Inits `user_`, its `profile_` and `behavior_` before using the screen. - void Init(const WizardContext* context); + void Init(const WizardContext& context); // syncer::SyncServiceObserver: void OnStateChanged(syncer::SyncService* sync) override; @@ -138,7 +138,7 @@ void Finish(Result result); // BaseScreen: - bool MaybeSkip(WizardContext* context) override; + bool MaybeSkip(WizardContext& context) override; void ShowImpl() override; void HideImpl() override;
diff --git a/chrome/browser/ash/login/screens/terms_of_service_screen.cc b/chrome/browser/ash/login/screens/terms_of_service_screen.cc index 2e3dc6e..7f1f771b 100644 --- a/chrome/browser/ash/login/screens/terms_of_service_screen.cc +++ b/chrome/browser/ash/login/screens/terms_of_service_screen.cc
@@ -120,11 +120,11 @@ StartDownload(); } -bool TermsOfServiceScreen::MaybeSkip(WizardContext* context) { +bool TermsOfServiceScreen::MaybeSkip(WizardContext& context) { // Only show the Terms of Service when Terms of Service have been specified // through policy. In all other cases, advance to the post-ToS part // immediately. - if (context->skip_post_login_screens_for_tests || + if (context.skip_post_login_screens_for_tests || !ProfileManager::GetActiveUserProfile()->GetPrefs()->IsManagedPreference( prefs::kTermsOfServiceURL)) { exit_callback_.Run(Result::NOT_APPLICABLE);
diff --git a/chrome/browser/ash/login/screens/terms_of_service_screen.h b/chrome/browser/ash/login/screens/terms_of_service_screen.h index 25ff798..3c77007 100644 --- a/chrome/browser/ash/login/screens/terms_of_service_screen.h +++ b/chrome/browser/ash/login/screens/terms_of_service_screen.h
@@ -68,7 +68,7 @@ static base::FilePath GetTosFilePath(); private: // BaseScreen: - bool MaybeSkip(WizardContext* context) override; + bool MaybeSkip(WizardContext& context) override; void ShowImpl() override; void HideImpl() override; void OnUserAction(const base::Value::List& args) override;
diff --git a/chrome/browser/ash/login/screens/theme_selection_screen.cc b/chrome/browser/ash/login/screens/theme_selection_screen.cc index 0ef9cca..18301c4 100644 --- a/chrome/browser/ash/login/screens/theme_selection_screen.cc +++ b/chrome/browser/ash/login/screens/theme_selection_screen.cc
@@ -54,8 +54,8 @@ ThemeSelectionScreen::~ThemeSelectionScreen() = default; -bool ThemeSelectionScreen::MaybeSkip(WizardContext* context) { - if (context->skip_post_login_screens_for_tests) { +bool ThemeSelectionScreen::MaybeSkip(WizardContext& context) { + if (context.skip_post_login_screens_for_tests) { exit_callback_.Run(Result::kNotApplicable); return true; }
diff --git a/chrome/browser/ash/login/screens/theme_selection_screen.h b/chrome/browser/ash/login/screens/theme_selection_screen.h index b68d9f95..a5f8331c 100644 --- a/chrome/browser/ash/login/screens/theme_selection_screen.h +++ b/chrome/browser/ash/login/screens/theme_selection_screen.h
@@ -50,7 +50,7 @@ } private: - bool MaybeSkip(WizardContext* context) override; + bool MaybeSkip(WizardContext& context) override; void ShowImpl() override; void HideImpl() override; void OnUserAction(const base::Value::List& args) override;
diff --git a/chrome/browser/ash/login/screens/update_screen.cc b/chrome/browser/ash/login/screens/update_screen.cc index a0278c6c..0f6a2f3 100644 --- a/chrome/browser/ash/login/screens/update_screen.cc +++ b/chrome/browser/ash/login/screens/update_screen.cc
@@ -121,21 +121,21 @@ UpdateScreen::~UpdateScreen() = default; -bool UpdateScreen::MaybeSkip(WizardContext* context) { - if (context->enrollment_triggered_early) { +bool UpdateScreen::MaybeSkip(WizardContext& context) { + if (context.enrollment_triggered_early) { LOG(WARNING) << "Skip OOBE Update because of enrollment request."; exit_callback_.Run(VersionUpdater::Result::UPDATE_SKIPPED); return true; } - if (ash::IsRollbackFlow(*context)) { + if (ash::IsRollbackFlow(context)) { LOG(WARNING) << "Skip OOBE Update because enterprise rollback just happened."; exit_callback_.Run(VersionUpdater::Result::UPDATE_SKIPPED); return true; } - if (!context->is_branded_build) { + if (!context.is_branded_build) { LOG(WARNING) << "Skip OOBE Update because of not branded build."; exit_callback_.Run(VersionUpdater::Result::UPDATE_SKIPPED); return true;
diff --git a/chrome/browser/ash/login/screens/update_screen.h b/chrome/browser/ash/login/screens/update_screen.h index a6feef10..e431881 100644 --- a/chrome/browser/ash/login/screens/update_screen.h +++ b/chrome/browser/ash/login/screens/update_screen.h
@@ -119,7 +119,7 @@ protected: // BaseScreen: - bool MaybeSkip(WizardContext* context) override; + bool MaybeSkip(WizardContext& context) override; void ShowImpl() override; void HideImpl() override; void OnUserAction(const base::Value::List& args) override;
diff --git a/chrome/browser/ash/login/screens/user_creation_screen.cc b/chrome/browser/ash/login/screens/user_creation_screen.cc index 2b7baed..f6ba9225 100644 --- a/chrome/browser/ash/login/screens/user_creation_screen.cc +++ b/chrome/browser/ash/login/screens/user_creation_screen.cc
@@ -67,16 +67,16 @@ test_exit_delegate = test_delegate; } -bool UserCreationScreen::MaybeSkip(WizardContext* context) { +bool UserCreationScreen::MaybeSkip(WizardContext& context) { if (g_browser_process->platform_part() ->browser_policy_connector_ash() ->IsDeviceEnterpriseManaged() || - context->skip_to_login_for_tests) { - context->is_user_creation_enabled = false; + context.skip_to_login_for_tests) { + context.is_user_creation_enabled = false; RunExitCallback(Result::SKIPPED); return true; } - context->is_user_creation_enabled = true; + context.is_user_creation_enabled = true; return false; }
diff --git a/chrome/browser/ash/login/screens/user_creation_screen.h b/chrome/browser/ash/login/screens/user_creation_screen.h index 3d68e23..c233a67 100644 --- a/chrome/browser/ash/login/screens/user_creation_screen.h +++ b/chrome/browser/ash/login/screens/user_creation_screen.h
@@ -60,7 +60,7 @@ private: // BaseScreen: - bool MaybeSkip(WizardContext* context) override; + bool MaybeSkip(WizardContext& context) override; void ShowImpl() override; void HideImpl() override; void OnUserAction(const base::Value::List& args) override;
diff --git a/chrome/browser/ash/login/wizard_controller.cc b/chrome/browser/ash/login/wizard_controller.cc index e4adfd7..361282f 100644 --- a/chrome/browser/ash/login/wizard_controller.cc +++ b/chrome/browser/ash/login/wizard_controller.cc
@@ -2014,7 +2014,7 @@ VLOG(1) << "SetCurrentScreen: " << (new_current ? new_current->screen_id().name : "null"); - if (new_current && new_current->MaybeSkip(wizard_context_)) { + if (new_current && new_current->MaybeSkip(*wizard_context_)) { RecordUMAHistogramForOOBEStepShownStatus(new_current->screen_id(), ScreenShownStatus::kSkipped); return; @@ -2349,7 +2349,7 @@ void WizardController::SkipPostLoginScreensForTesting() { wizard_context_->skip_post_login_screens_for_tests = true; auto* current_screen = default_controller()->current_screen(); - if (current_screen && !current_screen->MaybeSkip(wizard_context_)) { + if (current_screen && !current_screen->MaybeSkip(*wizard_context_)) { LOG(WARNING) << __func__ << ": Ignore screen " << current_screen->screen_id().name; }
diff --git a/chrome/browser/ash/mojo_service_manager/connection_helper.cc b/chrome/browser/ash/mojo_service_manager/connection_helper.cc index a2f650a..9ed518c 100644 --- a/chrome/browser/ash/mojo_service_manager/connection_helper.cc +++ b/chrome/browser/ash/mojo_service_manager/connection_helper.cc
@@ -28,6 +28,10 @@ } #if !BUILDFLAG(USE_REAL_CHROMEOS_SERVICES) +// The security context of ash-chrome. This will be used as the identity to +// access fake service manager. +constexpr char kAshSecurityContext[] = "u:r:cros_browser:s0"; + void ResetFakeConnection( std::unique_ptr<service_manager::FakeMojoServiceManager> fake_service_manager) { @@ -41,7 +45,7 @@ auto fake_service_manager = std::make_unique<service_manager::FakeMojoServiceManager>(); service_manager::SetServiceManagerRemoteForTesting( - fake_service_manager->BindNewPipeAndPassRemote()); + fake_service_manager->AddNewPipeAndPassRemote(kAshSecurityContext)); return base::ScopedClosureRunner{ base::BindOnce(&ResetFakeConnection, std::move(fake_service_manager))};
diff --git a/chrome/browser/ash/settings/owner_pending_setting_controller.cc b/chrome/browser/ash/settings/owner_pending_setting_controller.cc index 36ed811..25e712b 100644 --- a/chrome/browser/ash/settings/owner_pending_setting_controller.cc +++ b/chrome/browser/ash/settings/owner_pending_setting_controller.cc
@@ -178,7 +178,7 @@ absl::optional<base::Value> OwnerPendingSettingController::GetPendingValue() const { if (local_state_->HasPrefPath(pending_pref_name_)) { - return local_state_->Get(pending_pref_name_)->Clone(); + return local_state_->GetValue(pending_pref_name_).Clone(); } return absl::nullopt; }
diff --git a/chrome/browser/banners/app_banner_manager_browsertest.cc b/chrome/browser/banners/app_banner_manager_browsertest.cc index 45d6d4b..de81e5c 100644 --- a/chrome/browser/banners/app_banner_manager_browsertest.cc +++ b/chrome/browser/banners/app_banner_manager_browsertest.cc
@@ -726,7 +726,7 @@ struct FeatureOperatorOverload { bool operator()(const base::Feature& feature1, const base::Feature& feature2) const { - return std::strcmp(feature1.name, feature2.name) == 0; + return std::strcmp(feature1.name, feature2.name) < 0; } };
diff --git a/chrome/browser/chrome_browser_interface_binders.cc b/chrome/browser/chrome_browser_interface_binders.cc index 513698d..4c2bf4d 100644 --- a/chrome/browser/chrome_browser_interface_binders.cc +++ b/chrome/browser/chrome_browser_interface_binders.cc
@@ -248,6 +248,8 @@ #include "chrome/browser/ui/webui/chromeos/audio/audio.mojom.h" #include "chrome/browser/ui/webui/chromeos/audio/audio_ui.h" #include "chrome/browser/ui/webui/chromeos/bluetooth_pairing_dialog.h" +#include "chrome/browser/ui/webui/chromeos/cloud_upload/cloud_upload.mojom.h" +#include "chrome/browser/ui/webui/chromeos/cloud_upload/cloud_upload_ui.h" #include "chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer.mojom.h" #include "chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_ui.h" #include "chrome/browser/ui/webui/chromeos/crostini_upgrader/crostini_upgrader.mojom.h" @@ -1207,6 +1209,12 @@ chromeos::ManageMirrorSyncUI>(map); } + if (ash::features::IsUploadOfficeToCloudEnabled()) { + RegisterWebUIControllerInterfaceBinder< + chromeos::cloud_upload::mojom::PageHandlerFactory, + chromeos::cloud_upload::CloudUploadUI>(map); + } + #endif // BUILDFLAG(IS_CHROMEOS_ASH) #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \
diff --git a/chrome/browser/chromeos/launcher_search/search_util.cc b/chrome/browser/chromeos/launcher_search/search_util.cc index 6391056..1affc5c 100644 --- a/chrome/browser/chromeos/launcher_search/search_util.cc +++ b/chrome/browser/chromeos/launcher_search/search_util.cc
@@ -301,14 +301,13 @@ result->description = match.description; result->description_type = ClassesToType(match.description_class); + // This may not be the final type. Bookmarks take precedence. + result->omnibox_type = MatchTypeToOmniboxType(match.type); + if (match.type == AutocompleteMatchType::SEARCH_SUGGEST_ENTITY && !match.image_url.is_empty()) { - result->omnibox_type = SearchResult::OmniboxType::kRichImage; result->image_url = match.image_url; } else { - // This may not be the final type. Bookmarks take precedence. - result->omnibox_type = MatchTypeToOmniboxType(match.type); - // Set the favicon if this result is eligible. bool use_favicon = result->omnibox_type == SearchResult::OmniboxType::kDomain ||
diff --git a/chrome/browser/chromeos/launcher_search/search_util_unittest.cc b/chrome/browser/chromeos/launcher_search/search_util_unittest.cc index 3061d82..263844f 100644 --- a/chrome/browser/chromeos/launcher_search/search_util_unittest.cc +++ b/chrome/browser/chromeos/launcher_search/search_util_unittest.cc
@@ -92,7 +92,7 @@ EXPECT_EQ(result->is_omnibox_search, mojom::SearchResult::OptionalBool::kTrue); EXPECT_EQ(result->is_answer, mojom::SearchResult::OptionalBool::kFalse); - EXPECT_EQ(result->omnibox_type, mojom::SearchResult::OmniboxType::kRichImage); + EXPECT_EQ(result->omnibox_type, mojom::SearchResult::OmniboxType::kSearch); ASSERT_TRUE(result->image_url.has_value()); EXPECT_EQ(result->image_url.value(), GURL("http://www.example.com/image.jpeg"));
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_rules_manager_impl.cc b/chrome/browser/chromeos/policy/dlp/dlp_rules_manager_impl.cc index e3680ba..0f8c1d3 100644 --- a/chrome/browser/chromeos/policy/dlp/dlp_rules_manager_impl.cc +++ b/chrome/browser/chromeos/policy/dlp/dlp_rules_manager_impl.cc
@@ -42,6 +42,8 @@ using RulesConditionsMap = std::map<RuleId, UrlConditionId>; +constexpr char kWildCardMatching[] = "*"; + DlpRulesManager::Restriction GetClassMapping(const std::string& restriction) { static constexpr auto kRestrictionsMap = base::MakeFixedFlatMap<base::StringPiece, DlpRulesManager::Restriction>( @@ -389,7 +391,12 @@ std::map<Level, std::set<std::string>> result; for (auto it : destination_level_map) { - result[it.second].insert(it.first); + if (it.first == kWildCardMatching) { + result[it.second] = {it.first}; + } else if (result[it.second].find(kWildCardMatching) == + result[it.second].end()) { + result[it.second].insert(it.first); + } } return result; }
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_rules_manager_impl_unittest.cc b/chrome/browser/chromeos/policy/dlp/dlp_rules_manager_impl_unittest.cc index f81e7b0..35501cc7 100644 --- a/chrome/browser/chromeos/policy/dlp/dlp_rules_manager_impl_unittest.cc +++ b/chrome/browser/chromeos/policy/dlp/dlp_rules_manager_impl_unittest.cc
@@ -1036,7 +1036,7 @@ src_urls1.Append(kExampleUrl); base::Value dst_urls1(base::Value::Type::LIST); dst_urls1.Append(kCompanyUrl); - // Specific destinations and the wildcard should all be returned. + // Since there is a wildcard, all specific destinations will be ignored. dst_urls1.Append(kWildCardMatching); base::Value restrictions1(base::Value::Type::LIST); restrictions1.Append(dlp_test_util::CreateRestrictionWithLevel( @@ -1077,7 +1077,6 @@ auto result = dlp_rules_manager_.GetAggregatedDestinations( GURL(kExampleUrl), DlpRulesManager::Restriction::kClipboard); std::map<DlpRulesManager::Level, std::set<std::string>> expected; - expected[DlpRulesManager::Level::kBlock].insert(kCompanyUrl); expected[DlpRulesManager::Level::kBlock].insert(kWildCardMatching); expected[DlpRulesManager::Level::kWarn].insert(kGmailUrl); expected[DlpRulesManager::Level::kReport].insert(kGoogleUrl);
diff --git a/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_apitest.cc b/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_apitest.cc index 651912e..aa71b2e5 100644 --- a/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_apitest.cc +++ b/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_apitest.cc
@@ -29,9 +29,13 @@ #include "services/network/test/test_url_loader_factory.h" #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) +#include "base/files/file_path.h" +#include "base/process/process.h" +#include "base/strings/string_util.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/policy/chrome_browser_policy_connector.h" #include "components/device_signals/core/common/signals_features.h" +#include "components/device_signals/core/system_signals/platform_utils.h" // nogncheck #endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) #if !BUILDFLAG(IS_CHROMEOS_ASH) @@ -550,6 +554,61 @@ #endif // BUILDFLAG(IS_WIN) +#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) + +IN_PROC_BROWSER_TEST_F(EnterpriseReportingPrivateApiTest, + GetFileSystemInfo_Success) { + // Use the test runner process and binary as test parameters, as it will always + // be running. + auto test_runner_file_path = + device_signals::GetProcessExePath(base::Process::Current().Pid()); + + ASSERT_TRUE(test_runner_file_path.has_value()); + ASSERT_FALSE(test_runner_file_path->empty()); + + constexpr char kTest[] = R"( + chrome.test.assertEq( + 'function', + typeof chrome.enterprise.reportingPrivate.getFileSystemInfo); + const userContext = {userId: '%s'}; + + const executablePath = '%s'; + const fileItem = { + path: executablePath, + computeSha256: true, + computeExecutableMetadata: true + }; + + const request = { userContext, options: [fileItem] }; + + chrome.enterprise.reportingPrivate.getFileSystemInfo( + request, + (fileItems) => { + chrome.test.assertNoLastError(); + chrome.test.assertTrue(fileItems instanceof Array); + chrome.test.assertEq(1, fileItems.length); + + const fileItemResponse = fileItems[0]; + chrome.test.assertEq(executablePath, fileItemResponse.path); + chrome.test.assertEq('FOUND', fileItemResponse.presence); + chrome.test.assertTrue(!!fileItemResponse.sha256Hash); + chrome.test.assertTrue(fileItemResponse.isRunning); + + chrome.test.notifyPass(); + }); + )"; + + // Escape all backslashes. + std::string escaped_file_path = test_runner_file_path->AsUTF8Unsafe(); + base::ReplaceSubstringsAfterOffset(&escaped_file_path, 0U, "\\", "\\\\"); + + AccountInfo account_info = SignIn("some-email@example.com"); + RunTest(base::StringPrintf(kTest, account_info.gaia.c_str(), + escaped_file_path.c_str())); +} + +#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) + #if BUILDFLAG(IS_CHROMEOS) static void RunTestUsingProfile(const std::string& background_js, Profile* profile) {
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index b12e65c5..d65b6b3 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -1401,6 +1401,11 @@ "expiry_milestone": 104 }, { + "name": "disruptive-notification-permission-revocation", + "owners": [ "engedy", "ravjit", "andypaicu", "hkamila", "elklm" ], + "expiry_milestone": 115 + }, + { "name": "dm-token-deletion", "owners": [ "igorruvinov", "zmin" ], "expiry_milestone": 115 @@ -3298,6 +3303,11 @@ "expiry_milestone": 107 }, { + "name": "experience-kit-maps", + "owners": [ "djean@google.com", "erahmaoui@google.com", "bling-flags@google.com" ], + "expiry_milestone": 109 + }, + { "name": "explore-sites", "owners": [ "chili", "dewittj" ], "expiry_milestone": 102
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index c8405e8..b741fad 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -755,6 +755,13 @@ const char kDiscountConsentV2Name[] = "Discount Consent V2"; const char kDiscountConsentV2Description[] = "Enables Discount Consent V2"; +const char kDisruptiveNotificationPermissionRevocationName[] = + "Disruptive notification permission revocation"; +const char kDisruptiveNotificationPermissionRevocationDescription[] = + "Enables revoking the notification permission on sites that send " + "disruptive notifications unless the permission was granted through a " + "prompt that informed the user about this possibility."; + const char kIsolatedAppOriginsName[] = "Isolated App Origins"; const char kIsolatedAppOriginsDescription[] = "Enables Isolated App policy enforcement and related APIs (e.g. Direct " @@ -5144,11 +5151,6 @@ const char kExoOrdinalMotionDescription[] = "Send unaccelerated values as raw motion events to linux applications."; -const char kExoPointerLockName[] = "Pointer lock for Linux applications"; -const char kExoPointerLockDescription[] = - "Allow Linux applications to request a pointer lock, i.e. exclusive use of " - "the mouse pointer."; - const char kExoLockNotificationName[] = "Notification bubble for UI lock"; const char kExoLockNotificationDescription[] = "Show a notification bubble once an application has switched to "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 91c5ed2..16db4d8 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -415,6 +415,9 @@ extern const char kDiscountConsentV2Name[]; extern const char kDiscountConsentV2Description[]; +extern const char kDisruptiveNotificationPermissionRevocationName[]; +extern const char kDisruptiveNotificationPermissionRevocationDescription[]; + extern const char kDoubleBufferCompositingName[]; extern const char kDoubleBufferCompositingDescription[]; @@ -2941,9 +2944,6 @@ extern const char kExoOrdinalMotionName[]; extern const char kExoOrdinalMotionDescription[]; -extern const char kExoPointerLockName[]; -extern const char kExoPointerLockDescription[]; - extern const char kExoLockNotificationName[]; extern const char kExoLockNotificationDescription[];
diff --git a/chrome/browser/history_clusters/java/src/org/chromium/chrome/browser/history_clusters/HistoryClustersCoordinator.java b/chrome/browser/history_clusters/java/src/org/chromium/chrome/browser/history_clusters/HistoryClustersCoordinator.java index 56a56d6..9524fca 100644 --- a/chrome/browser/history_clusters/java/src/org/chromium/chrome/browser/history_clusters/HistoryClustersCoordinator.java +++ b/chrome/browser/history_clusters/java/src/org/chromium/chrome/browser/history_clusters/HistoryClustersCoordinator.java
@@ -147,6 +147,11 @@ return mActivityContentView; } + /** Handles a back button press event, returning true if the event is handled. */ + public boolean onBackPressed() { + return mSelectableListLayout.onBackPressed(); + } + void inflateActivityView() { mAdapter = new SimpleRecyclerViewAdapter(mModelList); mAdapter.registerType(
diff --git a/chrome/browser/metrics/variations/variations_http_headers_browsertest.cc b/chrome/browser/metrics/variations/variations_http_headers_browsertest.cc index 0957d0f..6ad1517 100644 --- a/chrome/browser/metrics/variations/variations_http_headers_browsertest.cc +++ b/chrome/browser/metrics/variations/variations_http_headers_browsertest.cc
@@ -621,12 +621,11 @@ local_state->SetInteger(metrics::prefs::kMetricsLowEntropySource, 5); } -// TODO(crbug.com/1349693): Re-enable this test IN_PROC_BROWSER_TEST_F(VariationsHttpHeadersBrowserTest, - DISABLED_CheckLowEntropySourceValue) { + CheckLowEntropySourceValue) { std::unique_ptr<const base::FieldTrial::EntropyProvider> low_entropy_provider = g_browser_process->GetMetricsServicesManager() - ->CreateEntropyProviderForTesting(); + ->CreateLowEntropyProviderForTesting(); // Create a trial with 100 groups and variation ids to validate that the group // reported in the variations header is actually based on the low entropy
diff --git a/chrome/browser/permissions/abusive_origin_notifications_permission_revocation_config.cc b/chrome/browser/permissions/abusive_origin_notifications_permission_revocation_config.cc deleted file mode 100644 index df8fd59..0000000 --- a/chrome/browser/permissions/abusive_origin_notifications_permission_revocation_config.cc +++ /dev/null
@@ -1,12 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/permissions/abusive_origin_notifications_permission_revocation_config.h" - -#include "chrome/common/chrome_features.h" - -bool AbusiveOriginNotificationsPermissionRevocationConfig::IsEnabled() { - return base::FeatureList::IsEnabled( - features::kAbusiveNotificationPermissionRevocation); -}
diff --git a/chrome/browser/permissions/abusive_origin_notifications_permission_revocation_config.h b/chrome/browser/permissions/abusive_origin_notifications_permission_revocation_config.h deleted file mode 100644 index 629a086..0000000 --- a/chrome/browser/permissions/abusive_origin_notifications_permission_revocation_config.h +++ /dev/null
@@ -1,19 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_PERMISSIONS_ABUSIVE_ORIGIN_NOTIFICATIONS_PERMISSION_REVOCATION_CONFIG_H_ -#define CHROME_BROWSER_PERMISSIONS_ABUSIVE_ORIGIN_NOTIFICATIONS_PERMISSION_REVOCATION_CONFIG_H_ - -#include "build/build_config.h" - -// Field trial configuration for the abusive origin notifications permission -// revocation. -class AbusiveOriginNotificationsPermissionRevocationConfig { - public: - // Whether or not automatically revoking the notification permission from - // abusive origins is enabled. - static bool IsEnabled(); -}; - -#endif // CHROME_BROWSER_PERMISSIONS_ABUSIVE_ORIGIN_NOTIFICATIONS_PERMISSION_REVOCATION_CONFIG_H_
diff --git a/chrome/browser/permissions/chrome_permissions_client.cc b/chrome/browser/permissions/chrome_permissions_client.cc index 3728028..5b7804cf 100644 --- a/chrome/browser/permissions/chrome_permissions_client.cc +++ b/chrome/browser/permissions/chrome_permissions_client.cc
@@ -17,12 +17,12 @@ #include "chrome/browser/content_settings/host_content_settings_map_factory.h" #include "chrome/browser/engagement/important_sites_util.h" #include "chrome/browser/metrics/ukm_background_recorder_service.h" -#include "chrome/browser/permissions/abusive_origin_permission_revocation_request.h" #include "chrome/browser/permissions/adaptive_quiet_notification_permission_ui_enabler.h" #include "chrome/browser/permissions/contextual_notification_permission_ui_selector.h" #include "chrome/browser/permissions/permission_actions_history_factory.h" #include "chrome/browser/permissions/permission_decision_auto_blocker_factory.h" #include "chrome/browser/permissions/permission_manager_factory.h" +#include "chrome/browser/permissions/permission_revocation_request.h" #include "chrome/browser/permissions/prediction_based_permission_ui_selector.h" #include "chrome/browser/permissions/pref_notification_permission_ui_selector.h" #include "chrome/browser/permissions/quiet_notification_permission_ui_config.h" @@ -335,9 +335,11 @@ (quiet_ui_reason.value() == QuietUiReason::kTriggeredDueToAbusiveRequests || quiet_ui_reason.value() == - QuietUiReason::kTriggeredDueToAbusiveContent)) { - AbusiveOriginPermissionRevocationRequest:: - ExemptOriginFromFutureRevocations(profile, origin); + QuietUiReason::kTriggeredDueToAbusiveContent || + quiet_ui_reason.value() == + QuietUiReason::kTriggeredDueToDisruptiveBehavior)) { + PermissionRevocationRequest::ExemptOriginFromFutureRevocations(profile, + origin); } } @@ -368,8 +370,8 @@ } Profile* profile = Profile::FromBrowserContext(browser_context); - return AbusiveOriginPermissionRevocationRequest:: - HasPreviouslyRevokedPermission(profile, origin); + return PermissionRevocationRequest::HasPreviouslyRevokedPermission(profile, + origin); } absl::optional<url::Origin> ChromePermissionsClient::GetAutoApprovalOrigin() {
diff --git a/chrome/browser/permissions/contextual_notification_permission_ui_selector.cc b/chrome/browser/permissions/contextual_notification_permission_ui_selector.cc index c9a32338..3ee09f9a 100644 --- a/chrome/browser/permissions/contextual_notification_permission_ui_selector.cc +++ b/chrome/browser/permissions/contextual_notification_permission_ui_selector.cc
@@ -98,6 +98,14 @@ return Decision(QuietUiReason::kTriggeredDueToAbusiveContent, Decision::ShowNoWarning()); } + case CrowdDenyPreloadData::SiteReputation::DISRUPTIVE_BEHAVIOR: { + DCHECK(!site_reputation->warning_only()); + + if (!Config::IsDisruptiveBehaviorRequestBlockingEnabled()) + return absl::nullopt; + return Decision(QuietUiReason::kTriggeredDueToDisruptiveBehavior, + Decision::ShowNoWarning()); + } case CrowdDenyPreloadData::SiteReputation::UNKNOWN: { return absl::nullopt; } @@ -143,9 +151,10 @@ return; } - // Even if the quiet UI is enabled on all sites, the crowd deny and abuse - // trigger conditions must be evaluated first, so that the corresponding, - // less prominent UI and the strings are shown on blocklisted origins. + // Even if the quiet UI is enabled on all sites, the crowd deny, abuse and + // disruption trigger conditions must be evaluated first, so that the + // corresponding, less prominent UI and the strings are shown on blocklisted + // origins. EvaluatePerSiteTriggers(url::Origin::Create(request->requesting_origin())); }
diff --git a/chrome/browser/permissions/contextual_notification_permission_ui_selector_unittest.cc b/chrome/browser/permissions/contextual_notification_permission_ui_selector_unittest.cc index 2171d8d9..fe578bf 100644 --- a/chrome/browser/permissions/contextual_notification_permission_ui_selector_unittest.cc +++ b/chrome/browser/permissions/contextual_notification_permission_ui_selector_unittest.cc
@@ -57,6 +57,7 @@ constexpr char kTestOriginAbusiveContent[] = "https://abusive-content.com/"; constexpr char kTestOriginAbusiveContentWarn[] = "https://warn-abusive-content.com/"; +constexpr char kTestOriginDisruptive[] = "https://disruptive.com/"; constexpr const char* kAllTestingOrigins[] = { kTestOriginNoData, @@ -69,7 +70,7 @@ kTestOriginAbusivePromptsWarn, kTestOriginAbusiveContent, kTestOriginAbusiveContentWarn, -}; + kTestOriginDisruptive}; } // namespace @@ -177,6 +178,13 @@ testing_preload_data_.SetOriginReputation( url::Origin::Create(GURL(kTestOriginAbusiveContentWarn)), std::move(reputation_abusive_content_warn)); + + SiteReputation reputation_disruptive; + reputation_disruptive.set_notification_ux_quality( + SiteReputation::DISRUPTIVE_BEHAVIOR); + testing_preload_data_.SetOriginReputation( + url::Origin::Create(GURL(kTestOriginDisruptive)), + std::move(reputation_disruptive)); } void AddUrlToFakeApiAbuseBlocklist(const GURL& url) { @@ -245,6 +253,7 @@ {Config::kEnableAbusiveRequestWarning, "true"}, {Config::kEnableAbusiveContentTriggeredRequestBlocking, "true"}, {Config::kEnableAbusiveContentTriggeredRequestWarning, "true"}, + {Config::kEnableDisruptiveBehaviorRequestBlocking, "true"}, {Config::kCrowdDenyHoldBackChance, "0.0"}}); LoadTestPreloadData(); @@ -290,6 +299,8 @@ QuietUiReason::kTriggeredDueToAbusiveContent}, {kTestOriginAbusiveContentWarn, Decision::UseNormalUi(), WarningReason::kAbusiveContent}, + {kTestOriginDisruptive, + QuietUiReason::kTriggeredDueToDisruptiveBehavior}, }; SCOPED_TRACE(quiet_ui_enabled_in_prefs ? "Quiet UI enabled in prefs" @@ -330,7 +341,9 @@ {Config::kEnableAbusiveRequestBlocking, "false"}, {Config::kEnableAbusiveRequestWarning, "false"}, {Config::kEnableAbusiveContentTriggeredRequestBlocking, "false"}, - {Config::kEnableAbusiveContentTriggeredRequestWarning, "false"}}); + {Config::kEnableAbusiveContentTriggeredRequestWarning, "false"}, + {Config::kEnableDisruptiveBehaviorRequestBlocking, "false"}, + {Config::kEnableDisruptiveBehaviorRequestWarning, "false"}}); SetQuietUiEnabledInPrefs(true); LoadTestPreloadData(); @@ -355,6 +368,8 @@ {Config::kEnableAbusiveRequestWarning, "false"}, {Config::kEnableAbusiveContentTriggeredRequestBlocking, "false"}, {Config::kEnableAbusiveContentTriggeredRequestWarning, "false"}, + {Config::kEnableDisruptiveBehaviorRequestBlocking, "false"}, + {Config::kEnableDisruptiveBehaviorRequestWarning, "false"}, {Config::kCrowdDenyHoldBackChance, "0.0"}}); LoadTestPreloadData(); @@ -373,6 +388,7 @@ {kTestOriginAbusivePromptsWarn}, {kTestOriginAbusiveContent}, {kTestOriginAbusiveContentWarn}, + {kTestOriginDisruptive}, }; for (const auto& test : kTestCases) { @@ -395,7 +411,9 @@ {Config::kEnableAbusiveRequestBlocking, "false"}, {Config::kEnableAbusiveRequestWarning, "false"}, {Config::kEnableAbusiveContentTriggeredRequestBlocking, "true"}, - {Config::kEnableAbusiveContentTriggeredRequestWarning, "false"}}); + {Config::kEnableAbusiveContentTriggeredRequestWarning, "false"}, + {Config::kEnableDisruptiveBehaviorRequestBlocking, "false"}, + {Config::kEnableDisruptiveBehaviorRequestWarning, "false"}}); LoadTestPreloadData(); LoadTestSafeBrowsingBlocklist(); @@ -413,6 +431,7 @@ {kTestOriginAbusivePromptsWarn}, {kTestOriginAbusiveContent, QuietUiReason::kTriggeredDueToAbusiveContent}, {kTestOriginAbusiveContentWarn}, + {kTestOriginDisruptive}, }; for (const auto& test : kTestCases) { @@ -435,7 +454,8 @@ {Config::kEnableAbusiveRequestBlocking, "false"}, {Config::kEnableAbusiveRequestWarning, "false"}, {Config::kEnableAbusiveContentTriggeredRequestBlocking, "false"}, - {Config::kEnableAbusiveContentTriggeredRequestWarning, "true"}}); + {Config::kEnableAbusiveContentTriggeredRequestWarning, "true"}, + {Config::kEnableDisruptiveBehaviorRequestBlocking, "false"}}); LoadTestPreloadData(); LoadTestSafeBrowsingBlocklist(); @@ -454,6 +474,7 @@ {kTestOriginAbusiveContent}, {kTestOriginAbusiveContentWarn, Decision::UseNormalUi(), WarningReason::kAbusiveContent}, + {kTestOriginDisruptive}, }; for (const auto& test : kTestCases) { @@ -476,7 +497,9 @@ {Config::kEnableAbusiveRequestBlocking, "true"}, {Config::kEnableAbusiveRequestWarning, "false"}, {Config::kEnableAbusiveContentTriggeredRequestBlocking, "false"}, - {Config::kEnableAbusiveContentTriggeredRequestWarning, "false"}}); + {Config::kEnableAbusiveContentTriggeredRequestWarning, "false"}, + {Config::kEnableDisruptiveBehaviorRequestBlocking, "false"}, + {Config::kEnableDisruptiveBehaviorRequestWarning, "false"}}); LoadTestPreloadData(); LoadTestSafeBrowsingBlocklist(); @@ -496,6 +519,7 @@ {kTestOriginAbusivePromptsWarn}, {kTestOriginAbusiveContent}, {kTestOriginAbusiveContentWarn}, + {kTestOriginDisruptive}, }; for (const auto& test : kTestCases) { @@ -518,7 +542,8 @@ {Config::kEnableAbusiveRequestBlocking, "false"}, {Config::kEnableAbusiveRequestWarning, "true"}, {Config::kEnableAbusiveContentTriggeredRequestBlocking, "false"}, - {Config::kEnableAbusiveContentTriggeredRequestWarning, "false"}}); + {Config::kEnableAbusiveContentTriggeredRequestWarning, "false"}, + {Config::kEnableDisruptiveBehaviorRequestBlocking, "false"}}); LoadTestPreloadData(); LoadTestSafeBrowsingBlocklist(); @@ -537,6 +562,49 @@ WarningReason::kAbusiveRequests}, {kTestOriginAbusiveContent}, {kTestOriginAbusiveContentWarn}, + {kTestOriginDisruptive}, + }; + + for (const auto& test : kTestCases) { + SCOPED_TRACE(test.origin_string); + QueryAndExpectDecisionForUrl(GURL(test.origin_string), + test.expected_ui_reason, + test.expected_warning_reason); + } +} + +// The feature is enabled but only the `disruptive behavior` trigger is enabled. +TEST_F(ContextualNotificationPermissionUiSelectorTest, + OnlyDisruptiveBehaviorRequestBlockingEnabled) { + using Config = QuietNotificationPermissionUiConfig; + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeatureWithParameters( + features::kQuietNotificationPrompts, + {{Config::kEnableAdaptiveActivation, "true"}, + {Config::kEnableCrowdDenyTriggering, "false"}, + {Config::kEnableAbusiveRequestBlocking, "false"}, + {Config::kEnableAbusiveRequestWarning, "false"}, + {Config::kEnableAbusiveContentTriggeredRequestBlocking, "false"}, + {Config::kEnableAbusiveContentTriggeredRequestWarning, "false"}, + {Config::kEnableDisruptiveBehaviorRequestBlocking, "true"}}); + + LoadTestPreloadData(); + LoadTestSafeBrowsingBlocklist(); + + const struct { + const char* origin_string; + absl::optional<QuietUiReason> expected_ui_reason = Decision::UseNormalUi(); + absl::optional<WarningReason> expected_warning_reason = + Decision::ShowNoWarning(); + } kTestCases[] = { + {kTestOriginSpammy}, + {kTestOriginSpammyWarn}, + {kTestOriginAbusivePrompts}, + {kTestOriginSubDomainOfAbusivePrompts}, + {kTestOriginAbusivePromptsWarn}, + {kTestOriginAbusiveContent}, + {kTestOriginAbusiveContentWarn}, + {kTestOriginDisruptive, QuietUiReason::kTriggeredDueToDisruptiveBehavior}, }; for (const auto& test : kTestCases) { @@ -576,6 +644,7 @@ {Config::kEnableAbusiveContentTriggeredRequestBlocking, "true"}, {Config::kEnableAbusiveContentTriggeredRequestWarning, "true"}, {Config::kEnableCrowdDenyTriggering, "true"}, + {Config::kEnableDisruptiveBehaviorRequestBlocking, "true"}, {Config::kCrowdDenyHoldBackChance, test.holdback_chance}}); base::HistogramTester histograms;
diff --git a/chrome/browser/permissions/crowd_deny.proto b/chrome/browser/permissions/crowd_deny.proto index 1353e2d6..20337b0 100644 --- a/chrome/browser/permissions/crowd_deny.proto +++ b/chrome/browser/permissions/crowd_deny.proto
@@ -20,6 +20,7 @@ UNSOLICITED_PROMPTS = 2; ABUSIVE_PROMPTS = 3; // Supported as of M84. ABUSIVE_CONTENT = 4; // Supported as of M85. + DISRUPTIVE_BEHAVIOR = 5; } // The quality of the experience users have with notifications on this site.
diff --git a/chrome/browser/permissions/notifications_permission_revocation_config.cc b/chrome/browser/permissions/notifications_permission_revocation_config.cc new file mode 100644 index 0000000..8dd48c8 --- /dev/null +++ b/chrome/browser/permissions/notifications_permission_revocation_config.cc
@@ -0,0 +1,19 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/permissions/notifications_permission_revocation_config.h" + +#include "chrome/common/chrome_features.h" + +bool NotificationsPermissionRevocationConfig:: + IsAbusiveOriginPermissionRevocationEnabled() { + return base::FeatureList::IsEnabled( + features::kAbusiveNotificationPermissionRevocation); +} + +bool NotificationsPermissionRevocationConfig:: + IsDisruptiveOriginPermissionRevocationEnabled() { + return base::FeatureList::IsEnabled( + features::kDisruptiveNotificationPermissionRevocation); +}
diff --git a/chrome/browser/permissions/notifications_permission_revocation_config.h b/chrome/browser/permissions/notifications_permission_revocation_config.h new file mode 100644 index 0000000..85311bc --- /dev/null +++ b/chrome/browser/permissions/notifications_permission_revocation_config.h
@@ -0,0 +1,23 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_PERMISSIONS_NOTIFICATIONS_PERMISSION_REVOCATION_CONFIG_H_ +#define CHROME_BROWSER_PERMISSIONS_NOTIFICATIONS_PERMISSION_REVOCATION_CONFIG_H_ + +#include "build/build_config.h" + +// Field trial configuration for the notifications permission +// revocation. +class NotificationsPermissionRevocationConfig { + public: + // Whether or not automatically revoking the notification permission from + // abusive origins is enabled. + static bool IsAbusiveOriginPermissionRevocationEnabled(); + + // Whether or not automatically revoking the notification permission from + // sites that may send disruptive notifications is enabled. + static bool IsDisruptiveOriginPermissionRevocationEnabled(); +}; + +#endif // CHROME_BROWSER_PERMISSIONS_NOTIFICATIONS_PERMISSION_REVOCATION_CONFIG_H_
diff --git a/chrome/browser/permissions/abusive_origin_permission_revocation_request.cc b/chrome/browser/permissions/permission_revocation_request.cc similarity index 71% rename from chrome/browser/permissions/abusive_origin_permission_revocation_request.cc rename to chrome/browser/permissions/permission_revocation_request.cc index 1d239ac..86246762 100644 --- a/chrome/browser/permissions/abusive_origin_permission_revocation_request.cc +++ b/chrome/browser/permissions/permission_revocation_request.cc
@@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/permissions/abusive_origin_permission_revocation_request.h" +#include "chrome/browser/permissions/permission_revocation_request.h" #include "base/time/default_clock.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" -#include "chrome/browser/permissions/abusive_origin_notifications_permission_revocation_config.h" +#include "chrome/browser/permissions/notifications_permission_revocation_config.h" #include "chrome/browser/permissions/permission_manager_factory.h" #include "chrome/browser/safe_browsing/safe_browsing_service.h" #include "components/content_settings/core/browser/host_content_settings_map.h" @@ -93,52 +93,54 @@ } } // namespace -AbusiveOriginPermissionRevocationRequest:: - AbusiveOriginPermissionRevocationRequest(Profile* profile, - const GURL& origin, - OutcomeCallback callback) +PermissionRevocationRequest::PermissionRevocationRequest( + Profile* profile, + const GURL& origin, + OutcomeCallback callback) : profile_(profile), origin_(origin), callback_(std::move(callback)) { base::SequencedTaskRunnerHandle::Get()->PostTask( FROM_HERE, - base::BindOnce( - &AbusiveOriginPermissionRevocationRequest::CheckAndRevokeIfAbusive, - weak_factory_.GetWeakPtr())); + base::BindOnce(&PermissionRevocationRequest::CheckAndRevokeIfBlocklisted, + weak_factory_.GetWeakPtr())); } -AbusiveOriginPermissionRevocationRequest:: - ~AbusiveOriginPermissionRevocationRequest() = default; +PermissionRevocationRequest::~PermissionRevocationRequest() = default; // static -void AbusiveOriginPermissionRevocationRequest:: - ExemptOriginFromFutureRevocations(Profile* profile, const GURL& origin) { +void PermissionRevocationRequest::ExemptOriginFromFutureRevocations( + Profile* profile, + const GURL& origin) { OriginStatus status = GetOriginStatus(profile, origin); status.is_exempt_from_future_revocations = true; SetOriginStatus(profile, origin, status); } // static -bool AbusiveOriginPermissionRevocationRequest:: - IsOriginExemptedFromFutureRevocations(Profile* profile, - const GURL& origin) { +bool PermissionRevocationRequest::IsOriginExemptedFromFutureRevocations( + Profile* profile, + const GURL& origin) { OriginStatus status = GetOriginStatus(profile, origin); return status.is_exempt_from_future_revocations; } // static -bool AbusiveOriginPermissionRevocationRequest::HasPreviouslyRevokedPermission( +bool PermissionRevocationRequest::HasPreviouslyRevokedPermission( Profile* profile, const GURL& origin) { OriginStatus status = GetOriginStatus(profile, origin); return status.has_been_previously_revoked; } -void AbusiveOriginPermissionRevocationRequest::CheckAndRevokeIfAbusive() { +void PermissionRevocationRequest::CheckAndRevokeIfBlocklisted() { DCHECK(profile_); DCHECK(callback_); - if (!AbusiveOriginNotificationsPermissionRevocationConfig::IsEnabled() || - !safe_browsing::IsSafeBrowsingEnabled(*profile_->GetPrefs()) || - IsOriginExemptedFromFutureRevocations(profile_, origin_)) { + if (!safe_browsing::IsSafeBrowsingEnabled(*profile_->GetPrefs()) || + IsOriginExemptedFromFutureRevocations(profile_, origin_) || + (!NotificationsPermissionRevocationConfig:: + IsAbusiveOriginPermissionRevocationEnabled() && + !NotificationsPermissionRevocationConfig:: + IsDisruptiveOriginPermissionRevocationEnabled())) { NotifyCallback(Outcome::PERMISSION_NOT_REVOKED); return; } @@ -152,12 +154,11 @@ crowd_deny->GetReputationDataForSiteAsync( url::Origin::Create(origin_), - base::BindOnce( - &AbusiveOriginPermissionRevocationRequest::OnSiteReputationReady, - weak_factory_.GetWeakPtr())); + base::BindOnce(&PermissionRevocationRequest::OnSiteReputationReady, + weak_factory_.GetWeakPtr())); } -void AbusiveOriginPermissionRevocationRequest::OnSiteReputationReady( +void PermissionRevocationRequest::OnSiteReputationReady( const CrowdDenyPreloadData::SiteReputation* site_reputation) { if (crowd_deny_request_start_time_.has_value()) { crowd_deny_request_duration_ = @@ -168,23 +169,26 @@ (site_reputation->notification_ux_quality() == CrowdDenyPreloadData::SiteReputation::ABUSIVE_PROMPTS || site_reputation->notification_ux_quality() == - CrowdDenyPreloadData::SiteReputation::ABUSIVE_CONTENT)) { + CrowdDenyPreloadData::SiteReputation::ABUSIVE_CONTENT || + site_reputation->notification_ux_quality() == + CrowdDenyPreloadData::SiteReputation::DISRUPTIVE_BEHAVIOR)) { DCHECK(g_browser_process->safe_browsing_service()); if (g_browser_process->safe_browsing_service()) { safe_browsing_request_.emplace( g_browser_process->safe_browsing_service()->database_manager(), base::DefaultClock::GetInstance(), url::Origin::Create(origin_), - base::BindOnce(&AbusiveOriginPermissionRevocationRequest:: - OnSafeBrowsingVerdictReceived, - weak_factory_.GetWeakPtr())); + base::BindOnce( + &PermissionRevocationRequest::OnSafeBrowsingVerdictReceived, + weak_factory_.GetWeakPtr(), site_reputation)); return; } } NotifyCallback(Outcome::PERMISSION_NOT_REVOKED); } -void AbusiveOriginPermissionRevocationRequest::OnSafeBrowsingVerdictReceived( +void PermissionRevocationRequest::OnSafeBrowsingVerdictReceived( + const CrowdDenyPreloadData::SiteReputation* site_reputation, CrowdDenySafeBrowsingRequest::Verdict verdict) { DCHECK(safe_browsing_request_); DCHECK(profile_); @@ -192,13 +196,21 @@ if (verdict == CrowdDenySafeBrowsingRequest::Verdict::kUnacceptable) { RevokePermission(origin_, profile_); - NotifyCallback(Outcome::PERMISSION_REVOKED_DUE_TO_ABUSE); + if (site_reputation->notification_ux_quality() == + CrowdDenyPreloadData::SiteReputation::ABUSIVE_PROMPTS || + site_reputation->notification_ux_quality() == + CrowdDenyPreloadData::SiteReputation::ABUSIVE_CONTENT) { + NotifyCallback(Outcome::PERMISSION_REVOKED_DUE_TO_ABUSE); + } else if (site_reputation->notification_ux_quality() == + CrowdDenyPreloadData::SiteReputation::DISRUPTIVE_BEHAVIOR) { + NotifyCallback(Outcome::PERMISSION_REVOKED_DUE_TO_DISRUPTIVE_BEHAVIOR); + } } else { NotifyCallback(Outcome::PERMISSION_NOT_REVOKED); } } -void AbusiveOriginPermissionRevocationRequest::NotifyCallback(Outcome outcome) { +void PermissionRevocationRequest::NotifyCallback(Outcome outcome) { if (outcome == Outcome::PERMISSION_NOT_REVOKED && crowd_deny_request_duration_.has_value()) { permissions::PermissionUmaUtil::RecordCrowdDenyDelayedPushNotification(
diff --git a/chrome/browser/permissions/abusive_origin_permission_revocation_request.h b/chrome/browser/permissions/permission_revocation_request.h similarity index 62% rename from chrome/browser/permissions/abusive_origin_permission_revocation_request.h rename to chrome/browser/permissions/permission_revocation_request.h index b6239da..bca4e426 100644 --- a/chrome/browser/permissions/abusive_origin_permission_revocation_request.h +++ b/chrome/browser/permissions/permission_revocation_request.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_PERMISSIONS_ABUSIVE_ORIGIN_PERMISSION_REVOCATION_REQUEST_H_ -#define CHROME_BROWSER_PERMISSIONS_ABUSIVE_ORIGIN_PERMISSION_REVOCATION_REQUEST_H_ +#ifndef CHROME_BROWSER_PERMISSIONS_PERMISSION_REVOCATION_REQUEST_H_ +#define CHROME_BROWSER_PERMISSIONS_PERMISSION_REVOCATION_REQUEST_H_ #include "base/callback.h" #include "base/memory/raw_ptr.h" @@ -17,34 +17,35 @@ class Profile; enum class ContentSettingsType; -// Revokes the notifications permission if an origin marked as abusive. -// This is the case when: +// Revokes the notifications permission if an origin marked as abusive or +// disruptive. This is the case when: // 1) The notifications permission revocation experiment is enabled. -// 2) The origin exists on ABUSIVE_PROMPTS or ABUSIVE_CONTENT blocking lists. +// 2) The origin exists on ABUSIVE_PROMPTS, ABUSIVE_CONTENT or +// DISRUPTIVE_BEHAVIOR blocking lists. // 3) The origin exists on SafeBrowsing. // 4) If a user granted notification permission via quiet permission prompt UI, // revocation will not applied. -class AbusiveOriginPermissionRevocationRequest { +class PermissionRevocationRequest { public: - // The abusive permission revocation verdict for a given origin. + // The permission revocation verdict for a given origin. enum class Outcome { PERMISSION_NOT_REVOKED, PERMISSION_REVOKED_DUE_TO_ABUSE, + PERMISSION_REVOKED_DUE_TO_DISRUPTIVE_BEHAVIOR, }; using OutcomeCallback = base::OnceCallback<void(Outcome)>; // Asynchronously starts origin verification and revokes notifications // permission. - AbusiveOriginPermissionRevocationRequest(Profile* profile, - const GURL& origin, - OutcomeCallback callback); - ~AbusiveOriginPermissionRevocationRequest(); + PermissionRevocationRequest(Profile* profile, + const GURL& origin, + OutcomeCallback callback); + ~PermissionRevocationRequest(); - AbusiveOriginPermissionRevocationRequest( - const AbusiveOriginPermissionRevocationRequest&) = delete; - AbusiveOriginPermissionRevocationRequest& operator=( - const AbusiveOriginPermissionRevocationRequest&) = delete; + PermissionRevocationRequest(const PermissionRevocationRequest&) = delete; + PermissionRevocationRequest& operator=(const PermissionRevocationRequest&) = + delete; static void ExemptOriginFromFutureRevocations(Profile* profile, const GURL& origin); @@ -56,13 +57,14 @@ const GURL& origin); private: - // Verifies if |origin_| is on ABUSIVE_PROMPTS and ABUSIVE_CONTENT lists. If - // yes, the notifications permission will be revoked. |callback_| will be - // synchronously called with the result. - void CheckAndRevokeIfAbusive(); + // Verifies if |origin_| is on ABUSIVE_PROMPTS, ABUSIVE_CONTENT or + // DISRUPTIVE_BEHAVIOR lists. If yes, the notifications permission will be + // revoked. |callback_| will be synchronously called with the result. + void CheckAndRevokeIfBlocklisted(); void OnSiteReputationReady( const CrowdDenyPreloadData::SiteReputation* reputation); void OnSafeBrowsingVerdictReceived( + const CrowdDenyPreloadData::SiteReputation* reputation, CrowdDenySafeBrowsingRequest::Verdict verdict); void NotifyCallback(Outcome outcome); @@ -74,8 +76,7 @@ absl::optional<base::TimeTicks> crowd_deny_request_start_time_; // The Crowd Deny component load duration. absl::optional<base::TimeDelta> crowd_deny_request_duration_; - base::WeakPtrFactory<AbusiveOriginPermissionRevocationRequest> weak_factory_{ - this}; + base::WeakPtrFactory<PermissionRevocationRequest> weak_factory_{this}; }; -#endif // CHROME_BROWSER_PERMISSIONS_ABUSIVE_ORIGIN_PERMISSION_REVOCATION_REQUEST_H_ +#endif // CHROME_BROWSER_PERMISSIONS_PERMISSION_REVOCATION_REQUEST_H_
diff --git a/chrome/browser/permissions/abusive_origin_permission_revocation_request_unittests.cc b/chrome/browser/permissions/permission_revocation_request_unittests.cc similarity index 83% rename from chrome/browser/permissions/abusive_origin_permission_revocation_request_unittests.cc rename to chrome/browser/permissions/permission_revocation_request_unittests.cc index 3fdb591..2e95dc3 100644 --- a/chrome/browser/permissions/abusive_origin_permission_revocation_request_unittests.cc +++ b/chrome/browser/permissions/permission_revocation_request_unittests.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/permissions/abusive_origin_permission_revocation_request.h" +#include "chrome/browser/permissions/permission_revocation_request.h" #include "base/files/scoped_temp_dir.h" #include "base/run_loop.h" @@ -11,9 +11,9 @@ #include "base/test/scoped_feature_list.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" #include "chrome/browser/history/history_service_factory.h" -#include "chrome/browser/permissions/abusive_origin_notifications_permission_revocation_config.h" #include "chrome/browser/permissions/crowd_deny_fake_safe_browsing_database_manager.h" #include "chrome/browser/permissions/crowd_deny_preload_data.h" +#include "chrome/browser/permissions/notifications_permission_revocation_config.h" #include "chrome/browser/safe_browsing/test_safe_browsing_service.h" #include "chrome/common/chrome_features.h" #include "chrome/test/base/testing_browser_process.h" @@ -22,19 +22,19 @@ #include "components/prefs/pref_service.h" #include "content/public/test/browser_task_environment.h" -class AbusiveOriginPermissionRevocationRequestTestBase : public testing::Test { +class PermissionRevocationRequestTestBase : public testing::Test { public: - using Outcome = AbusiveOriginPermissionRevocationRequest::Outcome; + using Outcome = PermissionRevocationRequest::Outcome; using SiteReputation = CrowdDenyPreloadData::SiteReputation; - AbusiveOriginPermissionRevocationRequestTestBase() = default; + PermissionRevocationRequestTestBase() = default; - AbusiveOriginPermissionRevocationRequestTestBase( - const AbusiveOriginPermissionRevocationRequestTestBase&) = delete; - AbusiveOriginPermissionRevocationRequestTestBase& operator=( - const AbusiveOriginPermissionRevocationRequestTestBase&) = delete; + PermissionRevocationRequestTestBase( + const PermissionRevocationRequestTestBase&) = delete; + PermissionRevocationRequestTestBase& operator=( + const PermissionRevocationRequestTestBase&) = delete; - ~AbusiveOriginPermissionRevocationRequestTestBase() override = default; + ~PermissionRevocationRequestTestBase() override = default; protected: void SetUp() override { @@ -89,9 +89,8 @@ Outcome expected_result) { base::MockOnceCallback<void(Outcome)> mock_callback_receiver; base::RunLoop run_loop; - auto permission_revocation = - std::make_unique<AbusiveOriginPermissionRevocationRequest>( - testing_profile_.get(), origin, mock_callback_receiver.Get()); + auto permission_revocation = std::make_unique<PermissionRevocationRequest>( + testing_profile_.get(), origin, mock_callback_receiver.Get()); EXPECT_CALL(mock_callback_receiver, Run(expected_result)) .WillOnce( testing::InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); @@ -136,16 +135,15 @@ safe_browsing_factory_; }; -class AbusiveOriginPermissionRevocationRequestTest - : public AbusiveOriginPermissionRevocationRequestTestBase { +class PermissionRevocationRequestTest + : public PermissionRevocationRequestTestBase { public: - AbusiveOriginPermissionRevocationRequestTest() = default; + PermissionRevocationRequestTest() = default; - ~AbusiveOriginPermissionRevocationRequestTest() override = default; + ~PermissionRevocationRequestTest() override = default; }; -TEST_F(AbusiveOriginPermissionRevocationRequestTest, - OriginIsNotOnBlockingLists) { +TEST_F(PermissionRevocationRequestTest, OriginIsNotOnBlockingLists) { const GURL origin_to_revoke = GURL("https://origin.com/"); SetPermission(origin_to_revoke, CONTENT_SETTING_ALLOW); @@ -155,7 +153,7 @@ VerifyNotificationsPermission(origin_to_revoke, CONTENT_SETTING_ALLOW); } -TEST_F(AbusiveOriginPermissionRevocationRequestTest, SafeBrowsingTest) { +TEST_F(PermissionRevocationRequestTest, SafeBrowsingTest) { const GURL origin_to_revoke = GURL("https://origin.com/"); SetPermission(origin_to_revoke, CONTENT_SETTING_ALLOW); @@ -170,21 +168,19 @@ QueryAndExpectDecisionForUrl(origin_to_revoke, Outcome::PERMISSION_NOT_REVOKED); VerifyNotificationsPermission(origin_to_revoke, CONTENT_SETTING_ALLOW); - EXPECT_FALSE( - AbusiveOriginPermissionRevocationRequest::HasPreviouslyRevokedPermission( - GetTestingProfile(), origin_to_revoke)); + EXPECT_FALSE(PermissionRevocationRequest::HasPreviouslyRevokedPermission( + GetTestingProfile(), origin_to_revoke)); AddToPreloadDataBlocklist(origin_to_revoke, SiteReputation::ABUSIVE_CONTENT, /*has_warning=*/false); QueryAndExpectDecisionForUrl(origin_to_revoke, Outcome::PERMISSION_REVOKED_DUE_TO_ABUSE); VerifyNotificationsPermission(origin_to_revoke, CONTENT_SETTING_ASK); - EXPECT_TRUE( - AbusiveOriginPermissionRevocationRequest::HasPreviouslyRevokedPermission( - GetTestingProfile(), origin_to_revoke)); + EXPECT_TRUE(PermissionRevocationRequest::HasPreviouslyRevokedPermission( + GetTestingProfile(), origin_to_revoke)); } -TEST_F(AbusiveOriginPermissionRevocationRequestTest, PreloadDataTest) { +TEST_F(PermissionRevocationRequestTest, PreloadDataTest) { const GURL abusive_content_origin_to_revoke = GURL("https://abusive-content.com/"); const GURL abusive_prompts_origin_to_revoke = @@ -237,7 +233,7 @@ QueryAndExpectDecisionForUrl(unknown_origin, Outcome::PERMISSION_NOT_REVOKED); } -TEST_F(AbusiveOriginPermissionRevocationRequestTest, PreloadDataAsyncTest) { +TEST_F(PermissionRevocationRequestTest, PreloadDataAsyncTest) { auto* instance = CrowdDenyPreloadData::GetInstance(); // From this point on CrowdDenyPreloadData is not usable for origins // verification. @@ -246,18 +242,16 @@ const GURL abusive_content_origin_to_revoke = GURL("https://abusive-content.com/"); base::MockOnceCallback<void(Outcome)> mock_callback_receiver_1; - auto permission_revocation_1 = - std::make_unique<AbusiveOriginPermissionRevocationRequest>( - GetTestingProfile(), abusive_content_origin_to_revoke, - mock_callback_receiver_1.Get()); + auto permission_revocation_1 = std::make_unique<PermissionRevocationRequest>( + GetTestingProfile(), abusive_content_origin_to_revoke, + mock_callback_receiver_1.Get()); const GURL abusive_prompts_origin_to_revoke = GURL("https://abusive-prompts.com/"); base::MockOnceCallback<void(Outcome)> mock_callback_receiver_2; - auto permission_revocation_2 = - std::make_unique<AbusiveOriginPermissionRevocationRequest>( - GetTestingProfile(), abusive_prompts_origin_to_revoke, - mock_callback_receiver_2.Get()); + auto permission_revocation_2 = std::make_unique<PermissionRevocationRequest>( + GetTestingProfile(), abusive_prompts_origin_to_revoke, + mock_callback_receiver_2.Get()); base::RunLoop run_loop; EXPECT_CALL(mock_callback_receiver_1, @@ -283,8 +277,7 @@ run_loop.Run(); } -TEST_F(AbusiveOriginPermissionRevocationRequestTest, - PreloadDataAsyncHistogramTest) { +TEST_F(PermissionRevocationRequestTest, PreloadDataAsyncHistogramTest) { base::HistogramTester histograms; // The Crowd Deny component is ready to use, there should be no // DelayedPushNotification recording. @@ -295,7 +288,7 @@ AddToPreloadDataBlocklist(origin_1, SiteReputation::ACCEPTABLE, /*has_warning=*/false); auto permission_revocation_1 = - std::make_unique<AbusiveOriginPermissionRevocationRequest>( + std::make_unique<PermissionRevocationRequest>( GetTestingProfile(), origin_1, mock_callback_receiver_1.Get()); EXPECT_CALL(mock_callback_receiver_1, Run(Outcome::PERMISSION_NOT_REVOKED)); @@ -313,26 +306,23 @@ const GURL origin_1 = GURL("https://not-abusive-origin-1.com/"); SetPermission(origin_1, CONTENT_SETTING_ALLOW); base::MockOnceCallback<void(Outcome)> mock_callback_receiver_1; - auto permission_revocation_1 = - std::make_unique<AbusiveOriginPermissionRevocationRequest>( - GetTestingProfile(), origin_1, mock_callback_receiver_1.Get()); + auto permission_revocation_1 = std::make_unique<PermissionRevocationRequest>( + GetTestingProfile(), origin_1, mock_callback_receiver_1.Get()); EXPECT_CALL(mock_callback_receiver_1, Run(Outcome::PERMISSION_NOT_REVOKED)); const GURL origin_2 = GURL("https://not-abusive-origin-2.com/"); SetPermission(origin_2, CONTENT_SETTING_ALLOW); base::MockOnceCallback<void(Outcome)> mock_callback_receiver_2; - auto permission_revocation_2 = - std::make_unique<AbusiveOriginPermissionRevocationRequest>( - GetTestingProfile(), origin_2, mock_callback_receiver_2.Get()); + auto permission_revocation_2 = std::make_unique<PermissionRevocationRequest>( + GetTestingProfile(), origin_2, mock_callback_receiver_2.Get()); EXPECT_CALL(mock_callback_receiver_2, Run(Outcome::PERMISSION_NOT_REVOKED)); const GURL abusive_origin = GURL("https://abusive-origin.com/"); SetPermission(abusive_origin, CONTENT_SETTING_ALLOW); AddToSafeBrowsingBlocklist(abusive_origin); base::MockOnceCallback<void(Outcome)> mock_callback_receiver_3; - auto permission_revocation_3 = - std::make_unique<AbusiveOriginPermissionRevocationRequest>( - GetTestingProfile(), abusive_origin, mock_callback_receiver_3.Get()); + auto permission_revocation_3 = std::make_unique<PermissionRevocationRequest>( + GetTestingProfile(), abusive_origin, mock_callback_receiver_3.Get()); EXPECT_CALL(mock_callback_receiver_3, Run(Outcome::PERMISSION_REVOKED_DUE_TO_ABUSE)); @@ -348,8 +338,7 @@ "Permissions.CrowdDeny.PreloadData.DelayedPushNotification", 2); } -TEST_F(AbusiveOriginPermissionRevocationRequestTest, - PreloadDataTestWithWarning) { +TEST_F(PermissionRevocationRequestTest, PreloadDataTestWithWarning) { const GURL abusive_content_origin_to_revoke = GURL("https://abusive-content.com/"); const GURL abusive_prompts_origin_to_revoke = @@ -396,11 +385,11 @@ QueryAndExpectDecisionForUrl(origin, Outcome::PERMISSION_NOT_REVOKED); } -TEST_F(AbusiveOriginPermissionRevocationRequestTest, ExemptAbusiveOriginTest) { +TEST_F(PermissionRevocationRequestTest, ExemptAbusiveOriginTest) { const GURL origin_to_exempt = GURL("https://origin-allow.com/"); const GURL origin_to_revoke = GURL("https://origin.com/"); - AbusiveOriginPermissionRevocationRequest::ExemptOriginFromFutureRevocations( + PermissionRevocationRequest::ExemptOriginFromFutureRevocations( GetTestingProfile(), origin_to_exempt); SetPermission(origin_to_exempt, CONTENT_SETTING_ALLOW); @@ -424,7 +413,7 @@ VerifyNotificationsPermission(origin_to_revoke, CONTENT_SETTING_ASK); } -TEST_F(AbusiveOriginPermissionRevocationRequestTest, SafeBrowsingDisabledTest) { +TEST_F(PermissionRevocationRequestTest, SafeBrowsingDisabledTest) { const GURL origin_to_revoke = GURL("https://origin.com/"); SetPermission(origin_to_revoke, CONTENT_SETTING_ALLOW); @@ -453,17 +442,17 @@ VerifyNotificationsPermission(origin_to_not_revoke, CONTENT_SETTING_ALLOW); } -class AbusiveOriginPermissionRevocationRequestDisabledTest - : public AbusiveOriginPermissionRevocationRequestTestBase { +class PermissionRevocationRequestDisabledTest + : public PermissionRevocationRequestTestBase { public: - AbusiveOriginPermissionRevocationRequestDisabledTest() { + PermissionRevocationRequestDisabledTest() { feature_list_.InitAndDisableFeature( features::kAbusiveNotificationPermissionRevocation); } - ~AbusiveOriginPermissionRevocationRequestDisabledTest() override = default; + ~PermissionRevocationRequestDisabledTest() override = default; }; -TEST_F(AbusiveOriginPermissionRevocationRequestDisabledTest, +TEST_F(PermissionRevocationRequestDisabledTest, PermissionRevocationFeatureDisabled) { const GURL origin_to_revoke = GURL("https://origin.com/");
diff --git a/chrome/browser/permissions/quiet_notification_permission_ui_config.cc b/chrome/browser/permissions/quiet_notification_permission_ui_config.cc index b4e6c1f..4f24cbc 100644 --- a/chrome/browser/permissions/quiet_notification_permission_ui_config.cc +++ b/chrome/browser/permissions/quiet_notification_permission_ui_config.cc
@@ -49,6 +49,16 @@ "enable_abusive_content_warning"; // static +const char QuietNotificationPermissionUiConfig:: + kEnableDisruptiveBehaviorRequestBlocking[] = + "enable_disruptive_behavior_triggering"; + +// static +const char QuietNotificationPermissionUiConfig:: + kEnableDisruptiveBehaviorRequestWarning[] = + "enable_disruptive_behavior_warning"; + +// static const char QuietNotificationPermissionUiConfig::kMiniInfobarExpandLinkText[] = "mini_infobar_expand_link_text"; @@ -149,3 +159,25 @@ features::kQuietNotificationPrompts, kEnableAbusiveContentTriggeredRequestWarning, true /* default */); } + +// static +bool QuietNotificationPermissionUiConfig:: + IsDisruptiveBehaviorRequestBlockingEnabled() { + if (!base::FeatureList::IsEnabled(features::kQuietNotificationPrompts)) + return false; + + return base::GetFieldTrialParamByFeatureAsBool( + features::kQuietNotificationPrompts, + kEnableDisruptiveBehaviorRequestBlocking, true /* default */); +} + +// static +bool QuietNotificationPermissionUiConfig:: + IsDisruptiveBehaviorRequestWarningEnabled() { + if (!base::FeatureList::IsEnabled(features::kQuietNotificationPrompts)) + return false; + + return base::GetFieldTrialParamByFeatureAsBool( + features::kQuietNotificationPrompts, + kEnableDisruptiveBehaviorRequestWarning, true /* default */); +}
diff --git a/chrome/browser/permissions/quiet_notification_permission_ui_config.h b/chrome/browser/permissions/quiet_notification_permission_ui_config.h index 089a13d..ca9d9cc 100644 --- a/chrome/browser/permissions/quiet_notification_permission_ui_config.h +++ b/chrome/browser/permissions/quiet_notification_permission_ui_config.h
@@ -55,6 +55,16 @@ // warning list for showing abusive notification content. static const char kEnableAbusiveContentTriggeredRequestWarning[]; + // Name of the boolean variation parameter that determines if the quiet + // notification permission prompt UI should be enabled as a one-off on sites + // with disruptive notification behavior. + static const char kEnableDisruptiveBehaviorRequestBlocking[]; + + // Name of the boolean variation parameter that determines if a console + // message in Developer Tools should be printed on sites that are on the + // warning list for disruptive notification behavior. + static const char kEnableDisruptiveBehaviorRequestWarning[]; + // Name of the variation parameter that represents the chance that a // quiet notifications permission prompt UI triggered by crowd deny will be // replaced by the normal UI. This ensures that a small percentage of @@ -115,6 +125,16 @@ // Whether or not showing a console message in Developer Tools is enabled for // sites on the abusive content warning list. static bool IsAbusiveContentTriggeredRequestWarningEnabled(); + + // Whether or not triggering via the disruptive behavior list is enabled. This + // means that on sites with disruptive behavior permission request flows, the + // quiet UI will be shown as a one-off, even when it is not turned on for all + // sites in prefs. + static bool IsDisruptiveBehaviorRequestBlockingEnabled(); + + // Whether or not showing a console message in Developer Tools is enabled for + // sites on the disruptive behavior warning list. + static bool IsDisruptiveBehaviorRequestWarningEnabled(); }; #endif // CHROME_BROWSER_PERMISSIONS_QUIET_NOTIFICATION_PERMISSION_UI_CONFIG_H_
diff --git a/chrome/browser/permissions/quiet_permission_prompt_model_android.cc b/chrome/browser/permissions/quiet_permission_prompt_model_android.cc index ccf306e5..eedc9611 100644 --- a/chrome/browser/permissions/quiet_permission_prompt_model_android.cc +++ b/chrome/browser/permissions/quiet_permission_prompt_model_android.cc
@@ -31,6 +31,9 @@ case QuietUiReason::kOnDevicePredictedVeryUnlikelyGrant: return l10n_util::GetStringUTF16( IDS_NOTIFICATION_QUIET_PERMISSION_INFOBAR_PREDICTION_SERVICE_MESSAGE); + case QuietUiReason::kTriggeredDueToDisruptiveBehavior: + return l10n_util::GetStringUTF16( + IDS_NOTIFICATION_QUIET_PERMISSION_INFOBAR_DISRUPTIVE_MESSAGE); } NOTREACHED(); return std::u16string(); @@ -67,6 +70,7 @@ break; case QuietUiReason::kTriggeredDueToAbusiveRequests: case QuietUiReason::kTriggeredDueToAbusiveContent: + case QuietUiReason::kTriggeredDueToDisruptiveBehavior: model.primary_button_label = l10n_util::GetStringUTF16( IDS_NOTIFICATIONS_QUIET_PERMISSION_BUBBLE_CONTINUE_BLOCKING_BUTTON); model.primary_button_behavior = PrimaryButtonBehavior::kContinueBlocking;
diff --git a/chrome/browser/policy/status_provider/updater_status_and_value_provider.cc b/chrome/browser/policy/status_provider/updater_status_and_value_provider.cc new file mode 100644 index 0000000..1e46626 --- /dev/null +++ b/chrome/browser/policy/status_provider/updater_status_and_value_provider.cc
@@ -0,0 +1,135 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/policy/status_provider/updater_status_and_value_provider.h" + +#include <windows.h> + +#include <DSRole.h> +#include <algorithm> +#include <utility> + +#include "base/callback_forward.h" +#include "base/sequence_checker.h" +#include "base/strings/utf_string_conversions.h" +#include "base/task/task_traits.h" +#include "base/task/thread_pool.h" +#include "base/values.h" +#include "chrome/browser/google/google_update_policy_fetcher_win.h" +#include "chrome/browser/policy/chrome_policy_conversions_client.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/install_static/install_util.h" +#include "content/public/browser/browser_task_traits.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/web_contents.h" + +namespace { + +std::string GetActiveDirectoryDomain() { + std::string domain; + ::DSROLE_PRIMARY_DOMAIN_INFO_BASIC* info = nullptr; + if (::DsRoleGetPrimaryDomainInformation(nullptr, + ::DsRolePrimaryDomainInfoBasic, + (PBYTE*)&info) != ERROR_SUCCESS) { + return domain; + } + if (info->DomainNameDns) + domain = base::WideToUTF8(info->DomainNameDns); + ::DsRoleFreeMemory(info); + return domain; +} + +} // namespace + +UpdaterStatusAndValueProvider::UpdaterStatusAndValueProvider(Profile* profile) + : profile_(profile) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + base::ThreadPool::PostTaskAndReplyWithResult( + FROM_HERE, + {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}, + base::BindOnce(&GetActiveDirectoryDomain), + base::BindOnce(&UpdaterStatusAndValueProvider::OnDomainReceived, + weak_factory_.GetWeakPtr())); +} + +UpdaterStatusAndValueProvider::~UpdaterStatusAndValueProvider() = default; + +base::Value::Dict UpdaterStatusAndValueProvider::GetStatus() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + base::Value::Dict dict; + if (!domain_.empty()) + dict.Set("domain", domain_); + if (!updater_status_) + return dict; + if (!updater_status_->version.empty()) + dict.Set("version", base::WideToUTF8(updater_status_->version)); + if (!updater_status_->last_checked_time.is_null()) { + dict.Set("timeSinceLastRefresh", + GetTimeSinceLastActionString(updater_status_->last_checked_time)); + } + return dict; +} + +void UpdaterStatusAndValueProvider::GetValues( + base::Value::List& out_policy_values) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (!updater_policies_) { + return; + } + + base::Value::Dict updater_policies_data; + updater_policies_data.Set("name", "Google Update Policies"); + updater_policies_data.Set("id", "updater"); + + auto client = + std::make_unique<policy::ChromePolicyConversionsClient>(profile_); + client->EnableConvertValues(true); + client->SetDropDefaultValues(true); + // TODO(b/241519819): Find an alternative to using PolicyConversionsClient + // directly. + updater_policies_data.Set("policies", client->ConvertUpdaterPolicies( + updater_policies_->Clone(), + GetGoogleUpdatePolicySchemas())); + out_policy_values.Append(std::move(updater_policies_data)); +} + +base::Value::Dict UpdaterStatusAndValueProvider::GetNames() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + base::Value::Dict names; + if (updater_policies_) { + base::Value::Dict updater_policies; + updater_policies.Set("name", "Google Update Policies"); + updater_policies.Set("policyNames", GetGoogleUpdatePolicyNames()); + names.Set("updater", std::move(updater_policies)); + } + return names; +} + +void UpdaterStatusAndValueProvider::Refresh() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + base::PostTaskAndReplyWithResult( + base::ThreadPool::CreateCOMSTATaskRunner( + {base::TaskPriority::USER_BLOCKING, + base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN, base::MayBlock()}) + .get(), + FROM_HERE, base::BindOnce(&GetGoogleUpdatePoliciesAndState), + base::BindOnce(&UpdaterStatusAndValueProvider::OnUpdaterPoliciesRefreshed, + weak_factory_.GetWeakPtr())); +} + +void UpdaterStatusAndValueProvider::OnDomainReceived(std::string domain) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + domain_ = std::move(domain); + // Call Refresh() to load the policies when the domain is received. + Refresh(); +} + +void UpdaterStatusAndValueProvider::OnUpdaterPoliciesRefreshed( + std::unique_ptr<GoogleUpdatePoliciesAndState> updater_policies_and_state) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + updater_policies_ = std::move(updater_policies_and_state->policies); + updater_status_ = std::move(updater_policies_and_state->state); + NotifyValueChange(); + NotifyStatusChange(); +}
diff --git a/chrome/browser/policy/status_provider/updater_status_and_value_provider.h b/chrome/browser/policy/status_provider/updater_status_and_value_provider.h new file mode 100644 index 0000000..ab361e5 --- /dev/null +++ b/chrome/browser/policy/status_provider/updater_status_and_value_provider.h
@@ -0,0 +1,61 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_POLICY_STATUS_PROVIDER_UPDATER_STATUS_AND_VALUE_PROVIDER_H_ +#define CHROME_BROWSER_POLICY_STATUS_PROVIDER_UPDATER_STATUS_AND_VALUE_PROVIDER_H_ + +#include <memory> +#include <string> + +#include "base/memory/raw_ptr.h" +#include "base/memory/weak_ptr.h" +#include "base/sequence_checker.h" +#include "base/values.h" +#include "chrome/browser/policy/value_provider/policy_value_provider.h" +#include "components/policy/core/browser/webui/policy_status_provider.h" + +struct GoogleUpdateState; +struct GoogleUpdatePoliciesAndState; + +class Profile; + +namespace policy { +class PolicyMap; +} + +// A status and value provider for Google Updater policies. Starts to load the +// policy values and status asynchronously during construction and +// notifies when the policies are loaded. GetStatus() and GetValues() will +// return empty if they're called before policies are loaded. +class UpdaterStatusAndValueProvider : public policy::PolicyStatusProvider, + public policy::PolicyValueProvider { + public: + explicit UpdaterStatusAndValueProvider(Profile* profile); + ~UpdaterStatusAndValueProvider() override; + + // policy::PolicyStatusProvider implementation. + base::Value::Dict GetStatus() override; + + // policy::PolicyValueProvider implementation. + void GetValues(base::Value::List& out_policy_values) override; + + base::Value::Dict GetNames() override; + + void Refresh() override; + + private: + void OnDomainReceived(std::string domain); + + void OnUpdaterPoliciesRefreshed( + std::unique_ptr<GoogleUpdatePoliciesAndState> updater_policies_and_state); + + SEQUENCE_CHECKER(sequence_checker_); + std::unique_ptr<GoogleUpdateState> updater_status_; + std::unique_ptr<policy::PolicyMap> updater_policies_; + std::string domain_; + base::raw_ptr<Profile> profile_; + base::WeakPtrFactory<UpdaterStatusAndValueProvider> weak_factory_{this}; +}; + +#endif // CHROME_BROWSER_POLICY_STATUS_PROVIDER_UPDATER_STATUS_AND_VALUE_PROVIDER_H_
diff --git a/chrome/browser/policy/status_provider/updater_status_provider.cc b/chrome/browser/policy/status_provider/updater_status_provider.cc deleted file mode 100644 index 9d1f3fa..0000000 --- a/chrome/browser/policy/status_provider/updater_status_provider.cc +++ /dev/null
@@ -1,68 +0,0 @@ -// Copyright 2022 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/policy/status_provider/updater_status_provider.h" - -#include <windows.h> - -#include <DSRole.h> - -#include "base/strings/utf_string_conversions.h" -#include "base/task/task_traits.h" -#include "base/task/thread_pool.h" -#include "base/values.h" -#include "chrome/browser/google/google_update_policy_fetcher_win.h" -#include "chrome/install_static/install_util.h" - -UpdaterStatusProvider::UpdaterStatusProvider() { - base::ThreadPool::PostTaskAndReplyWithResult( - FROM_HERE, - {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}, - base::BindOnce(&UpdaterStatusProvider::FetchActiveDirectoryDomain), - base::BindOnce(&UpdaterStatusProvider::OnDomainReceived, - weak_factory_.GetWeakPtr())); -} - -UpdaterStatusProvider::~UpdaterStatusProvider() {} - -void UpdaterStatusProvider::SetUpdaterStatus( - std::unique_ptr<GoogleUpdateState> status) { - updater_status_ = std::move(status); - NotifyStatusChange(); -} - -base::Value::Dict UpdaterStatusProvider::GetStatus() { - base::Value::Dict dict; - if (!domain_.empty()) - dict.Set("domain", domain_); - if (!updater_status_) - return dict; - if (!updater_status_->version.empty()) - dict.Set("version", base::WideToUTF8(updater_status_->version)); - if (!updater_status_->last_checked_time.is_null()) { - dict.Set("timeSinceLastRefresh", - GetTimeSinceLastActionString(updater_status_->last_checked_time)); - } - return dict; -} - -// static -std::string UpdaterStatusProvider::FetchActiveDirectoryDomain() { - std::string domain; - ::DSROLE_PRIMARY_DOMAIN_INFO_BASIC* info = nullptr; - if (::DsRoleGetPrimaryDomainInformation(nullptr, - ::DsRolePrimaryDomainInfoBasic, - (PBYTE*)&info) != ERROR_SUCCESS) { - return domain; - } - if (info->DomainNameDns) - domain = base::WideToUTF8(info->DomainNameDns); - ::DsRoleFreeMemory(info); - return domain; -} - -void UpdaterStatusProvider::OnDomainReceived(std::string domain) { - domain_ = std::move(domain); - NotifyStatusChange(); -}
diff --git a/chrome/browser/policy/status_provider/updater_status_provider.h b/chrome/browser/policy/status_provider/updater_status_provider.h deleted file mode 100644 index ebab196..0000000 --- a/chrome/browser/policy/status_provider/updater_status_provider.h +++ /dev/null
@@ -1,30 +0,0 @@ -// Copyright 2022 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_POLICY_STATUS_PROVIDER_UPDATER_STATUS_PROVIDER_H_ -#define CHROME_BROWSER_POLICY_STATUS_PROVIDER_UPDATER_STATUS_PROVIDER_H_ - -#include <string> - -#include "components/policy/core/browser/webui/policy_status_provider.h" - -struct GoogleUpdateState; - -class UpdaterStatusProvider : public policy::PolicyStatusProvider { - public: - UpdaterStatusProvider(); - ~UpdaterStatusProvider() override; - void SetUpdaterStatus(std::unique_ptr<GoogleUpdateState> status); - base::Value::Dict GetStatus() override; - - private: - static std::string FetchActiveDirectoryDomain(); - void OnDomainReceived(std::string domain); - - std::unique_ptr<GoogleUpdateState> updater_status_; - std::string domain_; - base::WeakPtrFactory<UpdaterStatusProvider> weak_factory_{this}; -}; - -#endif // CHROME_BROWSER_POLICY_STATUS_PROVIDER_UPDATER_STATUS_PROVIDER_H_
diff --git a/chrome/browser/policy/value_provider/extension_policies_value_provider.cc b/chrome/browser/policy/value_provider/extension_policies_value_provider.cc index 6e35ed3..dff406c 100644 --- a/chrome/browser/policy/value_provider/extension_policies_value_provider.cc +++ b/chrome/browser/policy/value_provider/extension_policies_value_provider.cc
@@ -56,23 +56,22 @@ #endif // BUILDFLAG(IS_CHROMEOS_ASH) } -base::Value::List ExtensionPoliciesValueProvider::GetValues() { +void ExtensionPoliciesValueProvider::GetValues( + base::Value::List& out_policy_values) { auto client = std::make_unique<policy::ChromePolicyConversionsClient>(profile_); - base::Value::List extension_policies; if (client->HasUserPolicies()) { for (auto& policy : client->GetExtensionPolicies(policy::POLICY_DOMAIN_EXTENSIONS)) { - extension_policies.Append(std::move(policy)); + out_policy_values.Append(std::move(policy)); } } #if BUILDFLAG(IS_CHROMEOS_ASH) for (auto& policy : client->GetExtensionPolicies(policy::POLICY_DOMAIN_SIGNIN_EXTENSIONS)) { - extension_policies.Append(std::move(policy)); + out_policy_values.Append(std::move(policy)); } #endif // BUILDFLAG(IS_CHROMEOS_ASH) - return extension_policies; } base::Value::Dict ExtensionPoliciesValueProvider::GetNames() {
diff --git a/chrome/browser/policy/value_provider/extension_policies_value_provider.h b/chrome/browser/policy/value_provider/extension_policies_value_provider.h index 38835457..4e42d4b 100644 --- a/chrome/browser/policy/value_provider/extension_policies_value_provider.h +++ b/chrome/browser/policy/value_provider/extension_policies_value_provider.h
@@ -31,7 +31,9 @@ ~ExtensionPoliciesValueProvider() override; // PolicyValueProvider overrides. - base::Value::List GetValues() override; + // Appends each individual extension policy as a separate entry at the end of + // `out_policy_values`. + void GetValues(base::Value::List& out_policy_values) override; base::Value::Dict GetNames() override;
diff --git a/chrome/browser/policy/value_provider/policy_value_provider.cc b/chrome/browser/policy/value_provider/policy_value_provider.cc index 5375a804..d088923d 100644 --- a/chrome/browser/policy/value_provider/policy_value_provider.cc +++ b/chrome/browser/policy/value_provider/policy_value_provider.cc
@@ -14,6 +14,8 @@ PolicyValueProvider::~PolicyValueProvider() = default; +void PolicyValueProvider::Refresh() {} + void PolicyValueProvider::NotifyValueChange() { for (auto& observer : observers_) observer.OnPolicyValueChanged();
diff --git a/chrome/browser/policy/value_provider/policy_value_provider.h b/chrome/browser/policy/value_provider/policy_value_provider.h index c78c950..f4a7479 100644 --- a/chrome/browser/policy/value_provider/policy_value_provider.h +++ b/chrome/browser/policy/value_provider/policy_value_provider.h
@@ -25,12 +25,18 @@ PolicyValueProvider& operator=(const PolicyValueProvider&) = delete; virtual ~PolicyValueProvider(); - // Returns the list of available policy values. - virtual base::Value::List GetValues() = 0; + // Appends the policy values at the end of `out_policy_values` if they're + // available. + // TODO(b/233209041): Update GetValues function to return a base::Value::Dict + // instead. + virtual void GetValues(base::Value::List& out_policy_values) = 0; // Returns the dictionary containing the policy names. virtual base::Value::Dict GetNames() = 0; + // Refreshes the policy values and notifies the observers. + virtual void Refresh(); + void AddObserver(Observer* observer); void RemoveObserver(Observer* observer);
diff --git a/chrome/browser/privacy_sandbox/mock_privacy_sandbox_service.h b/chrome/browser/privacy_sandbox/mock_privacy_sandbox_service.h index 517e370..aa58683f 100644 --- a/chrome/browser/privacy_sandbox/mock_privacy_sandbox_service.h +++ b/chrome/browser/privacy_sandbox/mock_privacy_sandbox_service.h
@@ -27,6 +27,15 @@ (override)); // Mock this method to enable opening the settings page in tests. MOCK_METHOD(bool, IsPrivacySandboxRestricted, (), (override)); + MOCK_METHOD((base::flat_map<net::SchemefulSite, net::SchemefulSite>), + GetFirstPartySets, + (), + (override)); + MOCK_METHOD(absl::optional<std::u16string>, + GetFpsOwnerForDisplay, + (const GURL& site_url), + (override)); + MOCK_METHOD(bool, ShouldShowDetailedFpsControls, (), (override)); }; std::unique_ptr<KeyedService> BuildMockPrivacySandboxService(
diff --git a/chrome/browser/privacy_sandbox/privacy_sandbox_service.cc b/chrome/browser/privacy_sandbox/privacy_sandbox_service.cc index b56ed40..c8d360f 100644 --- a/chrome/browser/privacy_sandbox/privacy_sandbox_service.cc +++ b/chrome/browser/privacy_sandbox/privacy_sandbox_service.cc
@@ -14,6 +14,7 @@ #include "base/metrics/user_metrics.h" #include "base/ranges/algorithm.h" #include "base/strings/string_number_conversions.h" +#include "base/strings/utf_string_conversions.h" #include "base/time/time.h" #include "chrome/common/webui_url_constants.h" #include "components/browsing_topics/browsing_topics_service.h" @@ -601,6 +602,42 @@ privacy_sandbox_settings_->SetTopicAllowed(topic, allowed); } +base::flat_map<net::SchemefulSite, net::SchemefulSite> +PrivacySandboxService::GetFirstPartySets() { + if (privacy_sandbox::kPrivacySandboxFirstPartySetsUISampleSets.Get()) { + return {{net::SchemefulSite(GURL("https://youtube.com")), + net::SchemefulSite(GURL("https://google.com"))}, + {net::SchemefulSite(GURL("https://google.com")), + net::SchemefulSite(GURL("https://google.com"))}, + {net::SchemefulSite(GURL("https://google.com.au")), + net::SchemefulSite(GURL("https://google.com"))}, + {net::SchemefulSite(GURL("https://google.de")), + net::SchemefulSite(GURL("https://google.com"))}}; + } + + // TODO(crbug.com/1332513): Retrieve set information from FPS delegate. + return {}; +} + +absl::optional<std::u16string> PrivacySandboxService::GetFpsOwnerForDisplay( + const GURL& site_url) { + auto sets = GetFirstPartySets(); + auto schemeful_site = net::SchemefulSite(site_url); + + if (!sets.count(schemeful_site)) + return absl::nullopt; + + // TODO(crbug.com/1332513): Apply formatting that correctly displays unicode + // domains. + return base::UTF8ToUTF16(sets[schemeful_site].GetURL().host()); +} + +bool PrivacySandboxService::ShouldShowDetailedFpsControls() { + // TODO(crbug.com/1332513): Consult the preference state to determine whether + // detailed controls should be shown. + return privacy_sandbox::kPrivacySandboxFirstPartySetsUISampleSets.Get(); +} + /*static*/ PrivacySandboxService::PromptType PrivacySandboxService::GetRequiredPromptTypeInternal( PrefService* pref_service,
diff --git a/chrome/browser/privacy_sandbox/privacy_sandbox_service.h b/chrome/browser/privacy_sandbox/privacy_sandbox_service.h index d230015..b1bd4d7 100644 --- a/chrome/browser/privacy_sandbox/privacy_sandbox_service.h +++ b/chrome/browser/privacy_sandbox/privacy_sandbox_service.h
@@ -17,6 +17,7 @@ #include "components/privacy_sandbox/canonical_topic.h" #include "components/privacy_sandbox/privacy_sandbox_settings.h" #include "components/profile_metrics/browser_profile_type.h" +#include "net/base/schemeful_site.h" class Browser; class PrefService; @@ -205,6 +206,26 @@ virtual void SetTopicAllowed(privacy_sandbox::CanonicalTopic topic, bool allowed); + // Returns the first party sets recognised by the current profile. If FPS is + // disabled, or if sets have not been loaded yet, an empty map is returned. + // Virtual for mocking in tests. + // TODO (crbug.com/1350062): Reconsider whether ignoring async FPS information + // is appropriate. + virtual base::flat_map<net::SchemefulSite, net::SchemefulSite> + GetFirstPartySets(); + + // Returns the owner domain of the first party set that `site_url` is a member + // of, or absl::nullopt if `site_url` is not recognised as a member of an FPS. + // Virtual for mocking in tests. + virtual absl::optional<std::u16string> GetFpsOwnerForDisplay( + const GURL& site_url); + + // Returns whether detailed FPS controls should be shown based on the current + // profile state. Detailed FPS controls are only shown when the user has FPS + // enabled, and is blocking 3PC. + // Virtual for mocking in tests. + virtual bool ShouldShowDetailedFpsControls(); + protected: friend class PrivacySandboxServiceTest; FRIEND_TEST_ALL_PREFIXES(PrivacySandboxServiceTest,
diff --git a/chrome/browser/privacy_sandbox/privacy_sandbox_service_unittest.cc b/chrome/browser/privacy_sandbox/privacy_sandbox_service_unittest.cc index 1b56e59..337089a 100644 --- a/chrome/browser/privacy_sandbox/privacy_sandbox_service_unittest.cc +++ b/chrome/browser/privacy_sandbox/privacy_sandbox_service_unittest.cc
@@ -1970,6 +1970,19 @@ 1); } +TEST_F(PrivacySandboxServiceTest, SampleFpsData) { + feature_list()->InitAndEnableFeatureWithParameters( + privacy_sandbox::kPrivacySandboxFirstPartySetsUI, + {{"use-sample-sets", "true"}}); + + EXPECT_EQ(u"google.com", privacy_sandbox_service()->GetFpsOwnerForDisplay( + GURL("https://mail.google.com.au"))); + EXPECT_EQ(u"google.com", privacy_sandbox_service()->GetFpsOwnerForDisplay( + GURL("https://youtube.com"))); + EXPECT_EQ(absl::nullopt, privacy_sandbox_service()->GetFpsOwnerForDisplay( + GURL("https://example.com"))); +} + class PrivacySandboxServiceTestNonRegularProfile : public PrivacySandboxServiceTest { profile_metrics::BrowserProfileType GetProfileType() override {
diff --git a/chrome/browser/push_messaging/push_messaging_service_impl.cc b/chrome/browser/push_messaging/push_messaging_service_impl.cc index a9564d2..de0d1a13 100644 --- a/chrome/browser/push_messaging/push_messaging_service_impl.cc +++ b/chrome/browser/push_messaging/push_messaging_service_impl.cc
@@ -26,7 +26,7 @@ #include "chrome/browser/gcm/gcm_profile_service_factory.h" #include "chrome/browser/gcm/instance_id/instance_id_profile_service_factory.h" #include "chrome/browser/lifetime/termination_notification.h" -#include "chrome/browser/permissions/abusive_origin_permission_revocation_request.h" +#include "chrome/browser/permissions/permission_revocation_request.h" #include "chrome/browser/profiles/keep_alive/profile_keep_alive_types.h" #include "chrome/browser/profiles/keep_alive/scoped_profile_keep_alive.h" #include "chrome/browser/profiles/profile.h" @@ -394,10 +394,10 @@ if (IsPermissionSet(app_identifier.origin())) { messages_pending_permission_check_.emplace(app_id, message); - // Start abusive origin verification only if no other verification is in - // progress. - if (!abusive_origin_revocation_request_) - CheckOriginForAbuseAndDispatchNextMessage(); + // Start abusive and disruptive origin verifications only if no other + // respective verification is in progress. + if (!origin_revocation_request_) + CheckOriginAndDispatchNextMessage(); } else { // Drop message and unregister if origin has lost push permission. DeliverMessageCallback(app_id, app_identifier.origin(), @@ -407,7 +407,7 @@ } } -void PushMessagingServiceImpl::CheckOriginForAbuseAndDispatchNextMessage() { +void PushMessagingServiceImpl::CheckOriginAndDispatchNextMessage() { if (messages_pending_permission_check_.empty()) return; @@ -419,17 +419,16 @@ PushMessagingAppIdentifier::FindByAppId(profile_, message.app_id); if (app_identifier.is_null()) { - CheckOriginForAbuseAndDispatchNextMessage(); + CheckOriginAndDispatchNextMessage(); return; } - DCHECK(!abusive_origin_revocation_request_) - << "Create one Abusive Origin Revocation instance per request."; - abusive_origin_revocation_request_ = - std::make_unique<AbusiveOriginPermissionRevocationRequest>( - profile_, app_identifier.origin(), - base::BindOnce(&PushMessagingServiceImpl::OnCheckedOriginForAbuse, - weak_factory_.GetWeakPtr(), std::move(message))); + DCHECK(!origin_revocation_request_) + << "Create one Origin Revocation instance per request."; + origin_revocation_request_ = std::make_unique<PermissionRevocationRequest>( + profile_, app_identifier.origin(), + base::BindOnce(&PushMessagingServiceImpl::OnCheckedOrigin, + weak_factory_.GetWeakPtr(), std::move(message))); } #if BUILDFLAG(IS_ANDROID) @@ -503,10 +502,10 @@ } #endif -void PushMessagingServiceImpl::OnCheckedOriginForAbuse( +void PushMessagingServiceImpl::OnCheckedOrigin( PendingMessage message, - AbusiveOriginPermissionRevocationRequest::Outcome outcome) { - abusive_origin_revocation_request_.reset(); + PermissionRevocationRequest::Outcome outcome) { + origin_revocation_request_.reset(); base::UmaHistogramLongTimes("PushMessaging.CheckOriginForAbuseTime", base::Time::Now() - message.received_time); @@ -515,7 +514,7 @@ PushMessagingAppIdentifier::FindByAppId(profile_, message.app_id); if (app_identifier.is_null()) { - CheckOriginForAbuseAndDispatchNextMessage(); + CheckOriginAndDispatchNextMessage(); return; } @@ -525,8 +524,7 @@ // It is possible that Notifications permission has been revoked by a user // during abusive origin verification. - if (outcome == AbusiveOriginPermissionRevocationRequest::Outcome:: - PERMISSION_NOT_REVOKED && + if (outcome == PermissionRevocationRequest::Outcome::PERMISSION_NOT_REVOKED && IsPermissionSet(origin)) { std::queue<PendingMessage>& delivery_queue = message_delivery_queue_[{origin, service_worker_registration_id}]; @@ -540,18 +538,32 @@ origin, service_worker_registration_id); } } else { + blink::mojom::PushEventStatus status; + + switch (outcome) { + case PermissionRevocationRequest::Outcome::PERMISSION_NOT_REVOKED: + status = blink::mojom::PushEventStatus::PERMISSION_DENIED; + break; + case PermissionRevocationRequest::Outcome:: + PERMISSION_REVOKED_DUE_TO_ABUSE: + status = blink::mojom::PushEventStatus::PERMISSION_REVOKED_ABUSIVE; + break; + case PermissionRevocationRequest::Outcome:: + PERMISSION_REVOKED_DUE_TO_DISRUPTIVE_BEHAVIOR: + status = blink::mojom::PushEventStatus::PERMISSION_REVOKED_DISRUPTIVE; + break; + default: + NOTREACHED(); + } + // Drop message and unregister if origin has lost push permission. - DeliverMessageCallback( - message.app_id, origin, service_worker_registration_id, message.message, - /*did_enqueue_message=*/false, - outcome == AbusiveOriginPermissionRevocationRequest::Outcome:: - PERMISSION_NOT_REVOKED - ? blink::mojom::PushEventStatus::PERMISSION_DENIED - : blink::mojom::PushEventStatus::PERMISSION_REVOKED_ABUSIVE); + DeliverMessageCallback(message.app_id, origin, + service_worker_registration_id, message.message, + /* did_enqueue_message */ false, status); } // Verify the next message in the queue. - CheckOriginForAbuseAndDispatchNextMessage(); + CheckOriginAndDispatchNextMessage(); } void PushMessagingServiceImpl:: @@ -679,6 +691,10 @@ unsubscribe_reason = blink::mojom::PushUnregistrationReason::PERMISSION_REVOKED_ABUSIVE; break; + case blink::mojom::PushEventStatus::PERMISSION_REVOKED_DISRUPTIVE: + unsubscribe_reason = + blink::mojom::PushUnregistrationReason::PERMISSION_REVOKED_DISRUPTIVE; + break; } // If |message_handled_callback| was not yet used, make a
diff --git a/chrome/browser/push_messaging/push_messaging_service_impl.h b/chrome/browser/push_messaging/push_messaging_service_impl.h index 1e3b011b..5b5a7d62 100644 --- a/chrome/browser/push_messaging/push_messaging_service_impl.h +++ b/chrome/browser/push_messaging/push_messaging_service_impl.h
@@ -20,7 +20,7 @@ #include "base/memory/weak_ptr.h" #include "base/scoped_observation.h" #include "base/time/time.h" -#include "chrome/browser/permissions/abusive_origin_permission_revocation_request.h" +#include "chrome/browser/permissions/permission_revocation_request.h" #include "chrome/browser/push_messaging/push_messaging_notification_manager.h" #include "chrome/browser/push_messaging/push_messaging_refresher.h" #include "chrome/common/buildflags.h" @@ -243,15 +243,14 @@ const std::string& push_message_id, bool did_show_generic_notification); - void OnCheckedOriginForAbuse( - PendingMessage message, - AbusiveOriginPermissionRevocationRequest::Outcome outcome); + void OnCheckedOrigin(PendingMessage message, + PermissionRevocationRequest::Outcome outcome); void DeliverNextQueuedMessageForServiceWorkerRegistration( const GURL& origin, int64_t service_worker_registration_id); - void CheckOriginForAbuseAndDispatchNextMessage(); + void CheckOriginAndDispatchNextMessage(); #if BUILDFLAG(IS_ANDROID) // Verifies if Chrome has Android app-level Notifications permission. If @@ -264,7 +263,6 @@ const gcm::IncomingMessage& message, const PushMessagingAppIdentifier& app_identifier); #endif - // Subscribe methods --------------------------------------------------------- void DoSubscribe(PushMessagingAppIdentifier app_identifier, @@ -450,8 +448,7 @@ void OnAppTerminating(); raw_ptr<Profile> profile_; - std::unique_ptr<AbusiveOriginPermissionRevocationRequest> - abusive_origin_revocation_request_; + std::unique_ptr<PermissionRevocationRequest> origin_revocation_request_; std::queue<PendingMessage> messages_pending_permission_check_; // {Origin, ServiceWokerRegistratonId} key for message delivery queue. This
diff --git a/chrome/browser/resources/chromeos/cloud_upload/BUILD.gn b/chrome/browser/resources/chromeos/cloud_upload/BUILD.gn index 23e1e83..f2530eb 100644 --- a/chrome/browser/resources/chromeos/cloud_upload/BUILD.gn +++ b/chrome/browser/resources/chromeos/cloud_upload/BUILD.gn
@@ -9,8 +9,14 @@ static_files = [ "main.html" ] web_component_files = [ "cloud_upload_dialog.ts" ] + non_web_component_files = [ "browser_proxy.ts" ] + mojo_files = [ "$root_gen_dir/mojom-webui/chrome/browser/ui/webui/chromeos/cloud_upload/cloud_upload.mojom-webui.js" ] + mojo_files_deps = [ + "//chrome/browser/ui/webui/chromeos/cloud_upload:mojo_bindings_webui_js", + ] html_to_wrapper_template = "native" + ts_definitions = [ "//tools/typescript/definitions/chrome_send.d.ts" ] ts_deps = [ "//ui/webui/resources:library" ] }
diff --git a/chrome/browser/resources/chromeos/cloud_upload/browser_proxy.ts b/chrome/browser/resources/chromeos/cloud_upload/browser_proxy.ts new file mode 100644 index 0000000..56a65cabb --- /dev/null +++ b/chrome/browser/resources/chromeos/cloud_upload/browser_proxy.ts
@@ -0,0 +1,24 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import {PageHandlerFactory, PageHandlerRemote} from './cloud_upload.mojom-webui.js'; + +export class BrowserProxy { + handler: PageHandlerRemote = new PageHandlerRemote(); + + constructor() { + const factory = PageHandlerFactory.getRemote(); + factory.createPageHandler(this.handler.$.bindNewPipeAndPassReceiver()); + } + + static getInstance(): BrowserProxy { + return instance || (instance = new BrowserProxy()); + } + + static setInstance(obj: BrowserProxy) { + instance = obj; + } +} + +let instance: BrowserProxy|null = null; \ No newline at end of file
diff --git a/chrome/browser/resources/chromeos/cloud_upload/cloud_upload_dialog.html b/chrome/browser/resources/chromeos/cloud_upload/cloud_upload_dialog.html index 002cec6..71ed20c 100644 --- a/chrome/browser/resources/chromeos/cloud_upload/cloud_upload_dialog.html +++ b/chrome/browser/resources/chromeos/cloud_upload/cloud_upload_dialog.html
@@ -1,13 +1,29 @@ <style> - cr-dialog::part(dialog) { + cr-dialog::part(dialog), + cr-dialog::part(wrapper) { height: 100%; } + + [slot='button-container'] { + margin-block-start: auto; + } </style> -<cr-dialog id="dialog"> +<cr-dialog> <!-- TODO: Use localized strings --> - <div slot="title">Upload to Drive</div> + <div slot="title"> + Upload to Drive + </div> <div slot="body"> - Body + Upload your file to Google Drive to open with Google Docs. + <div id="upload-location" hidden></div> + </div> + <div slot="button-container"> + <cr-button id="cancel-button" class="cancel-button"> + Cancel + </cr-button> + <cr-button id="upload-button" class="action-button"> + Upload to Drive + </cr-button> </div> </cr-dialog>
diff --git a/chrome/browser/resources/chromeos/cloud_upload/cloud_upload_dialog.ts b/chrome/browser/resources/chromeos/cloud_upload/cloud_upload_dialog.ts index 7f0946f..71b5dc1c 100644 --- a/chrome/browser/resources/chromeos/cloud_upload/cloud_upload_dialog.ts +++ b/chrome/browser/resources/chromeos/cloud_upload/cloud_upload_dialog.ts
@@ -2,6 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; + +import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js'; + +import {BrowserProxy} from './browser_proxy.js'; import {getTemplate} from './cloud_upload_dialog.html.js'; /** @@ -17,6 +22,34 @@ const fragment = template.content.cloneNode(true); this.attachShadow({mode: 'open'}).appendChild(fragment); } + + $<T extends Element>(query: string): T { + return this.shadowRoot!.querySelector(query)!; + } + + get dialog(): CrDialogElement { + return this.$('cr-dialog') as CrDialogElement; + } + + connectedCallback(): void { + this.dialog.showModal(); + const cancelButton = this.$('#cancel-button'); + cancelButton.addEventListener('click', () => this.onCancelButtonClick()); + const uploadButton = this.$('#upload-button'); + uploadButton.addEventListener('click', () => this.onUploadButtonClick()); + } + + private onCancelButtonClick(): void { + chrome.send('dialogClose'); + } + + private async onUploadButtonClick() { + const proxy = BrowserProxy.getInstance().handler; + const {uploadPath} = await proxy.getUploadPath(); + const uploadLocationElement = this.$('#upload-location') as HTMLElement; + uploadLocationElement.innerText = `Upload location: ${uploadPath.path}`; + uploadLocationElement.toggleAttribute('hidden', false); + } } customElements.define('cloud-upload-dialog', CloudUploadDialogElement);
diff --git a/chrome/browser/resources/chromeos/cloud_upload/tsconfig_base.json b/chrome/browser/resources/chromeos/cloud_upload/tsconfig_base.json index 4874355..b01690fe 100644 --- a/chrome/browser/resources/chromeos/cloud_upload/tsconfig_base.json +++ b/chrome/browser/resources/chromeos/cloud_upload/tsconfig_base.json
@@ -1,6 +1,7 @@ { "extends": "../../../../../tools/typescript/tsconfig_base.json", "compilerOptions": { + "allowJs": true, "importsNotUsedAsValues": "preserve", "typeRoots": [ "../../../../../third_party/node/node_modules/@types"
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/input_method_util.js b/chrome/browser/resources/settings/chromeos/os_languages_page/input_method_util.js index a2d14c52..42971f7 100644 --- a/chrome/browser/resources/settings/chromeos/os_languages_page/input_method_util.js +++ b/chrome/browser/resources/settings/chromeos/os_languages_page/input_method_util.js
@@ -111,7 +111,7 @@ [OptionType.PHYSICAL_KEYBOARD_AUTO_CORRECTION_LEVEL]: 0, [OptionType.PHYSICAL_KEYBOARD_ENABLE_CAPITALIZATION]: true, [OptionType.PHYSICAL_KEYBOARD_ENABLE_PREDICTIVE_WRITING]: true, - [OptionType.PHYSICAL_KEYBOARD_ENABLE_DIACRITICS_ON_LONGPRESS]: false, + [OptionType.PHYSICAL_KEYBOARD_ENABLE_DIACRITICS_ON_LONGPRESS]: true, [OptionType.VIRTUAL_KEYBOARD_AUTO_CORRECTION_LEVEL]: 1, [OptionType.VIRTUAL_KEYBOARD_ENABLE_CAPITALIZATION]: true, [OptionType.XKB_LAYOUT]: 'US',
diff --git a/chrome/browser/resources/signin/BUILD.gn b/chrome/browser/resources/signin/BUILD.gn index e957bb6..197353a1 100644 --- a/chrome/browser/resources/signin/BUILD.gn +++ b/chrome/browser/resources/signin/BUILD.gn
@@ -36,7 +36,7 @@ if (is_chromeos_lacros) { static_files += [ "enterprise_profile_welcome/images/lacros_enterprise_profile_welcome_illustration.svg" ] } - if (!is_chromeos_ash && !is_chromeos_lacros) { + if (!is_chromeos) { static_files += [ "enterprise_profile_welcome/images/enterprise_profile_welcome_illustration.svg" ] } if (enable_dice_support) {
diff --git a/chrome/browser/spellchecker/spelling_request.cc b/chrome/browser/spellchecker/spelling_request.cc index 76ef20c..5147a2c6 100644 --- a/chrome/browser/spellchecker/spelling_request.cc +++ b/chrome/browser/spellchecker/spelling_request.cc
@@ -6,6 +6,8 @@ #include "base/barrier_closure.h" #include "base/bind.h" +#include "base/i18n/char_iterator.h" +#include "base/memory/ptr_util.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/spellchecker/spellcheck_custom_dictionary.h" #include "chrome/browser/spellchecker/spellcheck_factory.h" @@ -25,6 +27,17 @@ } // namespace +// static +std::unique_ptr<SpellingRequest> SpellingRequest::CreateForTest( + const std::u16string& text, + RequestTextCheckCallback callback, + DestructionCallback destruction_callback, + base::RepeatingClosure completion_barrier) { + return base::WrapUnique<SpellingRequest>(new SpellingRequest( + text, std::move(callback), std::move(destruction_callback), + std::move(completion_barrier))); +} + SpellingRequest::SpellingRequest(PlatformSpellChecker* platform_spell_checker, SpellingServiceClient* client, const std::u16string& text, @@ -46,6 +59,16 @@ RequestLocalCheck(platform_spell_checker, document_tag); } +SpellingRequest::SpellingRequest(const std::u16string& text, + RequestTextCheckCallback callback, + DestructionCallback destruction_callback, + base::RepeatingClosure completion_barrier) + : completion_barrier_(std::move(completion_barrier)), + remote_success_(false), + text_(text), + callback_(std::move(callback)), + destruction_callback_(std::move(destruction_callback)) {} + SpellingRequest::~SpellingRequest() = default; // static @@ -124,6 +147,35 @@ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); remote_success_ = success; remote_results_ = results; + + if (results.size() > 0) { + // The spelling service uses "logical" character positions, whereas the + // Chromium spell check infrastructure uses positions based on code points, + // which causes mismatches when the text contains characters made of + // multiple code points (such as emojis). Use a UTF-16 char iterator on the + // text to replace the logical positions of the remote results with their + // corresponding code points position in the string. + std::sort(remote_results_.begin(), remote_results_.end(), CompareLocation); + base::i18n::UTF16CharIterator char_iter(text); + std::vector<SpellCheckResult>::iterator result_iter; + + for (result_iter = remote_results_.begin(); + result_iter != remote_results_.end(); ++result_iter) { + while (char_iter.char_offset() < result_iter->location) { + char_iter.Advance(); + } + + if (char_iter.char_offset() > result_iter->location) { + // This remote result has a logical position that somehow doesn't + // correspond to a code point boundary position in the string. Behavior + // is undefined, so leave it as is. + continue; + } + + result_iter->location = char_iter.array_pos(); + } + } + completion_barrier_.Run(); }
diff --git a/chrome/browser/spellchecker/spelling_request.h b/chrome/browser/spellchecker/spelling_request.h index ec34ded..ac0222b 100644 --- a/chrome/browser/spellchecker/spelling_request.h +++ b/chrome/browser/spellchecker/spelling_request.h
@@ -6,6 +6,7 @@ #define CHROME_BROWSER_SPELLCHECKER_SPELLING_REQUEST_H_ #include "base/containers/unique_ptr_adapters.h" +#include "base/gtest_prod_util.h" #include "components/spellcheck/browser/platform_spell_checker.h" #include "components/spellcheck/browser/spell_check_host_impl.h" #include "components/spellcheck/browser/spelling_service_client.h" @@ -21,6 +22,14 @@ spellcheck::mojom::SpellCheckHost::RequestTextCheckCallback; using DestructionCallback = base::OnceCallback<void(SpellingRequest*)>; + // Creates the request, but does not start it. Gives tests finer control over + // how the request is executed. + static std::unique_ptr<SpellingRequest> CreateForTest( + const std::u16string& text, + RequestTextCheckCallback callback, + DestructionCallback destruction_callback, + base::RepeatingClosure completion_barrier); + SpellingRequest(PlatformSpellChecker* platform_spell_checker, SpellingServiceClient* client, const std::u16string& text, @@ -40,6 +49,16 @@ const std::vector<SpellCheckResult>& local_results); private: + FRIEND_TEST_ALL_PREFIXES(SpellingRequestRemoteCheckUnitTest, + OnRemoteCheckCompleted); + + // Test-only constructor that does not kick off the remote and local checks. + // Use the `CreateForTest` static helper. + SpellingRequest(const std::u16string& text, + RequestTextCheckCallback callback, + DestructionCallback destruction_callback, + base::RepeatingClosure completion_barrier); + // Request server-side checking for |text_|. void RequestRemoteCheck(SpellingServiceClient* client, int render_process_id);
diff --git a/chrome/browser/spellchecker/spelling_request_unittest.cc b/chrome/browser/spellchecker/spelling_request_unittest.cc new file mode 100644 index 0000000..e4312e47 --- /dev/null +++ b/chrome/browser/spellchecker/spelling_request_unittest.cc
@@ -0,0 +1,121 @@ +// Copyright (c) 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/spellchecker/spelling_request.h" + +#include <memory> +#include <string> +#include <vector> + +#include "base/callback_helpers.h" +#include "components/spellcheck/common/spellcheck_result.h" +#include "content/public/test/browser_task_environment.h" +#include "testing/gtest/include/gtest/gtest.h" + +struct RemoteCheckTestCase { + std::string test_name; + std::u16string text; + std::vector<SpellCheckResult> initial_results; + std::vector<SpellCheckResult> expected_converted_results; +}; + +SpellCheckResult MakeResult(int pos, int length) { + return SpellCheckResult(SpellCheckResult::Decoration::SPELLING, pos, length, + u""); +} + +class SpellingRequestRemoteCheckUnitTest + : public testing::TestWithParam<RemoteCheckTestCase> { + public: + SpellingRequestRemoteCheckUnitTest() { + spelling_request_ = SpellingRequest::CreateForTest( + u"", base::DoNothing(), base::DoNothing(), base::DoNothing()); + } + + ~SpellingRequestRemoteCheckUnitTest() override = default; + + protected: + content::BrowserTaskEnvironment task_environment_; + std::unique_ptr<SpellingRequest> spelling_request_; +}; + +// Helper for setting the test case's name. +static std::string DescribeParams( + const testing::TestParamInfo<RemoteCheckTestCase>& info) { + return info.param.test_name; +} + +std::vector<RemoteCheckTestCase> BuildTestCases() { + std::vector<RemoteCheckTestCase> test_cases = { + RemoteCheckTestCase{"no_results_all_ascii", + u"This has no spelling mistakes 1 2 3", + {}, + {}}, + RemoteCheckTestCase{ + "some_results_all_ascii", + u"Tihs has 3 speling mistkes", + {MakeResult(0, 4), MakeResult(11, 7), MakeResult(19, 7)}, + {MakeResult(0, 4), MakeResult(11, 7), MakeResult(19, 7)}}, + RemoteCheckTestCase{ + "no_results_non_ascii", + u"\u00e9\u00c8\u00e7\u00e2\u062c\u305c\u000a\u0020\u00ef", + {}, + {}}, + RemoteCheckTestCase{"some_results_non_ascii", + u"\u00e9\u00c8\u00e7 tihs\u00e2\u062c is " + u"\u305c\u000a a \u0020 mistke\u00ef", + {MakeResult(4, 4), MakeResult(21, 6)}, + {MakeResult(4, 4), MakeResult(21, 6)}}, + RemoteCheckTestCase{ + "no_results_some_surrogate_pairs", + u"👨👩👦👦 This 😁 has 🧑🏿 emojis", + // The code point representation of the emojis in the above string is: + // "\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66 + // This \ud83d\ude01 has \ud83e\uddd1\ud83c\udfff emojis" + {}, + {}}, + RemoteCheckTestCase{ + "some_results_some_surrogate_pairs", + u"👨👩👦👦 Tihs 😁 has 🧑🏿 emjis", + // The code point representation of the emojis in the above string is: + // "\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66 + // Tihs \ud83d\ude01 has \ud83e\uddd1\ud83c\udfff emjis" + {MakeResult(8, 4), MakeResult(22, 5)}, + {MakeResult(12, 4), MakeResult(29, 5)}}}; + + return test_cases; +} + +INSTANTIATE_TEST_SUITE_P(/* No prefix */, + SpellingRequestRemoteCheckUnitTest, + testing::ValuesIn(BuildTestCases()), + DescribeParams); + +// Tests that remote results have their position value correctly adjusted to +// the corresponding code point position. +TEST_P(SpellingRequestRemoteCheckUnitTest, OnRemoteCheckCompleted) { + const RemoteCheckTestCase& param = GetParam(); + spelling_request_->OnRemoteCheckCompleted(true, param.text, + param.initial_results); + const std::vector<SpellCheckResult>& actual_converted_results = + spelling_request_->remote_results_; + + EXPECT_EQ(actual_converted_results.size(), + param.expected_converted_results.size()); + for (const auto& expected : param.expected_converted_results) { + bool found = false; + + for (const auto& actual : actual_converted_results) { + if (expected.decoration == actual.decoration && + expected.location == actual.location && + expected.length == actual.length) { + found = true; + break; + } + } + + EXPECT_TRUE(found) << "Result with pos = " << expected.location + << " and length = " << expected.length << " not found."; + } +}
diff --git a/chrome/browser/sync/device_info_sync_client_impl.cc b/chrome/browser/sync/device_info_sync_client_impl.cc index 090f2668..5b2ea64a 100644 --- a/chrome/browser/sync/device_info_sync_client_impl.cc +++ b/chrome/browser/sync/device_info_sync_client_impl.cc
@@ -23,6 +23,10 @@ #include "chrome/browser/webauthn/android/cable_module_android.h" #endif +#if BUILDFLAG(IS_CHROMEOS_ASH) +#include "chrome/browser/ash/crosapi/browser_util.h" +#endif + namespace browser_sync { DeviceInfoSyncClientImpl::DeviceInfoSyncClientImpl(Profile* profile) @@ -51,9 +55,15 @@ // syncer::DeviceInfoSyncClient: bool DeviceInfoSyncClientImpl::GetSendTabToSelfReceivingEnabled() const { - // Always true starting with M101, see crbug.com/1299833. Older clients and - // clients from other embedders might still return false. + // TODO(crbug.com/1286405): Current logic allows to disable receiving tabs + // in Ash, while sending is still enabled - this seems to be the best solution + // for Lacros-Primary. Once Lacros-Only is the only available option, this + // should simply check whether SendTabToSelf datatype is enabled. +#if BUILDFLAG(IS_CHROMEOS_ASH) + return !crosapi::browser_util::IsLacrosPrimaryBrowser(); +#else return true; +#endif } // syncer::DeviceInfoSyncClient:
diff --git a/chrome/browser/sync/test/integration/sync_errors_test.cc b/chrome/browser/sync/test/integration/sync_errors_test.cc index 19afb5e..02461e4 100644 --- a/chrome/browser/sync/test/integration/sync_errors_test.cc +++ b/chrome/browser/sync/test/integration/sync_errors_test.cc
@@ -33,6 +33,7 @@ using bookmarks_helper::AddFolder; using bookmarks_helper::SetTitle; using syncer::SyncServiceImpl; +using testing::IsEmpty; using user_events_helper::CreateTestEvent; namespace { @@ -347,6 +348,10 @@ IN_PROC_BROWSER_TEST_F(SyncErrorTest, ShouldResendUncommittedEntitiesAfterBrowserRestart) { + // Make sure the PRE_ test didn't successfully commit the event. + ASSERT_THAT(GetFakeServer()->GetSyncEntitiesByModelType(syncer::USER_EVENTS), + IsEmpty()); + ASSERT_TRUE(SetupClients()) << "SetupClients() failed."; ASSERT_TRUE(GetClient(0)->AwaitEngineInitialization());
diff --git a/chrome/browser/sync/test/integration/sync_service_impl_harness.cc b/chrome/browser/sync/test/integration/sync_service_impl_harness.cc index f8968b05..f399e3a6 100644 --- a/chrome/browser/sync/test/integration/sync_service_impl_harness.cc +++ b/chrome/browser/sync/test/integration/sync_service_impl_harness.cc
@@ -398,7 +398,7 @@ } std::vector<SyncServiceImpl*> services; - for (const SyncServiceImplHarness* harness : clients) { + for (SyncServiceImplHarness* harness : clients) { services.push_back(harness->service()); } return QuiesceStatusChangeChecker(services).Wait();
diff --git a/chrome/browser/sync/test/integration/sync_service_impl_harness.h b/chrome/browser/sync/test/integration/sync_service_impl_harness.h index cc31d63b4..91b28fb 100644 --- a/chrome/browser/sync/test/integration/sync_service_impl_harness.h +++ b/chrome/browser/sync/test/integration/sync_service_impl_harness.h
@@ -157,7 +157,8 @@ bool AwaitSyncTransportActive(); // Returns the SyncServiceImpl member of the sync client. - syncer::SyncServiceImpl* service() const { return service_; } + syncer::SyncServiceImpl* service() { return service_; } + const syncer::SyncServiceImpl* service() const { return service_; } // Returns the debug name for this profile. Used for logging. const std::string& profile_debug_name() const { return profile_debug_name_; }
diff --git a/chrome/browser/sync/test/integration/sync_test.cc b/chrome/browser/sync/test/integration/sync_test.cc index 33a5199..5563e496 100644 --- a/chrome/browser/sync/test/integration/sync_test.cc +++ b/chrome/browser/sync/test/integration/sync_test.cc
@@ -6,6 +6,7 @@ #include <utility> +#include "base/as_const.h" #include "base/bind.h" #include "base/callback_helpers.h" #include "base/command_line.h" @@ -22,6 +23,7 @@ #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/test_timeouts.h" #include "build/build_config.h" #include "build/chromeos_buildflags.h" #include "chrome/browser/bookmarks/bookmark_model_factory.h" @@ -248,9 +250,13 @@ SyncTest::SyncTest(TestType test_type) : test_type_(test_type), test_construction_time_(base::Time::Now()), + sync_run_loop_timeout(FROM_HERE, TestTimeouts::action_max_timeout()), server_type_(SERVER_TYPE_UNDECIDED), previous_profile_(nullptr), num_clients_(-1) { + // Any RunLoop timeout will by default result in test failure. + sync_run_loop_timeout.SetAddGTestFailureOnTimeout(); + sync_datatype_helper::AssociateWithTest(this); switch (test_type_) { case SINGLE_CLIENT: { @@ -518,6 +524,7 @@ // may be destroyed soon. It may not exist for browsers added during // tests using AddBrowser(). if (i < clients_.size()) { + CheckForDataTypeFailures(/*client_index=*/i); clients_[i].reset(); } break; @@ -534,6 +541,11 @@ #endif SyncServiceImplHarness* SyncTest::GetClient(int index) { + return const_cast<SyncServiceImplHarness*>( + base::as_const(*this).GetClient(index)); +} + +const SyncServiceImplHarness* SyncTest::GetClient(int index) const { if (clients_.empty()) { LOG(FATAL) << "SetupClients() has not yet been called."; } @@ -954,13 +966,7 @@ // This may happen if the last tab and hence a browser has been closed. continue; } - if (GetClient(client_index)->service()->HasAnyDatatypeErrorForTest()) { - ADD_FAILURE() << "Data types failed during tests: " - << GetClient(client_index) - ->service() - ->GetTypeStatusMapForDebugging() - ->DebugString(); - } + CheckForDataTypeFailures(client_index); } // Workaround for https://crbug.com/801569: |prefs::kProfileLastUsed| stores @@ -1383,3 +1389,14 @@ return true; } + +void SyncTest::CheckForDataTypeFailures(size_t client_index) const { + DCHECK(GetClient(client_index)); + if (GetClient(client_index)->service()->HasAnyDatatypeErrorForTest()) { + ADD_FAILURE() << "Data types failed during tests: " + << GetClient(client_index) + ->service() + ->GetTypeStatusMapForDebugging() + ->DebugString(); + } +}
diff --git a/chrome/browser/sync/test/integration/sync_test.h b/chrome/browser/sync/test/integration/sync_test.h index dd30dd78..9858c4e 100644 --- a/chrome/browser/sync/test/integration/sync_test.h +++ b/chrome/browser/sync/test/integration/sync_test.h
@@ -12,6 +12,7 @@ #include "base/memory/raw_ptr.h" #include "base/test/scoped_feature_list.h" +#include "base/test/scoped_run_loop_timeout.h" #include "base/time/time.h" #include "build/build_config.h" #include "build/buildflag.h" @@ -186,6 +187,7 @@ // Returns a pointer to a particular sync client. Callee owns the object // and manages its lifetime. SyncServiceImplHarness* GetClient(int index); + const SyncServiceImplHarness* GetClient(int index) const; // Returns a list of the collection of sync clients. std::vector<SyncServiceImplHarness*> GetSyncClients(); @@ -408,6 +410,10 @@ // SetupSync() call which might be unexpected in several tests. bool WaitForAsyncChangesToBeCommitted(size_t profile_index) const; + // Verifies that there are no data type failures for the given |client_index|. + // Otherwise, causes test failure. A corresponding client must exist. + void CheckForDataTypeFailures(size_t client_index) const; + // Used to differentiate between single-client and two-client tests. const TestType test_type_; @@ -415,6 +421,9 @@ // how long the setup took. const base::Time test_construction_time_; + // Used to catch any timeout within RunLoop and cause test error. + base::test::ScopedRunLoopTimeout sync_run_loop_timeout; + // GAIA account used by the test case. std::string username_;
diff --git a/chrome/browser/sync/test/lacros/sync_custom_passphrase_sharing_lacros_browsertest.cc b/chrome/browser/sync/test/lacros/sync_custom_passphrase_sharing_lacros_browsertest.cc index 1c3343b..6c888bdc 100644 --- a/chrome/browser/sync/test/lacros/sync_custom_passphrase_sharing_lacros_browsertest.cc +++ b/chrome/browser/sync/test/lacros/sync_custom_passphrase_sharing_lacros_browsertest.cc
@@ -14,78 +14,35 @@ #include "chromeos/crosapi/mojom/sync.mojom.h" #include "chromeos/lacros/lacros_service.h" #include "components/sync/chromeos/explicit_passphrase_mojo_utils.h" +#include "components/sync/chromeos/lacros/fake_sync_explicit_passphrase_client_ash.h" +#include "components/sync/chromeos/lacros/fake_sync_mojo_service.h" #include "components/sync/engine/nigori/nigori.h" #include "components/sync/nigori/nigori_test_utils.h" #include "components/sync/test/fake_server/fake_server_nigori_helper.h" #include "content/public/test/browser_test.h" -#include "mojo/public/cpp/bindings/pending_receiver.h" -#include "mojo/public/cpp/bindings/pending_remote.h" -#include "mojo/public/cpp/bindings/receiver.h" #include "mojo/public/cpp/bindings/remote.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" namespace { -using testing::_; - -std::string ComputeKeyName(const syncer::Nigori& nigori) { - std::string key_name; - nigori.Permute(syncer::Nigori::Password, syncer::kNigoriKeyName, &key_name); - return key_name; +crosapi::mojom::NigoriKeyPtr MakeMojoNigoriKey( + const syncer::KeyParamsForTesting& key_params) { + return syncer::NigoriToMojo(*syncer::Nigori::CreateByDerivation( + key_params.derivation_params, key_params.password)); } -MATCHER_P(AccountKeyEq, expected_account_key, "") { - const crosapi::mojom::AccountKeyPtr& given_account_key = arg; - return given_account_key->id == expected_account_key.id && - given_account_key->account_type == expected_account_key.account_type; +syncer::KeyParamsForTesting +MakeCustomPassphraseKeyParamsFromServerNigoriAndPassphrase( + const std::string& passphrase, + fake_server::FakeServer* fake_server) { + sync_pb::NigoriSpecifics nigori_specifics; + fake_server::GetServerNigori(fake_server, &nigori_specifics); + return {syncer::InitCustomPassphraseKeyDerivationParamsFromNigori( + nigori_specifics), + passphrase}; } -MATCHER_P(MojoNigoriCanDecryptServerNigori, fake_server, "") { - const crosapi::mojom::NigoriKeyPtr& mojo_nigori = arg; - sync_pb::NigoriSpecifics server_specifics; - fake_server::GetServerNigori(fake_server, &server_specifics); - return mojo_nigori && ComputeKeyName(*syncer::NigoriFromMojo(*mojo_nigori)) == - server_specifics.encryption_keybag().key_name(); -} - -class MockSyncExplicitPassphraseClientAsh - : public crosapi::mojom::SyncExplicitPassphraseClient { - public: - MockSyncExplicitPassphraseClientAsh() = default; - ~MockSyncExplicitPassphraseClientAsh() override = default; - - MOCK_METHOD(void, - AddObserver, - (mojo::PendingRemote< - crosapi::mojom::SyncExplicitPassphraseClientObserver>), - (override)); - MOCK_METHOD(void, - GetDecryptionNigoriKey, - (crosapi::mojom::AccountKeyPtr, GetDecryptionNigoriKeyCallback), - (override)); - MOCK_METHOD(void, - SetDecryptionNigoriKey, - (crosapi::mojom::AccountKeyPtr, crosapi::mojom::NigoriKeyPtr), - (override)); -}; - -class MockSyncMojoService : public crosapi::mojom::SyncService { - public: - MockSyncMojoService() = default; - ~MockSyncMojoService() override = default; - - MOCK_METHOD( - void, - BindExplicitPassphraseClient, - (mojo::PendingReceiver<crosapi::mojom::SyncExplicitPassphraseClient>), - (override)); - MOCK_METHOD(void, - BindUserSettingsClient, - (mojo::PendingReceiver<crosapi::mojom::SyncUserSettingsClient>), - (override)); -}; - class SyncCustomPassphraseSharingLacrosBrowserTest : public SyncTest { public: SyncCustomPassphraseSharingLacrosBrowserTest() : SyncTest(SINGLE_CLIENT) {} @@ -123,18 +80,7 @@ chromeos::LacrosService::Get() ->GetRemote<crosapi::mojom::SyncService>(); remote.reset(); - sync_mojo_service_receiver_.Bind(remote.BindNewPipeAndPassReceiver()); - - // Lacros client is not expected to call these methods more than once. - ON_CALL(sync_mojo_service_, BindExplicitPassphraseClient) - .WillByDefault(testing::Invoke( - this, &SyncCustomPassphraseSharingLacrosBrowserTest:: - BindExplicitPassphraseClient)); - - ON_CALL(client_ash_, AddObserver) - .WillByDefault(testing::Invoke( - this, - &SyncCustomPassphraseSharingLacrosBrowserTest::AddClientObserver)); + sync_mojo_service_.BindReceiver(remote.BindNewPipeAndPassReceiver()); } bool IsServiceAvailable() const { @@ -144,43 +90,28 @@ lacros_service->IsAvailable<crosapi::mojom::SyncService>(); } - crosapi::mojom::AccountKey GetSyncingUserAccountKey() { - crosapi::mojom::AccountKey account_key; - account_key.id = GetSyncService(0)->GetAccountInfo().gaia; - account_key.account_type = crosapi::mojom::AccountType::kGaia; - return account_key; + bool SetupSyncAndSetAccountKeyExpectations() { + if (!SetupSync()) { + return false; + } + + crosapi::mojom::AccountKeyPtr account_key = + crosapi::mojom::AccountKey::New(); + account_key->id = GetSyncService(0)->GetAccountInfo().gaia; + account_key->account_type = crosapi::mojom::AccountType::kGaia; + client_ash().SetExpectedAccountKey(std::move(account_key)); + + return true; } - MockSyncExplicitPassphraseClientAsh* client_ash() { return &client_ash_; } - - crosapi::mojom::SyncExplicitPassphraseClientObserver* client_observer() { - return client_observer_remote_.get(); + syncer::FakeSyncExplicitPassphraseClientAsh& client_ash() { + return sync_mojo_service_.GetFakeSyncExplicitPassphraseClientAsh(); } private: - void BindExplicitPassphraseClient( - mojo::PendingReceiver<crosapi::mojom::SyncExplicitPassphraseClient> - pending_receiver) { - client_ash_receiver_.Bind(std::move(pending_receiver)); - } - - void AddClientObserver( - mojo::PendingRemote<crosapi::mojom::SyncExplicitPassphraseClientObserver> - pending_remote) { - client_observer_remote_.Bind(std::move(pending_remote)); - } - - testing::NiceMock<MockSyncMojoService> sync_mojo_service_; - testing::NiceMock<MockSyncExplicitPassphraseClientAsh> client_ash_; - // Mojo fields order is important to allow safe use of `this` when passing // callbacks. - mojo::Remote<crosapi::mojom::SyncExplicitPassphraseClientObserver> - client_observer_remote_; - mojo::Receiver<crosapi::mojom::SyncExplicitPassphraseClient> - client_ash_receiver_{&client_ash_}; - mojo::Receiver<crosapi::mojom::SyncService> sync_mojo_service_receiver_{ - &sync_mojo_service_}; + syncer::FakeSyncMojoService sync_mojo_service_; }; IN_PROC_BROWSER_TEST_F(SyncCustomPassphraseSharingLacrosBrowserTest, @@ -189,7 +120,7 @@ GTEST_SKIP() << "Unsupported Ash version."; } - ASSERT_TRUE(SetupSync()); + ASSERT_TRUE(SetupSyncAndSetAccountKeyExpectations()); // Mimic custom passphrase being set by other client. const syncer::KeyParamsForTesting kKeyParams = @@ -210,14 +141,7 @@ // Mimic passphrase being provided by Ash, verify that passphrase is no longer // required and the data is decryptable. - EXPECT_CALL(*client_ash(), GetDecryptionNigoriKey( - AccountKeyEq(GetSyncingUserAccountKey()), _)) - .WillOnce([&kKeyParams](auto account_key, auto callback) { - std::move(callback).Run( - syncer::NigoriToMojo(*syncer::Nigori::CreateByDerivation( - kKeyParams.derivation_params, kKeyParams.password))); - }); - client_observer()->OnPassphraseAvailable(); + client_ash().MimicPassphraseAvailable(MakeMojoNigoriKey(kKeyParams)); EXPECT_TRUE(PassphraseAcceptedChecker(GetSyncService(0)).Wait()); EXPECT_TRUE(PasswordFormsChecker(0, {password_form}).Wait()); } @@ -228,7 +152,7 @@ GTEST_SKIP() << "Unsupported Ash version."; } - ASSERT_TRUE(SetupSync()); + ASSERT_TRUE(SetupSyncAndSetAccountKeyExpectations()); // Mimic custom passphrase being set by other client. const syncer::KeyParamsForTesting kKeyParams = @@ -239,23 +163,20 @@ // Mimic Ash received the remote update and indicates that passphrase is // required. - client_observer()->OnPassphraseRequired(); + base::RunLoop run_loop; + client_ash().MimicPassphraseRequired( + /*expected_nigori_key=*/MakeMojoNigoriKey(kKeyParams), + /*passphrase_provided_callback=*/run_loop.QuitClosure()); ASSERT_TRUE(PassphraseRequiredChecker(GetSyncService(0)).Wait()); // Mimic that user enters the passphrase, key should be exposed to Ash. - base::RunLoop run_loop; - EXPECT_CALL( - *client_ash(), - SetDecryptionNigoriKey(AccountKeyEq(GetSyncingUserAccountKey()), - MojoNigoriCanDecryptServerNigori(GetFakeServer()))) - .WillOnce(base::test::RunOnceClosure(run_loop.QuitClosure())); - ASSERT_TRUE(GetSyncService(0)->GetUserSettings()->SetDecryptionPassphrase( kKeyParams.password)); ASSERT_TRUE(PassphraseAcceptedChecker(GetSyncService(0)).Wait()); run_loop.Run(); + EXPECT_FALSE(client_ash().IsPassphraseRequired()); } IN_PROC_BROWSER_TEST_F(SyncCustomPassphraseSharingLacrosBrowserTest, @@ -264,7 +185,7 @@ GTEST_SKIP() << "Unsupported Ash version."; } - ASSERT_TRUE(SetupSync()); + ASSERT_TRUE(SetupSyncAndSetAccountKeyExpectations()); const std::string kPassphrase = "hunter2"; GetSyncService(0)->GetUserSettings()->SetEncryptionPassphrase(kPassphrase); @@ -275,14 +196,14 @@ // Mimic Ash received the remote update and indicates that passphrase is // required, key should be exposed to Ash. base::RunLoop run_loop; - EXPECT_CALL( - *client_ash(), - SetDecryptionNigoriKey(AccountKeyEq(GetSyncingUserAccountKey()), - MojoNigoriCanDecryptServerNigori(GetFakeServer()))) - .WillOnce(base::test::RunOnceClosure(run_loop.QuitClosure())); + client_ash().MimicPassphraseRequired( + /*expected_nigori_key=*/MakeMojoNigoriKey( + MakeCustomPassphraseKeyParamsFromServerNigoriAndPassphrase( + kPassphrase, GetFakeServer())), + /*passphrase_provided_callback=*/run_loop.QuitClosure()); - client_observer()->OnPassphraseRequired(); run_loop.Run(); + EXPECT_FALSE(client_ash().IsPassphraseRequired()); } } // namespace
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index 383af7a..20f6047be 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -2091,6 +2091,7 @@ "app_list/search/omnibox_provider.h", "app_list/search/omnibox_result.cc", "app_list/search/omnibox_result.h", + "app_list/search/omnibox_util.cc", "app_list/search/omnibox_util.h", "app_list/search/open_tab_result.cc", "app_list/search/open_tab_result.h", @@ -2562,6 +2563,10 @@ "webui/chromeos/certificate_manager_dialog_ui.h", "webui/chromeos/cloud_upload/cloud_upload_dialog.cc", "webui/chromeos/cloud_upload/cloud_upload_dialog.h", + "webui/chromeos/cloud_upload/cloud_upload_page_handler.cc", + "webui/chromeos/cloud_upload/cloud_upload_page_handler.h", + "webui/chromeos/cloud_upload/cloud_upload_ui.cc", + "webui/chromeos/cloud_upload/cloud_upload_ui.h", "webui/chromeos/connectivity_diagnostics_dialog.cc", "webui/chromeos/connectivity_diagnostics_dialog.h", "webui/chromeos/crostini_installer/crostini_installer_dialog.cc", @@ -3129,6 +3134,7 @@ "//chrome/browser/ui/quick_answers", "//chrome/browser/ui/webui/chromeos/add_supervision:mojo_bindings", "//chrome/browser/ui/webui/chromeos/audio:mojo_bindings", + "//chrome/browser/ui/webui/chromeos/cloud_upload:mojo_bindings", "//chrome/browser/ui/webui/chromeos/crostini_upgrader:mojo_bindings", "//chrome/browser/ui/webui/chromeos/launcher_internals:mojo_bindings", "//chrome/browser/ui/webui/chromeos/manage_mirrorsync:mojo_bindings", @@ -4700,8 +4706,6 @@ "views/passwords/views_utils.h", "views/payments/contact_info_editor_view_controller.cc", "views/payments/contact_info_editor_view_controller.h", - "views/payments/credit_card_editor_view_controller.cc", - "views/payments/credit_card_editor_view_controller.h", "views/payments/editor_view_controller.cc", "views/payments/editor_view_controller.h", "views/payments/error_message_view_controller.cc", @@ -4890,6 +4894,8 @@ "views/side_search/unified_side_search_helper.cc", "views/site_data/page_specific_site_data_dialog.cc", "views/site_data/page_specific_site_data_dialog.h", + "views/site_data/page_specific_site_data_dialog_controller.cc", + "views/site_data/page_specific_site_data_dialog_controller.h", "views/ssl_client_certificate_selector.cc", "views/ssl_client_certificate_selector.h", "views/status_bubble_views.cc",
diff --git a/chrome/browser/ui/android/signin/DEPS b/chrome/browser/ui/android/signin/DEPS index 43a0368..f3ede55 100644 --- a/chrome/browser/ui/android/signin/DEPS +++ b/chrome/browser/ui/android/signin/DEPS
@@ -12,4 +12,7 @@ "SigninPromoController.java": [ "+chrome/android/features/start_surface/public/java/src/org/chromium/chrome/features/start_surface/StartSurfaceConfiguration.java" ], + "SyncPromoController.java": [ + "+chrome/android/features/start_surface/public/java/src/org/chromium/chrome/features/start_surface/StartSurfaceConfiguration.java" + ], }
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd index 0ce2e4dc..a4db0cd8 100644 --- a/chrome/browser/ui/android/strings/android_chrome_strings.grd +++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -1091,8 +1091,8 @@ <message name="IDS_PRIVACY_SANDBOX_NOTICE_SHEET_TITLE" desc="CONTEXT: there are updates to the Chrome browser each month. Just after the user accepts the latest update, this message will appear. The title of the page. * “Help us” is intended to convey a sense of collaboration. Privacy Sandbox is an ongoing multi-year effort. There are sites participating to help us and we also need users to agree to these trials so that we can measure the effectiveness of the features we're building. * “build” is intended to convey that this is a process. The user is agreeing to an effort rather than a stable set of features. Something like “make” doesn't have the same nuance. * See www.privacysandbox.com for more context."> Help us build a better web </message> - <message name="IDS_PRIVACY_SANDBOX_NOTICE_SHEET_DESCRIPTION" desc="* “ad spam”: Spam related to web advertising. * “estimate your interests”: Topics of interest include things like “Live comedy” and “Rock music”. Chrome estimates these interests based on the sites users visit. It’s an “estimation”, and we don’t want to suggest that we know with certainty the user’s interests. Avoid words like “guess”, “establish”, “define”, etc. (in place of “estimate”)."> - Chrome is exploring ways to limit ad spam, fraud, and sharing between sites. Chrome also <ph name="BEGIN_LINK"><link></ph>estimates your interests<ph name="END_LINK"></link></ph> that sites can use to show you ads. You can manage your interests in settings. + <message name="IDS_PRIVACY_SANDBOX_NOTICE_SHEET_DESCRIPTION" desc="* “Chrome is finding new ways”: “finding” is meant to convey a work in progress, like “build” in the title. The features are live and functional, but still in beta. So we want a verb that’s stronger than “exploring” but weaker than “launching”. * “reduce tracking”: This used to read “reduce cross-site tracking”, but we’ve dropped “cross-site” because it makes the idea unnecessarily complicated. * “estimate your interests”: Topics of interest include things like “Live comedy” and “Rock music”. Chrome estimates these interests based on the sites users visit. It’s an “estimation”, and we don’t want to suggest that we know with certainty the user’s interests. Avoid words like “guess”, “establish”, “define”, etc. (in place of “estimate”). * “Then” is an important keyword. It suggests some amount of time later. The first step is that interests are generated. Later (minutes or weeks), a different site might request interests."> + Chrome is finding new ways to reduce tracking and keep you even safer as you browse. Chrome also <ph name="BEGIN_LINK"><link></ph>estimates your interests<ph name="END_LINK"></link></ph> and enables you to manage them. Then, sites you visit can ask Chrome for your interests to show you ads. </message> <!-- Secure DNS Settings. Used by //chrome/browser/privacy. -->
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PRIVACY_SANDBOX_NOTICE_SHEET_DESCRIPTION.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PRIVACY_SANDBOX_NOTICE_SHEET_DESCRIPTION.png.sha1 index 96f5b2cf..05d36da 100644 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PRIVACY_SANDBOX_NOTICE_SHEET_DESCRIPTION.png.sha1 +++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PRIVACY_SANDBOX_NOTICE_SHEET_DESCRIPTION.png.sha1
@@ -1 +1 @@ -bf9747db03de532e7297d606b1c7637ab8515bc0 \ No newline at end of file +cfa9942ea635d74d5f2541b54774095f0984aa3e \ No newline at end of file
diff --git a/chrome/browser/ui/app_list/search/omnibox_lacros_provider.cc b/chrome/browser/ui/app_list/search/omnibox_lacros_provider.cc index fa05697..573e10dd 100644 --- a/chrome/browser/ui/app_list/search/omnibox_lacros_provider.cc +++ b/chrome/browser/ui/app_list/search/omnibox_lacros_provider.cc
@@ -4,26 +4,67 @@ #include "chrome/browser/ui/app_list/search/omnibox_lacros_provider.h" +#include "ash/public/cpp/app_list/app_list_features.h" #include "base/bind.h" +#include "base/callback_forward.h" #include "chrome/browser/ash/crosapi/crosapi_ash.h" #include "chrome/browser/ash/crosapi/crosapi_manager.h" #include "chrome/browser/ash/crosapi/search_provider_ash.h" +#include "chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.h" +#include "chrome/browser/chromeos/launcher_search/search_util.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/app_list/app_list_controller_delegate.h" +#include "chrome/browser/ui/app_list/search/omnibox_answer_result.h" +#include "chrome/browser/ui/app_list/search/omnibox_result.h" +#include "chrome/browser/ui/app_list/search/omnibox_util.h" +#include "chrome/browser/ui/app_list/search/open_tab_result.h" +#include "chromeos/ash/components/string_matching/tokenized_string.h" #include "chromeos/crosapi/mojom/crosapi.mojom.h" +#include "chromeos/crosapi/mojom/launcher_search.mojom.h" +#include "components/omnibox/browser/autocomplete_input.h" +#include "url/gurl.h" namespace app_list { +// Note that there is necessarily a lot of overlap with code in the non-lacros +// omnibox provider, since this is implementing the same behavior (but using +// crosapi types). + +namespace { + +using ::ash::string_matching::TokenizedString; +using CrosApiSearchResult = ::crosapi::mojom::SearchResult; + +// Some answer result types overtrigger on short queries. Returns true if an +// answer should be filtered. +bool ShouldFilterAnswer(const crosapi::mojom::SearchResultPtr& search_result, + const std::u16string& query) { + // TODO(crbug.com/1258415): Move this to the filtering ranker once more + // detailed result subtype info is exposed by ChromeSearchResult. + if (query.size() >= kMinQueryLengthForCommonAnswers) + return false; + + switch (search_result->answer_type) { + case CrosApiSearchResult::AnswerType::kDictionary: + case CrosApiSearchResult::AnswerType::kTranslation: + return true; + default: + return false; + } +} + +} // namespace + OmniboxLacrosProvider::OmniboxLacrosProvider( Profile* profile, - AppListControllerDelegate* list_controller) + AppListControllerDelegate* list_controller, + crosapi::CrosapiManager* crosapi_manager) : profile_(profile), list_controller_(list_controller) { DCHECK(profile_); DCHECK(list_controller_); - if (crosapi::CrosapiManager::IsInitialized()) { - search_provider_ = - crosapi::CrosapiManager::Get()->crosapi_ash()->search_provider_ash(); + if (crosapi_manager) { + search_provider_ = crosapi_manager->crosapi_ash()->search_provider_ash(); DCHECK(search_provider_); } } @@ -34,6 +75,16 @@ if (!search_provider_) return; + last_query_ = query; + last_tokenized_query_.emplace(query, TokenizedString::Mode::kCamelCase); + + // Use page classification value CHROMEOS_APP_LIST to differentiate the + // suggest requests initiated by ChromeOS app_list from the ones by Chrome + // omnibox. + input_ = + AutocompleteInput(query, metrics::OmniboxEventProto::CHROMEOS_APP_LIST, + ChromeAutocompleteSchemeClassifier(profile_)); + search_provider_->Search( query, base::BindRepeating(&OmniboxLacrosProvider::OnResultsReceived, weak_factory_.GetWeakPtr())); @@ -45,7 +96,52 @@ void OmniboxLacrosProvider::OnResultsReceived( std::vector<crosapi::mojom::SearchResultPtr> results) { - // TODO(crbug.com/1228587): Implement. + SearchProvider::Results new_results; + new_results.reserve(results.size()); + + std::vector<std::unique_ptr<OmniboxResult>> list_results; + list_results.reserve(results.size()); + + for (auto&& search_result : results) { + // Do not return a match in any of these cases: + // - The URL is invalid. + // - The URL points to Drive Web and is not an open tab. The Drive search + // provider surfaces Drive results. + // - The URL points to a local file. The Local file search provider handles + // local file results, even if they've been opened in the browser. + const GURL& url = *search_result->destination_url; + const bool is_drive = + IsDriveUrl(url) && search_result->omnibox_type != + CrosApiSearchResult::OmniboxType::kOpenTab; + if (!url.is_valid() || is_drive || url.SchemeIsFile()) + continue; + + if (search_result->omnibox_type == + CrosApiSearchResult::OmniboxType::kOpenTab) { + // Open tab result. + DCHECK(last_tokenized_query_.has_value()); + new_results.emplace_back(std::make_unique<OpenTabResult>( + profile_, list_controller_, std::move(search_result), + last_tokenized_query_.value())); + } else if (!crosapi::OptionalBoolIsTrue(search_result->is_answer)) { + // Omnibox result. + list_results.emplace_back(std::make_unique<OmniboxResult>( + profile_, list_controller_, base::DoNothing(), + std::move(search_result), last_query_, + /*is_zero_suggestion=*/false)); + } else if (!ShouldFilterAnswer(search_result, last_query_)) { + // Answer result. + new_results.emplace_back(std::make_unique<OmniboxAnswerResult>( + profile_, list_controller_, std::move(search_result), last_query_)); + } + } + + // Deduplicate the list results and then move-concatenate it into new_results. + RemoveDuplicateResults(list_results); + std::move(list_results.begin(), list_results.end(), + std::back_inserter(new_results)); + + SwapResults(&new_results); } } // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/omnibox_lacros_provider.h b/chrome/browser/ui/app_list/search/omnibox_lacros_provider.h index e9f8bd8..08c47eca 100644 --- a/chrome/browser/ui/app_list/search/omnibox_lacros_provider.h +++ b/chrome/browser/ui/app_list/search/omnibox_lacros_provider.h
@@ -8,12 +8,16 @@ #include "ash/public/cpp/app_list/app_list_types.h" #include "base/memory/weak_ptr.h" #include "chrome/browser/ui/app_list/search/search_provider.h" +#include "chromeos/ash/components/string_matching/tokenized_string.h" #include "chromeos/crosapi/mojom/launcher_search.mojom.h" +#include "components/omnibox/browser/autocomplete_input.h" +#include "third_party/abseil-cpp/absl/types/optional.h" class AppListControllerDelegate; class Profile; namespace crosapi { +class CrosapiManager; class SearchProviderAsh; } // namespace crosapi @@ -22,7 +26,8 @@ class OmniboxLacrosProvider : public SearchProvider { public: OmniboxLacrosProvider(Profile* profile, - AppListControllerDelegate* list_controller); + AppListControllerDelegate* list_controller, + crosapi::CrosapiManager* crosapi_manager); ~OmniboxLacrosProvider() override; // SearchProvider: @@ -33,8 +38,13 @@ void OnResultsReceived(std::vector<crosapi::mojom::SearchResultPtr> results); crosapi::SearchProviderAsh* search_provider_; - Profile* profile_; - AppListControllerDelegate* list_controller_; + Profile* const profile_; + AppListControllerDelegate* const list_controller_; + + AutocompleteInput input_; + + std::u16string last_query_; + absl::optional<ash::string_matching::TokenizedString> last_tokenized_query_; base::WeakPtrFactory<OmniboxLacrosProvider> weak_factory_{this}; };
diff --git a/chrome/browser/ui/app_list/search/omnibox_lacros_provider_unittest.cc b/chrome/browser/ui/app_list/search/omnibox_lacros_provider_unittest.cc new file mode 100644 index 0000000..fb1a5e7 --- /dev/null +++ b/chrome/browser/ui/app_list/search/omnibox_lacros_provider_unittest.cc
@@ -0,0 +1,368 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/app_list/search/omnibox_lacros_provider.h" + +#include <memory> +#include <string> +#include <vector> + +#include "ash/constants/ash_features.h" +#include "base/run_loop.h" +#include "base/test/scoped_feature_list.h" +#include "chrome/browser/ash/crosapi/crosapi_ash.h" +#include "chrome/browser/ash/crosapi/crosapi_manager.h" +#include "chrome/browser/ash/crosapi/idle_service_ash.h" +#include "chrome/browser/ash/crosapi/search_provider_ash.h" +#include "chrome/browser/ash/crosapi/test_crosapi_dependency_registry.h" +#include "chrome/browser/search_engines/template_url_service_factory.h" +#include "chrome/browser/ui/app_list/search/omnibox_util.h" +#include "chrome/browser/ui/app_list/search/test/test_search_controller.h" +#include "chrome/browser/ui/app_list/test/test_app_list_controller_delegate.h" +#include "chrome/common/chrome_constants.h" +#include "chrome/test/base/testing_browser_process.h" +#include "chrome/test/base/testing_profile_manager.h" +#include "chromeos/crosapi/mojom/launcher_search.mojom.h" +#include "chromeos/login/login_state/login_state.h" +#include "content/public/test/browser_task_environment.h" +#include "mojo/public/cpp/bindings/associated_remote.h" +#include "mojo/public/cpp/bindings/pending_remote.h" +#include "mojo/public/cpp/bindings/receiver.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" + +namespace app_list::test { +namespace { + +namespace cam = ::crosapi::mojom; +using ::test::TestAppListControllerDelegate; + +// Helper functions to populate search results. + +cam::SearchResultPtr NewOmniboxResult(const std::string& url) { + auto result = cam::SearchResult::New(); + + result->type = cam::SearchResultType::kOmniboxResult; + result->relevance = 1.0; + result->destination_url = GURL(url); + result->stripped_destination_url = GURL(url); + result->is_answer = cam::SearchResult::OptionalBool::kFalse; + result->contents = u"contents"; + result->contents_type = cam::SearchResult::TextType::kUnset; + result->description = u"description"; + result->description_type = cam::SearchResult::TextType::kUnset; + result->is_omnibox_search = cam::SearchResult::OptionalBool::kFalse; + result->omnibox_type = cam::SearchResult::OmniboxType::kDomain; + result->metrics_type = cam::SearchResult::MetricsType::kWhatYouTyped; + + return result; +} + +cam::SearchResultPtr NewAnswerResult( + const std::string& url, + cam::SearchResult::AnswerType answer_type) { + auto result = cam::SearchResult::New(); + + result->type = cam::SearchResultType::kOmniboxResult; + result->relevance = 1.0; + result->destination_url = GURL(url); + result->stripped_destination_url = GURL(url); + result->is_answer = cam::SearchResult::OptionalBool::kTrue; + result->contents = u"contents"; + result->contents_type = cam::SearchResult::TextType::kUnset; + result->description = u"description"; + result->description_type = cam::SearchResult::TextType::kUnset; + result->is_omnibox_search = cam::SearchResult::OptionalBool::kTrue; + result->is_omnibox_search = cam::SearchResult::OptionalBool::kFalse; + result->answer_type = answer_type; + + return result; +} + +cam::SearchResultPtr NewOpenTabResult(const std::string& url) { + auto result = cam::SearchResult::New(); + + result->type = cam::SearchResultType::kOmniboxResult; + result->relevance = 1.0; + result->destination_url = GURL(url); + result->stripped_destination_url = GURL(url); + result->is_answer = cam::SearchResult::OptionalBool::kFalse; + result->contents = u"contents"; + result->contents_type = cam::SearchResult::TextType::kUnset; + result->description = u"description"; + result->description_type = cam::SearchResult::TextType::kUnset; + result->is_omnibox_search = cam::SearchResult::OptionalBool::kFalse; + result->omnibox_type = cam::SearchResult::OmniboxType::kOpenTab; + + return result; +} + +// A class that emulates lacros-side logic by producing and transmitting search +// results. Named "producer" because "controller", "provider" and "publisher" +// are all taken (sometimes more than once!). +class TestSearchResultProducer : public cam::SearchController { + public: + TestSearchResultProducer() = default; + TestSearchResultProducer(const TestSearchResultProducer&) = delete; + TestSearchResultProducer& operator=(const TestSearchResultProducer&) = delete; + ~TestSearchResultProducer() override = default; + + mojo::PendingRemote<cam::SearchController> BindToRemote() { + return receiver_.BindNewPipeAndPassRemote(); + } + + void ProduceResults(std::vector<cam::SearchResultPtr> results) { + // Bad search statuses aren't tested because the `OmniboxLacrosProvider` + // isn't responsible for handling them. + publisher_->OnSearchResultsReceived(cam::SearchStatus::kDone, + std::move(results)); + } + + const std::u16string& last_query() { return last_query_; } + + private: + // cam::SearchController overrides: + void Search(const std::u16string& query, SearchCallback callback) override { + last_query_ = query; + std::move(callback).Run(publisher_.BindNewEndpointAndPassReceiver()); + } + + mojo::Receiver<cam::SearchController> receiver_{this}; + mojo::AssociatedRemote<cam::SearchResultsPublisher> publisher_; + std::u16string last_query_; +}; + +} // namespace + +// Our main test fixture. Provides `search_producer_` with which tests can +// produce "lacros-side" results, and `search_controller_` with which tests can +// read the output of the `OmniboxLacrosProvider`. +class OmniboxLacrosProviderTest : public testing::Test { + public: + OmniboxLacrosProviderTest() { + scoped_feature_list_.InitAndEnableFeature( + ash::features::kProductivityLauncher); + } + OmniboxLacrosProviderTest(const OmniboxLacrosProviderTest&) = delete; + OmniboxLacrosProviderTest& operator=(const OmniboxLacrosProviderTest&) = + delete; + ~OmniboxLacrosProviderTest() override = default; + + void SetUp() override { + // The `CrosapiManager` requires: + // - An active profile manager and profile. + // - Various services disabled that can't run in unit tests. + // - A valid login state. + + // Create the profile manager and an active profile. + profile_manager_ = std::make_unique<TestingProfileManager>( + TestingBrowserProcess::GetGlobal()); + ASSERT_TRUE(profile_manager_->SetUp()); + // The profile needs a template URL service for history Omnibox results. + profile_ = profile_manager_->CreateTestingProfile( + chrome::kInitialProfile, + {{TemplateURLServiceFactory::GetInstance(), + base::BindRepeating(&TemplateURLServiceFactory::BuildInstanceFor)}}); + + // The idle service has dependencies we can't instantiate in unit tests. + crosapi::IdleServiceAsh::DisableForTesting(); + + // The crosapi manager reads the global login state. + chromeos::LoginState::Initialize(); + + crosapi_manager_ = crosapi::CreateCrosapiManagerWithTestRegistry(); + + // Create fake lacros-side logic. + search_producer_ = std::make_unique<TestSearchResultProducer>(); + crosapi_manager_->crosapi_ash() + ->search_provider_ash() + ->RegisterSearchController(search_producer_->BindToRemote()); + + // Create client of our provider. + search_controller_ = std::make_unique<TestSearchController>(); + + // Create the object to actually test. + omnibox_provider_ = std::make_unique<OmniboxLacrosProvider>( + profile_, &list_controller_, crosapi_manager_.get()); + omnibox_provider_->set_controller(search_controller_.get()); + } + + void TearDown() override { + omnibox_provider_.reset(); + search_controller_.reset(); + search_producer_.reset(); + crosapi_manager_.reset(); + chromeos::LoginState::Shutdown(); + profile_ = nullptr; + profile_manager_->DeleteTestingProfile(chrome::kInitialProfile); + } + + // Tells the producer to produce the given results, then waits for the results + // to be transmitted over their Mojo pipe. + void ProduceResults(std::vector<cam::SearchResultPtr> results) { + search_producer_->ProduceResults(std::move(results)); + base::RunLoop().RunUntilIdle(); + } + + // Starts a search and waits for the query to be sent to "lacros" over a Mojo + // pipe. + void StartSearch(const std::u16string& query) { + omnibox_provider_->Start(query); + base::RunLoop().RunUntilIdle(); + } + + protected: + std::unique_ptr<TestSearchResultProducer> search_producer_; + std::unique_ptr<TestSearchController> search_controller_; + + private: + base::test::ScopedFeatureList scoped_feature_list_; + content::BrowserTaskEnvironment task_environment_; + TestAppListControllerDelegate list_controller_; + + std::unique_ptr<TestingProfileManager> profile_manager_; + TestingProfile* profile_; + + std::unique_ptr<crosapi::CrosapiManager> crosapi_manager_; + + std::unique_ptr<OmniboxLacrosProvider> omnibox_provider_; +}; + +// Test that results sent from lacros each instantiate a Chrome search result. +TEST_F(OmniboxLacrosProviderTest, Basic) { + StartSearch(u"query"); + EXPECT_EQ(u"query", search_producer_->last_query()); + + std::vector<cam::SearchResultPtr> to_produce; + to_produce.emplace_back(NewOmniboxResult("https://example.com/result")); + to_produce.emplace_back(NewAnswerResult( + "https://example.com/answer", cam::SearchResult::AnswerType::kWeather)); + to_produce.emplace_back(NewOpenTabResult("https://example.com/open_tab")); + ProduceResults(std::move(to_produce)); + + // Results always appear after answer and open tab entries. + ASSERT_EQ(3u, search_controller_->last_results().size()); + EXPECT_EQ("omnibox_answer://https://example.com/answer", + search_controller_->last_results()[0]->id()); + EXPECT_EQ("opentab://https://example.com/open_tab", + search_controller_->last_results()[1]->id()); + EXPECT_EQ("https://example.com/result", + search_controller_->last_results()[2]->id()); +} + +// Test that newly-produced results supersede previous results. +TEST_F(OmniboxLacrosProviderTest, NewResults) { + StartSearch(u"query"); + + // Produce one result. + std::vector<cam::SearchResultPtr> to_produce; + to_produce.emplace_back(NewOpenTabResult("https://example.com/open_tab_1")); + ProduceResults(std::move(to_produce)); + + // Then produce another. + to_produce.clear(); + to_produce.emplace_back(NewOpenTabResult("https://example.com/open_tab_2")); + ProduceResults(std::move(to_produce)); + + // Only newest result should be stored. + ASSERT_EQ(1u, search_controller_->last_results().size()); + EXPECT_EQ("opentab://https://example.com/open_tab_2", + search_controller_->last_results()[0]->id()); +} + +// Test that invalid URLs aren't accepted. +TEST_F(OmniboxLacrosProviderTest, BadUrls) { + StartSearch(u"query"); + + // All results have bad URLs. + std::vector<cam::SearchResultPtr> to_produce; + to_produce.emplace_back(NewOmniboxResult("")); + to_produce.emplace_back( + NewAnswerResult("badscheme", cam::SearchResult::AnswerType::kWeather)); + to_produce.emplace_back(NewOpenTabResult("http://?k=v")); + ProduceResults(std::move(to_produce)); + + // None of the results should be accepted. + EXPECT_TRUE(search_controller_->last_results().empty()); +} + +// Test that results with the same URL are deduplicated in the correct order. +TEST_F(OmniboxLacrosProviderTest, Deduplicate) { + StartSearch(u"query"); + + // A result that has the same URL as another result, but is a history (i.e. + // higher-priority) type. + auto history_result = NewOmniboxResult("https://example.com/result_1"); + history_result->contents = u"history"; + history_result->is_omnibox_search = cam::SearchResult::OptionalBool::kTrue; + history_result->omnibox_type = cam::SearchResult::OmniboxType::kHistory; + history_result->metrics_type = cam::SearchResult::MetricsType::kSearchHistory; + + std::vector<cam::SearchResultPtr> to_produce; + to_produce.emplace_back(NewOmniboxResult("https://example.com/result_2")); + to_produce.emplace_back(NewOmniboxResult("https://example.com/result_1")); + to_produce.emplace_back(std::move(history_result)); + + ProduceResults(std::move(to_produce)); + + // Only the higher-priority (i.e. history) result for URL 1 should be kept. + ASSERT_EQ(2u, search_controller_->last_results().size()); + EXPECT_EQ("https://example.com/result_1", + search_controller_->last_results()[0]->id()); + EXPECT_EQ(u"history", search_controller_->last_results()[0]->title()); + EXPECT_EQ("https://example.com/result_2", + search_controller_->last_results()[1]->id()); +} + +// Test that results aren't created for URLs for which there are other +// specialist producers. +TEST_F(OmniboxLacrosProviderTest, UnhandledUrls) { + StartSearch(u"query"); + + // Drive URLs aren't handled (_unless_ they are open tabs pointing to the + // Drive website), and file URLs aren't handled. + std::vector<cam::SearchResultPtr> to_produce; + to_produce.emplace_back(NewOmniboxResult("https://drive.google.com/doc1")); + to_produce.emplace_back(NewAnswerResult( + "https://docs.google.com/doc2", cam::SearchResult::AnswerType::kFinance)); + to_produce.emplace_back(NewOpenTabResult("https://drive.google.com/doc1")); + to_produce.emplace_back(NewOpenTabResult("https://docs.google.com/doc2")); + to_produce.emplace_back(NewOpenTabResult("file:///docs/doc3")); + ProduceResults(std::move(to_produce)); + + ASSERT_EQ(2u, search_controller_->last_results().size()); + EXPECT_EQ("opentab://https://drive.google.com/doc1", + search_controller_->last_results()[0]->id()); + EXPECT_EQ("opentab://https://docs.google.com/doc2", + search_controller_->last_results()[1]->id()); +} + +// Test that answers of certain kinds (that tend to over-trigger) aren't shown +// on very short queries. +TEST_F(OmniboxLacrosProviderTest, ShortQuery) { + // Start with a query that is one character too short. + StartSearch(std::u16string(kMinQueryLengthForCommonAnswers - 1, 'a')); + + // All results except dictionary and translate answers are allowed. + std::vector<cam::SearchResultPtr> to_produce; + to_produce.emplace_back(NewOmniboxResult("https://nonanswer.com/")); + to_produce.emplace_back(NewAnswerResult( + "https://finance.com/", cam::SearchResult::AnswerType::kFinance)); + to_produce.emplace_back(NewOpenTabResult("https://opentab.com/")); + to_produce.emplace_back(NewAnswerResult( + "https://translation.com/", cam::SearchResult::AnswerType::kTranslation)); + to_produce.emplace_back(NewAnswerResult( + "https://dictionary.com/", cam::SearchResult::AnswerType::kDictionary)); + ProduceResults(std::move(to_produce)); + + ASSERT_EQ(3u, search_controller_->last_results().size()); + EXPECT_EQ("omnibox_answer://https://finance.com/", + search_controller_->last_results()[0]->id()); + EXPECT_EQ("opentab://https://opentab.com/", + search_controller_->last_results()[1]->id()); + EXPECT_EQ("https://nonanswer.com/", + search_controller_->last_results()[2]->id()); +} + +} // namespace app_list::test
diff --git a/chrome/browser/ui/app_list/search/omnibox_provider.cc b/chrome/browser/ui/app_list/search/omnibox_provider.cc index 5feb9350..2933cba 100644 --- a/chrome/browser/ui/app_list/search/omnibox_provider.cc +++ b/chrome/browser/ui/app_list/search/omnibox_provider.cc
@@ -12,7 +12,6 @@ #include "ash/public/cpp/app_list/app_list_features.h" #include "base/bind.h" #include "base/callback_forward.h" -#include "base/containers/flat_set.h" #include "base/memory/ptr_util.h" #include "base/metrics/histogram_macros.h" #include "chrome/browser/autocomplete/chrome_autocomplete_provider_client.h" @@ -27,6 +26,7 @@ #include "chrome/browser/ui/app_list/search/common/types_util.h" #include "chrome/browser/ui/app_list/search/omnibox_answer_result.h" #include "chrome/browser/ui/app_list/search/omnibox_result.h" +#include "chrome/browser/ui/app_list/search/omnibox_util.h" #include "chrome/browser/ui/app_list/search/open_tab_result.h" #include "chrome/browser/ui/app_list/search/ranking/util.h" #include "components/favicon/core/favicon_service.h" @@ -42,16 +42,6 @@ using ::ash::string_matching::TokenizedString; -// Some omnibox answers overtrigger on short queries. This controls the minimum -// query length before they are displayed. -constexpr size_t kMinQueryLengthForCommonAnswers = 4u; - -bool IsDriveUrl(const GURL& url) { - // Returns true if the |url| points to a Drive Web host. - const std::string& host = url.host(); - return host == "drive.google.com" || host == "docs.google.com"; -} - // Returns true if the match is an answer, including calculator answers. bool IsAnswer(const AutocompleteMatch& match) { return match.answer.has_value() || @@ -91,28 +81,6 @@ return providers; } -void RemoveDuplicates(std::vector<std::unique_ptr<OmniboxResult>>& results) { - // Sort the results by deduplication priority and then filter from left to - // right. This ensures that higher priority results are retained. - sort(results.begin(), results.end(), - [](const std::unique_ptr<OmniboxResult>& a, - const std::unique_ptr<OmniboxResult>& b) { - return a->dedup_priority() > b->dedup_priority(); - }); - - base::flat_set<std::string> seen_ids; - for (auto iter = results.begin(); iter != results.end();) { - bool inserted = seen_ids.insert((*iter)->id()).second; - if (!inserted) { - // C++11:: The return value of erase(iter) is an iterator pointing to the - // next element in the container. - iter = results.erase(iter); - } else { - ++iter; - } - } -} - } // namespace OmniboxProvider::OmniboxProvider(Profile* profile, @@ -232,7 +200,7 @@ } // Deduplicate the list results and then move-concatenate it into new_results. - RemoveDuplicates(list_results); + RemoveDuplicateResults(list_results); std::move(list_results.begin(), list_results.end(), std::back_inserter(new_results));
diff --git a/chrome/browser/ui/app_list/search/omnibox_result.cc b/chrome/browser/ui/app_list/search/omnibox_result.cc index 4d38f66..049a88b 100644 --- a/chrome/browser/ui/app_list/search/omnibox_result.cc +++ b/chrome/browser/ui/app_list/search/omnibox_result.cc
@@ -277,8 +277,7 @@ } bool OmniboxResult::IsRichEntity() const { - return search_result_->omnibox_type == - CrosApiSearchResult::OmniboxType::kRichImage; + return search_result_->image_url.value_or(GURL()).is_valid(); } void OmniboxResult::FetchRichEntityImage(const GURL& url) {
diff --git a/chrome/browser/ui/app_list/search/omnibox_result.h b/chrome/browser/ui/app_list/search/omnibox_result.h index 9a0f2c5f..a388a02 100644 --- a/chrome/browser/ui/app_list/search/omnibox_result.h +++ b/chrome/browser/ui/app_list/search/omnibox_result.h
@@ -30,6 +30,9 @@ public: // `remove_closure` must remove this result from the results list; it is // called when the "x" button next to the search result is pressed. + // + // TODO(1272361): remove this argument once result deletions are handled via + // their own ranker. OmniboxResult(Profile* profile, AppListControllerDelegate* list_controller, base::RepeatingClosure remove_closure,
diff --git a/chrome/browser/ui/app_list/search/omnibox_result_unittest.cc b/chrome/browser/ui/app_list/search/omnibox_result_unittest.cc index d845a4fe..acc5668 100644 --- a/chrome/browser/ui/app_list/search/omnibox_result_unittest.cc +++ b/chrome/browser/ui/app_list/search/omnibox_result_unittest.cc
@@ -403,6 +403,8 @@ GURL("https://example.com/icon.png")); base::RunLoop().RunUntilIdle(); + EXPECT_EQ(ash::AppListSearchResultCategory::kSearchAndAssistant, + result->category()); EXPECT_TRUE(ImageSkiasEqual(TestIcon(), result->icon().icon)); }
diff --git a/chrome/browser/ui/app_list/search/omnibox_util.cc b/chrome/browser/ui/app_list/search/omnibox_util.cc new file mode 100644 index 0000000..c136fa3 --- /dev/null +++ b/chrome/browser/ui/app_list/search/omnibox_util.cc
@@ -0,0 +1,45 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/app_list/search/omnibox_util.h" + +#include <algorithm> +#include <string> + +#include "base/containers/flat_set.h" +#include "chrome/browser/ui/app_list/search/omnibox_result.h" +#include "url/gurl.h" + +namespace app_list { + +bool IsDriveUrl(const GURL& url) { + // Returns true if the |url| points to a Drive Web host. + const std::string& host = url.host(); + return host == "drive.google.com" || host == "docs.google.com"; +} + +void RemoveDuplicateResults( + std::vector<std::unique_ptr<OmniboxResult>>& results) { + // Sort the results by deduplication priority and then filter from left to + // right. This ensures that higher priority results are retained. + sort(results.begin(), results.end(), + [](const std::unique_ptr<OmniboxResult>& a, + const std::unique_ptr<OmniboxResult>& b) { + return a->dedup_priority() > b->dedup_priority(); + }); + + base::flat_set<std::string> seen_ids; + for (auto iter = results.begin(); iter != results.end();) { + bool inserted = seen_ids.insert((*iter)->id()).second; + if (!inserted) { + // C++11:: The return value of erase(iter) is an iterator pointing to the + // next element in the container. + iter = results.erase(iter); + } else { + ++iter; + } + } +} + +} // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/omnibox_util.h b/chrome/browser/ui/app_list/search/omnibox_util.h index 08a11e13..cdb9d1f 100644 --- a/chrome/browser/ui/app_list/search/omnibox_util.h +++ b/chrome/browser/ui/app_list/search/omnibox_util.h
@@ -5,10 +5,17 @@ #ifndef CHROME_BROWSER_UI_APP_LIST_SEARCH_OMNIBOX_UTIL_H_ #define CHROME_BROWSER_UI_APP_LIST_SEARCH_OMNIBOX_UTIL_H_ +#include <memory> +#include <vector> + #include "net/traffic_annotation/network_traffic_annotation.h" +class GURL; + namespace app_list { +class OmniboxResult; + // The magic number 1500 is the highest score of an omnibox result. // See comments in autocomplete_provider.h. constexpr double kMaxOmniboxScore = 1500.0; @@ -40,6 +47,19 @@ "publicly available image." })"); +// Some omnibox answers overtrigger on short queries. This controls the minimum +// query length before they are displayed. +constexpr size_t kMinQueryLengthForCommonAnswers = 4u; + +// Whether this URL points to a Drive location. +bool IsDriveUrl(const GURL& url); + +// Removes duplicate results from the given list, with higher-priority results +// taking precedence over lower. After calling this function, the list will be +// sorted in descending order of priority. +void RemoveDuplicateResults( + std::vector<std::unique_ptr<OmniboxResult>>& results); + } // namespace app_list #endif // CHROME_BROWSER_UI_APP_LIST_SEARCH_OMNIBOX_UTIL_H_
diff --git a/chrome/browser/ui/app_list/search/search_controller_factory.cc b/chrome/browser/ui/app_list/search/search_controller_factory.cc index 8af49e6..78cb7b3 100644 --- a/chrome/browser/ui/app_list/search/search_controller_factory.cc +++ b/chrome/browser/ui/app_list/search/search_controller_factory.cc
@@ -16,6 +16,7 @@ #include "base/time/default_clock.h" #include "build/build_config.h" #include "chrome/browser/ash/arc/arc_util.h" +#include "chrome/browser/ash/crosapi/crosapi_manager.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/app_list/search/app_search_provider.h" #include "chrome/browser/ui/app_list/search/arc/arc_app_shortcuts_search_provider.h" @@ -114,7 +115,8 @@ if (app_list_features::IsLauncherLacrosIntegrationEnabled()) { controller->AddProvider( omnibox_group_id, - std::make_unique<OmniboxLacrosProvider>(profile, list_controller)); + std::make_unique<OmniboxLacrosProvider>( + profile, list_controller, crosapi::CrosapiManager::Get())); } else { controller->AddProvider(omnibox_group_id, std::make_unique<OmniboxProvider>( profile, list_controller));
diff --git a/chrome/browser/ui/content_settings/content_setting_bubble_model.cc b/chrome/browser/ui/content_settings/content_setting_bubble_model.cc index 28493de7..23f254c6 100644 --- a/chrome/browser/ui/content_settings/content_setting_bubble_model.cc +++ b/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
@@ -1600,6 +1600,19 @@ base::RecordAction( base::UserMetricsAction("Notifications.Quiet.StaticIconClicked")); break; + case QuietUiReason::kTriggeredDueToDisruptiveBehavior: + DCHECK_EQ(request_type, permissions::RequestType::kNotifications); + set_message(l10n_util::GetStringUTF16( + IDS_NOTIFICATIONS_QUIET_PERMISSION_BUBBLE_DISRUPTIVE_DESCRIPTION)); + set_cancel_button_text(l10n_util::GetStringUTF16( + IDS_NOTIFICATIONS_QUIET_PERMISSION_BUBBLE_COMPACT_ALLOW_BUTTON)); + set_done_button_text(l10n_util::GetStringUTF16( + IDS_NOTIFICATIONS_QUIET_PERMISSION_BUBBLE_CONTINUE_BLOCKING_BUTTON)); + set_show_learn_more(true); + set_manage_text_style(ManageTextStyle::kNone); + base::RecordAction( + base::UserMetricsAction("Notifications.Quiet.StaticIconClicked")); + break; case QuietUiReason::kServicePredictedVeryUnlikelyGrant: case QuietUiReason::kOnDevicePredictedVeryUnlikelyGrant: int bubble_message_string_id = 0; @@ -1716,6 +1729,7 @@ break; case QuietUiReason::kTriggeredDueToAbusiveRequests: case QuietUiReason::kTriggeredDueToAbusiveContent: + case QuietUiReason::kTriggeredDueToDisruptiveBehavior: manager->Deny(); base::RecordAction(base::UserMetricsAction( "Notifications.Quiet.ContinueBlockingClicked")); @@ -1739,6 +1753,7 @@ break; case QuietUiReason::kTriggeredDueToAbusiveRequests: case QuietUiReason::kTriggeredDueToAbusiveContent: + case QuietUiReason::kTriggeredDueToDisruptiveBehavior: manager->Accept(); base::RecordAction( base::UserMetricsAction("Notifications.Quiet.ShowForSiteClicked"));
diff --git a/chrome/browser/ui/hats/hats_service_browsertest.cc b/chrome/browser/ui/hats/hats_service_browsertest.cc index 56d53b0..67c36d6 100644 --- a/chrome/browser/ui/hats/hats_service_browsertest.cc +++ b/chrome/browser/ui/hats/hats_service_browsertest.cc
@@ -42,11 +42,6 @@ {{"probability", "1.000"}, {"survey", kHatsSurveyTriggerSettings}, {"en_site_id", "test_site_id"}}}; -base::test::ScopedFeatureList::FeatureAndParams settings_probability_one{ - features::kHappinessTrackingSurveysForDesktopSettings, - {{"probability", "1.000"}, - {"survey", kHatsSurveyTriggerSettings}, - {"en_site_id", "test_site_id"}}}; class ScopedSetMetricsConsent { public: @@ -128,9 +123,7 @@ delete; protected: - HatsServiceProbabilityOne() - : HatsServiceBrowserTestBase( - {probability_one, settings_probability_one}) {} + HatsServiceProbabilityOne() : HatsServiceBrowserTestBase({probability_one}) {} ~HatsServiceProbabilityOne() override = default;
diff --git a/chrome/browser/ui/views/collected_cookies_views.cc b/chrome/browser/ui/views/collected_cookies_views.cc index 70964ea..0d6eff2 100644 --- a/chrome/browser/ui/views/collected_cookies_views.cc +++ b/chrome/browser/ui/views/collected_cookies_views.cc
@@ -15,7 +15,7 @@ #include "chrome/browser/ui/views/chrome_layout_provider.h" #include "chrome/browser/ui/views/chrome_typography.h" #include "chrome/browser/ui/views/cookie_info_view.h" -#include "chrome/browser/ui/views/site_data/page_specific_site_data_dialog.h" +#include "chrome/browser/ui/views/site_data/page_specific_site_data_dialog_controller.h" #include "chrome/grit/generated_resources.h" #include "components/browsing_data/content/cookie_helper.h" #include "components/browsing_data/content/database_helper.h" @@ -27,7 +27,6 @@ #include "components/content_settings/browser/page_specific_content_settings.h" #include "components/content_settings/core/browser/cookie_settings.h" #include "components/infobars/content/content_infobar_manager.h" -#include "components/page_info/core/features.h" #include "components/strings/grit/components_strings.h" #include "components/vector_icons/vector_icons.h" #include "components/web_modal/web_contents_modal_dialog_manager.h" @@ -125,62 +124,6 @@ } // namespace -class CollectedCookiesViews::WebContentsUserData - : public content::WebContentsUserData< - CollectedCookiesViews::WebContentsUserData> { - public: - ~WebContentsUserData() override { - if (!tracker_.view()) - return; // Dialog already destroyed. - // Destroyed while the Widget is still alive, close immediately. - tracker_.view()->GetWidget()->CloseNow(); - } - - static views::View* GetDialogView(content::WebContents* web_contents) { - WebContentsUserData* handle = static_cast<WebContentsUserData*>( - web_contents->GetUserData(UserDataKey())); - if (!handle) - return nullptr; - return handle->GetDialogView(); - } - - static void Create(content::WebContents* web_contents) { - CollectedCookiesViews::WebContentsUserData::CreateForWebContents( - web_contents); - } - - private: - friend class content::WebContentsUserData<WebContentsUserData>; - - explicit WebContentsUserData(content::WebContents* web_contents) - : content::WebContentsUserData< - CollectedCookiesViews::WebContentsUserData>(*web_contents) { - // TODO(crbug.com/1344787): Provide a public interface to show cookies - // dialog independent on the actual implementation, not tied to any views - // class. - if (base::FeatureList::IsEnabled(page_info::kPageSpecificSiteDataDialog)) { - views::Widget* widget = ShowPageSpecificSiteDataDialog(web_contents); - tracker_.SetView(widget->GetRootView()); - } else { - // CollectedCookiesViews is DialogDelegateView and it's owned by its - // widget. It created the widget in the constructor using - // `ShowWebModalDialogViews()`. It will be destroyed when its widget is - // destroyed. - CollectedCookiesViews* const dialog = - new CollectedCookiesViews(web_contents); - tracker_.SetView(dialog); - } - } - - views::View* GetDialogView() { return tracker_.view(); } - - views::ViewTracker tracker_; - - WEB_CONTENTS_USER_DATA_KEY_DECL(); -}; - -WEB_CONTENTS_USER_DATA_KEY_IMPL(CollectedCookiesViews::WebContentsUserData); - // This DrawingProvider allows TreeModelNodes to be annotated with auxiliary // text. Annotated nodes will be drawn in a lighter color than normal to // indicate that their state has changed, and will have their auxiliary text @@ -325,42 +268,11 @@ CollectedCookiesViews::~CollectedCookiesViews() { web_contents_->RemoveUserData( - CollectedCookiesViews::WebContentsUserData::UserDataKey()); + PageSpecificSiteDataDialogController::UserDataKey()); allowed_cookies_tree_->SetModel(nullptr); blocked_cookies_tree_->SetModel(nullptr); } -// static -void CollectedCookiesViews::CreateAndShowForWebContents( - content::WebContents* web_contents) { - views::View* const instance = - CollectedCookiesViews::WebContentsUserData::GetDialogView(web_contents); - if (!instance) { - CollectedCookiesViews::WebContentsUserData::Create(web_contents); - return; - } - - // On rare occasions, |instance| may have started, but not finished, - // closing. In this case, the modal dialog manager will have removed the - // dialog from its list of tracked dialogs, and therefore might not have any - // active dialog. This should be rare enough that it's not worth trying to - // re-open the dialog. See https://crbug.com/989888 - if (instance->GetWidget()->IsClosed()) - return; - - auto* dialog_manager = - web_modal::WebContentsModalDialogManager::FromWebContents(web_contents); - CHECK(dialog_manager->IsDialogActive()); - dialog_manager->FocusTopmostDialog(); -} - -CollectedCookiesViews* CollectedCookiesViews::GetDialogForTesting( - content::WebContents* web_contents) { - CHECK(!base::FeatureList::IsEnabled(page_info::kPageSpecificSiteDataDialog)); - return static_cast<CollectedCookiesViews*>( - CollectedCookiesViews::WebContentsUserData::GetDialogView(web_contents)); -} - /////////////////////////////////////////////////////////////////////////////// // CollectedCookiesViews, views::TabbedPaneListener implementation:
diff --git a/chrome/browser/ui/views/collected_cookies_views.h b/chrome/browser/ui/views/collected_cookies_views.h index 4c11e2a..13915c7 100644 --- a/chrome/browser/ui/views/collected_cookies_views.h +++ b/chrome/browser/ui/views/collected_cookies_views.h
@@ -48,12 +48,6 @@ CollectedCookiesViews& operator=(const CollectedCookiesViews&) = delete; ~CollectedCookiesViews() override; - // Use BrowserWindow::ShowCollectedCookiesDialog to show. - static void CreateAndShowForWebContents(content::WebContents* web_contents); - - static CollectedCookiesViews* GetDialogForTesting( - content::WebContents* web_contents); - void set_status_changed_for_testing() { status_changed_ = true; } // views::TabbedPaneListener: @@ -66,7 +60,7 @@ gfx::Size GetMinimumSize() const override; private: - class WebContentsUserData; + friend class PageSpecificSiteDataDialogController; explicit CollectedCookiesViews(content::WebContents* web_contents);
diff --git a/chrome/browser/ui/views/collected_cookies_views_browsertest.cc b/chrome/browser/ui/views/collected_cookies_views_browsertest.cc index 8760532..fbed8c3 100644 --- a/chrome/browser/ui/views/collected_cookies_views_browsertest.cc +++ b/chrome/browser/ui/views/collected_cookies_views_browsertest.cc
@@ -9,6 +9,7 @@ #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/views/collected_cookies_views.h" +#include "chrome/browser/ui/views/site_data/page_specific_site_data_dialog_controller.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" #include "components/content_settings/core/browser/cookie_settings.h" @@ -40,8 +41,11 @@ // Spawn a cookies dialog. auto* web_contents = browser()->tab_strip_model()->GetActiveWebContents(); - CollectedCookiesViews::CreateAndShowForWebContents(web_contents); - cookies_dialog_ = CollectedCookiesViews::GetDialogForTesting(web_contents); + PageSpecificSiteDataDialogController::CreateAndShowForWebContents( + web_contents); + cookies_dialog_ = + PageSpecificSiteDataDialogController::GetDialogViewForTesting( + web_contents); } // Closing dialog with modified data will shows infobar. @@ -107,6 +111,7 @@ IN_PROC_BROWSER_TEST_F(CollectedCookiesViewsTest, CloseDialogAndReopen) { CloseCookiesDialog(); auto* web_contents = browser()->tab_strip_model()->GetActiveWebContents(); - CollectedCookiesViews::CreateAndShowForWebContents(web_contents); + PageSpecificSiteDataDialogController::CreateAndShowForWebContents( + web_contents); // If the test didn't crash, it has passed. }
diff --git a/chrome/browser/ui/views/frame/webui_tab_strip_field_trial_browsertest.cc b/chrome/browser/ui/views/frame/webui_tab_strip_field_trial_browsertest.cc index 1ee791e..f38a66d 100644 --- a/chrome/browser/ui/views/frame/webui_tab_strip_field_trial_browsertest.cc +++ b/chrome/browser/ui/views/frame/webui_tab_strip_field_trial_browsertest.cc
@@ -13,7 +13,6 @@ #include "base/strings/string_piece.h" #include "base/test/mock_entropy_provider.h" #include "base/test/scoped_feature_list.h" -#include "base/test/scoped_field_trial_list_resetter.h" #include "build/build_config.h" #include "build/chromeos_buildflags.h" #include "chrome/browser/ui/ui_features.h" @@ -74,6 +73,9 @@ WebUITabStripFieldTrialBrowserTest() { variations::SyntheticTrialsActiveGroupIdProvider::GetInstance() ->ResetForTesting(); + null_feature_list_.InitWithNullFeatureAndFieldTrialLists(); + field_trial_list_ = std::make_unique<base::FieldTrialList>( + std::make_unique<base::MockEntropyProvider>(0.0)); } protected: @@ -84,10 +86,14 @@ base::FeatureList* feature_list() { return feature_list_.get(); } private: - base::test::ScopedFieldTrialListResetter scoped_field_trial_list_resetter_; - base::FieldTrialList field_trial_list_{ - std::make_unique<base::MockEntropyProvider>(0.0)}; - + // |null_feature_list_| is used to initialize FieldTrialLists to be + // null. This is required to create a new FieldTrialList. + base::test::ScopedFeatureList null_feature_list_; + // |field_trial_list_| is a new FieldTrialList with MockEntryProvider(0.0), + // created for WebUITabStripFieldTrialBrowserTest. + std::unique_ptr<base::FieldTrialList> field_trial_list_; + // |scoped_feature_list_| is used to enable and disable features for + // WebUITabStripFieldTrialBrowserTest. base::test::ScopedFeatureList scoped_feature_list_; std::unique_ptr<base::FeatureList> feature_list_ =
diff --git a/chrome/browser/ui/views/payments/credit_card_editor_view_controller.cc b/chrome/browser/ui/views/payments/credit_card_editor_view_controller.cc deleted file mode 100644 index 045f48e7..0000000 --- a/chrome/browser/ui/views/payments/credit_card_editor_view_controller.cc +++ /dev/null
@@ -1,745 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/views/payments/credit_card_editor_view_controller.h" - -#include <memory> -#include <string> -#include <utility> -#include <vector> - -#include "base/bind.h" -#include "base/callback.h" -#include "base/logging.h" -#include "base/memory/raw_ptr.h" -#include "base/strings/utf_string_conversions.h" -#include "base/time/time.h" -#include "chrome/browser/ui/autofill/payments/autofill_dialog_models.h" -#include "chrome/browser/ui/scoped_tabbed_browser_displayer.h" -#include "chrome/browser/ui/singleton_tabs.h" -#include "chrome/browser/ui/views/chrome_layout_provider.h" -#include "chrome/browser/ui/views/payments/payment_request_dialog_view.h" -#include "chrome/browser/ui/views/payments/payment_request_dialog_view_ids.h" -#include "chrome/browser/ui/views/payments/payment_request_views_util.h" -#include "chrome/browser/ui/views/payments/validating_combobox.h" -#include "chrome/browser/ui/views/payments/validating_textfield.h" -#include "chrome/grit/generated_resources.h" -#include "components/autofill/core/browser/autofill_data_util.h" -#include "components/autofill/core/browser/autofill_type.h" -#include "components/autofill/core/browser/data_model/credit_card.h" -#include "components/autofill/core/browser/field_types.h" -#include "components/autofill/core/browser/payments/payments_service_url.h" -#include "components/autofill/core/browser/personal_data_manager.h" -#include "components/autofill/core/browser/ui/address_combobox_model.h" -#include "components/autofill/core/browser/validation.h" -#include "components/autofill/core/common/autofill_clock.h" -#include "components/autofill/core/common/autofill_constants.h" -#include "components/payments/content/payment_request_spec.h" -#include "components/payments/content/payment_request_state.h" -#include "components/payments/core/autofill_card_validation.h" -#include "components/payments/core/payment_request_data_util.h" -#include "components/payments/core/strings_util.h" -#include "components/strings/grit/components_strings.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/compositor/layer.h" -#include "ui/gfx/geometry/insets.h" -#include "ui/native_theme/native_theme.h" -#include "ui/views/controls/button/md_text_button.h" -#include "ui/views/controls/image_view.h" -#include "ui/views/controls/label.h" -#include "ui/views/controls/styled_label.h" -#include "ui/views/controls/textfield/textfield.h" -#include "ui/views/layout/box_layout.h" -#include "ui/views/layout/fill_layout.h" -#include "ui/views/view.h" - -namespace payments { - -namespace { - -// Opacity of card network icons when they are not selected and are displayed -// alongside a selected icon. -const float kDimmedCardIconOpacity = 0.33f; - -// This is not quite right but is the closest server type that wasn't already -// used. -const auto kBillingAddressType = autofill::ADDRESS_HOME_LINE1; - -bool IsCardExpired(const std::u16string& month, - const std::u16string& year, - const std::string& app_locale) { - autofill::CreditCard card; - card.SetExpirationMonthFromString(month, app_locale); - card.SetExpirationYearFromString(year); - return card.IsExpired(autofill::AutofillClock::Now()); -} - -// Validates the two comboboxes used for expiration date. -class ExpirationDateValidationDelegate : public ValidationDelegate { - public: - ExpirationDateValidationDelegate(EditorViewController* controller, - const std::string& app_locale, - bool initially_valid) - : controller_(controller), - app_locale_(app_locale), - initially_valid_(initially_valid) {} - - ExpirationDateValidationDelegate(const ExpirationDateValidationDelegate&) = - delete; - ExpirationDateValidationDelegate& operator=( - const ExpirationDateValidationDelegate&) = delete; - - bool IsValidTextfield(views::Textfield* textfield, - std::u16string* error_message) override { - NOTREACHED(); - return true; - } - - bool IsValidCombobox(ValidatingCombobox* combobox, - std::u16string* error_message) override { - // View will have no parent if it's not been attached yet. Use initial - // validity state. - views::View* view_parent = combobox->parent(); - if (!view_parent) { - *error_message = - initially_valid_ - ? std::u16string() - : l10n_util::GetStringUTF16( - IDS_PAYMENTS_VALIDATION_INVALID_CREDIT_CARD_EXPIRED); - return initially_valid_; - } - - // Get the combined date from the month and year dropdowns. - views::Combobox* month_combobox = static_cast<views::Combobox*>( - view_parent->GetViewByID(EditorViewController::GetInputFieldViewId( - autofill::CREDIT_CARD_EXP_MONTH))); - std::u16string month = month_combobox->GetModel()->GetItemAt( - month_combobox->GetSelectedIndex().value()); - - views::Combobox* year_combobox = static_cast<views::Combobox*>( - view_parent->GetViewByID(EditorViewController::GetInputFieldViewId( - autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR))); - std::u16string year = year_combobox->GetModel()->GetItemAt( - year_combobox->GetSelectedIndex().value()); - - bool is_expired = IsCardExpired(month, year, app_locale_); - month_combobox->SetInvalid(is_expired); - year_combobox->SetInvalid(is_expired); - - *error_message = - is_expired ? l10n_util::GetStringUTF16( - IDS_PAYMENTS_VALIDATION_INVALID_CREDIT_CARD_EXPIRED) - : std::u16string(); - return !is_expired; - } - - bool TextfieldValueChanged(views::Textfield* textfield, - bool was_blurred) override { - NOTREACHED(); - return true; - } - - bool ComboboxValueChanged(ValidatingCombobox* combobox) override { - std::u16string error_message; - bool is_valid = IsValidCombobox(combobox, &error_message); - controller_->DisplayErrorMessageForField( - autofill::CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, error_message); - return is_valid; - } - - void ComboboxModelChanged(ValidatingCombobox* combobox) override {} - - private: - raw_ptr<EditorViewController> controller_; - const std::string app_locale_; - bool initially_valid_; -}; - -} // namespace - -CreditCardEditorViewController::CreditCardEditorViewController( - base::WeakPtr<PaymentRequestSpec> spec, - base::WeakPtr<PaymentRequestState> state, - base::WeakPtr<PaymentRequestDialogView> dialog, - BackNavigationType back_navigation, - base::OnceClosure on_edited, - base::OnceCallback<void(const autofill::CreditCard&)> on_added, - autofill::CreditCard* credit_card, - bool is_incognito) - : EditorViewController(spec, state, dialog, back_navigation, is_incognito), - on_edited_(std::move(on_edited)), - on_added_(std::move(on_added)), - credit_card_to_edit_(credit_card) { - if (spec) - supported_card_networks_ = spec->supported_card_networks_set(); -} - -CreditCardEditorViewController::~CreditCardEditorViewController() {} - -// Creates the "Cards accepted" view with a row of icons at the top of the -// credit card editor. -// +----------------------------------------------+ -// | Cards Accepted | -// | | -// | | VISA | | MC | | AMEX | | -// +----------------------------------------------+ -std::unique_ptr<views::View> -CreditCardEditorViewController::CreateHeaderView() { - std::unique_ptr<views::View> view = std::make_unique<views::View>(); - if (!spec()) - return view; - - // 9dp is required between the first row (label) and second row (icons). - constexpr int kRowVerticalSpacing = 9; - // 6dp is added to the bottom padding, for a total of 12 between the icons and - // the first input field. - constexpr int kRowBottomPadding = 6; - auto layout = std::make_unique<views::BoxLayout>( - views::BoxLayout::Orientation::kVertical, - gfx::Insets::VH(kRowBottomPadding, kPaymentRequestRowHorizontalInsets), - kRowVerticalSpacing); - layout->set_main_axis_alignment(views::BoxLayout::MainAxisAlignment::kStart); - layout->set_cross_axis_alignment( - views::BoxLayout::CrossAxisAlignment::kStart); - view->SetLayoutManager(std::move(layout)); - - // "Accepted cards" label is "hint" grey. - view->AddChildView(CreateHintLabel(l10n_util::GetStringUTF16( - IDS_PAYMENTS_ACCEPTED_CARDS_LABEL)) - .release()); - - // 8dp padding is required between icons. - constexpr int kPaddingBetweenCardIcons = 8; - std::unique_ptr<views::View> icons_row = std::make_unique<views::View>(); - icons_row->SetLayoutManager(std::make_unique<views::BoxLayout>( - views::BoxLayout::Orientation::kHorizontal, gfx::Insets(), - kPaddingBetweenCardIcons)); - - std::string selected_network = - credit_card_to_edit_ ? autofill::data_util::GetPaymentRequestData( - credit_card_to_edit_->network()) - .basic_card_issuer_network - : ""; - constexpr gfx::Size kCardIconSize = gfx::Size(30, 18); - for (const std::string& supported_network : - spec()->supported_card_networks()) { - const std::string autofill_card_network = - autofill::data_util::GetIssuerNetworkForBasicCardIssuerNetwork( - supported_network); - // Icon is fully opaque if no network is selected, or if it is the selected - // network. - float opacity = - selected_network.empty() || selected_network == supported_network - ? 1.0f - : kDimmedCardIconOpacity; - std::unique_ptr<views::ImageView> card_icon_view = CreateAppIconView( - autofill::data_util::GetPaymentRequestData(autofill_card_network) - .icon_resource_id, - /*icon_bitmap=*/nullptr, base::UTF8ToUTF16(supported_network), opacity); - card_icon_view->SetImageSize(kCardIconSize); - - // Keep track of this card icon to later adjust opacity. - card_icons_[supported_network] = card_icon_view.get(); - - icons_row->AddChildView(card_icon_view.release()); - } - view->AddChildView(icons_row.release()); - - // If dealing with a server card, we add "From Google Payments" with an edit - // link. - if (IsEditingServerCard()) { - std::unique_ptr<views::View> data_source = std::make_unique<views::View>(); - data_source->SetLayoutManager(std::make_unique<views::BoxLayout>( - views::BoxLayout::Orientation::kHorizontal, gfx::Insets(), - kPaddingBetweenCardIcons)); - - // "From Google Payments". - data_source->AddChildView( - CreateHintLabel( - l10n_util::GetStringUTF16(IDS_AUTOFILL_FROM_GOOGLE_ACCOUNT_LONG)) - .release()); - - // "Edit" link. - auto edit_link = std::make_unique<views::StyledLabel>(); - std::u16string link_text = - l10n_util::GetStringUTF16(IDS_AUTOFILL_WALLET_MANAGEMENT_LINK_TEXT); - edit_link->SetText(link_text); - edit_link->SetID( - static_cast<int>(DialogViewID::GOOGLE_PAYMENTS_EDIT_LINK_LABEL)); - edit_link->AddStyleRange( - gfx::Range(0, link_text.size()), - views::StyledLabel::RangeStyleInfo::CreateForLink(base::BindRepeating( - [](base::WeakPtr<PaymentRequestDialogView> dialog) { - chrome::ScopedTabbedBrowserDisplayer displayer( - dialog->GetProfile()); - ShowSingletonTab(displayer.browser(), - autofill::payments::GetManageAddressesUrl()); - }, - dialog()))); - edit_link->SizeToFit(0); - data_source->AddChildView(edit_link.release()); - - view->AddChildView(data_source.release()); - } - - return view; -} - -std::unique_ptr<views::View> -CreditCardEditorViewController::CreateCustomFieldView( - autofill::ServerFieldType type, - views::View** focusable_field, - bool* valid, - std::u16string* error_message) { - DCHECK_EQ(type, autofill::CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR); - - std::unique_ptr<views::View> view = std::make_unique<views::View>(); - if (IsEditingServerCard()) { - std::unique_ptr<views::Label> exp_label = std::make_unique<views::Label>( - credit_card_to_edit_->ExpirationDateForDisplay()); - exp_label->SetID( - GetInputFieldViewId(autofill::CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR)); - exp_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); - - view = std::move(exp_label); - } else { - // Two comboboxes, one for month and the other for year. - - // Space between the two comboboxes. - constexpr int kHorizontalSpacing = 8; - view->SetLayoutManager(std::make_unique<views::BoxLayout>( - views::BoxLayout::Orientation::kHorizontal, - gfx::Insets(), kHorizontalSpacing)) - ->SetDefaultFlex(1); - - EditorField tmp_month{ - autofill::CREDIT_CARD_EXP_MONTH, - l10n_util::GetStringUTF16(IDS_SETTINGS_CREDIT_CARD_EXPIRATION_MONTH), - EditorField::LengthHint::HINT_SHORT, - /*required=*/true, EditorField::ControlType::COMBOBOX}; - std::unique_ptr<ValidatingCombobox> month_combobox = - CreateComboboxForField(tmp_month, error_message); - *focusable_field = view->AddChildView(std::move(month_combobox)); - - EditorField tmp_year{ - autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR, - l10n_util::GetStringUTF16(IDS_SETTINGS_CREDIT_CARD_EXPIRATION_YEAR), - EditorField::LengthHint::HINT_SHORT, - /*required=*/true, EditorField::ControlType::COMBOBOX}; - std::unique_ptr<ValidatingCombobox> year_combobox = - CreateComboboxForField(tmp_year, error_message); - view->AddChildView(std::move(year_combobox)); - } - - // Set the initial validity of the custom view. - std::u16string month = - GetInitialValueForType(autofill::CREDIT_CARD_EXP_MONTH); - std::u16string year = - GetInitialValueForType(autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR); - *valid = !IsCardExpired(month, year, state()->GetApplicationLocale()); - return view; -} - -std::unique_ptr<views::View> -CreditCardEditorViewController::CreateExtraViewForField( - autofill::ServerFieldType type) { - if (type != kBillingAddressType) - return nullptr; - - auto button_view = std::make_unique<views::View>(); - button_view->SetLayoutManager(std::make_unique<views::FillLayout>()); - - // The button to add new billing addresses. - auto add_button = std::make_unique<views::MdTextButton>( - base::BindRepeating( - &PaymentRequestDialogView::ShowShippingAddressEditor, dialog(), - BackNavigationType::kOneStep, base::RepeatingClosure(), - base::BindRepeating( - &CreditCardEditorViewController::AddAndSelectNewBillingAddress, - weak_ptr_factory_.GetWeakPtr()), - nullptr), - l10n_util::GetStringUTF16(IDS_ADD)); - add_button->SetID(static_cast<int>(DialogViewID::ADD_BILLING_ADDRESS_BUTTON)); - add_button->SetFocusBehavior(views::View::FocusBehavior::ALWAYS); - button_view->AddChildView(std::move(add_button)); - return button_view; -} - -bool CreditCardEditorViewController::IsEditingExistingItem() { - return !!credit_card_to_edit_; -} - -std::vector<EditorField> CreditCardEditorViewController::GetFieldDefinitions() { - bool is_server_card = IsEditingServerCard(); - return std::vector<EditorField>{ - {autofill::CREDIT_CARD_NUMBER, - l10n_util::GetStringUTF16(IDS_SETTINGS_CREDIT_CARD_NUMBER), - EditorField::LengthHint::HINT_SHORT, /*required=*/true, - is_server_card ? EditorField::ControlType::READONLY_LABEL - : EditorField::ControlType::TEXTFIELD_NUMBER}, - {autofill::CREDIT_CARD_NAME_FULL, - l10n_util::GetStringUTF16(IDS_SETTINGS_NAME_ON_CREDIT_CARD), - EditorField::LengthHint::HINT_SHORT, /*required=*/true, - is_server_card ? EditorField::ControlType::READONLY_LABEL - : EditorField::ControlType::TEXTFIELD}, - {autofill::CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, - l10n_util::GetStringUTF16(IDS_SETTINGS_CREDIT_CARD_EXPIRATION_DATE), - EditorField::LengthHint::HINT_SHORT, /*required=*/true, - EditorField::ControlType::CUSTOMFIELD}, - {kBillingAddressType, - l10n_util::GetStringUTF16(IDS_AUTOFILL_FIELD_LABEL_BILLING_ADDRESS), - EditorField::LengthHint::HINT_SHORT, /*required=*/true, - EditorField::ControlType::COMBOBOX}}; -} - -std::u16string CreditCardEditorViewController::GetInitialValueForType( - autofill::ServerFieldType type) { - if (!credit_card_to_edit_ || type == kBillingAddressType) - return std::u16string(); - - std::u16string info = credit_card_to_edit_->GetInfo( - autofill::AutofillType(type), state()->GetApplicationLocale()); - - return type == autofill::CREDIT_CARD_NUMBER - ? data_util::FormatCardNumberForDisplay(info) - : info; -} - -bool CreditCardEditorViewController::ValidateModelAndSave() { - if (IsEditingServerCard()) { - views::Combobox* address_combobox = static_cast<views::Combobox*>( - dialog()->GetViewByID(GetInputFieldViewId(kBillingAddressType))); - if (address_combobox->GetInvalid()) - return false; - - autofill::AddressComboboxModel* model = - static_cast<autofill::AddressComboboxModel*>( - address_combobox->GetModel()); - - credit_card_to_edit_->set_billing_address_id(model->GetItemIdentifierAt( - address_combobox->GetSelectedIndex().value())); - if (!is_incognito()) { - state()->GetPersonalDataManager()->UpdateServerCardsMetadata( - {*credit_card_to_edit_}); - } - return true; - } - - const std::string& locale = state()->GetApplicationLocale(); - // Use a temporary object for validation. - autofill::CreditCard credit_card; - credit_card.set_origin(autofill::kSettingsOrigin); - - if (!ValidateInputFields()) - return false; - - for (const auto& field : text_fields()) { - // ValidatingTextfield* is the key, EditorField is the value. - DCHECK_EQ(autofill::FieldTypeGroup::kCreditCard, - autofill::AutofillType(field.second.type).group()); - credit_card.SetInfo(autofill::AutofillType(field.second.type), - field.first->GetText(), locale); - } - for (const auto& field : comboboxes()) { - // ValidatingCombobox* is the key, EditorField is the value. - ValidatingCombobox* combobox = field.first; - - if (field.second.type == kBillingAddressType) { - autofill::AddressComboboxModel* model = - static_cast<autofill::AddressComboboxModel*>(combobox->GetModel()); - - credit_card.set_billing_address_id( - model->GetItemIdentifierAt(combobox->GetSelectedIndex().value())); - } else { - credit_card.SetInfo( - autofill::AutofillType(field.second.type), - combobox->GetTextForRow(combobox->GetSelectedIndex().value()), - locale); - } - } - - // TODO(crbug.com/711365): Display global error message. - if (GetCompletionStatusForCard( - credit_card, locale, - state()->GetPersonalDataManager()->GetProfiles()) != - CREDIT_CARD_COMPLETE) { - return false; - } - - if (!credit_card_to_edit_) { - if (!is_incognito()) { - // Add the card (will not add a duplicate). - state()->GetPersonalDataManager()->AddCreditCard(credit_card); - } - std::move(on_added_).Run(credit_card); - } else { - credit_card_to_edit_->set_billing_address_id( - credit_card.billing_address_id()); - // We were in edit mode. Copy the data from the temporary object to retain - // the edited object's other properties (use count, use date, guid, etc.). - for (const auto& field : text_fields()) { - credit_card_to_edit_->SetInfo( - autofill::AutofillType(field.second.type), - credit_card.GetInfo(autofill::AutofillType(field.second.type), - locale), - locale); - } - for (const auto& field : comboboxes()) { - // The billing address is transfered above. - if (field.second.type == kBillingAddressType) - continue; - - credit_card_to_edit_->SetInfo( - autofill::AutofillType(field.second.type), - credit_card.GetInfo(autofill::AutofillType(field.second.type), - locale), - locale); - } - if (!is_incognito()) - state()->GetPersonalDataManager()->UpdateCreditCard( - *credit_card_to_edit_); - std::move(on_edited_).Run(); - } - - return true; -} - -std::unique_ptr<ValidationDelegate> -CreditCardEditorViewController::CreateValidationDelegate( - const EditorField& field) { - if (field.type == autofill::CREDIT_CARD_EXP_MONTH || - field.type == autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR) { - bool initially_valid = - credit_card_to_edit_ - ? !credit_card_to_edit_->IsExpired(autofill::AutofillClock::Now()) - : true; - return std::make_unique<ExpirationDateValidationDelegate>( - this, state()->GetApplicationLocale(), initially_valid); - } - // The supported card networks for non-cc-number types are not passed to avoid - // the data copy in the delegate. - return std::make_unique< - CreditCardEditorViewController::CreditCardValidationDelegate>(field, - this); -} - -std::unique_ptr<ui::ComboboxModel> -CreditCardEditorViewController::GetComboboxModelForType( - const autofill::ServerFieldType& type) { - switch (type) { - case autofill::CREDIT_CARD_EXP_MONTH: { - return std::make_unique<autofill::MonthComboboxModel>(); - } - case autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR: - return std::make_unique<autofill::YearComboboxModel>( - credit_card_to_edit_ ? credit_card_to_edit_->expiration_year() : 0); - case kBillingAddressType: - // The combobox filled with potential billing addresses. It's fine to pass - // empty string as the default selected guid if there are no cards being - // edited. - return std::make_unique<autofill::AddressComboboxModel>( - *state()->GetPersonalDataManager(), state()->GetApplicationLocale(), - credit_card_to_edit_ ? credit_card_to_edit_->billing_address_id() - : ""); - default: - NOTREACHED(); - break; - } - return nullptr; -} - -void CreditCardEditorViewController::SelectBasicCardNetworkIcon( - const std::string& basic_card_network) { - // If empty string was passed or if the icon representing |basic_card_network| - // is not present (i.e. not supported), all icons have full opacity. - bool full_opacity = - card_icons_.find(basic_card_network) == card_icons_.end() || - basic_card_network.empty(); - for (auto network_icon_it : card_icons_) { - float target_opacity = - full_opacity || network_icon_it.first == basic_card_network - ? 1.0f - : kDimmedCardIconOpacity; - network_icon_it.second->layer()->SetOpacity(target_opacity); - network_icon_it.second->layer()->ScheduleDraw(); - } -} - -void CreditCardEditorViewController::FillContentView( - views::View* content_view) { - EditorViewController::FillContentView(content_view); - // We need to search from the content view here, since the dialog may not have - // the content view added to it yet. - views::Combobox* combobox = static_cast<views::Combobox*>( - content_view->GetViewByID(GetInputFieldViewId(kBillingAddressType))); - // When the combobox has a single item, it's because it has no addresses - // (otherwise, it would have the select header, and a separator before the - // first address to choose from). - DCHECK(combobox); - combobox->SetEnabled(combobox->GetRowCount() > 1); -} - -bool CreditCardEditorViewController::IsValidCreditCardNumber( - const std::u16string& card_number, - std::u16string* error_message) { - return autofill::IsValidCreditCardNumberForBasicCardNetworks( - card_number, supported_card_networks_, error_message); - // TODO(crbug.com/725604): The UI should offer to load / update the existing - // credit card info if another local credit card has already been created with - // this number. (Does not apply to server cards, which can be accessed only in - // tokenized form through Google Pay.) -} - -std::u16string CreditCardEditorViewController::GetSheetTitle() { - if (!credit_card_to_edit_) - return l10n_util::GetStringUTF16(IDS_PAYMENTS_ADD_CARD); - - // Gets the completion message, or empty if nothing is missing from the card. - std::u16string title = GetCompletionMessageForCard(GetCompletionStatusForCard( - *credit_card_to_edit_, state()->GetApplicationLocale(), - state()->GetPersonalDataManager()->GetProfiles())); - return title.empty() ? l10n_util::GetStringUTF16(IDS_PAYMENTS_EDIT_CARD) - : title; -} - -void CreditCardEditorViewController::AddAndSelectNewBillingAddress( - const autofill::AutofillProfile& profile) { - state()->AddAutofillShippingProfile(false, profile); - views::Combobox* address_combobox = static_cast<views::Combobox*>( - dialog()->GetViewByID(GetInputFieldViewId(kBillingAddressType))); - autofill::AddressComboboxModel* model = - static_cast<autofill::AddressComboboxModel*>( - address_combobox->GetModel()); - int index = model->AddNewProfile(profile); - // SetSelectedIndex doesn't trigger a perform action notification, which is - // needed to update the valid state. - address_combobox->SetSelectedRow(index); - // The combobox might be initially disabled in FillContentView, but we've - // added an item; check if we should re-enable it. - address_combobox->SetEnabled(address_combobox->GetRowCount() > 1); - // But it needs to be blured at least once. - address_combobox->OnBlur(); -} - -bool CreditCardEditorViewController::IsEditingServerCard() const { - return credit_card_to_edit_ && credit_card_to_edit_->record_type() != - autofill::CreditCard::LOCAL_CARD; -} - -CreditCardEditorViewController::CreditCardValidationDelegate:: - CreditCardValidationDelegate(const EditorField& field, - CreditCardEditorViewController* controller) - : field_(field), controller_(controller) {} -CreditCardEditorViewController::CreditCardValidationDelegate:: - ~CreditCardValidationDelegate() {} - -bool CreditCardEditorViewController::CreditCardValidationDelegate:: - ShouldFormat() { - return field_.type == autofill::CREDIT_CARD_NUMBER; -} - -std::u16string -CreditCardEditorViewController::CreditCardValidationDelegate::Format( - const std::u16string& text) { - return data_util::FormatCardNumberForDisplay(text); -} - -bool CreditCardEditorViewController::CreditCardValidationDelegate:: - IsValidTextfield(views::Textfield* textfield, - std::u16string* error_message) { - return ValidateValue(textfield->GetText(), error_message); -} - -bool CreditCardEditorViewController::CreditCardValidationDelegate:: - IsValidCombobox(ValidatingCombobox* combobox, - std::u16string* error_message) { - return ValidateCombobox(combobox, error_message); -} - -bool CreditCardEditorViewController::CreditCardValidationDelegate:: - TextfieldValueChanged(views::Textfield* textfield, bool was_blurred) { - // The only behavior pre-blur is selecting the card icon. - if (field_.type == autofill::CREDIT_CARD_NUMBER) { - std::string basic_card_network = - autofill::data_util::GetPaymentRequestData( - autofill::CreditCard::GetCardNetwork(textfield->GetText())) - .basic_card_issuer_network; - controller_->SelectBasicCardNetworkIcon(basic_card_network); - } - - // We return true if the field was not yet blurred, because validation should - // not occur yet. - if (!was_blurred) - return true; - - std::u16string error_message; - bool is_valid = ValidateValue(textfield->GetText(), &error_message); - controller_->DisplayErrorMessageForField(field_.type, error_message); - - return is_valid; -} - -bool CreditCardEditorViewController::CreditCardValidationDelegate:: - ComboboxValueChanged(ValidatingCombobox* combobox) { - std::u16string error_message; - bool is_valid = ValidateCombobox(combobox, nullptr); - controller_->DisplayErrorMessageForField(field_.type, error_message); - return is_valid; -} - -bool CreditCardEditorViewController::CreditCardValidationDelegate:: - ValidateValue(const std::u16string& value, std::u16string* error_message) { - if (!value.empty()) { - std::u16string local_error_message; - bool is_valid = false; - if (field_.type == autofill::CREDIT_CARD_NUMBER) { - is_valid = - controller_->IsValidCreditCardNumber(value, &local_error_message); - } else { - is_valid = - autofill::IsValidForType(value, field_.type, &local_error_message); - } - if (error_message) - *error_message = local_error_message; - return is_valid; - } - - if (error_message && field_.required) { - *error_message = l10n_util::GetStringUTF16( - IDS_PREF_EDIT_DIALOG_FIELD_REQUIRED_VALIDATION_MESSAGE); - } - return !field_.required; -} - -bool CreditCardEditorViewController::CreditCardValidationDelegate:: - ValidateCombobox(ValidatingCombobox* combobox, - std::u16string* error_message) { - // The billing address ID is the selected item identifier and not the combobox - // value itself. - if (field_.type == kBillingAddressType) { - // TODO(crbug.com/718905) Find a way to deal with existing incomplete - // addresses when choosing them as billing addresses. - autofill::AddressComboboxModel* model = - static_cast<autofill::AddressComboboxModel*>(combobox->GetModel()); - if (model->GetItemIdentifierAt(combobox->GetSelectedIndex().value()) - .empty()) { - if (error_message) { - *error_message = - l10n_util::GetStringUTF16(IDS_PAYMENTS_BILLING_ADDRESS_REQUIRED); - } - return false; - } - return true; - } - return ValidateValue( - combobox->GetTextForRow(combobox->GetSelectedIndex().value()), - error_message); -} - -bool CreditCardEditorViewController::GetSheetId(DialogViewID* sheet_id) { - *sheet_id = DialogViewID::CREDIT_CARD_EDITOR_SHEET; - return true; -} - -} // namespace payments
diff --git a/chrome/browser/ui/views/payments/credit_card_editor_view_controller.h b/chrome/browser/ui/views/payments/credit_card_editor_view_controller.h deleted file mode 100644 index 06ab1b8..0000000 --- a/chrome/browser/ui/views/payments/credit_card_editor_view_controller.h +++ /dev/null
@@ -1,158 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_VIEWS_PAYMENTS_CREDIT_CARD_EDITOR_VIEW_CONTROLLER_H_ -#define CHROME_BROWSER_UI_VIEWS_PAYMENTS_CREDIT_CARD_EDITOR_VIEW_CONTROLLER_H_ - -#include <memory> -#include <set> -#include <string> -#include <vector> - -#include "base/callback_forward.h" -#include "base/memory/raw_ptr.h" -#include "base/memory/weak_ptr.h" -#include "chrome/browser/ui/views/payments/editor_view_controller.h" -#include "chrome/browser/ui/views/payments/validation_delegate.h" -#include "ui/base/models/simple_combobox_model.h" - -namespace autofill { -class AutofillProfile; -class CreditCard; -} // namespace autofill - -namespace payments { - -class PaymentRequestSpec; -class PaymentRequestState; -class PaymentRequestDialogView; - -// Credit card editor screen of the Payment Request flow. -class CreditCardEditorViewController : public EditorViewController { - public: - // Does not take ownership of the arguments (except for the |on_edited| and - // |on_added| callbacks), which should outlive this object. Additionally, - // |credit_card| could be nullptr if we are adding a card. Else, it's a valid - // pointer to a card that needs to be updated, and which will outlive this - // controller. - CreditCardEditorViewController( - base::WeakPtr<PaymentRequestSpec> spec, - base::WeakPtr<PaymentRequestState> state, - base::WeakPtr<PaymentRequestDialogView> dialog, - BackNavigationType back_navigation, - base::OnceClosure on_edited, - base::OnceCallback<void(const autofill::CreditCard&)> on_added, - autofill::CreditCard* credit_card, - bool is_incognito); - - CreditCardEditorViewController(const CreditCardEditorViewController&) = - delete; - CreditCardEditorViewController& operator=( - const CreditCardEditorViewController&) = delete; - - ~CreditCardEditorViewController() override; - - // EditorViewController: - std::unique_ptr<views::View> CreateHeaderView() override; - std::unique_ptr<views::View> CreateCustomFieldView( - autofill::ServerFieldType type, - views::View** focusable_field, - bool* valid, - std::u16string* error_message) override; - std::unique_ptr<views::View> CreateExtraViewForField( - autofill::ServerFieldType type) override; - bool IsEditingExistingItem() override; - std::vector<EditorField> GetFieldDefinitions() override; - std::u16string GetInitialValueForType( - autofill::ServerFieldType type) override; - bool ValidateModelAndSave() override; - std::unique_ptr<ValidationDelegate> CreateValidationDelegate( - const EditorField& field) override; - std::unique_ptr<ui::ComboboxModel> GetComboboxModelForType( - const autofill::ServerFieldType& type) override; - - // Selects the icon in the UI corresponding to |basic_card_network| with - // higher opacity. If empty string, selects none of them (all full opacity). - void SelectBasicCardNetworkIcon(const std::string& basic_card_network); - - // Exposed for validation delegate. - bool IsValidCreditCardNumber(const std::u16string& card_number, - std::u16string* error_message); - - protected: - // PaymentRequestSheetController: - void FillContentView(views::View* content_view) override; - std::u16string GetSheetTitle() override; - - private: - class CreditCardValidationDelegate : public ValidationDelegate { - public: - // Used to validate |field| type. A reference to the |controller| should - // outlive this delegate. - CreditCardValidationDelegate(const EditorField& field, - CreditCardEditorViewController* controller); - - CreditCardValidationDelegate(const CreditCardValidationDelegate&) = delete; - CreditCardValidationDelegate& operator=( - const CreditCardValidationDelegate&) = delete; - - ~CreditCardValidationDelegate() override; - - // ValidationDelegate: - bool ShouldFormat() override; - std::u16string Format(const std::u16string& text) override; - bool IsValidTextfield(views::Textfield* textfield, - std::u16string* error_message) override; - bool IsValidCombobox(ValidatingCombobox* combobox, - std::u16string* error_message) override; - bool TextfieldValueChanged(views::Textfield* textfield, - bool was_blurred) override; - bool ComboboxValueChanged(ValidatingCombobox* combobox) override; - void ComboboxModelChanged(ValidatingCombobox* combobox) override {} - - private: - // Validates a specific |value|/|combobox|. - bool ValidateValue(const std::u16string& value, - std::u16string* error_message); - bool ValidateCombobox(ValidatingCombobox* combobox, - std::u16string* error_message); - - EditorField field_; - // Outlives this class. - raw_ptr<CreditCardEditorViewController> controller_; - }; - - bool GetSheetId(DialogViewID* sheet_id) override; - - // Called when a new address was created to be used as the billing address. - // The lifespan of |profile| beyond this call is undefined but it's OK, it's - // simply propagated to the address combobox model. - void AddAndSelectNewBillingAddress(const autofill::AutofillProfile& profile); - - // Whether the editor is editing a server card (masked). - bool IsEditingServerCard() const; - - // Called when |credit_card_to_edit_| was successfully edited. - base::OnceClosure on_edited_; - // Called when a new card was added. The const reference is short-lived, and - // the callee should make a copy. - base::OnceCallback<void(const autofill::CreditCard&)> on_added_; - - // If non-nullptr, a pointer to an object to be edited. Must outlive this - // controller. - raw_ptr<autofill::CreditCard> credit_card_to_edit_; - - // Keeps track of the card icons currently visible, keyed by basic card - // network. - std::map<std::string, views::View*> card_icons_; - - // The list of supported basic card networks. - std::set<std::string> supported_card_networks_; - - base::WeakPtrFactory<CreditCardEditorViewController> weak_ptr_factory_{this}; -}; - -} // namespace payments - -#endif // CHROME_BROWSER_UI_VIEWS_PAYMENTS_CREDIT_CARD_EDITOR_VIEW_CONTROLLER_H_
diff --git a/chrome/browser/ui/views/payments/payment_method_view_controller.cc b/chrome/browser/ui/views/payments/payment_method_view_controller.cc index 9cf15b12..e42d893da 100644 --- a/chrome/browser/ui/views/payments/payment_method_view_controller.cc +++ b/chrome/browser/ui/views/payments/payment_method_view_controller.cc
@@ -171,9 +171,7 @@ base::WeakPtr<PaymentRequestState> state, base::WeakPtr<PaymentRequestDialogView> dialog) : PaymentRequestSheetController(spec, state, dialog), - payment_method_list_(dialog), - enable_add_card_(!state->is_retry_called() && - spec->supports_basic_card()) { + payment_method_list_(dialog) { const std::vector<std::unique_ptr<PaymentApp>>& available_apps = state->available_apps(); for (const auto& app : available_apps) { @@ -211,23 +209,13 @@ } bool PaymentMethodViewController::ShouldShowSecondaryButton() { - return enable_add_card_; + return false; } std::u16string PaymentMethodViewController::GetSecondaryButtonLabel() { return l10n_util::GetStringUTF16(IDS_PAYMENTS_ADD_CARD); } -PaymentRequestSheetController::ButtonCallback -PaymentMethodViewController::GetSecondaryButtonCallback() { - return base::BindRepeating( - &PaymentRequestDialogView::ShowCreditCardEditor, dialog(), - BackNavigationType::kPaymentSheet, base::RepeatingClosure(), - base::BindRepeating(&PaymentRequestState::AddAutofillPaymentApp, state(), - true), - nullptr); -} - int PaymentMethodViewController::GetSecondaryButtonId() { return static_cast<int>(DialogViewID::PAYMENT_METHOD_ADD_CARD_BUTTON); }
diff --git a/chrome/browser/ui/views/payments/payment_method_view_controller.h b/chrome/browser/ui/views/payments/payment_method_view_controller.h index bce8838fd..f5d8960 100644 --- a/chrome/browser/ui/views/payments/payment_method_view_controller.h +++ b/chrome/browser/ui/views/payments/payment_method_view_controller.h
@@ -36,13 +36,9 @@ bool ShouldShowPrimaryButton() override; bool ShouldShowSecondaryButton() override; std::u16string GetSecondaryButtonLabel() override; - ButtonCallback GetSecondaryButtonCallback() override; int GetSecondaryButtonId() override; PaymentRequestItemList payment_method_list_; - - // Whether or not adding a new card is allowed. - bool enable_add_card_; }; } // namespace payments
diff --git a/chrome/browser/ui/views/payments/payment_request_dialog_view.cc b/chrome/browser/ui/views/payments/payment_request_dialog_view.cc index b1e834d..ba3ea69 100644 --- a/chrome/browser/ui/views/payments/payment_request_dialog_view.cc +++ b/chrome/browser/ui/views/payments/payment_request_dialog_view.cc
@@ -14,7 +14,6 @@ #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/views/payments/contact_info_editor_view_controller.h" -#include "chrome/browser/ui/views/payments/credit_card_editor_view_controller.h" #include "chrome/browser/ui/views/payments/error_message_view_controller.h" #include "chrome/browser/ui/views/payments/order_summary_view_controller.h" #include "chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.h" @@ -25,7 +24,6 @@ #include "chrome/browser/ui/views/payments/shipping_address_editor_view_controller.h" #include "chrome/browser/ui/views/payments/shipping_option_view_controller.h" #include "components/autofill/core/browser/data_model/autofill_profile.h" -#include "components/autofill/core/browser/data_model/credit_card.h" #include "components/constrained_window/constrained_window_views.h" #include "components/payments/content/payment_request.h" #include "components/payments/core/features.h" @@ -370,27 +368,6 @@ observer_for_testing_->OnShippingOptionSectionOpened(); } -void PaymentRequestDialogView::ShowCreditCardEditor( - BackNavigationType back_navigation_type, - base::OnceClosure on_edited, - base::OnceCallback<void(const autofill::CreditCard&)> on_added, - autofill::CreditCard* credit_card) { - if (!request_->spec()) - return; - - view_stack_->Push( - CreateViewAndInstallController( - std::make_unique<CreditCardEditorViewController>( - request_->spec(), request_->state(), - weak_ptr_factory_.GetWeakPtr(), back_navigation_type, - std::move(on_edited), std::move(on_added), credit_card, - request_->IsOffTheRecord()), - &controller_map_), - /* animate = */ true); - if (observer_for_testing_) - observer_for_testing_->OnCreditCardEditorOpened(); -} - void PaymentRequestDialogView::ShowShippingAddressEditor( BackNavigationType back_navigation_type, base::OnceClosure on_edited,
diff --git a/chrome/browser/ui/views/payments/payment_request_dialog_view.h b/chrome/browser/ui/views/payments/payment_request_dialog_view.h index 6a157a30..df84f9c 100644 --- a/chrome/browser/ui/views/payments/payment_request_dialog_view.h +++ b/chrome/browser/ui/views/payments/payment_request_dialog_view.h
@@ -22,7 +22,6 @@ namespace autofill { class AutofillProfile; -class CreditCard; } // namespace autofill class Profile; @@ -141,17 +140,6 @@ void ShowShippingProfileSheet(); void ShowPaymentMethodSheet(); void ShowShippingOptionSheet(); - // |credit_card| is the card to be edited, or nullptr for adding a card. - // |on_edited| is called when |credit_card| was successfully edited, and - // |on_added| is called when a new credit card was added (the reference is - // short-lived; callee should make a copy of the CreditCard object). - // |back_navigation_type| identifies the type of navigation to execute once - // the editor has completed successfully. - void ShowCreditCardEditor( - BackNavigationType back_navigation_type, - base::OnceClosure on_edited, - base::OnceCallback<void(const autofill::CreditCard&)> on_added, - autofill::CreditCard* credit_card = nullptr); // |profile| is the address to be edited, or nullptr for adding an address. // |on_edited| is called when |profile| was successfully edited, and // |on_added| is called when a new profile was added (the reference is
diff --git a/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc b/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc index 2519d8d..c607711a 100644 --- a/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc +++ b/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc
@@ -631,13 +631,12 @@ /*button_enabled=*/true); } -// Creates the Payment Method row, which contains a "Payment" label, the user's -// masked Credit Card details, the icon for the selected card, and a chevron. -// If no option is selected or none is available, the Chevron and icon are -// replaced with a button +// Creates the Payment Method row, which contains a "Payment" label, the +// selected Payment Method's name and details, the Payment Method's icon, and a +// chevron. // +----------------------------------------------+ -// | Payment Visa ****0000 | -// | John Smith | VISA | > | +// | Payment BobBucks | +// | bobbucks.dev | ICON | > | // | | // +----------------------------------------------+ std::unique_ptr<PaymentRequestRowView> @@ -647,58 +646,40 @@ PaymentSheetRowBuilder builder( this, l10n_util::GetStringUTF16( IDS_PAYMENT_REQUEST_PAYMENT_METHOD_SECTION_NAME)); - builder - .Id(selected_app - ? DialogViewID::PAYMENT_SHEET_PAYMENT_METHOD_SECTION - : DialogViewID::PAYMENT_SHEET_PAYMENT_METHOD_SECTION_BUTTON) - .Closure( - state()->available_apps().empty() - ? base::BindRepeating( - &PaymentSheetViewController::AddPaymentMethodButtonPressed, - base::Unretained(this)) - : base::BindRepeating( - &PaymentRequestDialogView::ShowPaymentMethodSheet, - dialog())); + builder.Id(DialogViewID::PAYMENT_SHEET_PAYMENT_METHOD_SECTION) + .Closure(base::BindRepeating( + &PaymentRequestDialogView::ShowPaymentMethodSheet, dialog())); - if (selected_app) { - auto content_view = - views::Builder<views::BoxLayoutView>() - .SetOrientation(views::BoxLayout::Orientation::kVertical) - .SetCrossAxisAlignment(views::BoxLayout::CrossAxisAlignment::kStart) - .SetMainAxisAlignment(views::BoxLayout::MainAxisAlignment::kCenter) - .AddChildren(views::Builder<views::Label>() - .SetText(selected_app->GetLabel()) - .SetHorizontalAlignment(gfx::ALIGN_LEFT), - views::Builder<views::Label>() - .SetText(selected_app->GetSublabel()) - .SetHorizontalAlignment(gfx::ALIGN_LEFT)); + // This method may be called with either no app pre-selected (e.g., if no app + // has a valid icon), or without any apps available at all (e.g., if we have a + // ServiceWorker payment app that has not yet been loaded). In those cases, we + // render a 'choose' dialog instead of the app details. + if (!selected_app) { + const std::u16string label = state()->available_apps().empty() + ? std::u16string() + : state()->available_apps()[0]->GetLabel(); + return builder.CreateWithButton( + label, l10n_util::GetStringUTF16(IDS_CHOOSE), true); + } - std::unique_ptr<views::ImageView> icon_view = CreateAppIconView( - selected_app->icon_resource_id(), selected_app->icon_bitmap(), - selected_app->GetLabel()); + auto content_view = + views::Builder<views::BoxLayoutView>() + .SetOrientation(views::BoxLayout::Orientation::kVertical) + .SetCrossAxisAlignment(views::BoxLayout::CrossAxisAlignment::kStart) + .SetMainAxisAlignment(views::BoxLayout::MainAxisAlignment::kCenter) + .AddChildren(views::Builder<views::Label>() + .SetText(selected_app->GetLabel()) + .SetHorizontalAlignment(gfx::ALIGN_LEFT), + views::Builder<views::Label>() + .SetText(selected_app->GetSublabel()) + .SetHorizontalAlignment(gfx::ALIGN_LEFT)); - return builder.AccessibleContent(selected_app->GetLabel()) - .CreateWithChevron(std::move(content_view).Build(), - std::move(icon_view)); - } - if (state()->available_apps().empty()) { - return builder.CreateWithButton(std::u16string(), - l10n_util::GetStringUTF16(IDS_ADD), - /*button_enabled=*/true); - } - const std::u16string label = state()->available_apps()[0]->GetLabel(); - if (state()->available_apps().size() == 1) { - return builder.CreateWithButton(label, - l10n_util::GetStringUTF16(IDS_CHOOSE), - /*button_enabled=*/true); - } - std::u16string format = l10n_util::GetPluralStringFUTF16( - IDS_PAYMENT_REQUEST_PAYMENT_METHODS_PREVIEW, - state()->available_apps().size() - 1); - return builder.CreateWithButton(label, format, - state()->available_apps().size() - 1, - l10n_util::GetStringUTF16(IDS_CHOOSE), - /*button_enabled=*/true); + std::unique_ptr<views::ImageView> icon_view = + CreateAppIconView(selected_app->icon_resource_id(), + selected_app->icon_bitmap(), selected_app->GetLabel()); + + return builder.AccessibleContent(selected_app->GetLabel()) + .CreateWithChevron(std::move(content_view).Build(), std::move(icon_view)); } std::unique_ptr<views::View> @@ -904,14 +885,6 @@ nullptr); } -void PaymentSheetViewController::AddPaymentMethodButtonPressed() { - dialog()->ShowCreditCardEditor( - BackNavigationType::kPaymentSheet, base::RepeatingClosure(), - base::BindRepeating(&PaymentRequestState::AddAutofillPaymentApp, state(), - true), - nullptr); -} - void PaymentSheetViewController::AddContactInfoButtonPressed() { dialog()->ShowContactInfoEditor( BackNavigationType::kPaymentSheet, base::RepeatingClosure(),
diff --git a/chrome/browser/ui/views/payments/payment_sheet_view_controller.h b/chrome/browser/ui/views/payments/payment_sheet_view_controller.h index 2024a0d..897c756 100644 --- a/chrome/browser/ui/views/payments/payment_sheet_view_controller.h +++ b/chrome/browser/ui/views/payments/payment_sheet_view_controller.h
@@ -67,7 +67,6 @@ std::unique_ptr<views::View> CreateDataSourceRow(); void AddShippingButtonPressed(); - void AddPaymentMethodButtonPressed(); void AddContactInfoButtonPressed(); };
diff --git a/chrome/browser/ui/views/side_panel/side_panel_coordinator_unittest.cc b/chrome/browser/ui/views/side_panel/side_panel_coordinator_unittest.cc index 7893abe..8629ed1 100644 --- a/chrome/browser/ui/views/side_panel/side_panel_coordinator_unittest.cc +++ b/chrome/browser/ui/views/side_panel/side_panel_coordinator_unittest.cc
@@ -193,6 +193,42 @@ min_web_contents_width); } +TEST_F(SidePanelCoordinatorTest, ChangeSidePanelWidthWindowResize) { + coordinator_->Toggle(); + const int starting_width = 500; + browser_view()->right_aligned_side_panel()->SetPanelWidth(starting_width); + browser_view()->Layout(); + EXPECT_EQ(browser_view()->right_aligned_side_panel()->width(), + starting_width); + + // Shrink browser window enough that side panel should also shrink in + // observance of web contents minimum width. + gfx::Rect original_bounds(browser_view()->GetBounds()); + gfx::Size new_size(starting_width, starting_width); + gfx::Rect new_bounds(original_bounds); + new_bounds.set_size(new_size); + // Explicitly restore the browser window on ChromeOS, as it would otherwise + // be maximized and the SetBounds call would be a no-op. +#if BUILDFLAG(IS_CHROMEOS_ASH) + browser_view()->Restore(); +#endif + browser_view()->SetBounds(new_bounds); + EXPECT_LT(browser_view()->right_aligned_side_panel()->width(), + starting_width); + BrowserViewLayout* layout_manager = + static_cast<BrowserViewLayout*>(browser_view()->GetLayoutManager()); + const int min_web_contents_width = + layout_manager->GetMinWebContentsWidthForTesting(); + EXPECT_EQ(browser_view()->contents_web_view()->width(), + min_web_contents_width); + + // Return browser window to original size, side panel should also return to + // size prior to window resize. + browser_view()->SetBounds(original_bounds); + EXPECT_EQ(browser_view()->right_aligned_side_panel()->width(), + starting_width); +} + TEST_F(SidePanelCoordinatorTest, ChangeSidePanelAlignment) { browser_view()->GetProfile()->GetPrefs()->SetBoolean( prefs::kSidePanelHorizontalAlignment, true);
diff --git a/chrome/browser/ui/views/site_data/page_specific_site_data_dialog_controller.cc b/chrome/browser/ui/views/site_data/page_specific_site_data_dialog_controller.cc new file mode 100644 index 0000000..d3f2073 --- /dev/null +++ b/chrome/browser/ui/views/site_data/page_specific_site_data_dialog_controller.cc
@@ -0,0 +1,90 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/views/site_data/page_specific_site_data_dialog_controller.h" + +#include "base/feature_list.h" +#include "chrome/browser/ui/views/collected_cookies_views.h" +#include "chrome/browser/ui/views/site_data/page_specific_site_data_dialog.h" +#include "components/page_info/core/features.h" +#include "components/web_modal/web_contents_modal_dialog_manager.h" +#include "content/public/browser/web_contents_user_data.h" +#include "ui/views/widget/widget.h" + +PageSpecificSiteDataDialogController::~PageSpecificSiteDataDialogController() { + if (!tracker_.view()) + return; // Dialog already destroyed. + + // Destroyed while the Widget is still alive, close immediately. + tracker_.view()->GetWidget()->CloseNow(); +} + +// static +views::View* PageSpecificSiteDataDialogController::GetDialogView( + content::WebContents* web_contents) { + PageSpecificSiteDataDialogController* handle = + static_cast<PageSpecificSiteDataDialogController*>( + web_contents->GetUserData( + PageSpecificSiteDataDialogController::UserDataKey())); + if (!handle) + return nullptr; + return handle->GetDialogView(); +} + +// static +CollectedCookiesViews* +PageSpecificSiteDataDialogController::GetDialogViewForTesting( + content::WebContents* web_contents) { + CHECK(!base::FeatureList::IsEnabled(page_info::kPageSpecificSiteDataDialog)); + return static_cast<CollectedCookiesViews*>( + PageSpecificSiteDataDialogController::GetDialogView(web_contents)); +} + +// static +void PageSpecificSiteDataDialogController::CreateAndShowForWebContents( + content::WebContents* web_contents) { + views::View* const instance = + PageSpecificSiteDataDialogController::GetDialogView(web_contents); + if (!instance) { + PageSpecificSiteDataDialogController::CreateForWebContents(web_contents); + return; + } + + // On rare occasions, |instance| may have started, but not finished, + // closing. In this case, the modal dialog manager will have removed the + // dialog from its list of tracked dialogs, and therefore might not have any + // active dialog. This should be rare enough that it's not worth trying to + // re-open the dialog. See https://crbug.com/989888 + if (instance->GetWidget()->IsClosed()) + return; + + auto* dialog_manager = + web_modal::WebContentsModalDialogManager::FromWebContents(web_contents); + CHECK(dialog_manager->IsDialogActive()); + dialog_manager->FocusTopmostDialog(); +} + +PageSpecificSiteDataDialogController::PageSpecificSiteDataDialogController( + content::WebContents* web_contents) + : content::WebContentsUserData<PageSpecificSiteDataDialogController>( + *web_contents) { + if (base::FeatureList::IsEnabled(page_info::kPageSpecificSiteDataDialog)) { + views::Widget* const widget = ShowPageSpecificSiteDataDialog(web_contents); + tracker_.SetView(widget->GetRootView()); + } else { + // CollectedCookiesViews is DialogDelegateView and it's owned by its + // widget. It created the widget in the constructor using + // `ShowWebModalDialogViews()`. It will be destroyed when its widget is + // destroyed. + CollectedCookiesViews* const dialog = + new CollectedCookiesViews(web_contents); + tracker_.SetView(dialog); + } +} + +views::View* PageSpecificSiteDataDialogController::GetDialogView() { + return tracker_.view(); +} + +WEB_CONTENTS_USER_DATA_KEY_IMPL(PageSpecificSiteDataDialogController);
diff --git a/chrome/browser/ui/views/site_data/page_specific_site_data_dialog_controller.h b/chrome/browser/ui/views/site_data/page_specific_site_data_dialog_controller.h new file mode 100644 index 0000000..a1673589 --- /dev/null +++ b/chrome/browser/ui/views/site_data/page_specific_site_data_dialog_controller.h
@@ -0,0 +1,54 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_VIEWS_SITE_DATA_PAGE_SPECIFIC_SITE_DATA_DIALOG_CONTROLLER_H_ +#define CHROME_BROWSER_UI_VIEWS_SITE_DATA_PAGE_SPECIFIC_SITE_DATA_DIALOG_CONTROLLER_H_ + +#include "content/public/browser/web_contents_observer.h" +#include "content/public/browser/web_contents_user_data.h" +#include "ui/views/view_tracker.h" + +namespace content { +class WebContents; +} // namespace content + +class CollectedCookiesViews; + +// The controller responsible for creating, showing and holding the reference to +// the page specific site data dialog. The actual dialog opened could be either +// PageSpecificSiteDataDialog or CollectedCookiesView, depending on +// `kPageSpecificSiteDataDialog` feature. The dialog is set as user data to the +// WebContents. The dialog represents the state of the site data of the +// WebContents. To display the dialog, invoke `ShowCollectedCookies()` on the +// `TabDialogs`. +class PageSpecificSiteDataDialogController + : public content::WebContentsUserData< + PageSpecificSiteDataDialogController> { + public: + ~PageSpecificSiteDataDialogController() override; + + // TODO(crbug.com/1344787): Don't use this method, it will be deprecated with + // the CollectedCookiesViews after kPageSpecificSiteDataDialog is finished. + static CollectedCookiesViews* GetDialogViewForTesting( + content::WebContents* web_contents); + + static void CreateAndShowForWebContents(content::WebContents* web_contents); + + private: + friend class content::WebContentsUserData< + PageSpecificSiteDataDialogController>; + + static views::View* GetDialogView(content::WebContents* web_contents); + + explicit PageSpecificSiteDataDialogController( + content::WebContents* web_contents); + + views::View* GetDialogView(); + + views::ViewTracker tracker_; + + WEB_CONTENTS_USER_DATA_KEY_DECL(); +}; + +#endif // CHROME_BROWSER_UI_VIEWS_SITE_DATA_PAGE_SPECIFIC_SITE_DATA_DIALOG_CONTROLLER_H_
diff --git a/chrome/browser/ui/views/tab_dialogs_views.cc b/chrome/browser/ui/views/tab_dialogs_views.cc index 6f520cc..2b62ef3 100644 --- a/chrome/browser/ui/views/tab_dialogs_views.cc +++ b/chrome/browser/ui/views/tab_dialogs_views.cc
@@ -9,9 +9,9 @@ #include "build/build_config.h" #include "chrome/browser/ui/sync/profile_signin_confirmation_helper.h" -#include "chrome/browser/ui/views/collected_cookies_views.h" #include "chrome/browser/ui/views/hung_renderer_view.h" #include "chrome/browser/ui/views/passwords/password_bubble_view_base.h" +#include "chrome/browser/ui/views/site_data/page_specific_site_data_dialog_controller.h" #include "content/public/browser/web_contents.h" #if defined(TOOLKIT_VIEWS) && !BUILDFLAG(IS_CHROMEOS) @@ -40,7 +40,8 @@ } void TabDialogsViews::ShowCollectedCookies() { - CollectedCookiesViews::CreateAndShowForWebContents(web_contents_); + PageSpecificSiteDataDialogController::CreateAndShowForWebContents( + web_contents_); } void TabDialogsViews::ShowHungRendererDialog(
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc index 32824fe..7f93fed8 100644 --- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc +++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -34,7 +34,6 @@ #include "chrome/browser/ui/webui/autofill_and_password_manager_internals/password_manager_internals_ui.h" #include "chrome/browser/ui/webui/bluetooth_internals/bluetooth_internals_ui.h" #include "chrome/browser/ui/webui/browsing_topics/browsing_topics_internals_ui.h" -#include "chrome/browser/ui/webui/chromeos/cloud_upload/cloud_upload_dialog.h" #include "chrome/browser/ui/webui/components/components_ui.h" #include "chrome/browser/ui/webui/constrained_web_dialog_ui.h" #include "chrome/browser/ui/webui/crashes_ui.h" @@ -254,6 +253,7 @@ #include "chrome/browser/ui/webui/chromeos/bluetooth_pairing_dialog.h" #include "chrome/browser/ui/webui/chromeos/cellular_setup/mobile_setup_ui.h" #include "chrome/browser/ui/webui/chromeos/certificate_manager_dialog_ui.h" +#include "chrome/browser/ui/webui/chromeos/cloud_upload/cloud_upload_ui.h" #include "chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_ui.h" #include "chrome/browser/ui/webui/chromeos/crostini_upgrader/crostini_upgrader_ui.h" #include "chrome/browser/ui/webui/chromeos/cryptohome_ui.h" @@ -956,7 +956,7 @@ if (!ash::features::IsUploadOfficeToCloudEnabled()) { return nullptr; } - return &NewWebUI<chromeos::cloud_upload::CloudUploadDialogUI>; + return &NewWebUI<chromeos::cloud_upload::CloudUploadUI>; } if (url.host_piece() == chrome::kChromeUIAccountManagerErrorHost) return &NewWebUI<chromeos::AccountManagerErrorUI>;
diff --git a/chrome/browser/ui/webui/chromeos/cloud_upload/BUILD.gn b/chrome/browser/ui/webui/chromeos/cloud_upload/BUILD.gn new file mode 100644 index 0000000..e2bd090 --- /dev/null +++ b/chrome/browser/ui/webui/chromeos/cloud_upload/BUILD.gn
@@ -0,0 +1,15 @@ +# Copyright 2022 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//build/config/chromeos/ui_mode.gni") +import("//mojo/public/tools/bindings/mojom.gni") + +assert(is_chromeos_ash, "The cloud upload dialog is ash-chrome only") + +mojom("mojo_bindings") { + sources = [ "cloud_upload.mojom" ] + + public_deps = [ "//mojo/public/mojom/base" ] + webui_module_path = "/" +}
diff --git a/chrome/browser/ui/webui/chromeos/cloud_upload/OWNERS b/chrome/browser/ui/webui/chromeos/cloud_upload/OWNERS index 73220a8..b5340c8 100644 --- a/chrome/browser/ui/webui/chromeos/cloud_upload/OWNERS +++ b/chrome/browser/ui/webui/chromeos/cloud_upload/OWNERS
@@ -1 +1,4 @@ file://ui/file_manager/OWNERS + +per-file *.mojom=set noparent +per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/chrome/browser/ui/webui/chromeos/cloud_upload/cloud_upload.mojom b/chrome/browser/ui/webui/chromeos/cloud_upload/cloud_upload.mojom new file mode 100644 index 0000000..ce1e4ec --- /dev/null +++ b/chrome/browser/ui/webui/chromeos/cloud_upload/cloud_upload.mojom
@@ -0,0 +1,21 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +module chromeos.cloud_upload.mojom; + +import "mojo/public/mojom/base/file_path.mojom"; + +// Lives in the browser process. A renderer uses this to create a page handler +// that enables communication between a renderer and the browser process. +interface PageHandlerFactory { + // Creates a page handler to enable communication with the browser process. + CreatePageHandler(pending_receiver<PageHandler> handler); +}; + +// Lives in the browser process. A renderer uses this to invoke methods that +// are implemented in the browser process. +interface PageHandler { + // Returns the path of the Office file to upload. + GetUploadPath() => (mojo_base.mojom.FilePath upload_path); +};
diff --git a/chrome/browser/ui/webui/chromeos/cloud_upload/cloud_upload_dialog.cc b/chrome/browser/ui/webui/chromeos/cloud_upload/cloud_upload_dialog.cc index 46d2eac..96cf4c1 100644 --- a/chrome/browser/ui/webui/chromeos/cloud_upload/cloud_upload_dialog.cc +++ b/chrome/browser/ui/webui/chromeos/cloud_upload/cloud_upload_dialog.cc
@@ -5,14 +5,7 @@ #include "chrome/browser/ui/webui/chromeos/cloud_upload/cloud_upload_dialog.h" #include "base/logging.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/webui/webui_util.h" #include "chrome/common/webui_url_constants.h" -#include "chrome/grit/cloud_upload_resources.h" -#include "chrome/grit/cloud_upload_resources_map.h" -#include "content/public/browser/web_ui.h" -#include "content/public/browser/web_ui_data_source.h" -#include "services/network/public/mojom/content_security_policy.mojom.h" namespace chromeos::cloud_upload { @@ -42,15 +35,4 @@ return false; } -CloudUploadDialogUI::CloudUploadDialogUI(content::WebUI* web_ui) - : ui::WebDialogUI(web_ui) { - content::WebUIDataSource* source = content::WebUIDataSource::CreateAndAdd( - Profile::FromWebUI(web_ui), chrome::kChromeUICloudUploadHost); - webui::SetupWebUIDataSource( - source, base::make_span(kCloudUploadResources, kCloudUploadResourcesSize), - IDR_CLOUD_UPLOAD_MAIN_HTML); -} - -CloudUploadDialogUI::~CloudUploadDialogUI() = default; - } // namespace chromeos::cloud_upload
diff --git a/chrome/browser/ui/webui/chromeos/cloud_upload/cloud_upload_dialog.h b/chrome/browser/ui/webui/chromeos/cloud_upload/cloud_upload_dialog.h index 34166cd..55aa2c9 100644 --- a/chrome/browser/ui/webui/chromeos/cloud_upload/cloud_upload_dialog.h +++ b/chrome/browser/ui/webui/chromeos/cloud_upload/cloud_upload_dialog.h
@@ -6,7 +6,6 @@ #define CHROME_BROWSER_UI_WEBUI_CHROMEOS_CLOUD_UPLOAD_CLOUD_UPLOAD_DIALOG_H_ #include "chrome/browser/ui/webui/chromeos/system_web_dialog_delegate.h" -#include "ui/web_dialogs/web_dialog_ui.h" namespace chromeos::cloud_upload { @@ -26,16 +25,6 @@ bool ShouldShowCloseButton() const override; }; -// The WebUI for chrome://cloud-upload-dialog, used for uploading files to the -// cloud. -class CloudUploadDialogUI : public ui::WebDialogUI { - public: - explicit CloudUploadDialogUI(content::WebUI* web_ui); - CloudUploadDialogUI(const CloudUploadDialogUI&) = delete; - CloudUploadDialogUI& operator=(const CloudUploadDialogUI&) = delete; - ~CloudUploadDialogUI() override; -}; - } // namespace chromeos::cloud_upload #endif // CHROME_BROWSER_UI_WEBUI_CHROMEOS_CLOUD_UPLOAD_CLOUD_UPLOAD_DIALOG_H_
diff --git a/chrome/browser/ui/webui/chromeos/cloud_upload/cloud_upload_page_handler.cc b/chrome/browser/ui/webui/chromeos/cloud_upload/cloud_upload_page_handler.cc new file mode 100644 index 0000000..ff3570f6 --- /dev/null +++ b/chrome/browser/ui/webui/chromeos/cloud_upload/cloud_upload_page_handler.cc
@@ -0,0 +1,22 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/webui/chromeos/cloud_upload/cloud_upload_page_handler.h" + +#include "base/files/file_path.h" + +namespace chromeos::cloud_upload { + +CloudUploadPageHandler::CloudUploadPageHandler( + mojo::PendingReceiver<chromeos::cloud_upload::mojom::PageHandler> + pending_page_handler) + : receiver_{this, std::move(pending_page_handler)} {} + +CloudUploadPageHandler::~CloudUploadPageHandler() = default; + +void CloudUploadPageHandler::GetUploadPath(GetUploadPathCallback callback) { + std::move(callback).Run(std::move(base::FilePath("/from Chromebook"))); +} + +} // namespace chromeos::cloud_upload
diff --git a/chrome/browser/ui/webui/chromeos/cloud_upload/cloud_upload_page_handler.h b/chrome/browser/ui/webui/chromeos/cloud_upload/cloud_upload_page_handler.h new file mode 100644 index 0000000..cdd43d30 --- /dev/null +++ b/chrome/browser/ui/webui/chromeos/cloud_upload/cloud_upload_page_handler.h
@@ -0,0 +1,43 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_WEBUI_CHROMEOS_CLOUD_UPLOAD_CLOUD_UPLOAD_PAGE_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_CLOUD_UPLOAD_CLOUD_UPLOAD_PAGE_HANDLER_H_ + +#include "base/callback.h" +#include "base/memory/weak_ptr.h" +#include "chrome/browser/ui/webui/chromeos/cloud_upload/cloud_upload.mojom.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" +#include "mojo/public/cpp/bindings/pending_remote.h" +#include "mojo/public/cpp/bindings/receiver.h" +#include "mojo/public/cpp/bindings/remote.h" + +namespace chromeos::cloud_upload { + +// Handles communication from the chrome://cloud-upload renderer process to +// the browser process exposing various methods for the JS to invoke. +class CloudUploadPageHandler + : public chromeos::cloud_upload::mojom::PageHandler { + public: + explicit CloudUploadPageHandler( + mojo::PendingReceiver<chromeos::cloud_upload::mojom::PageHandler> + pending_page_handler); + + CloudUploadPageHandler(const CloudUploadPageHandler&) = delete; + CloudUploadPageHandler& operator=(const CloudUploadPageHandler&) = delete; + + ~CloudUploadPageHandler() override; + + // chromeos::cloud_upload::mojom::PageHandler: + void GetUploadPath(GetUploadPathCallback callback) override; + + private: + mojo::Receiver<chromeos::cloud_upload::mojom::PageHandler> receiver_; + + base::WeakPtrFactory<CloudUploadPageHandler> weak_ptr_factory_{this}; +}; + +} // namespace chromeos::cloud_upload + +#endif // CHROME_BROWSER_UI_WEBUI_CHROMEOS_CLOUD_UPLOAD_CLOUD_UPLOAD_PAGE_HANDLER_H_
diff --git a/chrome/browser/ui/webui/chromeos/cloud_upload/cloud_upload_ui.cc b/chrome/browser/ui/webui/chromeos/cloud_upload/cloud_upload_ui.cc new file mode 100644 index 0000000..849507b --- /dev/null +++ b/chrome/browser/ui/webui/chromeos/cloud_upload/cloud_upload_ui.cc
@@ -0,0 +1,46 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/webui/chromeos/cloud_upload/cloud_upload_ui.h" + +#include "base/logging.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/webui/webui_util.h" +#include "chrome/common/webui_url_constants.h" +#include "chrome/grit/cloud_upload_resources.h" +#include "chrome/grit/cloud_upload_resources_map.h" +#include "content/public/browser/web_ui.h" +#include "content/public/browser/web_ui_data_source.h" + +namespace chromeos::cloud_upload { + +CloudUploadUI::CloudUploadUI(content::WebUI* web_ui) + : ui::MojoWebDialogUI{web_ui} { + content::WebUIDataSource* source = content::WebUIDataSource::CreateAndAdd( + Profile::FromWebUI(web_ui), chrome::kChromeUICloudUploadHost); + webui::SetupWebUIDataSource( + source, base::make_span(kCloudUploadResources, kCloudUploadResourcesSize), + IDR_CLOUD_UPLOAD_MAIN_HTML); +} + +CloudUploadUI::~CloudUploadUI() = default; + +void CloudUploadUI::BindInterface( + mojo::PendingReceiver<chromeos::cloud_upload::mojom::PageHandlerFactory> + pending_receiver) { + if (factory_receiver_.is_bound()) { + factory_receiver_.reset(); + } + factory_receiver_.Bind(std::move(pending_receiver)); +} + +void CloudUploadUI::CreatePageHandler( + mojo::PendingReceiver<chromeos::cloud_upload::mojom::PageHandler> + receiver) { + page_handler_ = std::make_unique<CloudUploadPageHandler>(std::move(receiver)); +} + +WEB_UI_CONTROLLER_TYPE_IMPL(CloudUploadUI); + +} // namespace chromeos::cloud_upload
diff --git a/chrome/browser/ui/webui/chromeos/cloud_upload/cloud_upload_ui.h b/chrome/browser/ui/webui/chromeos/cloud_upload/cloud_upload_ui.h new file mode 100644 index 0000000..0acdeb2 --- /dev/null +++ b/chrome/browser/ui/webui/chromeos/cloud_upload/cloud_upload_ui.h
@@ -0,0 +1,45 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_WEBUI_CHROMEOS_CLOUD_UPLOAD_CLOUD_UPLOAD_UI_H_ +#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_CLOUD_UPLOAD_CLOUD_UPLOAD_UI_H_ + +#include "chrome/browser/ui/webui/chromeos/cloud_upload/cloud_upload.mojom.h" +#include "chrome/browser/ui/webui/chromeos/cloud_upload/cloud_upload_page_handler.h" +#include "ui/web_dialogs/web_dialog_ui.h" + +namespace chromeos::cloud_upload { + +// The UI for chrome://cloud-upload, used for uploading files to the cloud. +class CloudUploadUI : public ui::MojoWebDialogUI, + public chromeos::cloud_upload::mojom::PageHandlerFactory { + public: + explicit CloudUploadUI(content::WebUI* web_ui); + CloudUploadUI(const CloudUploadUI&) = delete; + CloudUploadUI& operator=(const CloudUploadUI&) = delete; + + ~CloudUploadUI() override; + + // Instantiates implementor of the mojom::PageHandlerFactory + // mojo interface passing the pending receiver that will be internally bound. + void BindInterface( + mojo::PendingReceiver<chromeos::cloud_upload::mojom::PageHandlerFactory> + pending_receiver); + + // chromeos::cloud_upload::mojom::PageHandlerFactory: + void CreatePageHandler( + mojo::PendingReceiver<chromeos::cloud_upload::mojom::PageHandler> + pending_page_handler) override; + + private: + std::unique_ptr<CloudUploadPageHandler> page_handler_; + mojo::Receiver<chromeos::cloud_upload::mojom::PageHandlerFactory> + factory_receiver_{this}; + + WEB_UI_CONTROLLER_TYPE_DECL(); +}; + +} // namespace chromeos::cloud_upload + +#endif // CHROME_BROWSER_UI_WEBUI_CHROMEOS_CLOUD_UPLOAD_CLOUD_UPLOAD_UI_H_
diff --git a/chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.cc index 6ff7ce0..3f3a5277 100644 --- a/chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.cc
@@ -40,8 +40,6 @@ namespace chromeos { -constexpr StaticOobeScreenId AppLaunchSplashScreenView::kScreenId; - AppLaunchSplashScreenHandler::AppLaunchSplashScreenHandler( const scoped_refptr<NetworkStateInformer>& network_state_informer, ErrorScreen* error_screen) @@ -69,19 +67,7 @@ product_os_name)); } -void AppLaunchSplashScreenHandler::InitializeDeprecated() { - if (show_on_init_) { - show_on_init_ = false; - Show(); - } -} - void AppLaunchSplashScreenHandler::Show() { - if (!IsJavascriptAllowed()) { - show_on_init_ = true; - return; - } - is_shown_ = true; base::Value::Dict data; @@ -124,10 +110,7 @@ return; state_ = state; - if (IsJavascriptAllowed()) { - SetLaunchText( - l10n_util::GetStringUTF8(GetProgressMessageFromState(state_))); - } + SetLaunchText(l10n_util::GetStringUTF8(GetProgressMessageFromState(state_))); UpdateState(NetworkError::ERROR_REASON_UPDATE); } @@ -243,7 +226,7 @@ } void AppLaunchSplashScreenHandler::SetLaunchText(const std::string& text) { - CallJS("login.AppLaunchSplashScreen.updateMessage", text); + CallExternalAPI("updateMessage", text); } int AppLaunchSplashScreenHandler::GetProgressMessageFromState( @@ -285,7 +268,7 @@ } void AppLaunchSplashScreenHandler::DoToggleNetworkConfig(bool visible) { - CallJS("login.AppLaunchSplashScreen.toggleNetworkConfig", visible); + CallExternalAPI("toggleNetworkConfig", visible); } } // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.h index b9488b2..5455b25 100644 --- a/chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.h +++ b/chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.h
@@ -53,7 +53,8 @@ kShowingNetworkConfigureUI, }; - constexpr static StaticOobeScreenId kScreenId{"app-launch-splash"}; + inline constexpr static StaticOobeScreenId kScreenId{"app-launch-splash", + "AppLaunchSplashScreen"}; virtual ~AppLaunchSplashScreenView() {} @@ -106,7 +107,6 @@ // BaseScreenHandler implementation: void DeclareLocalizedValues( ::login::LocalizedValuesBuilder* builder) override; - void InitializeDeprecated() override; // WebUIMessageHandler implementation: void RegisterMessages() override; @@ -135,7 +135,6 @@ Delegate* delegate_ = nullptr; bool is_shown_ = false; - bool show_on_init_ = false; AppLaunchState state_ = AppLaunchState::kPreparingProfile; scoped_refptr<NetworkStateInformer> network_state_informer_;
diff --git a/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.cc index 63fb9ffa..2207e6d5 100644 --- a/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.cc
@@ -291,6 +291,7 @@ void AssistantOptInFlowScreenHandler::OnActivityControlOptInResult( bool opted_in) { Profile* profile = ProfileManager::GetActiveUserProfile(); + CHECK(!pending_consent_data_.empty()); auto data = pending_consent_data_.front(); pending_consent_data_.pop_front(); RecordActivityControlConsent(profile, data.ui_audit_key, opted_in, @@ -298,6 +299,7 @@ if (opted_in) { has_opted_in_any_consent_ = true; RecordAssistantActivityControlOptInStatus(data.setting_type, opted_in); + CHECK(assistant::AssistantSettings::Get()); assistant::AssistantSettings::Get()->UpdateSettings( GetSettingsUiUpdate(data.consent_token).SerializeAsString(), base::BindOnce( @@ -363,6 +365,7 @@ } assistant::SettingsUiSelector selector = GetSettingsUiSelector(); + CHECK(assistant::AssistantSettings::Get()); assistant::AssistantSettings::Get()->GetSettingsWithHeader( selector.SerializeAsString(), base::BindOnce(&AssistantOptInFlowScreenHandler::OnGetSettingsResponse, @@ -373,6 +376,7 @@ void AssistantOptInFlowScreenHandler::StopSpeakerIdEnrollment() { DCHECK(voice_match_enrollment_started_); voice_match_enrollment_started_ = false; + CHECK(assistant::AssistantSettings::Get()); assistant::AssistantSettings::Get()->StopSpeakerIdEnrollment(); // Reset the mojom receiver of |SpeakerIdEnrollmentClient|. ResetReceiver(); @@ -614,6 +618,7 @@ DCHECK(!voice_match_enrollment_started_); voice_match_enrollment_started_ = true; + CHECK(assistant::AssistantSettings::Get()); assistant::AssistantSettings::Get()->StartSpeakerIdEnrollment( flow_type_ == ash::FlowType::kSpeakerIdRetrain, weak_factory_.GetWeakPtr());
diff --git a/chrome/browser/ui/webui/chromeos/parent_access/parent_access_dialog.cc b/chrome/browser/ui/webui/chromeos/parent_access/parent_access_dialog.cc index d33cdc25..0f956488 100644 --- a/chrome/browser/ui/webui/chromeos/parent_access/parent_access_dialog.cc +++ b/chrome/browser/ui/webui/chromeos/parent_access/parent_access_dialog.cc
@@ -19,8 +19,8 @@ namespace { -constexpr int kDialogHeightDp = 512; -constexpr int kDialogWidthDp = 462; +constexpr int kDialogHeightDp = 526; +constexpr int kDialogWidthDp = 600; } // namespace
diff --git a/chrome/browser/ui/webui/policy/policy_ui_handler.cc b/chrome/browser/ui/webui/policy/policy_ui_handler.cc index 5a2a47d..be1c7de 100644 --- a/chrome/browser/ui/webui/policy/policy_ui_handler.cc +++ b/chrome/browser/ui/webui/policy/policy_ui_handler.cc
@@ -118,32 +118,9 @@ #endif #if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) -#include <windows.h> - -#include <DSRole.h> - -#include "chrome/browser/google/google_update_policy_fetcher_win.h" -#include "chrome/browser/policy/status_provider/updater_status_provider.h" -#include "chrome/install_static/install_util.h" -#include "content/public/browser/browser_task_traits.h" -#include "content/public/browser/browser_thread.h" +#include "chrome/browser/policy/status_provider/updater_status_and_value_provider.h" #endif // BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) -namespace { - -#if BUILDFLAG(ENABLE_EXTENSIONS) -// Appends the contents of `from_list` to end of `to_list`. Moves contents of -// `from_list` while appending. -void AppendList(base::Value::List& to_list, base::Value::List&& from_list) { - for (auto& value : from_list) { - to_list.Append(std::move(value)); - } - from_list.clear(); -} -#endif // BUILDFLAG(ENABLE_EXTENSIONS) - -} // namespace - PolicyUIHandler::PolicyUIHandler() = default; PolicyUIHandler::~PolicyUIHandler() { @@ -315,25 +292,27 @@ std::make_unique<DevicePolicyStatusProviderLacros>(); #endif // BUILDFLAG(IS_CHROMEOS_LACROS) -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - ReloadUpdaterPoliciesAndState(); -#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - if (!user_status_provider_.get()) user_status_provider_ = std::make_unique<policy::PolicyStatusProvider>(); if (!device_status_provider_.get()) device_status_provider_ = std::make_unique<policy::PolicyStatusProvider>(); if (!machine_status_provider_.get()) machine_status_provider_ = std::make_unique<policy::PolicyStatusProvider>(); - if (!updater_status_provider_.get()) - updater_status_provider_ = std::make_unique<policy::PolicyStatusProvider>(); auto update_callback(base::BindRepeating(&PolicyUIHandler::SendStatus, base::Unretained(this))); user_status_provider_->SetStatusChangeCallback(update_callback); device_status_provider_->SetStatusChangeCallback(update_callback); machine_status_provider_->SetStatusChangeCallback(update_callback); - updater_status_provider_->SetStatusChangeCallback(update_callback); + +#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) + updater_status_and_value_provider_ = + std::make_unique<UpdaterStatusAndValueProvider>( + Profile::FromWebUI(web_ui())); + policy_value_provider_observations_.AddObservation( + updater_status_and_value_provider_.get()); + updater_status_and_value_provider_->SetStatusChangeCallback(update_callback); +#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) pref_change_registrar_ = std::make_unique<PrefChangeRegistrar>(); pref_change_registrar_->Init(g_browser_process->local_state()); @@ -449,12 +428,7 @@ #endif // !BUILDFLAG(IS_CHROMEOS) #if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - if (updater_policies_) { - base::Value::Dict updater_policies; - updater_policies.Set("name", "Google Update Policies"); - updater_policies.Set("policyNames", GetGoogleUpdatePolicyNames()); - names.Set("updater", std::move(updater_policies)); - } + names.Merge(updater_status_and_value_provider_->GetNames()); #endif // BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) #if BUILDFLAG(ENABLE_EXTENSIONS) @@ -468,19 +442,6 @@ base::Value::List PolicyUIHandler::GetPolicyValues() { auto client = std::make_unique<policy::ChromePolicyConversionsClient>( web_ui()->GetWebContents()->GetBrowserContext()); - -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - if (updater_policies_) { - return policy::ArrayPolicyConversions(std::move(client)) - .EnableConvertValues(true) - .SetDropDefaultValues(true) - .WithUpdaterPolicies( - std::make_unique<policy::PolicyMap>(updater_policies_->Clone())) - .WithUpdaterPolicySchemas(GetGoogleUpdatePolicySchemas()) - .ToValueList(); - } -#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - auto policy_conversions = policy::ArrayPolicyConversions(std::move(client)); #if BUILDFLAG(IS_CHROMEOS_LACROS) @@ -495,10 +456,13 @@ .ToValueList(); #if BUILDFLAG(ENABLE_EXTENSIONS) - // Append the extension policy values. - AppendList(policy_values, extension_policies_value_provider_->GetValues()); + extension_policies_value_provider_->GetValues(policy_values); #endif // BUILDFLAG(ENABLE_EXTENSIONS) +#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) + updater_status_and_value_provider_->GetValues(policy_values); +#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) + return policy_values; } @@ -518,8 +482,6 @@ base::Value::Dict machine_status = machine_status_provider_->GetStatus(); - base::Value::Dict updater_status = updater_status_provider_->GetStatus(); - base::Value::Dict status; if (!device_status.empty()) { if (for_webui) @@ -539,11 +501,15 @@ status.Set("user", std::move(user_status)); } +#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) + base::Value::Dict updater_status = + updater_status_and_value_provider_->GetStatus(); if (!updater_status.empty()) { if (for_webui) updater_status.Set("boxLegendKey", "statusUpdater"); status.Set("updater", std::move(updater_status)); } +#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) return status; } @@ -629,7 +595,7 @@ #endif #if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - ReloadUpdaterPoliciesAndState(); + updater_status_and_value_provider_->Refresh(); #endif // BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) GetPolicyService(Profile::FromWebUI(web_ui())) @@ -689,31 +655,6 @@ base::Value(GetPolicyValues())); } -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) -void PolicyUIHandler::SetUpdaterPoliciesAndState( - std::unique_ptr<GoogleUpdatePoliciesAndState> updater_policies_and_state) { - updater_policies_ = std::move(updater_policies_and_state->policies); - static_cast<UpdaterStatusProvider*>(updater_status_provider_.get()) - ->SetUpdaterStatus(std::move(updater_policies_and_state->state)); - if (updater_policies_) - SendPolicies(); -} - -void PolicyUIHandler::ReloadUpdaterPoliciesAndState() { - if (!updater_status_provider_) - updater_status_provider_ = std::make_unique<UpdaterStatusProvider>(); - base::PostTaskAndReplyWithResult( - base::ThreadPool::CreateCOMSTATaskRunner( - {base::TaskPriority::USER_BLOCKING, - base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN, base::MayBlock()}) - .get(), - FROM_HERE, base::BindOnce(&GetGoogleUpdatePoliciesAndState), - base::BindOnce(&PolicyUIHandler::SetUpdaterPoliciesAndState, - weak_factory_.GetWeakPtr())); -} - -#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - void PolicyUIHandler::OnRefreshPoliciesDone() { SendPolicies(); SendStatus();
diff --git a/chrome/browser/ui/webui/policy/policy_ui_handler.h b/chrome/browser/ui/webui/policy/policy_ui_handler.h index bbb3dcc..540019ff 100644 --- a/chrome/browser/ui/webui/policy/policy_ui_handler.h +++ b/chrome/browser/ui/webui/policy/policy_ui_handler.h
@@ -33,8 +33,11 @@ #include "chrome/browser/policy/value_provider/extension_policies_value_provider.h" #endif +#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) +#include "chrome/browser/policy/status_provider/updater_status_and_value_provider.h" +#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) + class PrefChangeRegistrar; -struct GoogleUpdatePoliciesAndState; namespace policy { class PolicyMap; @@ -93,16 +96,6 @@ // metadata is sent. void SendPolicies(); -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - // Sets |updater_policies_| in this instance, updates - // |updater_status_provider_| with a new state and refreshes the UI via - // SendPolicies. - void SetUpdaterPoliciesAndState( - std::unique_ptr<GoogleUpdatePoliciesAndState> updater_policies_and_state); - - void ReloadUpdaterPoliciesAndState(); -#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - // Send the status of cloud policy to the UI. void SendStatus(); @@ -134,7 +127,6 @@ std::unique_ptr<policy::PolicyStatusProvider> user_status_provider_; std::unique_ptr<policy::PolicyStatusProvider> device_status_provider_; std::unique_ptr<policy::PolicyStatusProvider> machine_status_provider_; - std::unique_ptr<policy::PolicyStatusProvider> updater_status_provider_; #if BUILDFLAG(ENABLE_EXTENSIONS) std::unique_ptr<ExtensionPoliciesValueProvider> @@ -142,7 +134,8 @@ #endif // BUILDFLAG(ENABLE_EXTENSIONS) #if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - std::unique_ptr<policy::PolicyMap> updater_policies_; + std::unique_ptr<UpdaterStatusAndValueProvider> + updater_status_and_value_provider_; #endif // BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) #if BUILDFLAG(IS_CHROMEOS_LACROS)
diff --git a/chrome/browser/ui/webui/settings/site_settings_handler.cc b/chrome/browser/ui/webui/settings/site_settings_handler.cc index 9d428fd..b25a3af 100644 --- a/chrome/browser/ui/webui/settings/site_settings_handler.cc +++ b/chrome/browser/ui/webui/settings/site_settings_handler.cc
@@ -11,6 +11,7 @@ #include "base/barrier_closure.h" #include "base/bind.h" +#include "base/callback_helpers.h" #include "base/containers/contains.h" #include "base/containers/flat_set.h" #include "base/feature_list.h" @@ -29,6 +30,8 @@ #include "chrome/browser/hid/hid_chooser_context_factory.h" #include "chrome/browser/media/unified_autoplay_config.h" #include "chrome/browser/permissions/permission_decision_auto_blocker_factory.h" +#include "chrome/browser/privacy_sandbox/privacy_sandbox_service.h" +#include "chrome/browser/privacy_sandbox/privacy_sandbox_service_factory.h" #include "chrome/browser/serial/serial_chooser_context.h" #include "chrome/browser/serial/serial_chooser_context_factory.h" #include "chrome/browser/ui/browser.h" @@ -98,6 +101,7 @@ constexpr char kHasPermissionSettings[] = "hasPermissionSettings"; constexpr char kHasInstalledPWA[] = "hasInstalledPWA"; constexpr char kIsInstalled[] = "isInstalled"; +constexpr char kFpsOwner[] = "fpsOwner"; constexpr char kZoom[] = "zoom"; // Placeholder value for ETLD+1 until a valid origin is added. If an ETLD+1 // only has placeholder, then create an ETLD+1 origin. @@ -260,9 +264,9 @@ } // Converts |etld_plus1| into an origin representation by adding HTTP scheme. -std::string ConvertEtldToOrigin(const std::string etld_plus1) { - return std::string(url::kHttpScheme) + url::kStandardSchemeSeparator + - etld_plus1 + "/"; +std::string ConvertEtldToOrigin(const std::string etld_plus1, bool secure) { + return std::string(secure ? url::kHttpsScheme : url::kHttpScheme) + + url::kStandardSchemeSeparator + etld_plus1 + "/"; } // Converts a given |site_group_map| to a list of base::Value::Dicts, adding @@ -274,6 +278,9 @@ base::Value::List* list_value, Profile* profile) { DCHECK(profile); + auto* privacy_sandbox_service = + PrivacySandboxServiceFactory::GetForProfile(profile); + auto first_party_sets = privacy_sandbox_service->GetFirstPartySets(); base::flat_set<std::string> installed_origins = GetInstalledAppOrigins(profile); site_engagement::SiteEngagementService* engagement_service = @@ -290,8 +297,8 @@ base::Value::Dict origin_object; // If origin is placeholder, create a http ETLD+1 origin for it. if (origin == kPlaceholder) { - origin_object.Set("origin", - base::Value(ConvertEtldToOrigin(entry.first))); + origin_object.Set("origin", base::Value(ConvertEtldToOrigin( + entry.first, /*secure=*/false))); } else { origin_object.Set("origin", base::Value(origin)); } @@ -315,6 +322,14 @@ site_group.Set(kHasInstalledPWA, base::Value(has_installed_pwa)); site_group.Set(kNumCookies, base::Value(0)); site_group.Set(kOriginList, std::move(origin_list)); + if (first_party_sets.size()) { + auto site = net::SchemefulSite( + GURL(ConvertEtldToOrigin(entry.first, /*secure=*/true))); + + if (first_party_sets.count(site)) { + site_group.Set(kFpsOwner, (first_party_sets)[site].Serialize()); + } + } list_value->Append(std::move(site_group)); } } @@ -1768,7 +1783,7 @@ // eTLD+1 itself should be converted to an origin, the same as it would // have been for display. origin_is_partitioned.first == kPlaceholder - ? GURL(ConvertEtldToOrigin(etld_plus1)) + ? GURL(ConvertEtldToOrigin(etld_plus1, /*secure=*/false)) : GURL(origin_is_partitioned.first))); }
diff --git a/chrome/browser/ui/webui/settings/site_settings_handler.h b/chrome/browser/ui/webui/settings/site_settings_handler.h index 28f8cb7..bc367897 100644 --- a/chrome/browser/ui/webui/settings/site_settings_handler.h +++ b/chrome/browser/ui/webui/settings/site_settings_handler.h
@@ -138,6 +138,7 @@ IncludeWebUISchemesInGetOriginPermissions); FRIEND_TEST_ALL_PREFIXES(SiteSettingsHandlerTest, HandleGetUsageInfo); FRIEND_TEST_ALL_PREFIXES(SiteSettingsHandlerTest, NonTreeModelDeletion); + FRIEND_TEST_ALL_PREFIXES(SiteSettingsHandlerTest, FirstPartySetsMembership); // Creates the CookiesTreeModel if necessary. void EnsureCookiesTreeModelCreated();
diff --git a/chrome/browser/ui/webui/settings/site_settings_handler_unittest.cc b/chrome/browser/ui/webui/settings/site_settings_handler_unittest.cc index ac974d6..5775a96 100644 --- a/chrome/browser/ui/webui/settings/site_settings_handler_unittest.cc +++ b/chrome/browser/ui/webui/settings/site_settings_handler_unittest.cc
@@ -30,6 +30,8 @@ #include "chrome/browser/extensions/test_extension_system.h" #include "chrome/browser/history/history_service_factory.h" #include "chrome/browser/permissions/permission_decision_auto_blocker_factory.h" +#include "chrome/browser/privacy_sandbox/mock_privacy_sandbox_service.h" +#include "chrome/browser/privacy_sandbox/privacy_sandbox_service_factory.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/webui/settings/site_settings_helper.h" @@ -90,6 +92,8 @@ #include "chrome/browser/plugins/chrome_plugin_service_filter.h" #endif +using ::testing::Return; + namespace { constexpr char kCallbackId[] = "test-callback-id"; @@ -118,6 +122,34 @@ {{"http://127.0.0.1", "location"}, {true, ""}}, // Localhost is secure. {{"http://[::1]", "location"}, {true, ""}}}; +// Converts |etld_plus1| into an HTTPS SchemefulSite. +net::SchemefulSite ConvertEtldToSchemefulSite(const std::string etld_plus1) { + return net::SchemefulSite(GURL(std::string(url::kHttpsScheme) + + url::kStandardSchemeSeparator + etld_plus1 + + "/")); +} + +// Validates that the list of sites are aligned with the first party sets +// mapping. +void ValidateSitesWithFps( + const base::Value::List& storage_and_cookie_list, + base::flat_map<net::SchemefulSite, net::SchemefulSite>& first_party_sets) { + for (const base::Value& site_group : storage_and_cookie_list) { + std::string etld_plus1 = *site_group.GetDict().FindString("etldPlus1"); + auto schemeful_site = ConvertEtldToSchemefulSite(etld_plus1); + + if (first_party_sets.count(schemeful_site)) { + // Ensure that the `fpsOwner` is set correctly and aligned with + // |first_party_sets| mapping of site group owners. + ASSERT_EQ(first_party_sets[schemeful_site].Serialize(), + *site_group.GetDict().FindString("fpsOwner")); + } else { + // The site doesn't have `fpsOwner` set, `FindString` should return null. + ASSERT_FALSE(site_group.GetDict().FindString("fpsOwner")); + } + } +} + apps::AppPtr MakeApp(const std::string& app_id, apps::AppType app_type, const std::string& publisher_id, @@ -216,6 +248,9 @@ return mock_browsing_topics_service; })); + mock_privacy_sandbox_service_ = static_cast<MockPrivacySandboxService*>( + PrivacySandboxServiceFactory::GetInstance()->SetTestingFactoryAndUse( + profile(), base::BindRepeating(&BuildMockPrivacySandboxService))); handler_ = std::make_unique<SiteSettingsHandler>(profile_.get()); handler()->set_web_ui(web_ui()); handler()->AllowJavascript(); @@ -241,6 +276,9 @@ browsing_topics::MockBrowsingTopicsService* mock_browsing_topics_service() { return mock_browsing_topics_service_; } + MockPrivacySandboxService* mock_privacy_sandbox_service() { + return mock_privacy_sandbox_service_.get(); + } void ValidateBlockAutoplay(bool expected_value, bool expected_enabled) { const content::TestWebUI::CallData& data = *web_ui()->call_data().back(); @@ -595,6 +633,7 @@ #endif raw_ptr<browsing_topics::MockBrowsingTopicsService> mock_browsing_topics_service_; + raw_ptr<MockPrivacySandboxService> mock_privacy_sandbox_service_; }; // True if testing for handle clear unpartitioned usage with HTTPS scheme URL. @@ -2901,4 +2940,31 @@ browsing_data_remover->GetLastUsedOriginTypeMaskForTesting()); } +TEST_F(SiteSettingsHandlerTest, FirstPartySetsMembership) { + base::flat_map<net::SchemefulSite, net::SchemefulSite> first_party_sets = { + {ConvertEtldToSchemefulSite("google.com"), + ConvertEtldToSchemefulSite("google.com")}, + {ConvertEtldToSchemefulSite("google.com.au"), + ConvertEtldToSchemefulSite("google.com")}, + }; + EXPECT_CALL(*mock_privacy_sandbox_service(), GetFirstPartySets()) + .WillOnce(Return(first_party_sets)); + + SetUpCookiesTreeModel(); + + handler()->ClearAllSitesMapForTesting(); + + handler()->OnStorageFetched(); + const content::TestWebUI::CallData& data = *web_ui()->call_data().back(); + EXPECT_EQ("cr.webUIListenerCallback", data.function_name()); + + ASSERT_TRUE(data.arg1()->is_string()); + EXPECT_EQ("onStorageListFetched", data.arg1()->GetString()); + + ASSERT_TRUE(data.arg2()->is_list()); + const base::Value::List& storage_and_cookie_list = data.arg2()->GetList(); + EXPECT_EQ(4U, storage_and_cookie_list.size()); + + ValidateSitesWithFps(storage_and_cookie_list, first_party_sets); +} } // namespace settings
diff --git a/chrome/browser/updater/browser_updater_client_mac.mm b/chrome/browser/updater/browser_updater_client_mac.mm index 012a59d6..a00ead4 100644 --- a/chrome/browser/updater/browser_updater_client_mac.mm +++ b/chrome/browser/updater/browser_updater_client_mac.mm
@@ -123,7 +123,7 @@ // Checks for update of a given app, with specified priority. Sends repeated // updates of progress and returns the result in the reply block. -- (void)checkForUpdateWithAppID:(NSString* _Nonnull)appID +- (void)checkForUpdateWithAppId:(NSString* _Nonnull)appID installDataIndex:(NSString* _Nullable)installDataIndex priority:(CRUPriorityWrapper* _Nonnull)priority policySameVersionUpdate: @@ -138,7 +138,7 @@ }; [[_xpcConnection remoteObjectProxyWithErrorHandler:errorHandler] - checkForUpdateWithAppID:appID + checkForUpdateWithAppId:appID installDataIndex:installDataIndex priority:priority policySameVersionUpdate:policySameVersionUpdate @@ -171,6 +171,23 @@ NOTIMPLEMENTED(); } +- (void)cancelInstallsWithAppId:(NSString* _Nonnull)appId { + NOTIMPLEMENTED(); +} + +- (void)installWithAppId:(NSString* _Nonnull)appId + brandCode:(NSString* _Nullable)brandCode + brandPath:(NSString* _Nullable)brandPath + tag:(NSString* _Nullable)ap + version:(NSString* _Nullable)version + existenceCheckerPath:(NSString* _Nullable)existenceCheckerPath + installDataIndex:(NSString* _Nullable)installDataIndex + priority:(CRUPriorityWrapper* _Nonnull)priority + updateState:(CRUUpdateStateObserver* _Nonnull)updateState + reply:(void (^_Nonnull)(int rc))reply { + NOTIMPLEMENTED(); +} + @end BrowserUpdaterClientMac::BrowserUpdaterClientMac(updater::UpdaterScope scope) @@ -249,7 +266,7 @@ policySameVersionUpdateWrapper([[CRUPolicySameVersionUpdateWrapper alloc] initWithPolicySameVersionUpdate: updater::UpdateService::PolicySameVersionUpdate::kNotAllowed]); - [client_ checkForUpdateWithAppID:GetAppIdForUpdaterAsNSString() + [client_ checkForUpdateWithAppId:GetAppIdForUpdaterAsNSString() installDataIndex:nil priority:priority_wrapper.get() policySameVersionUpdate:policySameVersionUpdateWrapper.get()
diff --git a/chrome/browser/web_applications/test/app_registration_waiter.cc b/chrome/browser/web_applications/test/app_registration_waiter.cc index c24513e1..0538a324 100644 --- a/chrome/browser/web_applications/test/app_registration_waiter.cc +++ b/chrome/browser/web_applications/test/app_registration_waiter.cc
@@ -9,6 +9,35 @@ namespace web_app { +AppTypeInitializationWaiter::AppTypeInitializationWaiter(Profile* profile, + apps::AppType app_type) + : app_type_(app_type) { + apps::AppRegistryCache& cache = + apps::AppServiceProxyFactory::GetForProfile(profile)->AppRegistryCache(); + Observe(&cache); + + if (cache.IsAppTypeInitialized(app_type)) + run_loop_.Quit(); +} + +AppTypeInitializationWaiter::~AppTypeInitializationWaiter() = default; + +void AppTypeInitializationWaiter::Await() { + run_loop_.Run(); +} + +void AppTypeInitializationWaiter::OnAppUpdate(const apps::AppUpdate& update) {} + +void AppTypeInitializationWaiter::OnAppTypeInitialized(apps::AppType app_type) { + if (app_type == app_type_) + run_loop_.Quit(); +} + +void AppTypeInitializationWaiter::OnAppRegistryCacheWillBeDestroyed( + apps::AppRegistryCache* cache) { + Observe(nullptr); +} + AppRegistrationWaiter::AppRegistrationWaiter(Profile* profile, const AppId& app_id, apps::Readiness readiness)
diff --git a/chrome/browser/web_applications/test/app_registration_waiter.h b/chrome/browser/web_applications/test/app_registration_waiter.h index 6a323e2..45b8ee1 100644 --- a/chrome/browser/web_applications/test/app_registration_waiter.h +++ b/chrome/browser/web_applications/test/app_registration_waiter.h
@@ -15,6 +15,24 @@ namespace web_app { +class AppTypeInitializationWaiter : public apps::AppRegistryCache::Observer { + public: + AppTypeInitializationWaiter(Profile* profile, apps::AppType app_type); + ~AppTypeInitializationWaiter() override; + + void Await(); + + private: + // apps::AppRegistryCache::Observer: + void OnAppUpdate(const apps::AppUpdate& update) override; + void OnAppTypeInitialized(apps::AppType app_type) override; + void OnAppRegistryCacheWillBeDestroyed( + apps::AppRegistryCache* cache) override; + + const apps::AppType app_type_; + base::RunLoop run_loop_; +}; + class AppRegistrationWaiter : public apps::AppRegistryCache::Observer { public: AppRegistrationWaiter(Profile* profile,
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt index d52f3f7e..5ebb7da 100644 --- a/chrome/build/linux.pgo.txt +++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@ -chrome-linux-main-1659657524-31c5f752f6d78a154deadd06609947156c1aa345.profdata +chrome-linux-main-1659700777-361cef41c1f44884c13c26d36cca9eebf56d383f.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt index 5beae8f..fcb7a334 100644 --- a/chrome/build/mac-arm.pgo.txt +++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@ -chrome-mac-arm-main-1659657524-a20cbea04da22de92830cfbc9103276d18442ac8.profdata +chrome-mac-arm-main-1659700777-66a81eb1018978ad01f392e7f74c2d6422b49959.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt index 7d99a6c..db19cb1e 100644 --- a/chrome/build/mac.pgo.txt +++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@ -chrome-mac-main-1659657524-999b9a65f836a3d348d35b76c773b8794103162f.profdata +chrome-mac-main-1659700777-bba15ab02f33e2a968bb402628bbb0a670470628.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index 729def50..ffeb403 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-main-1659657524-2aa4df9ef1199c79b4f74de79a15d8e0ba9a3785.profdata +chrome-win32-main-1659689676-10e03a9b000649c4006ac166aef65fac8b441d4f.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index c6b72e8..f973f22c 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-main-1659657524-1291c3284e82fe5148712ad31983ff4757be63f0.profdata +chrome-win64-main-1659689676-fb2b7f31eca336c4919d32e839cd340e83a995de.profdata
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc index f84d6cc..690736a 100644 --- a/chrome/common/chrome_features.cc +++ b/chrome/common/chrome_features.cc
@@ -296,6 +296,12 @@ "KeepForceInstalledPreinstalledApps", base::FEATURE_DISABLED_BY_DEFAULT}; #endif +// Enables notification permission revocation for origins that may send +// disruptive notifications. +const base::Feature kDisruptiveNotificationPermissionRevocation{ + "DisruptiveNotificationPermissionRevocation", + base::FEATURE_DISABLED_BY_DEFAULT}; + // Enable DNS over HTTPS (DoH). const base::Feature kDnsOverHttps { "DnsOverHttps",
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h index 38f02a54..01f228e 100644 --- a/chrome/common/chrome_features.h +++ b/chrome/common/chrome_features.h
@@ -215,6 +215,9 @@ #endif COMPONENT_EXPORT(CHROME_FEATURES) +extern const base::Feature kDisruptiveNotificationPermissionRevocation; + +COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kDnsOverHttps; COMPONENT_EXPORT(CHROME_FEATURES) extern const base::FeatureParam<bool> kDnsOverHttpsFallbackParam;
diff --git a/chrome/common/extensions/api/input_method_private.json b/chrome/common/extensions/api/input_method_private.json index 370fdab..029f2f19 100644 --- a/chrome/common/extensions/api/input_method_private.json +++ b/chrome/common/extensions/api/input_method_private.json
@@ -93,6 +93,7 @@ "enableSoundOnKeypress": { "type": "boolean", "optional": true, "description": "Whether to enable sound on keypress."}, "physicalKeyboardAutoCorrectionLevel": { "type": "integer", "optional": true, "description": "The level of auto correction for physical keyboard (0: Off, 1: Modest, 2: Aggressive)."}, "physicalKeyboardEnableCapitalization": { "type": "boolean", "optional": true, "description": "Whether to enable auto capitalization for physical keyboard."}, + "physicalKeyboardEnableDiacriticsOnLongpress": { "type": "boolean", "optional": true, "description": "Whether to enable diacritics on longpress for physical keyboard."}, "virtualKeyboardAutoCorrectionLevel": { "type": "integer", "optional": true, "description": "The level of auto correction for virtual keyboard (0: Off, 1: Modest, 2: Aggressive)."}, "virtualKeyboardEnableCapitalization": { "type": "boolean", "optional": true, "description": "Whether enable auto capitalization for virtual keyboard."}, "xkbLayout": { "type": "string", "optional": true, "description": "The xkb keyboard (system provided keyboard) layout."},
diff --git a/chrome/common/webui_url_constants.cc b/chrome/common/webui_url_constants.cc index ea0a0f8..ac923e85 100644 --- a/chrome/common/webui_url_constants.cc +++ b/chrome/common/webui_url_constants.cc
@@ -300,8 +300,8 @@ const char kChromeUICertificateManagerDialogURL[] = "chrome://certificate-manager/"; const char kChromeUICertificateManagerHost[] = "certificate-manager"; -const char kChromeUICloudUploadHost[] = "cloud-upload-dialog"; -const char kChromeUICloudUploadURL[] = "chrome://cloud-upload-dialog/"; +const char kChromeUICloudUploadHost[] = "cloud-upload"; +const char kChromeUICloudUploadURL[] = "chrome://cloud-upload/"; const char kChromeUIConfirmPasswordChangeHost[] = "confirm-password-change"; const char kChromeUIConfirmPasswordChangeUrl[] = "chrome://confirm-password-change";
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index cd602ff..e247f630 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -3114,6 +3114,7 @@ "//chrome/browser/enterprise/connectors/device_trust/common", "//chrome/browser/enterprise/connectors/device_trust/key_management/browser/commands:test_support", "//chrome/browser/enterprise/connectors/device_trust/key_management/core/persistence:test_support", + "//components/device_signals/core/common", "//components/device_signals/core/common:features", ] } @@ -5285,7 +5286,6 @@ "../browser/performance_manager/test_support/page_aggregator.cc", "../browser/performance_manager/test_support/page_aggregator.h", "../browser/performance_monitor/system_monitor_unittest.cc", - "../browser/permissions/abusive_origin_permission_revocation_request_unittests.cc", "../browser/permissions/adaptive_quiet_notification_permission_ui_enabler_unittest.cc", "../browser/permissions/chrome_permission_manager_unittest.cc", "../browser/permissions/chrome_permission_request_manager_unittest.cc", @@ -5294,6 +5294,7 @@ "../browser/permissions/crowd_deny_safe_browsing_request_unittest.cc", "../browser/permissions/notifications_engagement_service_unittest.cc", "../browser/permissions/permission_context_base_permissions_policy_unittest.cc", + "../browser/permissions/permission_revocation_request_unittests.cc", "../browser/permissions/prediction_based_permission_ui_selector_unittest.cc", "../browser/permissions/pref_notification_permission_ui_selector_unittest.cc", "../browser/persisted_state_db/session_proto_db_factory_unittest.cc", @@ -7195,6 +7196,7 @@ "../browser/ui/app_list/search/keyboard_shortcut_result_unittest.cc", "../browser/ui/app_list/search/mixer_unittest.cc", "../browser/ui/app_list/search/omnibox_answer_result_unittest.cc", + "../browser/ui/app_list/search/omnibox_lacros_provider_unittest.cc", "../browser/ui/app_list/search/omnibox_result_unittest.cc", "../browser/ui/app_list/search/open_tab_result_unittest.cc", "../browser/ui/app_list/search/ranking/answer_ranker_unittest.cc", @@ -7582,6 +7584,10 @@ sources += [ "../browser/spellchecker/spelling_service_client_unittest.cc" ] } + + if (use_browser_spellchecker && enable_spelling_service) { + sources += [ "../browser/spellchecker/spelling_request_unittest.cc" ] + } } # TODO(crbug.com/1229899): Clean up and move this to a separate target.
diff --git a/chrome/updater/test/integration_tests.cc b/chrome/updater/test/integration_tests.cc index 20bb2ea2..1f5dd09 100644 --- a/chrome/updater/test/integration_tests.cc +++ b/chrome/updater/test/integration_tests.cc
@@ -345,11 +345,7 @@ Uninstall(); } -#if BUILDFLAG(IS_MAC) TEST_F(IntegrationTest, OverinstallWorking) { -#else -TEST_F(IntegrationTest, DISABLED_OverinstallWorking) { -#endif SetupRealUpdaterLowerVersion(); WaitForUpdaterExit(); ExpectVersionNotActive(kUpdaterVersion); @@ -363,12 +359,7 @@ Uninstall(); } -// TODO(https://crbug.com/1344846): Flaky on Mac. -#if BUILDFLAG(IS_MAC) -TEST_F(IntegrationTest, DISABLED_OverinstallBroken) { -#else -TEST_F(IntegrationTest, DISABLED_OverinstallBroken) { -#endif +TEST_F(IntegrationTest, OverinstallBroken) { SetupRealUpdaterLowerVersion(); WaitForUpdaterExit(); DeleteUpdaterDirectory(); @@ -722,11 +713,7 @@ #if BUILDFLAG(CHROMIUM_BRANDING) || BUILDFLAG(GOOGLE_CHROME_BRANDING) #if !defined(COMPONENT_BUILD) -#if BUILDFLAG(IS_MAC) TEST_F(IntegrationTest, SelfUpdateFromOldReal) { -#else -TEST_F(IntegrationTest, DISABLED_SelfUpdateFromOldReal) { -#endif ScopedServer test_server(test_commands_); SetupRealUpdaterLowerVersion();
diff --git a/chromeos/components/mojo_service_manager/fake_mojo_service_manager.cc b/chromeos/components/mojo_service_manager/fake_mojo_service_manager.cc index e3ad3cc2..e62ae071 100644 --- a/chromeos/components/mojo_service_manager/fake_mojo_service_manager.cc +++ b/chromeos/components/mojo_service_manager/fake_mojo_service_manager.cc
@@ -4,39 +4,135 @@ #include "chromeos/components/mojo_service_manager/fake_mojo_service_manager.h" -#include "base/notreached.h" +#include <utility> + +#include "base/check.h" namespace chromeos::mojo_service_manager { -FakeMojoServiceManager::FakeMojoServiceManager() : receiver_(this) {} +FakeMojoServiceManager::ServiceState::ServiceState() = default; -FakeMojoServiceManager::~FakeMojoServiceManager() {} +FakeMojoServiceManager::ServiceState::~ServiceState() = default; + +FakeMojoServiceManager::FakeMojoServiceManager() = default; + +FakeMojoServiceManager::~FakeMojoServiceManager() = default; mojo::PendingRemote<mojom::ServiceManager> -FakeMojoServiceManager::BindNewPipeAndPassRemote() { - return receiver_.BindNewPipeAndPassRemote(); +FakeMojoServiceManager::AddNewPipeAndPassRemote( + const std::string& security_context) { + mojo::PendingRemote<mojom::ServiceManager> remote; + receiver_set_.Add(this, remote.InitWithNewPipeAndPassReceiver(), + mojom::ProcessIdentity::New(security_context, 0, 0, 0)); + return remote; } void FakeMojoServiceManager::Register( const std::string& service_name, mojo::PendingRemote<mojom::ServiceProvider> service_provider) { - NOTIMPLEMENTED(); + auto it = service_map_.find(service_name); + if (it == service_map_.end()) { + auto [it_new, success] = service_map_.try_emplace(service_name); + CHECK(success); + it = it_new; + } + + ServiceState& service_state = it->second; + if (service_state.service_provider.is_bound()) { + service_provider.ResetWithReason( + static_cast<uint32_t>(mojom::ErrorCode::kServiceAlreadyRegistered), + "The service: " + service_name + " has already been registered."); + return; + } + service_state.service_provider.Bind(std::move(service_provider)); + service_state.service_provider.set_disconnect_handler( + base::BindOnce(&FakeMojoServiceManager::ServiceProviderDisconnectHandler, + base::Unretained(this), service_name)); + + const mojom::ProcessIdentityPtr& identity = receiver_set_.current_context(); + service_state.owner = identity.Clone(); + SendServiceEvent(mojom::ServiceEvent::New( + mojom::ServiceEvent::Type::kRegistered, service_name, identity.Clone())); + + auto pending_requests = std::move(service_state.pending_requests); + for (auto& [requester, receiver] : pending_requests) { + // If a receiver become invalid before being posted, don't send it because + // the mojo will complain about sending invalid handles and reset the + // connection of service provider. + if (!receiver.is_valid()) + continue; + service_state.service_provider->Request(std::move(requester), + std::move(receiver)); + } } -void FakeMojoServiceManager::Request(const std::string& service_name, - absl::optional<base::TimeDelta> timeout, - mojo::ScopedMessagePipeHandle receiver) { - NOTIMPLEMENTED(); +void FakeMojoServiceManager::Request( + const std::string& service_name, + absl::optional<base::TimeDelta> /*timeout*/, + mojo::ScopedMessagePipeHandle receiver) { + auto it = service_map_.find(service_name); + if (it == service_map_.end()) { + auto [it_new, success] = service_map_.try_emplace(service_name); + CHECK(success); + it = it_new; + } + + ServiceState& service_state = it->second; + const mojom::ProcessIdentityPtr& identity = receiver_set_.current_context(); + if (service_state.service_provider.is_bound()) { + service_state.service_provider->Request(identity.Clone(), + std::move(receiver)); + return; + } + service_state.pending_requests.emplace_back(identity.Clone(), + std::move(receiver)); } void FakeMojoServiceManager::Query(const std::string& service_name, QueryCallback callback) { - NOTIMPLEMENTED(); + auto it = service_map_.find(service_name); + if (it == service_map_.end()) { + std::move(callback).Run(mojom::ErrorOrServiceState::NewError( + mojom::Error::New(mojom::ErrorCode::kServiceNotFound, + "Cannot find service: " + service_name))); + return; + } + + const ServiceState& service_state = it->second; + mojom::ServiceStatePtr state = + service_state.service_provider.is_bound() + ? mojom::ServiceState::NewRegisteredState( + mojom::RegisteredServiceState::New( + /*owner=*/service_state.owner.Clone())) + : mojom::ServiceState::NewUnregisteredState( + mojom::UnregisteredServiceState::New()); + std::move(callback).Run( + mojom::ErrorOrServiceState::NewState(std::move(state))); } void FakeMojoServiceManager::AddServiceObserver( mojo::PendingRemote<mojom::ServiceObserver> observer) { - NOTIMPLEMENTED(); + service_observers_.Add(std::move(observer)); +} + +void FakeMojoServiceManager::ServiceProviderDisconnectHandler( + const std::string& service_name) { + auto it = service_map_.find(service_name); + CHECK(it != service_map_.end()); + ServiceState& service_state = it->second; + service_state.service_provider.reset(); + mojom::ProcessIdentityPtr dispatcher; + dispatcher.Swap(&service_state.owner); + SendServiceEvent( + mojom::ServiceEvent::New(mojom::ServiceEvent::Type::kUnRegistered, + service_name, std::move(dispatcher))); +} + +void FakeMojoServiceManager::SendServiceEvent(mojom::ServiceEventPtr event) { + for (const mojo::Remote<mojom::ServiceObserver>& remote : + service_observers_) { + remote->OnServiceEvent(event.Clone()); + } } } // namespace chromeos::mojo_service_manager
diff --git a/chromeos/components/mojo_service_manager/fake_mojo_service_manager.h b/chromeos/components/mojo_service_manager/fake_mojo_service_manager.h index d7a1841..df35a36 100644 --- a/chromeos/components/mojo_service_manager/fake_mojo_service_manager.h +++ b/chromeos/components/mojo_service_manager/fake_mojo_service_manager.h
@@ -5,14 +5,29 @@ #ifndef CHROMEOS_COMPONENTS_MOJO_SERVICE_MANAGER_FAKE_MOJO_SERVICE_MANAGER_H_ #define CHROMEOS_COMPONENTS_MOJO_SERVICE_MANAGER_FAKE_MOJO_SERVICE_MANAGER_H_ +#include <string> +#include <vector> + #include "base/component_export.h" #include "chromeos/components/mojo_service_manager/mojom/mojo_service_manager.mojom.h" +#include "mojo/public/cpp/bindings/receiver_set.h" #include "mojo/public/cpp/bindings/remote.h" +#include "mojo/public/cpp/bindings/remote_set.h" namespace chromeos::mojo_service_manager { -// Provides fake implementation of the service manager for testing. This sets -// a fake mojo remote to the |Connection|. +// Provides fake implementation of the service manager for testing. +// +// The behaviors are different from the real service: +// * No permission checking. A fake identity can be set when binding the mojo +// remote. It will be used as the identity of owner or requester. +// * Register always succeeds, except that the services has already been +// registered. +// * Request always succeeds. Timeout is ignored (always wait forever). +// * Query returns "not found" if the service is not yet registered / requested, +// otherwise returns the state of the service. +// * The ServiceObserver can receive all the event (no permission checking). +// class COMPONENT_EXPORT(CHROMEOS_MOJO_SERVICE_MANAGER) FakeMojoServiceManager : public mojom::ServiceManager { public: @@ -21,10 +36,27 @@ FakeMojoServiceManager& operator=(FakeMojoServiceManager&) = delete; ~FakeMojoServiceManager() override; - // Binds a new pipe and pass the pending remote. - mojo::PendingRemote<mojom::ServiceManager> BindNewPipeAndPassRemote(); + // Adds a new pipe and pass the pending remote. The identity of remote will + // be bound to |security_context|. + mojo::PendingRemote<mojom::ServiceManager> AddNewPipeAndPassRemote( + const std::string& security_context); private: + // Keeps all the objects related to a mojo service. + struct ServiceState { + ServiceState(); + ~ServiceState(); + + // The pending requests to be sent after the service is available. + std::vector< + std::pair<mojom::ProcessIdentityPtr, mojo::ScopedMessagePipeHandle>> + pending_requests; + // The owner of the service. + mojom::ProcessIdentityPtr owner; + // The mojo remote to the service provider. + mojo::Remote<mojom::ServiceProvider> service_provider; + }; + // mojom::ServiceManager overrides. void Register( const std::string& service_name, @@ -36,8 +68,19 @@ void AddServiceObserver( mojo::PendingRemote<mojom::ServiceObserver> observer) override; - // The receiver object to provide the fake service manager. - mojo::Receiver<mojom::ServiceManager> receiver_; + // Handles disconnection from service providers. + void ServiceProviderDisconnectHandler(const std::string& service_name); + + // Sends service event to all the observers. + void SendServiceEvent(mojom::ServiceEventPtr event); + + // The receiver set to provide the fake service manager. + mojo::ReceiverSet<mojom::ServiceManager, mojom::ProcessIdentityPtr> + receiver_set_; + // The map of the service name to the service state. + std::map<std::string, ServiceState> service_map_; + // The remote set for the service observer. + mojo::RemoteSet<mojom::ServiceObserver> service_observers_; }; } // namespace chromeos::mojo_service_manager
diff --git a/chromeos/crosapi/mojom/launcher_search.mojom b/chromeos/crosapi/mojom/launcher_search.mojom index fe24121..70fb420 100644 --- a/chromeos/crosapi/mojom/launcher_search.mojom +++ b/chromeos/crosapi/mojom/launcher_search.mojom
@@ -75,7 +75,9 @@ // The page transition type of this result. Used for opening a result. [MinVersion=2] PageTransition page_transition@15; - // The image url of the result, if any. Used to download the result image. + // The image url of the result, if any. Used to download the result image. The + // presence of this field defines a result as a "rich entity". We consider + // weather answer results with icons as a special kind of rich entity. url.mojom.Url? image_url@7; // Favicon of the result, if available. The presence or absence of this field // is what defines a result as a "favicon-type result". @@ -115,7 +117,7 @@ [Stable, Extensible] enum OmniboxType { [Default] kUnset = 0, - kRichImage = 1, + kRichImageDeprecated = 1, kFaviconDeprecated = 2, kBookmark = 3, kDomain = 4,
diff --git a/chromeos/tast_control.gni b/chromeos/tast_control.gni index 086baf86..3b55306 100644 --- a/chromeos/tast_control.gni +++ b/chromeos/tast_control.gni
@@ -246,6 +246,9 @@ # b/241122961 "policy.BlockThirdPartyCookies", + + # https://crbug.com/1350180 + "printer.Print", ] # To create filters to be used on specific builders add them like this:
diff --git a/components/autofill_assistant/browser/headless/client_headless.cc b/components/autofill_assistant/browser/headless/client_headless.cc index 3f65bce..3cc3cb1 100644 --- a/components/autofill_assistant/browser/headless/client_headless.cc +++ b/components/autofill_assistant/browser/headless/client_headless.cc
@@ -17,7 +17,6 @@ #include "components/autofill_assistant/browser/controller.h" #include "components/autofill_assistant/browser/display_strings_util.h" #include "components/autofill_assistant/browser/features.h" -#include "components/autofill_assistant/browser/headless/headless_script_controller_impl.h" #include "components/autofill_assistant/browser/public/password_change/empty_website_login_manager_impl.h" #include "components/autofill_assistant/browser/public/password_change/website_login_manager.h" #include "components/autofill_assistant/browser/public/password_change/website_login_manager_impl.h" @@ -46,20 +45,26 @@ content::WebContents* web_contents, const CommonDependencies* common_dependencies, ExternalActionDelegate* action_extension_delegate, - WebsiteLoginManager* website_login_manager, - HeadlessScriptControllerImpl* external_script_controller) + WebsiteLoginManager* website_login_manager) : web_contents_(web_contents), common_dependencies_(common_dependencies), - website_login_manager_(website_login_manager), - external_script_controller_(external_script_controller) { + website_login_manager_(website_login_manager) { headless_ui_controller_ = std::make_unique<HeadlessUiController>(action_extension_delegate); } ClientHeadless::~ClientHeadless() = default; -void ClientHeadless::Start(const GURL& url, - std::unique_ptr<TriggerContext> trigger_context) { +void ClientHeadless::Start( + const GURL& url, + std::unique_ptr<TriggerContext> trigger_context, + base::OnceCallback<void(Metrics::DropOutReason reason)> + script_ended_callback) { + // Ignore the call if a script is already running. + if (script_ended_callback_) { + return; + } + script_ended_callback_ = std::move(script_ended_callback); controller_ = std::make_unique<Controller>( web_contents_, /* client= */ this, base::DefaultTickClock::GetInstance(), RuntimeManager::GetForWebContents(web_contents_)->GetWeakPtr(), @@ -182,7 +187,9 @@ } void ClientHeadless::NotifyScriptEnded(Metrics::DropOutReason reason) { - external_script_controller_->NotifyScriptEnded(reason); + if (script_ended_callback_) { + std::move(script_ended_callback_).Run(reason); + } // This instance can be destroyed by the above call, so nothing should be // added here.
diff --git a/components/autofill_assistant/browser/headless/client_headless.h b/components/autofill_assistant/browser/headless/client_headless.h index 815b51a0d..b1b0c6f 100644 --- a/components/autofill_assistant/browser/headless/client_headless.h +++ b/components/autofill_assistant/browser/headless/client_headless.h
@@ -27,25 +27,25 @@ namespace autofill_assistant { -class HeadlessScriptControllerImpl; class WebsiteLoginManager; // An Autofill Assistant client for headless runs. class ClientHeadless : public Client, public AccessTokenFetcher { public: - explicit ClientHeadless( - content::WebContents* web_contents, - const CommonDependencies* common_dependencies, - ExternalActionDelegate* action_extension_delegate, - WebsiteLoginManager* website_login_manager, - HeadlessScriptControllerImpl* external_script_controller); + explicit ClientHeadless(content::WebContents* web_contents, + const CommonDependencies* common_dependencies, + ExternalActionDelegate* action_extension_delegate, + WebsiteLoginManager* website_login_manager); ClientHeadless(const ClientHeadless&) = delete; ClientHeadless& operator=(const ClientHeadless&) = delete; ~ClientHeadless() override; bool IsRunning() const; - void Start(const GURL& url, std::unique_ptr<TriggerContext> trigger_context); + void Start(const GURL& url, + std::unique_ptr<TriggerContext> trigger_context, + base::OnceCallback<void(Metrics::DropOutReason reason)> + script_ended_callback); // Overrides Client void AttachUI() override; @@ -100,7 +100,10 @@ std::unique_ptr<signin::AccessTokenFetcher> access_token_fetcher_; base::OnceCallback<void(bool, const std::string&)> fetch_access_token_callback_; - const raw_ptr<HeadlessScriptControllerImpl> external_script_controller_; + + // Only set while a script is running. + base::OnceCallback<void(Metrics::DropOutReason reason)> + script_ended_callback_; base::WeakPtrFactory<ClientHeadless> weak_ptr_factory_{this}; };
diff --git a/components/autofill_assistant/browser/headless/headless_script_controller_impl.cc b/components/autofill_assistant/browser/headless/headless_script_controller_impl.cc index fa58c56..5187218 100644 --- a/components/autofill_assistant/browser/headless/headless_script_controller_impl.cc +++ b/components/autofill_assistant/browser/headless/headless_script_controller_impl.cc
@@ -23,7 +23,7 @@ if (starter) { client_ = std::make_unique<ClientHeadless>( web_contents, starter->GetCommonDependencies(), - action_extension_delegate, website_login_manager, this); + action_extension_delegate, website_login_manager); } } @@ -88,7 +88,10 @@ // TODO(b/201964911): At this point we should be sure no other Controller // exists on this tab. Add logic to the starter to check that's the case. - client_->Start(*url, std::move(trigger_context)); + client_->Start( + *url, std::move(trigger_context), + base::BindOnce(&HeadlessScriptControllerImpl::NotifyScriptEnded, + weak_ptr_factory_.GetWeakPtr())); } void HeadlessScriptControllerImpl::NotifyScriptEnded(
diff --git a/components/autofill_assistant/browser/headless/headless_script_controller_impl.h b/components/autofill_assistant/browser/headless/headless_script_controller_impl.h index 87ff55b8..55b8ffb2 100644 --- a/components/autofill_assistant/browser/headless/headless_script_controller_impl.h +++ b/components/autofill_assistant/browser/headless/headless_script_controller_impl.h
@@ -46,15 +46,16 @@ bool use_autofill_assistant_onboarding, base::OnceCallback<void()> onboarding_successful_callback) override; + private: + void OnReadyToStart(bool can_start, + absl::optional<GURL> url, + std::unique_ptr<TriggerContext> trigger_context); + // Notifies the external caller that the script has ended. Note that the // external caller can decide to destroy this instance once it has been // notified so this method should not be called directly to avoid UAF issues. void NotifyScriptEnded(Metrics::DropOutReason reason); - private: - void OnReadyToStart(bool can_start, - absl::optional<GURL> url, - std::unique_ptr<TriggerContext> trigger_context); raw_ptr<content::WebContents> web_contents_; std::unique_ptr<ClientHeadless> client_;
diff --git a/components/autofill_assistant/browser/script_parameters.cc b/components/autofill_assistant/browser/script_parameters.cc index c9272204..f39dcfb 100644 --- a/components/autofill_assistant/browser/script_parameters.cc +++ b/components/autofill_assistant/browser/script_parameters.cc
@@ -80,13 +80,14 @@ // to send to the backend i.e., they do not require explicit approval in the // autofill-assistant onboarding. Even so, please always reach out to Chrome // privacy when you plan to make use of this list, and/or adjust it. -constexpr std::array<const char*, 6> kNonSensitiveScriptParameters = { +constexpr std::array<const char*, 7> kNonSensitiveScriptParameters = { public_script_parameters::kDebugBundleIdParameterName, "DEBUG_BUNDLE_VERSION", public_script_parameters::kDebugSocketIdParameterName, "FALLBACK_BUNDLE_ID", "FALLBACK_BUNDLE_VERSION", - public_script_parameters::kIntentParameterName}; + public_script_parameters::kIntentParameterName, + "CAPABILITIES_REQUEST_ID"}; // Parameters to specify details before the first backend roundtrip. const char kDetailsShowInitialParameterName[] = "DETAILS_SHOW_INITIAL";
diff --git a/components/autofill_assistant/browser/script_parameters_unittest.cc b/components/autofill_assistant/browser/script_parameters_unittest.cc index 36e77df..c335835 100644 --- a/components/autofill_assistant/browser/script_parameters_unittest.cc +++ b/components/autofill_assistant/browser/script_parameters_unittest.cc
@@ -68,7 +68,8 @@ {"FALLBACK_BUNDLE_ID", "fallback_id"}, {"key_b", "value_b"}, {"FALLBACK_BUNDLE_VERSION", "fallback_ver"}, - {"INTENT", "FAKE_INTENT"}}}; + {"INTENT", "FAKE_INTENT"}, + {"CAPABILITIES_REQUEST_ID", "123456789"}}}; EXPECT_THAT( parameters.ToProto(/* only_non_sensitive_allowlisted = */ false), @@ -80,7 +81,8 @@ {"FALLBACK_BUNDLE_ID", "fallback_id"}, {"key_b", "value_b"}, {"FALLBACK_BUNDLE_VERSION", "fallback_ver"}, - {"INTENT", "FAKE_INTENT"}}))); + {"INTENT", "FAKE_INTENT"}, + {"CAPABILITIES_REQUEST_ID", "123456789"}}))); EXPECT_THAT( parameters.ToProto(/* only_non_sensitive_allowlisted = */ true), @@ -90,7 +92,8 @@ {"DEBUG_SOCKET_ID", "678"}, {"FALLBACK_BUNDLE_ID", "fallback_id"}, {"FALLBACK_BUNDLE_VERSION", "fallback_ver"}, - {"INTENT", "FAKE_INTENT"}}))); + {"INTENT", "FAKE_INTENT"}, + {"CAPABILITIES_REQUEST_ID", "123456789"}}))); } TEST(ScriptParametersTest, SpecialScriptParameters) {
diff --git a/components/device_signals/core/system_signals/BUILD.gn b/components/device_signals/core/system_signals/BUILD.gn index a33c4ac0..59de635 100644 --- a/components/device_signals/core/system_signals/BUILD.gn +++ b/components/device_signals/core/system_signals/BUILD.gn
@@ -4,19 +4,32 @@ static_library("system_signals") { public = [ - "base_platform_delegate.h", "file_system_service.h", "platform_delegate.h", + "platform_utils.h", ] sources = [ - "base_platform_delegate.cc", "file_system_service.cc", "hashing_utils.cc", "hashing_utils.h", "platform_delegate.cc", ] + if (is_win || is_mac || is_linux) { + public += [ "base_platform_delegate.h" ] + + sources += [ "base_platform_delegate.cc" ] + } + + if (is_win) { + sources += [ "win/platform_utils_win.cc" ] + } + + if (is_mac || is_linux) { + sources += [ "posix/platform_utils_posix.cc" ] + } + public_deps = [ "//third_party/abseil-cpp:absl" ] deps = [ @@ -45,10 +58,11 @@ source_set("unit_tests") { testonly = true - sources = [ - "base_platform_delegate_unittest.cc", - "file_system_service_unittest.cc", - ] + sources = [ "file_system_service_unittest.cc" ] + + if (is_win || is_mac || is_linux) { + sources += [ "base_platform_delegate_unittest.cc" ] + } deps = [ ":system_signals",
diff --git a/components/device_signals/core/system_signals/base_platform_delegate.cc b/components/device_signals/core/system_signals/base_platform_delegate.cc index f66296c5..5f2340e 100644 --- a/components/device_signals/core/system_signals/base_platform_delegate.cc +++ b/components/device_signals/core/system_signals/base_platform_delegate.cc
@@ -4,9 +4,14 @@ #include "components/device_signals/core/system_signals/base_platform_delegate.h" +#include "base/containers/flat_map.h" +#include "base/containers/flat_set.h" #include "base/files/file_path.h" #include "base/files/file_util.h" +#include "base/process/process_iterator.h" #include "components/device_signals/core/common/common_types.h" +#include "components/device_signals/core/system_signals/platform_utils.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace device_signals { @@ -23,4 +28,53 @@ return base::DirectoryExists(file_path); } +FilePathMap<bool> BasePlatformDelegate::AreExecutablesRunning( + const FilePathSet& file_paths) { + // Initialize map with the given file paths. + FilePathMap<bool> running_map; + running_map.reserve(file_paths.size()); + for (const auto& file_path : file_paths) { + // Default initialize as not running. + running_map[file_path] = false; + } + + // Use counter to keep track of how many entries were found, which can allow + // for an earlier return if all executables were to be found early. + size_t counter = 0; + base::ProcessIterator process_iterator(nullptr); + while (const auto* process_entry = process_iterator.NextProcessEntry()) { + if (counter >= running_map.size()) { + // Found all items we were looking for, so return early. + break; + } + + absl::optional<base::FilePath> exe_path = + GetProcessExePath(process_entry->pid()); + if (exe_path && running_map.contains(exe_path.value())) { + ++counter; + running_map[exe_path.value()] = true; + } + } + + return running_map; +} + +FilePathMap<ExecutableMetadata> BasePlatformDelegate::GetAllExecutableMetadata( + const FilePathSet& file_paths) { + FilePathMap<bool> files_are_running_map = AreExecutablesRunning(file_paths); + + FilePathMap<ExecutableMetadata> file_paths_to_metadata_map; + for (const auto& file_path : file_paths) { + ExecutableMetadata executable_metadata; + + if (files_are_running_map.contains(file_path)) { + executable_metadata.is_running = files_are_running_map[file_path]; + } + + file_paths_to_metadata_map[file_path] = executable_metadata; + } + + return file_paths_to_metadata_map; +} + } // namespace device_signals
diff --git a/components/device_signals/core/system_signals/base_platform_delegate.h b/components/device_signals/core/system_signals/base_platform_delegate.h index 3d0ad19..cbc08cc8 100644 --- a/components/device_signals/core/system_signals/base_platform_delegate.h +++ b/components/device_signals/core/system_signals/base_platform_delegate.h
@@ -18,9 +18,16 @@ // PlatformDelegate: bool PathIsReadable(const base::FilePath& file_path) const override; bool DirectoryExists(const base::FilePath& file_path) const override; + FilePathMap<ExecutableMetadata> GetAllExecutableMetadata( + const FilePathSet& file_paths) override; protected: BasePlatformDelegate(); + + // Returns a map of file paths to whether a currently running process was + // spawned from that file. The set of file paths in the map are specified by + // `file_paths`. + FilePathMap<bool> AreExecutablesRunning(const FilePathSet& file_paths); }; } // namespace device_signals
diff --git a/components/device_signals/core/system_signals/base_platform_delegate_unittest.cc b/components/device_signals/core/system_signals/base_platform_delegate_unittest.cc index e8944d70..af04853 100644 --- a/components/device_signals/core/system_signals/base_platform_delegate_unittest.cc +++ b/components/device_signals/core/system_signals/base_platform_delegate_unittest.cc
@@ -29,10 +29,6 @@ ResolveFilePath, (const base::FilePath&, base::FilePath*), (override)); - MOCK_METHOD(FilePathMap<ExecutableMetadata>, - GetAllExecutableMetadata, - (const FilePathSet&), - (override)); }; class BasePlatformDelegateTest : public testing::Test {
diff --git a/components/device_signals/core/system_signals/linux/linux_platform_delegate.cc b/components/device_signals/core/system_signals/linux/linux_platform_delegate.cc index cfd8eb0..a4e4da3 100644 --- a/components/device_signals/core/system_signals/linux/linux_platform_delegate.cc +++ b/components/device_signals/core/system_signals/linux/linux_platform_delegate.cc
@@ -4,19 +4,10 @@ #include "components/device_signals/core/system_signals/linux/linux_platform_delegate.h" -#include "base/files/file_path.h" -#include "components/device_signals/core/common/common_types.h" - namespace device_signals { LinuxPlatformDelegate::LinuxPlatformDelegate() = default; LinuxPlatformDelegate::~LinuxPlatformDelegate() = default; -FilePathMap<ExecutableMetadata> LinuxPlatformDelegate::GetAllExecutableMetadata( - const FilePathSet& file_paths) { - // TODO(b:231326345): Implement. - return FilePathMap<ExecutableMetadata>(); -} - } // namespace device_signals
diff --git a/components/device_signals/core/system_signals/linux/linux_platform_delegate.h b/components/device_signals/core/system_signals/linux/linux_platform_delegate.h index b45fdcb575..9fb85f3b 100644 --- a/components/device_signals/core/system_signals/linux/linux_platform_delegate.h +++ b/components/device_signals/core/system_signals/linux/linux_platform_delegate.h
@@ -13,10 +13,6 @@ public: LinuxPlatformDelegate(); ~LinuxPlatformDelegate() override; - - // PlatformDelegate: - FilePathMap<ExecutableMetadata> GetAllExecutableMetadata( - const FilePathSet& file_paths) override; }; } // namespace device_signals
diff --git a/components/device_signals/core/system_signals/mac/mac_platform_delegate.h b/components/device_signals/core/system_signals/mac/mac_platform_delegate.h index 72d91ce..2bc1887 100644 --- a/components/device_signals/core/system_signals/mac/mac_platform_delegate.h +++ b/components/device_signals/core/system_signals/mac/mac_platform_delegate.h
@@ -13,10 +13,6 @@ public: MacPlatformDelegate(); ~MacPlatformDelegate() override; - - // FileSystemDelegate: - FilePathMap<ExecutableMetadata> GetAllExecutableMetadata( - const FilePathSet& file_paths) override; }; } // namespace device_signals
diff --git a/components/device_signals/core/system_signals/mac/mac_platform_delegate.mm b/components/device_signals/core/system_signals/mac/mac_platform_delegate.mm index 258e54d..e763e18 100644 --- a/components/device_signals/core/system_signals/mac/mac_platform_delegate.mm +++ b/components/device_signals/core/system_signals/mac/mac_platform_delegate.mm
@@ -4,19 +4,10 @@ #include "components/device_signals/core/system_signals/mac/mac_platform_delegate.h" -#include "base/files/file_path.h" -#include "components/device_signals/core/common/common_types.h" - namespace device_signals { MacPlatformDelegate::MacPlatformDelegate() = default; MacPlatformDelegate::~MacPlatformDelegate() = default; -FilePathMap<ExecutableMetadata> MacPlatformDelegate::GetAllExecutableMetadata( - const FilePathSet& file_paths) { - // TODO(b:231326198): Implement. - return FilePathMap<ExecutableMetadata>(); -} - } // namespace device_signals
diff --git a/components/device_signals/core/system_signals/platform_utils.h b/components/device_signals/core/system_signals/platform_utils.h new file mode 100644 index 0000000..9152e54 --- /dev/null +++ b/components/device_signals/core/system_signals/platform_utils.h
@@ -0,0 +1,23 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_DEVICE_SIGNALS_CORE_SYSTEM_SIGNALS_PLATFORM_UTILS_H_ +#define COMPONENTS_DEVICE_SIGNALS_CORE_SYSTEM_SIGNALS_PLATFORM_UTILS_H_ + +#include "base/process/process_handle.h" +#include "third_party/abseil-cpp/absl/types/optional.h" + +namespace base { +class FilePath; +} // namespace base + +namespace device_signals { + +// Returns the file path pointing to the executable file that spawned +// the given process `pid`. +absl::optional<base::FilePath> GetProcessExePath(base::ProcessId pid); + +} // namespace device_signals + +#endif // COMPONENTS_DEVICE_SIGNALS_CORE_SYSTEM_SIGNALS_PLATFORM_UTILS_H_
diff --git a/components/device_signals/core/system_signals/posix/platform_utils_posix.cc b/components/device_signals/core/system_signals/posix/platform_utils_posix.cc new file mode 100644 index 0000000..e749bdb --- /dev/null +++ b/components/device_signals/core/system_signals/posix/platform_utils_posix.cc
@@ -0,0 +1,20 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/device_signals/core/system_signals/platform_utils.h" + +#include "base/files/file_path.h" +#include "base/process/process_handle.h" + +namespace device_signals { + +absl::optional<base::FilePath> GetProcessExePath(base::ProcessId pid) { + auto file_path = base::GetProcessExecutablePath(pid); + if (file_path.empty()) { + return absl::nullopt; + } + return file_path; +} + +} // namespace device_signals
diff --git a/components/device_signals/core/system_signals/win/platform_utils_win.cc b/components/device_signals/core/system_signals/win/platform_utils_win.cc new file mode 100644 index 0000000..c25fff49 --- /dev/null +++ b/components/device_signals/core/system_signals/win/platform_utils_win.cc
@@ -0,0 +1,31 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/device_signals/core/system_signals/platform_utils.h" + +#include <windows.h> + +#include "base/files/file_path.h" +#include "base/process/process.h" + +namespace device_signals { + +absl::optional<base::FilePath> GetProcessExePath(base::ProcessId pid) { + base::Process process( + ::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid)); + if (!process.IsValid()) { + return absl::nullopt; + } + + DWORD path_len = MAX_PATH; + wchar_t path_string[MAX_PATH]; + if (!::QueryFullProcessImageName(process.Handle(), 0, path_string, + &path_len)) { + return absl::nullopt; + } + + return base::FilePath(path_string); +} + +} // namespace device_signals
diff --git a/components/device_signals/core/system_signals/win/win_platform_delegate.cc b/components/device_signals/core/system_signals/win/win_platform_delegate.cc index 86d6520..dcf1d11 100644 --- a/components/device_signals/core/system_signals/win/win_platform_delegate.cc +++ b/components/device_signals/core/system_signals/win/win_platform_delegate.cc
@@ -8,7 +8,10 @@ #include "base/files/file_path.h" #include "base/files/file_util.h" +#include "base/process/process.h" +#include "base/process/process_iterator.h" #include "base/strings/string_util.h" +#include "base/strings/string_util_win.h" #include "components/device_signals/core/common/common_types.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -23,7 +26,7 @@ std::wstring path_expanded; DWORD path_len = MAX_PATH; do { - DWORD result = ExpandEnvironmentStrings( + DWORD result = ::ExpandEnvironmentStrings( path.c_str(), base::WriteInto(&path_expanded, path_len), path_len); if (!result) { // Failed to expand variables. @@ -59,10 +62,4 @@ return true; } -FilePathMap<ExecutableMetadata> WinPlatformDelegate::GetAllExecutableMetadata( - const FilePathSet& file_paths) { - // TODO(b:231472924): Implement. - return FilePathMap<ExecutableMetadata>(); -} - } // namespace device_signals
diff --git a/components/device_signals/core/system_signals/win/win_platform_delegate.h b/components/device_signals/core/system_signals/win/win_platform_delegate.h index 86c4df2..b8e456a 100644 --- a/components/device_signals/core/system_signals/win/win_platform_delegate.h +++ b/components/device_signals/core/system_signals/win/win_platform_delegate.h
@@ -17,8 +17,6 @@ // PlatformDelegate: bool ResolveFilePath(const base::FilePath& file_path, base::FilePath* resolved_file_path) override; - FilePathMap<ExecutableMetadata> GetAllExecutableMetadata( - const FilePathSet& file_paths) override; }; } // namespace device_signals
diff --git a/components/exo/pointer_unittest.cc b/components/exo/pointer_unittest.cc index 20da2818..3a46589 100644 --- a/components/exo/pointer_unittest.cc +++ b/components/exo/pointer_unittest.cc
@@ -179,10 +179,7 @@ #if BUILDFLAG(IS_CHROMEOS_ASH) class PointerConstraintTest : public PointerTest { public: - PointerConstraintTest() { - feature_list_.InitAndEnableFeature(chromeos::features::kExoPointerLock); - } - + PointerConstraintTest() = default; PointerConstraintTest(const PointerConstraintTest&) = delete; PointerConstraintTest& operator=(const PointerConstraintTest&) = delete; @@ -232,7 +229,6 @@ return shell_surface; } - base::test::ScopedFeatureList feature_list_; std::unique_ptr<ui::test::EventGenerator> generator_; std::unique_ptr<Pointer> pointer_; std::unique_ptr<Seat> seat_;
diff --git a/components/exo/ui_lock_controller_unittest.cc b/components/exo/ui_lock_controller_unittest.cc index 627fd8d..4101802 100644 --- a/components/exo/ui_lock_controller_unittest.cc +++ b/components/exo/ui_lock_controller_unittest.cc
@@ -139,9 +139,7 @@ test::ExoTestBase::SetUp(); seat_ = std::make_unique<Seat>(); scoped_feature_list_.InitWithFeatures( - {chromeos::features::kExoLockNotification, - chromeos::features::kExoPointerLock}, - {}); + {chromeos::features::kExoLockNotification}, {}); WMHelper::GetInstance()->RegisterAppPropertyResolver( std::make_unique<TestPropertyResolver>()); }
diff --git a/components/metrics/log_store.h b/components/metrics/log_store.h index da81179..700f36b 100644 --- a/components/metrics/log_store.h +++ b/components/metrics/log_store.h
@@ -56,8 +56,13 @@ // the staged log needs discarded. virtual void MarkStagedLogAsSent() = 0; - // Trims saved logs and writes to persistent storage. - virtual void TrimAndPersistUnsentLogs() = 0; + // Trims saved logs and writes them to persistent storage. When + // |overwrite_in_memory_store| is false, we will still not persist logs that + // should be trimmed away, but they will still be available in memory + // (allowing them to still be eligible for upload this session). + // TODO(crbug/1171830): Revisit call sites and determine what value of + // |overwrite_in_memory_store| they should use. + virtual void TrimAndPersistUnsentLogs(bool overwrite_in_memory_store) = 0; // Loads unsent logs from persistent storage. virtual void LoadPersistedUnsentLogs() = 0;
diff --git a/components/metrics/metrics_log_store.cc b/components/metrics/metrics_log_store.cc index ab31462..ef1daef 100644 --- a/components/metrics/metrics_log_store.cc +++ b/components/metrics/metrics_log_store.cc
@@ -74,7 +74,8 @@ void MetricsLogStore::UnsetAlternateOngoingLogStore() { DCHECK(has_alternate_ongoing_log_store()); - alternate_ongoing_log_queue_->TrimAndPersistUnsentLogs(); + alternate_ongoing_log_queue_->TrimAndPersistUnsentLogs( + /*overwrite_in_memory_store=*/true); alternate_ongoing_log_queue_.reset(); } @@ -164,15 +165,16 @@ ongoing_log_queue_.MarkStagedLogAsSent(); } -void MetricsLogStore::TrimAndPersistUnsentLogs() { +void MetricsLogStore::TrimAndPersistUnsentLogs(bool overwrite_in_memory_store) { DCHECK(unsent_logs_loaded_); if (!unsent_logs_loaded_) return; - initial_log_queue_.TrimAndPersistUnsentLogs(); - ongoing_log_queue_.TrimAndPersistUnsentLogs(); + initial_log_queue_.TrimAndPersistUnsentLogs(overwrite_in_memory_store); + ongoing_log_queue_.TrimAndPersistUnsentLogs(overwrite_in_memory_store); if (has_alternate_ongoing_log_store()) - alternate_ongoing_log_queue_->TrimAndPersistUnsentLogs(); + alternate_ongoing_log_queue_->TrimAndPersistUnsentLogs( + overwrite_in_memory_store); } } // namespace metrics
diff --git a/components/metrics/metrics_log_store.h b/components/metrics/metrics_log_store.h index c3497229..cd1b26b 100644 --- a/components/metrics/metrics_log_store.h +++ b/components/metrics/metrics_log_store.h
@@ -106,7 +106,7 @@ void StageNextLog() override; void DiscardStagedLog() override; void MarkStagedLogAsSent() override; - void TrimAndPersistUnsentLogs() override; + void TrimAndPersistUnsentLogs(bool overwrite_in_memory_store) override; void LoadPersistedUnsentLogs() override; // Inspection methods for tests.
diff --git a/components/metrics/metrics_log_store_unittest.cc b/components/metrics/metrics_log_store_unittest.cc index 32564c8..5aa5b940 100644 --- a/components/metrics/metrics_log_store_unittest.cc +++ b/components/metrics/metrics_log_store_unittest.cc
@@ -98,7 +98,7 @@ log_store.LoadPersistedUnsentLogs(); EXPECT_FALSE(log_store.has_unsent_logs()); log_store.StoreLog("a", MetricsLog::ONGOING_LOG, LogMetadata()); - log_store.TrimAndPersistUnsentLogs(); + log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true); EXPECT_EQ(0U, TypeCount(MetricsLog::INITIAL_STABILITY_LOG)); EXPECT_EQ(1U, TypeCount(MetricsLog::ONGOING_LOG)); } @@ -120,7 +120,7 @@ EXPECT_EQ(0U, TypeCount(MetricsLog::INITIAL_STABILITY_LOG)); EXPECT_EQ(1U, TypeCount(MetricsLog::ONGOING_LOG)); - log_store.TrimAndPersistUnsentLogs(); + log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true); EXPECT_EQ(1U, TypeCount(MetricsLog::INITIAL_STABILITY_LOG)); EXPECT_EQ(2U, TypeCount(MetricsLog::ONGOING_LOG)); } @@ -136,7 +136,7 @@ log_store.DiscardStagedLog(); // The initial log should be sent first; update the persisted storage to // verify. - log_store.TrimAndPersistUnsentLogs(); + log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true); EXPECT_EQ(0U, TypeCount(MetricsLog::INITIAL_STABILITY_LOG)); EXPECT_EQ(2U, TypeCount(MetricsLog::ONGOING_LOG)); @@ -154,7 +154,7 @@ // hasn't been called again. EXPECT_EQ(2U, TypeCount(MetricsLog::ONGOING_LOG)); // Persist, and make sure nothing is left. - log_store.TrimAndPersistUnsentLogs(); + log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true); EXPECT_EQ(0U, TypeCount(MetricsLog::INITIAL_STABILITY_LOG)); EXPECT_EQ(0U, TypeCount(MetricsLog::ONGOING_LOG)); } @@ -167,7 +167,7 @@ log_store.LoadPersistedUnsentLogs(); log_store.StoreLog("a", MetricsLog::ONGOING_LOG, LogMetadata()); log_store.StageNextLog(); - log_store.TrimAndPersistUnsentLogs(); + log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true); EXPECT_EQ(0U, TypeCount(MetricsLog::INITIAL_STABILITY_LOG)); EXPECT_EQ(1U, TypeCount(MetricsLog::ONGOING_LOG)); @@ -180,7 +180,7 @@ log_store.LoadPersistedUnsentLogs(); log_store.StoreLog("b", MetricsLog::INITIAL_STABILITY_LOG, LogMetadata()); log_store.StageNextLog(); - log_store.TrimAndPersistUnsentLogs(); + log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true); EXPECT_EQ(1U, TypeCount(MetricsLog::INITIAL_STABILITY_LOG)); EXPECT_EQ(0U, TypeCount(MetricsLog::ONGOING_LOG)); @@ -198,7 +198,7 @@ log_store.StoreLog("not_persisted", MetricsLog::ONGOING_LOG, LogMetadata()); // Only the stability log should be written out, due to the threshold. - log_store.TrimAndPersistUnsentLogs(); + log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true); EXPECT_EQ(1U, TypeCount(MetricsLog::INITIAL_STABILITY_LOG)); EXPECT_EQ(0U, TypeCount(MetricsLog::ONGOING_LOG)); }
diff --git a/components/metrics/metrics_service.cc b/components/metrics/metrics_service.cc index fda6c7e2..f0eb920 100644 --- a/components/metrics/metrics_service.cc +++ b/components/metrics/metrics_service.cc
@@ -793,7 +793,7 @@ return; // We didn't and still don't have time to get plugin list etc. CloseCurrentLog(); - log_store()->TrimAndPersistUnsentLogs(); + log_store()->TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true); } //------------------------------------------------------------------------------ @@ -894,7 +894,7 @@ // Store unsent logs, including the stability log that was just saved, so // that they're not lost in case of a crash before upload time. - log_store()->TrimAndPersistUnsentLogs(); + log_store()->TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true); return true; } @@ -932,7 +932,7 @@ // Store unsent logs, including the initial log that was just saved, so // that they're not lost in case of a crash before upload time. - log_store()->TrimAndPersistUnsentLogs(); + log_store()->TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true); state_ = SENDING_LOGS; }
diff --git a/components/metrics/reporting_service.cc b/components/metrics/reporting_service.cc index e46d164..ce91186d4 100644 --- a/components/metrics/reporting_service.cc +++ b/components/metrics/reporting_service.cc
@@ -124,7 +124,7 @@ !client_->ShouldUploadMetricsForUserId(staged_user_id.value())) { // Remove the log and update list to disk. log_store()->DiscardStagedLog(); - log_store()->TrimAndPersistUnsentLogs(); + log_store()->TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true); // Notify the scheduler that the next log should be uploaded. If there are // no more logs, then stop the scheduler. @@ -222,7 +222,7 @@ log_store()->DiscardStagedLog(); // Store the updated list to disk now that the removed log is uploaded. - log_store()->TrimAndPersistUnsentLogs(); + log_store()->TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true); } }
diff --git a/components/metrics/reporting_service_unittest.cc b/components/metrics/reporting_service_unittest.cc index e167dd0..9c23ac9 100644 --- a/components/metrics/reporting_service_unittest.cc +++ b/components/metrics/reporting_service_unittest.cc
@@ -72,7 +72,7 @@ staged_log_hash_.clear(); } void MarkStagedLogAsSent() override {} - void TrimAndPersistUnsentLogs() override {} + void TrimAndPersistUnsentLogs(bool overwrite_in_memory_store) override {} void LoadPersistedUnsentLogs() override {} private:
diff --git a/components/metrics/unsent_log_store.cc b/components/metrics/unsent_log_store.cc index 963a692b..e89fdbf7 100644 --- a/components/metrics/unsent_log_store.cc +++ b/components/metrics/unsent_log_store.cc
@@ -47,6 +47,83 @@ return result; } +// Used to write unsent logs to prefs. +class LogsPrefWriter { + public: + // Create a writer that will write unsent logs to |list_value|. |list_value| + // should be a base::Value::List representing a pref. Clears the contents of + // |list_value|. + explicit LogsPrefWriter(base::Value::List* list_value) + : list_value_(list_value) { + DCHECK(list_value); + list_value->clear(); + }; + + LogsPrefWriter(const LogsPrefWriter&) = delete; + LogsPrefWriter& operator=(const LogsPrefWriter&) = delete; + + ~LogsPrefWriter() { DCHECK(finished_); } + + // Persists |log| by appending it to |list_value_|. + void WriteLogEntry(UnsentLogStore::LogInfo* log) { + DCHECK(!finished_); + + base::Value dict_value{base::Value::Type::DICTIONARY}; + dict_value.SetStringKey(kLogHashKey, EncodeToBase64(log->hash)); + dict_value.SetStringKey(kLogSignatureKey, EncodeToBase64(log->signature)); + dict_value.SetStringKey(kLogDataKey, + EncodeToBase64(log->compressed_log_data)); + dict_value.SetStringKey(kLogTimestampKey, log->timestamp); + + auto user_id = log->log_metadata.user_id; + if (user_id.has_value()) { + dict_value.SetStringKey( + kLogUserIdKey, EncodeToBase64(base::NumberToString(user_id.value()))); + } + list_value_->Append(std::move(dict_value)); + + auto samples_count = log->log_metadata.samples_count; + if (samples_count.has_value()) { + unsent_samples_count_ += samples_count.value(); + } + unsent_persisted_size_ += log->compressed_log_data.length(); + ++unsent_logs_count_; + } + + // Indicates to this writer that it is finished, and that it should not write + // any more logs. This also reverses |list_value_| in order to maintain the + // original order of the logs that were written. + void Finish() { + DCHECK(!finished_); + finished_ = true; + std::reverse(list_value_->begin(), list_value_->end()); + } + + base::HistogramBase::Count unsent_samples_count() const { + return unsent_samples_count_; + } + + size_t unsent_persisted_size() const { return unsent_persisted_size_; } + + size_t unsent_logs_count() const { return unsent_logs_count_; } + + private: + // The list where the logs will be written to. This should represent a pref. + raw_ptr<base::Value::List> list_value_; + + // Whether or not this writer has finished writing to pref. + bool finished_ = false; + + // The total number of histogram samples written so far. + base::HistogramBase::Count unsent_samples_count_ = 0; + + // The total size of logs written so far. + size_t unsent_persisted_size_ = 0; + + // The total number of logs written so far. + size_t unsent_logs_count_ = 0; +}; + } // namespace UnsentLogStore::LogInfo::LogInfo() = default; @@ -177,10 +254,75 @@ total_samples_sent_ += samples_count.value(); } -void UnsentLogStore::TrimAndPersistUnsentLogs() { +void UnsentLogStore::TrimAndPersistUnsentLogs(bool overwrite_in_memory_store) { ListPrefUpdate update(local_state_, log_data_pref_name_); - TrimLogs(); - WriteLogsToPrefList(update.Get()); + LogsPrefWriter writer(&update->GetList()); + + std::vector<std::unique_ptr<LogInfo>> trimmed_list; + size_t bytes_used = 0; + + // The distance of the staged log from the end of the list of logs, which is + // usually 0 (end of list). This is used in case there is currently a staged + // log, which may or may not get trimmed. We want to keep track of the new + // position of the staged log after trimming so that we can update + // |staged_log_index_|. + absl::optional<size_t> staged_index_distance; + + // Reverse order, so newest ones are prioritized. + for (int i = list_.size() - 1; i >= 0; --i) { + size_t log_size = list_[i]->compressed_log_data.length(); + // Hit the caps, we can stop moving the logs. + if (bytes_used >= min_log_bytes_ && + writer.unsent_logs_count() >= min_log_count_) { + break; + } + // Omit overly large individual logs. + if (log_size > max_log_size_) { + metrics_->RecordDroppedLogSize(log_size); + continue; + } + + bytes_used += log_size; + + if (staged_log_index_ == i) { + staged_index_distance = writer.unsent_logs_count(); + } + + // Append log to prefs. + writer.WriteLogEntry(list_[i].get()); + if (overwrite_in_memory_store) + trimmed_list.emplace_back(std::move(list_[i])); + } + + writer.Finish(); + + if (overwrite_in_memory_store) { + // We went in reverse order, but appended entries. So reverse list to + // correct. + std::reverse(trimmed_list.begin(), trimmed_list.end()); + + size_t dropped_logs_count = list_.size() - trimmed_list.size(); + if (dropped_logs_count > 0) + metrics_->RecordDroppedLogsNum(dropped_logs_count); + + // Put the trimmed list in the correct place. + list_.swap(trimmed_list); + + // We may need to adjust the staged index since the number of logs may be + // reduced. + if (staged_index_distance.has_value()) { + staged_log_index_ = list_.size() - 1 - staged_index_distance.value(); + } else { + // Set |staged_log_index_| to -1. It might already be -1. E.g., at the + // time we are trimming logs, there was no staged log. However, it is also + // possible that we trimmed away the staged log, so we need to update the + // index to -1. + staged_log_index_ = -1; + } + } + + WriteToMetricsPref(writer.unsent_samples_count(), total_samples_sent_, + writer.unsent_persisted_size()); } void UnsentLogStore::LoadPersistedUnsentLogs() { @@ -286,94 +428,6 @@ metrics_->RecordLogReadStatus(UnsentLogStoreMetrics::RECALL_SUCCESS); } -void UnsentLogStore::TrimLogs() { - std::vector<std::unique_ptr<LogInfo>> trimmed_list; - size_t bytes_used = 0; - - // The distance of the staged log from the end of the list of logs, which is - // usually 0 (end of list). This is used in case there is currently a staged - // log, which may or may not get trimmed. We want to keep track of the new - // position of the staged log after trimming so that we can update - // |staged_log_index_|. - absl::optional<size_t> staged_index_distance; - - // Reverse order, so newest ones are prioritized. - for (int i = list_.size() - 1; i >= 0; --i) { - size_t log_size = list_[i]->compressed_log_data.length(); - // Hit the caps, we can stop moving the logs. - if (bytes_used >= min_log_bytes_ && trimmed_list.size() >= min_log_count_) { - break; - } - // Omit overly large individual logs. - if (log_size > max_log_size_) { - metrics_->RecordDroppedLogSize(log_size); - continue; - } - - bytes_used += log_size; - - if (staged_log_index_ == i) { - staged_index_distance = trimmed_list.size(); - } - - trimmed_list.emplace_back(std::move(list_[i])); - } - - // We went in reverse order, but appended entries. So reverse list to correct. - std::reverse(trimmed_list.begin(), trimmed_list.end()); - - size_t dropped_logs_count = list_.size() - trimmed_list.size(); - if (dropped_logs_count > 0) - metrics_->RecordDroppedLogsNum(dropped_logs_count); - - // Put the trimmed list in the correct place. - list_.swap(trimmed_list); - - // We may need to adjust the staged index since the number of logs may be - // reduced. However, we want to make sure not to change the index if there is - // no log staged. - if (staged_index_distance.has_value()) { - staged_log_index_ = list_.size() - 1 - staged_index_distance.value(); - } else { - // Set |staged_log_index_| to -1. It might already be -1. E.g., at the time - // we are trimming logs, there was no staged log. However, it is also - // possible that we trimmed away the staged log, so we need to update the - // index to -1. - staged_log_index_ = -1; - } -} - -void UnsentLogStore::WriteLogsToPrefList(base::Value* list_value) const { - list_value->ClearList(); - - base::HistogramBase::Count unsent_samples_count = 0; - size_t unsent_persisted_size = 0; - - for (auto& log : list_) { - base::Value dict_value{base::Value::Type::DICTIONARY}; - dict_value.SetStringKey(kLogHashKey, EncodeToBase64(log->hash)); - dict_value.SetStringKey(kLogSignatureKey, EncodeToBase64(log->signature)); - dict_value.SetStringKey(kLogDataKey, - EncodeToBase64(log->compressed_log_data)); - dict_value.SetStringKey(kLogTimestampKey, log->timestamp); - - auto user_id = log->log_metadata.user_id; - if (user_id.has_value()) { - dict_value.SetStringKey( - kLogUserIdKey, EncodeToBase64(base::NumberToString(user_id.value()))); - } - list_value->Append(std::move(dict_value)); - - auto samples_count = log->log_metadata.samples_count; - if (samples_count.has_value()) { - unsent_samples_count += samples_count.value(); - } - unsent_persisted_size += log->compressed_log_data.length(); - } - WriteToMetricsPref(unsent_samples_count, total_samples_sent_, - unsent_persisted_size); -} - void UnsentLogStore::WriteToMetricsPref( base::HistogramBase::Count unsent_samples_count, base::HistogramBase::Count sent_samples_count,
diff --git a/components/metrics/unsent_log_store.h b/components/metrics/unsent_log_store.h index 5bf1f69e..0c77cd37 100644 --- a/components/metrics/unsent_log_store.h +++ b/components/metrics/unsent_log_store.h
@@ -61,6 +61,44 @@ ~UnsentLogStore() override; + struct LogInfo { + LogInfo(); + LogInfo(const LogInfo& other); + ~LogInfo(); + + // Initializes the members based on uncompressed |log_data|, + // |log_timestamp|, and |signing_key|. |log_data| is the uncompressed + // serialized log protobuf. A hash and a signature are computed from + // |log_data|. The signature is produced using |signing_key|. |log_data| + // will be compressed and stored in |compressed_log_data|. |log_timestamp| + // is stored as is. |log_metadata| is any optional metadata that will be + // attached to the log. + // |metrics| is the parent's metrics_ object, and should not be held. + void Init(UnsentLogStoreMetrics* metrics, + const std::string& log_data, + const std::string& log_timestamp, + const std::string& signing_key, + const LogMetadata& log_metadata); + + // Compressed log data - a serialized protobuf that's been gzipped. + std::string compressed_log_data; + + // The SHA1 hash of the log. Computed in Init and stored to catch errors + // from memory corruption. + std::string hash; + + // The HMAC-SHA256 signature of the log, used to validate the log came from + // Chrome. It's computed in Init and stored, instead of computed on demand, + // to catch errors from memory corruption. + std::string signature; + + // The timestamp of when the log was created as a time_t value. + std::string timestamp; + + // Properties of the log. + LogMetadata log_metadata; + }; + // LogStore: bool has_unsent_logs() const override; bool has_staged_log() const override; @@ -71,7 +109,7 @@ void StageNextLog() override; void DiscardStagedLog() override; void MarkStagedLogAsSent() override; - void TrimAndPersistUnsentLogs() override; + void TrimAndPersistUnsentLogs(bool overwrite_in_memory_store) override; void LoadPersistedUnsentLogs() override; // Adds a UMA log to the list. |log_metadata| refers to metadata associated @@ -106,14 +144,6 @@ private: FRIEND_TEST_ALL_PREFIXES(UnsentLogStoreTest, UnsentLogMetadataMetrics); - // Keep the most recent logs which are smaller than |max_log_size_|. - // We keep at least |min_log_bytes_| and |min_log_count_| of logs before - // discarding older logs. - void TrimLogs(); - - // Writes the list of logs to |list|. - void WriteLogsToPrefList(base::Value* list) const; - // Reads the list of logs from |list|. void ReadLogsFromPrefList(const base::Value& list); @@ -153,43 +183,6 @@ // authentic. const std::string signing_key_; - struct LogInfo { - LogInfo(); - LogInfo(const LogInfo& other); - ~LogInfo(); - - // Initializes the members based on uncompressed |log_data|, - // |log_timestamp|, and |signing_key|. |log_data| is the uncompressed - // serialized log protobuf. A hash and a signature are computed from - // |log_data|. The signature is produced using |signing_key|. |log_data| - // will be compressed and stored in |compressed_log_data|. |log_timestamp| - // is stored as is. |log_metadata| is any optional metadata that will be - // attached to the log. - // |metrics| is the parent's metrics_ object, and should not be held. - void Init(UnsentLogStoreMetrics* metrics, - const std::string& log_data, - const std::string& log_timestamp, - const std::string& signing_key, - const LogMetadata& log_metadata); - - // Compressed log data - a serialized protobuf that's been gzipped. - std::string compressed_log_data; - - // The SHA1 hash of the log. Computed in Init and stored to catch errors - // from memory corruption. - std::string hash; - - // The HMAC-SHA256 signature of the log, used to validate the log came from - // Chrome. It's computed in Init and stored, instead of computed on demand, - // to catch errors from memory corruption. - std::string signature; - - // The timestamp of when the log was created as a time_t value. - std::string timestamp; - - // Properties of the log. - LogMetadata log_metadata; - }; // A list of all of the stored logs, stored with SHA1 hashes to check for // corruption while they are stored in memory. std::vector<std::unique_ptr<LogInfo>> list_;
diff --git a/components/metrics/unsent_log_store_unittest.cc b/components/metrics/unsent_log_store_unittest.cc index 4f98b18..45b09b8 100644 --- a/components/metrics/unsent_log_store_unittest.cc +++ b/components/metrics/unsent_log_store_unittest.cc
@@ -137,7 +137,7 @@ TEST_F(UnsentLogStoreTest, EmptyLogList) { TestUnsentLogStore unsent_log_store(&prefs_, kLogByteLimit); - unsent_log_store.TrimAndPersistUnsentLogs(); + unsent_log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true); EXPECT_EQ(0U, prefs_.GetValueList(kTestPrefName).size()); TestUnsentLogStore result_unsent_log_store(&prefs_, kLogByteLimit); @@ -151,7 +151,7 @@ LogMetadata log_metadata; unsent_log_store.StoreLog("Hello world!", log_metadata); - unsent_log_store.TrimAndPersistUnsentLogs(); + unsent_log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true); TestUnsentLogStore result_unsent_log_store(&prefs_, kLogByteLimit); result_unsent_log_store.LoadPersistedUnsentLogs(); @@ -181,7 +181,7 @@ unsent_log_store.StoreLog("x", log_metadata); EXPECT_EQ(log_count, unsent_log_store.size()); - unsent_log_store.TrimAndPersistUnsentLogs(); + unsent_log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true); EXPECT_EQ(log_count, unsent_log_store.size()); TestUnsentLogStore result_unsent_log_store(&prefs_, kLogByteLimit); @@ -221,7 +221,7 @@ unsent_log_store.StoreLog(last_kept, log_metadata); size_t original_size = unsent_log_store.size(); - unsent_log_store.TrimAndPersistUnsentLogs(); + unsent_log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true); // New size has been reduced. EXPECT_EQ(original_size - 2, unsent_log_store.size()); @@ -250,7 +250,7 @@ for (size_t i = 0; i < log_count; ++i) { unsent_log_store.StoreLog(log_data, log_metadata); } - unsent_log_store.TrimAndPersistUnsentLogs(); + unsent_log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true); TestUnsentLogStore result_unsent_log_store(&prefs_, kLogByteLimit); result_unsent_log_store.LoadPersistedUnsentLogs(); @@ -281,7 +281,7 @@ unsent_log_store.StoreLog(log_data, log_metadata); } - unsent_log_store.TrimAndPersistUnsentLogs(); + unsent_log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true); TestUnsentLogStore result_unsent_log_store(&prefs_, kLogByteLimit); result_unsent_log_store.LoadPersistedUnsentLogs(); @@ -319,7 +319,7 @@ } EXPECT_EQ(kLogCountLimit + 1, unsent_log_store.size()); - unsent_log_store.TrimAndPersistUnsentLogs(); + unsent_log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true); // Verify that the first log (the staged one) was trimmed away, and that the // log store does not consider to have any staged log anymore. The other logs @@ -333,6 +333,86 @@ } } +// Verifies that when calling TrimAndPersistUnsentLogs() with +// |overwrite_in_memory_store| set to false, the in memory log store is +// unaffected. +TEST_F(UnsentLogStoreTest, + TrimAndPersistUnsentLogs_DoNotOverwriteInMemoryStore) { + TestUnsentLogStore unsent_log_store( + std::make_unique<UnsentLogStoreMetricsImpl>(), &prefs_, kLogByteLimit); + + LogMetadata log_metadata; + std::string log_data = GenerateLogWithMinCompressedSize(kLogByteLimit + 1); + unsent_log_store.StoreLog(log_data, log_metadata); + unsent_log_store.TrimAndPersistUnsentLogs( + /*overwrite_in_memory_store=*/false); + + // Verify that the log store still contains the log. + EXPECT_EQ(1U, unsent_log_store.size()); + unsent_log_store.ExpectNextLog(log_data); + + // Verify that the log was trimmed when persisted to memory. + TestUnsentLogStore result_unsent_log_store(&prefs_, kLogByteLimit); + result_unsent_log_store.LoadPersistedUnsentLogs(); + EXPECT_EQ(0U, result_unsent_log_store.size()); +} + +// Verifies that TrimAndPersistUnsentLogs() maintains the log order. +TEST_F(UnsentLogStoreTest, TrimAndPersistUnsentLogs_MaintainsLogOrder) { + TestUnsentLogStore unsent_log_store( + std::make_unique<UnsentLogStoreMetricsImpl>(), &prefs_, kLogByteLimit); + + LogMetadata log_metadata; + unsent_log_store.StoreLog("1", log_metadata); + unsent_log_store.StoreLog(GenerateLogWithMinCompressedSize(kLogByteLimit + 1), + log_metadata); + unsent_log_store.StoreLog("2", log_metadata); + unsent_log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true); + + // Verify that only the second log was trimmed (since it was over the max log + // size), and that the log order was maintained. I.e., "2" should be the most + // recent log, followed by "1". + EXPECT_EQ(2U, unsent_log_store.size()); + unsent_log_store.ExpectNextLog("2"); + unsent_log_store.ExpectNextLog("1"); + + // Similarly, verify that the order was also maintained in persistent memory. + TestUnsentLogStore result_unsent_log_store(&prefs_, kLogByteLimit); + result_unsent_log_store.LoadPersistedUnsentLogs(); + EXPECT_EQ(2U, result_unsent_log_store.size()); + result_unsent_log_store.ExpectNextLog("2"); + result_unsent_log_store.ExpectNextLog("1"); +} + +// Verifies that calling TrimAndPersistUnsentLogs() clears the pref list before +// writing the trimmed logs list. +TEST_F(UnsentLogStoreTest, TrimAndPersistUnsentLogs_OverwritesPrefs) { + TestUnsentLogStore unsent_log_store(&prefs_, kLogByteLimit); + + LogMetadata log_metadata; + unsent_log_store.StoreLog("Hello world!", log_metadata); + // Call TrimAndPersistUnsentLogs(). The log should not be trimmed. + unsent_log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true); + + TestUnsentLogStore result_unsent_log_store(&prefs_, kLogByteLimit); + result_unsent_log_store.LoadPersistedUnsentLogs(); + EXPECT_EQ(1U, result_unsent_log_store.size()); + + // Verify that the result log matches the initial log. + result_unsent_log_store.ExpectNextLog("Hello world!"); + + // Call TrimAndPersistUnsentLogs() and load the persisted logs once again. + // There should still only be one log. + unsent_log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true); + + TestUnsentLogStore result_unsent_log_store2(&prefs_, kLogByteLimit); + result_unsent_log_store2.LoadPersistedUnsentLogs(); + EXPECT_EQ(1U, result_unsent_log_store2.size()); + + // Verify that the result log matches the initial log. + result_unsent_log_store2.ExpectNextLog("Hello world!"); +} + // Check that the store/stage/discard functions work as expected. TEST_F(UnsentLogStoreTest, Staging) { TestUnsentLogStore unsent_log_store(&prefs_, kLogByteLimit); @@ -372,7 +452,7 @@ unsent_log_store.StageNextLog(); unsent_log_store.StoreLog("two", log_metadata); unsent_log_store.DiscardStagedLog(); - unsent_log_store.TrimAndPersistUnsentLogs(); + unsent_log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true); TestUnsentLogStore result_unsent_log_store(&prefs_, kLogByteLimit); result_unsent_log_store.LoadPersistedUnsentLogs(); @@ -451,7 +531,7 @@ EXPECT_EQ(Compress(foo_text), unsent_log_store.staged_log()); EXPECT_EQ(unsent_log_store.staged_log_user_id().value(), user_id); - unsent_log_store.TrimAndPersistUnsentLogs(); + unsent_log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true); // Reads persisted logs from new log store. TestUnsentLogStore read_unsent_log_store(&prefs_, kLogByteLimit); @@ -475,7 +555,7 @@ EXPECT_EQ(Compress(foo_text), unsent_log_store.staged_log()); EXPECT_EQ(unsent_log_store.staged_log_user_id().value(), large_user_id); - unsent_log_store.TrimAndPersistUnsentLogs(); + unsent_log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true); // Reads persisted logs from new log store. TestUnsentLogStore read_unsent_log_store(&prefs_, kLogByteLimit); @@ -525,7 +605,7 @@ LogMetadata log_metadata_foo_bar_sample(kFooBarSampleCount, absl::nullopt); unsent_log_store.StoreLog(foobar_log, log_metadata_foo_bar_sample); - unsent_log_store.TrimAndPersistUnsentLogs(); + unsent_log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true); unsent_log_store.RecordMetaDataMetrics(); // The |oversize_log| was ignored, the kNoSampleLog won't be counted to @@ -538,7 +618,7 @@ unsent_log_store.StageNextLog(); unsent_log_store.MarkStagedLogAsSent(); unsent_log_store.DiscardStagedLog(); - unsent_log_store.TrimAndPersistUnsentLogs(); + unsent_log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true); unsent_log_store.RecordMetaDataMetrics(); // The |foobar_log| shall be sent. @@ -549,7 +629,7 @@ // Pretend |kFooText| upload failure. unsent_log_store.StageNextLog(); unsent_log_store.DiscardStagedLog(); - unsent_log_store.TrimAndPersistUnsentLogs(); + unsent_log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true); unsent_log_store.RecordMetaDataMetrics(); // Verify the failed upload wasn't added to the sent samples count.
diff --git a/components/metrics_services_manager/metrics_services_manager.cc b/components/metrics_services_manager/metrics_services_manager.cc index 31d987c..b694353 100644 --- a/components/metrics_services_manager/metrics_services_manager.cc +++ b/components/metrics_services_manager/metrics_services_manager.cc
@@ -69,8 +69,8 @@ } std::unique_ptr<const base::FieldTrial::EntropyProvider> -MetricsServicesManager::CreateEntropyProviderForTesting() { - return client_->GetMetricsStateManager()->CreateDefaultEntropyProvider(); +MetricsServicesManager::CreateLowEntropyProviderForTesting() { + return client_->GetMetricsStateManager()->CreateLowEntropyProvider(); } metrics::MetricsServiceClient*
diff --git a/components/metrics_services_manager/metrics_services_manager.h b/components/metrics_services_manager/metrics_services_manager.h index 304f924..82c2481 100644 --- a/components/metrics_services_manager/metrics_services_manager.h +++ b/components/metrics_services_manager/metrics_services_manager.h
@@ -74,9 +74,9 @@ // Returns true iff UKM is allowed for all profiles. bool IsUkmAllowedForAllProfiles(); - // Returns the default entropy provider. + // Returns a low entropy provider. std::unique_ptr<const base::FieldTrial::EntropyProvider> - CreateEntropyProviderForTesting(); + CreateLowEntropyProviderForTesting(); private: // Returns the MetricsServiceClient, creating it if it hasn't been
diff --git a/components/page_load_metrics/browser/observers/core/largest_contentful_paint_handler.cc b/components/page_load_metrics/browser/observers/core/largest_contentful_paint_handler.cc index be6321b..aac0ba3 100644 --- a/components/page_load_metrics/browser/observers/core/largest_contentful_paint_handler.cc +++ b/components/page_load_metrics/browser/observers/core/largest_contentful_paint_handler.cc
@@ -73,10 +73,6 @@ merged_candidate.Type(), merged_candidate.ImageBPP()); } -bool IsSubframe(content::RenderFrameHost* subframe_rfh) { - return subframe_rfh != nullptr && subframe_rfh->GetParent() != nullptr; -} - void Reset(ContentfulPaintTimingInfo& timing) { timing.Reset(absl::nullopt, 0u, blink::LargestContentfulPaintType::kNone, /*image_bpp=*/0.0); @@ -220,32 +216,6 @@ LargestContentfulPaintHandler::~LargestContentfulPaintHandler() = default; -void LargestContentfulPaintHandler::RecordTiming( - const page_load_metrics::mojom::LargestContentfulPaintTiming& - largest_contentful_paint, - const absl::optional<base::TimeDelta>& - first_input_or_scroll_notified_timestamp, - content::RenderFrameHost* subframe_rfh) { - if (!IsSubframe(subframe_rfh)) { - RecordMainFrameTiming(largest_contentful_paint, - first_input_or_scroll_notified_timestamp); - return; - } - // For subframes - const auto it = subframe_navigation_start_offset_.find( - subframe_rfh->GetFrameTreeNodeId()); - if (it == subframe_navigation_start_offset_.end()) { - // We received timing information for an untracked load. Ignore it. - return; - } - RecordSubframeTiming(largest_contentful_paint, - first_input_or_scroll_notified_timestamp, it->second); - if (!IsSameSite(subframe_rfh->GetLastCommittedURL(), - subframe_rfh->GetMainFrame()->GetLastCommittedURL())) { - RecordCrossSiteSubframeTiming(largest_contentful_paint, it->second); - } -} - const ContentfulPaintTimingInfo& LargestContentfulPaintHandler::MergeMainFrameAndSubframes() const { const ContentfulPaintTimingInfo& main_frame_timing = @@ -255,6 +225,55 @@ return MergeTimingsBySizeAndTime(main_frame_timing, subframe_timing); } +void LargestContentfulPaintHandler::RecordMainFrameTiming( + const page_load_metrics::mojom::LargestContentfulPaintTiming& + largest_contentful_paint, + const absl::optional<base::TimeDelta>& + first_input_or_scroll_notified_timestamp) { + UpdateFirstInputOrScrollNotified( + first_input_or_scroll_notified_timestamp, + /* navigation_start_offset */ base::TimeDelta()); + if (IsValid(largest_contentful_paint.largest_text_paint)) { + main_frame_contentful_paint_.Text().Reset( + largest_contentful_paint.largest_text_paint, + largest_contentful_paint.largest_text_paint_size, + blink::LargestContentfulPaintType::kNone, + /*image_bpp=*/0.0); + } + if (IsValid(largest_contentful_paint.largest_image_paint)) { + main_frame_contentful_paint_.Image().Reset( + largest_contentful_paint.largest_image_paint, + largest_contentful_paint.largest_image_paint_size, + static_cast<blink::LargestContentfulPaintType>( + largest_contentful_paint.type), + largest_contentful_paint.image_bpp); + } +} + +void LargestContentfulPaintHandler::RecordSubFrameTiming( + const page_load_metrics::mojom::LargestContentfulPaintTiming& + largest_contentful_paint, + const absl::optional<base::TimeDelta>& + first_input_or_scroll_notified_timestamp, + content::RenderFrameHost* subframe_rfh, + const GURL& main_frame_url) { + // For subframes + const auto it = subframe_navigation_start_offset_.find( + subframe_rfh->GetFrameTreeNodeId()); + if (it == subframe_navigation_start_offset_.end()) { + // We received timing information for an untracked load. Ignore it. + return; + } + RecordSubFrameTimingInternal(largest_contentful_paint, + first_input_or_scroll_notified_timestamp, + it->second); + // Note that subframe can be in other page like FencedFrames. + // So, we can't know `main_frame_url` without help of PageLoadTracker. + if (!IsSameSite(subframe_rfh->GetLastCommittedURL(), main_frame_url)) { + RecordCrossSiteSubframeTiming(largest_contentful_paint, it->second); + } +} + // We handle subframe and main frame differently. For main frame, we directly // substitute the candidate when we receive a new one. For subframes (plural), // we merge the candidates from different subframes by keeping the largest one. @@ -263,7 +282,7 @@ // should have been able when a large ephemeral element is removed). This is a // trade-off we make to keep a simple algorithm, otherwise we will have to // track one candidate per subframe. -void LargestContentfulPaintHandler::RecordSubframeTiming( +void LargestContentfulPaintHandler::RecordSubFrameTimingInternal( const page_load_metrics::mojom::LargestContentfulPaintTiming& largest_contentful_paint, const absl::optional<base::TimeDelta>& @@ -335,31 +354,6 @@ } } -void LargestContentfulPaintHandler::RecordMainFrameTiming( - const page_load_metrics::mojom::LargestContentfulPaintTiming& - largest_contentful_paint, - const absl::optional<base::TimeDelta>& - first_input_or_scroll_notified_timestamp) { - UpdateFirstInputOrScrollNotified( - first_input_or_scroll_notified_timestamp, - /* navigation_start_offset */ base::TimeDelta()); - if (IsValid(largest_contentful_paint.largest_text_paint)) { - main_frame_contentful_paint_.Text().Reset( - largest_contentful_paint.largest_text_paint, - largest_contentful_paint.largest_text_paint_size, - blink::LargestContentfulPaintType::kNone, - /*image_bpp=*/0.0); - } - if (IsValid(largest_contentful_paint.largest_image_paint)) { - main_frame_contentful_paint_.Image().Reset( - largest_contentful_paint.largest_image_paint, - largest_contentful_paint.largest_image_paint_size, - static_cast<blink::LargestContentfulPaintType>( - largest_contentful_paint.type), - largest_contentful_paint.image_bpp); - } -} - void LargestContentfulPaintHandler::UpdateFirstInputOrScrollNotified( const absl::optional<base::TimeDelta>& candidate_new_time, const base::TimeDelta& navigation_start_offset) {
diff --git a/components/page_load_metrics/browser/observers/core/largest_contentful_paint_handler.h b/components/page_load_metrics/browser/observers/core/largest_contentful_paint_handler.h index a32e739..d7da8067 100644 --- a/components/page_load_metrics/browser/observers/core/largest_contentful_paint_handler.h +++ b/components/page_load_metrics/browser/observers/core/largest_contentful_paint_handler.h
@@ -12,6 +12,7 @@ #include "components/page_load_metrics/common/page_load_timing.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/blink/public/common/performance/largest_contentful_paint_type.h" +#include "url/gurl.h" namespace content { @@ -118,12 +119,18 @@ ContentfulPaintTimingInfo::LargestContentTextOrImage* largest_content_type); - void RecordTiming( + void RecordMainFrameTiming( + const page_load_metrics::mojom::LargestContentfulPaintTiming& + largest_contentful_paint, + const absl::optional<base::TimeDelta>& + first_input_or_scroll_notified_timestamp); + void RecordSubFrameTiming( const page_load_metrics::mojom::LargestContentfulPaintTiming& largest_contentful_paint, const absl::optional<base::TimeDelta>& first_input_or_scroll_notified_timestamp, - content::RenderFrameHost* subframe_rfh); + content::RenderFrameHost* subframe_rfh, + const GURL& main_frame_url); inline void RecordMainFrameTreeNodeId(int main_frame_tree_node_id) { main_frame_tree_node_id_.emplace(main_frame_tree_node_id); } @@ -160,7 +167,7 @@ void OnSubFrameDeleted(int frame_tree_node_id); private: - void RecordSubframeTiming( + void RecordSubFrameTimingInternal( const page_load_metrics::mojom::LargestContentfulPaintTiming& largest_contentful_paint, const absl::optional<base::TimeDelta>& @@ -172,11 +179,6 @@ const page_load_metrics::mojom::LargestContentfulPaintTiming& largest_contentful_paint, const base::TimeDelta& navigation_start_offset); - void RecordMainFrameTiming( - const page_load_metrics::mojom::LargestContentfulPaintTiming& - largest_contentful_paint, - const absl::optional<base::TimeDelta>& - first_input_or_scroll_notified_timestamp); void UpdateFirstInputOrScrollNotified( const absl::optional<base::TimeDelta>& candidate_new_time, const base::TimeDelta& navigation_start_offset);
diff --git a/components/page_load_metrics/browser/page_load_tracker.cc b/components/page_load_metrics/browser/page_load_tracker.cc index 683b820..8cd2c3e4 100644 --- a/components/page_load_metrics/browser/page_load_tracker.cc +++ b/components/page_load_metrics/browser/page_load_tracker.cc
@@ -806,14 +806,12 @@ const mojom::PaintTimingPtr& paint_timing = metrics_update_dispatcher_.timing().paint_timing; - largest_contentful_paint_handler_.RecordTiming( + largest_contentful_paint_handler_.RecordMainFrameTiming( *paint_timing->largest_contentful_paint, - paint_timing->first_input_or_scroll_notified_timestamp, - nullptr /* subframe_rfh */); - experimental_largest_contentful_paint_handler_.RecordTiming( + paint_timing->first_input_or_scroll_notified_timestamp); + experimental_largest_contentful_paint_handler_.RecordMainFrameTiming( *paint_timing->experimental_largest_contentful_paint, - paint_timing->first_input_or_scroll_notified_timestamp, - nullptr /* subframe_rfh */); + paint_timing->first_input_or_scroll_notified_timestamp); for (const auto& observer : observers_) { DispatchObserverTimingCallbacks( @@ -834,12 +832,12 @@ const mojom::PageLoadTiming& timing) { DCHECK(rfh->GetParentOrOuterDocument()); const mojom::PaintTimingPtr& paint_timing = timing.paint_timing; - largest_contentful_paint_handler_.RecordTiming( + largest_contentful_paint_handler_.RecordSubFrameTiming( *paint_timing->largest_contentful_paint, - paint_timing->first_input_or_scroll_notified_timestamp, rfh); - experimental_largest_contentful_paint_handler_.RecordTiming( + paint_timing->first_input_or_scroll_notified_timestamp, rfh, url_); + experimental_largest_contentful_paint_handler_.RecordSubFrameTiming( *paint_timing->experimental_largest_contentful_paint, - paint_timing->first_input_or_scroll_notified_timestamp, rfh); + paint_timing->first_input_or_scroll_notified_timestamp, rfh, url_); for (const auto& observer : observers_) { observer->OnTimingUpdate(rfh, timing); }
diff --git a/components/permissions/permission_request_manager.cc b/components/permissions/permission_request_manager.cc index 6f43ff4..74bc276 100644 --- a/components/permissions/permission_request_manager.cc +++ b/components/permissions/permission_request_manager.cc
@@ -70,6 +70,10 @@ "possible and submit your site for another review. Learn more at " "https://support.google.com/webtools/answer/9799048"; +constexpr char kDisruptiveNotificationBehaviorEnforcementMessage[] = + "Chrome is blocking notification permission requests on this site because " + "the site exhibits behaviors that may be disruptive to users."; + namespace { // When there are multiple permissions requests in @@ -730,6 +734,10 @@ case QuietUiReason::kTriggeredDueToAbusiveContent: LogWarningToConsole(kAbusiveNotificationContentEnforcementMessage); break; + case QuietUiReason::kTriggeredDueToDisruptiveBehavior: + LogWarningToConsole( + kDisruptiveNotificationBehaviorEnforcementMessage); + break; } base::RecordAction(base::UserMetricsAction( "Notifications.Quiet.PermissionRequestShown")); @@ -973,6 +981,7 @@ return false; case QuietUiReason::kTriggeredDueToAbusiveRequests: case QuietUiReason::kTriggeredDueToAbusiveContent: + case QuietUiReason::kTriggeredDueToDisruptiveBehavior: return true; } } @@ -1001,6 +1010,8 @@ case WarningReason::kAbusiveContent: LogWarningToConsole(kAbusiveNotificationContentWarningMessage); break; + case WarningReason::kDisruptiveBehavior: + break; } } @@ -1065,6 +1076,7 @@ case QuietUiReason::kTriggeredByCrowdDeny: case QuietUiReason::kTriggeredDueToAbusiveRequests: case QuietUiReason::kTriggeredDueToAbusiveContent: + case QuietUiReason::kTriggeredDueToDisruptiveBehavior: return PermissionPromptDispositionReason::SAFE_BROWSING_VERDICT; case QuietUiReason::kServicePredictedVeryUnlikelyGrant: return PermissionPromptDispositionReason::PREDICTION_SERVICE;
diff --git a/components/permissions/permission_ui_selector.cc b/components/permissions/permission_ui_selector.cc index 1599dad..58dc8e1 100644 --- a/components/permissions/permission_ui_selector.cc +++ b/components/permissions/permission_ui_selector.cc
@@ -21,6 +21,7 @@ case QuietUiReason::kTriggeredByCrowdDeny: case QuietUiReason::kTriggeredDueToAbusiveRequests: case QuietUiReason::kTriggeredDueToAbusiveContent: + case QuietUiReason::kTriggeredDueToDisruptiveBehavior: return true; } }
diff --git a/components/permissions/permission_ui_selector.h b/components/permissions/permission_ui_selector.h index bd6c6b9..70ba24505 100644 --- a/components/permissions/permission_ui_selector.h +++ b/components/permissions/permission_ui_selector.h
@@ -27,11 +27,13 @@ kTriggeredDueToAbusiveContent, kServicePredictedVeryUnlikelyGrant, kOnDevicePredictedVeryUnlikelyGrant, + kTriggeredDueToDisruptiveBehavior, }; enum class WarningReason { kAbusiveRequests, kAbusiveContent, + kDisruptiveBehavior, }; struct Decision {
diff --git a/components/policy/core/browser/policy_conversions.cc b/components/policy/core/browser/policy_conversions.cc index e6847d9..2d13c5d 100644 --- a/components/policy/core/browser/policy_conversions.cc +++ b/components/policy/core/browser/policy_conversions.cc
@@ -43,19 +43,6 @@ PolicyConversions::~PolicyConversions() = default; -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) -PolicyConversions& PolicyConversions::WithUpdaterPolicies( - std::unique_ptr<PolicyMap> policies) { - client()->SetUpdaterPolicies(std::move(policies)); - return *this; -} -PolicyConversions& PolicyConversions::WithUpdaterPolicySchemas( - PolicyToSchemaMap schemas) { - client()->SetUpdaterPolicySchemas(std::move(schemas)); - return *this; -} -#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - PolicyConversions& PolicyConversions::EnableConvertTypes(bool enabled) { client_->EnableConvertTypes(enabled); return *this; @@ -106,21 +93,6 @@ : PolicyConversions(std::move(client)) {} DictionaryPolicyConversions::~DictionaryPolicyConversions() = default; -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) -DictionaryPolicyConversions& DictionaryPolicyConversions::WithUpdaterPolicies( - std::unique_ptr<PolicyMap> policies) { - PolicyConversions::WithUpdaterPolicies(std::move(policies)); - return *this; -} - -DictionaryPolicyConversions& -DictionaryPolicyConversions::WithUpdaterPolicySchemas( - PolicyToSchemaMap schemas) { - PolicyConversions::WithUpdaterPolicySchemas(std::move(schemas)); - return *this; -} -#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - DictionaryPolicyConversions& DictionaryPolicyConversions::EnableConvertTypes( bool enabled) { PolicyConversions::EnableConvertTypes(enabled); @@ -201,11 +173,6 @@ #endif // BUILDFLAG(ENABLE_EXTENSIONS) } -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - if (client()->HasUpdaterPolicies()) - all_policies.Set("updaterPolicies", client()->GetUpdaterPolicies()); -#endif - #if BUILDFLAG(IS_CHROMEOS_ASH) all_policies.Set("deviceLocalAccountPolicies", GetDeviceLocalAccountPolicies()); @@ -342,12 +309,8 @@ // table is not shown in chrome://policy. all_policies.Append(GetPrecedencePolicies()); #endif // !BUILDFLAG(IS_CHROMEOS) - -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - if (client()->HasUpdaterPolicies()) - all_policies.Append(GetUpdaterPolicies()); -#endif } + #if BUILDFLAG(ENABLE_EXTENSIONS) if (extension_policies_enabled_) { for (auto& extension_policy : GetExtensionPolicies()) { @@ -368,28 +331,6 @@ return all_policies; } -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) -Value::Dict ArrayPolicyConversions::GetUpdaterPolicies() { - Value::Dict chrome_policies_data; - chrome_policies_data.Set("name", "Google Update Policies"); - chrome_policies_data.Set("id", "updater"); - chrome_policies_data.Set("policies", client()->GetUpdaterPolicies()); - return chrome_policies_data; -} - -ArrayPolicyConversions& ArrayPolicyConversions::WithUpdaterPolicies( - std::unique_ptr<PolicyMap> policies) { - PolicyConversions::WithUpdaterPolicies(std::move(policies)); - return *this; -} - -ArrayPolicyConversions& ArrayPolicyConversions::WithUpdaterPolicySchemas( - PolicyToSchemaMap schemas) { - PolicyConversions::WithUpdaterPolicySchemas(std::move(schemas)); - return *this; -} -#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - Value::Dict ArrayPolicyConversions::GetChromePolicies() { Value::Dict chrome_policies_data; chrome_policies_data.Set("id", "chrome");
diff --git a/components/policy/core/browser/policy_conversions.h b/components/policy/core/browser/policy_conversions.h index 4676c03..a33b660 100644 --- a/components/policy/core/browser/policy_conversions.h +++ b/components/policy/core/browser/policy_conversions.h
@@ -71,16 +71,6 @@ // from ArrayPolicyConversions. virtual PolicyConversions& EnableExtensionPolicies(bool enabled); -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - // Sets the updater policies. - virtual PolicyConversions& WithUpdaterPolicies( - std::unique_ptr<PolicyMap> policies); - - // Sets the updater policy schemas. - virtual PolicyConversions& WithUpdaterPolicySchemas( - PolicyToSchemaMap schemas); -#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - // Returns the policy data as a JSON string; virtual std::string ToJSON() = 0; @@ -119,16 +109,6 @@ DictionaryPolicyConversions& EnableExtensionPolicies(bool enabled) override; -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - // Sets the updater policies. - DictionaryPolicyConversions& WithUpdaterPolicies( - std::unique_ptr<PolicyMap> policies) override; - - // Sets the updater policy schemas. - DictionaryPolicyConversions& WithUpdaterPolicySchemas( - PolicyToSchemaMap schemas) override; -#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - #if BUILDFLAG(ENABLE_EXTENSIONS) base::Value::Dict GetExtensionPolicies(); #endif // BUILDFLAG(ENABLE_EXTENSIONS) @@ -170,16 +150,6 @@ ArrayPolicyConversions& EnableExtensionPolicies(bool enabled) override; -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - // Sets the updater policies. - ArrayPolicyConversions& WithUpdaterPolicies( - std::unique_ptr<PolicyMap> policies) override; - - // Sets the updater policy schemas. - ArrayPolicyConversions& WithUpdaterPolicySchemas( - PolicyToSchemaMap schemas) override; -#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - std::string ToJSON() override; base::Value::List ToValueList(); @@ -199,10 +169,6 @@ base::Value::List GetExtensionPolicies(); #endif // BUILDFLAG(ENABLE_EXTENSIONS) -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - base::Value::Dict GetUpdaterPolicies(); -#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - #if BUILDFLAG(IS_CHROMEOS_LACROS) base::Value::Dict additional_chrome_policies_; #endif // BUILDFLAG(IS_CHROMEOS_LACROS)
diff --git a/components/policy/core/browser/policy_conversions_client.cc b/components/policy/core/browser/policy_conversions_client.cc index 3c609a73..8870737 100644 --- a/components/policy/core/browser/policy_conversions_client.cc +++ b/components/policy/core/browser/policy_conversions_client.cc
@@ -61,13 +61,6 @@ drop_default_values_enabled_ = enabled; } -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) -void PolicyConversionsClient::SetUpdaterPolicies( - std::unique_ptr<PolicyMap> policies) { - updater_policies_ = std::move(policies); -} -#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - std::string PolicyConversionsClient::ConvertValueToJSON( const Value& value) const { std::string json_string; @@ -433,21 +426,12 @@ } #if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) -Value::Dict PolicyConversionsClient::GetUpdaterPolicies() { - return updater_policies_ - ? GetPolicyValues(*updater_policies_, nullptr, PoliciesSet(), - PoliciesSet(), updater_policy_schemas_) - : base::Value::Dict(); -} - -bool PolicyConversionsClient::PolicyConversionsClient::HasUpdaterPolicies() - const { - return !!updater_policies_; -} - -void PolicyConversionsClient::SetUpdaterPolicySchemas( - PolicyConversions::PolicyToSchemaMap schemas) { - updater_policy_schemas_ = std::move(schemas); +Value::Dict PolicyConversionsClient::ConvertUpdaterPolicies( + PolicyMap updater_policies, + absl::optional<PolicyConversions::PolicyToSchemaMap> + updater_policy_schemas) { + return GetPolicyValues(updater_policies, nullptr, PoliciesSet(), + PoliciesSet(), updater_policy_schemas); } #endif // BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
diff --git a/components/policy/core/browser/policy_conversions_client.h b/components/policy/core/browser/policy_conversions_client.h index 6cc847a..4d735771 100644 --- a/components/policy/core/browser/policy_conversions_client.h +++ b/components/policy/core/browser/policy_conversions_client.h
@@ -63,16 +63,10 @@ void SetDropDefaultValues(bool enabled); #if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - // Sets the updater policies. - void SetUpdaterPolicies(std::unique_ptr<PolicyMap> policies); - - // Returns true if this client is able to return information on the updater's - // policies. - bool HasUpdaterPolicies() const; - base::Value::Dict GetUpdaterPolicies(); - - // Sets the updater policy schemas. - void SetUpdaterPolicySchemas(PolicyConversions::PolicyToSchemaMap schemas); + base::Value::Dict ConvertUpdaterPolicies( + PolicyMap updater_policies, + absl::optional<PolicyConversions::PolicyToSchemaMap> + updater_policy_schemas); #endif // BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) // Converts the given |value| to JSON, respecting the configuration @@ -172,10 +166,6 @@ private: friend class PolicyConversionsClientTest; -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - std::unique_ptr<PolicyMap> updater_policies_; - absl::optional<PolicyConversions::PolicyToSchemaMap> updater_policy_schemas_; -#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) && BUILDFLAG(IS_WIN) bool convert_types_enabled_ = true; bool convert_values_enabled_ = false;
diff --git a/components/privacy_sandbox/privacy_sandbox_features.cc b/components/privacy_sandbox/privacy_sandbox_features.cc index 02f5bcbf..f4604e48 100644 --- a/components/privacy_sandbox/privacy_sandbox_features.cc +++ b/components/privacy_sandbox/privacy_sandbox_features.cc
@@ -35,5 +35,7 @@ const base::Feature kPrivacySandboxFirstPartySetsUI{ "PrivacySandboxFirstPartySetsUI", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::FeatureParam<bool> kPrivacySandboxFirstPartySetsUISampleSets{ + &kPrivacySandboxFirstPartySetsUI, "use-sample-sets", false}; } // namespace privacy_sandbox
diff --git a/components/privacy_sandbox/privacy_sandbox_features.h b/components/privacy_sandbox/privacy_sandbox_features.h index be5a0ae..5b9a9fa 100644 --- a/components/privacy_sandbox/privacy_sandbox_features.h +++ b/components/privacy_sandbox/privacy_sandbox_features.h
@@ -51,6 +51,10 @@ // Enables the First Party Sets UI. extern const base::Feature kPrivacySandboxFirstPartySetsUI; +// Populates First Party Sets information with sample membership information, +// for testing purposes only. +extern const base::FeatureParam<bool> kPrivacySandboxFirstPartySetsUISampleSets; + } // namespace privacy_sandbox #endif // COMPONENTS_PRIVACY_SANDBOX_PRIVACY_SANDBOX_FEATURES_H_
diff --git a/components/services/screen_ai/buildflags/features.gni b/components/services/screen_ai/buildflags/features.gni index 4b48eb12..7c45840a 100644 --- a/components/services/screen_ai/buildflags/features.gni +++ b/components/services/screen_ai/buildflags/features.gni
@@ -7,6 +7,5 @@ declare_args() { # Screen AI service is still not supported on other platforms. - enable_screen_ai_service = - is_linux || is_mac || is_chromeos_ash || is_chromeos_lacros + enable_screen_ai_service = is_linux || is_mac || is_chromeos }
diff --git a/components/site_isolation/site_isolation_policy_unittest.cc b/components/site_isolation/site_isolation_policy_unittest.cc index 9f5b14be..11abb44 100644 --- a/components/site_isolation/site_isolation_policy_unittest.cc +++ b/components/site_isolation/site_isolation_policy_unittest.cc
@@ -13,7 +13,6 @@ #include "base/test/metrics/histogram_tester.h" #include "base/test/mock_entropy_provider.h" #include "base/test/scoped_feature_list.h" -#include "base/test/scoped_field_trial_list_resetter.h" #include "base/time/time.h" #include "build/branding_buildflags.h" #include "build/build_config.h" @@ -692,8 +691,9 @@ // or disabled state. class PasswordSiteIsolationFieldTrialTest : public BaseSiteIsolationTest { public: - explicit PasswordSiteIsolationFieldTrialTest(bool should_enable) - : field_trial_list_(std::make_unique<base::MockEntropyProvider>()) { + explicit PasswordSiteIsolationFieldTrialTest(bool should_enable) { + empty_feature_scope_.InitWithEmptyFeatureAndFieldTrialLists(); + const std::string kTrialName = "PasswordSiteIsolation"; const std::string kGroupName = "FooGroup"; // unused scoped_refptr<base::FieldTrial> trial = @@ -736,9 +736,12 @@ } protected: - base::test::ScopedFieldTrialListResetter trial_list_resetter_; + // |empty_feature_scope_| is used to prepare an environment with empty + // features and field trial lists. + base::test::ScopedFeatureList empty_feature_scope_; + // |feature_list_| is used to enable and disable features for + // PasswordSiteIsolationFieldTrialTest. base::test::ScopedFeatureList feature_list_; - base::FieldTrialList field_trial_list_; }; class EnabledPasswordSiteIsolationFieldTrialTest @@ -905,8 +908,9 @@ // or disabled state. class StrictOriginIsolationFieldTrialTest : public BaseSiteIsolationTest { public: - explicit StrictOriginIsolationFieldTrialTest(bool should_enable) - : field_trial_list_(std::make_unique<base::MockEntropyProvider>()) { + explicit StrictOriginIsolationFieldTrialTest(bool should_enable) { + empty_feature_scope_.InitWithEmptyFeatureAndFieldTrialLists(); + const std::string kTrialName = "StrictOriginIsolation"; const std::string kGroupName = "FooGroup"; // unused scoped_refptr<base::FieldTrial> trial = @@ -949,9 +953,12 @@ } protected: - base::test::ScopedFieldTrialListResetter trial_list_resetter_; + // |empty_feature_scope_| is used to prepare an environment with empty + // features and field trial lists. + base::test::ScopedFeatureList empty_feature_scope_; + // |feature_list_| is used to enable and disable features for + // StrictOriginIsolationFieldTrialTest. base::test::ScopedFeatureList feature_list_; - base::FieldTrialList field_trial_list_; }; class EnabledStrictOriginIsolationFieldTrialTest
diff --git a/components/spellcheck/common/spellcheck_result.h b/components/spellcheck/common/spellcheck_result.h index 9f81769..c332a127 100644 --- a/components/spellcheck/common/spellcheck_result.h +++ b/components/spellcheck/common/spellcheck_result.h
@@ -39,8 +39,19 @@ SpellCheckResult(const SpellCheckResult&); Decoration decoration; + + // The zero-based index where the misspelling starts. For spell check results + // returned by the local spell check infrastructure, this is measured by + // the code point count, i.e. each surrogate pair, such as emojis, will count + // for 2 positions. For results returned by enhanced (server side) spell + // check, positions are based on "logical" characters, i.e. emojis and their + // modifiers count for 1. int location; + + // The length of the misspelled word. The same code point / logical character + // count distinction as for `location` applies. int length; + std::vector<std::u16string> replacements; bool spelling_service_used = false; };
diff --git a/components/sync/chromeos/lacros/fake_sync_explicit_passphrase_client_ash.cc b/components/sync/chromeos/lacros/fake_sync_explicit_passphrase_client_ash.cc index 391d29c..971b5e0 100644 --- a/components/sync/chromeos/lacros/fake_sync_explicit_passphrase_client_ash.cc +++ b/components/sync/chromeos/lacros/fake_sync_explicit_passphrase_client_ash.cc
@@ -50,6 +50,8 @@ return; } stored_nigori_key_ = std::move(nigori_key); + expected_nigori_key_ = nullptr; + std::move(passphrase_provided_callback_).Run(); } void FakeSyncExplicitPassphraseClientAsh::BindReceiver( @@ -68,8 +70,10 @@ } void FakeSyncExplicitPassphraseClientAsh::MimicPassphraseRequired( - crosapi::mojom::NigoriKeyPtr expected_nigori_key) { + crosapi::mojom::NigoriKeyPtr expected_nigori_key, + base::OnceClosure passphrase_provided_callback) { expected_nigori_key_ = std::move(expected_nigori_key); + passphrase_provided_callback_ = std::move(passphrase_provided_callback); for (auto& observer : observers_) { observer->OnPassphraseRequired(); } @@ -82,8 +86,7 @@ } bool FakeSyncExplicitPassphraseClientAsh::IsPassphraseRequired() const { - return expected_account_key_ && - !expected_nigori_key_.Equals(stored_nigori_key_); + return !expected_nigori_key_.is_null(); } bool FakeSyncExplicitPassphraseClientAsh::IsGetDecryptionNigoriKeyCalled()
diff --git a/components/sync/chromeos/lacros/fake_sync_explicit_passphrase_client_ash.h b/components/sync/chromeos/lacros/fake_sync_explicit_passphrase_client_ash.h index 3b669ea8..838afc4 100644 --- a/components/sync/chromeos/lacros/fake_sync_explicit_passphrase_client_ash.h +++ b/components/sync/chromeos/lacros/fake_sync_explicit_passphrase_client_ash.h
@@ -5,6 +5,7 @@ #ifndef COMPONENTS_SYNC_CHROMEOS_LACROS_FAKE_SYNC_EXPLICIT_PASSPHRASE_CLIENT_ASH_H_ #define COMPONENTS_SYNC_CHROMEOS_LACROS_FAKE_SYNC_EXPLICIT_PASSPHRASE_CLIENT_ASH_H_ +#include "base/callback.h" #include "chromeos/crosapi/mojom/account_manager.mojom.h" #include "chromeos/crosapi/mojom/sync.mojom.h" #include "mojo/public/cpp/bindings/pending_receiver.h" @@ -37,7 +38,8 @@ receiver); void MimicPassphraseAvailable(crosapi::mojom::NigoriKeyPtr nigori_key); void MimicPassphraseRequired( - crosapi::mojom::NigoriKeyPtr expected_nigori_key); + crosapi::mojom::NigoriKeyPtr expected_nigori_key, + base::OnceClosure passphrase_provided_callback = base::DoNothing()); void SetExpectedAccountKey(crosapi::mojom::AccountKeyPtr account_key); bool IsPassphraseRequired() const; @@ -53,6 +55,8 @@ crosapi::mojom::NigoriKeyPtr expected_nigori_key_; crosapi::mojom::AccountKeyPtr expected_account_key_; + base::OnceClosure passphrase_provided_callback_; + bool get_decryption_nigori_key_called_ = false; bool set_decryption_nigori_key_called_ = false; };
diff --git a/components/sync/driver/fake_sync_service.cc b/components/sync/driver/fake_sync_service.cc index 405f14d4e..d978764 100644 --- a/components/sync/driver/fake_sync_service.cc +++ b/components/sync/driver/fake_sync_service.cc
@@ -112,7 +112,8 @@ return SyncCycleSnapshot(); } -std::unique_ptr<base::Value> FakeSyncService::GetTypeStatusMapForDebugging() { +std::unique_ptr<base::Value> FakeSyncService::GetTypeStatusMapForDebugging() + const { return nullptr; }
diff --git a/components/sync/driver/fake_sync_service.h b/components/sync/driver/fake_sync_service.h index 34e6b92f..671ce266 100644 --- a/components/sync/driver/fake_sync_service.h +++ b/components/sync/driver/fake_sync_service.h
@@ -51,7 +51,7 @@ bool QueryDetailedSyncStatusForDebugging(SyncStatus* result) const override; base::Time GetLastSyncedTimeForDebugging() const override; SyncCycleSnapshot GetLastCycleSnapshotForDebugging() const override; - std::unique_ptr<base::Value> GetTypeStatusMapForDebugging() override; + std::unique_ptr<base::Value> GetTypeStatusMapForDebugging() const override; void GetEntityCountsForDebugging( base::OnceCallback<void(const std::vector<TypeEntitiesCount>&)> callback) const override;
diff --git a/components/sync/driver/mock_sync_service.h b/components/sync/driver/mock_sync_service.h index cf506d0..6453b67 100644 --- a/components/sync/driver/mock_sync_service.h +++ b/components/sync/driver/mock_sync_service.h
@@ -101,7 +101,7 @@ MOCK_METHOD(std::unique_ptr<base::Value>, GetTypeStatusMapForDebugging, (), - (override)); + (const override)); MOCK_METHOD(void, GetEntityCountsForDebugging, (base::OnceCallback<void(const std::vector<TypeEntitiesCount>&)>),
diff --git a/components/sync/driver/sync_service.h b/components/sync/driver/sync_service.h index 968a94c..31bc424c 100644 --- a/components/sync/driver/sync_service.h +++ b/components/sync/driver/sync_service.h
@@ -408,7 +408,7 @@ // chrome://sync-internals page. It returns a ListValue rather than a // DictionaryValue in part to make it easier to iterate over its elements when // constructing that page. - virtual std::unique_ptr<base::Value> GetTypeStatusMapForDebugging() = 0; + virtual std::unique_ptr<base::Value> GetTypeStatusMapForDebugging() const = 0; // Retrieves the TypeEntitiesCount for all registered data types. virtual void GetEntityCountsForDebugging(
diff --git a/components/sync/driver/sync_service_impl.cc b/components/sync/driver/sync_service_impl.cc index 5938c5d..39d2c02 100644 --- a/components/sync/driver/sync_service_impl.cc +++ b/components/sync/driver/sync_service_impl.cc
@@ -1300,7 +1300,8 @@ return migrator_.get(); } -std::unique_ptr<base::Value> SyncServiceImpl::GetTypeStatusMapForDebugging() { +std::unique_ptr<base::Value> SyncServiceImpl::GetTypeStatusMapForDebugging() + const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); auto result = std::make_unique<base::ListValue>();
diff --git a/components/sync/driver/sync_service_impl.h b/components/sync/driver/sync_service_impl.h index dc2adb5..ec0a179 100644 --- a/components/sync/driver/sync_service_impl.h +++ b/components/sync/driver/sync_service_impl.h
@@ -146,7 +146,7 @@ bool QueryDetailedSyncStatusForDebugging(SyncStatus* result) const override; base::Time GetLastSyncedTimeForDebugging() const override; SyncCycleSnapshot GetLastCycleSnapshotForDebugging() const override; - std::unique_ptr<base::Value> GetTypeStatusMapForDebugging() override; + std::unique_ptr<base::Value> GetTypeStatusMapForDebugging() const override; void GetEntityCountsForDebugging( base::OnceCallback<void(const std::vector<TypeEntitiesCount>&)> callback) const override;
diff --git a/components/sync/driver/test_sync_service.cc b/components/sync/driver/test_sync_service.cc index 628e292..2ca6db4 100644 --- a/components/sync/driver/test_sync_service.cc +++ b/components/sync/driver/test_sync_service.cc
@@ -241,7 +241,8 @@ return last_cycle_snapshot_; } -std::unique_ptr<base::Value> TestSyncService::GetTypeStatusMapForDebugging() { +std::unique_ptr<base::Value> TestSyncService::GetTypeStatusMapForDebugging() + const { return std::make_unique<base::ListValue>(); }
diff --git a/components/sync/driver/test_sync_service.h b/components/sync/driver/test_sync_service.h index 4e0cb923..bfe9f10 100644 --- a/components/sync/driver/test_sync_service.h +++ b/components/sync/driver/test_sync_service.h
@@ -89,7 +89,7 @@ bool QueryDetailedSyncStatusForDebugging(SyncStatus* result) const override; base::Time GetLastSyncedTimeForDebugging() const override; SyncCycleSnapshot GetLastCycleSnapshotForDebugging() const override; - std::unique_ptr<base::Value> GetTypeStatusMapForDebugging() override; + std::unique_ptr<base::Value> GetTypeStatusMapForDebugging() const override; void GetEntityCountsForDebugging( base::OnceCallback<void(const std::vector<TypeEntitiesCount>&)> callback) const override;
diff --git a/components/sync_device_info/BUILD.gn b/components/sync_device_info/BUILD.gn index ed4e2ae..6730ce5 100644 --- a/components/sync_device_info/BUILD.gn +++ b/components/sync_device_info/BUILD.gn
@@ -54,11 +54,15 @@ sources += [ "local_device_info_util_android.cc" ] } + if (is_chromeos) { + sources += [ "local_device_info_util_chromeos.cc" ] + } + if (is_ios) { sources += [ "local_device_info_util_ios.mm" ] } - if (is_linux || is_chromeos) { + if (is_linux) { sources += [ "local_device_info_util_linux.cc" ] } @@ -78,8 +82,7 @@ sources += [ "local_device_info_util_win.cc" ] } - if (is_chromeos_ash) { - # Required by device_info_util_linux.cc on Chrome OS. + if (is_chromeos) { deps += [ "//chromeos/constants", "//chromeos/system",
diff --git a/components/sync_device_info/device_info_sync_client.h b/components/sync_device_info/device_info_sync_client.h index bd64fc0..67766d82 100644 --- a/components/sync_device_info/device_info_sync_client.h +++ b/components/sync_device_info/device_info_sync_client.h
@@ -23,9 +23,6 @@ virtual ~DeviceInfoSyncClient(); virtual std::string GetSigninScopedDeviceId() const = 0; - // TODO(crbug.com/1324936): This only returns false for one embedder, it can - // be replaced with a check for whether send-tab-to-self is "enabled" - // (preconditions met?). virtual bool GetSendTabToSelfReceivingEnabled() const = 0; virtual absl::optional<DeviceInfo::SharingInfo> GetLocalSharingInfo() const = 0;
diff --git a/components/sync_device_info/local_device_info_util.cc b/components/sync_device_info/local_device_info_util.cc index 8da7db4a..6f32d77 100644 --- a/components/sync_device_info/local_device_info_util.cc +++ b/components/sync_device_info/local_device_info_util.cc
@@ -22,6 +22,13 @@ namespace syncer { +// Declared here but defined in platform-specific files. +std::string GetPersonalizableDeviceNameInternal(); + +#if BUILDFLAG(IS_CHROMEOS) +std::string GetChromeOSDeviceNameFromType(); +#endif + LocalDeviceNameInfo::LocalDeviceNameInfo() = default; LocalDeviceNameInfo::LocalDeviceNameInfo(const LocalDeviceNameInfo& other) = default; @@ -39,7 +46,7 @@ base::ScopedClosureRunner done_closure, base::SysInfo::HardwareInfo hardware_info) { name_info_ptr->manufacturer_name = std::move(hardware_info.manufacturer); -#if BUILDFLAG(IS_CHROMEOS_ASH) +#if BUILDFLAG(IS_CHROMEOS) // For ChromeOS the returned model values are product code names like Eve. We // want to use generic names like Chromebook. name_info_ptr->model_name = GetChromeOSDeviceNameFromType(); @@ -68,13 +75,10 @@ } // namespace -// Declared here but defined in platform-specific files. -std::string GetPersonalizableDeviceNameInternal(); - sync_pb::SyncEnums::DeviceType GetLocalDeviceType() { -#if BUILDFLAG(IS_CHROMEOS_ASH) +#if BUILDFLAG(IS_CHROMEOS) return sync_pb::SyncEnums_DeviceType_TYPE_CROS; -#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS) +#elif BUILDFLAG(IS_LINUX) return sync_pb::SyncEnums_DeviceType_TYPE_LINUX; #elif BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS) return ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET
diff --git a/components/sync_device_info/local_device_info_util.h b/components/sync_device_info/local_device_info_util.h index 7afce40a..e0feae18 100644 --- a/components/sync_device_info/local_device_info_util.h +++ b/components/sync_device_info/local_device_info_util.h
@@ -8,7 +8,6 @@ #include <string> #include "base/callback_forward.h" -#include "build/chromeos_buildflags.h" #include "components/sync/protocol/sync_enums.pb.h" namespace syncer { @@ -37,10 +36,6 @@ sync_pb::SyncEnums::DeviceType GetLocalDeviceType(); -#if BUILDFLAG(IS_CHROMEOS_ASH) -std::string GetChromeOSDeviceNameFromType(); -#endif - // Returns the personalizable device name. This may contain // personally-identifiable information - e.g. Alex's MacbookPro. std::string GetPersonalizableDeviceNameBlocking();
diff --git a/components/sync_device_info/local_device_info_util_chromeos.cc b/components/sync_device_info/local_device_info_util_chromeos.cc new file mode 100644 index 0000000..063e4f3 --- /dev/null +++ b/components/sync_device_info/local_device_info_util_chromeos.cc
@@ -0,0 +1,31 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <string> + +#include "chromeos/constants/devicetype.h" + +namespace syncer { + +std::string GetChromeOSDeviceNameFromType() { + switch (chromeos::GetDeviceType()) { + case chromeos::DeviceType::kChromebase: + return "Chromebase"; + case chromeos::DeviceType::kChromebit: + return "Chromebit"; + case chromeos::DeviceType::kChromebook: + return "Chromebook"; + case chromeos::DeviceType::kChromebox: + return "Chromebox"; + case chromeos::DeviceType::kUnknown: + break; + } + return "Chromebook"; +} + +std::string GetPersonalizableDeviceNameInternal() { + return GetChromeOSDeviceNameFromType(); +} + +} // namespace syncer
diff --git a/components/sync_device_info/local_device_info_util_linux.cc b/components/sync_device_info/local_device_info_util_linux.cc index 30f8bfb..e076504c 100644 --- a/components/sync_device_info/local_device_info_util_linux.cc +++ b/components/sync_device_info/local_device_info_util_linux.cc
@@ -8,42 +8,15 @@ #include <string> #include "base/linux_util.h" -#include "build/chromeos_buildflags.h" - -#if BUILDFLAG(IS_CHROMEOS_ASH) -#include "chromeos/constants/devicetype.h" // nogncheck -#endif namespace syncer { -#if BUILDFLAG(IS_CHROMEOS_ASH) -std::string GetChromeOSDeviceNameFromType() { - switch (chromeos::GetDeviceType()) { - case chromeos::DeviceType::kChromebase: - return "Chromebase"; - case chromeos::DeviceType::kChromebit: - return "Chromebit"; - case chromeos::DeviceType::kChromebook: - return "Chromebook"; - case chromeos::DeviceType::kChromebox: - return "Chromebox"; - case chromeos::DeviceType::kUnknown: - break; - } - return "Chromebook"; -} -#endif - std::string GetPersonalizableDeviceNameInternal() { -#if BUILDFLAG(IS_CHROMEOS_ASH) - return GetChromeOSDeviceNameFromType(); -#else char hostname[HOST_NAME_MAX]; if (gethostname(hostname, HOST_NAME_MAX) == 0) { // Success. return hostname; } return base::GetLinuxDistro(); -#endif } } // namespace syncer
diff --git a/components/ukm/ukm_service.cc b/components/ukm/ukm_service.cc index 23984bf..2dda24d 100644 --- a/components/ukm/ukm_service.cc +++ b/components/ukm/ukm_service.cc
@@ -309,7 +309,8 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (initialize_complete_) BuildAndStoreLog(); - reporting_service_.ukm_log_store()->TrimAndPersistUnsentLogs(); + reporting_service_.ukm_log_store()->TrimAndPersistUnsentLogs( + /*overwrite_in_memory_store=*/true); } void UkmService::Purge() {
diff --git a/components/variations/entropy_provider_unittest.cc b/components/variations/entropy_provider_unittest.cc index d5b07db9..953112a 100644 --- a/components/variations/entropy_provider_unittest.cc +++ b/components/variations/entropy_provider_unittest.cc
@@ -15,7 +15,7 @@ #include "base/guid.h" #include "base/rand_util.h" #include "base/strings/string_number_conversions.h" -#include "base/test/scoped_field_trial_list_resetter.h" +#include "base/test/scoped_feature_list.h" #include "components/variations/hashing.h" #include "testing/gtest/include/gtest/gtest.h" @@ -180,7 +180,9 @@ } // namespace TEST(EntropyProviderTest, UseOneTimeRandomizationSHA1) { - base::test::ScopedFieldTrialListResetter resetter; + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitWithNullFeatureAndFieldTrialLists(); + // Simply asserts that two trials using one-time randomization // that have different names, normally generate different results. // @@ -210,7 +212,9 @@ } TEST(EntropyProviderTest, UseOneTimeRandomizationNormalizedMurmurHash) { - base::test::ScopedFieldTrialListResetter resetter; + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitWithNullFeatureAndFieldTrialLists(); + // Simply asserts that two trials using one-time randomization // that have different names, normally generate different results. // @@ -241,7 +245,9 @@ } TEST(EntropyProviderTest, UseOneTimeRandomizationWithCustomSeedSHA1) { - base::test::ScopedFieldTrialListResetter resetter; + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitWithNullFeatureAndFieldTrialLists(); + // Ensures that two trials with different names but the same custom seed used // for one time randomization produce the same group assignments. base::FieldTrialList field_trial_list( @@ -269,7 +275,9 @@ TEST(EntropyProviderTest, UseOneTimeRandomizationWithCustomSeedNormalizedMurmurHash) { - base::test::ScopedFieldTrialListResetter resetter; + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitWithNullFeatureAndFieldTrialLists(); + // Ensures that two trials with different names but the same custom seed used // for one time randomization produce the same group assignments. base::FieldTrialList field_trial_list(
diff --git a/components/variations/service/variations_field_trial_creator_unittest.cc b/components/variations/service/variations_field_trial_creator_unittest.cc index 850508a..825d230 100644 --- a/components/variations/service/variations_field_trial_creator_unittest.cc +++ b/components/variations/service/variations_field_trial_creator_unittest.cc
@@ -23,7 +23,6 @@ #include "base/strings/stringprintf.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/mock_entropy_provider.h" -#include "base/test/scoped_field_trial_list_resetter.h" #include "base/test/task_environment.h" #include "base/time/time.h" #include "base/version.h"
diff --git a/components/variations/variations_params_manager.cc b/components/variations/variations_params_manager.cc index f9de8c7..7261ed9 100644 --- a/components/variations/variations_params_manager.cc +++ b/components/variations/variations_params_manager.cc
@@ -32,8 +32,9 @@ } // namespace VariationParamsManager::VariationParamsManager() - : field_trial_list_(new base::FieldTrialList(nullptr)), - scoped_feature_list_(new base::test::ScopedFeatureList()) {} + : scoped_feature_list_(new base::test::ScopedFeatureList()) { + scoped_feature_list_->InitWithEmptyFeatureAndFieldTrialLists(); +} VariationParamsManager::VariationParamsManager( const std::string& trial_name, @@ -66,6 +67,8 @@ const std::string& trial_name, const std::map<std::string, std::string>& param_values, const std::set<std::string>& associated_features) { + scoped_feature_list_ = std::make_unique<base::test::ScopedFeatureList>(); + base::FieldTrial* field_trial = CreateFieldTrialWithParams(trial_name, param_values); @@ -89,9 +92,7 @@ // When the scoped feature list is destroyed, it puts back the original // feature list that was there when InitWithFeatureList() was called. scoped_feature_list_ = std::make_unique<base::test::ScopedFeatureList>(); - // Ensure the destructor is called properly, so it can be freshly recreated. - field_trial_list_.reset(); - field_trial_list_ = std::make_unique<base::FieldTrialList>(nullptr); + scoped_feature_list_->InitWithEmptyFeatureAndFieldTrialLists(); } // static
diff --git a/components/variations/variations_params_manager.h b/components/variations/variations_params_manager.h index e16d154..3c84bdc 100644 --- a/components/variations/variations_params_manager.h +++ b/components/variations/variations_params_manager.h
@@ -10,8 +10,6 @@ #include <set> #include <string> -#include "base/test/scoped_field_trial_list_resetter.h" - namespace base { class CommandLine; class FieldTrialList; @@ -92,8 +90,6 @@ base::CommandLine* command_line); private: - base::test::ScopedFieldTrialListResetter field_trial_list_resetter_; - std::unique_ptr<base::FieldTrialList> field_trial_list_; std::unique_ptr<base::test::ScopedFeatureList> scoped_feature_list_; };
diff --git a/components/variations/variations_seed_processor_unittest.cc b/components/variations/variations_seed_processor_unittest.cc index 9f50235..4157ebf 100644 --- a/components/variations/variations_seed_processor_unittest.cc +++ b/components/variations/variations_seed_processor_unittest.cc
@@ -23,7 +23,6 @@ #include "base/test/metrics/histogram_tester.h" #include "base/test/mock_entropy_provider.h" #include "base/test/scoped_feature_list.h" -#include "base/test/scoped_field_trial_list_resetter.h" #include "base/time/time.h" #include "components/variations/client_filterable_state.h" #include "components/variations/processed_study.h" @@ -1020,7 +1019,8 @@ // An entropy value of 0.1 will cause the AA group to be chosen, since AA is // the only non-default group, and has a probability percent above 0.1. - base::test::ScopedFieldTrialListResetter resetter; + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitWithNullFeatureAndFieldTrialLists(); base::FieldTrialList field_trial_list( std::make_unique<base::MockEntropyProvider>(0.1));
diff --git a/components/viz/host/gpu_host_impl.cc b/components/viz/host/gpu_host_impl.cc index 8c05e03..4c37e29 100644 --- a/components/viz/host/gpu_host_impl.cc +++ b/components/viz/host/gpu_host_impl.cc
@@ -176,14 +176,14 @@ // to be re-created. if (activity_flags_.IsFlagSet( gpu::ActivityFlagsBase::FLAG_LOADING_PROGRAM_BINARY)) { - auto* shader_cache_factory = delegate_->GetShaderCacheFactory(); - for (auto cache_key : client_id_to_shader_cache_) { + auto* gpu_disk_cache_factory = delegate_->GetGpuDiskCacheFactory(); + for (auto& [client_id, _] : client_id_to_shader_cache_) { // This call will temporarily extend the lifetime of the cache (kept // alive in the factory), and may drop loads of cached shader binaries if // it takes a while to complete. As we are intentionally dropping all // binaries, this behavior is fine. - shader_cache_factory->ClearByClientId( - cache_key.first, base::Time(), base::Time::Max(), base::DoNothing()); + gpu_disk_cache_factory->ClearByClientId( + client_id, base::Time(), base::Time::Max(), base::DoNothing()); } } } @@ -249,7 +249,7 @@ } bool cache_shaders_on_disk = - delegate_->GetShaderCacheFactory()->Get(client_id) != nullptr; + delegate_->GetGpuDiskCacheFactory()->Get(client_id) != nullptr; channel_requests_[client_id] = std::move(callback); if (sync) { @@ -403,12 +403,12 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); TRACE_EVENT0("gpu", "GpuHostImpl::CreateChannelCache"); - scoped_refptr<gpu::ShaderDiskCache> cache = - delegate_->GetShaderCacheFactory()->Get(client_id); + scoped_refptr<gpu::GpuDiskCache> cache = + delegate_->GetGpuDiskCacheFactory()->Get(client_id); if (!cache) return; - cache->set_shader_loaded_callback(base::BindRepeating( + cache->SetBlobLoadedCallback(base::BindRepeating( &GpuHostImpl::LoadedShader, weak_ptr_factory_.GetWeakPtr(), client_id)); client_id_to_shader_cache_[client_id] = cache;
diff --git a/components/viz/host/gpu_host_impl.h b/components/viz/host/gpu_host_impl.h index 1d77a89..85d9a137 100644 --- a/components/viz/host/gpu_host_impl.h +++ b/components/viz/host/gpu_host_impl.h
@@ -50,8 +50,8 @@ } namespace gpu { -class ShaderCacheFactory; -class ShaderDiskCache; +class GpuDiskCacheFactory; +class GpuDiskCache; } // namespace gpu namespace viz { @@ -86,7 +86,7 @@ gpu::DomainGuilt guilt) = 0; virtual void DisableGpuCompositing() = 0; virtual bool GpuAccessAllowed() const = 0; - virtual gpu::ShaderCacheFactory* GetShaderCacheFactory() = 0; + virtual gpu::GpuDiskCacheFactory* GetGpuDiskCacheFactory() = 0; virtual void RecordLogMessage(int32_t severity, const std::string& header, const std::string& message) = 0; @@ -295,7 +295,7 @@ // are guilty, and block automatic execution of 3D content from those domains. std::multiset<GURL> urls_with_live_offscreen_contexts_; - std::map<int32_t, scoped_refptr<gpu::ShaderDiskCache>> + std::map<int32_t, scoped_refptr<gpu::GpuDiskCache>> client_id_to_shader_cache_; std::string shader_prefix_key_;
diff --git a/content/browser/attribution_reporting/attribution_src_browsertest.cc b/content/browser/attribution_reporting/attribution_src_browsertest.cc index ac0e5e1..73d94f3 100644 --- a/content/browser/attribution_reporting/attribution_src_browsertest.cc +++ b/content/browser/attribution_reporting/attribution_src_browsertest.cc
@@ -159,11 +159,13 @@ for (const char* registration_js : kTestCases) { EXPECT_TRUE(NavigateToURL(web_contents(), page_url)); std::unique_ptr<MockDataHost> data_host; - base::RunLoop loop; + base::RunLoop loop, disconnect_loop; EXPECT_CALL(mock_attribution_host(), RegisterDataHost) .WillOnce( [&](mojo::PendingReceiver<blink::mojom::AttributionDataHost> host) { data_host = GetRegisteredDataHost(std::move(host)); + data_host->receiver().set_disconnect_handler( + disconnect_loop.QuitClosure()); loop.Quit(); }); @@ -176,6 +178,9 @@ loop.Run(); data_host->WaitForSourceData(/*num_source_data=*/1); const auto& source_data = data_host->source_data(); + // Regression test for crbug.com/1336797. This will timeout flakily if the + // data host isn't disconnected promptly. + disconnect_loop.Run(); EXPECT_EQ(source_data.size(), 1u); EXPECT_EQ(source_data.front()->source_event_id, 5UL);
diff --git a/content/browser/attribution_reporting/attribution_test_utils.h b/content/browser/attribution_reporting/attribution_test_utils.h index b38051bf5..c379a9eb 100644 --- a/content/browser/attribution_reporting/attribution_test_utils.h +++ b/content/browser/attribution_reporting/attribution_test_utils.h
@@ -133,6 +133,10 @@ return trigger_data_; } + mojo::Receiver<blink::mojom::AttributionDataHost>& receiver() { + return receiver_; + } + private: // blink::mojom::AttributionDataHost: void SourceDataAvailable(
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc index 1c2a6239..85b116ad 100644 --- a/content/browser/browser_main_loop.cc +++ b/content/browser/browser_main_loop.cc
@@ -1237,10 +1237,10 @@ cc::SetClientNameForMetrics("Browser"); } - // Initialize the GPU shader cache. This needs to be initialized before + // Initialize the GPU cache. This needs to be initialized before // BrowserGpuChannelHostFactory below, since that depends on an initialized - // ShaderCacheFactory. - InitShaderCacheFactorySingleton(); + // GpuDiskCacheFactory. + InitGpuDiskCacheFactorySingleton(); // Initialize the FontRenderParams. This needs to be initialized before gpu // process initialization below.
diff --git a/content/browser/gpu/browser_gpu_channel_host_factory.cc b/content/browser/gpu/browser_gpu_channel_host_factory.cc index 15e5e06..af8447f 100644 --- a/content/browser/gpu/browser_gpu_channel_host_factory.cc +++ b/content/browser/gpu/browser_gpu_channel_host_factory.cc
@@ -476,16 +476,16 @@ void BrowserGpuChannelHostFactory::InitializeShaderDiskCacheOnIO( int gpu_client_id, const base::FilePath& cache_dir) { - GetShaderCacheFactorySingleton()->SetCacheInfo(gpu_client_id, cache_dir); - GetShaderCacheFactorySingleton()->SetCacheInfo( + GetGpuDiskCacheFactorySingleton()->SetCacheInfo(gpu_client_id, cache_dir); + GetGpuDiskCacheFactorySingleton()->SetCacheInfo( gpu::kDisplayCompositorClientId, cache_dir); } // static void BrowserGpuChannelHostFactory::InitializeGrShaderDiskCacheOnIO( const base::FilePath& cache_dir) { - GetShaderCacheFactorySingleton()->SetCacheInfo(gpu::kGrShaderCacheClientId, - cache_dir); + GetGpuDiskCacheFactorySingleton()->SetCacheInfo(gpu::kGrShaderCacheClientId, + cache_dir); } } // namespace content
diff --git a/content/browser/gpu/gpu_data_manager_impl_private.cc b/content/browser/gpu/gpu_data_manager_impl_private.cc index 0ba1cdcc..f999f95 100644 --- a/content/browser/gpu/gpu_data_manager_impl_private.cc +++ b/content/browser/gpu/gpu_data_manager_impl_private.cc
@@ -1361,8 +1361,7 @@ gfx::BufferUsage::GPU_READ_CPU_READ_WRITE); } - gpu_preferences->gpu_program_cache_size = - gpu::ShaderDiskCache::CacheSizeBytes(); + gpu_preferences->gpu_program_cache_size = gpu::GpuDiskCache::CacheSizeBytes(); gpu_preferences->texture_target_exception_list = gpu::CreateBufferUsageAndFormatExceptionList();
diff --git a/content/browser/gpu/gpu_disk_cache_factory.cc b/content/browser/gpu/gpu_disk_cache_factory.cc index 7efa749..e07eafe 100644 --- a/content/browser/gpu/gpu_disk_cache_factory.cc +++ b/content/browser/gpu/gpu_disk_cache_factory.cc
@@ -10,21 +10,20 @@ namespace { -gpu::ShaderCacheFactory* factory_instance = nullptr; +gpu::GpuDiskCacheFactory* factory_instance = nullptr; void CreateFactoryInstance() { DCHECK(!factory_instance); - factory_instance = new gpu::ShaderCacheFactory(); + factory_instance = new gpu::GpuDiskCacheFactory(); } } // namespace -void InitShaderCacheFactorySingleton() { +void InitGpuDiskCacheFactorySingleton() { CreateFactoryInstance(); } -gpu::ShaderCacheFactory* GetShaderCacheFactorySingleton() { - DCHECK(!factory_instance || factory_instance->CalledOnValidThread()); +gpu::GpuDiskCacheFactory* GetGpuDiskCacheFactorySingleton() { return factory_instance; }
diff --git a/content/browser/gpu/gpu_disk_cache_factory.h b/content/browser/gpu/gpu_disk_cache_factory.h index ee7b0e7..1b66066 100644 --- a/content/browser/gpu/gpu_disk_cache_factory.h +++ b/content/browser/gpu/gpu_disk_cache_factory.h
@@ -10,12 +10,12 @@ namespace content { -// Initializes the ShaderCacheFactory singleton instance. -CONTENT_EXPORT void InitShaderCacheFactorySingleton(); +// Initializes the GpuDiskCacheFactory singleton instance. +CONTENT_EXPORT void InitGpuDiskCacheFactorySingleton(); -// Returns an instance previously created by InitShaderCacheFactorySingleton(). +// Returns an instance previously created by InitGpuDiskCacheFactorySingleton(). // This can return nullptr if an instance has not yet been created. -CONTENT_EXPORT gpu::ShaderCacheFactory* GetShaderCacheFactorySingleton(); +CONTENT_EXPORT gpu::GpuDiskCacheFactory* GetGpuDiskCacheFactorySingleton(); } // namespace content
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc index 651cafa..f0419826 100644 --- a/content/browser/gpu/gpu_process_host.cc +++ b/content/browser/gpu/gpu_process_host.cc
@@ -1079,8 +1079,8 @@ #endif } -gpu::ShaderCacheFactory* GpuProcessHost::GetShaderCacheFactory() { - return GetShaderCacheFactorySingleton(); +gpu::GpuDiskCacheFactory* GpuProcessHost::GetGpuDiskCacheFactory() { + return GetGpuDiskCacheFactorySingleton(); } void GpuProcessHost::RecordLogMessage(int32_t severity,
diff --git a/content/browser/gpu/gpu_process_host.h b/content/browser/gpu/gpu_process_host.h index 8341b7f..4c32e62 100644 --- a/content/browser/gpu/gpu_process_host.h +++ b/content/browser/gpu/gpu_process_host.h
@@ -172,7 +172,7 @@ void BlockDomainFrom3DAPIs(const GURL& url, gpu::DomainGuilt guilt) override; void DisableGpuCompositing() override; bool GpuAccessAllowed() const override; - gpu::ShaderCacheFactory* GetShaderCacheFactory() override; + gpu::GpuDiskCacheFactory* GetGpuDiskCacheFactory() override; void RecordLogMessage(int32_t severity, const std::string& header, const std::string& message) override;
diff --git a/content/browser/renderer_host/frame_tree.cc b/content/browser/renderer_host/frame_tree.cc index bfa5f35..7c91edacd 100644 --- a/content/browser/renderer_host/frame_tree.cc +++ b/content/browser/renderer_host/frame_tree.cc
@@ -599,7 +599,6 @@ scoped_refptr<RenderViewHostImpl> FrameTree::CreateRenderViewHost( SiteInstance* site_instance, int32_t main_frame_routing_id, - bool swapped_out, bool renderer_initiated_creation, scoped_refptr<BrowsingContextState> main_browsing_context_state) { if (main_browsing_context_state) { @@ -609,7 +608,7 @@ static_cast<RenderViewHostImpl*>(RenderViewHostFactory::Create( this, static_cast<SiteInstanceImpl*>(site_instance)->group(), site_instance->GetStoragePartitionConfig(), render_view_delegate_, - render_widget_delegate_, main_frame_routing_id, swapped_out, + render_widget_delegate_, main_frame_routing_id, renderer_initiated_creation, std::move(main_browsing_context_state))); return base::WrapRefCounted(rvh); }
diff --git a/content/browser/renderer_host/frame_tree.h b/content/browser/renderer_host/frame_tree.h index 10c584b..96f93f69 100644 --- a/content/browser/renderer_host/frame_tree.h +++ b/content/browser/renderer_host/frame_tree.h
@@ -388,7 +388,6 @@ scoped_refptr<RenderViewHostImpl> CreateRenderViewHost( SiteInstance* site_instance, int32_t main_frame_routing_id, - bool swapped_out, bool renderer_initiated_creation, scoped_refptr<BrowsingContextState> main_browsing_context_state);
diff --git a/content/browser/renderer_host/frame_tree_node.cc b/content/browser/renderer_host/frame_tree_node.cc index a69a9b6..5c11655 100644 --- a/content/browser/renderer_host/frame_tree_node.cc +++ b/content/browser/renderer_host/frame_tree_node.cc
@@ -631,7 +631,7 @@ current_frame_host()->browsing_context_state()->OnDidStartLoading(); base::UmaHistogramTimes( base::StrCat({"Navigation.DidStartLoading.", - IsMainFrame() ? "MainFrame" : "Subframe"}), + IsOutermostMainFrame() ? "MainFrame" : "Subframe"}), timer.Elapsed()); }
diff --git a/content/browser/renderer_host/render_frame_host_manager.cc b/content/browser/renderer_host/render_frame_host_manager.cc index 75fb5860..6181e69 100644 --- a/content/browser/renderer_host/render_frame_host_manager.cc +++ b/content/browser/renderer_host/render_frame_host_manager.cc
@@ -2766,8 +2766,7 @@ } if (!render_view_host) { render_view_host = frame_tree->CreateRenderViewHost( - site_instance, frame_routing_id, - /*swapped_out=*/false, renderer_initiated_creation, + site_instance, frame_routing_id, renderer_initiated_creation, features::GetBrowsingContextMode() == features::BrowsingContextStateImplementationType:: kSwapForCrossBrowsingInstanceNavigations @@ -3038,7 +3037,7 @@ // exists for |instance|, as it creates the page level structure in Blink. render_view_host = frame_tree_node_->frame_tree()->CreateRenderViewHost( instance, /*main_frame_routing_id=*/MSG_ROUTING_NONE, - /*swapped_out=*/true, /*renderer_initiated_creation=*/false, + /*renderer_initiated_creation=*/false, features::GetBrowsingContextMode() == features::BrowsingContextStateImplementationType:: kSwapForCrossBrowsingInstanceNavigations
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index f8ce67c..4fa6c5e 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -298,13 +298,13 @@ nullptr; void CacheShaderInfo(int32_t id, base::FilePath path) { - if (GetShaderCacheFactorySingleton()) - GetShaderCacheFactorySingleton()->SetCacheInfo(id, path); + if (GetGpuDiskCacheFactorySingleton()) + GetGpuDiskCacheFactorySingleton()->SetCacheInfo(id, path); } void RemoveShaderInfo(int32_t id) { - if (GetShaderCacheFactorySingleton()) - GetShaderCacheFactorySingleton()->RemoveCacheInfo(id); + if (GetGpuDiskCacheFactorySingleton()) + GetGpuDiskCacheFactorySingleton()->RemoveCacheInfo(id); } // the global list of all renderer processes
diff --git a/content/browser/renderer_host/render_view_host_factory.cc b/content/browser/renderer_host/render_view_host_factory.cc index c6872b2..02a1e909 100644 --- a/content/browser/renderer_host/render_view_host_factory.cc +++ b/content/browser/renderer_host/render_view_host_factory.cc
@@ -29,7 +29,6 @@ RenderViewHostDelegate* delegate, RenderWidgetHostDelegate* widget_delegate, int32_t main_frame_routing_id, - bool swapped_out, bool renderer_initiated_creation, scoped_refptr<BrowsingContextState> main_browsing_context_state) { int32_t routing_id = group->process()->GetNextRoutingID(); @@ -38,7 +37,7 @@ if (factory_) { return factory_->CreateRenderViewHost( frame_tree, group, storage_partition_config, delegate, widget_delegate, - routing_id, main_frame_routing_id, widget_routing_id, swapped_out, + routing_id, main_frame_routing_id, widget_routing_id, std::move(main_browsing_context_state)); } @@ -47,7 +46,7 @@ RenderWidgetHostFactory::Create( frame_tree, widget_delegate, group->GetSafeRef(), widget_routing_id, /*hidden=*/true, renderer_initiated_creation), - delegate, routing_id, main_frame_routing_id, swapped_out, + delegate, routing_id, main_frame_routing_id, true /* has_initialized_audio_host */, std::move(main_browsing_context_state)); return view_host;
diff --git a/content/browser/renderer_host/render_view_host_factory.h b/content/browser/renderer_host/render_view_host_factory.h index 844990e..ef25f23 100644 --- a/content/browser/renderer_host/render_view_host_factory.h +++ b/content/browser/renderer_host/render_view_host_factory.h
@@ -32,7 +32,6 @@ RenderViewHostDelegate* delegate, RenderWidgetHostDelegate* widget_delegate, int32_t main_frame_routing_id, - bool swapped_out, bool renderer_initiated_creation, scoped_refptr<BrowsingContextState> main_browsing_context_state); @@ -71,7 +70,6 @@ int32_t routing_id, int32_t main_frame_routing_id, int32_t widget_routing_id, - bool swapped_out, scoped_refptr<BrowsingContextState> main_browsing_context_state) = 0; // Registers your factory to be called when new RenderViewHosts are created.
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc index 8af65c5..eeae3906 100644 --- a/content/browser/renderer_host/render_view_host_impl.cc +++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -289,7 +289,6 @@ RenderViewHostDelegate* delegate, int32_t routing_id, int32_t main_frame_routing_id, - bool swapped_out, bool has_initialized_audio_host, scoped_refptr<BrowsingContextState> main_browsing_context_state) : render_widget_host_(std::move(widget)),
diff --git a/content/browser/renderer_host/render_view_host_impl.h b/content/browser/renderer_host/render_view_host_impl.h index fa144ac..8702fd32a 100644 --- a/content/browser/renderer_host/render_view_host_impl.h +++ b/content/browser/renderer_host/render_view_host_impl.h
@@ -124,7 +124,6 @@ RenderViewHostDelegate* delegate, int32_t routing_id, int32_t main_frame_routing_id, - bool swapped_out, bool has_initialized_audio_host, scoped_refptr<BrowsingContextState> main_browsing_context_state);
diff --git a/content/browser/renderer_host/render_widget_host_view_android_unittest.cc b/content/browser/renderer_host/render_widget_host_view_android_unittest.cc index a4d7ea9..adc2d582 100644 --- a/content/browser/renderer_host/render_widget_host_view_android_unittest.cc +++ b/content/browser/renderer_host/render_widget_host_view_android_unittest.cc
@@ -191,7 +191,7 @@ frame_tree_.get(), site_instance_group_.get(), site_instance_->GetStoragePartitionConfig(), std::move(mock_host), web_contents_.get(), process_->GetNextRoutingID(), - process_->GetNextRoutingID(), false, nullptr); + process_->GetNextRoutingID(), nullptr); parent_layer_ = cc::Layer::Create(); parent_view_.SetLayer(parent_layer_); layer_ = cc::Layer::Create();
diff --git a/content/browser/service_worker/service_worker_metrics.cc b/content/browser/service_worker/service_worker_metrics.cc index 754748e..1d8ac934 100644 --- a/content/browser/service_worker/service_worker_metrics.cc +++ b/content/browser/service_worker/service_worker_metrics.cc
@@ -240,14 +240,13 @@ void ServiceWorkerMetrics::RecordRunAfterStartWorkerStatus( EmbeddedWorkerStatus running_status, EventType purpose) { - UMA_HISTOGRAM_ENUMERATION("ServiceWorker.RunAfterStartWorker.RunningStatus", + UMA_HISTOGRAM_ENUMERATION("ServiceWorker.MaybeStartWorker.RunningStatus", running_status); base::UmaHistogramEnumeration( - base::StrCat({"ServiceWorker.RunAfterStartWorker.RunningStatusByPurpose", + base::StrCat({"ServiceWorker.MaybeStartWorker.RunningStatusByPurpose", EventTypeToSuffix(purpose)}), running_status); - UMA_HISTOGRAM_ENUMERATION("ServiceWorker.RunAfterStartWorker.Purpose", - purpose); + UMA_HISTOGRAM_ENUMERATION("ServiceWorker.MaybeStartWorker.Purpose", purpose); } void ServiceWorkerMetrics::RecordStartWorkerTime(base::TimeDelta time,
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc index f30bec1..2af1689 100644 --- a/content/browser/storage_partition_impl.cc +++ b/content/browser/storage_partition_impl.cc
@@ -302,10 +302,10 @@ quota_storage_type, std::move(quota_client_types), std::move(callback)); } -void ClearedShaderCache(base::OnceClosure callback) { +void ClearedGpuCache(base::OnceClosure callback) { if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { GetUIThreadTaskRunner({})->PostTask( - FROM_HERE, base::BindOnce(&ClearedShaderCache, std::move(callback))); + FROM_HERE, base::BindOnce(&ClearedGpuCache, std::move(callback))); return; } std::move(callback).Run(); @@ -997,12 +997,13 @@ kQuota = 3, kLocalStorage = 4, kSessionStorage = 5, - kShaderCache = 6, + kShaderCache = 6, // Deprecated in favor of using kGpuCache. kPluginPrivate = 7, kConversions = 8, kAggregationService = 9, kSharedStorage = 10, - kMaxValue = kSharedStorage, + kGpuCache = 11, + kMaxValue = kGpuCache, }; base::OnceClosure CreateTaskCompletionClosure(TracingDataType data_type); @@ -2500,16 +2501,15 @@ } if (remove_mask_ & REMOVE_DATA_MASK_SHADER_CACHE) { - gpu::ShaderCacheFactory* shader_cache_factory = - GetShaderCacheFactorySingleton(); + gpu::GpuDiskCacheFactory* gpu_cache_factory = + GetGpuDiskCacheFactorySingleton(); // May be null in tests where it is difficult to plumb through a test // storage partition. - if (shader_cache_factory) { - shader_cache_factory->ClearByPath( + if (gpu_cache_factory) { + gpu_cache_factory->ClearByPath( path, begin, end, - base::BindOnce( - &ClearedShaderCache, - CreateTaskCompletionClosure(TracingDataType::kShaderCache))); + base::BindOnce(&ClearedGpuCache, CreateTaskCompletionClosure( + TracingDataType::kGpuCache))); } }
diff --git a/content/browser/storage_partition_impl_unittest.cc b/content/browser/storage_partition_impl_unittest.cc index fa3e880..2aea21f 100644 --- a/content/browser/storage_partition_impl_unittest.cc +++ b/content/browser/storage_partition_impl_unittest.cc
@@ -755,16 +755,16 @@ StoragePartitionShaderClearTest() : task_environment_(content::BrowserTaskEnvironment::IO_MAINLOOP), browser_context_(new TestBrowserContext()) { - InitShaderCacheFactorySingleton(); - GetShaderCacheFactorySingleton()->SetCacheInfo( + InitGpuDiskCacheFactorySingleton(); + GetGpuDiskCacheFactorySingleton()->SetCacheInfo( kDefaultClientId, browser_context()->GetDefaultStoragePartition()->GetPath()); - cache_ = GetShaderCacheFactorySingleton()->Get(kDefaultClientId); + cache_ = GetGpuDiskCacheFactorySingleton()->Get(kDefaultClientId); } ~StoragePartitionShaderClearTest() override { cache_ = nullptr; - GetShaderCacheFactorySingleton()->RemoveCacheInfo(kDefaultClientId); + GetGpuDiskCacheFactorySingleton()->RemoveCacheInfo(kDefaultClientId); } void InitCache() { @@ -789,7 +789,7 @@ content::BrowserTaskEnvironment task_environment_; std::unique_ptr<TestBrowserContext> browser_context_; - scoped_refptr<gpu::ShaderDiskCache> cache_; + scoped_refptr<gpu::GpuDiskCache> cache_; }; // Tests ---------------------------------------------------------------------
diff --git a/content/browser/webrtc/webrtc_media_recorder_browsertest.cc b/content/browser/webrtc/webrtc_media_recorder_browsertest.cc index b385e89..b06393fb 100644 --- a/content/browser/webrtc/webrtc_media_recorder_browsertest.cc +++ b/content/browser/webrtc/webrtc_media_recorder_browsertest.cc
@@ -36,27 +36,11 @@ namespace content { -// All tests in this fixture experience flaky DCHECK failures on macOS; see -// https://crbug.com/810321. -#if BUILDFLAG(IS_MAC) && DCHECK_IS_ON() -#define MAYBE_WebRtcMediaRecorderTest DISABLED_WebRtcMediaRecorderTest -#else -#define MAYBE_WebRtcMediaRecorderTest WebRtcMediaRecorderTest -#endif - // This class tests the recording of a media stream. -class MAYBE_WebRtcMediaRecorderTest +class WebRtcMediaRecorderTest : public WebRtcContentBrowserTestBase, public testing::WithParamInterface<struct EncodingParameters> { public: - MAYBE_WebRtcMediaRecorderTest() {} - - MAYBE_WebRtcMediaRecorderTest(const MAYBE_WebRtcMediaRecorderTest&) = delete; - MAYBE_WebRtcMediaRecorderTest& operator=( - const MAYBE_WebRtcMediaRecorderTest&) = delete; - - ~MAYBE_WebRtcMediaRecorderTest() override {} - void SetUpCommandLine(base::CommandLine* command_line) override { WebRtcContentBrowserTestBase::SetUpCommandLine(command_line); @@ -75,11 +59,11 @@ } }; -IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcMediaRecorderTest, Start) { +IN_PROC_BROWSER_TEST_F(WebRtcMediaRecorderTest, Start) { MakeTypicalCall("testStartAndRecorderState();", kMediaRecorderHtmlFile); } -IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcMediaRecorderTest, StartAndStop) { +IN_PROC_BROWSER_TEST_F(WebRtcMediaRecorderTest, StartAndStop) { MakeTypicalCall("testStartStopAndRecorderState();", kMediaRecorderHtmlFile); } @@ -89,8 +73,7 @@ #else #define MAYBE_StartAndDataAvailable StartAndDataAvailable #endif -IN_PROC_BROWSER_TEST_P(MAYBE_WebRtcMediaRecorderTest, - MAYBE_StartAndDataAvailable) { +IN_PROC_BROWSER_TEST_P(WebRtcMediaRecorderTest, MAYBE_StartAndDataAvailable) { MaybeForceDisableEncodeAccelerator(GetParam().disable_accelerator); MakeTypicalCall(base::StringPrintf("testStartAndDataAvailable(\"%s\");", GetParam().mime_type.c_str()), @@ -104,20 +87,18 @@ #else #define MAYBE_StartWithTimeSlice StartWithTimeSlice #endif -IN_PROC_BROWSER_TEST_P(MAYBE_WebRtcMediaRecorderTest, - MAYBE_StartWithTimeSlice) { +IN_PROC_BROWSER_TEST_P(WebRtcMediaRecorderTest, MAYBE_StartWithTimeSlice) { MaybeForceDisableEncodeAccelerator(GetParam().disable_accelerator); MakeTypicalCall(base::StringPrintf("testStartWithTimeSlice(\"%s\");", GetParam().mime_type.c_str()), kMediaRecorderHtmlFile); } -IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcMediaRecorderTest, Resume) { +IN_PROC_BROWSER_TEST_F(WebRtcMediaRecorderTest, Resume) { MakeTypicalCall("testResumeAndRecorderState();", kMediaRecorderHtmlFile); } -IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcMediaRecorderTest, - NoResumeWhenRecorderInactive) { +IN_PROC_BROWSER_TEST_F(WebRtcMediaRecorderTest, NoResumeWhenRecorderInactive) { MakeTypicalCall("testIllegalResumeThrowsDOMError();", kMediaRecorderHtmlFile); } @@ -127,15 +108,14 @@ #else #define MAYBE_ResumeAndDataAvailable ResumeAndDataAvailable #endif -IN_PROC_BROWSER_TEST_P(MAYBE_WebRtcMediaRecorderTest, - MAYBE_ResumeAndDataAvailable) { +IN_PROC_BROWSER_TEST_P(WebRtcMediaRecorderTest, MAYBE_ResumeAndDataAvailable) { MaybeForceDisableEncodeAccelerator(GetParam().disable_accelerator); MakeTypicalCall(base::StringPrintf("testResumeAndDataAvailable(\"%s\");", GetParam().mime_type.c_str()), kMediaRecorderHtmlFile); } -IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcMediaRecorderTest, Pause) { +IN_PROC_BROWSER_TEST_F(WebRtcMediaRecorderTest, Pause) { MakeTypicalCall("testPauseAndRecorderState();", kMediaRecorderHtmlFile); } @@ -145,11 +125,11 @@ #else #define MAYBE_PauseStop PauseStop #endif -IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcMediaRecorderTest, MAYBE_PauseStop) { +IN_PROC_BROWSER_TEST_F(WebRtcMediaRecorderTest, MAYBE_PauseStop) { MakeTypicalCall("testPauseStopAndRecorderState();", kMediaRecorderHtmlFile); } -IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcMediaRecorderTest, +IN_PROC_BROWSER_TEST_F(WebRtcMediaRecorderTest, PausePreventsDataavailableFromBeingFired) { MakeTypicalCall("testPausePreventsDataavailableFromBeingFired();", kMediaRecorderHtmlFile); @@ -161,7 +141,7 @@ #else #define MAYBE_IllegalPauseThrowsDOMError IllegalPauseThrowsDOMError #endif -IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcMediaRecorderTest, +IN_PROC_BROWSER_TEST_F(WebRtcMediaRecorderTest, MAYBE_IllegalPauseThrowsDOMError) { MakeTypicalCall("testIllegalPauseThrowsDOMError();", kMediaRecorderHtmlFile); } @@ -172,30 +152,29 @@ #else #define MAYBE_TwoChannelAudioRecording TwoChannelAudioRecording #endif -IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcMediaRecorderTest, +IN_PROC_BROWSER_TEST_F(WebRtcMediaRecorderTest, MAYBE_TwoChannelAudioRecording) { MakeTypicalCall("testTwoChannelAudio();", kMediaRecorderHtmlFile); } -IN_PROC_BROWSER_TEST_P(MAYBE_WebRtcMediaRecorderTest, RecordWithTransparency) { +IN_PROC_BROWSER_TEST_P(WebRtcMediaRecorderTest, RecordWithTransparency) { MaybeForceDisableEncodeAccelerator(GetParam().disable_accelerator); MakeTypicalCall(base::StringPrintf("testRecordWithTransparency(\"%s\");", GetParam().mime_type.c_str()), kMediaRecorderHtmlFile); } -IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcMediaRecorderTest, - IllegalStopThrowsDOMError) { +IN_PROC_BROWSER_TEST_F(WebRtcMediaRecorderTest, IllegalStopThrowsDOMError) { MakeTypicalCall("testIllegalStopThrowsDOMError();", kMediaRecorderHtmlFile); } -IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcMediaRecorderTest, +IN_PROC_BROWSER_TEST_F(WebRtcMediaRecorderTest, IllegalStartWhileRecordingThrowsDOMError) { MakeTypicalCall("testIllegalStartInRecordingStateThrowsDOMError();", kMediaRecorderHtmlFile); } -IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcMediaRecorderTest, +IN_PROC_BROWSER_TEST_F(WebRtcMediaRecorderTest, IllegalStartWhilePausedThrowsDOMError) { MakeTypicalCall("testIllegalStartInPausedStateThrowsDOMError();", kMediaRecorderHtmlFile); @@ -208,7 +187,7 @@ #else #define MAYBE_IllegalRequestDataThrowsDOMError IllegalRequestDataThrowsDOMError #endif -IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcMediaRecorderTest, +IN_PROC_BROWSER_TEST_F(WebRtcMediaRecorderTest, MAYBE_IllegalRequestDataThrowsDOMError) { MakeTypicalCall("testIllegalRequestDataThrowsDOMError();", kMediaRecorderHtmlFile); @@ -232,7 +211,7 @@ #define MAYBE_PeerConnection PeerConnection #endif -IN_PROC_BROWSER_TEST_P(MAYBE_WebRtcMediaRecorderTest, MAYBE_PeerConnection) { +IN_PROC_BROWSER_TEST_P(WebRtcMediaRecorderTest, MAYBE_PeerConnection) { MaybeForceDisableEncodeAccelerator(GetParam().disable_accelerator); MakeTypicalCall(base::StringPrintf("testRecordRemotePeerConnection(\"%s\");", GetParam().mime_type.c_str()), @@ -251,26 +230,26 @@ #define MAYBE_AddingTrackToMediaStreamFiresErrorEvent \ AddingTrackToMediaStreamFiresErrorEvent #endif -IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcMediaRecorderTest, +IN_PROC_BROWSER_TEST_F(WebRtcMediaRecorderTest, MAYBE_AddingTrackToMediaStreamFiresErrorEvent) { MakeTypicalCall("testAddingTrackToMediaStreamFiresErrorEvent();", kMediaRecorderHtmlFile); } -IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcMediaRecorderTest, +IN_PROC_BROWSER_TEST_F(WebRtcMediaRecorderTest, RemovingTrackFromMediaStreamFiresErrorEvent) { MakeTypicalCall("testRemovingTrackFromMediaStreamFiresErrorEvent();", kMediaRecorderHtmlFile); } INSTANTIATE_TEST_SUITE_P(OpenCodec, - MAYBE_WebRtcMediaRecorderTest, + WebRtcMediaRecorderTest, testing::ValuesIn(kEncodingParameters)); #if BUILDFLAG(USE_PROPRIETARY_CODECS) INSTANTIATE_TEST_SUITE_P(ProprietaryCodec, - MAYBE_WebRtcMediaRecorderTest, + WebRtcMediaRecorderTest, testing::ValuesIn(kProprietaryEncodingParameters)); #endif // BUILDFLAG(USE_PROPRIETARY_CODECS)
diff --git a/content/renderer/dom_serializer_browsertest.cc b/content/renderer/dom_serializer_browsertest.cc index 0cd9779b..52d9e972 100644 --- a/content/renderer/dom_serializer_browsertest.cc +++ b/content/renderer/dom_serializer_browsertest.cc
@@ -633,8 +633,17 @@ // Test situation of non-standard HTML entities when serializing HTML DOM. // This test started to fail at WebKit r65351. See http://crbug.com/52279. + +// Disabled due to test failure. http://crbug.com/1349583 +#if BUILDFLAG(IS_LINUX) +#define MAYBE_SerializeHTMLDOMWithNonStandardEntities \ + DISABLED_SerializeHTMLDOMWithNonStandardEntities +#else +#define MAYBE_SerializeHTMLDOMWithNonStandardEntities \ + SerializeHTMLDOMWithNonStandardEntities +#endif IN_PROC_BROWSER_TEST_F(MAYBE_DomSerializerTests, - SerializeHTMLDOMWithNonStandardEntities) { + MAYBE_SerializeHTMLDOMWithNonStandardEntities) { // Make a test file URL and load it. base::FilePath page_file_path = GetTestFilePath("dom_serializer", "nonstandard_htmlentities.htm"); @@ -671,7 +680,15 @@ // When serializing, we should comment the BASE tag, append a new BASE tag. // rewrite all the savable URLs to relative local path, and change other URLs // to absolute URLs. -IN_PROC_BROWSER_TEST_F(MAYBE_DomSerializerTests, SerializeHTMLDOMWithBaseTag) { + +// Disabled due to test failure. http://crbug.com/1349583 +#if BUILDFLAG(IS_LINUX) +#define MAYBE_SerializeHTMLDOMWithBaseTag DISABLED_SerializeHTMLDOMWithBaseTag +#else +#define MAYBE_SerializeHTMLDOMWithBaseTag SerializeHTMLDOMWithBaseTag +#endif +IN_PROC_BROWSER_TEST_F(MAYBE_DomSerializerTests, + MAYBE_SerializeHTMLDOMWithBaseTag) { base::FilePath page_file_path = GetTestFilePath("dom_serializer", "html_doc_has_base_tag.htm");
diff --git a/content/test/test_render_view_host.cc b/content/test/test_render_view_host.cc index 3501b4a..a039d7e9 100644 --- a/content/test/test_render_view_host.cc +++ b/content/test/test_render_view_host.cc
@@ -333,7 +333,6 @@ RenderViewHostDelegate* delegate, int32_t routing_id, int32_t main_frame_routing_id, - bool swapped_out, scoped_refptr<BrowsingContextState> main_browsing_context_state) : RenderViewHostImpl(frame_tree, group, @@ -342,7 +341,6 @@ delegate, routing_id, main_frame_routing_id, - swapped_out, false /* has_initialized_audio_host */, std::move(main_browsing_context_state)), delete_counter_(nullptr) {
diff --git a/content/test/test_render_view_host.h b/content/test/test_render_view_host.h index 65c53ee..631b674 100644 --- a/content/test/test_render_view_host.h +++ b/content/test/test_render_view_host.h
@@ -266,7 +266,6 @@ RenderViewHostDelegate* delegate, int32_t routing_id, int32_t main_frame_routing_id, - bool swapped_out, scoped_refptr<BrowsingContextState> main_browsing_context_state); TestRenderViewHost(const TestRenderViewHost&) = delete;
diff --git a/content/test/test_render_view_host_factory.cc b/content/test/test_render_view_host_factory.cc index d5da5e9..389e77d6 100644 --- a/content/test/test_render_view_host_factory.cc +++ b/content/test/test_render_view_host_factory.cc
@@ -46,14 +46,13 @@ int32_t routing_id, int32_t main_frame_routing_id, int32_t widget_routing_id, - bool swapped_out, scoped_refptr<BrowsingContextState> main_browsing_context_state) { return new TestRenderViewHost( frame_tree, group, storage_partition_config, TestRenderWidgetHost::Create(frame_tree, widget_delegate, group->GetSafeRef(), widget_routing_id, false), - delegate, routing_id, main_frame_routing_id, swapped_out, + delegate, routing_id, main_frame_routing_id, std::move(main_browsing_context_state)); }
diff --git a/content/test/test_render_view_host_factory.h b/content/test/test_render_view_host_factory.h index 6a154c0a..a3f31661 100644 --- a/content/test/test_render_view_host_factory.h +++ b/content/test/test_render_view_host_factory.h
@@ -42,7 +42,6 @@ int32_t routing_id, int32_t main_frame_routing_id, int32_t widget_routing_id, - bool swapped_out, scoped_refptr<BrowsingContextState> main_browsing_context_state) override; };
diff --git a/docs/webui_in_chrome.md b/docs/webui_in_chrome.md index ad3c81c..d8ca357a 100644 --- a/docs/webui_in_chrome.md +++ b/docs/webui_in_chrome.md
@@ -11,20 +11,31 @@ </style> # Creating WebUI Interfaces outside components/ -This guide is based on [Creating WebUI Interfaces in components](webui_in_components.md), and comments from reviewers when creating the ChromeOS emoji picker. +This guide is based on +[Creating WebUI Interfaces in components](webui_in_components.md). [TOC] -WebUI pages live in `chrome/browser/resources`. You should create a folder for your project `chrome/browser/resources/hello_world`. -When creating WebUI resources, follow the [Web Development Style Guide](https://chromium.googlesource.com/chromium/src/+/main/styleguide/web/web.md). For a sample WebUI page you could start with the following files: +A WebUI page is made of a Polymer single-page application, which communicates +with a C++ UI controller, as explained [here](webui_explainer.md). -`chrome/browser/resources/hello_world/hello_world_container.html` +WebUI pages live in `chrome/browser/resources` and their native counterpart in +`chrome/browser/ui/webui/`. We will start by creating folders for the new page +in `chrome/browser/[resources|ui/webui]/hello_world`. When creating WebUI +resources, follow the +[Web Development Style Guide](https://chromium.googlesource.com/chromium/src/+/main/styleguide/web/web.md). + +## Making a basic WebUI page + +For a sample WebUI page you could start with the following files: + +`chrome/browser/resources/hello_world/hello_world.html` ```html <!DOCTYPE HTML> <html> <meta charset="utf-8"> <link rel="stylesheet" href="hello_world.css"> - <hello-world></hello-world> + <hello-world-app></hello-world-app> <script type="module" src="hello_world.js"></script> </html> ``` @@ -36,23 +47,23 @@ } ``` -`chrome/browser/resources/hello_world/hello_world.html` +`chrome/browser/resources/hello_world/app.html` ```html <h1>Hello World</h1> <div id="example-div">[[message_]]</div> ``` -`chrome/browser/resources/hello_world/hello_world.ts` +`chrome/browser/resources/hello_world/app.ts` ```js import './strings.m.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js'; import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; -import {getTemplate} from './hello_world.html.js'; +import {getTemplate} from './app.html.js'; -export class HelloWorldElement extends PolymerElement { +export class HelloWorldAppElement extends PolymerElement { static get is() { - return 'hello-world'; + return 'hello-world-app'; } static get template() { @@ -67,19 +78,27 @@ }, }; } - - private message_: string; } -customElements.define(HelloWorldElement.is, HelloWorldElement); +declare global { + interface HTMLElementTagNameMap { + 'hello-world-app': HelloWorldAppElement; + } +} + +customElements.define(HelloWorldAppElement.is, HelloWorldAppElement); ``` -Add a 'tsconfig_base.json' file to configure TypeScript options. Typical options -needed by Polymer UIs include noUncheckedIndexAccess, noUnusedLocals, and -strictPropertyInitialization, all set to false. +Add a `tsconfig_base.json` file to configure TypeScript options. Typical +options needed by Polymer UIs include: +- disabling `noUncheckedIndexAccess` +- disabling `noUnusedLocals`: private members from Elements are accessed from + their HTML template +- disabling `strictPropertyInitialization`: Element properties can be + initialized via the `property` map. `chrome/browser/resources/hello_world/tsconfig_base.json` -``` +```json { "extends": "../../../../tools/typescript/tsconfig_base.json", "compilerOptions": { @@ -94,93 +113,40 @@ from which the template will be imported. `chrome/browser/resources/hello_world/BUILD.gn` -``` -import("//tools/polymer/html_to_wrapper.gni") -import("//tools/grit/preprocess_if_expr.gni") -import("//tools/typescript/ts_library.gni") +```py +import("//chrome/browser/resources/tools/build_webui.gni") -html_to_wrapper("html_wrapper_files") { - in_files = [ "hello_world.html" ] -} +build_webui("build") { + grd_prefix = "hello_world" -# Move everything to one folder using preprocess_if_expr. -preprocess_folder = "preprocessed" + static_files = [ "hello_world.html", "hello_world.css" ] -preprocess_if_expr("preprocess_generated") { - # This file is generated by html_to_wrapper(). - in_files = [ "hello_world.html.ts" ] - in_folder = target_gen_dir - out_folder = "$target_gen_dir/$preprocess_folder" - deps = [ ":html_wrapper_files" ] -} + web_component_files = [ "app.ts" ] -preprocess_if_expr("preprocess") { - in_files = [ "hello_world.ts" ] - in_folder = "." - out_folder = "$target_gen_dir/$preprocess_folder" -} - -ts_library("build_ts") { - root_dir = "$target_gen_dir/$preprocess_folder" - out_dir = "$target_gen_dir/tsc" - tsconfig_base = "tsconfig_base.json" - in_files = [ - "hello_world.ts", - "hello_world.html.ts" + non_web_component_files = [ + # For example the BrowserProxy file would go here. ] - deps = [ + + ts_deps = [ "//third_party/polymer/v3_0:library", "//ui/webui/resources:library", ] - extra_deps = [ - ":preprocess", - ":preprocess_generated", - ] } ``` +> Note: See [the build config docs for more examples](webui_build_configuration.md#example-build-configurations) +of how the build could be configured. + Finally, create an `OWNERS` file for the new folder. -## Adding the resources -Resources for the browser are stored in `grd` files. Current best practice is to autogenerate a grd file for your -component in the `BUILD` file we created earlier. See new content below: +### Adding the resources -`chrome/browser/resources/hello_world/BUILD.gn new additions` -``` -import("//tools/grit/grit_rule.gni") -import("//ui/webui/resources/tools/generate_grd.gni") +The `build_webui` target in `BUILD.gn` autogenerates some targets and files +that need to be linked from the binary-wide resource targets: -resources_grd_file = "$target_gen_dir/resources.grd" +Add the new resource target to `chrome/browser/resources/BUILD.gn` -generate_grd("build_grd") { - grd_prefix = "hello_world" - out_grd = resources_grd_file - input_files = [ - "hello_world.css", - "hello_world_container.html", - ] - input_files_base_dir = rebase_path(".", "//") - deps = [ ":build_ts" ] - manifest_files = filter_include( - get_target_outputs(":build_ts"), [ "*.manifest" ]) -} - -grit("resources") { - enable_input_discovery_for_gn_analyze = false - source = resources_grd_file - deps = [ ":build_grd" ] - outputs = [ - "grit/hello_world_resources.h", - "grit/hello_world_resources_map.cc", - "grit/hello_world_resources_map.h", - "hello_world_resources.pak", - ] - output_dir = "$root_gen_dir/chrome" -} -``` - -Then add the new resource target to `chrome/browser/resources/BUILD.gn` -``` +```py group("resources") { public_deps += [ ... @@ -190,9 +156,25 @@ } ``` -Also add to `chrome/chrome_paks.gni` +Add an entry to resource_ids.spec + +This file is for automatically generating resource ids. Ensure that your entry +has a unique ID and preserves numerical ordering. + +`tools/gritsettings/resource_ids.spec` ``` + # START chrome/ WebUI resources section + ... (lots) + "<(SHARED_INTERMEDIATE_DIR)/chrome/browser/resources/hello_world/resources.grd": { + "META": {"sizes": {"includes": [5]}}, + "includes": [2085], + }, +``` + +Also add to `chrome/chrome_paks.gni` + +```py template("chrome_extra_paks") { ... (lots) sources += [ @@ -208,7 +190,7 @@ } ``` -## Adding URL constants for the new chrome URL +### Adding URL constants for the new chrome URL `chrome/common/webui_url_constants.cc:` ```c++ @@ -222,11 +204,12 @@ extern const char kChromeUIHelloWorldHost[]; ``` -## Adding a WebUI class for handling requests to the chrome://hello-world/ URL +### Adding a WebUI class for handling requests to the `chrome://hello-world/` URL + Next we need a class to handle requests to this new resource URL. Typically this will subclass `WebUIController` (WebUI dialogs will also need another class which will subclass `WebDialogDelegate`, this is shown later). -`chrome/browser/ui/webui/hello_world_ui.h` +`chrome/browser/ui/webui/hello_world/hello_world_ui.h` ```c++ #ifndef CHROME_BROWSER_UI_WEBUI_HELLO_WORLD_HELLO_WORLD_H_ #define CHROME_BROWSER_UI_WEBUI_HELLO_WORLD_HELLO_WORLD_H_ @@ -243,7 +226,7 @@ #endif // CHROME_BROWSER_UI_WEBUI_HELLO_WORLD_HELLO_WORLD_H_ ``` -`chrome/browser/ui/webui/hello_world_ui.cc` +`chrome/browser/ui/webui/hello_world/hello_world_ui.cc` ```c++ #include "chrome/browser/ui/webui/hello_world_ui.h" @@ -260,23 +243,19 @@ HelloWorldUI::HelloWorldUI(content::WebUI* web_ui) : content::WebUIController(web_ui) { // Set up the chrome://hello-world source. - content::WebUIDataSource* html_source = - content::WebUIDataSource::Create(chrome::kChromeUIHelloWorldHost); - - // As a demonstration of passing a variable for JS to use we pass in some - // a simple message. - html_source->AddString("message", "Hello World!"); - html_source->UseStringsJs(); + content::WebUIDataSource* source = content::WebUIDataSource::CreateAndAdd( + web_ui->GetWebContents()->GetBrowserContext(), + chrome::kChromeUIHelloWorldHost); // Add required resources. webui::SetupWebUIDataSource( - html_source, + source, base::make_span(kHelloWorldResources, kHelloWorldResourcesSize), IDR_HELLO_WORLD_HELLO_WORLD_CONTAINER_HTML); - content::BrowserContext* browser_context = - web_ui->GetWebContents()->GetBrowserContext(); - content::WebUIDataSource::Add(browser_context, html_source); + // As a demonstration of passing a variable for JS to use we pass in some + // a simple message. + source->AddString("message", "Hello World!"); } HelloWorldUI::~HelloWorldUI() = default; @@ -284,42 +263,30 @@ To ensure that your code actually gets compiled, you need to add it to `chrome/browser/ui/BUILD.gn`: -``` +```py static_library("ui") { sources = [ ... (lots) - "webui/hello_world_ui.cc", - "webui/hello_world_ui.h", + "webui/hello_world/hello_world_ui.cc", + "webui/hello_world/hello_world_ui.h", + ... + ] +} ``` -## Adding your WebUI request handler to the Chrome WebUI factory +### Adding your WebUI request handler to the Chrome WebUI factory The Chrome WebUI factory is where you setup your new request handler. `chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc:` ```c++ -+ #include "chrome/browser/ui/webui/hello_world_ui.h" ++ #include "chrome/browser/ui/webui/hello_world/hello_world_ui.h" ... + if (url.host() == chrome::kChromeUIHelloWorldHost) + return &NewWebUI<HelloWorldUI>; ``` -## Add an entry to resource_ids.spec -This file is for automatically generating resource ids. Ensure that your entry -has a unique ID and preserves numerical ordering. - -`tools/gritsettings/resource_ids.spec` - -``` - # START chrome/ WebUI resources section - ... (lots) - "<(SHARED_INTERMEDIATE_DIR)/chrome/browser/resources/hello_world/resources.grd": { - "META": {"sizes": {"includes": [5]}}, - "includes": [2085], - }, -``` - -## Check everything works +### Check everything works You're done! Assuming no errors (because everyone gets their code perfect the first time) you should be able to compile and run chrome and navigate to `chrome://hello-world/` and see your nifty welcome text! @@ -332,7 +299,7 @@ `ui::WebDialogDelegate`. The easiest way to do that is to edit the `hello_world_ui.*` files -`chrome/browser/ui/webui/hello_world_ui.h` +`chrome/browser/ui/webui/hello_world/hello_world_ui.h` ```c++ // Leave the old content, but add this new code class HelloWorldDialog : public ui::WebDialogDelegate { @@ -362,7 +329,7 @@ }; ``` -`chrome/browser/ui/webui/hello_world_ui.cc` +`chrome/browser/ui/webui/hello_world/hello_world_ui.cc` ```c++ // Leave the old content, but add this new stuff @@ -420,3 +387,60 @@ ``` Finally, you will need to do something to actually show your dialog, which can be done by calling `HelloWorldDialog::Show()`. + +## More elaborate configurations + +### Referencing resources from another webui page + +There are already mechanisms to make resources available chrome-wide, by +publishing them under `chrome://resources`. If this is not appropriate, there +are some ways to serve a file from some other webui page directly through +another host. + +First, a few explanations. The configuration based on the `build_webui()` BUILD +target as presented above generates a few helpers that hide the complexity of +the page's configuration. For example, considering the snippet below: + +```cpp +//... +#include "chrome/grit/hello_world_resources.h" +#include "chrome/grit/hello_world_resources_map.h" + +HelloWorldUI::HelloWorldUI(content::WebUI* web_ui) + : content::WebUIController(web_ui) { + // ... + webui::SetupWebUIDataSource( + source, + base::make_span(kHelloWorldResources, kHelloWorldResourcesSize), + IDR_HELLO_WORLD_HELLO_WORLD_CONTAINER_HTML); +} +``` + +`kHelloWorldResources` and `kHelloWorldResourcesSize` come from from the +imported grit-generated files, as configured by the build target, and reference +the files listed in it so they can be served out of the given host name. +For example, they would contain values like: + +```cpp +const webui::ResourcePath kHelloWorldResources[] = { + {"hello_world.html", IDR_CHROME_BROWSER_RESOURCES_HELLO_WORLD_HELLO_WORLD_HTML}, + {"hello_world.css", IDR_CHROME_BROWSER_RESOURCES_HELLO_WORLD_HELLO_WORLD_CSS}, +}; +``` + +Using `WebUIDataSource::AddResourcePaths()` we can add other resources, +looking for the right way to declare them by looking through the generated +grit files (e.g. via codesearch), or manual registrations if they exist. + +```cpp +#include "chrome/grit/signin_resources.h" +// ... +HelloWorldUI::HelloWorldUI(content::WebUI* web_ui) { + // ... + static constexpr webui::ResourcePath kResources[] = { + {"signin_shared.css.js", IDR_SIGNIN_SIGNIN_SHARED_CSS_JS}, + {"signin_vars.css.js", IDR_SIGNIN_SIGNIN_VARS_CSS_JS}, + }; + source->AddResourcePaths(kResources); +} +```
diff --git a/gpu/config/gpu_driver_bug_list.json b/gpu/config/gpu_driver_bug_list.json index 79ebb7c6..eaec480 100644 --- a/gpu/config/gpu_driver_bug_list.json +++ b/gpu/config/gpu_driver_bug_list.json
@@ -1121,7 +1121,7 @@ "type": "android" }, "features": [ - "max_texture_size_limit_4096" + "webgl_or_caps_max_texture_size_limit_4096" ] }, { @@ -2817,8 +2817,8 @@ }, "vendor_id": "0x8086", "features": [ - "max_texture_size_limit_4096", - "max_3d_array_texture_size_1024" + "max_3d_array_texture_size_1024", + "webgl_or_caps_max_texture_size_limit_4096" ] }, {
diff --git a/gpu/config/gpu_driver_bug_workarounds.cc b/gpu/config/gpu_driver_bug_workarounds.cc index 55c5d167..117e031 100644 --- a/gpu/config/gpu_driver_bug_workarounds.cc +++ b/gpu/config/gpu_driver_bug_workarounds.cc
@@ -26,8 +26,7 @@ NOTIMPLEMENTED(); } } - // TODO(crbug.com/1319451): Rename workaround. - if (workarounds->max_texture_size_limit_4096) + if (workarounds->webgl_or_caps_max_texture_size_limit_4096) workarounds->webgl_or_caps_max_texture_size = 4096; if (workarounds->max_copy_texture_chromium_size_1048576)
diff --git a/gpu/config/gpu_finch_features.cc b/gpu/config/gpu_finch_features.cc index ea9ab74..f7b135e2 100644 --- a/gpu/config/gpu_finch_features.cc +++ b/gpu/config/gpu_finch_features.cc
@@ -146,7 +146,7 @@ const base::Feature kCanvasOopRasterization { "CanvasOopRasterization", #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS_ASH) || \ - (BUILDFLAG(IS_MAC) && defined(ARCH_CPU_ARM64)) + (BUILDFLAG(IS_MAC) && defined(ARCH_CPU_ARM64)) || BUILDFLAG(IS_FUCHSIA) base::FEATURE_ENABLED_BY_DEFAULT #else base::FEATURE_DISABLED_BY_DEFAULT
diff --git a/gpu/config/gpu_switches.cc b/gpu/config/gpu_switches.cc index 4ba7c3e8..f59be13 100644 --- a/gpu/config/gpu_switches.cc +++ b/gpu/config/gpu_switches.cc
@@ -35,7 +35,7 @@ // Allows explicitly specifying the shader disk cache size for embedded devices. // Default value is 6MB. On Android, 2MB is default and 128KB for low-end // devices. -const char kShaderDiskCacheSizeKB[] = "shader-disk-cache-size-kb"; +const char kGpuDiskCacheSizeKB[] = "gpu-disk-cache-size-kb"; // Disables the non-sandboxed GPU process for DX12 info collection const char kDisableGpuProcessForDX12InfoCollection[] =
diff --git a/gpu/config/gpu_switches.h b/gpu/config/gpu_switches.h index 0dc1a04a..80a737d5 100644 --- a/gpu/config/gpu_switches.h +++ b/gpu/config/gpu_switches.h
@@ -16,7 +16,7 @@ GPU_EXPORT extern const char kGpuDriverBugListTestGroup[]; GPU_EXPORT extern const char kGpuPreferences[]; GPU_EXPORT extern const char kIgnoreGpuBlocklist[]; -GPU_EXPORT extern const char kShaderDiskCacheSizeKB[]; +GPU_EXPORT extern const char kGpuDiskCacheSizeKB[]; GPU_EXPORT extern const char kDisableGpuProcessForDX12InfoCollection[]; GPU_EXPORT extern const char kEnableUnsafeWebGPU[]; GPU_EXPORT extern const char kEnableWebGPUDeveloperFeatures[];
diff --git a/gpu/config/gpu_workaround_list.txt b/gpu/config/gpu_workaround_list.txt index 82c0e2a..f795d57 100644 --- a/gpu/config/gpu_workaround_list.txt +++ b/gpu/config/gpu_workaround_list.txt
@@ -99,7 +99,6 @@ max_copy_texture_chromium_size_1048576 max_msaa_sample_count_2 max_msaa_sample_count_4 -max_texture_size_limit_4096 msaa_is_slow msaa_is_slow_2 multisample_renderbuffer_resize_emulation @@ -141,3 +140,4 @@ use_virtualized_gl_contexts validate_multisample_buffer_allocation wake_up_gpu_before_drawing +webgl_or_caps_max_texture_size_limit_4096
diff --git a/gpu/ipc/host/gpu_disk_cache.cc b/gpu/ipc/host/gpu_disk_cache.cc index 25c0359..c5dae10 100644 --- a/gpu/ipc/host/gpu_disk_cache.cc +++ b/gpu/ipc/host/gpu_disk_cache.cc
@@ -45,18 +45,18 @@ } // namespace -// ShaderDiskCacheEntry handles the work of caching/updating the cached -// shaders. -class ShaderDiskCacheEntry : public base::ThreadChecker { +// GpuDiskCacheEntry handles the work of caching/updating the cached +// blobs. +class GpuDiskCacheEntry { public: - ShaderDiskCacheEntry(ShaderDiskCache* cache, - const std::string& key, - const std::string& shader); + GpuDiskCacheEntry(GpuDiskCache* cache, + const std::string& key, + const std::string& blob); - ShaderDiskCacheEntry(const ShaderDiskCacheEntry&) = delete; - ShaderDiskCacheEntry& operator=(const ShaderDiskCacheEntry&) = delete; + GpuDiskCacheEntry(const GpuDiskCacheEntry&) = delete; + GpuDiskCacheEntry& operator=(const GpuDiskCacheEntry&) = delete; - ~ShaderDiskCacheEntry(); + ~GpuDiskCacheEntry(); void Cache(); void OnOpComplete(int rv); @@ -73,27 +73,29 @@ int WriteCallback(int rv); int IOComplete(int rv); - raw_ptr<ShaderDiskCache> cache_; - OpType op_type_; + THREAD_CHECKER(thread_checker_); + + raw_ptr<GpuDiskCache> cache_; + OpType op_type_ = OPEN_ENTRY; std::string key_; - std::string shader_; + std::string blob_; raw_ptr<disk_cache::Entry> entry_; - base::WeakPtr<ShaderDiskCacheEntry> weak_ptr_; - base::WeakPtrFactory<ShaderDiskCacheEntry> weak_ptr_factory_{this}; + base::WeakPtr<GpuDiskCacheEntry> weak_ptr_; + base::WeakPtrFactory<GpuDiskCacheEntry> weak_ptr_factory_{this}; }; -// ShaderDiskReadHelper is used to load all of the cached shaders from the +// GpuDiskCacheReadHelper is used to load all of the cached blobs from the // disk cache and send to the memory cache. -class ShaderDiskReadHelper : public base::ThreadChecker { +class GpuDiskCacheReadHelper { public: - using ShaderLoadedCallback = ShaderDiskCache::ShaderLoadedCallback; - ShaderDiskReadHelper(ShaderDiskCache* cache, - const ShaderLoadedCallback& callback); + using BlobLoadedCallback = GpuDiskCache::BlobLoadedCallback; + GpuDiskCacheReadHelper(GpuDiskCache* cache, + const BlobLoadedCallback& callback); - ShaderDiskReadHelper(const ShaderDiskReadHelper&) = delete; - ShaderDiskReadHelper& operator=(const ShaderDiskReadHelper&) = delete; + GpuDiskCacheReadHelper(const GpuDiskCacheReadHelper&) = delete; + GpuDiskCacheReadHelper& operator=(const GpuDiskCacheReadHelper&) = delete; - ~ShaderDiskReadHelper(); + ~GpuDiskCacheReadHelper(); void LoadCache(); void OnOpComplete(int rv); @@ -113,70 +115,70 @@ int ReadComplete(int rv); int IterationComplete(int rv); - raw_ptr<ShaderDiskCache> cache_; - ShaderLoadedCallback shader_loaded_callback_; - OpType op_type_; + THREAD_CHECKER(thread_checker_); + + raw_ptr<GpuDiskCache> cache_; + BlobLoadedCallback blob_loaded_callback_; + OpType op_type_ = OPEN_NEXT; std::unique_ptr<disk_cache::Backend::Iterator> iter_; scoped_refptr<net::IOBufferWithSize> buf_; raw_ptr<disk_cache::Entry> entry_; - base::WeakPtrFactory<ShaderDiskReadHelper> weak_ptr_factory_{this}; + base::WeakPtrFactory<GpuDiskCacheReadHelper> weak_ptr_factory_{this}; }; -class ShaderClearHelper : public base::ThreadChecker { +class GpuDiskCacheClearHelper { public: - ShaderClearHelper(ShaderCacheFactory* factory, - scoped_refptr<ShaderDiskCache> cache, - const base::FilePath& path, - const base::Time& delete_begin, - const base::Time& delete_end, - base::OnceClosure callback); + GpuDiskCacheClearHelper(GpuDiskCacheFactory* factory, + scoped_refptr<GpuDiskCache> cache, + const base::FilePath& path, + const base::Time& delete_begin, + const base::Time& delete_end, + base::OnceClosure callback); - ShaderClearHelper(const ShaderClearHelper&) = delete; - ShaderClearHelper& operator=(const ShaderClearHelper&) = delete; + GpuDiskCacheClearHelper(const GpuDiskCacheClearHelper&) = delete; + GpuDiskCacheClearHelper& operator=(const GpuDiskCacheClearHelper&) = delete; - ~ShaderClearHelper(); + ~GpuDiskCacheClearHelper(); void Clear(); private: enum OpType { TERMINATE, VERIFY_CACHE_SETUP, DELETE_CACHE }; - void DoClearShaderCache(int rv); + void DoClearGpuCache(int rv); - raw_ptr<ShaderCacheFactory> factory_; - scoped_refptr<ShaderDiskCache> cache_; - OpType op_type_; + THREAD_CHECKER(thread_checker_); + + raw_ptr<GpuDiskCacheFactory> factory_; + scoped_refptr<GpuDiskCache> cache_; + OpType op_type_ = VERIFY_CACHE_SETUP; base::FilePath path_; base::Time delete_begin_; base::Time delete_end_; base::OnceClosure callback_; - base::WeakPtrFactory<ShaderClearHelper> weak_ptr_factory_{this}; + base::WeakPtrFactory<GpuDiskCacheClearHelper> weak_ptr_factory_{this}; }; //////////////////////////////////////////////////////////////////////////////// -// ShaderDiskCacheEntry +// GpuDiskCacheEntry -ShaderDiskCacheEntry::ShaderDiskCacheEntry(ShaderDiskCache* cache, - const std::string& key, - const std::string& shader) - : cache_(cache), - op_type_(OPEN_ENTRY), - key_(key), - shader_(shader), - entry_(nullptr) { +GpuDiskCacheEntry::GpuDiskCacheEntry(GpuDiskCache* cache, + const std::string& key, + const std::string& blob) + : cache_(cache), key_(key), blob_(blob), entry_(nullptr) { weak_ptr_ = weak_ptr_factory_.GetWeakPtr(); } -ShaderDiskCacheEntry::~ShaderDiskCacheEntry() { - DCHECK(CalledOnValidThread()); +GpuDiskCacheEntry::~GpuDiskCacheEntry() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); if (entry_) entry_->Close(); } -void ShaderDiskCacheEntry::Cache() { - DCHECK(CalledOnValidThread()); +void GpuDiskCacheEntry::Cache() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - auto callback = base::BindOnce(&ShaderDiskCacheEntry::OnEntryOpenComplete, + auto callback = base::BindOnce(&GpuDiskCacheEntry::OnEntryOpenComplete, weak_ptr_factory_.GetWeakPtr()); disk_cache::EntryResult result = @@ -185,8 +187,8 @@ OnEntryOpenComplete(std::move(result)); } -void ShaderDiskCacheEntry::OnOpComplete(int rv) { - DCHECK(CalledOnValidThread()); +void GpuDiskCacheEntry::OnOpComplete(int rv) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); // The function calls inside the switch block below can end up destroying // |this|. So hold on to a WeakPtr<>, and terminate the while loop if |this| // has been destroyed. @@ -208,14 +210,14 @@ weak_ptr_ = std::move(weak_ptr); } -void ShaderDiskCacheEntry::OnEntryOpenComplete(disk_cache::EntryResult result) { +void GpuDiskCacheEntry::OnEntryOpenComplete(disk_cache::EntryResult result) { int rv = result.net_error(); entry_ = result.ReleaseEntry(); OnOpComplete(rv); } -int ShaderDiskCacheEntry::OpenCallback(int rv) { - DCHECK(CalledOnValidThread()); +int GpuDiskCacheEntry::OpenCallback(int rv) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); if (rv == net::OK) { cache_->backend()->OnExternalCacheHit(key_); cache_->EntryComplete(this); @@ -224,7 +226,7 @@ op_type_ = CREATE_ENTRY; - auto callback = base::BindOnce(&ShaderDiskCacheEntry::OnEntryOpenComplete, + auto callback = base::BindOnce(&GpuDiskCacheEntry::OnEntryOpenComplete, weak_ptr_factory_.GetWeakPtr()); disk_cache::EntryResult create_result = @@ -236,53 +238,53 @@ return rv; } -int ShaderDiskCacheEntry::WriteCallback(int rv) { - DCHECK(CalledOnValidThread()); +int GpuDiskCacheEntry::WriteCallback(int rv) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); if (rv != net::OK) { - LOG(ERROR) << "Failed to create shader cache entry: " << rv; + LOG(ERROR) << "Failed to create blob cache entry: " << rv; cache_->EntryComplete(this); return rv; } op_type_ = WRITE_DATA; - auto io_buf = base::MakeRefCounted<net::StringIOBuffer>(shader_); - return entry_->WriteData(1, 0, io_buf.get(), shader_.length(), - base::BindOnce(&ShaderDiskCacheEntry::OnOpComplete, + auto io_buf = base::MakeRefCounted<net::StringIOBuffer>(blob_); + return entry_->WriteData(1, 0, io_buf.get(), blob_.length(), + base::BindOnce(&GpuDiskCacheEntry::OnOpComplete, weak_ptr_factory_.GetWeakPtr()), false); } -int ShaderDiskCacheEntry::IOComplete(int rv) { - DCHECK(CalledOnValidThread()); +int GpuDiskCacheEntry::IOComplete(int rv) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); cache_->EntryComplete(this); return rv; } //////////////////////////////////////////////////////////////////////////////// -// ShaderDiskReadHelper +// GpuDiskCacheReadHelper -ShaderDiskReadHelper::ShaderDiskReadHelper(ShaderDiskCache* cache, - const ShaderLoadedCallback& callback) +GpuDiskCacheReadHelper::GpuDiskCacheReadHelper( + GpuDiskCache* cache, + const BlobLoadedCallback& callback) : cache_(cache), - shader_loaded_callback_(callback), - op_type_(OPEN_NEXT), + blob_loaded_callback_(callback), buf_(nullptr), entry_(nullptr) {} -ShaderDiskReadHelper::~ShaderDiskReadHelper() { - DCHECK(CalledOnValidThread()); +GpuDiskCacheReadHelper::~GpuDiskCacheReadHelper() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); if (entry_) entry_->Close(); iter_ = nullptr; } -void ShaderDiskReadHelper::LoadCache() { - DCHECK(CalledOnValidThread()); +void GpuDiskCacheReadHelper::LoadCache() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); OnOpComplete(net::OK); } -void ShaderDiskReadHelper::OnOpComplete(int rv) { - DCHECK(CalledOnValidThread()); +void GpuDiskCacheReadHelper::OnOpComplete(int rv) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); do { switch (op_type_) { case OPEN_NEXT: @@ -305,19 +307,20 @@ } while (rv != net::ERR_IO_PENDING); } -void ShaderDiskReadHelper::OnEntryOpenComplete(disk_cache::EntryResult result) { +void GpuDiskCacheReadHelper::OnEntryOpenComplete( + disk_cache::EntryResult result) { int rv = result.net_error(); entry_ = result.ReleaseEntry(); OnOpComplete(rv); } -int ShaderDiskReadHelper::OpenNextEntry() { - DCHECK(CalledOnValidThread()); +int GpuDiskCacheReadHelper::OpenNextEntry() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); op_type_ = OPEN_NEXT_COMPLETE; if (!iter_) iter_ = cache_->backend()->CreateIterator(); - auto callback = base::BindOnce(&ShaderDiskReadHelper::OnEntryOpenComplete, + auto callback = base::BindOnce(&GpuDiskCacheReadHelper::OnEntryOpenComplete, weak_ptr_factory_.GetWeakPtr()); disk_cache::EntryResult result = iter_->OpenNextEntry(std::move(callback)); @@ -328,8 +331,8 @@ return rv; } -int ShaderDiskReadHelper::OpenNextEntryComplete(int rv) { - DCHECK(CalledOnValidThread()); +int GpuDiskCacheReadHelper::OpenNextEntryComplete(int rv) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); if (rv == net::ERR_FAILED) { iter_.reset(); op_type_ = ITERATION_FINISHED; @@ -342,15 +345,15 @@ op_type_ = READ_COMPLETE; buf_ = base::MakeRefCounted<net::IOBufferWithSize>(entry_->GetDataSize(1)); return entry_->ReadData(1, 0, buf_.get(), buf_->size(), - base::BindOnce(&ShaderDiskReadHelper::OnOpComplete, + base::BindOnce(&GpuDiskCacheReadHelper::OnOpComplete, weak_ptr_factory_.GetWeakPtr())); } -int ShaderDiskReadHelper::ReadComplete(int rv) { - DCHECK(CalledOnValidThread()); - if (rv && rv == buf_->size() && !shader_loaded_callback_.is_null()) { - shader_loaded_callback_.Run(entry_->GetKey(), - std::string(buf_->data(), buf_->size())); +int GpuDiskCacheReadHelper::ReadComplete(int rv) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + if (rv && rv == buf_->size() && !blob_loaded_callback_.is_null()) { + blob_loaded_callback_.Run(entry_->GetKey(), + std::string(buf_->data(), buf_->size())); } buf_ = nullptr; @@ -361,54 +364,54 @@ return net::OK; } -int ShaderDiskReadHelper::IterationComplete(int rv) { - DCHECK(CalledOnValidThread()); +int GpuDiskCacheReadHelper::IterationComplete(int rv) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); iter_.reset(); op_type_ = TERMINATE; return net::OK; } //////////////////////////////////////////////////////////////////////////////// -// ShaderClearHelper +// GpuDiskCacheClearHelper -ShaderClearHelper::ShaderClearHelper(ShaderCacheFactory* factory, - scoped_refptr<ShaderDiskCache> cache, - const base::FilePath& path, - const base::Time& delete_begin, - const base::Time& delete_end, - base::OnceClosure callback) +GpuDiskCacheClearHelper::GpuDiskCacheClearHelper( + GpuDiskCacheFactory* factory, + scoped_refptr<GpuDiskCache> cache, + const base::FilePath& path, + const base::Time& delete_begin, + const base::Time& delete_end, + base::OnceClosure callback) : factory_(factory), cache_(std::move(cache)), - op_type_(VERIFY_CACHE_SETUP), path_(path), delete_begin_(delete_begin), delete_end_(delete_end), callback_(std::move(callback)) {} -ShaderClearHelper::~ShaderClearHelper() { - DCHECK(CalledOnValidThread()); +GpuDiskCacheClearHelper::~GpuDiskCacheClearHelper() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); } -void ShaderClearHelper::Clear() { - DCHECK(CalledOnValidThread()); - DoClearShaderCache(net::OK); +void GpuDiskCacheClearHelper::Clear() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DoClearGpuCache(net::OK); } -void ShaderClearHelper::DoClearShaderCache(int rv) { - DCHECK(CalledOnValidThread()); +void GpuDiskCacheClearHelper::DoClearGpuCache(int rv) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); while (rv != net::ERR_IO_PENDING) { switch (op_type_) { case VERIFY_CACHE_SETUP: rv = cache_->SetAvailableCallback( - base::BindOnce(&ShaderClearHelper::DoClearShaderCache, + base::BindOnce(&GpuDiskCacheClearHelper::DoClearGpuCache, weak_ptr_factory_.GetWeakPtr())); op_type_ = DELETE_CACHE; break; case DELETE_CACHE: - rv = - cache_->Clear(delete_begin_, delete_end_, - base::BindOnce(&ShaderClearHelper::DoClearShaderCache, - weak_ptr_factory_.GetWeakPtr())); + rv = cache_->Clear( + delete_begin_, delete_end_, + base::BindOnce(&GpuDiskCacheClearHelper::DoClearGpuCache, + weak_ptr_factory_.GetWeakPtr())); op_type_ = TERMINATE; break; case TERMINATE: @@ -422,106 +425,106 @@ } //////////////////////////////////////////////////////////////////////////////// -// ShaderCacheFactory +// GpuDiskCacheFactory -ShaderCacheFactory::ShaderCacheFactory() = default; +GpuDiskCacheFactory::GpuDiskCacheFactory() = default; -ShaderCacheFactory::~ShaderCacheFactory() = default; +GpuDiskCacheFactory::~GpuDiskCacheFactory() = default; -void ShaderCacheFactory::SetCacheInfo(int32_t client_id, - const base::FilePath& path) { - DCHECK(CalledOnValidThread()); +void GpuDiskCacheFactory::SetCacheInfo(int32_t client_id, + const base::FilePath& path) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); client_id_to_path_map_[client_id] = path; } -void ShaderCacheFactory::RemoveCacheInfo(int32_t client_id) { - DCHECK(CalledOnValidThread()); +void GpuDiskCacheFactory::RemoveCacheInfo(int32_t client_id) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); client_id_to_path_map_.erase(client_id); } -scoped_refptr<ShaderDiskCache> ShaderCacheFactory::Get(int32_t client_id) { - DCHECK(CalledOnValidThread()); +scoped_refptr<GpuDiskCache> GpuDiskCacheFactory::Get(int32_t client_id) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); ClientIdToPathMap::iterator iter = client_id_to_path_map_.find(client_id); if (iter == client_id_to_path_map_.end()) return nullptr; - return ShaderCacheFactory::GetByPath(iter->second); + return GpuDiskCacheFactory::GetByPath(iter->second); } -scoped_refptr<ShaderDiskCache> ShaderCacheFactory::GetByPath( +scoped_refptr<GpuDiskCache> GpuDiskCacheFactory::GetByPath( const base::FilePath& path) { - DCHECK(CalledOnValidThread()); - ShaderCacheMap::iterator iter = shader_cache_map_.find(path); - if (iter != shader_cache_map_.end()) + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + auto iter = gpu_cache_map_.find(path); + if (iter != gpu_cache_map_.end()) return iter->second; - auto cache = base::WrapRefCounted(new ShaderDiskCache(this, path)); + auto cache = base::WrapRefCounted(new GpuDiskCache(this, path)); cache->Init(); return cache; } -void ShaderCacheFactory::AddToCache(const base::FilePath& key, - ShaderDiskCache* cache) { - DCHECK(CalledOnValidThread()); - shader_cache_map_[key] = cache; +void GpuDiskCacheFactory::AddToCache(const base::FilePath& key, + GpuDiskCache* cache) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + gpu_cache_map_[key] = cache; } -void ShaderCacheFactory::RemoveFromCache(const base::FilePath& key) { - DCHECK(CalledOnValidThread()); - shader_cache_map_.erase(key); +void GpuDiskCacheFactory::RemoveFromCache(const base::FilePath& key) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + gpu_cache_map_.erase(key); } -void ShaderCacheFactory::ClearByPath(const base::FilePath& path, - const base::Time& delete_begin, - const base::Time& delete_end, - base::OnceClosure callback) { - DCHECK(CalledOnValidThread()); +void GpuDiskCacheFactory::ClearByPath(const base::FilePath& path, + const base::Time& delete_begin, + const base::Time& delete_end, + base::OnceClosure callback) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(!callback.is_null()); if (path.empty()) { std::move(callback).Run(); return; } - auto helper = std::make_unique<ShaderClearHelper>(this, GetByPath(path), path, - delete_begin, delete_end, - std::move(callback)); + auto helper = std::make_unique<GpuDiskCacheClearHelper>( + this, GetByPath(path), path, delete_begin, delete_end, + std::move(callback)); // We could receive requests to clear the same path with different // begin/end times. So, we keep a list of requests. If we haven't seen this // path before we kick off the clear and add it to the list. If we have see it // already, then we already have a clear running. We add this clear to the // list and wait for any previous clears to finish. - ShaderClearMap::iterator iter = shader_clear_map_.find(path); - if (iter != shader_clear_map_.end()) { + auto iter = gpu_clear_map_.find(path); + if (iter != gpu_clear_map_.end()) { iter->second.push(std::move(helper)); return; } // Insert the helper in the map before calling Clear(), since it can lead to a // call back into CacheCleared(). - ShaderClearHelper* helper_ptr = helper.get(); - shader_clear_map_.insert( - std::pair<base::FilePath, ShaderClearQueue>(path, ShaderClearQueue())); - shader_clear_map_[path].push(std::move(helper)); + GpuDiskCacheClearHelper* helper_ptr = helper.get(); + gpu_clear_map_.insert( + std::pair<base::FilePath, ClearHelperQueue>(path, ClearHelperQueue())); + gpu_clear_map_[path].push(std::move(helper)); helper_ptr->Clear(); } -void ShaderCacheFactory::ClearByClientId(int32_t client_id, - const base::Time& delete_begin, - const base::Time& delete_end, - base::OnceClosure callback) { - DCHECK(CalledOnValidThread()); - ClientIdToPathMap::iterator iter = client_id_to_path_map_.find(client_id); +void GpuDiskCacheFactory::ClearByClientId(int32_t client_id, + const base::Time& delete_begin, + const base::Time& delete_end, + base::OnceClosure callback) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + auto iter = client_id_to_path_map_.find(client_id); if (iter == client_id_to_path_map_.end()) return; return ClearByPath(iter->second, delete_begin, delete_end, std::move(callback)); } -void ShaderCacheFactory::CacheCleared(const base::FilePath& path) { - DCHECK(CalledOnValidThread()); +void GpuDiskCacheFactory::CacheCleared(const base::FilePath& path) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - ShaderClearMap::iterator iter = shader_clear_map_.find(path); - if (iter == shader_clear_map_.end()) { + auto iter = gpu_clear_map_.find(path); + if (iter == gpu_clear_map_.end()) { LOG(ERROR) << "Completed clear but missing clear helper."; return; } @@ -535,38 +538,36 @@ return; } - shader_clear_map_.erase(iter); + gpu_clear_map_.erase(iter); } //////////////////////////////////////////////////////////////////////////////// -// ShaderDiskCache +// GpuDiskCache -ShaderDiskCache::ShaderDiskCache(ShaderCacheFactory* factory, - const base::FilePath& cache_path) - : factory_(factory), - cache_available_(false), - cache_path_(cache_path), - is_initialized_(false) { +GpuDiskCache::GpuDiskCache(GpuDiskCacheFactory* factory, + const base::FilePath& cache_path) + : factory_(factory), cache_path_(cache_path) { factory_->AddToCache(cache_path_, this); } -ShaderDiskCache::~ShaderDiskCache() { +GpuDiskCache::~GpuDiskCache() { factory_->RemoveFromCache(cache_path_); } -void ShaderDiskCache::Init() { +void GpuDiskCache::Init() { if (is_initialized_) { NOTREACHED(); // can't initialize disk cache twice. return; } is_initialized_ = true; + // TODO(dawn:549) Add GPU_CACHE type and replace SHADER_CACHE here. disk_cache::BackendResult rv = disk_cache::CreateCacheBackend( net::SHADER_CACHE, net::CACHE_BACKEND_DEFAULT, /*file_operations=*/nullptr, cache_path_.Append(kGpuCachePath), CacheSizeBytes(), disk_cache::ResetHandling::kResetOnError, /*net_log=*/nullptr, - base::BindOnce(&ShaderDiskCache::CacheCreatedCallback, this)); + base::BindOnce(&GpuDiskCache::CacheCreatedCallback, this)); if (rv.net_error == net::OK) { NOTREACHED(); // This shouldn't actually happen with a non-memory backend. @@ -575,19 +576,19 @@ } } -void ShaderDiskCache::Cache(const std::string& key, const std::string& shader) { +void GpuDiskCache::Cache(const std::string& key, const std::string& blob) { if (!cache_available_) return; - auto shim = std::make_unique<ShaderDiskCacheEntry>(this, key, shader); + auto shim = std::make_unique<GpuDiskCacheEntry>(this, key, blob); shim->Cache(); auto* raw_ptr = shim.get(); entries_.insert(std::make_pair(raw_ptr, std::move(shim))); } -int ShaderDiskCache::Clear(const base::Time begin_time, - const base::Time end_time, - net::CompletionOnceCallback completion_callback) { +int GpuDiskCache::Clear(const base::Time begin_time, + const base::Time end_time, + net::CompletionOnceCallback completion_callback) { int rv; if (begin_time.is_null()) { rv = backend_->DoomAllEntries(std::move(completion_callback)); @@ -598,38 +599,37 @@ return rv; } -int32_t ShaderDiskCache::Size() { +int32_t GpuDiskCache::Size() { if (!cache_available_) return -1; return backend_->GetEntryCount(); } -int ShaderDiskCache::SetAvailableCallback( - net::CompletionOnceCallback callback) { +int GpuDiskCache::SetAvailableCallback(net::CompletionOnceCallback callback) { if (cache_available_) return net::OK; available_callback_ = std::move(callback); return net::ERR_IO_PENDING; } -void ShaderDiskCache::CacheCreatedCallback(disk_cache::BackendResult result) { +void GpuDiskCache::CacheCreatedCallback(disk_cache::BackendResult result) { if (result.net_error != net::OK) { - LOG(ERROR) << "Shader Cache Creation failed: " << result.net_error; + LOG(ERROR) << "Gpu Cache Creation failed: " << result.net_error; return; } backend_ = std::move(result.backend); helper_ = - std::make_unique<ShaderDiskReadHelper>(this, shader_loaded_callback_); + std::make_unique<GpuDiskCacheReadHelper>(this, blob_loaded_callback_); helper_->LoadCache(); } -void ShaderDiskCache::EntryComplete(ShaderDiskCacheEntry* entry) { +void GpuDiskCache::EntryComplete(GpuDiskCacheEntry* entry) { entries_.erase(entry); if (entries_.empty() && cache_complete_callback_) std::move(cache_complete_callback_).Run(net::OK); } -void ShaderDiskCache::ReadComplete() { +void GpuDiskCache::ReadComplete() { helper_ = nullptr; // The cache is considered available after we have finished reading any @@ -640,7 +640,7 @@ std::move(available_callback_).Run(net::OK); } -int ShaderDiskCache::SetCacheCompleteCallback( +int GpuDiskCache::SetCacheCompleteCallback( net::CompletionOnceCallback callback) { if (entries_.empty()) { return net::OK; @@ -650,10 +650,10 @@ } // static -size_t ShaderDiskCache::CacheSizeBytes() { +size_t GpuDiskCache::CacheSizeBytes() { #if !BUILDFLAG(IS_ANDROID) size_t custom_cache_size = - GetCustomCacheSizeBytesIfExists(switches::kShaderDiskCacheSizeKB); + GetCustomCacheSizeBytesIfExists(switches::kGpuDiskCacheSizeKB); if (custom_cache_size) return custom_cache_size; return kDefaultMaxProgramCacheMemoryBytes;
diff --git a/gpu/ipc/host/gpu_disk_cache.h b/gpu/ipc/host/gpu_disk_cache.h index 072be1d..b4f87d08 100644 --- a/gpu/ipc/host/gpu_disk_cache.h +++ b/gpu/ipc/host/gpu_disk_cache.h
@@ -21,27 +21,26 @@ namespace gpu { -class ShaderCacheFactory; -class ShaderDiskCacheEntry; -class ShaderDiskReadHelper; -class ShaderClearHelper; +class GpuDiskCacheFactory; +class GpuDiskCacheEntry; +class GpuDiskCacheReadHelper; +class GpuDiskCacheClearHelper; -// ShaderDiskCache is the interface to the on disk cache for -// GL shaders. -class ShaderDiskCache : public base::RefCounted<ShaderDiskCache> { +// GpuDiskCache is the interface to the on disk cache for the GPU process. +class GpuDiskCache : public base::RefCounted<GpuDiskCache> { public: - using ShaderLoadedCallback = + using BlobLoadedCallback = base::RepeatingCallback<void(const std::string&, const std::string&)>; - ShaderDiskCache(const ShaderDiskCache&) = delete; - ShaderDiskCache& operator=(const ShaderDiskCache&) = delete; + GpuDiskCache(const GpuDiskCache&) = delete; + GpuDiskCache& operator=(const GpuDiskCache&) = delete; - void set_shader_loaded_callback(const ShaderLoadedCallback& callback) { - shader_loaded_callback_ = callback; + void SetBlobLoadedCallback(const BlobLoadedCallback& callback) { + blob_loaded_callback_ = callback; } - // Store the |shader| into the cache under |key|. - void Cache(const std::string& key, const std::string& shader); + // Store the |blob| into the cache under |key|. + void Cache(const std::string& key, const std::string& blob); // Clear a range of entries. This supports unbounded deletes in either // direction by using null Time values for either |begin_time| or |end_time|. @@ -68,55 +67,53 @@ // been written to the cache. int SetCacheCompleteCallback(net::CompletionOnceCallback callback); - // Returns the size which should be used for the shader disk cache. + // Returns the size which should be used for the gpu disk cache. static size_t CacheSizeBytes(); private: - friend class base::RefCounted<ShaderDiskCache>; - friend class ShaderDiskCacheEntry; - friend class ShaderDiskReadHelper; - friend class ShaderCacheFactory; + friend class base::RefCounted<GpuDiskCache>; + friend class GpuDiskCacheEntry; + friend class GpuDiskCacheReadHelper; + friend class GpuDiskCacheFactory; - ShaderDiskCache(ShaderCacheFactory* factory, - const base::FilePath& cache_path); - ~ShaderDiskCache(); + GpuDiskCache(GpuDiskCacheFactory* factory, const base::FilePath& cache_path); + ~GpuDiskCache(); void Init(); void CacheCreatedCallback(disk_cache::BackendResult rv); disk_cache::Backend* backend() { return backend_.get(); } - void EntryComplete(ShaderDiskCacheEntry* entry); + void EntryComplete(GpuDiskCacheEntry* entry); void ReadComplete(); - raw_ptr<ShaderCacheFactory> factory_; - bool cache_available_; + raw_ptr<GpuDiskCacheFactory> factory_; + bool cache_available_ = false; base::FilePath cache_path_; - bool is_initialized_; + bool is_initialized_ = false; net::CompletionOnceCallback available_callback_; net::CompletionOnceCallback cache_complete_callback_; - ShaderLoadedCallback shader_loaded_callback_; + BlobLoadedCallback blob_loaded_callback_; std::unique_ptr<disk_cache::Backend> backend_; - std::unique_ptr<ShaderDiskReadHelper> helper_; - std::unordered_map<ShaderDiskCacheEntry*, - std::unique_ptr<ShaderDiskCacheEntry>> + std::unique_ptr<GpuDiskCacheReadHelper> helper_; + std::unordered_map<GpuDiskCacheEntry*, std::unique_ptr<GpuDiskCacheEntry>> entries_; }; -// ShaderCacheFactory maintains a cache of ShaderDiskCache objects -// so we only create one per profile directory. -class ShaderCacheFactory : public base::ThreadChecker { +// GpuDiskCacheFactory maintains a cache of GpuDiskCache objects so we only +// create one per profile directory. +class GpuDiskCacheFactory { public: - ShaderCacheFactory(); + GpuDiskCacheFactory(); - ShaderCacheFactory(const ShaderCacheFactory&) = delete; - ShaderCacheFactory& operator=(const ShaderCacheFactory&) = delete; + GpuDiskCacheFactory(const GpuDiskCacheFactory&) = delete; + GpuDiskCacheFactory& operator=(const GpuDiskCacheFactory&) = delete; - ~ShaderCacheFactory(); + ~GpuDiskCacheFactory(); - // Clear the shader disk cache for the given |path|. This supports unbounded + // Clear the gpu disk cache for the given |path|. This supports unbounded // deletes in either direction by using null Time values for either // |begin_time| or |end_time|. The |callback| will be executed when the // clear is complete. @@ -132,8 +129,8 @@ const base::Time& end_time, base::OnceClosure callback); - // Retrieve the shader disk cache for the provided |client_id|. - scoped_refptr<ShaderDiskCache> Get(int32_t client_id); + // Retrieve the gpu disk cache for the provided |client_id|. + scoped_refptr<GpuDiskCache> Get(int32_t client_id); // Set the |path| to be used for the disk cache for |client_id|. void SetCacheInfo(int32_t client_id, const base::FilePath& path); @@ -142,26 +139,29 @@ void RemoveCacheInfo(int32_t client_id); // Set the provided |cache| into the cache map for the given |path|. - void AddToCache(const base::FilePath& path, ShaderDiskCache* cache); + void AddToCache(const base::FilePath& path, GpuDiskCache* cache); // Remove the provided |path| from our cache map. void RemoveFromCache(const base::FilePath& path); private: - friend class ShaderClearHelper; + friend class GpuDiskCacheClearHelper; - scoped_refptr<ShaderDiskCache> GetByPath(const base::FilePath& path); + scoped_refptr<GpuDiskCache> GetByPath(const base::FilePath& path); void CacheCleared(const base::FilePath& path); - using ShaderCacheMap = std::map<base::FilePath, ShaderDiskCache*>; - ShaderCacheMap shader_cache_map_; + THREAD_CHECKER(thread_checker_); + + using PathToCacheMap = std::map<base::FilePath, GpuDiskCache*>; + PathToCacheMap gpu_cache_map_; using ClientIdToPathMap = std::map<int32_t, base::FilePath>; ClientIdToPathMap client_id_to_path_map_; - using ShaderClearQueue = base::queue<std::unique_ptr<ShaderClearHelper>>; - using ShaderClearMap = std::map<base::FilePath, ShaderClearQueue>; - ShaderClearMap shader_clear_map_; + using ClearHelperQueue = + base::queue<std::unique_ptr<GpuDiskCacheClearHelper>>; + using PathToClearHelperQueueMap = std::map<base::FilePath, ClearHelperQueue>; + PathToClearHelperQueueMap gpu_clear_map_; }; } // namespace gpu
diff --git a/gpu/ipc/host/gpu_disk_cache_unittest.cc b/gpu/ipc/host/gpu_disk_cache_unittest.cc index 5396f7d6..362e44a 100644 --- a/gpu/ipc/host/gpu_disk_cache_unittest.cc +++ b/gpu/ipc/host/gpu_disk_cache_unittest.cc
@@ -22,14 +22,14 @@ } // namespace -class ShaderDiskCacheTest : public testing::Test { +class GpuDiskCacheTest : public testing::Test { public: - ShaderDiskCacheTest() = default; + GpuDiskCacheTest() = default; - ShaderDiskCacheTest(const ShaderDiskCacheTest&) = delete; - ShaderDiskCacheTest& operator=(const ShaderDiskCacheTest&) = delete; + GpuDiskCacheTest(const GpuDiskCacheTest&) = delete; + GpuDiskCacheTest& operator=(const GpuDiskCacheTest&) = delete; - ~ShaderDiskCacheTest() override = default; + ~GpuDiskCacheTest() override = default; const base::FilePath& cache_path() { return temp_dir_.GetPath(); } @@ -38,7 +38,7 @@ factory_.SetCacheInfo(kDefaultClientId, cache_path()); } - ShaderCacheFactory* factory() { return &factory_; } + GpuDiskCacheFactory* factory() { return &factory_; } private: void TearDown() override { @@ -52,13 +52,13 @@ base::test::TaskEnvironment task_environment_; base::ScopedTempDir temp_dir_; - ShaderCacheFactory factory_; + GpuDiskCacheFactory factory_; }; -TEST_F(ShaderDiskCacheTest, ClearsCache) { +TEST_F(GpuDiskCacheTest, ClearsCache) { InitCache(); - scoped_refptr<ShaderDiskCache> cache = factory()->Get(kDefaultClientId); + scoped_refptr<GpuDiskCache> cache = factory()->Get(kDefaultClientId); ASSERT_TRUE(cache.get() != nullptr); net::TestCompletionCallback available_cb; @@ -80,7 +80,7 @@ EXPECT_EQ(0, cache->Size()); } -TEST_F(ShaderDiskCacheTest, ClearByPathTriggersCallback) { +TEST_F(GpuDiskCacheTest, ClearByPathTriggersCallback) { InitCache(); factory()->Get(kDefaultClientId)->Cache(kCacheKey, kCacheValue); net::TestCompletionCallback test_callback; @@ -91,7 +91,7 @@ } // Important for clearing in-memory profiles. -TEST_F(ShaderDiskCacheTest, ClearByPathWithEmptyPathTriggersCallback) { +TEST_F(GpuDiskCacheTest, ClearByPathWithEmptyPathTriggersCallback) { net::TestCompletionCallback test_callback; factory()->ClearByPath( base::FilePath(), base::Time(), base::Time::Max(), @@ -100,11 +100,11 @@ } // For https://crbug.com/663589. -TEST_F(ShaderDiskCacheTest, SafeToDeleteCacheMidEntryOpen) { +TEST_F(GpuDiskCacheTest, SafeToDeleteCacheMidEntryOpen) { InitCache(); // Create a cache and wait for it to open. - scoped_refptr<ShaderDiskCache> cache = factory()->Get(kDefaultClientId); + scoped_refptr<GpuDiskCache> cache = factory()->Get(kDefaultClientId); ASSERT_TRUE(cache.get() != nullptr); net::TestCompletionCallback available_cb; int rv = cache->SetAvailableCallback(available_cb.callback()); @@ -126,11 +126,11 @@ ASSERT_EQ(net::OK, available_cb2.GetResult(rv2)); } -TEST_F(ShaderDiskCacheTest, MultipleLoaderCallbacks) { +TEST_F(GpuDiskCacheTest, MultipleLoaderCallbacks) { InitCache(); // Create a cache and wait for it to open. - scoped_refptr<ShaderDiskCache> cache = factory()->Get(kDefaultClientId); + scoped_refptr<GpuDiskCache> cache = factory()->Get(kDefaultClientId); ASSERT_TRUE(cache.get() != nullptr); net::TestCompletionCallback available_cb; int rv = cache->SetAvailableCallback(available_cb.callback()); @@ -151,7 +151,7 @@ cache = factory()->Get(kDefaultClientId); ASSERT_TRUE(cache.get() != nullptr); int loaded_calls = 0; - cache->set_shader_loaded_callback(base::BindLambdaForTesting( + cache->SetBlobLoadedCallback(base::BindLambdaForTesting( [&loaded_calls](const std::string& key, const std::string& value) { ++loaded_calls; }));
diff --git a/gpu/vulkan/vulkan_image_android.cc b/gpu/vulkan/vulkan_image_android.cc index 3490b79..8b1ba24 100644 --- a/gpu/vulkan/vulkan_image_android.cc +++ b/gpu/vulkan/vulkan_image_android.cc
@@ -12,6 +12,26 @@ namespace gpu { +namespace { +bool IsSinglePlaneRGBVulkanAHBFormat(VkFormat format) { + switch (format) { + // AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM + case VK_FORMAT_R8G8B8A8_UNORM: + // AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM + case VK_FORMAT_R8G8B8_UNORM: + // AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM + case VK_FORMAT_R5G6B5_UNORM_PACK16: + // AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT + case VK_FORMAT_R16G16B16A16_SFLOAT: + // AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM + case VK_FORMAT_A2B10G10R10_UNORM_PACK32: + return true; + default: + return false; + } +} +} // namespace + bool VulkanImage::InitializeFromGpuMemoryBufferHandle( VulkanDeviceQueue* device_queue, gfx::GpuMemoryBufferHandle gmb_handle, @@ -62,8 +82,10 @@ .externalFormat = 0, }; - // If image has an external format, format must be VK_FORMAT_UNDEFINED. - if (ahb_format_props.format == VK_FORMAT_UNDEFINED) { + const bool should_use_external_format = + !IsSinglePlaneRGBVulkanAHBFormat(ahb_format_props.format); + + if (should_use_external_format) { // externalFormat must be 0 or a value returned in the externalFormat member // of VkAndroidHardwareBufferFormatPropertiesANDROID by an earlier call to // vkGetAndroidHardwareBufferPropertiesANDROID. @@ -126,8 +148,12 @@ .size = ahb_props.allocationSize, .memoryTypeBits = ahb_props.memoryTypeBits, }; - if (!Initialize(device_queue, size, ahb_format_props.format, usage_flags, - create_flags, VK_IMAGE_TILING_OPTIMAL, + + // If we want to use external format, format must be VK_FORMAT_UNDEFINED. + if (!Initialize(device_queue, size, + should_use_external_format ? VK_FORMAT_UNDEFINED + : ahb_format_props.format, + usage_flags, create_flags, VK_IMAGE_TILING_OPTIMAL, &external_memory_image_info, &ahb_import_info, &requirements)) { return false; @@ -135,7 +161,7 @@ queue_family_index_ = queue_family_index; - if (ahb_format_props.format == VK_FORMAT_UNDEFINED) { + if (should_use_external_format) { ycbcr_info_.emplace(VK_FORMAT_UNDEFINED, ahb_format_props.externalFormat, ahb_format_props.suggestedYcbcrModel, ahb_format_props.suggestedYcbcrRange,
diff --git a/infra/archive_config/lacros-arm-archive-rel.json b/infra/archive_config/lacros-arm-archive-rel.json index eaee35a..e73da57 100644 --- a/infra/archive_config/lacros-arm-archive-rel.json +++ b/infra/archive_config/lacros-arm-archive-rel.json
@@ -10,6 +10,8 @@ "headless_lib_strings.pak", "icudtl.dat", "icudtl.dat.hash", + "libEGL.so", + "libGLESv2.so", "metadata.json", "nacl_helper", "nacl_helper_bootstrap",
diff --git a/infra/archive_config/lacros64-archive-rel.json b/infra/archive_config/lacros64-archive-rel.json index 058ce79e..02865d32 100644 --- a/infra/archive_config/lacros64-archive-rel.json +++ b/infra/archive_config/lacros64-archive-rel.json
@@ -10,6 +10,8 @@ "headless_lib_strings.pak", "icudtl.dat", "icudtl.dat.hash", + "libEGL.so", + "libGLESv2.so", "metadata.json", "nacl_helper", "nacl_irt_x86_64.nexe",
diff --git a/infra/archive_config/mac-archive-rel.json b/infra/archive_config/mac-archive-rel.json index 2be5a22f..b33b6d18 100644 --- a/infra/archive_config/mac-archive-rel.json +++ b/infra/archive_config/mac-archive-rel.json
@@ -73,19 +73,11 @@ }, { "files": [ - "chrome/updater/.install" - ], - "dirs": [ - "ChromiumUpdater.app", - "ChromiumUpdater_test.app", - "Updater Packaging" - ], - "rename_dirs": [ - {"from_dir": ".", "to_dir": "updater"} + "updater.zip" ], "gcs_bucket": "chromium-browser-snapshots", - "gcs_path": "Mac/{%position%}/updater.zip", - "archive_type": "ARCHIVE_TYPE_ZIP" + "gcs_path": "Mac/{%position%}", + "archive_type": "ARCHIVE_TYPE_FILES" } ] }
diff --git a/infra/archive_config/mac-arm64-archive-rel.json b/infra/archive_config/mac-arm64-archive-rel.json index 7f2cd6c..c1baef5 100644 --- a/infra/archive_config/mac-arm64-archive-rel.json +++ b/infra/archive_config/mac-arm64-archive-rel.json
@@ -64,19 +64,11 @@ }, { "files": [ - "chrome/updater/.install" - ], - "dirs": [ - "ChromiumUpdater.app", - "ChromiumUpdater_test.app", - "Updater Packaging" - ], - "rename_dirs": [ - {"from_dir": ".", "to_dir": "updater"} + "updater.zip" ], "gcs_bucket": "chromium-browser-snapshots", - "gcs_path": "Mac_Arm/{%position%}/updater.zip", - "archive_type": "ARCHIVE_TYPE_ZIP" + "gcs_path": "Mac_Arm/{%position%}", + "archive_type": "ARCHIVE_TYPE_FILES" } ] }
diff --git a/ios/chrome/app/BUILD.gn b/ios/chrome/app/BUILD.gn index 052ebaa..58de1e1 100644 --- a/ios/chrome/app/BUILD.gn +++ b/ios/chrome/app/BUILD.gn
@@ -30,6 +30,7 @@ deps = [ "//base", "//ios/chrome/browser", + "//ios/chrome/browser/ui:feature_flags", "//net", "//url", ]
diff --git a/ios/chrome/app/app_startup_parameters.h b/ios/chrome/app/app_startup_parameters.h index 7b285ad..5a86a17 100644 --- a/ios/chrome/app/app_startup_parameters.h +++ b/ios/chrome/app/app_startup_parameters.h
@@ -11,7 +11,13 @@ #include <string> #include <vector> -enum class ApplicationModeForTabOpening { NORMAL, INCOGNITO, CURRENT }; +// Input format for the `TabOpening` protocol. +enum class ApplicationModeForTabOpening { + NORMAL, + INCOGNITO, + CURRENT, + UNDETERMINED +}; enum TabOpeningPostOpeningAction { // No action should be done @@ -50,9 +56,13 @@ externalURLParams; // Boolean to track if the app should launch in incognito mode. -@property(nonatomic, readwrite, assign) BOOL launchInIncognito; -// The mode in which the tab must be opened. -@property(nonatomic, readonly) ApplicationModeForTabOpening applicationMode; +// Explicitly setting this to YES or NO will either set `applicationMode` +// to INCOGNITO in the first case, or to NORMAL in the second case. +@property(nonatomic, assign) BOOL launchInIncognito; +// The mode in which the tab must be opened. Defaults to NORMAL, unless the flag +// `kIOS3PIntentsInIncognito` is enabled, in which case it is UNDETERMINED. +// TODO(crbug.com/1318750): Change this comment when flag is enabled by default. +@property(nonatomic, assign) ApplicationModeForTabOpening applicationMode; // Action to be taken after loading the URL. @property(nonatomic, readwrite, assign) TabOpeningPostOpeningAction postOpeningAction;
diff --git a/ios/chrome/app/app_startup_parameters.mm b/ios/chrome/app/app_startup_parameters.mm index 16a21a9..e33a265f 100644 --- a/ios/chrome/app/app_startup_parameters.mm +++ b/ios/chrome/app/app_startup_parameters.mm
@@ -4,7 +4,9 @@ #import "ios/chrome/app/app_startup_parameters.h" +#import "base/feature_list.h" #include "ios/chrome/browser/chrome_url_constants.h" +#import "ios/chrome/browser/ui/ui_feature_flags.h" #import "net/base/mac/url_conversions.h" #include "net/base/url_util.h" #include "url/gurl.h" @@ -21,7 +23,7 @@ @synthesize externalURLParams = _externalURLParams; @synthesize postOpeningAction = _postOpeningAction; -@synthesize launchInIncognito = _launchInIncognito; +@synthesize applicationMode = _applicationMode; // TODO(crbug.com/1021752): Remove this stub. @synthesize completePaymentRequest = _completePaymentRequest; @synthesize textQuery = _textQuery; @@ -40,6 +42,9 @@ if (self) { _externalURL = externalURL; _completeURL = completeURL; + if (base::FeatureList::IsEnabled(kIOS3PIntentsInIncognito)) { + _applicationMode = ApplicationModeForTabOpening::UNDETERMINED; + } } return self; } @@ -58,7 +63,6 @@ return self; } - - (NSString*)description { NSMutableString* description = [NSMutableString stringWithFormat:@"AppStartupParameters: %s", @@ -88,9 +92,16 @@ return description; } -- (ApplicationModeForTabOpening)applicationMode { - return self.launchInIncognito ? ApplicationModeForTabOpening::INCOGNITO - : ApplicationModeForTabOpening::NORMAL; +- (BOOL)launchInIncognito { + return _applicationMode == ApplicationModeForTabOpening::INCOGNITO; +} + +- (void)setLaunchInIncognito:(BOOL)launchInIncognito { + if (launchInIncognito) { + _applicationMode = ApplicationModeForTabOpening::INCOGNITO; + } else { + _applicationMode = ApplicationModeForTabOpening::NORMAL; + } } - (void)setPostOpeningAction:(TabOpeningPostOpeningAction)action {
diff --git a/ios/chrome/app/application_delegate/BUILD.gn b/ios/chrome/app/application_delegate/BUILD.gn index ee563701..f03b340 100644 --- a/ios/chrome/app/application_delegate/BUILD.gn +++ b/ios/chrome/app/application_delegate/BUILD.gn
@@ -65,6 +65,7 @@ "//ios/chrome/browser/signin:test_support", "//ios/chrome/browser/tabs", "//ios/chrome/browser/u2f", + "//ios/chrome/browser/ui:feature_flags", "//ios/chrome/browser/ui/commands", "//ios/chrome/browser/ui/main", "//ios/chrome/browser/ui/main:scene", @@ -226,6 +227,7 @@ "//ios/chrome/browser/signin", "//ios/chrome/browser/tabs", "//ios/chrome/browser/u2f", + "//ios/chrome/browser/ui:feature_flags", "//ios/chrome/browser/ui/authentication", "//ios/chrome/browser/ui/commands", "//ios/chrome/browser/ui/content_suggestions:feature_flags",
diff --git a/ios/chrome/app/application_delegate/mock_tab_opener.h b/ios/chrome/app/application_delegate/mock_tab_opener.h index 3d29926..581649d 100644 --- a/ios/chrome/app/application_delegate/mock_tab_opener.h +++ b/ios/chrome/app/application_delegate/mock_tab_opener.h
@@ -12,12 +12,14 @@ struct UrlLoadParams; // Mocks a class adopting the TabOpening protocol. It saves the arguments of -// -dismissModalsAndOpenSelectedTabInMode:withUrlLoadParams:dismissOmnibox: +// -dismissModalsAndMaybeOpenSelectedTabInMode:withUrlLoadParams:dismissOmnibox: // completion:. Can also save the arguments of // -dismissModalsAndOpenMultipleTabsInMode:URLs:dismissOmnibox:completion:. +// This mock assumes the Incognito interstitial setting is disabled, so it +// falls back to `NORMAL` mode if `targetMode` is `UNDETERMINED`. @interface MockTabOpener : NSObject<TabOpening> // Arguments for -// -dismissModalsAndOpenSelectedTabInMode:withUrlLoadParams:dismissOmnibox: +// -dismissModalsAndMaybeOpenSelectedTabInMode:withUrlLoadParams:dismissOmnibox: // completion:. @property(nonatomic, readonly) UrlLoadParams urlLoadParams; @property(nonatomic, readonly) ApplicationModeForTabOpening applicationMode;
diff --git a/ios/chrome/app/application_delegate/mock_tab_opener.mm b/ios/chrome/app/application_delegate/mock_tab_opener.mm index 6f0fab2c..b684a71 100644 --- a/ios/chrome/app/application_delegate/mock_tab_opener.mm +++ b/ios/chrome/app/application_delegate/mock_tab_opener.mm
@@ -19,23 +19,27 @@ std::vector<GURL> _URLs; } -- (void)dismissModalsAndOpenSelectedTabInMode: +- (void)dismissModalsAndMaybeOpenSelectedTabInMode: (ApplicationModeForTabOpening)targetMode - withUrlLoadParams: - (const UrlLoadParams&)urlLoadParams - dismissOmnibox:(BOOL)dismissOmnibox - completion:(ProceduralBlock)completion { + withUrlLoadParams: + (const UrlLoadParams&)urlLoadParams + dismissOmnibox:(BOOL)dismissOmnibox + completion:(ProceduralBlock)completion { + if (targetMode == ApplicationModeForTabOpening::UNDETERMINED) { + // Falling back to `NORMAL`. + targetMode = ApplicationModeForTabOpening::NORMAL; + } + _urlLoadParams = urlLoadParams; _applicationMode = targetMode; _completionBlock = [completion copy]; _URLs.push_back(urlLoadParams.web_params.url); } -- (void)dismissModalsAndOpenMultipleTabsInMode: - (ApplicationModeForTabOpening)targetMode - URLs:(const std::vector<GURL>&)URLs - dismissOmnibox:(BOOL)dismissOmnibox - completion:(ProceduralBlock)completion { +- (void)dismissModalsAndOpenMultipleTabsWithURLs:(const std::vector<GURL>&)URLs + inIncognitoMode:(BOOL)incognitoMode + dismissOmnibox:(BOOL)dismissOmnibox + completion:(ProceduralBlock)completion { _URLs = URLs; }
diff --git a/ios/chrome/app/application_delegate/tab_opening.h b/ios/chrome/app/application_delegate/tab_opening.h index f4a2613..4a3b8c7 100644 --- a/ios/chrome/app/application_delegate/tab_opening.h +++ b/ios/chrome/app/application_delegate/tab_opening.h
@@ -20,25 +20,32 @@ // Protocol for object that can open new tabs during application launch. @protocol TabOpening<NSObject> -// Dismisses any modal view, excluding the omnibox if `dismissOmnibox` is NO, -// then opens either a normal or incognito tab with `url`. After opening `url`, -// run completion `handler` if it is not nil. After Tab is opened the virtual -// URL is set to the pending navigation item. -- (void)dismissModalsAndOpenSelectedTabInMode: +// 1. Dismisses any modal view, excluding the omnibox if `dismissOmnibox` is NO, +// 2. (only if `targetMode` is UNDETERMINED) Resolves the value of `targetMode`, +// potentially by presenting the Incognito interstitial to the user and +// letting them choose, alternatively by falling back to normal mode if the +// user did not enable the "Ask to Open Links from Other Apps in Incognito" +// setting. +// 3. Opens either a normal or incognito tab with `urlLoadParams`, +// unless it was manually cancelled by the user at step 2. +// +// If `completion` is not nil, it is either called once Incognito interstitial +// has been presented, or once a new tab has been opened. +// After Tab is opened the virtual URL is set to the pending navigation item. +- (void)dismissModalsAndMaybeOpenSelectedTabInMode: (ApplicationModeForTabOpening)targetMode - withUrlLoadParams: - (const UrlLoadParams&)urlLoadParams - dismissOmnibox:(BOOL)dismissOmnibox - completion:(ProceduralBlock)completion; + withUrlLoadParams: + (const UrlLoadParams&)urlLoadParams + dismissOmnibox:(BOOL)dismissOmnibox + completion:(ProceduralBlock)completion; // Dismisses any modal view, excluding the omnibox if `dismissOmnibox` is NO, // then opens the list of URLs in `URLs` in either normal or incognito. // After opening the array of URLs, run completion `handler` if it not nil. -- (void)dismissModalsAndOpenMultipleTabsInMode: - (ApplicationModeForTabOpening)targetMode - URLs:(const std::vector<GURL>&)URLs - dismissOmnibox:(BOOL)dismissOmnibox - completion:(ProceduralBlock)completion; +- (void)dismissModalsAndOpenMultipleTabsWithURLs:(const std::vector<GURL>&)URLs + inIncognitoMode:(BOOL)incognitoMode + dismissOmnibox:(BOOL)dismissOmnibox + completion:(ProceduralBlock)completion; // Creates a new tab if the launch options are not null. - (void)openTabFromLaunchWithParams:(URLOpenerParams*)params @@ -51,7 +58,7 @@ // Returns a block that can be executed on the new tab to trigger one of the // commands. This block can be passed to -// `dismissModalsAndOpenSelectedTabInMode:withURL:transition:completion:`. +// `dismissModalsAndMaybeOpenSelectedTabInMode:withURL:transition:completion:`. // This block must only be executed if new tab opened on NTP. - (ProceduralBlock)completionBlockForTriggeringAction: (TabOpeningPostOpeningAction)action;
diff --git a/ios/chrome/app/application_delegate/url_opener.mm b/ios/chrome/app/application_delegate/url_opener.mm index 5a90dc2..50701a0 100644 --- a/ios/chrome/app/application_delegate/url_opener.mm +++ b/ios/chrome/app/application_delegate/url_opener.mm
@@ -112,11 +112,13 @@ } [tabOpener - dismissModalsAndOpenSelectedTabInMode:targetMode - withUrlLoadParams:urlLoadParams - dismissOmnibox:[params postOpeningAction] != - FOCUS_OMNIBOX - completion:tabOpenedCompletion]; + dismissModalsAndMaybeOpenSelectedTabInMode:targetMode + withUrlLoadParams:urlLoadParams + dismissOmnibox:[params + postOpeningAction] != + FOCUS_OMNIBOX + completion:tabOpenedCompletion]; + return YES; } return NO;
diff --git a/ios/chrome/app/application_delegate/url_opener_unittest.mm b/ios/chrome/app/application_delegate/url_opener_unittest.mm index 80f8fc7d..c6a6d16 100644 --- a/ios/chrome/app/application_delegate/url_opener_unittest.mm +++ b/ios/chrome/app/application_delegate/url_opener_unittest.mm
@@ -7,6 +7,7 @@ #import <Foundation/Foundation.h> #include "base/check_op.h" +#import "base/test/with_feature_override.h" #include "ios/chrome/app/application_delegate/app_state.h" #import "ios/chrome/app/application_delegate/app_state_observer.h" #include "ios/chrome/app/application_delegate/mock_tab_opener.h" @@ -17,6 +18,7 @@ #import "ios/chrome/browser/ui/main/test/fake_connection_information.h" #import "ios/chrome/browser/ui/main/test/stub_browser_interface.h" #import "ios/chrome/browser/ui/main/test/stub_browser_interface_provider.h" +#import "ios/chrome/browser/ui/ui_feature_flags.h" #import "ios/chrome/browser/url_loading/url_loading_params.h" #import "ios/chrome/browser/web_state_list/web_state_list.h" #import "ios/testing/open_url_context.h" @@ -78,12 +80,16 @@ #pragma mark - -class URLOpenerTest : public PlatformTest { +class URLOpenerTest : public base::test::WithFeatureOverride, + public PlatformTest { + protected: + URLOpenerTest() : WithFeatureOverride(kIOS3PIntentsInIncognito) {} + private: web::WebTaskEnvironment task_environment_; }; -TEST_F(URLOpenerTest, HandleOpenURL) { +TEST_P(URLOpenerTest, HandleOpenURL) { // A set of tests for robustness of // application:openURL:options:tabOpener:startupInformation: // It verifies that the function handles correctly different URLs parsed by @@ -217,7 +223,7 @@ } // Tests that -handleApplication set startup parameters as expected. -TEST_F(URLOpenerTest, VerifyLaunchOptions) { +TEST_P(URLOpenerTest, VerifyLaunchOptions) { // Setup. NSURL* url = [NSURL URLWithString:@"chromium://www.google.com"]; NSDictionary* launchOptions = @{ @@ -262,7 +268,7 @@ // Tests that -handleApplication set startup parameters as expected with options // as nil. -TEST_F(URLOpenerTest, VerifyLaunchOptionsNil) { +TEST_P(URLOpenerTest, VerifyLaunchOptionsNil) { // Creates a mock with no stub. This test will pass only if we don't use these // objects. id startupInformationMock = @@ -282,7 +288,7 @@ // Tests that -handleApplication set startup parameters as expected with no // source application. -TEST_F(URLOpenerTest, VerifyLaunchOptionsWithNoSourceApplication) { +TEST_P(URLOpenerTest, VerifyLaunchOptionsWithNoSourceApplication) { // Setup. NSURL* url = [NSURL URLWithString:@"chromium://www.google.com"]; NSDictionary* launchOptions = @{ @@ -325,7 +331,7 @@ } // Tests that -handleApplication set startup parameters as expected with no url. -TEST_F(URLOpenerTest, VerifyLaunchOptionsWithNoURL) { +TEST_P(URLOpenerTest, VerifyLaunchOptionsWithNoURL) { // Setup. NSDictionary* launchOptions = @{ UIApplicationLaunchOptionsSourceApplicationKey : @"com.apple.mobilesafari" @@ -352,7 +358,7 @@ // Tests that -handleApplication set startup parameters as expected with a bad // url. -TEST_F(URLOpenerTest, VerifyLaunchOptionsWithBadURL) { +TEST_P(URLOpenerTest, VerifyLaunchOptionsWithBadURL) { // Setup. NSURL* url = [NSURL URLWithString:@"chromium.www.google.com"]; NSDictionary* launchOptions = @{ @@ -389,7 +395,7 @@ } // Tests URL is not opened if the FRE is presented. -TEST_F(URLOpenerTest, PresentingFirstRunUI) { +TEST_P(URLOpenerTest, PresentingFirstRunUI) { // Setup. NSURL* url = [NSURL URLWithString:@"chromium://www.google.com"]; NSDictionary* launchOptions = @{ @@ -430,3 +436,5 @@ EXPECT_OCMOCK_VERIFY(startupInformationMock); EXPECT_OCMOCK_VERIFY(appStateMock); } + +INSTANTIATE_FEATURE_OVERRIDE_TEST_SUITE(URLOpenerTest);
diff --git a/ios/chrome/app/application_delegate/user_activity_handler.mm b/ios/chrome/app/application_delegate/user_activity_handler.mm index 91c3bcf0..45b3962 100644 --- a/ios/chrome/app/application_delegate/user_activity_handler.mm +++ b/ios/chrome/app/application_delegate/user_activity_handler.mm
@@ -323,13 +323,13 @@ [tabOpener URLIsOpenedInRegularMode:webpageGURL]) { // Record metric. } - [tabOpener dismissModalsAndOpenSelectedTabInMode:targetMode - withUrlLoadParams:params - dismissOmnibox:YES - completion:^{ - [connectionInformation - setStartupParameters:nil]; - }]; + [tabOpener dismissModalsAndMaybeOpenSelectedTabInMode:targetMode + withUrlLoadParams:params + dismissOmnibox:YES + completion:^{ + [connectionInformation + setStartupParameters:nil]; + }]; return YES; } @@ -349,11 +349,8 @@ + (void)openMultipleTabsWithConnectionInformation: (id<ConnectionInformation>)connectionInformation tabOpener:(id<TabOpening>)tabOpener { - ApplicationModeForTabOpening mode = - connectionInformation.startupParameters.launchInIncognito - ? ApplicationModeForTabOpening::INCOGNITO - : ApplicationModeForTabOpening::NORMAL; - + BOOL incognitoMode = + connectionInformation.startupParameters.launchInIncognito; BOOL dismissOmnibox = [[connectionInformation startupParameters] postOpeningAction] != FOCUS_OMNIBOX; @@ -367,13 +364,14 @@ __weak id<ConnectionInformation> weakConnectionInfo = connectionInformation; [tabOpener - dismissModalsAndOpenMultipleTabsInMode:mode - URLs:weakConnectionInfo - .startupParameters.URLs - dismissOmnibox:dismissOmnibox - completion:^{ - weakConnectionInfo.startupParameters = nil; - }]; + dismissModalsAndOpenMultipleTabsWithURLs:weakConnectionInfo + .startupParameters.URLs + inIncognitoMode:incognitoMode + dismissOmnibox:dismissOmnibox + completion:^{ + weakConnectionInfo.startupParameters = + nil; + }]; } + (BOOL)continueUserActivityURLs:(const std::vector<GURL>&)webpageURLs @@ -515,7 +513,8 @@ // The app is already active so the applicationDidBecomeActive: method // will never be called. Open the requested URL after all modal UIs have // been dismissed. `_startupParameters` must be retained until all deferred - // modal UIs are dismissed and tab opened with requested URL. + // modal UIs are dismissed and tab opened (or Incognito interstitial shown) + // with requested URL. ApplicationModeForTabOpening targetMode = [[connectionInformation startupParameters] applicationMode]; GURL URL; @@ -556,16 +555,17 @@ // Record metric. } - [tabOpener dismissModalsAndOpenSelectedTabInMode:targetMode - withUrlLoadParams:params - dismissOmnibox:[[connectionInformation - startupParameters] - postOpeningAction] != - FOCUS_OMNIBOX - completion:^{ - [connectionInformation - setStartupParameters:nil]; - }]; + [tabOpener + dismissModalsAndMaybeOpenSelectedTabInMode:targetMode + withUrlLoadParams:params + dismissOmnibox:[[connectionInformation + startupParameters] + postOpeningAction] != + FOCUS_OMNIBOX + completion:^{ + [connectionInformation + setStartupParameters:nil]; + }]; } }
diff --git a/ios/chrome/app/application_delegate/user_activity_handler_unittest.mm b/ios/chrome/app/application_delegate/user_activity_handler_unittest.mm index e3102d31..95c5788 100644 --- a/ios/chrome/app/application_delegate/user_activity_handler_unittest.mm +++ b/ios/chrome/app/application_delegate/user_activity_handler_unittest.mm
@@ -13,6 +13,7 @@ #include "base/strings/sys_string_conversions.h" #include "base/test/scoped_command_line.h" #import "base/test/task_environment.h" +#import "base/test/with_feature_override.h" #include "components/handoff/handoff_utility.h" #import "ios/chrome/app/app_startup_parameters.h" #import "ios/chrome/app/application_delegate/app_state_observer.h" @@ -34,6 +35,7 @@ #import "ios/chrome/browser/ui/main/connection_information.h" #import "ios/chrome/browser/ui/main/test/fake_connection_information.h" #import "ios/chrome/browser/ui/main/test/stub_browser_interface_provider.h" +#import "ios/chrome/browser/ui/ui_feature_flags.h" #import "ios/chrome/browser/url_loading/url_loading_params.h" #import "ios/chrome/browser/web_state_list/web_state_list.h" #import "ios/chrome/browser/web_state_list/web_state_opener.h" @@ -90,9 +92,10 @@ // A block that takes a BOOL argument and returns nothing. typedef void (^conditionBlock)(BOOL); -class UserActivityHandlerTest : public PlatformTest { +class UserActivityHandlerTest : public base::test::WithFeatureOverride, + public PlatformTest { public: - UserActivityHandlerTest() { + UserActivityHandlerTest() : WithFeatureOverride(kIOS3PIntentsInIncognito) { interfaceProvider_ = [[StubBrowserInterfaceProvider alloc] init]; } @@ -160,7 +163,7 @@ // Tests that Chrome notifies the user if we are passing a correct // userActivityType. -TEST_F(UserActivityHandlerTest, WillContinueUserActivityCorrectActivity) { +TEST_P(UserActivityHandlerTest, WillContinueUserActivityCorrectActivity) { EXPECT_TRUE([UserActivityHandler willContinueUserActivityWithType:handoff::kChromeHandoffActivityType]); @@ -172,7 +175,7 @@ // Tests that Chrome does not notifies the user if we are passing an incorrect // userActivityType. -TEST_F(UserActivityHandlerTest, WillContinueUserActivityIncorrectActivity) { +TEST_P(UserActivityHandlerTest, WillContinueUserActivityIncorrectActivity) { EXPECT_FALSE([UserActivityHandler willContinueUserActivityWithType:[handoff::kChromeHandoffActivityType stringByAppendingString:@"test"]]); @@ -187,7 +190,7 @@ // Tests that Chrome does not continue the activity is the activity type is // random. -TEST_F(UserActivityHandlerTest, ContinueUserActivityFromGarbage) { +TEST_P(UserActivityHandlerTest, ContinueUserActivityFromGarbage) { // Setup. NSString* handoffWithSuffix = [handoff::kChromeHandoffActivityType stringByAppendingString:@"test"]; @@ -226,7 +229,7 @@ // Tests that Chrome does not continue the activity if the webpage url is not // set. -TEST_F(UserActivityHandlerTest, ContinueUserActivityNoWebpage) { +TEST_P(UserActivityHandlerTest, ContinueUserActivityNoWebpage) { // Setup. NSUserActivity* userActivity = [[NSUserActivity alloc] initWithActivityType:handoff::kChromeHandoffActivityType]; @@ -254,7 +257,7 @@ // Tests that Chrome does not continue the activity if the activity is a // Spotlight action of an unknown type. -TEST_F(UserActivityHandlerTest, +TEST_P(UserActivityHandlerTest, ContinueUserActivitySpotlightActionFromGarbage) { // Only test Spotlight if it is enabled and available on the device. if (!spotlight::IsSpotlightAvailable()) { @@ -297,7 +300,7 @@ // Tests that Chrome continues the activity if the application is in background // by saving the url to startupParameters. -TEST_F(UserActivityHandlerTest, ContinueUserActivityBackground) { +TEST_P(UserActivityHandlerTest, ContinueUserActivityBackground) { // Setup. NSUserActivity* userActivity = [[NSUserActivity alloc] initWithActivityType:handoff::kChromeHandoffActivityType]; @@ -337,7 +340,7 @@ // Tests that Chrome continues the activity if the application is in foreground // by opening a new tab. -TEST_F(UserActivityHandlerTest, ContinueUserActivityForeground) { +TEST_P(UserActivityHandlerTest, ContinueUserActivityForeground) { // Setup. NSUserActivity* userActivity = [[NSUserActivity alloc] initWithActivityType:handoff::kChromeHandoffActivityType]; @@ -373,7 +376,7 @@ } // Tests that a new tab is created when application is started via handoff. -TEST_F(UserActivityHandlerTest, ContinueUserActivityBrowsingWeb) { +TEST_P(UserActivityHandlerTest, ContinueUserActivityBrowsingWeb) { NSUserActivity* userActivity = [[NSUserActivity alloc] initWithActivityType:NSUserActivityTypeBrowsingWeb]; // This URL is passed to application by iOS but is not used in this part @@ -408,7 +411,7 @@ // Tests that continueUserActivity sets startupParameters accordingly to the // Spotlight action used. -TEST_F(UserActivityHandlerTest, ContinueUserActivityShortcutActions) { +TEST_P(UserActivityHandlerTest, ContinueUserActivityShortcutActions) { // Only test Spotlight if it is enabled and available on the device. if (!spotlight::IsSpotlightAvailable()) { return; @@ -476,7 +479,7 @@ } // Tests that Chrome responds to open in incognito intent in the background -TEST_F(UserActivityHandlerTest, ContinueUserActivityIntentIncognitoBackground) { +TEST_P(UserActivityHandlerTest, ContinueUserActivityIntentIncognitoBackground) { NSURL* url1 = [[NSURL alloc] initWithString:@"http://www.google.com"]; NSURL* url2 = [[NSURL alloc] initWithString:@"http://www.apple.com"]; NSURL* url3 = [[NSURL alloc] initWithString:@"http://www.espn.com"]; @@ -534,7 +537,7 @@ } // Tests that Chrome responds to open intents in the background. -TEST_F(UserActivityHandlerTest, ContinueUserActivityIntentBackground) { +TEST_P(UserActivityHandlerTest, ContinueUserActivityIntentBackground) { NSUserActivity* userActivity = [[NSUserActivity alloc] initWithActivityType:@"OpenInChromeIntent"]; OpenInChromeIntent* intent = [[OpenInChromeIntent alloc] init]; @@ -589,7 +592,7 @@ } // Test that Chrome respond to open in incognito intent in the foreground. -TEST_F(UserActivityHandlerTest, ContinueUserActivityIntentIncognitoForeground) { +TEST_P(UserActivityHandlerTest, ContinueUserActivityIntentIncognitoForeground) { NSURL* url1 = [[NSURL alloc] initWithString:@"http://www.google.com"]; NSURL* url2 = [[NSURL alloc] initWithString:@"http://www.apple.com"]; NSURL* url3 = [[NSURL alloc] initWithString:@"http://www.espn.com"]; @@ -660,7 +663,7 @@ } // Tests that Chrome responds to open intents in the foreground. -TEST_F(UserActivityHandlerTest, ContinueUserActivityIntentForeground) { +TEST_P(UserActivityHandlerTest, ContinueUserActivityIntentForeground) { NSUserActivity* userActivity = [[NSUserActivity alloc] initWithActivityType:@"OpenInChromeIntent"]; OpenInChromeIntent* intent = [[OpenInChromeIntent alloc] init]; @@ -726,7 +729,7 @@ // Tests that handleStartupParameters with a file url. "external URL" gets // rewritten to chrome://URL, while "complete URL" remains full local file URL. -TEST_F(UserActivityHandlerTest, HandleStartupParamsWithExternalFile) { +TEST_P(UserActivityHandlerTest, HandleStartupParamsWithExternalFile) { // Setup. GURL externalURL("chrome://test.pdf"); GURL completeURL("file://test.pdf"); @@ -776,7 +779,7 @@ } // Tests that handleStartupParameters with a non-U2F url opens a new tab. -TEST_F(UserActivityHandlerTest, HandleStartupParamsNonU2F) { +TEST_P(UserActivityHandlerTest, HandleStartupParamsNonU2F) { // Setup. GURL gurl("http://www.google.com"); @@ -821,7 +824,7 @@ } // Tests that handleStartupParameters with a U2F url opens in the correct tab. -TEST_F(UserActivityHandlerTest, HandleStartupParamsU2F) { +TEST_P(UserActivityHandlerTest, HandleStartupParamsU2F) { // Setup. base::test::TaskEnvironment task_enviroment_; @@ -895,7 +898,7 @@ #define MAYBE_PerformActionForShortcutItemWithRealShortcut \ DISABLED_PerformActionForShortcutItemWithRealShortcut #endif -TEST_F(UserActivityHandlerTest, +TEST_P(UserActivityHandlerTest, MAYBE_PerformActionForShortcutItemWithRealShortcut) { // Setup. GURL gurlNewTab("chrome://newtab/"); @@ -949,7 +952,7 @@ // Tests that performActionForShortcutItem just executes the completionHandler // with NO if the firstRunUI is present. -TEST_F(UserActivityHandlerTest, PerformActionForShortcutItemWithFirstRunUI) { +TEST_P(UserActivityHandlerTest, PerformActionForShortcutItemWithFirstRunUI) { // Setup. id startupInformationMock = [OCMockObject mockForProtocol:@protocol(StartupInformation)]; @@ -982,3 +985,5 @@ EXPECT_FALSE(completionHandlerArgument()); EXPECT_FALSE(getHandleStartupParametersHasBeenCalled()); } + +INSTANTIATE_FEATURE_OVERRIDE_TEST_SUITE(UserActivityHandlerTest);
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm index 5b978ac..8a1292a 100644 --- a/ios/chrome/browser/flags/about_flags.mm +++ b/ios/chrome/browser/flags/about_flags.mm
@@ -996,6 +996,9 @@ flag_descriptions::kEnableExpKitCalendarTextClassifierName, flag_descriptions::kEnableExpKitCalendarTextClassifierDescription, flags_ui::kOsIos, FEATURE_VALUE_TYPE(kEnableExpKitCalendarTextClassifier)}, + {"experience-kit-maps", flag_descriptions::kMapsExperienceKitName, + flag_descriptions::kMapsExperienceKitDescription, flags_ui::kOsIos, + FEATURE_VALUE_TYPE(kMapsExperienceKit)}, {"https-only-mode", flag_descriptions::kHttpsOnlyModeName, flag_descriptions::kHttpsOnlyModeDescription, flags_ui::kOsIos, FEATURE_VALUE_TYPE(security_interstitials::features::kHttpsOnlyMode)},
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc index 5edc494..48ec406 100644 --- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc +++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
@@ -164,6 +164,11 @@ "When enabled, Experience Kit Calendar will use Text Classifier library in " "entity detection where possible."; +extern const char kMapsExperienceKitName[] = "Experience Kit Maps"; +extern const char kMapsExperienceKitDescription[] = + "When enabled, long pressing on an address will trigger Experience Kit Maps" + "location and directions handling"; + const char kContentSuggestionsUIModuleRefreshName[] = "Content Suggestions UI Module Refresh"; const char kContentSuggestionsUIModuleRefreshDescription[] =
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h index 3cb9769..dcbf790 100644 --- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h +++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
@@ -139,6 +139,11 @@ extern const char kEnableExpKitCalendarTextClassifierName[]; extern const char kEnableExpKitCalendarTextClassifierDescription[]; +// Title and description for the flag to enable experience kit maps location and +// directions. +extern const char kMapsExperienceKitName[]; +extern const char kMapsExperienceKitDescription[]; + // Title and description for the flag that updates the Content Suggestions to a // new module design. extern const char kContentSuggestionsUIModuleRefreshName[];
diff --git a/ios/chrome/browser/pref_names.cc b/ios/chrome/browser/pref_names.cc index e92426e7..2fea353 100644 --- a/ios/chrome/browser/pref_names.cc +++ b/ios/chrome/browser/pref_names.cc
@@ -105,6 +105,12 @@ const char kIosSettingsSigninPromoDisplayedCount[] = "ios.settings.signin_promo_displayed_count"; +// The count of how many times the user has shared the app. +const char kIosShareChromeCount[] = "ios.share_chrome.count"; + +// Preference to store the last time the user shared the chrome app. +const char kIosShareChromeLastShare[] = "ios.share_chrome.last_share"; + // Preference that hold a boolean indicating if the user has already dismissed // the sign-in promo in the ntp feed top section. const char kIosNtpFeedTopPromoAlreadySeen[] =
diff --git a/ios/chrome/browser/pref_names.h b/ios/chrome/browser/pref_names.h index f47bb9ac..c35d80f1 100644 --- a/ios/chrome/browser/pref_names.h +++ b/ios/chrome/browser/pref_names.h
@@ -27,6 +27,8 @@ extern const char kIosBookmarkFolderDefault[]; extern const char kIosBookmarkPromoAlreadySeen[]; extern const char kIosBookmarkSigninPromoDisplayedCount[]; +extern const char kIosShareChromeCount[]; +extern const char kIosShareChromeLastShare[]; extern const char kIosDiscoverFeedLastRefreshTime[]; extern const char kIosPromosManagerActivePromos[]; extern const char kIosPromosManagerImpressionHistory[];
diff --git a/ios/chrome/browser/prefs/browser_prefs.mm b/ios/chrome/browser/prefs/browser_prefs.mm index bda92ee..ecb7cb4f 100644 --- a/ios/chrome/browser/prefs/browser_prefs.mm +++ b/ios/chrome/browser/prefs/browser_prefs.mm
@@ -367,6 +367,11 @@ policy::policy_prefs::kUserPolicyNotificationWasShown, false); registry->RegisterIntegerPref(kAccountIdMigrationState, 0); + + registry->RegisterIntegerPref(prefs::kIosShareChromeCount, 0, + PrefRegistry::LOSSY_PREF); + registry->RegisterTimePref(prefs::kIosShareChromeLastShare, base::Time(), + PrefRegistry::LOSSY_PREF); } // This method should be periodically pruned of year+ old migrations.
diff --git a/ios/chrome/browser/ui/activity_services/activity_service_mediator.mm b/ios/chrome/browser/ui/activity_services/activity_service_mediator.mm index 711e7a2b..0969ad6 100644 --- a/ios/chrome/browser/ui/activity_services/activity_service_mediator.mm +++ b/ios/chrome/browser/ui/activity_services/activity_service_mediator.mm
@@ -203,6 +203,14 @@ RecordScenarioInitiated(scenario); } +- (void)recordShareChromeFinishedInPrefs { + PrefService* prefs = self.prefService; + DCHECK(prefs); + int count = prefs->GetInteger(prefs::kIosShareChromeCount); + prefs->SetInteger(prefs::kIosShareChromeCount, count + 1); + prefs->SetTime(prefs::kIosShareChromeLastShare, base::Time::Now()); +} + - (void)shareFinishedWithScenario:(ActivityScenario)scenario activityType:(NSString*)activityType completed:(BOOL)completed { @@ -212,6 +220,9 @@ activity_type_util::RecordMetricForActivity(type); RecordActivityForScenario(type, scenario); [self.promoScheduler logUserFinishedActivityFlow]; + if (ActivityScenario::ShareChrome == scenario) { + [self recordShareChromeFinishedInPrefs]; + } } else { // Share action was cancelled. base::RecordAction(base::UserMetricsAction("MobileShareMenuCancel"));
diff --git a/ios/chrome/browser/ui/activity_services/activity_service_mediator_unittest.mm b/ios/chrome/browser/ui/activity_services/activity_service_mediator_unittest.mm index f7ac63e..a90de69 100644 --- a/ios/chrome/browser/ui/activity_services/activity_service_mediator_unittest.mm +++ b/ios/chrome/browser/ui/activity_services/activity_service_mediator_unittest.mm
@@ -69,6 +69,10 @@ pref_service_->registry()->RegisterBooleanPref(prefs::kPrintingEnabled, true); + pref_service_->registry()->RegisterIntegerPref(prefs::kIosShareChromeCount, + 0); + pref_service_->registry()->RegisterTimePref(prefs::kIosShareChromeLastShare, + base::Time()); } void VerifyTypes(NSArray* activities, NSArray* expected_types) { @@ -378,6 +382,23 @@ histograms_tester_.ExpectBucketCount(histogramName, copyAction, 1); } +// Tests that successful action completion in ShareChrome scenario stores prefs +TEST_F(ActivityServiceMediatorTest, ShareFinished_SuccessShareChrome) { + int initialCount = pref_service_->GetInteger(prefs::kIosShareChromeCount); + base::Time startTime = base::Time::Now(); + // Since mocked_handler_ is a strict mock, any call to its methods would make + // the test fail. + NSString* copyActivityString = @"com.google.chrome.copyActivity"; + [mediator_ shareFinishedWithScenario:ActivityScenario::ShareChrome + activityType:copyActivityString + completed:YES]; + int count = pref_service_->GetInteger(prefs::kIosShareChromeCount); + base::Time lastShare = + pref_service_->GetTime(prefs::kIosShareChromeLastShare); + EXPECT_EQ(count, initialCount + 1); + EXPECT_GT(lastShare, startTime); +} + TEST_F(ActivityServiceMediatorTest, ShareFinished_Cancel) { // Since mocked_handler_ is a strict mock, any call to its methods would make // the test fail. That is our success condition.
diff --git a/ios/chrome/browser/ui/browser_view/BUILD.gn b/ios/chrome/browser/ui/browser_view/BUILD.gn index 84a17ad7..71c1ed0 100644 --- a/ios/chrome/browser/ui/browser_view/BUILD.gn +++ b/ios/chrome/browser/ui/browser_view/BUILD.gn
@@ -323,7 +323,10 @@ "//base/test:test_support", "//components/strings", "//ios/chrome/app/strings", + "//ios/chrome/browser:pref_names", "//ios/chrome/browser/ntp:features", + "//ios/chrome/browser/ui:feature_flags", + "//ios/chrome/browser/ui/content_suggestions:feature_flags", "//ios/chrome/browser/ui/popup_menu:constants", "//ios/chrome/browser/ui/start_surface:feature_flags", "//ios/chrome/test:eg_test_support+eg2",
diff --git a/ios/chrome/browser/ui/browser_view/browser_view_controller_egtest.mm b/ios/chrome/browser/ui/browser_view/browser_view_controller_egtest.mm index 0b19734..126dfe1 100644 --- a/ios/chrome/browser/ui/browser_view/browser_view_controller_egtest.mm +++ b/ios/chrome/browser/ui/browser_view/browser_view_controller_egtest.mm
@@ -9,7 +9,10 @@ #import "base/ios/ios_util.h" #include "base/strings/sys_string_conversions.h" #include "components/strings/grit/components_strings.h" +#import "ios/chrome/browser/pref_names.h" +#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.h" #import "ios/chrome/browser/ui/start_surface/start_surface_features.h" +#import "ios/chrome/browser/ui/ui_feature_flags.h" #include "ios/chrome/grit/ios_strings.h" #import "ios/chrome/test/earl_grey/chrome_earl_grey.h" #import "ios/chrome/test/earl_grey/chrome_earl_grey_ui.h" @@ -245,3 +248,21 @@ } @end + +@interface BrowserViewControllerWith3PIntentsInIncognitoFeatureTestCase + : BrowserViewControllerTestCase +@end + +@implementation BrowserViewControllerWith3PIntentsInIncognitoFeatureTestCase + +- (AppLaunchConfiguration)appConfigurationForTestCase { + AppLaunchConfiguration config = [super appConfigurationForTestCase]; + config.features_disabled.push_back(kTrendingQueriesModule); + return config; +} + +// This is currently needed to prevent this test case from being ignored. +- (void)testEmpty { +} + +@end
diff --git a/ios/chrome/browser/ui/incognito_interstitial/BUILD.gn b/ios/chrome/browser/ui/incognito_interstitial/BUILD.gn index e53b357..25cb4aa 100644 --- a/ios/chrome/browser/ui/incognito_interstitial/BUILD.gn +++ b/ios/chrome/browser/ui/incognito_interstitial/BUILD.gn
@@ -2,6 +2,14 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +source_set("constants") { + configs += [ "//build/config/compiler:enable_arc" ] + sources = [ + "incognito_interstitial_constants.h", + "incognito_interstitial_constants.mm", + ] +} + source_set("incognito_interstitial_ui") { configs += [ "//build/config/compiler:enable_arc" ] sources = [ @@ -10,6 +18,7 @@ "incognito_interstitial_view_controller_delegate.h", ] deps = [ + ":constants", "resources:incognito_interstitial_screen_banner", "//ios/chrome/app/strings:ios_strings_grit", "//ios/chrome/browser/ui:feature_flags", @@ -44,3 +53,22 @@ ] frameworks = [ "UIKit.framework" ] } + +source_set("eg2_tests") { + configs += [ + "//build/config/compiler:enable_arc", + "//build/config/ios:xctest_config", + ] + testonly = true + sources = [ "incognito_interstitial_egtest.mm" ] + deps = [ + "//ios/chrome/browser:pref_names", + "//ios/chrome/browser/ui:feature_flags", + "//ios/chrome/test:eg_test_support+eg2", + "//ios/chrome/test/earl_grey:eg_test_support+eg2", + "//ios/testing/earl_grey:eg_test_support+eg2", + "//ios/third_party/earl_grey2:test_lib", + "//net:test_support", + ] + frameworks = [ "UIKit.framework" ] +}
diff --git a/ios/chrome/browser/ui/incognito_interstitial/incognito_interstitial_constants.h b/ios/chrome/browser/ui/incognito_interstitial/incognito_interstitial_constants.h new file mode 100644 index 0000000..e9085b7 --- /dev/null +++ b/ios/chrome/browser/ui/incognito_interstitial/incognito_interstitial_constants.h
@@ -0,0 +1,18 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_UI_INCOGNITO_INTERSTITIAL_INCOGNITO_INTERSTITIAL_CONSTANTS_H_ +#define IOS_CHROME_BROWSER_UI_INCOGNITO_INTERSTITIAL_INCOGNITO_INTERSTITIAL_CONSTANTS_H_ + +@class NSString; + +// The accessibility identifier for the Incognito interstitial. +extern NSString* const kIncognitoInterstitialAccessibilityIdentifier; + +// The accessibility identifier for the Cancel button in the Incognito +// interstitial. +extern NSString* const + kIncognitoInterstitialCancelButtonAccessibilityIdentifier; + +#endif // IOS_CHROME_BROWSER_UI_INCOGNITO_INTERSTITIAL_INCOGNITO_INTERSTITIAL_CONSTANTS_H_
diff --git a/ios/chrome/browser/ui/incognito_interstitial/incognito_interstitial_constants.mm b/ios/chrome/browser/ui/incognito_interstitial/incognito_interstitial_constants.mm new file mode 100644 index 0000000..4453057 --- /dev/null +++ b/ios/chrome/browser/ui/incognito_interstitial/incognito_interstitial_constants.mm
@@ -0,0 +1,17 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import <Foundation/Foundation.h> + +#import "ios/chrome/browser/ui/incognito_interstitial/incognito_interstitial_constants.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +NSString* const kIncognitoInterstitialAccessibilityIdentifier = + @"incognitoInterstitialAccessibilityIdentifier"; + +NSString* const kIncognitoInterstitialCancelButtonAccessibilityIdentifier = + @"incognitoInterstitialCancelButtonAccessibilityIdentifier";
diff --git a/ios/chrome/browser/ui/incognito_interstitial/incognito_interstitial_coordinator.h b/ios/chrome/browser/ui/incognito_interstitial/incognito_interstitial_coordinator.h index 7671305..8bf89c0d 100644 --- a/ios/chrome/browser/ui/incognito_interstitial/incognito_interstitial_coordinator.h +++ b/ios/chrome/browser/ui/incognito_interstitial/incognito_interstitial_coordinator.h
@@ -25,10 +25,6 @@ // URL load parameters associated with the external intent. @property(nonatomic, assign) UrlLoadParams urlLoadParams; -// Whether to ask the tab opener to also dismiss the omnibox before opening a -// new tab. -@property(nonatomic, assign) BOOL shouldDismissOmnibox; - - (instancetype)init NS_UNAVAILABLE; // Stops the coordinator and dismisses the Incognito interstitial with
diff --git a/ios/chrome/browser/ui/incognito_interstitial/incognito_interstitial_coordinator.mm b/ios/chrome/browser/ui/incognito_interstitial/incognito_interstitial_coordinator.mm index fcb504f9..310b247 100644 --- a/ios/chrome/browser/ui/incognito_interstitial/incognito_interstitial_coordinator.mm +++ b/ios/chrome/browser/ui/incognito_interstitial/incognito_interstitial_coordinator.mm
@@ -65,14 +65,14 @@ - (void)didTapPrimaryActionButton { // Dismiss modals (including interstitial) and open link in incognito tab. __weak __typeof(self) weakSelf = self; - UrlLoadParams params = self.urlLoadParams; - BOOL dismissOmnibox = self.shouldDismissOmnibox; + UrlLoadParams copyOfUrlLoadParams = self.urlLoadParams; void (^dismissModalsAndOpenTab)() = ^{ - [weakSelf.tabOpener dismissModalsAndOpenSelectedTabInMode: - ApplicationModeForTabOpening::INCOGNITO - withUrlLoadParams:params - dismissOmnibox:dismissOmnibox - completion:nil]; + [weakSelf.tabOpener + dismissModalsAndMaybeOpenSelectedTabInMode: + ApplicationModeForTabOpening::INCOGNITO + withUrlLoadParams:copyOfUrlLoadParams + dismissOmnibox:YES + completion:nil]; }; SceneState* sceneState = @@ -93,11 +93,11 @@ - (void)didTapSecondaryActionButton { // Dismiss modals (including interstitial) and open link in regular tab. - [self.tabOpener - dismissModalsAndOpenSelectedTabInMode:ApplicationModeForTabOpening::NORMAL - withUrlLoadParams:self.urlLoadParams - dismissOmnibox:self.shouldDismissOmnibox - completion:nil]; + [self.tabOpener dismissModalsAndMaybeOpenSelectedTabInMode: + ApplicationModeForTabOpening::NORMAL + withUrlLoadParams:self.urlLoadParams + dismissOmnibox:YES + completion:nil]; } - (void)didTapCancelButton { @@ -108,11 +108,12 @@ - (void)loadURLInTab:(const GURL&)URL { [self.tabOpener - dismissModalsAndOpenSelectedTabInMode:ApplicationModeForTabOpening:: - INCOGNITO - withUrlLoadParams:UrlLoadParams::InCurrentTab(URL) - dismissOmnibox:YES - completion:nil]; + dismissModalsAndMaybeOpenSelectedTabInMode:ApplicationModeForTabOpening:: + INCOGNITO + withUrlLoadParams:UrlLoadParams::InCurrentTab( + URL) + dismissOmnibox:YES + completion:nil]; } @end
diff --git a/ios/chrome/browser/ui/incognito_interstitial/incognito_interstitial_egtest.mm b/ios/chrome/browser/ui/incognito_interstitial/incognito_interstitial_egtest.mm new file mode 100644 index 0000000..bc1bf136 --- /dev/null +++ b/ios/chrome/browser/ui/incognito_interstitial/incognito_interstitial_egtest.mm
@@ -0,0 +1,230 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "base/strings/sys_string_conversions.h" +#import "ios/chrome/browser/pref_names.h" +#import "ios/chrome/browser/ui/ui_feature_flags.h" +#import "ios/chrome/test/earl_grey/chrome_earl_grey.h" +#import "ios/chrome/test/earl_grey/chrome_matchers.h" +#import "ios/chrome/test/earl_grey/web_http_server_chrome_test_case.h" +#import "ios/testing/earl_grey/earl_grey_test.h" +#import "net/test/embedded_test_server/embedded_test_server.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +using chrome_test_util::IncognitoInterstitialCancelButton; +using chrome_test_util::IncognitoInterstitialMatcher; +using chrome_test_util::IncognitoInterstitialOpenInChromeButton; +using chrome_test_util::IncognitoInterstitialOpenInChromeIncognitoButton; +using chrome_test_util::IncognitoInterstitialSubtitleForURL; +using chrome_test_util::NTPIncognitoView; + +@interface IncognitoInterstitialTestCase : ChromeTestCase +@end + +@implementation IncognitoInterstitialTestCase + +- (AppLaunchConfiguration)appConfigurationForTestCase { + AppLaunchConfiguration config = [super appConfigurationForTestCase]; + config.features_enabled.push_back(kIOS3PIntentsInIncognito); + return config; +} + +- (void)setUp { + [super setUp]; + [ChromeEarlGrey setBoolValue:YES + forUserPref:prefs::kIncognitoInterstitialEnabled]; + + GREYAssertTrue(self.testServer->Start(), @"Server did not start."); +} + +- (void)tearDown { + [ChromeEarlGrey setBoolValue:NO + forUserPref:prefs::kIncognitoInterstitialEnabled]; + [super tearDown]; +} + +// Test the "Open in Chrome Incognito" journey through the Incognito +// interstitial. +- (void)testOpenInIncognitoFromNTP { + [ChromeEarlGrey closeCurrentTab]; + [ChromeEarlGrey openNewIncognitoTab]; + + // Starting from Incognito NTP, loading a new URL. + GURL destinationURL = self.testServer->GetURL("/destination.html"); + [ChromeEarlGrey sceneOpenURL:destinationURL]; + // Wait for the interstitial to appear. + [ChromeEarlGrey + waitForUIElementToAppearWithMatcher:IncognitoInterstitialMatcher()]; + // Check the appropriate subtitle is sufficiently visible within the + // Interstitial. + [[EarlGrey selectElementWithMatcher:IncognitoInterstitialSubtitleForURL( + destinationURL.spec())] + assertWithMatcher:grey_sufficientlyVisible()]; + // Tap the "Open in Chrome Incognito" button. + [[EarlGrey selectElementWithMatcher: + IncognitoInterstitialOpenInChromeIncognitoButton()] + performAction:grey_tap()]; + // Wait for the interstitial to disappear. + [ChromeEarlGrey + waitForUIElementToDisappearWithMatcher:IncognitoInterstitialMatcher()]; + // Wait for the expected page content to be displayed. + [ChromeEarlGrey waitForWebStateContainingText:"You've arrived"]; + // Wait for the Incognito tab count to be one, as expected. + [ChromeEarlGrey waitForIncognitoTabCount:1]; +} + +// Test the "Open in Chrome" journey through the Incognito interstitial. +- (void)testOpenInChromeFromNTP { + // Starting from NTP, loading a new URL. + GURL destinationURL = self.testServer->GetURL("/destination.html"); + [ChromeEarlGrey sceneOpenURL:destinationURL]; + // Wait for the interstitial to appear. + [ChromeEarlGrey + waitForUIElementToAppearWithMatcher:IncognitoInterstitialMatcher()]; + // Check the appropriate subtitle is sufficiently visible within the + // Interstitial. + [[EarlGrey selectElementWithMatcher:IncognitoInterstitialSubtitleForURL( + destinationURL.spec())] + assertWithMatcher:grey_sufficientlyVisible()]; + // Tap the "Open in Chrome" button. + [[EarlGrey selectElementWithMatcher:IncognitoInterstitialOpenInChromeButton()] + performAction:grey_tap()]; + // Wait for the interstitial to disappear. + [ChromeEarlGrey + waitForUIElementToDisappearWithMatcher:IncognitoInterstitialMatcher()]; + // Wait for the expected page content to be displayed. + [ChromeEarlGrey waitForWebStateContainingText:"You've arrived"]; + // Wait for the main tab count to be one, as expected. + [ChromeEarlGrey waitForMainTabCount:1]; +} + +// Test the "Open in Chrome" journey starting from an already opened tab. +- (void)testOpenInChromeFromTab { + // Go from NTP to some other web page. + [ChromeEarlGrey loadURL:GURL("https://invalid")]; + + // Starting from this regular tab, loading a new URL. + GURL destinationURL = self.testServer->GetURL("/destination.html"); + [ChromeEarlGrey sceneOpenURL:destinationURL]; + // Wait for the interstitial to appear. + [ChromeEarlGrey + waitForUIElementToAppearWithMatcher:IncognitoInterstitialMatcher()]; + // Check the appropriate subtitle is sufficiently visible within the + // Interstitial. + [[EarlGrey selectElementWithMatcher:IncognitoInterstitialSubtitleForURL( + destinationURL.spec())] + assertWithMatcher:grey_sufficientlyVisible()]; + // Tap the "Open in Chrome" button. + [[EarlGrey selectElementWithMatcher:IncognitoInterstitialOpenInChromeButton()] + performAction:grey_tap()]; + // Wait for the interstitial to disappear. + [ChromeEarlGrey + waitForUIElementToDisappearWithMatcher:IncognitoInterstitialMatcher()]; + // Wait for the expected page content to be displayed. + [ChromeEarlGrey waitForWebStateContainingText:"You've arrived"]; + // Wait for the main tab count to be two, as expected. + [ChromeEarlGrey waitForMainTabCount:2]; +} + +// Test the "Open in Chrome Incognito" journey starting from the tab switcher. +- (void)testOpenInChromeIncognitoFromTabSwitcher { + // Close the NTP to go to the tab switcher. + [ChromeEarlGrey closeCurrentTab]; + [ChromeEarlGrey waitForMainTabCount:0]; + + // Starting from the tab switcher, loading a new URL. + GURL destinationURL = self.testServer->GetURL("/destination.html"); + [ChromeEarlGrey sceneOpenURL:destinationURL]; + // Wait for the interstitial to appear. + [ChromeEarlGrey + waitForUIElementToAppearWithMatcher:IncognitoInterstitialMatcher()]; + // Check the appropriate subtitle is sufficiently visible within the + // Interstitial. + [[EarlGrey selectElementWithMatcher:IncognitoInterstitialSubtitleForURL( + destinationURL.spec())] + assertWithMatcher:grey_sufficientlyVisible()]; + // Tap the "Open in Chrome Incognito" button. + [[EarlGrey selectElementWithMatcher: + IncognitoInterstitialOpenInChromeIncognitoButton()] + performAction:grey_tap()]; + // Wait for the interstitial to disappear. + [ChromeEarlGrey + waitForUIElementToDisappearWithMatcher:IncognitoInterstitialMatcher()]; + // Wait for the expected page content to be displayed. + [ChromeEarlGrey waitForWebStateContainingText:"You've arrived"]; + // Wait for the main tab count to be two, as expected. + [ChromeEarlGrey waitForIncognitoTabCount:1]; +} + +// Test the "Cancel" button of the Incognito Interstitial. +- (void)testCancelButton { + [ChromeEarlGrey openNewIncognitoTab]; + + // Starting from this regular tab, loading a new URL. + GURL destinationURL = self.testServer->GetURL("/destination.html"); + [ChromeEarlGrey sceneOpenURL:destinationURL]; + // Wait for the interstitial to appear. + [ChromeEarlGrey + waitForUIElementToAppearWithMatcher:IncognitoInterstitialMatcher()]; + // Check the appropriate subtitle is sufficiently visible within the + // Interstitial. + [[EarlGrey selectElementWithMatcher:IncognitoInterstitialSubtitleForURL( + destinationURL.spec())] + assertWithMatcher:grey_sufficientlyVisible()]; + // Tap the Cancel button. + [[EarlGrey selectElementWithMatcher:IncognitoInterstitialCancelButton()] + performAction:grey_tap()]; + // Wait for the interstitial to disappear. + [ChromeEarlGrey + waitForUIElementToDisappearWithMatcher:IncognitoInterstitialMatcher()]; + // Wait for the Incognito tab count to be one, as expected. + [ChromeEarlGrey waitForIncognitoTabCount:1]; + // Check the Incognito NTP is back. + [[EarlGrey selectElementWithMatcher:NTPIncognitoView()] + assertWithMatcher:grey_sufficientlyVisible()]; +} + +// Test that a new intent triggers the dismissal of a former instance of the +// Interstitial, then displays an Interstitial with the new URL. +- (void)testNewInterstitialReplacesFormerInterstitial { + // Starting from NTP, loading a new URL. + GURL destinationURL = self.testServer->GetURL("/destination.html"); + [ChromeEarlGrey sceneOpenURL:destinationURL]; + // Wait for the interstitial to appear. + [ChromeEarlGrey + waitForUIElementToAppearWithMatcher:IncognitoInterstitialMatcher()]; + // Check the appropriate subtitle is sufficiently visible within the + // Interstitial. + [[EarlGrey selectElementWithMatcher:IncognitoInterstitialSubtitleForURL( + destinationURL.spec())] + assertWithMatcher:grey_sufficientlyVisible()]; + // While the Interstitial is shown, loading an alternative URL. + GURL alternativeURL = self.testServer->GetURL("/chromium_logo_page.html"); + [ChromeEarlGrey sceneOpenURL:alternativeURL]; + // Wait for the interstitial to appear. + [ChromeEarlGrey + waitForUIElementToAppearWithMatcher:IncognitoInterstitialMatcher()]; + // Check the appropriate subtitle is sufficiently visible within the + // Interstitial. + [[EarlGrey selectElementWithMatcher:IncognitoInterstitialSubtitleForURL( + alternativeURL.spec())] + assertWithMatcher:grey_sufficientlyVisible()]; + // Tap the "Open in Chrome Incognito" button. + [[EarlGrey selectElementWithMatcher: + IncognitoInterstitialOpenInChromeIncognitoButton()] + performAction:grey_tap()]; + // Wait for the interstitial to disappear. + [ChromeEarlGrey + waitForUIElementToDisappearWithMatcher:IncognitoInterstitialMatcher()]; + // Wait for the expected page content to be displayed. + [ChromeEarlGrey waitForWebStateContainingText: + "Page with some text and the chromium logo image."]; + // Wait for the Incognito tab count to be one, as expected. + [ChromeEarlGrey waitForIncognitoTabCount:1]; +} + +@end
diff --git a/ios/chrome/browser/ui/incognito_interstitial/incognito_interstitial_view_controller.mm b/ios/chrome/browser/ui/incognito_interstitial/incognito_interstitial_view_controller.mm index ac03e31..b308167 100644 --- a/ios/chrome/browser/ui/incognito_interstitial/incognito_interstitial_view_controller.mm +++ b/ios/chrome/browser/ui/incognito_interstitial/incognito_interstitial_view_controller.mm
@@ -6,6 +6,7 @@ #import "base/check.h" #import "base/cxx17_backports.h" #import "base/mac/foundation_util.h" +#import "ios/chrome/browser/ui/incognito_interstitial/incognito_interstitial_constants.h" #import "ios/chrome/browser/ui/ntp/incognito_view.h" #import "ios/chrome/browser/ui/ntp/revamped_incognito_view.h" #import "ios/chrome/browser/ui/ui_feature_flags.h" @@ -42,6 +43,9 @@ #pragma mark - UIViewController - (void)viewDidLoad { + self.view.accessibilityIdentifier = + kIncognitoInterstitialAccessibilityIdentifier; + self.bannerName = @"incognito_interstitial_screen_banner"; self.isTallBanner = YES; self.shouldBannerFillTopSpace = YES; @@ -76,6 +80,8 @@ initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self.delegate action:@selector(didTapCancelButton)]; + cancelButton.accessibilityIdentifier = + kIncognitoInterstitialCancelButtonAccessibilityIdentifier; UINavigationItem* navigationRootItem = [[UINavigationItem alloc] initWithTitle:@""];
diff --git a/ios/chrome/browser/ui/main/scene_controller.mm b/ios/chrome/browser/ui/main/scene_controller.mm index 152aebc..fd175b4 100644 --- a/ios/chrome/browser/ui/main/scene_controller.mm +++ b/ios/chrome/browser/ui/main/scene_controller.mm
@@ -98,6 +98,8 @@ #include "ios/chrome/browser/ui/first_run/fre_field_trial.h" #import "ios/chrome/browser/ui/first_run/orientation_limiting_navigation_controller.h" #include "ios/chrome/browser/ui/history/history_coordinator.h" +#import "ios/chrome/browser/ui/incognito_interstitial/incognito_interstitial_coordinator.h" +#import "ios/chrome/browser/ui/incognito_interstitial/incognito_interstitial_coordinator_delegate.h" #import "ios/chrome/browser/ui/incognito_reauth/incognito_reauth_scene_agent.h" #import "ios/chrome/browser/ui/main/browser_interface_provider.h" #import "ios/chrome/browser/ui/main/browser_view_wrangler.h" @@ -200,7 +202,8 @@ SceneURLLoadingServiceDelegate, TabGridCoordinatorDelegate, UserFeedbackDataSource, - WebStateListObserving> { + WebStateListObserving, + IncognitoInterstitialCoordinatorDelegate> { std::unique_ptr<WebStateListObserverBridge> _webStateListForwardingObserver; std::unique_ptr<PolicyWatcherBrowserAgentObserverBridge> _policyWatcherObserverBridge; @@ -274,6 +277,14 @@ // outside the sign-in prompt UI. @property(nonatomic, assign) BOOL dismissingSigninPromptFromExternalTrigger; +// The coordinator used to present the Incognito interstitial on Incognito +// third-party intents. Created in +// `showIncognitoInterstitialWithUrlLoadParams:dismissOmnibox:completion:` +// and destroyed in +// `closePresentedViews`. +@property(nonatomic, strong) + IncognitoInterstitialCoordinator* incognitoInterstitialCoordinator; + @end @implementation SceneController @@ -670,6 +681,23 @@ #pragma mark - private +// Shows the Incognito interstitial on top of `activeViewController`. +// Assumes the Incognito interstitial coordinator is currently not instantiated. +// Runs `completion` once the Incognito interstitial is presented. +- (void)showIncognitoInterstitialWithUrlLoadParams: + (const UrlLoadParams&)urlLoadParams + completion:(ProceduralBlock)completion { + DCHECK(self.incognitoInterstitialCoordinator == nil); + self.incognitoInterstitialCoordinator = + [[IncognitoInterstitialCoordinator alloc] + initWithBaseViewController:self.activeViewController + browser:self.currentInterface.browser]; + self.incognitoInterstitialCoordinator.delegate = self; + self.incognitoInterstitialCoordinator.tabOpener = self; + self.incognitoInterstitialCoordinator.urlLoadParams = urlLoadParams; + [self.incognitoInterstitialCoordinator startWithCompletion:completion]; +} + // A sink for appState:didTransitionFromInitStage: and // sceneState:transitionedToActivationLevel: events. Discussion: the scene // controller cares both about the app and the scene init stages. This method is @@ -1205,12 +1233,12 @@ UrlLoadParams params = UrlLoadParams::InNewTab(GURL(kChromeUIManagementURL)); params.web_params.transition_type = ui::PAGE_TRANSITION_TYPED; ProceduralBlock moreAction = ^{ - [self dismissModalsAndOpenSelectedTabInMode: + [self dismissModalsAndMaybeOpenSelectedTabInMode: inIncognitoMode ? ApplicationModeForTabOpening::INCOGNITO : ApplicationModeForTabOpening::NORMAL - withUrlLoadParams:params - dismissOmnibox:YES - completion:nil]; + withUrlLoadParams:params + dismissOmnibox:YES + completion:nil]; }; MDCSnackbarMessageAction* action = [[MDCSnackbarMessageAction alloc] init]; @@ -1382,16 +1410,16 @@ ApplicationModeForTabOpening mode = [self isIncognitoForced] ? ApplicationModeForTabOpening::INCOGNITO : ApplicationModeForTabOpening::NORMAL; - [self dismissModalsAndOpenSelectedTabInMode:mode - withUrlLoadParams:params - dismissOmnibox:YES - completion:nil]; + [self dismissModalsAndMaybeOpenSelectedTabInMode:mode + withUrlLoadParams:params + dismissOmnibox:YES + completion:nil]; }; - [self closeSettingsOrSigninAnimated:YES completion:completion]; + [self closePresentedViews:YES completion:completion]; } - (void)closeSettingsUI { - [self closeSettingsOrSigninAnimated:YES completion:nullptr]; + [self closePresentedViews:YES completion:nullptr]; } - (void)prepareTabSwitcher { @@ -2276,19 +2304,39 @@ #pragma mark - TabOpening implementation. -- (void)dismissModalsAndOpenSelectedTabInMode: +- (void)dismissModalsAndMaybeOpenSelectedTabInMode: (ApplicationModeForTabOpening)targetMode - withUrlLoadParams: - (const UrlLoadParams&)urlLoadParams - dismissOmnibox:(BOOL)dismissOmnibox - completion:(ProceduralBlock)completion { + withUrlLoadParams: + (const UrlLoadParams&)urlLoadParams + dismissOmnibox:(BOOL)dismissOmnibox + completion:(ProceduralBlock)completion { + // Fallback to NORMAL or INCOGNITO mode if the Incognito interstitial is not + // available. + if (targetMode == ApplicationModeForTabOpening::UNDETERMINED) { + PrefService* prefs = self.mainInterface.browserState->GetPrefs(); + BOOL canShowIncognitoInterstitial = + base::FeatureList::IsEnabled(kIOS3PIntentsInIncognito) && + prefs->GetBoolean(prefs::kIncognitoInterstitialEnabled); + + if (!canShowIncognitoInterstitial) { + targetMode = [self isIncognitoForced] + ? ApplicationModeForTabOpening::INCOGNITO + : ApplicationModeForTabOpening::NORMAL; + } + } + UrlLoadParams copyOfUrlLoadParams = urlLoadParams; __weak SceneController* weakSelf = self; void (^dismissModalsCompletion)() = ^{ - [weakSelf openSelectedTabInMode:targetMode - withUrlLoadParams:copyOfUrlLoadParams - completion:completion]; + if (targetMode == ApplicationModeForTabOpening::UNDETERMINED) { + [weakSelf showIncognitoInterstitialWithUrlLoadParams:copyOfUrlLoadParams + completion:completion]; + } else { + [weakSelf openSelectedTabInMode:targetMode + withUrlLoadParams:copyOfUrlLoadParams + completion:completion]; + } }; // Wrap the post-dismiss-modals action with the incognito auth check. @@ -2315,15 +2363,17 @@ dismissOmnibox:dismissOmnibox]; } -- (void)dismissModalsAndOpenMultipleTabsInMode: - (ApplicationModeForTabOpening)targetMode - URLs:(const std::vector<GURL>&)URLs - dismissOmnibox:(BOOL)dismissOmnibox - completion:(ProceduralBlock)completion { +- (void)dismissModalsAndOpenMultipleTabsWithURLs:(const std::vector<GURL>&)URLs + inIncognitoMode:(BOOL)incognitoMode + dismissOmnibox:(BOOL)dismissOmnibox + completion:(ProceduralBlock)completion { __weak SceneController* weakSelf = self; std::vector<GURL> copyURLs = URLs; + ApplicationModeForTabOpening targetMode = + incognitoMode ? ApplicationModeForTabOpening::INCOGNITO + : ApplicationModeForTabOpening::NORMAL; id<BrowserInterface> targetInterface = [self extractInterfaceBaseOnMode:targetMode]; @@ -2345,9 +2395,9 @@ navigation_manager->AddRestoreCompletionCallback(base::BindOnce(^{ [self dismissModalDialogsWithCompletion:^{ - [weakSelf openMultipleTabsInMode:targetMode - URLs:copyURLs - completion:completion]; + [weakSelf openMultipleTabsWithURLs:copyURLs + inIncognitoMode:incognitoMode + completion:completion]; } dismissOmnibox:dismissOmnibox]; })); @@ -2357,9 +2407,9 @@ [self dismissModalDialogsWithCompletion:^{ - [weakSelf openMultipleTabsInMode:targetMode - URLs:copyURLs - completion:completion]; + [weakSelf openMultipleTabsWithURLs:copyURLs + inIncognitoMode:incognitoMode + completion:completion]; } dismissOmnibox:dismissOmnibox]; } @@ -2506,28 +2556,27 @@ ? completionWithoutBVC : completionWithBVC; - [self closeSettingsOrSigninAnimated:NO completion:chosenCompletion]; + [self closePresentedViews:NO completion:chosenCompletion]; // Verify that no modal views are left presented. ios::provider::LogIfModalViewsArePresented(); } -- (void)openMultipleTabsInMode: - (ApplicationModeForTabOpening)tabOpeningTargetMode - URLs:(const std::vector<GURL>&)URLs - completion:(ProceduralBlock)completion { +- (void)openMultipleTabsWithURLs:(const std::vector<GURL>&)URLs + inIncognitoMode:(BOOL)openInIncognito + completion:(ProceduralBlock)completion { [self recursiveOpenURLs:URLs - inMode:tabOpeningTargetMode + inIncognitoMode:openInIncognito currentIndex:0 totalCount:URLs.size() completion:completion]; } -// Call `dismissModalsAndOpenSelectedTabInMode` recursively to open the list of -// URLs contained in `URLs`. Achieved through chaining -// `dismissModalsAndOpenSelectedTabInMode` in its completion handler. +// Call `dismissModalsAndMaybeOpenSelectedTabInMode` recursively to open the +// list of URLs contained in `URLs`. Achieved through chaining +// `dismissModalsAndMaybeOpenSelectedTabInMode` in its completion handler. - (void)recursiveOpenURLs:(const std::vector<GURL>&)URLs - inMode:(ApplicationModeForTabOpening)mode + inIncognitoMode:(BOOL)incognitoMode currentIndex:(size_t)currentIndex totalCount:(size_t)totalCount completion:(ProceduralBlock)completion { @@ -2544,7 +2593,7 @@ if (!webpageGURL.is_valid()) { [self recursiveOpenURLs:URLs - inMode:mode + inIncognitoMode:incognitoMode currentIndex:(currentIndex + 1) totalCount:totalCount completion:completion]; @@ -2554,17 +2603,21 @@ UrlLoadParams param = UrlLoadParams::InNewTab(webpageGURL, webpageGURL); std::vector<GURL> copyURLs = URLs; - [self dismissModalsAndOpenSelectedTabInMode:mode - withUrlLoadParams:param - dismissOmnibox:YES - completion:^{ - [weakSelf - recursiveOpenURLs:copyURLs - inMode:mode - currentIndex:(currentIndex + 1) - totalCount:totalCount - completion:completion]; - }]; + ApplicationModeForTabOpening mode = + incognitoMode ? ApplicationModeForTabOpening::INCOGNITO + : ApplicationModeForTabOpening::NORMAL; + [self + dismissModalsAndMaybeOpenSelectedTabInMode:mode + withUrlLoadParams:param + dismissOmnibox:YES + completion:^{ + [weakSelf + recursiveOpenURLs:copyURLs + inIncognitoMode:incognitoMode + currentIndex:(currentIndex + 1) + totalCount:totalCount + completion:completion]; + }]; } // Opens a tab in the target BVC, and switches to it in a way that's appropriate @@ -2580,6 +2633,7 @@ - (void)openSelectedTabInMode:(ApplicationModeForTabOpening)tabOpeningTargetMode withUrlLoadParams:(const UrlLoadParams&)urlLoadParams completion:(ProceduralBlock)completion { + DCHECK(tabOpeningTargetMode != ApplicationModeForTabOpening::UNDETERMINED); // Update the snapshot before opening a new tab. This ensures that the // snapshot is correct when tabs are openned via the dispatcher. [self updateActiveWebStateSnapshot]; @@ -2826,8 +2880,9 @@ completion:nil]; } -- (void)closeSettingsOrSigninAnimated:(BOOL)animated - completion:(ProceduralBlock)completion { +// Close Settings, or Signin or the 3rd-party intents Incognito interstitial. +- (void)closePresentedViews:(BOOL)animated + completion:(ProceduralBlock)completion { __weak __typeof(self) weakSelf = self; BOOL resetSigninState = self.signinCoordinator != nil; completion = ^{ @@ -2866,6 +2921,9 @@ // `self.signinCoordinator` can be presented without settings, from the // bookmarks or the recent tabs view. [self interruptSigninCoordinatorAnimated:animated completion:completion]; + } else if (self.incognitoInterstitialCoordinator) { + [self.incognitoInterstitialCoordinator stopWithCompletion:completion]; + self.incognitoInterstitialCoordinator = nil; } else { completion(); } @@ -2980,6 +3038,14 @@ } } +#pragma mark - IncognitoInterstitialCoordinatorDelegate + +- (void)shouldStopIncognitoInterstitial: + (IncognitoInterstitialCoordinator*)incognitoInterstitial { + DCHECK(incognitoInterstitial == self.incognitoInterstitialCoordinator); + [self closePresentedViews:YES completion:nil]; +} + #pragma mark - Helpers for web state list events // Called when the last incognito tab was closed. @@ -3113,6 +3179,7 @@ - (id<BrowserInterface>)extractInterfaceBaseOnMode: (ApplicationModeForTabOpening)targetMode { + DCHECK(targetMode != ApplicationModeForTabOpening::UNDETERMINED); ApplicationMode applicationMode; if (targetMode == ApplicationModeForTabOpening::CURRENT) {
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_egtest.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_egtest.mm index 4df88b4..f7887ccb 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_egtest.mm +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_egtest.mm
@@ -811,7 +811,7 @@ // scrolling that would happen closer to the left edge. GREYAssert(LongPressCellAndDragToOffsetOf(IdentifierForCellAtIndex(0), 0, IdentifierForCellAtIndex(0), 1, - CGVectorMake(0.4, 0.5)), + CGVectorMake(0.5, 0.5)), @"Failed to DND cell on cell"); GREYWaitForAppToIdle(@"App failed to idle");
diff --git a/ios/chrome/browser/ui/ui_feature_flags.cc b/ios/chrome/browser/ui/ui_feature_flags.cc index 080892d6..c5910aa 100644 --- a/ios/chrome/browser/ui/ui_feature_flags.cc +++ b/ios/chrome/browser/ui/ui_feature_flags.cc
@@ -85,5 +85,8 @@ const base::Feature kEnablePhoneNumbers{"EnablePhoneNumbers", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kMapsExperienceKit{"MapsExperienceKit", + base::FEATURE_DISABLED_BY_DEFAULT}; + const base::Feature kEnableMiniMap{"EnableMiniMap", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/ios/chrome/browser/ui/ui_feature_flags.h b/ios/chrome/browser/ui/ui_feature_flags.h index eb781a09..3cd5994 100644 --- a/ios/chrome/browser/ui/ui_feature_flags.h +++ b/ios/chrome/browser/ui/ui_feature_flags.h
@@ -100,6 +100,9 @@ // Feature flag to enable Phone Numbers detection. extern const base::Feature kEnablePhoneNumbers; +// Feature flag to enable Maps in experience kit. +extern const base::Feature kMapsExperienceKit; + // Feature flag to enable Mini Map in experience kit. extern const base::Feature kEnableMiniMap;
diff --git a/ios/chrome/browser/url_loading/scene_url_loading_service.h b/ios/chrome/browser/url_loading/scene_url_loading_service.h index f4d8ea09..70c059e 100644 --- a/ios/chrome/browser/url_loading/scene_url_loading_service.h +++ b/ios/chrome/browser/url_loading/scene_url_loading_service.h
@@ -37,13 +37,12 @@ withUrlLoadParams:(const UrlLoadParams&)urlLoadParams completion:(ProceduralBlock)completion; -// Open the list of URLs contained in |URLs| in mode specified by -// |tabOpeningTargetMode|. |completion| is executed after all the tabs are +// Open the list of URLs contained in |URLs| in Incognito mode if +// |inIncognitoMode| is YES. |completion| is executed after all the tabs are // opened. -- (void)openMultipleTabsInMode: - (ApplicationModeForTabOpening)tabOpeningTargetMode - URLs:(const std::vector<GURL>&)URLs - completion:(ProceduralBlock)completion; +- (void)openMultipleTabsWithURLs:(const std::vector<GURL>&)URLs + inIncognitoMode:(BOOL)incognitoMode + completion:(ProceduralBlock)completion; // Opens a new tab as if originating from |originPoint| and |focusOmnibox|. - (void)openNewTabFromOriginPoint:(CGPoint)originPoint
diff --git a/ios/chrome/test/earl_grey/BUILD.gn b/ios/chrome/test/earl_grey/BUILD.gn index 06391ea..ddb613e 100644 --- a/ios/chrome/test/earl_grey/BUILD.gn +++ b/ios/chrome/test/earl_grey/BUILD.gn
@@ -116,6 +116,7 @@ "//ios/chrome/browser/ui/first_run:eg_app_support+eg2", "//ios/chrome/browser/ui/fullscreen/test:eg_app_support+eg2", "//ios/chrome/browser/ui/history:constants", + "//ios/chrome/browser/ui/incognito_interstitial:constants", "//ios/chrome/browser/ui/infobars:eg_app_support+eg2", "//ios/chrome/browser/ui/location_bar:constants", "//ios/chrome/browser/ui/location_bar:location_bar", @@ -169,6 +170,7 @@ "//ios/chrome/browser/web", "//ios/chrome/browser/web:eg_app_support+eg2", "//ios/chrome/browser/web_state_list", + "//ios/chrome/common/ui/promo_style:constants", "//ios/chrome/test/app:test_support", "//ios/chrome/test/variations_smoke_test:eg_app_support+eg2", "//ios/public/provider/chrome/browser/signin:fake_chrome_identity",
diff --git a/ios/chrome/test/earl_grey/chrome_matchers.h b/ios/chrome/test/earl_grey/chrome_matchers.h index 3f05b3e3..429b540d 100644 --- a/ios/chrome/test/earl_grey/chrome_matchers.h +++ b/ios/chrome/test/earl_grey/chrome_matchers.h
@@ -536,6 +536,34 @@ // Returns a matcher to the add button in the toolbar in the settings view. id<GREYMatcher> SettingsToolbarAddButton(); +#pragma mark - Promo style view controller + +// Returns matcher for the primary action button. +id<GREYMatcher> PromoStylePrimaryActionButtonMatcher(); + +// Returns matcher for the secondary action button. +id<GREYMatcher> PromoStyleSecondaryActionButtonMatcher(); + +#pragma mark - Incognito Interstitial + +// Returns a matcher for the Incognito Interstitial view controller. +id<GREYMatcher> IncognitoInterstitialMatcher(); + +// Returns a matcher for the subtitle of the Incognito Interstitial, +// as it should appear when `URL` was given to the Interstitial. +id<GREYMatcher> IncognitoInterstitialSubtitleForURL(const std::string& url); + +// Returns a matcher for the primary action button in the Incognito +// Interstitial. +id<GREYMatcher> IncognitoInterstitialOpenInChromeIncognitoButton(); + +// Returns a matcher for the secondary action button in the Incognito +// Interstitial. +id<GREYMatcher> IncognitoInterstitialOpenInChromeButton(); + +// Returns a matcher for the Cancel button in the Incognito Interstitial. +id<GREYMatcher> IncognitoInterstitialCancelButton(); + #pragma mark - Manual Fallback // Returns a matcher for the scroll view in keyboard accessory bar.
diff --git a/ios/chrome/test/earl_grey/chrome_matchers.mm b/ios/chrome/test/earl_grey/chrome_matchers.mm index b1597044..e721fe6 100644 --- a/ios/chrome/test/earl_grey/chrome_matchers.mm +++ b/ios/chrome/test/earl_grey/chrome_matchers.mm
@@ -704,6 +704,40 @@ return [ChromeMatchersAppInterface settingsActionButton]; } +#pragma mark - Promo style view controller + +id<GREYMatcher> PromoStylePrimaryActionButtonMatcher() { + return [ChromeMatchersAppInterface promoStylePrimaryActionButtonMatcher]; +} + +id<GREYMatcher> PromoStyleSecondaryActionButtonMatcher() { + return [ChromeMatchersAppInterface promoStyleSecondaryActionButtonMatcher]; +} + +#pragma mark - Incognito Interstitial + +id<GREYMatcher> IncognitoInterstitialMatcher() { + return [ChromeMatchersAppInterface incognitoInterstitial]; +} + +id<GREYMatcher> IncognitoInterstitialSubtitleForURL(const std::string& url) { + return [ChromeMatchersAppInterface + incognitoInterstitialSubtitleForURL:base::SysUTF8ToNSString(url)]; +} + +id<GREYMatcher> IncognitoInterstitialOpenInChromeIncognitoButton() { + return [ChromeMatchersAppInterface + incognitoInterstitialOpenInChromeIncognitoButton]; +} + +id<GREYMatcher> IncognitoInterstitialOpenInChromeButton() { + return [ChromeMatchersAppInterface incognitoInterstitialOpenInChromeButton]; +} + +id<GREYMatcher> IncognitoInterstitialCancelButton() { + return [ChromeMatchersAppInterface incognitoInterstitialCancelButton]; +} + #pragma mark - Manual Fallback id<GREYMatcher> ManualFallbackFormSuggestionViewMatcher() {
diff --git a/ios/chrome/test/earl_grey/chrome_matchers_app_interface.h b/ios/chrome/test/earl_grey/chrome_matchers_app_interface.h index 129733b..5975e5b3 100644 --- a/ios/chrome/test/earl_grey/chrome_matchers_app_interface.h +++ b/ios/chrome/test/earl_grey/chrome_matchers_app_interface.h
@@ -563,6 +563,34 @@ // carousel. + (id<GREYMatcher>)settingsActionButton; +#pragma mark - Promo style view controller + +// Returns matcher for the primary action button. ++ (id<GREYMatcher>)promoStylePrimaryActionButtonMatcher; + +// Returns matcher for the secondary action button. ++ (id<GREYMatcher>)promoStyleSecondaryActionButtonMatcher; + +#pragma mark - Incognito Interstitial + +// Returns a matcher for the Incognito Interstitial view controller. ++ (id<GREYMatcher>)incognitoInterstitial; + +// Returns a matcher for the subtitle of the Incognito Interstitial, +// as it should appear when `URL` was given to the Interstitial. ++ (id<GREYMatcher>)incognitoInterstitialSubtitleForURL:(NSString*)url; + +// Returns a matcher for the primary action button in the Incognito +// Interstitial. ++ (id<GREYMatcher>)incognitoInterstitialOpenInChromeIncognitoButton; + +// Returns a matcher for the secondary action button in the Incognito +// Interstitial. ++ (id<GREYMatcher>)incognitoInterstitialOpenInChromeButton; + +// Returns a matcher for the Cancel button in the Incognito Interstitial. ++ (id<GREYMatcher>)incognitoInterstitialCancelButton; + #pragma mark - Manual Fallback // Returns a matcher for the scroll view in keyboard accessory bar.
diff --git a/ios/chrome/test/earl_grey/chrome_matchers_app_interface.mm b/ios/chrome/test/earl_grey/chrome_matchers_app_interface.mm index d00966d..605b422fd 100644 --- a/ios/chrome/test/earl_grey/chrome_matchers_app_interface.mm +++ b/ios/chrome/test/earl_grey/chrome_matchers_app_interface.mm
@@ -25,6 +25,7 @@ #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_constants.h" #import "ios/chrome/browser/ui/content_suggestions/ntp_home_constant.h" #import "ios/chrome/browser/ui/history/history_ui_constants.h" +#import "ios/chrome/browser/ui/incognito_interstitial/incognito_interstitial_constants.h" #import "ios/chrome/browser/ui/location_bar/location_bar_constants.h" #import "ios/chrome/browser/ui/location_bar/location_bar_steady_view.h" #import "ios/chrome/browser/ui/ntp/new_tab_page_constants.h" @@ -60,6 +61,7 @@ #include "ios/chrome/browser/ui/ui_feature_flags.h" #import "ios/chrome/browser/ui/util/ui_util.h" #import "ios/chrome/browser/ui/util/uikit_ui_util.h" +#import "ios/chrome/common/ui/promo_style/constants.h" #include "ios/chrome/grit/ios_strings.h" #import "ios/chrome/test/app/tab_test_util.h" #import "ios/chrome/test/app/window_test_util.h" @@ -1092,6 +1094,52 @@ return grey_accessibilityID(kToolsMenuSettingsActionId); } +#pragma mark - Promo style view controller + +// Returns matcher for the primary action button. ++ (id<GREYMatcher>)promoStylePrimaryActionButtonMatcher { + return grey_accessibilityID(kPromoStylePrimaryActionAccessibilityIdentifier); +} + +// Returns matcher for the secondary action button. ++ (id<GREYMatcher>)promoStyleSecondaryActionButtonMatcher { + return grey_accessibilityID( + kPromoStyleSecondaryActionAccessibilityIdentifier); +} + +#pragma mark - Incognito Interstitial + ++ (id<GREYMatcher>)incognitoInterstitial { + return grey_accessibilityID(kIncognitoInterstitialAccessibilityIdentifier); +} + ++ (id<GREYMatcher>)incognitoInterstitialSubtitleForURL:(NSString*)url { + return grey_allOf( + grey_accessibilityID(kPromoStyleSubtitleAccessibilityIdentifier), + grey_accessibilityLabel(url), nullptr); +} + ++ (id<GREYMatcher>)incognitoInterstitialOpenInChromeIncognitoButton { + return grey_allOf( + [ChromeMatchersAppInterface promoStylePrimaryActionButtonMatcher], + grey_accessibilityLabel(l10n_util::GetNSString( + IDS_IOS_INCOGNITO_INTERSTITIAL_OPEN_IN_CHROME_INCOGNITO)), + nullptr); +} + ++ (id<GREYMatcher>)incognitoInterstitialOpenInChromeButton { + return grey_allOf( + [ChromeMatchersAppInterface promoStyleSecondaryActionButtonMatcher], + grey_accessibilityLabel(l10n_util::GetNSString( + IDS_IOS_INCOGNITO_INTERSTITIAL_OPEN_IN_CHROME)), + nullptr); +} + ++ (id<GREYMatcher>)incognitoInterstitialCancelButton { + return grey_accessibilityID( + kIncognitoInterstitialCancelButtonAccessibilityIdentifier); +} + #pragma mark - Manual Fallback + (id<GREYMatcher>)manualFallbackFormSuggestionViewMatcher {
diff --git a/ios/chrome/test/earl_grey2/BUILD.gn b/ios/chrome/test/earl_grey2/BUILD.gn index 41431e82..04cd075 100644 --- a/ios/chrome/test/earl_grey2/BUILD.gn +++ b/ios/chrome/test/earl_grey2/BUILD.gn
@@ -163,6 +163,7 @@ "//ios/chrome/browser/ui/first_run:eg2_tests", "//ios/chrome/browser/ui/fullscreen:eg2_tests", "//ios/chrome/browser/ui/history:eg2_tests", + "//ios/chrome/browser/ui/incognito_interstitial:eg2_tests", "//ios/chrome/browser/ui/infobars:eg2_tests", "//ios/chrome/browser/ui/keyboard:eg2_tests", "//ios/chrome/browser/ui/link_to_text:eg2_tests",
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 index a328037..92cd297 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -96455434b65f6fa863762d64b1436ce742560233 \ No newline at end of file +9e70bf093b5d3f9d18b625dc1720060e3d4b66fa \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 index 48552dc..5dd8096f2 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -7096eee567da8a63435863373f74976cbf94afd6 \ No newline at end of file +1718d0f6c3c71267b1c8c8891411a0f86632233d \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 index 457869b7..6b54a37d 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -259232fd2a62e08819655fce7a3529109de4ef6d \ No newline at end of file +286ff4bd1e1bb3c99fa87ccb1503db4736f8c902 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 index 6290f3d..b4ce9a1 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -abbee34f9a40e8357141a3a89cd98721a24985f3 \ No newline at end of file +dc910631aab14a3230ae1f7f9b94a45cf4ceac2b \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1 index 5dd692d..251af531 100644 --- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -8584291aec6b0f1b7c63170284ed6ee2ae3b049e \ No newline at end of file +4f250ae0007d11e53398c9f0c83069ea223bfe20 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1 index dc6b893..c55dfdf2 100644 --- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -4d05f9b7762b8e9da997afa6ff713ffd6c57f111 \ No newline at end of file +fe0bdd2b92530cb9ff22e821617776ba4b23b38b \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 index 55d1682..708a9b3c 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -e5661d37bb6642e8ee9b49ba5e2124d264c3fa45 \ No newline at end of file +4b04f92fef9c92592a3a2090a4dadcc0092d1021 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 index 9dd9918c..c4e63ba 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -c3b1f36faa0dfa179a893abf0da665658a784689 \ No newline at end of file +7f531b5d34bef70a49fe77111358a76430995aca \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 index e3205fb4..4ca8ce8d 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -07c1771300bee66568d1433fe6d7296b1691c34e \ No newline at end of file +c5cad04dff3b3cad98154492f17856f5ae14c55b \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 index 8a4acec8..1f1f6e2 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -020da02b1f25c965cb2936ebb0db60fb31e885cc \ No newline at end of file +949090e2b96bf2b51eb00f48be99ba8096491b0f \ No newline at end of file
diff --git a/ios/web/find_in_page/find_in_page_manger_impl_unittest.mm b/ios/web/find_in_page/find_in_page_manger_impl_unittest.mm index dc75afc1..ddd84479 100644 --- a/ios/web/find_in_page/find_in_page_manger_impl_unittest.mm +++ b/ios/web/find_in_page/find_in_page_manger_impl_unittest.mm
@@ -701,11 +701,13 @@ base::RunLoop().RunUntilIdle(); return fake_delegate_.state() && fake_delegate_.state()->match_count == 2; })); - auto select_and_scroll_result = std::make_unique<base::DictionaryValue>(); - select_and_scroll_result->SetDouble("matches", 3.0); - select_and_scroll_result->SetDouble("index", 1.0); + base::Value::Dict select_and_scroll_result; + select_and_scroll_result.Set("matches", 3.0); + select_and_scroll_result.Set("index", 1.0); + base::Value select_and_scroll_result_value( + std::move(select_and_scroll_result)); frame_with_hidden_match_ptr->AddJsResultForFunctionCall( - select_and_scroll_result.get(), kFindInPageSelectAndScrollToMatch); + &select_and_scroll_result_value, kFindInPageSelectAndScrollToMatch); GetFindInPageManager()->Find(@"foo", FindInPageOptions::FindInPageNext); ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^bool {
diff --git a/media/capture/video/win/video_capture_device_mf_win.cc b/media/capture/video/win/video_capture_device_mf_win.cc index 0afde08..b16c15ea 100644 --- a/media/capture/video/win/video_capture_device_mf_win.cc +++ b/media/capture/video/win/video_capture_device_mf_win.cc
@@ -1186,14 +1186,21 @@ void VideoCaptureDeviceMFWin::StopAndDeAllocate() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - HRESULT hr = E_FAIL; if (is_started_ && engine_) { - hr = engine_->StopPreview(); + engine_->StopPreview(); } - if (SUCCEEDED(hr)) { - WaitOnCaptureEvent(MF_CAPTURE_ENGINE_PREVIEW_STOPPED); - } + // Ideally, we should wait for MF_CAPTURE_ENGINE_PREVIEW_STOPPED event here. + // However, since |engine_| is not reused for video capture after here, + // we can safely ignore this event to reduce the delay. + // It's only important to ensure that incoming events after the capture has + // stopped shouldn't lead to any crashes. + // This is achieved by ensuring that the |video_callback_| is shutdown in the + // destructor which will stop it from trying to use potentially destroyed + // VideoCaptureDeviceMFWin instance. + // Also, the callback itself is ref counted and |engine_| holds the reference, + // so we can delete this class at any time without creating use-after-free + // situations. is_started_ = false; client_.reset();
diff --git a/net/websockets/websocket_channel.cc b/net/websockets/websocket_channel.cc index 1786c34..4d9392f 100644 --- a/net/websockets/websocket_channel.cc +++ b/net/websockets/websocket_channel.cc
@@ -1008,7 +1008,11 @@ net::NetLogEventType::WEBSOCKET_CLOSE_TIMEOUT); stream_->Close(); SetState(CLOSED); - DoDropChannel(false, kWebSocketErrorAbnormalClosure, ""); + if (has_received_close_frame_) { + DoDropChannel(true, received_close_code_, received_close_reason_); + } else { + DoDropChannel(false, kWebSocketErrorAbnormalClosure, ""); + } // |this| has been deleted. }
diff --git a/net/websockets/websocket_channel_test.cc b/net/websockets/websocket_channel_test.cc index 8c3e9ad..13bc5f4 100644 --- a/net/websockets/websocket_channel_test.cc +++ b/net/websockets/websocket_channel_test.cc
@@ -1737,7 +1737,7 @@ EXPECT_CALL(checkpoint, Call(1)); EXPECT_CALL(*event_interface_, OnClosingHandshake()); EXPECT_CALL(*event_interface_, - OnDropChannel(false, kWebSocketErrorAbnormalClosure, _)) + OnDropChannel(true, kWebSocketNormalClosure, _)) .WillOnce(InvokeClosure(&completion)); } CreateChannelAndConnectSuccessfully();
diff --git a/services/audio/device_listener_output_stream.cc b/services/audio/device_listener_output_stream.cc index 834ede00..47bbb34f 100644 --- a/services/audio/device_listener_output_stream.cc +++ b/services/audio/device_listener_output_stream.cc
@@ -61,7 +61,9 @@ void DeviceListenerOutputStream::Close() { DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK(!source_callback_); - stream_->Close(); + // ExtractAsDangling clears the underlying pointer and returns another raw_ptr + // instance that is allowed to dangle. + stream_.ExtractAsDangling()->Close(); // To match a typical AudioOutputStream usage pattern. delete this; }
diff --git a/services/audio/device_listener_output_stream.h b/services/audio/device_listener_output_stream.h index aaeaeca9..e91d467f 100644 --- a/services/audio/device_listener_output_stream.h +++ b/services/audio/device_listener_output_stream.h
@@ -65,7 +65,7 @@ const raw_ptr<media::AudioManager> audio_manager_; - const raw_ptr<media::AudioOutputStream, DanglingUntriaged> stream_; + raw_ptr<media::AudioOutputStream> stream_; // Callback to process the device change. base::OnceClosure on_device_change_callback_;
diff --git a/services/network/first_party_sets/first_party_sets_access_delegate.cc b/services/network/first_party_sets/first_party_sets_access_delegate.cc index 5354341..60ba90f 100644 --- a/services/network/first_party_sets/first_party_sets_access_delegate.cc +++ b/services/network/first_party_sets/first_party_sets_access_delegate.cc
@@ -50,6 +50,10 @@ const std::set<net::SchemefulSite>& party_context, base::OnceCallback<void(net::FirstPartySetMetadata)> callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (!context_config_.is_enabled()) { + return {net::FirstPartySetMetadata()}; + } if (pending_queries_) { // base::Unretained() is safe because `this` owns `pending_queries_` and // `pending_queries_` will not run the enqueued callbacks after `this` is @@ -71,6 +75,11 @@ base::OnceCallback<void(FirstPartySetsAccessDelegate::OwnerResult)> callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (!context_config_.is_enabled()) { + return absl::make_optional<FirstPartySetsManager::OwnerResult>( + absl::nullopt); + } if (pending_queries_) { // base::Unretained() is safe because `this` owns `pending_queries_` and // `pending_queries_` will not run the enqueued callbacks after `this` is @@ -90,6 +99,10 @@ base::OnceCallback<void(FirstPartySetsAccessDelegate::OwnersResult)> callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (!context_config_.is_enabled()) + return {{}}; + if (pending_queries_) { // base::Unretained() is safe because `this` owns `pending_queries_` and // `pending_queries_` will not run the enqueued callbacks after `this` is @@ -109,6 +122,8 @@ const std::set<net::SchemefulSite>& party_context, base::OnceCallback<void(net::FirstPartySetMetadata)> callback) const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(context_config_.is_enabled()); + std::pair<base::OnceCallback<void(net::FirstPartySetMetadata)>, base::OnceCallback<void(net::FirstPartySetMetadata)>> callbacks = base::SplitOnceCallback(std::move(callback)); @@ -127,6 +142,8 @@ base::OnceCallback<void(FirstPartySetsAccessDelegate::OwnerResult)> callback) const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(context_config_.is_enabled()); + std::pair<base::OnceCallback<void(FirstPartySetsAccessDelegate::OwnerResult)>, base::OnceCallback<void(FirstPartySetsAccessDelegate::OwnerResult)>> callbacks = base::SplitOnceCallback(std::move(callback)); @@ -143,6 +160,8 @@ base::OnceCallback<void(FirstPartySetsAccessDelegate::OwnersResult)> callback) const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(context_config_.is_enabled()); + std::pair< base::OnceCallback<void(FirstPartySetsAccessDelegate::OwnersResult)>, base::OnceCallback<void(FirstPartySetsAccessDelegate::OwnersResult)>>
diff --git a/services/network/first_party_sets/first_party_sets_access_delegate_unittest.cc b/services/network/first_party_sets/first_party_sets_access_delegate_unittest.cc index c700489..75e576f 100644 --- a/services/network/first_party_sets/first_party_sets_access_delegate_unittest.cc +++ b/services/network/first_party_sets/first_party_sets_access_delegate_unittest.cc
@@ -172,6 +172,8 @@ FirstPartySetsAccessDelegate delegate_; }; +// Since the FPSs is disabled for the context, none of the callbacks +// should ever be called, and the return values should all be non-nullopt. class FirstPartySetsAccessDelegateDisabledTest : public FirstPartySetsAccessDelegateTest { public: @@ -180,19 +182,37 @@ }; TEST_F(FirstPartySetsAccessDelegateDisabledTest, ComputeMetadata) { - EXPECT_THAT(ComputeMetadataAndWait(kSet1Member1, &kSet1Member1, - {kSet1Member1, kSet1Owner}) - .context(), - net::SamePartyContext(Type::kCrossParty)); + // Same as the default ctor, but just to be explicit: + net::FirstPartySetMetadata expected_metadata(net::SamePartyContext(), + /*frame_owner=*/nullptr, + /*top_frame_owner=*/nullptr); + + EXPECT_THAT(delegate().ComputeMetadata( + kSet1Member1, &kSet1Member1, {kSet1Member1, kSet1Owner}, + base::BindOnce([](net::FirstPartySetMetadata) { FAIL(); })), + Optional(std::ref(expected_metadata))); } TEST_F(FirstPartySetsAccessDelegateDisabledTest, FindOwner) { - EXPECT_FALSE(FindOwnerAndWait(kSet1Owner)); - EXPECT_FALSE(FindOwnerAndWait(kSet1Member1)); + EXPECT_THAT( + delegate().FindOwner( + kSet1Owner, + base::BindOnce([](FirstPartySetsManager::OwnerResult) { FAIL(); })), + Optional(absl::nullopt)); + + EXPECT_THAT( + delegate().FindOwner( + kSet1Member1, + base::BindOnce([](FirstPartySetsManager::OwnerResult) { FAIL(); })), + Optional(absl::nullopt)); } TEST_F(FirstPartySetsAccessDelegateDisabledTest, FindOwners) { - EXPECT_THAT(FindOwnersAndWait({kSet1Member1, kSet2Member1}), IsEmpty()); + EXPECT_THAT( + delegate().FindOwners( + {kSet1Member1, kSet2Member1}, + base::BindOnce([](FirstPartySetsManager::OwnersResult) { FAIL(); })), + Optional(IsEmpty())); } // Test fixture that allows precise control over when the instance gets FPS
diff --git a/services/network/first_party_sets/first_party_sets_manager.cc b/services/network/first_party_sets/first_party_sets_manager.cc index ff16c821..dd79bb8 100644 --- a/services/network/first_party_sets/first_party_sets_manager.cc +++ b/services/network/first_party_sets/first_party_sets_manager.cc
@@ -123,6 +123,8 @@ const FirstPartySetsContextConfig& fps_context_config) const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(sets_.has_value()); + DCHECK(fps_context_config.is_enabled()); + const base::ElapsedTimer timer; net::SamePartyContext::Type context_type = @@ -150,6 +152,7 @@ const FirstPartySetsContextConfig& fps_context_config) const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(sets_.has_value()); + DCHECK(fps_context_config.is_enabled()); const base::ElapsedTimer timer; net::SchemefulSite normalized_site = site; @@ -157,7 +160,7 @@ FirstPartySetsManager::OwnerResult entry; - if (fps_context_config.is_enabled() && is_enabled()) { + if (is_enabled()) { // Check if `normalized_site` can be found in the customizations first. // If not, fall back to look up in `sets_`. if (const auto it = @@ -246,9 +249,7 @@ const FirstPartySetsContextConfig& fps_context_config) const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(sets_.has_value()); - - if (!fps_context_config.is_enabled()) - return {}; + DCHECK(fps_context_config.is_enabled()); std::vector<std::pair<net::SchemefulSite, net::FirstPartySetEntry>> sites_to_entries;
diff --git a/services/network/first_party_sets/first_party_sets_manager_unittest.cc b/services/network/first_party_sets/first_party_sets_manager_unittest.cc index ab14a5c..4008a08 100644 --- a/services/network/first_party_sets/first_party_sets_manager_unittest.cc +++ b/services/network/first_party_sets/first_party_sets_manager_unittest.cc
@@ -895,58 +895,6 @@ net::SchemefulSite(GURL("https://foo.test")))))); } -class DisabledContextFirstPartySetsManagerTest - : public PopulatedFirstPartySetsManagerTest { - public: - DisabledContextFirstPartySetsManagerTest() { - SetFirstPartySetsContextConfig( - false, - // Should not have effect when FPS is disabled for the context. - { - {net::SchemefulSite(GURL("https://example.test")), - absl::make_optional(net::FirstPartySetEntry( - net::SchemefulSite(GURL("https://foo.test"))))}, - // Below are the owner self mappings. - {net::SchemefulSite(GURL("https://foo.test")), - absl::make_optional(net::FirstPartySetEntry( - net::SchemefulSite(GURL("https://foo.test"))))}, - }); - } -}; - -TEST_F(DisabledContextFirstPartySetsManagerTest, FindOwners) { - EXPECT_THAT( - FindOwnersAndWait({net::SchemefulSite(GURL("https://example.test"))}), - IsEmpty()); -} - -TEST_F(DisabledContextFirstPartySetsManagerTest, FindOwner) { - EXPECT_FALSE( - FindOwnerAndWait(net::SchemefulSite(GURL("https://example.test")))); - EXPECT_FALSE( - FindOwnerAndWait(net::SchemefulSite(GURL("https://member.test")))); -} - -TEST_F(DisabledContextFirstPartySetsManagerTest, ComputeMetadata) { - net::SchemefulSite member(GURL("https://member1.test")); - net::SchemefulSite example(GURL("https://example.test")); - net::SchemefulSite wss_member(GURL("wss://member1.test")); - - // Works if the site is provided with WSS scheme instead of HTTPS. - EXPECT_THAT( - ComputeMetadataAndWait(wss_member, &member, {member, example}).context(), - net::SamePartyContext(Type::kCrossParty)); - - EXPECT_THAT(ComputeMetadataAndWait(example, &member, {member}).context(), - net::SamePartyContext(Type::kCrossParty)); - EXPECT_THAT(ComputeMetadataAndWait(member, &example, {member}).context(), - net::SamePartyContext(Type::kCrossParty)); - - EXPECT_THAT( - ComputeMetadataAndWait(member, &member, {member, example}).context(), - net::SamePartyContext(Type::kCrossParty)); -} - class OverrideSetsFirstPartySetsManagerTest : public FirstPartySetsEnabledTest { public: OverrideSetsFirstPartySetsManagerTest() {
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json index d96a2b34..aeab194b 100644 --- a/testing/buildbot/chromium.chromiumos.json +++ b/testing/buildbot/chromium.chromiumos.json
@@ -5750,21 +5750,21 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5219.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5220.0/test_ash_chrome" ], "isolate_profile_data": true, "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "interactive_ui_tests Lacros version skew testing ash 106.0.5219.0", + "name": "interactive_ui_tests Lacros version skew testing ash 106.0.5220.0", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v106.0.5219.0", - "revision": "version:106.0.5219.0" + "location": "lacros_version_skew_tests_v106.0.5220.0", + "revision": "version:106.0.5220.0" } ], "dimension_sets": [ @@ -5777,7 +5777,7 @@ }, "test": "interactive_ui_tests", "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/", - "variant_id": "Lacros version skew testing ash 106.0.5219.0" + "variant_id": "Lacros version skew testing ash 106.0.5220.0" }, { "isolate_profile_data": true, @@ -5915,21 +5915,21 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5219.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5220.0/test_ash_chrome" ], "isolate_profile_data": true, "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "lacros_chrome_browsertests Lacros version skew testing ash 106.0.5219.0", + "name": "lacros_chrome_browsertests Lacros version skew testing ash 106.0.5220.0", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v106.0.5219.0", - "revision": "version:106.0.5219.0" + "location": "lacros_version_skew_tests_v106.0.5220.0", + "revision": "version:106.0.5220.0" } ], "dimension_sets": [ @@ -5941,7 +5941,7 @@ }, "test": "lacros_chrome_browsertests", "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/", - "variant_id": "Lacros version skew testing ash 106.0.5219.0" + "variant_id": "Lacros version skew testing ash 106.0.5220.0" }, { "args": [ @@ -6061,21 +6061,21 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5219.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5220.0/test_ash_chrome" ], "isolate_profile_data": true, "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 106.0.5219.0", + "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 106.0.5220.0", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v106.0.5219.0", - "revision": "version:106.0.5219.0" + "location": "lacros_version_skew_tests_v106.0.5220.0", + "revision": "version:106.0.5220.0" } ], "dimension_sets": [ @@ -6087,7 +6087,7 @@ }, "test": "lacros_chrome_browsertests_run_in_series", "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests_run_in_series/", - "variant_id": "Lacros version skew testing ash 106.0.5219.0" + "variant_id": "Lacros version skew testing ash 106.0.5220.0" }, { "isolate_profile_data": true,
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json index aa9a91f..a8f21b8 100644 --- a/testing/buildbot/chromium.fyi.json +++ b/testing/buildbot/chromium.fyi.json
@@ -99293,21 +99293,21 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5219.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5220.0/test_ash_chrome" ], "isolate_profile_data": true, "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "interactive_ui_tests Lacros version skew testing ash 106.0.5219.0", + "name": "interactive_ui_tests Lacros version skew testing ash 106.0.5220.0", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v106.0.5219.0", - "revision": "version:106.0.5219.0" + "location": "lacros_version_skew_tests_v106.0.5220.0", + "revision": "version:106.0.5220.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", @@ -99315,7 +99315,7 @@ }, "test": "interactive_ui_tests", "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/", - "variant_id": "Lacros version skew testing ash 106.0.5219.0" + "variant_id": "Lacros version skew testing ash 106.0.5220.0" }, { "isolate_profile_data": true, @@ -99428,28 +99428,28 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5219.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5220.0/test_ash_chrome" ], "isolate_profile_data": true, "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "lacros_chrome_browsertests Lacros version skew testing ash 106.0.5219.0", + "name": "lacros_chrome_browsertests Lacros version skew testing ash 106.0.5220.0", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v106.0.5219.0", - "revision": "version:106.0.5219.0" + "location": "lacros_version_skew_tests_v106.0.5220.0", + "revision": "version:106.0.5220.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "lacros_chrome_browsertests", "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/", - "variant_id": "Lacros version skew testing ash 106.0.5219.0" + "variant_id": "Lacros version skew testing ash 106.0.5220.0" }, { "args": [ @@ -99549,28 +99549,28 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5219.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5220.0/test_ash_chrome" ], "isolate_profile_data": true, "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 106.0.5219.0", + "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 106.0.5220.0", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v106.0.5219.0", - "revision": "version:106.0.5219.0" + "location": "lacros_version_skew_tests_v106.0.5220.0", + "revision": "version:106.0.5220.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "lacros_chrome_browsertests_run_in_series", "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests_run_in_series/", - "variant_id": "Lacros version skew testing ash 106.0.5219.0" + "variant_id": "Lacros version skew testing ash 106.0.5220.0" }, { "isolate_profile_data": true, @@ -100908,20 +100908,20 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5219.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5220.0/test_ash_chrome" ], "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "interactive_ui_tests Lacros version skew testing ash 106.0.5219.0", + "name": "interactive_ui_tests Lacros version skew testing ash 106.0.5220.0", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v106.0.5219.0", - "revision": "version:106.0.5219.0" + "location": "lacros_version_skew_tests_v106.0.5220.0", + "revision": "version:106.0.5220.0" } ], "dimension_sets": [ @@ -100935,7 +100935,7 @@ }, "test": "interactive_ui_tests", "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/", - "variant_id": "Lacros version skew testing ash 106.0.5219.0" + "variant_id": "Lacros version skew testing ash 106.0.5220.0" }, { "merge": { @@ -101073,20 +101073,20 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5219.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5220.0/test_ash_chrome" ], "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "lacros_chrome_browsertests Lacros version skew testing ash 106.0.5219.0", + "name": "lacros_chrome_browsertests Lacros version skew testing ash 106.0.5220.0", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v106.0.5219.0", - "revision": "version:106.0.5219.0" + "location": "lacros_version_skew_tests_v106.0.5220.0", + "revision": "version:106.0.5220.0" } ], "dimension_sets": [ @@ -101099,7 +101099,7 @@ }, "test": "lacros_chrome_browsertests", "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/", - "variant_id": "Lacros version skew testing ash 106.0.5219.0" + "variant_id": "Lacros version skew testing ash 106.0.5220.0" }, { "args": [ @@ -101219,20 +101219,20 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5219.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5220.0/test_ash_chrome" ], "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 106.0.5219.0", + "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 106.0.5220.0", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v106.0.5219.0", - "revision": "version:106.0.5219.0" + "location": "lacros_version_skew_tests_v106.0.5220.0", + "revision": "version:106.0.5220.0" } ], "dimension_sets": [ @@ -101245,7 +101245,7 @@ }, "test": "lacros_chrome_browsertests_run_in_series", "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests_run_in_series/", - "variant_id": "Lacros version skew testing ash 106.0.5219.0" + "variant_id": "Lacros version skew testing ash 106.0.5220.0" }, { "merge": { @@ -102741,20 +102741,20 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5219.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5220.0/test_ash_chrome" ], "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "interactive_ui_tests Lacros version skew testing ash 106.0.5219.0", + "name": "interactive_ui_tests Lacros version skew testing ash 106.0.5220.0", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v106.0.5219.0", - "revision": "version:106.0.5219.0" + "location": "lacros_version_skew_tests_v106.0.5220.0", + "revision": "version:106.0.5220.0" } ], "dimension_sets": [ @@ -102768,7 +102768,7 @@ }, "test": "interactive_ui_tests", "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/", - "variant_id": "Lacros version skew testing ash 106.0.5219.0" + "variant_id": "Lacros version skew testing ash 106.0.5220.0" }, { "merge": { @@ -102906,20 +102906,20 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5219.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5220.0/test_ash_chrome" ], "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "lacros_chrome_browsertests Lacros version skew testing ash 106.0.5219.0", + "name": "lacros_chrome_browsertests Lacros version skew testing ash 106.0.5220.0", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v106.0.5219.0", - "revision": "version:106.0.5219.0" + "location": "lacros_version_skew_tests_v106.0.5220.0", + "revision": "version:106.0.5220.0" } ], "dimension_sets": [ @@ -102932,7 +102932,7 @@ }, "test": "lacros_chrome_browsertests", "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/", - "variant_id": "Lacros version skew testing ash 106.0.5219.0" + "variant_id": "Lacros version skew testing ash 106.0.5220.0" }, { "args": [ @@ -103052,20 +103052,20 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5219.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5220.0/test_ash_chrome" ], "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 106.0.5219.0", + "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 106.0.5220.0", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v106.0.5219.0", - "revision": "version:106.0.5219.0" + "location": "lacros_version_skew_tests_v106.0.5220.0", + "revision": "version:106.0.5220.0" } ], "dimension_sets": [ @@ -103078,7 +103078,7 @@ }, "test": "lacros_chrome_browsertests_run_in_series", "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests_run_in_series/", - "variant_id": "Lacros version skew testing ash 106.0.5219.0" + "variant_id": "Lacros version skew testing ash 106.0.5220.0" }, { "merge": { @@ -103813,20 +103813,20 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5219.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5220.0/test_ash_chrome" ], "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "interactive_ui_tests Lacros version skew testing ash 106.0.5219.0", + "name": "interactive_ui_tests Lacros version skew testing ash 106.0.5220.0", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v106.0.5219.0", - "revision": "version:106.0.5219.0" + "location": "lacros_version_skew_tests_v106.0.5220.0", + "revision": "version:106.0.5220.0" } ], "dimension_sets": [ @@ -103839,7 +103839,7 @@ }, "test": "interactive_ui_tests", "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/", - "variant_id": "Lacros version skew testing ash 106.0.5219.0" + "variant_id": "Lacros version skew testing ash 106.0.5220.0" } ] }, @@ -113763,6 +113763,84 @@ } ] }, + "win10.20h2-blink-rel": { + "isolated_scripts": [ + { + "args": [ + "--num-retries=3", + "--write-run-histories-to=${ISOLATED_OUTDIR}/run_histories.json", + "--git-revision=${got_revision}" + ], + "check_flakiness_for_new_tests": false, + "isolate_name": "blink_web_tests", + "merge": { + "args": [ + "--verbose" + ], + "script": "//third_party/blink/tools/merge_web_test_results.py" + }, + "name": "blink_web_tests", + "precommit_args": [ + "--gerrit-issue=${patch_issue}", + "--gerrit-patchset=${patch_set}", + "--buildbucket-id=${buildbucket_build_id}" + ], + "resultdb": { + "enable": true + }, + "results_handler": "layout tests", + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "os": "Windows-10-19042" + } + ], + "hard_timeout": 1200, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 6 + }, + "test_id_prefix": "ninja://:blink_web_tests/" + }, + { + "args": [ + "--num-retries=3", + "--write-run-histories-to=${ISOLATED_OUTDIR}/run_histories.json", + "--git-revision=${got_revision}" + ], + "check_flakiness_for_new_tests": false, + "isolate_name": "blink_wpt_tests", + "merge": { + "args": [ + "--verbose" + ], + "script": "//third_party/blink/tools/merge_web_test_results.py" + }, + "name": "blink_wpt_tests", + "precommit_args": [ + "--gerrit-issue=${patch_issue}", + "--gerrit-patchset=${patch_set}", + "--buildbucket-id=${buildbucket_build_id}" + ], + "resultdb": { + "enable": true + }, + "results_handler": "layout tests", + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "os": "Windows-10-19042" + } + ], + "hard_timeout": 1200, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 9 + }, + "test_id_prefix": "ninja://:blink_wpt_tests/" + } + ] + }, "win10.20h2-blink-rel-dummy": { "isolated_scripts": [ {
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json index 9439a6c..40eac77 100644 --- a/testing/buildbot/chromium.memory.json +++ b/testing/buildbot/chromium.memory.json
@@ -20871,21 +20871,21 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5219.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5220.0/test_ash_chrome" ], "isolate_profile_data": true, "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "interactive_ui_tests Lacros version skew testing ash 106.0.5219.0", + "name": "interactive_ui_tests Lacros version skew testing ash 106.0.5220.0", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v106.0.5219.0", - "revision": "version:106.0.5219.0" + "location": "lacros_version_skew_tests_v106.0.5220.0", + "revision": "version:106.0.5220.0" } ], "dimension_sets": [ @@ -20898,7 +20898,7 @@ }, "test": "interactive_ui_tests", "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/", - "variant_id": "Lacros version skew testing ash 106.0.5219.0" + "variant_id": "Lacros version skew testing ash 106.0.5220.0" }, { "isolate_profile_data": true, @@ -21036,21 +21036,21 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5219.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5220.0/test_ash_chrome" ], "isolate_profile_data": true, "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "lacros_chrome_browsertests Lacros version skew testing ash 106.0.5219.0", + "name": "lacros_chrome_browsertests Lacros version skew testing ash 106.0.5220.0", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v106.0.5219.0", - "revision": "version:106.0.5219.0" + "location": "lacros_version_skew_tests_v106.0.5220.0", + "revision": "version:106.0.5220.0" } ], "dimension_sets": [ @@ -21062,7 +21062,7 @@ }, "test": "lacros_chrome_browsertests", "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/", - "variant_id": "Lacros version skew testing ash 106.0.5219.0" + "variant_id": "Lacros version skew testing ash 106.0.5220.0" }, { "args": [ @@ -21182,21 +21182,21 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5219.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5220.0/test_ash_chrome" ], "isolate_profile_data": true, "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 106.0.5219.0", + "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 106.0.5220.0", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v106.0.5219.0", - "revision": "version:106.0.5219.0" + "location": "lacros_version_skew_tests_v106.0.5220.0", + "revision": "version:106.0.5220.0" } ], "dimension_sets": [ @@ -21208,7 +21208,7 @@ }, "test": "lacros_chrome_browsertests_run_in_series", "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests_run_in_series/", - "variant_id": "Lacros version skew testing ash 106.0.5219.0" + "variant_id": "Lacros version skew testing ash 106.0.5220.0" }, { "isolate_profile_data": true,
diff --git a/testing/buildbot/filters/android.emulator_12.content_browsertests.filter b/testing/buildbot/filters/android.emulator_12.content_browsertests.filter index abe0ab7..19302c2 100644 --- a/testing/buildbot/filters/android.emulator_12.content_browsertests.filter +++ b/testing/buildbot/filters/android.emulator_12.content_browsertests.filter
@@ -70,36 +70,3 @@ # crbug.com/1096612 -All/SitePerProcessBrowserTest.DetachedIframeUnloadHandlerABCB/* -# crbug.com/1304037 --File/MediaTest.VideoBearMp4/0 --File/MediaTest.VideoBearSilentMp4/0 --File/MediaTest.VideoTulipWebm/0 --Http/MediaTest.VideoBearMp4/0 --Http/MediaTest.VideoBearSilentMp4/0 --Http/MediaTest.VideoTulipWebm/0 --MediaSessionPictureInPictureContentBrowserTest.ActionAvailableAfterEndOfStreamAndSrcUpdate --MediaSourceTest.Playback_Video_MP4_Audio_WEBM --MediaTest.VideoBearRotated0 --MediaTest.VideoBearRotated180 --MediaTest.VideoBearRotated270 --MediaTest.VideoBearRotated90 --MSE_ClearKey/EncryptedMediaTest.Playback_Encryption_CBCS_Video_CENC_Audio/0 --MSE_ClearKey/EncryptedMediaTest.Playback_Encryption_CBCS/0 --MSE_ClearKey/EncryptedMediaTest.Playback_Encryption_CENC_Video_CBCS_Audio/0 --MSE_ClearKey/EncryptedMediaTest.Playback_Encryption_CENC/0 --MSE_ClearKey/EncryptedMediaTest.Playback_VideoOnly_MP4_AV1_10bit/0 --MSE_ClearKey/EncryptedMediaTest.Playback_VideoOnly_MP4_AV1/0 --MSE_ClearKey/EncryptedMediaTest.Playback_VideoOnly_WebM_AV1_10bit/0 --MSE_ClearKey/EncryptedMediaTest.Playback_VideoOnly_WebM_AV1/0 --MSE_ExternalClearKey/EncryptedMediaTest.Playback_Encryption_CBCS_Video_CENC_Audio/0 --MSE_ExternalClearKey/EncryptedMediaTest.Playback_Encryption_CBCS/0 --MSE_ExternalClearKey/EncryptedMediaTest.Playback_Encryption_CENC_Video_CBCS_Audio/0 --MSE_ExternalClearKey/EncryptedMediaTest.Playback_Encryption_CENC/0 --MSE_ExternalClearKey/EncryptedMediaTest.Playback_VideoOnly_MP4_AV1_10bit/0 --MSE_ExternalClearKey/EncryptedMediaTest.Playback_VideoOnly_MP4_AV1/0 --MSE_ExternalClearKey/EncryptedMediaTest.Playback_VideoOnly_WebM_AV1_10bit/0 --MSE_ExternalClearKey/EncryptedMediaTest.Playback_VideoOnly_WebM_AV1/0 --SRC_ClearKey/EncryptedMediaTest.Playback_VideoOnly_WebM_AV1_10bit/0 --SRC_ClearKey/EncryptedMediaTest.Playback_VideoOnly_WebM_AV1/0 --SRC_ExternalClearKey/EncryptedMediaTest.Playback_VideoOnly_WebM_AV1_10bit/0 --SRC_ExternalClearKey/EncryptedMediaTest.Playback_VideoOnly_WebM_AV1/0
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl index a1300111..236fd80 100644 --- a/testing/buildbot/test_suite_exceptions.pyl +++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -487,6 +487,12 @@ 'hard_timeout': 1800, }, }, + 'win10.20h2-blink-rel': { + 'swarming': { + 'shards': 6, + 'hard_timeout': 1200, + }, + }, 'win10.20h2-blink-rel-dummy': { 'swarming': { 'shards': 6, @@ -763,6 +769,12 @@ 'hard_timeout': 1800, }, }, + 'win10.20h2-blink-rel': { + 'swarming': { + 'shards': 9, + 'hard_timeout': 1200, + }, + }, 'win10.20h2-blink-rel-dummy': { 'swarming': { 'shards': 9,
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl index 0bb48d6..d4d493d5 100644 --- a/testing/buildbot/variants.pyl +++ b/testing/buildbot/variants.pyl
@@ -22,15 +22,15 @@ }, 'LACROS_VERSION_SKEW_CANARY': { 'args': [ - '--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5219.0/test_ash_chrome', + '--ash-chrome-path-override=../../lacros_version_skew_tests_v106.0.5220.0/test_ash_chrome', ], - 'identifier': 'Lacros version skew testing ash 106.0.5219.0', + 'identifier': 'Lacros version skew testing ash 106.0.5220.0', 'swarming': { 'cipd_packages': [ { 'cipd_package': 'chromium/testing/linux-ash-chromium/x86_64/ash.zip', - 'location': 'lacros_version_skew_tests_v106.0.5219.0', - 'revision': 'version:106.0.5219.0', + 'location': 'lacros_version_skew_tests_v106.0.5220.0', + 'revision': 'version:106.0.5220.0', }, ], },
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl index c64729a..24dc7f95 100644 --- a/testing/buildbot/waterfalls.pyl +++ b/testing/buildbot/waterfalls.pyl
@@ -3899,6 +3899,17 @@ 'gtest_tests': 'chromium_win_gtests', }, }, + 'win10.20h2-blink-rel': { + 'mixins': [ + 'win10', + ], + 'swarming': { + 'hard_timeout': 900, + }, + 'test_suites': { + 'isolated_scripts': 'chromium_webkit_isolated_scripts', + }, + }, 'win10.20h2-blink-rel-dummy': { 'mixins': [ 'win10',
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index f89e27a9..1f1af892 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -1930,6 +1930,42 @@ "enable_features": [ "BackForwardCacheMemoryControls" ] + }, + { + "name": "Enabled_1000", + "params": { + "memory_threshold_for_back_forward_cache_in_mb": "1000" + }, + "enable_features": [ + "BackForwardCacheMemoryControls" + ] + }, + { + "name": "Enabled_1300", + "params": { + "memory_threshold_for_back_forward_cache_in_mb": "1300" + }, + "enable_features": [ + "BackForwardCacheMemoryControls" + ] + }, + { + "name": "Enabled_1500", + "params": { + "memory_threshold_for_back_forward_cache_in_mb": "1500" + }, + "enable_features": [ + "BackForwardCacheMemoryControls" + ] + }, + { + "name": "Enabled_1700", + "params": { + "memory_threshold_for_back_forward_cache_in_mb": "1700" + }, + "enable_features": [ + "BackForwardCacheMemoryControls" + ] } ] } @@ -6792,6 +6828,7 @@ "android", "android_weblayer", "android_webview", + "linux", "windows" ], "experiments": [
diff --git a/third_party/blink/public/devtools_protocol/browser_protocol.pdl b/third_party/blink/public/devtools_protocol/browser_protocol.pdl index bdd2ca0b..38f9c63 100644 --- a/third_party/blink/public/devtools_protocol/browser_protocol.pdl +++ b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
@@ -708,6 +708,7 @@ InvalidRegisterTriggerHeader InvalidEligibleHeader TooManyConcurrentRequests + SourceAndTriggerHeaders # Details for issues around "Attribution Reporting API" usage. # Explainer: https://github.com/WICG/attribution-reporting-api
diff --git a/third_party/blink/public/mojom/push_messaging/push_messaging_status.mojom b/third_party/blink/public/mojom/push_messaging/push_messaging_status.mojom index 0a2c918..aaf8622 100644 --- a/third_party/blink/public/mojom/push_messaging/push_messaging_status.mojom +++ b/third_party/blink/public/mojom/push_messaging/push_messaging_status.mojom
@@ -43,6 +43,10 @@ // Notifications permission and FCM were revoked. NO_APP_LEVEL_PERMISSION_UNSUBSCRIBE = 10, + // The event could not be delivered because permission was auto-revoked as the + // origin may be disruptive. + PERMISSION_REVOKED_DISRUPTIVE = 11, + // NOTE: Do not renumber or delete these as that would confuse interpretation // of previously logged data. When making changes, also update the enum list // in tools/metrics/histograms/histograms.xml to keep it in sync. @@ -210,6 +214,10 @@ // period is over. NO_APP_LEVEL_PERMISSION = 14, + // Unregistering because permissions was auto-revoked as the origin may be + // disruptive. + PERMISSION_REVOKED_DISRUPTIVE = 15, + // NOTE: Do not renumber or delete these as that would confuse interpretation // of previously logged data. When making changes, also update the enum list // in tools/metrics/histograms/histograms.xml to keep it in sync.
diff --git a/third_party/blink/renderer/core/css/cascade_layer_map.cc b/third_party/blink/renderer/core/css/cascade_layer_map.cc index 74c8e16b..aa55feb 100644 --- a/third_party/blink/renderer/core/css/cascade_layer_map.cc +++ b/third_party/blink/renderer/core/css/cascade_layer_map.cc
@@ -7,10 +7,6 @@ #include "third_party/blink/renderer/core/css/rule_set.h" namespace blink { - -const unsigned CascadeLayerMap::kImplicitOuterLayerOrder = - std::numeric_limits<unsigned>::max(); - namespace { using CanonicalLayerMap =
diff --git a/third_party/blink/renderer/core/css/cascade_layer_map.h b/third_party/blink/renderer/core/css/cascade_layer_map.h index 62d3c1b8..4d41565 100644 --- a/third_party/blink/renderer/core/css/cascade_layer_map.h +++ b/third_party/blink/renderer/core/css/cascade_layer_map.h
@@ -17,7 +17,8 @@ // layers in each sheet to the sorted layer order number. class CORE_EXPORT CascadeLayerMap : public GarbageCollected<CascadeLayerMap> { public: - static const unsigned kImplicitOuterLayerOrder; + static constexpr unsigned kImplicitOuterLayerOrder = + std::numeric_limits<unsigned>::max(); explicit CascadeLayerMap(const ActiveStyleSheetVector&);
diff --git a/third_party/blink/renderer/core/css/element_rule_collector.cc b/third_party/blink/renderer/core/css/element_rule_collector.cc index 010db1e..3fcc632b 100644 --- a/third_party/blink/renderer/core/css/element_rule_collector.cc +++ b/third_party/blink/renderer/core/css/element_rule_collector.cc
@@ -337,9 +337,6 @@ int style_sheet_index, const SelectorChecker& checker, PartRequest* part_request) { - if (!rules || rules->IsEmpty()) - return; - SelectorChecker::StyleScopeFrame style_scope_frame(context_.GetElement()); SelectorChecker::SelectorCheckingContext context(&context_.GetElement()); @@ -354,14 +351,13 @@ rule_set->ContainerQueryIntervals()); Seeker<StyleScope> scope_seeker(rule_set->ScopeIntervals()); - unsigned rejected = 0; unsigned fast_rejected = 0; unsigned matched = 0; SelectorStatisticsCollector selector_statistics_collector; if (perf_trace_enabled) selector_statistics_collector.ReserveCapacity(rules->size()); - for (const auto& rule_data : *rules) { + for (const RuleData& rule_data : *rules) { if (perf_trace_enabled) { selector_statistics_collector.EndCollectionForCurrentRule(); selector_statistics_collector.BeginCollectionForRule(&rule_data); @@ -385,7 +381,6 @@ if (UNLIKELY(part_request && part_request->for_shadow_pseudo)) { if (!selector.IsAllowedAfterPart()) { DCHECK_EQ(selector.GetPseudoType(), CSSSelector::kPseudoPart); - rejected++; continue; } DCHECK_EQ(selector.Relation(), CSSSelector::kUAShadow); @@ -399,12 +394,10 @@ DCHECK(!context.is_inside_visited_link || inside_link_ != EInsideLink::kNotInsideLink); if (!checker.Match(context, result)) { - rejected++; continue; } if (pseudo_style_request_.pseudo_id != kPseudoIdNone && pseudo_style_request_.pseudo_id != result.dynamic_pseudo) { - rejected++; continue; } const ContainerQuery* container_query = @@ -424,7 +417,6 @@ result.dynamic_pseudo == kPseudoIdNone) { if (!EvaluateAndAddContainerQueries(*container_query, style_recalc_context_, result_)) { - rejected++; if (AffectsAnimations(rule_data)) result_.SetConditionallyAffectsAnimations(); continue; @@ -450,6 +442,7 @@ if (!style_engine.Stats()) return; + unsigned rejected = rules->size() - fast_rejected - matched; INCREMENT_STYLE_STATS_COUNTER(style_engine, rules_rejected, rejected); INCREMENT_STYLE_STATS_COUNTER(style_engine, rules_fast_rejected, fast_rejected); @@ -464,6 +457,13 @@ int style_sheet_index, const SelectorChecker& checker, PartRequest* part_request) { + // This is a very common case for many style sheets, and by putting it here + // instead of inside CollectMatchingRulesForListInternal(), we're usually + // inlined into the caller (which saves on stack setup and call overhead + // in that common case). + if (!rules || rules->IsEmpty()) + return; + // To reduce branching overhead for the common case, we use a template // parameter to eliminate branching in CollectMatchingRulesForListInternal // when tracing is not enabled. @@ -877,7 +877,8 @@ if (dynamic_pseudo == kPseudoIdHighlight) { DCHECK(result.custom_highlight_name); - style_->SetHasCustomHighlightName(result.custom_highlight_name); + style_->SetHasCustomHighlightName( + AtomicString(result.custom_highlight_name)); } } else if (dynamic_pseudo == kPseudoIdFirstLine && container_query) { style_->SetFirstLineDependsOnSizeContainerQueries(true);
diff --git a/third_party/blink/renderer/core/css/invalidation/style_invalidator.cc b/third_party/blink/renderer/core/css/invalidation/style_invalidator.cc index 0463c26..a493ff08 100644 --- a/third_party/blink/renderer/core/css/invalidation/style_invalidator.cc +++ b/third_party/blink/renderer/core/css/invalidation/style_invalidator.cc
@@ -183,7 +183,11 @@ ContainerNode& node, SiblingData& sibling_data) { auto pending_invalidations_iterator = pending_invalidation_map_.find(&node); - DCHECK(pending_invalidations_iterator != pending_invalidation_map_.end()); + if (pending_invalidations_iterator == pending_invalidation_map_.end()) { + NOTREACHED() << "We should strictly not have marked an element for " + "invalidation without any pending invalidations."; + return; + } NodeInvalidationSets& pending_invalidations = pending_invalidations_iterator->value;
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver_test.cc b/third_party/blink/renderer/core/css/resolver/style_resolver_test.cc index 994f7a1..c9743297 100644 --- a/third_party/blink/renderer/core/css/resolver/style_resolver_test.cc +++ b/third_party/blink/renderer/core/css/resolver/style_resolver_test.cc
@@ -1433,7 +1433,7 @@ ASSERT_EQ(properties.size(), 3u); const uint16_t kImplicitOuterLayerOrder = - CascadeLayerMap::kImplicitOuterLayerOrder; + ClampTo<uint16_t>(CascadeLayerMap::kImplicitOuterLayerOrder); // div { display: block; } EXPECT_TRUE(properties[0].properties->HasProperty(CSSPropertyID::kDisplay)); @@ -1480,7 +1480,7 @@ ASSERT_EQ(properties.size(), 4u); const uint16_t kImplicitOuterLayerOrder = - CascadeLayerMap::kImplicitOuterLayerOrder; + ClampTo<uint16_t>(CascadeLayerMap::kImplicitOuterLayerOrder); // div { display: block; } EXPECT_TRUE(properties[0].properties->HasProperty(CSSPropertyID::kDisplay)); @@ -1539,7 +1539,7 @@ ASSERT_EQ(properties.size(), 3u); const uint16_t kImplicitOuterLayerOrder = - CascadeLayerMap::kImplicitOuterLayerOrder; + ClampTo<uint16_t>(CascadeLayerMap::kImplicitOuterLayerOrder); // div { display: block } EXPECT_TRUE(properties[0].properties->HasProperty(CSSPropertyID::kDisplay)); @@ -1593,7 +1593,7 @@ ASSERT_EQ(properties.size(), 2u); const uint16_t kImplicitOuterLayerOrder = - CascadeLayerMap::kImplicitOuterLayerOrder; + ClampTo<uint16_t>(CascadeLayerMap::kImplicitOuterLayerOrder); // @layer { target { color: red } }" EXPECT_TRUE(properties[0].properties->HasProperty(CSSPropertyID::kColor));
diff --git a/third_party/blink/renderer/core/css/selector_checker.cc b/third_party/blink/renderer/core/css/selector_checker.cc index 1d08215..de18ddd 100644 --- a/third_party/blink/renderer/core/css/selector_checker.cc +++ b/third_party/blink/renderer/core/css/selector_checker.cc
@@ -1661,7 +1661,7 @@ // elements we have a single flag for tracking whether an element may // match _any_ ::highlight() element (kPseudoIdHighlight). if (!pseudo_argument_ || pseudo_argument_ == selector.Argument()) { - result.custom_highlight_name = selector.Argument(); + result.custom_highlight_name = selector.Argument().Impl(); return true; } return false;
diff --git a/third_party/blink/renderer/core/css/selector_checker.h b/third_party/blink/renderer/core/css/selector_checker.h index 99bd1be..0ceb4a8b 100644 --- a/third_party/blink/renderer/core/css/selector_checker.h +++ b/third_party/blink/renderer/core/css/selector_checker.h
@@ -191,7 +191,11 @@ public: PseudoId dynamic_pseudo{kPseudoIdNone}; - AtomicString custom_highlight_name; + + // Comes from an AtomicString, but not stored as one to avoid + // the cost of checking the refcount on cleaning up from every + // Match() call. Owned by the CSS selector it came from. + StringImpl* custom_highlight_name{nullptr}; // From the :has() argument selector checking, we need to get the element // that matches the leftmost compound selector to mark all possible :has()
diff --git a/third_party/blink/renderer/core/css/selector_filter.cc b/third_party/blink/renderer/core/css/selector_filter.cc index 67eb627..22f24d1 100644 --- a/third_party/blink/renderer/core/css/selector_filter.cc +++ b/third_party/blink/renderer/core/css/selector_filter.cc
@@ -120,7 +120,6 @@ } // namespace void SelectorFilter::PushParentStackFrame(Element& parent) { - DCHECK(ancestor_identifier_filter_); DCHECK(parent_stack_.IsEmpty() || parent_stack_.back().element == FlatTreeTraversal::ParentElement(parent)); @@ -132,22 +131,21 @@ CollectElementIdentifierHashes(parent, parent_frame.identifier_hashes); wtf_size_t count = parent_frame.identifier_hashes.size(); for (wtf_size_t i = 0; i < count; ++i) - ancestor_identifier_filter_->Add(parent_frame.identifier_hashes[i]); + ancestor_identifier_filter_.Add(parent_frame.identifier_hashes[i]); } void SelectorFilter::PopParentStackFrame() { DCHECK(!parent_stack_.IsEmpty()); - DCHECK(ancestor_identifier_filter_); const ParentStackFrame& parent_frame = parent_stack_.back(); wtf_size_t count = parent_frame.identifier_hashes.size(); for (wtf_size_t i = 0; i < count; ++i) - ancestor_identifier_filter_->Remove(parent_frame.identifier_hashes[i]); + ancestor_identifier_filter_.Remove(parent_frame.identifier_hashes[i]); parent_stack_.pop_back(); if (parent_stack_.IsEmpty()) { #if DCHECK_IS_ON() - DCHECK(ancestor_identifier_filter_->LikelyEmpty()); + DCHECK(ancestor_identifier_filter_.LikelyEmpty()); #endif - ancestor_identifier_filter_.reset(); + ancestor_identifier_filter_.Clear(); } } @@ -156,12 +154,12 @@ DCHECK(parent.InActiveDocument()); if (parent_stack_.IsEmpty()) { DCHECK_EQ(parent, parent.GetDocument().documentElement()); - DCHECK(!ancestor_identifier_filter_); - ancestor_identifier_filter_ = std::make_unique<IdentifierFilter>(); +#if DCHECK_IS_ON() + DCHECK(ancestor_identifier_filter_.IsClear()); +#endif PushParentStackFrame(parent); return; } - DCHECK(ancestor_identifier_filter_); // We may get invoked for some random elements in some wacky cases during // style resolve. Pause maintaining the stack in this case. if (parent_stack_.back().element != FlatTreeTraversal::ParentElement(parent))
diff --git a/third_party/blink/renderer/core/css/selector_filter.h b/third_party/blink/renderer/core/css/selector_filter.h index bc021ecc..4b03a0e 100644 --- a/third_party/blink/renderer/core/css/selector_filter.h +++ b/third_party/blink/renderer/core/css/selector_filter.h
@@ -31,8 +31,6 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_CSS_SELECTOR_FILTER_H_ #define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_SELECTOR_FILTER_H_ -#include <memory> - #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/dom/element.h" #include "third_party/blink/renderer/platform/wtf/bloom_filter.h" @@ -120,16 +118,15 @@ // With 100 unique strings in the filter, 2^12 slot table has false positive // rate of ~0.2%. using IdentifierFilter = CountingBloomFilter<12>; - std::unique_ptr<IdentifierFilter> ancestor_identifier_filter_; + IdentifierFilter ancestor_identifier_filter_; }; template <unsigned maximumIdentifierCount> inline bool SelectorFilter::FastRejectSelector( const unsigned* identifier_hashes) const { - DCHECK(ancestor_identifier_filter_); for (unsigned n = 0; n < maximumIdentifierCount && identifier_hashes[n]; ++n) { - if (!ancestor_identifier_filter_->MayContain(identifier_hashes[n])) + if (!ancestor_identifier_filter_.MayContain(identifier_hashes[n])) return true; } return false;
diff --git a/third_party/blink/renderer/core/frame/attribution_src_loader.cc b/third_party/blink/renderer/core/frame/attribution_src_loader.cc index 46c9d83..cf79775 100644 --- a/third_party/blink/renderer/core/frame/attribution_src_loader.cc +++ b/third_party/blink/renderer/core/frame/attribution_src_loader.cc
@@ -170,6 +170,8 @@ void HandleResponseHeaders(const ResourceResponse& response, uint64_t request_id); + void Finish(); + private: [[nodiscard]] bool CheckReportingOrigin( const SecurityOrigin& reporting_origin, @@ -447,6 +449,7 @@ auto* client = MakeGarbageCollected<ResourceClient>( this, src_type, /*associated_with_navigation=*/false); client->HandleResponseHeaders(response, resource->InspectorId()); + client->Finish(); return true; } @@ -480,6 +483,13 @@ RecordAttributionSrcRequestStatus(AttributionSrcRequestStatus::kReceived); } + Finish(); +} + +void AttributionSrcLoader::ResourceClient::Finish() { + DCHECK(data_host_.is_bound()); + DCHECK(keep_alive_); + // Eagerly reset the data host so that the receiver is closed and any buffered // triggers are flushed as soon as possible. See crbug.com/1336797 for // details. @@ -495,30 +505,50 @@ SecurityOrigin::Create(response.CurrentRequestUrl()); const auto& headers = response.HttpHeaderFields(); + const AtomicString& source_json = + headers.Get(http_names::kAttributionReportingRegisterSource); + const AtomicString& trigger_json = + headers.Get(http_names::kAttributionReportingRegisterTrigger); // TODO(apaseltiner): Report a DevTools issue when `type_` and `headers` do // not correspond correctly. - // TODO(johnidel): Consider surfacing an error when source and trigger headers - // are present together. + switch (type_) { + case SrcType::kSource: + if (!source_json.IsNull()) { + HandleSourceRegistration(source_json, std::move(reporting_origin), + request_id); + } + break; + case SrcType::kTrigger: + if (!trigger_json.IsNull()) { + HandleTriggerRegistration(trigger_json, std::move(reporting_origin), + request_id); + } + break; + case SrcType::kUndetermined: + if (!source_json.IsNull() && !trigger_json.IsNull()) { + LogAuditIssue(loader_->local_frame_->DomWindow(), + AttributionReportingIssueType::kSourceAndTriggerHeaders, + /*element=*/nullptr, request_id, + /*invalid_parameter=*/String()); + return; + } - if (type_ == SrcType::kUndetermined || type_ == SrcType::kSource) { - const AtomicString& json = - headers.Get(http_names::kAttributionReportingRegisterSource); - if (!json.IsNull()) { - type_ = SrcType::kSource; - HandleSourceRegistration(json, std::move(reporting_origin), request_id); - return; - } - } + if (!source_json.IsNull()) { + type_ = SrcType::kSource; + HandleSourceRegistration(source_json, std::move(reporting_origin), + request_id); + return; + } - if (type_ == SrcType::kUndetermined || type_ == SrcType::kTrigger) { - const AtomicString& json = - headers.Get(http_names::kAttributionReportingRegisterTrigger); - if (!json.IsNull()) { - type_ = SrcType::kTrigger; - HandleTriggerRegistration(json, std::move(reporting_origin), request_id); - } + if (!trigger_json.IsNull()) { + type_ = SrcType::kTrigger; + HandleTriggerRegistration(trigger_json, std::move(reporting_origin), + request_id); + } + + break; } }
diff --git a/third_party/blink/renderer/core/html/html_frame_set_element.cc b/third_party/blink/renderer/core/html/html_frame_set_element.cc index e91d93c..b60c264c 100644 --- a/third_party/blink/renderer/core/html/html_frame_set_element.cc +++ b/third_party/blink/renderer/core/html/html_frame_set_element.cc
@@ -230,6 +230,12 @@ } } +int HTMLFrameSetElement::Border(const ComputedStyle& style) const { + if (!HasFrameBorder() || border_ == 0) + return 0; + return std::max(ClampTo<int>(border_ * style.EffectiveZoom()), 1); +} + FrameEdgeInfo HTMLFrameSetElement::EdgeInfo() const { FrameEdgeInfo result(NoResize(), true); @@ -321,7 +327,7 @@ frameborder_ = frameset->HasFrameBorder(); if (frameborder_) { if (!border_set_) - border_ = frameset->Border(); + border_ = frameset->HasFrameBorder() ? frameset->border_ : 0; if (!border_color_set_) border_color_set_ = frameset->HasBorderColor(); } @@ -425,14 +431,23 @@ return; if (!resize_axis.IsResizingSplit()) return; - int current_split_position = - SplitPosition(axis, resize_axis.split_being_resized_); + const int split_index = resize_axis.split_being_resized_; + int current_split_position = SplitPosition(axis, split_index); int delta = (position - current_split_position) - resize_axis.split_resize_offset_; if (!delta) return; - resize_axis.deltas_[resize_axis.split_being_resized_ - 1] += delta; - resize_axis.deltas_[resize_axis.split_being_resized_] -= delta; + const int original_size_prev = + axis.sizes_[split_index - 1] - resize_axis.deltas_[split_index - 1]; + const int original_size_next = + axis.sizes_[split_index] - resize_axis.deltas_[split_index]; + if ((original_size_prev != 0 && axis.sizes_[split_index - 1] + delta <= 0) || + (original_size_next != 0 && axis.sizes_[split_index] - delta <= 0)) { + resize_axis.deltas_.Fill(0); + } else { + resize_axis.deltas_[split_index - 1] += delta; + resize_axis.deltas_[split_index] -= delta; + } GetLayoutObject()->SetNeedsLayoutAndFullPaintInvalidation( layout_invalidation_reason::kSizeChanged); } @@ -442,7 +457,7 @@ if (GetLayoutObject()->NeedsLayout()) return 0; - int border_thickness = Border(); + int border_thickness = Border(GetLayoutObject()->StyleRef()); int size = axis.sizes_.size(); if (!size) @@ -469,7 +484,7 @@ if (GetLayoutObject()->NeedsLayout()) return ResizeAxis::kNoSplit; - int border_thickness = Border(); + int border_thickness = Border(GetLayoutObject()->StyleRef()); if (border_thickness <= 0) return ResizeAxis::kNoSplit;
diff --git a/third_party/blink/renderer/core/html/html_frame_set_element.h b/third_party/blink/renderer/core/html/html_frame_set_element.h index 39a78a0..7286573 100644 --- a/third_party/blink/renderer/core/html/html_frame_set_element.h +++ b/third_party/blink/renderer/core/html/html_frame_set_element.h
@@ -53,7 +53,7 @@ wtf_size_t TotalCols() const { return std::max<wtf_size_t>(1, col_lengths_.size()); } - int Border() const { return HasFrameBorder() ? border_ : 0; } + int Border(const ComputedStyle& style) const; FrameEdgeInfo EdgeInfo() const; void CollectEdgeInfo();
diff --git a/third_party/blink/renderer/core/inspector/inspector_audits_issue.cc b/third_party/blink/renderer/core/inspector/inspector_audits_issue.cc index 2ea276e7..5cb5fa8 100644 --- a/third_party/blink/renderer/core/inspector/inspector_audits_issue.cc +++ b/third_party/blink/renderer/core/inspector/inspector_audits_issue.cc
@@ -160,6 +160,9 @@ case AttributionReportingIssueType::kTooManyConcurrentRequests: return protocol::Audits::AttributionReportingIssueTypeEnum:: TooManyConcurrentRequests; + case AttributionReportingIssueType::kSourceAndTriggerHeaders: + return protocol::Audits::AttributionReportingIssueTypeEnum:: + SourceAndTriggerHeaders; } }
diff --git a/third_party/blink/renderer/core/inspector/inspector_audits_issue.h b/third_party/blink/renderer/core/inspector/inspector_audits_issue.h index 9e4b9eaf..961c6d52 100644 --- a/third_party/blink/renderer/core/inspector/inspector_audits_issue.h +++ b/third_party/blink/renderer/core/inspector/inspector_audits_issue.h
@@ -111,6 +111,7 @@ kInvalidRegisterTriggerHeader, kInvalidEligibleHeader, kTooManyConcurrentRequests, + kSourceAndTriggerHeaders, }; enum class SharedArrayBufferIssueType {
diff --git a/third_party/blink/renderer/core/layout/layout_frame_set.cc b/third_party/blink/renderer/core/layout/layout_frame_set.cc index 925225ab..757f1421 100644 --- a/third_party/blink/renderer/core/layout/layout_frame_set.cc +++ b/third_party/blink/renderer/core/layout/layout_frame_set.cc
@@ -316,7 +316,7 @@ cols_.Resize(cols); } - LayoutUnit border_thickness(FrameSet()->Border()); + LayoutUnit border_thickness(FrameSet()->Border(StyleRef())); LayOutAxis(rows_, FrameSet()->RowLengths(), rows_deltas, (Size().Height() - (rows - 1) * border_thickness).ToInt()); LayOutAxis(cols_, FrameSet()->ColLengths(), cols_deltas, @@ -353,7 +353,7 @@ int rows = FrameSet()->TotalRows(); int cols = FrameSet()->TotalCols(); - int border_thickness = FrameSet()->Border(); + int border_thickness = FrameSet()->Border(StyleRef()); LayoutSize size; LayoutPoint position; for (int r = 0; r < rows; r++) {
diff --git a/third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker.cc b/third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker.cc index ddad2c1..c13faa5 100644 --- a/third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker.cc +++ b/third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker.cc
@@ -29,6 +29,8 @@ #include "third_party/blink/renderer/core/page/chrome_client.h" #include "third_party/blink/renderer/core/page/page.h" #include "third_party/blink/renderer/core/page/viewport_description.h" +#include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h" +#include "third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.h" #include "third_party/blink/renderer/platform/heap/visitor.h" #include "third_party/blink/renderer/platform/wtf/math_extras.h" #include "ui/display/screen_info.h" @@ -78,6 +80,15 @@ .MaximumScrollOffsetAtScale(initial_scale_) .x() == 0; is_painting_ = true; + viewport_transform_ = &frame_view_->GetLayoutView() + ->FirstFragment() + .ContentsProperties() + .Transform(); + previous_transform_ = viewport_transform_; + current_x_offset_ = 0.0; + + int frame_width = frame_view_->GetPage()->GetVisualViewport().Size().width(); + viewport_width_ = frame_width * viewport_scalar_ / initial_scale_; if (timer_.IsActive() || base::TimeTicks::Now() - last_evaluated_ < kEvaluationInterval) { @@ -578,44 +589,51 @@ } void MobileFriendlinessChecker::UpdateBeyondViewportAreaSizes( - const PhysicalRect& paint_rect) { + const PhysicalRect& paint_rect, + const TransformPaintPropertyNodeOrAlias& current_transform) { DCHECK(is_painting_); if (ignore_beyond_viewport_scope_count_ != 0) return; - int frame_width = frame_view_->GetPage()->GetVisualViewport().Size().width(); + if (previous_transform_ != ¤t_transform) { + auto projection = GeometryMapper::SourceToDestinationProjection( + current_transform, *viewport_transform_); + if (projection.IsIdentityOr2DTranslation()) { + current_x_offset_ = projection.Translation2D().x(); + previous_transform_ = ¤t_transform; + } else { + // For now we ignore offsets caused by non-2d-translation transforms. + current_x_offset_ = 0; + } + } - // TODO(kumagi): Map paint_rect from the local transform space to the viewport - // space. - PhysicalRect viewport_rect( - LayoutUnit(), LayoutUnit(), - LayoutUnit(frame_width * viewport_scalar_ / initial_scale_), - LayoutUnit(kIntMaxForLayoutUnit)); - int original_size = - ClampTo<int>((paint_rect.Width() * paint_rect.Height()).ToInt()); - viewport_rect.Intersect(paint_rect); + float right = paint_rect.Right() + current_x_offset_; + float width = paint_rect.Width(); + float width_beyond_viewport = + std::min(std::max(right - viewport_width_, 0.f), width); area_sizes_.content_beyond_viewport_area += - original_size - - ClampTo<int>((viewport_rect.Width() * viewport_rect.Height()).ToInt()); + width_beyond_viewport * paint_rect.Height(); } void MobileFriendlinessChecker::NotifyPaintTextFragment( const PhysicalRect& paint_rect, - int font_size) { + int font_size, + const TransformPaintPropertyNodeOrAlias& current_transform) { DCHECK(frame_view_->GetFrame().Client()->IsLocalFrameClientImpl()); DCHECK(frame_view_->GetFrame().IsOutermostMainFrame()); UpdateTextAreaSizes(paint_rect, font_size); - UpdateBeyondViewportAreaSizes(paint_rect); + UpdateBeyondViewportAreaSizes(paint_rect, current_transform); } void MobileFriendlinessChecker::NotifyPaintReplaced( - const PhysicalRect& paint_rect) { + const PhysicalRect& paint_rect, + const TransformPaintPropertyNodeOrAlias& current_transform) { DCHECK(frame_view_->GetFrame().Client()->IsLocalFrameClientImpl()); DCHECK(frame_view_->GetFrame().IsLocalRoot()); - UpdateBeyondViewportAreaSizes(paint_rect); + UpdateBeyondViewportAreaSizes(paint_rect, current_transform); } void MobileFriendlinessChecker::Trace(Visitor* visitor) const {
diff --git a/third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker.h b/third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker.h index 933fa67..ab8b1de 100644 --- a/third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker.h +++ b/third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker.h
@@ -18,6 +18,7 @@ class Document; class LocalFrameView; +class TransformPaintPropertyNodeOrAlias; struct ViewportDescription; // Calculates the mobile usability of current page, especially friendliness on @@ -39,8 +40,13 @@ void NotifyPaintEnd(); void WillBeRemovedFromFrame(); void NotifyViewportUpdated(const ViewportDescription&); - void NotifyPaintTextFragment(const PhysicalRect& paint_rect, int font_size); - void NotifyPaintReplaced(const PhysicalRect& paint_rect); + void NotifyPaintTextFragment( + const PhysicalRect& paint_rect, + int font_size, + const TransformPaintPropertyNodeOrAlias& current_transform); + void NotifyPaintReplaced( + const PhysicalRect& paint_rect, + const TransformPaintPropertyNodeOrAlias& current_transform); void Trace(Visitor* visitor) const override; @@ -87,10 +93,16 @@ int ComputeBadTapTargetsRatio(); void UpdateTextAreaSizes(const PhysicalRect& text_rect, int font_size); - void UpdateBeyondViewportAreaSizes(const PhysicalRect& paint_rect); + void UpdateBeyondViewportAreaSizes( + const PhysicalRect& paint_rect, + const TransformPaintPropertyNodeOrAlias& current_transform); private: Member<LocalFrameView> frame_view_; + const TransformPaintPropertyNodeOrAlias* viewport_transform_ = nullptr; + const TransformPaintPropertyNodeOrAlias* previous_transform_ = nullptr; + float current_x_offset_ = 0.0; + float viewport_width_ = 0.0; HeapTaskRunnerTimer<MobileFriendlinessChecker> timer_; double viewport_scalar_; double initial_scale_ = 1.0;
diff --git a/third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker_test.cc b/third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker_test.cc index dd88736..66d52d9d 100644 --- a/third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker_test.cc +++ b/third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker_test.cc
@@ -541,7 +541,7 @@ <meta name="viewport" content="width=device-width"> </head> <body> - <img style="width:3000px; height:50px"> + <img style="width:5000px; height:50px"> <p style="font-size: 12pt">Normal font text.</p> </body> </html> @@ -955,23 +955,23 @@ padding: 14px; } </style> - <meta name="viewport" content="width=480px, initial-scale=1.0 minimum-scale=1.0">f + <meta name="viewport" content="width=480px, initial-scale=1.0 minimum-scale=1.0"> </head> - <body style="font: 40px/1 Ahem; line-height: 1"> - <div class="scrollmenu"> - <a href="#1">First text</a> - <a href="#2">Second text</a> - <a href="#3">Third text</a> - <a href="#4">Fourth text</a> - <a href="#5">Fifth text</a> - <a href="#6">Sixth text</a> - <a href="#7">Seventh text</a> - <a href="#8">Eighth text</a> - <a href="#9">Ninth text</a> - <a href="#10">Tenth text</a> - <a href="#11">Eleventh text</a> - <a href="#12">Twelveth text</a> - </div> + <body style="font: 40px/1 Ahem; line-height: 1; height: 200px"> + <div class="scrollmenu"> + <a href="#1">First text</a> + <a href="#2">Second text</a> + <a href="#3">Third text</a> + <a href="#4">Fourth text</a> + <a href="#5">Fifth text</a> + <a href="#6">Sixth text</a> + <a href="#7">Seventh text</a> + <a href="#8">Eighth text</a> + <a href="#9">Ninth text</a> + <a href="#10">Tenth text</a> + <a href="#11">Eleventh text</a> + <a href="#12">Twelveth text</a> + </div> </body> </html> )"); @@ -1024,6 +1024,277 @@ EXPECT_EQ(actual_mf.text_content_outside_viewport_percentage, 0); } +TEST_F(MobileFriendlinessCheckerTest, SubScrollerHalfOutByMargin) { + MobileFriendliness actual_mf = CalculateMetricsForHTMLString(R"( +<html> + <head> + <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> + <style> + body { + margin: 0px; + } + div.scrollmenu { + margin-left: 240px; + width: 480px; + height: 800px; + background-color: #333; + overflow: scroll; + white-space: nowrap; + } + div.scrollmenu a { + display: inline-block; + color: white; + padding: 14px; + } + </style> + <meta name="viewport" content="width=480px, initial-scale=1.0 minimum-scale=1.0"> + </head> + <body style="font: 40px/1 Ahem; line-height: 1"> + <div class="scrollmenu"> + <a href="#1">First text</a> + <a href="#2">Second text</a> + <a href="#3">Third text</a> + <a href="#4">Fourth text</a> + <a href="#5">Fifth text</a> + <a href="#6">Sixth text</a> + <a href="#7">Seventh text</a> + <a href="#8">Eighth text</a> + <a href="#9">Ninth text</a> + <a href="#10">Tenth text</a> + <a href="#11">Eleventh text</a> + <a href="#12">Twelveth text</a> + </div> + </body> +</html> +)"); + // Fits within the viewport by scrollbar. + EXPECT_EQ(actual_mf.text_content_outside_viewport_percentage, 50); +} + +TEST_F(MobileFriendlinessCheckerTest, SubScrollerOutByTranslate) { + MobileFriendliness actual_mf = CalculateMetricsForHTMLString(R"( +<html> + <head> + <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> + <style> + body { + margin: 0px; + } + div.scrollmenu { + transform: translate(360px, 0px); + width: 480px; + height: 800px; + background-color: #333; + overflow: scroll; + white-space: nowrap; + } + div.scrollmenu a { + display: inline-block; + color: white; + padding: 14px; + } + </style> + <meta name="viewport" content="width=480px, initial-scale=1.0 minimum-scale=1.0"> + </head> + <body style="font: 40px/1 Ahem; line-height: 1"> + <div class="scrollmenu"> + <a href="#1">First text</a> + <a href="#2">Second text</a> + <a href="#3">Third text</a> + <a href="#4">Fourth text</a> + <a href="#5">Fifth text</a> + <a href="#6">Sixth text</a> + <a href="#7">Seventh text</a> + <a href="#8">Eighth text</a> + <a href="#9">Ninth text</a> + <a href="#10">Tenth text</a> + <a href="#11">Eleventh text</a> + <a href="#12">Twelveth text</a> + </div> + </body> +</html> +)"); + // Fits within the viewport by scrollbar. + EXPECT_EQ(actual_mf.text_content_outside_viewport_percentage, 75); +} + +/* + * TODO(kumagi): Get precise paint offset of rtl environment is hard. +TEST_F(MobileFriendlinessCheckerTest, SubScrollerGoesLeft) { + MobileFriendliness actual_mf = CalculateMetricsForHTMLString(R"( +<html> + <head> + <style> + body { + margin: 0px; + direction: rtl; + } + div.scroller { + margin-right: 360px; + width: 480px; + height: 800px; + overflow: scroll; + } + </style> + <meta name="viewport" content="width=480px, initial-scale=1.0 +minimum-scale=1.0"> + </head> + <body style="font: 40px/1 Ahem; line-height: 1"> + <div class="scroller"> + <img style="width: 9000px; height: 1px"> + </div> + </body> +</html> +)"); + // Right to left language scrollbar goes to left. + EXPECT_EQ(actual_mf.text_content_outside_viewport_percentage, 75); +} +*/ + +TEST_F(MobileFriendlinessCheckerTest, SubScrollerFitsWithinViewport) { + MobileFriendliness actual_mf = CalculateMetricsForHTMLString(R"( +<html> + <head> + <style> + body { + margin: 0px; + } + div.scroller1 { + width: 481px; + height: 1px; + overflow: scroll; + } + div.scroller2 { + width: 10px; + height: 800px; + overflow: scroll; + } + </style> + <meta name="viewport" content="width=480px, initial-scale=1.0 minimum-scale=1.0"> + </head> + <body style="font: 40px/1 Ahem; line-height: 1"> + <div class="scroller1"> + <img style="width: 9000px; height: 1px"> + This div goes out of viewport width 1px. + </div> + <div class="scroller2"> + <img style="width: 9000px; height: 1px"> + This div fits within viewport width. + </div> + </body> +</html> +)"); + // Only scroller1 gets out of viewport width. + EXPECT_EQ(actual_mf.text_content_outside_viewport_percentage, 1); +} + +TEST_F(MobileFriendlinessCheckerTest, SubScrollerTwice) { + MobileFriendliness actual_mf = CalculateMetricsForHTMLString(R"( +<html> + <head> + <style> + body { + margin: 0px; + } + div.scroller { + margin-left: 240px; + width: 480px; + height: 400px; + overflow: scroll; + } + </style> + <meta name="viewport" content="width=480px, initial-scale=1.0 minimum-scale=1.0"> + </head> + <body style="font: 40px/1 Ahem; line-height: 1"> + <div class="scroller"> + <img style="width: 9000px; height: 1px"> + hello this is a pen. + </div> + <div class="scroller"> + <img style="width: 9000px; height: 1px"> + </div> + </body> +</html> +)"); + // Both of subscrollers get out of viewport width. + EXPECT_EQ(actual_mf.text_content_outside_viewport_percentage, 50); +} + +TEST_F(MobileFriendlinessCheckerTest, SubScrollerInSubScroller) { + MobileFriendliness actual_mf = CalculateMetricsForHTMLString(R"( +<html> + <head> + <style> + body { + margin: 0px; + } + div.scroller { + width: 480px; + height: 200px; + overflow: scroll; + } + </style> + <meta name="viewport" content="width=480px, initial-scale=1.0 minimum-scale=1.0"> + </head> + <body style="font: 20px/1; line-height: 1"> + <div class="scroller" style="margin-left: 240px;"> + 240px*200px gets out of viewport. + <img style="width: 9000px; height: 1px"> + </div> + <div class="scroller" style="margin-left: 480px;"> + 480px*200px gets out of viewport. + <img style="width: 9000px; height: 1px"> + </div> + <div class="scroller" style="margin-left: 240px;"> + 240px*200px gets out of viewport. + <img style="width: 9000px; height: 1px"> + <div class="scroller"> + Contents inside of scroller will be ignored from the + text_content_outside_viewport_percentage metrics. + <img style="width: 9000px; height: 1px"> + </div> + </div> + <div class="scroller" style="margin-left: 480px;"> + 480px*200px gets out of viewport. + Hereby (240px*2)*400px + (480px*2)*400px gets out of viewport(480px*800px), + This is exactly 0.75. Then text_content_outside_viewport_percentage should be 75. + <img style="width: 9000px; height: 1px"> + <div class="scroller"> + <img style="width: 9000px; height: 1px"> + <div class="scroller"> + <img style="width: 9000px; height: 1px"> + </div> + </div> + </div> + </body> +</html> +)"); + // Fits within the viewport by scrollbar. + EXPECT_EQ(actual_mf.text_content_outside_viewport_percentage, 75); +} + +TEST_F(MobileFriendlinessCheckerTest, ScrollableLayoutView) { + MobileFriendliness actual_mf = CalculateMetricsForHTMLString(R"( +<html> + <head> + <style> + body { + margin: 0px; + width: 960px; + height: 800px; + } + </style> + <meta name="viewport" content="width=480px, initial-scale=1.0 minimum-scale=1.0"> + </head> + <body style="font: 20px/1; line-height: 1"> + <img style="width: 600px; height: 800px"> + </body> +</html> +)"); + // Fits within the viewport by scrollbar. + EXPECT_EQ(actual_mf.text_content_outside_viewport_percentage, 25); +} + TEST_F(MobileFriendlinessCheckerTest, SingleTapTarget) { MobileFriendliness actual_mf = CalculateMetricsForHTMLString(R"( <html>
diff --git a/third_party/blink/renderer/core/paint/frame_set_painter.cc b/third_party/blink/renderer/core/paint/frame_set_painter.cc index e753683..b800d87f 100644 --- a/third_party/blink/renderer/core/paint/frame_set_painter.cc +++ b/third_party/blink/renderer/core/paint/frame_set_painter.cc
@@ -109,7 +109,8 @@ BoxDrawingRecorder recorder(paint_info.context, layout_frame_set_, paint_info.phase, paint_offset); - LayoutUnit border_thickness(layout_frame_set_.FrameSet()->Border()); + LayoutUnit border_thickness( + layout_frame_set_.FrameSet()->Border(layout_frame_set_.StyleRef())); if (!border_thickness) return;
diff --git a/third_party/blink/renderer/core/paint/inline_text_box_painter.cc b/third_party/blink/renderer/core/paint/inline_text_box_painter.cc index b1086ee..e5d2373 100644 --- a/third_party/blink/renderer/core/paint/inline_text_box_painter.cc +++ b/third_party/blink/renderer/core/paint/inline_text_box_painter.cc
@@ -167,8 +167,11 @@ if (const auto* text = DynamicTo<LayoutText>(InlineLayoutObject())) { PhysicalRect clipped_rect = PhysicalRect(visual_rect); clipped_rect.Intersect(PhysicalRect(paint_info.GetCullRect().Rect())); - mf_checker->NotifyPaintTextFragment(clipped_rect, - text->StyleRef().FontSize()); + mf_checker->NotifyPaintTextFragment( + clipped_rect, text->StyleRef().FontSize(), + paint_info.context.GetPaintController() + .CurrentPaintChunkProperties() + .Transform()); } } }
diff --git a/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc index 1c179c60..481bbf0 100644 --- a/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc +++ b/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc
@@ -341,8 +341,11 @@ if (auto* text = DynamicTo<LayoutText>(*layout_object)) { PhysicalRect clipped_rect = PhysicalRect(visual_rect); clipped_rect.Intersect(PhysicalRect(paint_info.GetCullRect().Rect())); - mf_checker->NotifyPaintTextFragment(clipped_rect, - text->StyleRef().FontSize()); + mf_checker->NotifyPaintTextFragment( + clipped_rect, text->StyleRef().FontSize(), + paint_info.context.GetPaintController() + .CurrentPaintChunkProperties() + .Transform()); } } }
diff --git a/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc b/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc index 824dcc1..1a0a7dc3 100644 --- a/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc +++ b/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc
@@ -449,9 +449,8 @@ // context. If we're not participating in block fragmentation, the containing // fragment of an OOF fragment is always simply the parent. const LayoutBox* box = DynamicTo<LayoutBox>(&object); - // TODO(crbug.com/1343746): Review the revert of the following lines. - if (context.current_container.fragment && box && - box->GetNGPaginationBreakability() == LayoutBox::kForbidBreaks) { + if (!context.current_container.IsInFragmentationContext() || + (box && box->GetNGPaginationBreakability() == LayoutBox::kForbidBreaks)) { context.current_container.fragment = fragment; } @@ -922,20 +921,27 @@ } if (box_fragment) { - NGPrePaintInfo pre_paint_info( - *box_fragment, paint_offset, fragmentainer_idx, is_first_for_node, - is_last_for_node, is_inside_fragment_child, - context.current_container.IsInFragmentationContext()); + const ContainingFragment* container_for_child = + &context.current_container; + bool is_in_different_fragmentation_context = false; if (oof_containing_fragment_info && context.current_container.fragmentation_nesting_level != oof_containing_fragment_info->fragmentation_nesting_level) { // We're walking an out-of-flow positioned descendant that isn't in the - // same fragmentation context as parent_object. Update the context, so - // that we create FragmentData objects correctly both for the descendant - // and all its descendants. + // same fragmentation context as parent_object. We need to update the + // context, so that we create FragmentData objects correctly both for + // the descendant and all its descendants. + container_for_child = oof_containing_fragment_info; + is_in_different_fragmentation_context = true; + } + NGPrePaintInfo pre_paint_info( + *box_fragment, paint_offset, fragmentainer_idx, is_first_for_node, + is_last_for_node, is_inside_fragment_child, + container_for_child->IsInFragmentationContext()); + if (is_in_different_fragmentation_context) { PrePaintTreeWalkContext oof_context( context, NeedsTreeBuilderContextUpdate(*child, context)); - oof_context.current_container = *oof_containing_fragment_info; + oof_context.current_container = *container_for_child; Walk(*child, oof_context, &pre_paint_info); } else { Walk(*child, context, &pre_paint_info);
diff --git a/third_party/blink/renderer/core/paint/replaced_painter.cc b/third_party/blink/renderer/core/paint/replaced_painter.cc index 33c0e0f..c5875a5d 100644 --- a/third_party/blink/renderer/core/paint/replaced_painter.cc +++ b/third_party/blink/renderer/core/paint/replaced_painter.cc
@@ -82,8 +82,11 @@ PhysicalRect content_rect = replaced.ReplacedContentRect(); content_rect.Move(paint_offset_); content_rect.Intersect(PhysicalRect(GetPaintInfo().GetCullRect().Rect())); - mf_checker->NotifyPaintReplaced(content_rect); - + mf_checker->NotifyPaintReplaced(content_rect, + GetPaintInfo() + .context.GetPaintController() + .CurrentPaintChunkProperties() + .Transform()); mf_ignore_scope_.emplace(*mf_checker); } }
diff --git a/third_party/blink/renderer/core/paint/scoped_paint_state.cc b/third_party/blink/renderer/core/paint/scoped_paint_state.cc index 8d151d8a..c68445c 100644 --- a/third_party/blink/renderer/core/paint/scoped_paint_state.cc +++ b/third_party/blink/renderer/core/paint/scoped_paint_state.cc
@@ -144,16 +144,28 @@ if (input_paint_info_.phase == PaintPhase::kForeground) { // We treat horizontal-scrollable scrollers like replaced objects. - if (auto* scrollable_area = box.GetScrollableArea()) { - if (scrollable_area->HasHorizontalScrollbar()) { - if (auto* mf_checker = - MobileFriendlinessChecker::From(box.GetDocument())) { - PhysicalRect content_rect = box.LocalVisualRect(); - content_rect.Move(paint_offset_); - content_rect.Intersect( - PhysicalRect(input_paint_info_.GetCullRect().Rect())); - mf_checker->NotifyPaintReplaced(content_rect); - mf_ignore_scope_.emplace(*mf_checker); + if (auto* mf_checker = MobileFriendlinessChecker::From(box.GetDocument())) { + if (!box.IsLayoutView()) { + if (auto* scrollable_area = box.GetScrollableArea()) { + if (scrollable_area->MaximumScrollOffset().x() != 0) { + PhysicalRect content_rect = box.LocalVisualRect(); + content_rect.Move(paint_offset_); + content_rect.Intersect( + PhysicalRect(input_paint_info_.GetCullRect().Rect())); + mf_checker->NotifyPaintReplaced( + content_rect, input_paint_info_.context.GetPaintController() + .CurrentPaintChunkProperties() + .Transform()); + mf_ignore_scope_.emplace(*mf_checker); + } + } + // Don't check mobile friendliness for beyond viewport in position:fixed + // boxes because they don't scroll in the viewport. + if (const auto* properties = fragment_to_paint_->PaintProperties()) { + if (const auto* translation = properties->PaintOffsetTranslation()) { + if (translation->ScrollTranslationForFixed()) + mf_ignore_scope_.emplace(*mf_checker); + } } } }
diff --git a/third_party/blink/renderer/modules/mediastream/transferred_media_stream_track.cc b/third_party/blink/renderer/modules/mediastream/transferred_media_stream_track.cc index f8d9fd7f..86953f0 100644 --- a/third_party/blink/renderer/modules/mediastream/transferred_media_stream_track.cc +++ b/third_party/blink/renderer/modules/mediastream/transferred_media_stream_track.cc
@@ -88,9 +88,10 @@ void TransferredMediaStreamTrack::setEnabled(bool enabled) { if (track_) { track_->setEnabled(enabled); + return; } - // TODO(https://crbug.com/1288839): Save and forward to track_ once it's - // initialized. + setter_call_order_.push_back(SET_ENABLED); + enabled_state_list_.push_back(enabled); } bool TransferredMediaStreamTrack::muted() const { @@ -110,9 +111,10 @@ void TransferredMediaStreamTrack::SetContentHint(const String& content_hint) { if (track_) { track_->SetContentHint(content_hint); + return; } - // TODO(https://crbug.com/1288839): Save and forward to track_ once it's - // initialized. + setter_call_order_.push_back(SET_CONTENT_HINT); + content_hint_list_.push_back(content_hint); } String TransferredMediaStreamTrack::readyState() const { @@ -188,6 +190,7 @@ void TransferredMediaStreamTrack::applyConstraints( ScriptPromiseResolver* resolver, const MediaTrackConstraints* constraints) { + setter_call_order_.push_back(APPLY_CONSTRAINTS); constraints_list_.push_back(std::make_pair(resolver, constraints)); } @@ -196,10 +199,26 @@ transferred_component_.Clear(); // Replaying mutations which happened before this point. - for (auto it : constraints_list_) { - track->applyConstraints(it.first, it.second); + for (const auto& setter_function : setter_call_order_) { + switch (setter_function) { + case APPLY_CONSTRAINTS: { + const auto& entry = constraints_list_.front(); + track->applyConstraints(entry.first, entry.second); + constraints_list_.pop_front(); + break; + } + case SET_CONTENT_HINT: { + track->SetContentHint(content_hint_list_.front()); + content_hint_list_.pop_front(); + break; + } + case SET_ENABLED: { + track->setEnabled(enabled_state_list_.front()); + enabled_state_list_.pop_front(); + break; + } + } } - constraints_list_.clear(); // Set up an EventPropagator helper to forward any events fired on track so // that they're re-dispatched to anything that's listening on this.
diff --git a/third_party/blink/renderer/modules/mediastream/transferred_media_stream_track.h b/third_party/blink/renderer/modules/mediastream/transferred_media_stream_track.h index 1cc0d631..fe2be1e 100644 --- a/third_party/blink/renderer/modules/mediastream/transferred_media_stream_track.h +++ b/third_party/blink/renderer/modules/mediastream/transferred_media_stream_track.h
@@ -18,6 +18,7 @@ #include "third_party/blink/renderer/platform/mediastream/media_stream_source.h" #include "third_party/blink/renderer/platform/mediastream/transferred_media_stream_component.h" #include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h" +#include "third_party/blink/renderer/platform/wtf/deque.h" #include "third_party/blink/renderer/platform/wtf/forward.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" @@ -104,6 +105,9 @@ void Trace(Visitor*) const override; private: + // Enumerates function names which can change the state of MediaStreamTrack. + enum SetterFunction { APPLY_CONSTRAINTS, SET_CONTENT_HINT, SET_ENABLED }; + void applyConstraints(ScriptPromiseResolver*, const MediaTrackConstraints*) override; @@ -125,7 +129,10 @@ Member<MediaStreamTrack> track_; using ConstraintsPair = std::pair<ScriptPromiseResolver*, const MediaTrackConstraints*>; - Vector<ConstraintsPair> constraints_list_; + Vector<SetterFunction> setter_call_order_; + WTF::Deque<String> content_hint_list_; + WTF::Deque<ConstraintsPair> constraints_list_; + WTF::Deque<bool> enabled_state_list_; WeakMember<ExecutionContext> execution_context_; TransferredValues data_; Member<EventPropagator> event_propagator_;
diff --git a/third_party/blink/renderer/modules/mediastream/transferred_media_stream_track_test.cc b/third_party/blink/renderer/modules/mediastream/transferred_media_stream_track_test.cc index a1464ba3..6f7541d 100644 --- a/third_party/blink/renderer/modules/mediastream/transferred_media_stream_track_test.cc +++ b/third_party/blink/renderer/modules/mediastream/transferred_media_stream_track_test.cc
@@ -33,6 +33,7 @@ class TransferredMediaStreamTrackTest : public testing::Test { public: void CustomSetUp(V8TestingScope& scope) { + mock_impl_ = MakeGarbageCollected<MockMediaStreamTrack>(); transferred_track_ = MakeGarbageCollected<TransferredMediaStreamTrack>( scope.GetExecutionContext(), MediaStreamTrack::TransferredValues{ @@ -47,6 +48,7 @@ void TearDown() override { WebHeap::CollectAllGarbageForTesting(); } + WeakPersistent<MockMediaStreamTrack> mock_impl_; Persistent<TransferredMediaStreamTrack> transferred_track_; }; @@ -94,27 +96,25 @@ Persistent<MediaTrackSettings> settings = MediaTrackSettings::Create(); Persistent<CaptureHandle> capture_handle = CaptureHandle::Create(); - MockMediaStreamTrack* mock_impl = - MakeGarbageCollected<MockMediaStreamTrack>(); - mock_impl->SetKind(kKind); - mock_impl->SetId(kId); - mock_impl->SetLabel(kLabel); - mock_impl->setEnabled(kEnabled); - mock_impl->SetMuted(kMuted); - mock_impl->SetContentHint(kContentHint); - mock_impl->SetReadyState(kReadyState); - mock_impl->SetCapabilities(capabilities); - mock_impl->SetConstraints(constraints); - mock_impl->SetSettings(settings); - mock_impl->SetCaptureHandle(capture_handle); - mock_impl->SetReadyState(kReadyStateEnum); - mock_impl->SetComponent(nullptr); - mock_impl->SetEnded(kEnded); - mock_impl->SetSerializableSessionId(kSerializableSessionId); - mock_impl->SetExecutionContext(scope.GetExecutionContext()); + mock_impl_->SetKind(kKind); + mock_impl_->SetId(kId); + mock_impl_->SetLabel(kLabel); + mock_impl_->setEnabled(kEnabled); + mock_impl_->SetMuted(kMuted); + mock_impl_->SetContentHint(kContentHint); + mock_impl_->SetReadyState(kReadyState); + mock_impl_->SetCapabilities(capabilities); + mock_impl_->SetConstraints(constraints); + mock_impl_->SetSettings(settings); + mock_impl_->SetCaptureHandle(capture_handle); + mock_impl_->SetReadyState(kReadyStateEnum); + mock_impl_->SetComponent(nullptr); + mock_impl_->SetEnded(kEnded); + mock_impl_->SetSerializableSessionId(kSerializableSessionId); + mock_impl_->SetExecutionContext(scope.GetExecutionContext()); - EXPECT_CALL(*mock_impl, AddedEventListener(_, _)).Times(4); - transferred_track_->SetImplementation(mock_impl); + EXPECT_CALL(*mock_impl_, AddedEventListener(_, _)).Times(4); + transferred_track_->SetImplementation(mock_impl_); EXPECT_EQ(transferred_track_->kind(), kKind); EXPECT_EQ(transferred_track_->id(), kId); @@ -136,17 +136,15 @@ transferred_track_->addEventListener(event_type_names::kEnded, mock_event_handler); - MockMediaStreamTrack* mock_impl = - MakeGarbageCollected<MockMediaStreamTrack>(); - mock_impl->SetExecutionContext(scope.GetExecutionContext()); - EXPECT_CALL(*mock_impl, AddedEventListener(_, _)).Times(4); - transferred_track_->SetImplementation(mock_impl); + mock_impl_->SetExecutionContext(scope.GetExecutionContext()); + EXPECT_CALL(*mock_impl_, AddedEventListener(_, _)).Times(4); + transferred_track_->SetImplementation(mock_impl_); // Dispatching an event on the actual track underneath the // TransferredMediaStreamTrack should get propagated to be an event fired on // the TMST itself. EXPECT_CALL(*mock_event_handler, Invoke(_, _)); - ASSERT_EQ(mock_impl->DispatchEvent(*Event::Create(event_type_names::kEnded)), + ASSERT_EQ(mock_impl_->DispatchEvent(*Event::Create(event_type_names::kEnded)), DispatchEventResult::kNotCanceled); } @@ -155,35 +153,98 @@ V8TestingScope scope; CustomSetUp(scope); - MockMediaStreamTrack* mock_impl = - MakeGarbageCollected<MockMediaStreamTrack>(); - mock_impl->SetExecutionContext(scope.GetExecutionContext()); + mock_impl_->SetExecutionContext(scope.GetExecutionContext()); transferred_track_->applyConstraints(scope.GetScriptState(), MediaTrackConstraints::Create()); - EXPECT_CALL(*mock_impl, AddedEventListener(_, _)).Times(4); + EXPECT_CALL(*mock_impl_, AddedEventListener(_, _)).Times(4); - EXPECT_CALL(*mock_impl, applyConstraintsScriptState(_, _)).Times(0); - EXPECT_CALL(*mock_impl, applyConstraintsResolver(_, _)).Times(1); - transferred_track_->SetImplementation(mock_impl); + EXPECT_CALL(*mock_impl_, applyConstraintsScriptState(_, _)).Times(0); + EXPECT_CALL(*mock_impl_, applyConstraintsResolver(_, _)).Times(1); + transferred_track_->SetImplementation(mock_impl_); } TEST_F(TransferredMediaStreamTrackTest, ConstraintsAppliedAfterImplementation) { V8TestingScope scope; CustomSetUp(scope); - MockMediaStreamTrack* mock_impl = - MakeGarbageCollected<MockMediaStreamTrack>(); - mock_impl->SetExecutionContext(scope.GetExecutionContext()); - EXPECT_CALL(*mock_impl, AddedEventListener(_, _)).Times(4); + mock_impl_->SetExecutionContext(scope.GetExecutionContext()); + EXPECT_CALL(*mock_impl_, AddedEventListener(_, _)).Times(4); - EXPECT_CALL(*mock_impl, applyConstraintsScriptState(_, _)).Times(1); - EXPECT_CALL(*mock_impl, applyConstraintsResolver(_, _)).Times(0); - transferred_track_->SetImplementation(mock_impl); + EXPECT_CALL(*mock_impl_, applyConstraintsScriptState(_, _)).Times(1); + EXPECT_CALL(*mock_impl_, applyConstraintsResolver(_, _)).Times(0); + transferred_track_->SetImplementation(mock_impl_); transferred_track_->applyConstraints(scope.GetScriptState(), MediaTrackConstraints::Create()); } +TEST_F(TransferredMediaStreamTrackTest, ContentHintSetBeforeImplementation) { + V8TestingScope scope; + CustomSetUp(scope); + + mock_impl_->SetExecutionContext(scope.GetExecutionContext()); + const String kContentHint = "music"; + transferred_track_->SetContentHint(kContentHint); + ASSERT_EQ(transferred_track_->ContentHint(), ""); + transferred_track_->SetImplementation(mock_impl_); + EXPECT_EQ(transferred_track_->ContentHint(), kContentHint); +} + +TEST_F(TransferredMediaStreamTrackTest, ContentHintSetAfterImplementation) { + V8TestingScope scope; + CustomSetUp(scope); + + mock_impl_->SetExecutionContext(scope.GetExecutionContext()); + const String kContentHint = "speech"; + transferred_track_->SetImplementation(mock_impl_); + ASSERT_TRUE(transferred_track_->ContentHint().IsNull()); + transferred_track_->SetContentHint(kContentHint); + EXPECT_EQ(transferred_track_->ContentHint(), kContentHint); +} + +TEST_F(TransferredMediaStreamTrackTest, SetEnabledBeforeImplementation) { + V8TestingScope scope; + CustomSetUp(scope); + + mock_impl_->SetExecutionContext(scope.GetExecutionContext()); + transferred_track_->setEnabled(/*enabled=*/true); + ASSERT_TRUE(transferred_track_->enabled()); + ASSERT_FALSE(mock_impl_->enabled()); + transferred_track_->SetImplementation(mock_impl_); + EXPECT_TRUE(transferred_track_->enabled()); +} + +TEST_F(TransferredMediaStreamTrackTest, SetEnabledAfterImplementation) { + V8TestingScope scope; + CustomSetUp(scope); + + mock_impl_->SetExecutionContext(scope.GetExecutionContext()); + ASSERT_TRUE(transferred_track_->enabled()); + transferred_track_->SetImplementation(mock_impl_); + EXPECT_FALSE(transferred_track_->enabled()); + transferred_track_->setEnabled(/*enabled=*/true); + EXPECT_TRUE(transferred_track_->enabled()); +} + +TEST_F(TransferredMediaStreamTrackTest, MultipleSetterFunctions) { + V8TestingScope scope; + CustomSetUp(scope); + + EXPECT_CALL(*mock_impl_, applyConstraintsResolver(_, _)).Times(1); + mock_impl_->SetExecutionContext(scope.GetExecutionContext()); + transferred_track_->SetContentHint("speech"); + transferred_track_->applyConstraints(scope.GetScriptState(), + MediaTrackConstraints::Create()); + transferred_track_->setEnabled(/*enabled=*/true); + transferred_track_->SetContentHint("music"); + transferred_track_->setEnabled(/*enabled=*/false); + ASSERT_TRUE(transferred_track_->enabled()); + ASSERT_EQ(transferred_track_->ContentHint(), ""); + transferred_track_->SetImplementation(mock_impl_); + EXPECT_EQ(transferred_track_->ContentHint(), "music"); + EXPECT_FALSE(transferred_track_->enabled()); +} + TEST_F(TransferredMediaStreamTrackTest, SetImplementationTriggersObservers) { V8TestingScope scope; CustomSetUp(scope); @@ -198,10 +259,10 @@ V8TestingScope scope; CustomSetUp(scope); transferred_track_->AddObserver(MakeGarbageCollected<TestObserver>()); - MockMediaStreamTrack* mock_impl = + MockMediaStreamTrack* mock_impl_ = MakeGarbageCollected<testing::NiceMock<MockMediaStreamTrack>>(); - EXPECT_CALL(*mock_impl, AddObserver(_)); - transferred_track_->SetImplementation(mock_impl); + EXPECT_CALL(*mock_impl_, AddObserver(_)); + transferred_track_->SetImplementation(mock_impl_); } } // namespace blink
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.cc index c9abdd61..487af24 100644 --- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.cc +++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.cc
@@ -4,6 +4,8 @@ #include "third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.h" +#include "base/numerics/checked_math.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_clamp_options.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_conv_2d_options.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_gemm_options.h" @@ -12,9 +14,81 @@ #include "third_party/blink/renderer/modules/ml/ml_context.h" #include "third_party/blink/renderer/modules/ml/webnn/ml_operand.h" #include "third_party/blink/renderer/modules/ml/webnn/ml_operator.h" +#include "third_party/blink/renderer/platform/bindings/exception_state.h" namespace blink { +namespace { + +DOMArrayBufferView::ViewType GetArrayBufferViewType( + V8MLOperandType::Enum operand_type) { + switch (operand_type) { + case V8MLOperandType::Enum::kFloat32: + return DOMArrayBufferView::ViewType::kTypeFloat32; + case V8MLOperandType::Enum::kFloat16: + // Using Uint16Array for float16 is a workaround of WebNN spec issue: + // https://github.com/webmachinelearning/webnn/issues/127 + return DOMArrayBufferView::ViewType::kTypeUint16; + case V8MLOperandType::Enum::kInt32: + return DOMArrayBufferView::ViewType::kTypeInt32; + case V8MLOperandType::Enum::kUint32: + return DOMArrayBufferView::ViewType::kTypeUint32; + case V8MLOperandType::Enum::kInt8: + return DOMArrayBufferView::ViewType::kTypeInt8; + case V8MLOperandType::Enum::kUint8: + return DOMArrayBufferView::ViewType::kTypeUint8; + } +} + +size_t GetBytesPerElement(V8MLOperandType::Enum operand_type) { + switch (operand_type) { + case V8MLOperandType::Enum::kFloat32: + return sizeof(float); + case V8MLOperandType::Enum::kFloat16: + // Using Uint16Array for float16 is a workaround of WebNN spec issue: + // https://github.com/webmachinelearning/webnn/issues/127 + return sizeof(uint16_t); + case V8MLOperandType::Enum::kInt32: + return sizeof(int32_t); + case V8MLOperandType::Enum::kUint32: + return sizeof(uint32_t); + case V8MLOperandType::Enum::kInt8: + return sizeof(int8_t); + case V8MLOperandType::Enum::kUint8: + return sizeof(uint8_t); + } +} + +absl::optional<size_t> ValidateAndCalculateByteLength( + V8MLOperandType::Enum type, + const Vector<int32_t>& dimensions, + ExceptionState& exception_state) { + if (dimensions.IsEmpty()) { + exception_state.ThrowDOMException(DOMExceptionCode::kDataError, + "The dimensions is empty."); + return absl::nullopt; + } + base::CheckedNumeric<size_t> elements_num = 1; + for (auto& d : dimensions) { + if (d <= 0) { + exception_state.ThrowDOMException(DOMExceptionCode::kDataError, + "All dimensions should be positive"); + return absl::nullopt; + } + elements_num *= d; + } + base::CheckedNumeric<size_t> checked_byte_length = + elements_num * GetBytesPerElement(type); + if (!checked_byte_length.IsValid()) { + exception_state.ThrowDOMException(DOMExceptionCode::kDataError, + "The dimensions is too large."); + return absl::nullopt; + } + return checked_byte_length.ValueOrDie(); +} + +} // namespace + // static MLGraphBuilder* MLGraphBuilder::Create(MLContext* context) { return MakeGarbageCollected<MLGraphBuilder>(context); @@ -29,82 +103,132 @@ ScriptWrappable::Trace(visitor); } -MLOperand* MLGraphBuilder::input(String name, const MLOperandDescriptor* desc) { - // TODO(crbug.com/1273291): Implement this on operating systems to access - // hardware acceleration. - NOTIMPLEMENTED(); - return MakeGarbageCollected<MLOperand>(this); +MLOperand* MLGraphBuilder::input(String name, + const MLOperandDescriptor* desc, + ExceptionState& exception_state) { + if (name.IsEmpty()) { + exception_state.ThrowDOMException(DOMExceptionCode::kDataError, + "The name is empty."); + return nullptr; + } + V8MLOperandType::Enum type = desc->type().AsEnum(); + // If no dimensions, it represents a scalar. Set dimensions to {1}. + Vector<int32_t> dimensions = desc->getDimensionsOr({1}); + if (!ValidateAndCalculateByteLength(type, dimensions, exception_state)) { + return nullptr; + } + return MLOperand::CreateInput(this, type, std::move(dimensions), + std::move(name)); } MLOperand* MLGraphBuilder::constant(const MLOperandDescriptor* desc, - NotShared<DOMArrayBufferView> buffer_view) { - // TODO(crbug.com/1273291): Implement this on operating systems to access - // hardware acceleration. - NOTIMPLEMENTED(); - return MakeGarbageCollected<MLOperand>(this); + NotShared<DOMArrayBufferView> buffer_view, + ExceptionState& exception_state) { + if (GetArrayBufferViewType(desc->type().AsEnum()) != buffer_view->GetType()) { + exception_state.ThrowDOMException( + DOMExceptionCode::kDataError, + "The buffer view type doesn't match the operand type."); + return nullptr; + } + V8MLOperandType::Enum type = desc->type().AsEnum(); + // If no dimensions, it represents a scalar. Set dimensions to {1}. + Vector<int32_t> dimensions = desc->getDimensionsOr({1}); + absl::optional<size_t> expected_byte_length = + ValidateAndCalculateByteLength(type, dimensions, exception_state); + if (!expected_byte_length) { + return nullptr; + } + if (expected_byte_length.value() != buffer_view->byteLength()) { + exception_state.ThrowDOMException( + DOMExceptionCode::kDataError, + String::Format("The buffer view byte length (%zu) doesn't match the " + "expected byte length (%zu).", + buffer_view->byteLength(), + expected_byte_length.value())); + return nullptr; + } + return MLOperand::CreateConstant(this, type, std::move(dimensions), + buffer_view.Get()); } MLOperand* MLGraphBuilder::clamp(const MLOperand* input, - const MLClampOptions* options) { + const MLClampOptions* options, + ExceptionState& exception_state) { // TODO(crbug.com/1273291): Implement this on operating systems to access // hardware acceleration. - NOTIMPLEMENTED(); - return MakeGarbageCollected<MLOperand>(this); + exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError, + "Not implemented"); + return nullptr; } -MLOperator* MLGraphBuilder::clamp(const MLClampOptions* options) { +MLOperator* MLGraphBuilder::clamp(const MLClampOptions* options, + ExceptionState& exception_state) { // TODO(crbug.com/1273291): Implement this on operating systems to access // hardware acceleration. - NOTIMPLEMENTED(); - return MakeGarbageCollected<MLOperator>(this); + exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError, + "Not implemented"); + return nullptr; } MLOperand* MLGraphBuilder::conv2d(const MLOperand* input, const MLOperand* filter, - const MLConv2dOptions* options) { + const MLConv2dOptions* options, + ExceptionState& exception_state) { // TODO(crbug.com/1273291): Implement this on operating systems to access // hardware acceleration. - NOTIMPLEMENTED(); - return MakeGarbageCollected<MLOperand>(this); + exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError, + "Not implemented"); + return nullptr; } -MLOperand* MLGraphBuilder::add(const MLOperand* a, const MLOperand* b) { +MLOperand* MLGraphBuilder::add(const MLOperand* a, + const MLOperand* b, + ExceptionState& exception_state) { // TODO(crbug.com/1273291): Implement this on operating systems to access // hardware acceleration. - NOTIMPLEMENTED(); - return MakeGarbageCollected<MLOperand>(this); + exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError, + "Not implemented"); + return nullptr; } MLOperand* MLGraphBuilder::gemm(const MLOperand* a, const MLOperand* b, - const MLGemmOptions* options) { + const MLGemmOptions* options, + ExceptionState& exception_state) { // TODO(crbug.com/1273291): Implement this on operating systems to access // hardware acceleration. - NOTIMPLEMENTED(); - return MakeGarbageCollected<MLOperand>(this); + exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError, + "Not implemented"); + return nullptr; } MLOperand* MLGraphBuilder::averagePool2d(const MLOperand* input, - const MLPool2dOptions* options) { + const MLPool2dOptions* options, + ExceptionState& exception_state) { // TODO(crbug.com/1273291): Implement this on operating systems to access // hardware acceleration. - NOTIMPLEMENTED(); - return MakeGarbageCollected<MLOperand>(this); + exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError, + "Not implemented"); + return nullptr; } MLOperand* MLGraphBuilder::reshape(const MLOperand* input, - const Vector<int32_t>& new_shape) { + const Vector<int32_t>& new_shape, + ExceptionState& exception_state) { // TODO(crbug.com/1273291): Implement this on operating systems to access // hardware acceleration. - NOTIMPLEMENTED(); - return MakeGarbageCollected<MLOperand>(this); + exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError, + "Not implemented"); + return nullptr; } -MLOperand* MLGraphBuilder::softmax(const MLOperand* input) { +MLOperand* MLGraphBuilder::softmax(const MLOperand* input, + ExceptionState& exception_state) { // TODO(crbug.com/1273291): Implement this on operating systems to access // hardware acceleration. - NOTIMPLEMENTED(); - return MakeGarbageCollected<MLOperand>(this); + exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError, + "Not implemented"); + return nullptr; } } // namespace blink
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.h b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.h index 53c5924..2d4fc49 100644 --- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.h +++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.h
@@ -14,6 +14,7 @@ namespace blink { +class ExceptionState; class MLContext; class MLClampOptions; class MLConv2dOptions; @@ -41,27 +42,45 @@ void Trace(Visitor* visitor) const override; // ml_graph_builder.idl - MLOperand* input(String name, const MLOperandDescriptor* desc); + MLOperand* input(String name, + const MLOperandDescriptor* desc, + ExceptionState& exception_state); MLOperand* constant(const MLOperandDescriptor* desc, - NotShared<DOMArrayBufferView> buffer_view); + NotShared<DOMArrayBufferView> buffer_view, + ExceptionState& exception_state); // The order of operations declaration is the same as spec. - MLOperand* clamp(const MLOperand*, const MLClampOptions*); - MLOperator* clamp(const MLClampOptions*); + MLOperand* clamp(const MLOperand* input, + const MLClampOptions* options, + ExceptionState& exception_state); + MLOperator* clamp(const MLClampOptions* options, + ExceptionState& exception_state); - MLOperand* conv2d(const MLOperand*, const MLOperand*, const MLConv2dOptions*); + MLOperand* conv2d(const MLOperand* input, + const MLOperand* filter, + const MLConv2dOptions* options, + ExceptionState& exception_state); // Element-wise binary operations - MLOperand* add(const MLOperand*, const MLOperand*); + MLOperand* add(const MLOperand* a, + const MLOperand* b, + ExceptionState& exception_state); - MLOperand* gemm(const MLOperand*, const MLOperand*, const MLGemmOptions*); + MLOperand* gemm(const MLOperand* a, + const MLOperand* b, + const MLGemmOptions* options, + ExceptionState& exception_state); // Pooling operations - MLOperand* averagePool2d(const MLOperand*, const MLPool2dOptions*); + MLOperand* averagePool2d(const MLOperand* input, + const MLPool2dOptions* options, + ExceptionState& exception_state); - MLOperand* reshape(const MLOperand*, const Vector<int32_t>&); + MLOperand* reshape(const MLOperand* input, + const Vector<int32_t>& new_shape, + ExceptionState& exception_state); - MLOperand* softmax(const MLOperand*); + MLOperand* softmax(const MLOperand* input, ExceptionState& exception_state); private: Member<MLContext> ml_context_;
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.idl b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.idl index 56e8d40..a5d03b59 100644 --- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.idl +++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.idl
@@ -59,26 +59,24 @@ ] interface MLGraphBuilder { constructor(MLContext context); - MLOperand input(DOMString name, MLOperandDescriptor desc); + [RaisesException] MLOperand input(DOMString name, MLOperandDescriptor desc); - MLOperand constant(MLOperandDescriptor desc, MLBufferView bufferView); + [RaisesException] MLOperand constant(MLOperandDescriptor desc, MLBufferView bufferView); - MLOperand clamp(MLOperand input, optional MLClampOptions options = {}); - MLOperator clamp(optional MLClampOptions options = {}); + [RaisesException] MLOperand clamp(MLOperand input, optional MLClampOptions options = {}); + [RaisesException] MLOperator clamp(optional MLClampOptions options = {}); - MLOperand conv2d(MLOperand input, MLOperand filter, - optional MLConv2dOptions options = {}); + [RaisesException] MLOperand conv2d(MLOperand input, MLOperand filter, optional MLConv2dOptions options = {}); // Element-wise binary operations - MLOperand add(MLOperand a, MLOperand b); + [RaisesException] MLOperand add(MLOperand a, MLOperand b); - MLOperand gemm(MLOperand a, MLOperand b, optional MLGemmOptions options = {}); + [RaisesException] MLOperand gemm(MLOperand a, MLOperand b, optional MLGemmOptions options = {}); // Pooling operations - MLOperand averagePool2d(MLOperand input, - optional MLPool2dOptions options = {}); + [RaisesException] MLOperand averagePool2d(MLOperand input, optional MLPool2dOptions options = {}); - MLOperand reshape(MLOperand input, sequence<long> newShape); + [RaisesException] MLOperand reshape(MLOperand input, sequence<long> newShape); - MLOperand softmax(MLOperand input); + [RaisesException] MLOperand softmax(MLOperand input); };
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_operand.cc b/third_party/blink/renderer/modules/ml/webnn/ml_operand.cc index 5a6c487..d4dd804 100644 --- a/third_party/blink/renderer/modules/ml/webnn/ml_operand.cc +++ b/third_party/blink/renderer/modules/ml/webnn/ml_operand.cc
@@ -5,16 +5,90 @@ #include "third_party/blink/renderer/modules/ml/webnn/ml_operand.h" #include "third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.h" +#include "third_party/blink/renderer/modules/ml/webnn/ml_operator.h" namespace blink { -MLOperand::MLOperand(MLGraphBuilder* graph_builder) - : graph_builder_(graph_builder) {} +// static +MLOperand* MLOperand::CreateInput(MLGraphBuilder* builder, + const V8MLOperandType::Enum type, + Vector<int32_t> dimensions, + String name) { + auto* input = MakeGarbageCollected<MLOperand>(builder, OperandKind::kInput, + type, std::move(dimensions)); + input->name_ = std::move(name); + return input; +} + +// static +MLOperand* MLOperand::CreateConstant( + MLGraphBuilder* builder, + const V8MLOperandType::Enum type, + Vector<int32_t> dimensions, + const DOMArrayBufferView* array_buffer_view) { + auto* constant = MakeGarbageCollected<MLOperand>( + builder, OperandKind::kConstant, type, std::move(dimensions)); + constant->array_buffer_view_ = array_buffer_view; + return constant; +} + +// static +MLOperand* MLOperand::CreateOutput(MLGraphBuilder* builder, + const V8MLOperandType::Enum type, + Vector<int32_t> dimensions, + const MLOperator* ml_operator) { + auto* output = MakeGarbageCollected<MLOperand>(builder, OperandKind::kOutput, + type, std::move(dimensions)); + output->operator_ = ml_operator; + return output; +} + +MLOperand::MLOperand(MLGraphBuilder* builder, + OperandKind kind, + const V8MLOperandType::Enum type, + Vector<int32_t> dimensions) + : builder_(builder), + kind_(kind), + type_(type), + dimensions_(std::move(dimensions)) {} MLOperand::~MLOperand() = default; +MLGraphBuilder* MLOperand::Builder() const { + return builder_.Get(); +} + +MLOperand::OperandKind MLOperand::Kind() const { + return kind_; +} + +V8MLOperandType::Enum MLOperand::Type() const { + return type_; +} + +const Vector<int32_t>& MLOperand::Dimensions() const { + return dimensions_; +} + +const String& MLOperand::Name() const { + DCHECK_EQ(kind_, OperandKind::kInput); + return name_; +} + +const DOMArrayBufferView* MLOperand::ArrayBufferView() const { + DCHECK_EQ(kind_, OperandKind::kConstant); + return array_buffer_view_.Get(); +} + +const MLOperator* MLOperand::Operator() const { + DCHECK_EQ(kind_, OperandKind::kOutput); + return operator_.Get(); +} + void MLOperand::Trace(Visitor* visitor) const { - visitor->Trace(graph_builder_); + visitor->Trace(builder_); + visitor->Trace(array_buffer_view_); + visitor->Trace(operator_); ScriptWrappable::Trace(visitor); }
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_operand.h b/third_party/blink/renderer/modules/ml/webnn/ml_operand.h index 23c608e..8cfb443 100644 --- a/third_party/blink/renderer/modules/ml/webnn/ml_operand.h +++ b/third_party/blink/renderer/modules/ml/webnn/ml_operand.h
@@ -5,6 +5,9 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_ML_WEBNN_ML_OPERAND_H_ #define THIRD_PARTY_BLINK_RENDERER_MODULES_ML_WEBNN_ML_OPERAND_H_ +#include "third_party/blink/renderer/bindings/modules/v8/v8_ml_operand_descriptor.h" +#include "third_party/blink/renderer/core/typed_arrays/array_buffer_view_helpers.h" +#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer_view.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" #include "third_party/blink/renderer/platform/heap/member.h" #include "third_party/blink/renderer/platform/heap/visitor.h" @@ -12,12 +15,33 @@ namespace blink { class MLGraphBuilder; +class MLOperator; class MLOperand final : public ScriptWrappable { DEFINE_WRAPPERTYPEINFO(); public: - explicit MLOperand(MLGraphBuilder* graph_builder); + enum OperandKind { kInput, kConstant, kOutput }; + + static MLOperand* CreateInput(MLGraphBuilder* builder, + const V8MLOperandType::Enum type, + Vector<int32_t> dimensions, + String name); + static MLOperand* CreateConstant(MLGraphBuilder* builder, + const V8MLOperandType::Enum type, + Vector<int32_t> dimensions, + const DOMArrayBufferView* array_buffer_view); + static MLOperand* CreateOutput(MLGraphBuilder* builder, + const V8MLOperandType::Enum type, + Vector<int32_t> dimensions, + const MLOperator* ml_operator); + + // The constructor shouldn't be called directly. The callers should use + // Create* methods instead. + MLOperand(MLGraphBuilder* builder, + OperandKind kind, + const V8MLOperandType::Enum type, + Vector<int32_t> dimensions); MLOperand(const MLOperand&) = delete; MLOperand& operator=(const MLOperand&) = delete; @@ -26,8 +50,33 @@ void Trace(Visitor* visitor) const override; + MLGraphBuilder* Builder() const; + OperandKind Kind() const; + V8MLOperandType::Enum Type() const; + const Vector<int32_t>& Dimensions() const; + const String& Name() const; + const DOMArrayBufferView* ArrayBufferView() const; + const MLOperator* Operator() const; + private: - Member<MLGraphBuilder> graph_builder_; + Member<MLGraphBuilder> builder_; + OperandKind kind_; + V8MLOperandType::Enum type_; + // The dimensions of the operand. For scalar value, set {1}. + Vector<int32_t> dimensions_; + // The name of input operand. According to + // https://www.w3.org/TR/webnn/#dom-mlgraphbuilder-input, only input operand + // is created with a name. + String name_; + // The buffer view of constant operand. According to + // https://www.w3.org/TR/webnn/#dom-mlgraphbuilder-constant, only constant + // operand is associated with an array buffer view that contains the + // user-supplied constant data. + Member<const DOMArrayBufferView> array_buffer_view_; + // The operator that produces the output operand. Only output operand has an + // operator that produces the operand by an operator build method of + // MLGraphBuilder interface. + Member<const MLOperator> operator_; }; } // namespace blink
diff --git a/third_party/blink/renderer/platform/bindings/callback_function_base.h b/third_party/blink/renderer/platform/bindings/callback_function_base.h index 68025ed..fc559ebd9 100644 --- a/third_party/blink/renderer/platform/bindings/callback_function_base.h +++ b/third_party/blink/renderer/platform/bindings/callback_function_base.h
@@ -42,7 +42,7 @@ // Returns the ScriptState of the relevant realm of the callback object. // // NOTE: This function must be used only when it's pretty sure that the - // callcack object is the same origin-domain. Otherwise, + // callback object is the same origin-domain. Otherwise, // |CallbackRelevantScriptStateOrReportError| or // |CallbackRelevantScriptStateOrThrowException| must be used instead. ScriptState* CallbackRelevantScriptState() {
diff --git a/third_party/blink/renderer/platform/bindings/callback_interface_base.h b/third_party/blink/renderer/platform/bindings/callback_interface_base.h index e1b880b..6d33ee6 100644 --- a/third_party/blink/renderer/platform/bindings/callback_interface_base.h +++ b/third_party/blink/renderer/platform/bindings/callback_interface_base.h
@@ -57,7 +57,7 @@ // Returns the ScriptState of the relevant realm of the callback object. // // NOTE: This function must be used only when it's pretty sure that the - // callcack object is the same origin-domain. Otherwise, + // callback object is the same origin-domain. Otherwise, // |CallbackRelevantScriptStateOrReportError| or // |CallbackRelevantScriptStateOrThrowException| must be used instead. ScriptState* CallbackRelevantScriptState() {
diff --git a/third_party/blink/web_tests/FlagExpectations/disable-layout-ng b/third_party/blink/web_tests/FlagExpectations/disable-layout-ng index 8f6055d..d5d36ad 100644 --- a/third_party/blink/web_tests/FlagExpectations/disable-layout-ng +++ b/third_party/blink/web_tests/FlagExpectations/disable-layout-ng
@@ -11,6 +11,8 @@ # Tests that fail in legacy but pass in NG # ====== New tests from wpt-importer added here ====== +crbug.com/626703 external/wpt/css/css-pseudo/highlight-currentcolor-root-explicit-default-002.html [ Failure ] +crbug.com/626703 virtual/css-highlight-inheritance/external/wpt/css/css-pseudo/highlight-currentcolor-root-explicit-default-002.html [ Failure ] crbug.com/626703 external/wpt/css/css-sizing/aspect-ratio/block-aspect-ratio-050.html [ Failure ] crbug.com/626703 external/wpt/css/css-sizing/aspect-ratio/grid-aspect-ratio-040.html [ Crash ] crbug.com/626703 external/wpt/css/css-sizing/contain-intrinsic-size/contain-intrinsic-size-028.html [ Crash ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index c96d6bd41..665a2746 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -3367,6 +3367,18 @@ crbug.com/626703 [ Win ] virtual/partitioned-cookies/http/tests/inspector-protocol/network/disabled-cache-navigation.js [ Failure ] # ====== New tests from wpt-importer added here ====== +crbug.com/626703 external/wpt/css/css-pseudo/highlight-currentcolor-painting-properties-001.html [ Failure ] +crbug.com/626703 external/wpt/css/css-pseudo/highlight-currentcolor-painting-properties-002.html [ Failure ] +crbug.com/626703 external/wpt/css/css-pseudo/highlight-currentcolor-root-implicit-default-001.html [ Failure ] +crbug.com/626703 [ Mac10.15 ] external/wpt/html/browsers/browsing-the-web/remote-context-helper-tests/navigation-same-document.window.html [ Failure Timeout ] +crbug.com/626703 [ Mac11-arm64 ] external/wpt/html/browsers/browsing-the-web/remote-context-helper-tests/navigation-same-document.window.html [ Failure Timeout ] +crbug.com/626703 virtual/css-highlight-inheritance/external/wpt/css/css-pseudo/highlight-currentcolor-painting-properties-001.html [ Failure ] +crbug.com/626703 virtual/css-highlight-inheritance/external/wpt/css/css-pseudo/highlight-currentcolor-painting-properties-002.html [ Failure ] +crbug.com/626703 virtual/css-highlight-overlay-painting/external/wpt/css/css-pseudo/highlight-currentcolor-painting-properties-001.html [ Failure ] +crbug.com/626703 virtual/css-highlight-overlay-painting/external/wpt/css/css-pseudo/highlight-currentcolor-painting-properties-002.html [ Failure ] +crbug.com/626703 virtual/css-highlight-overlay-painting/external/wpt/css/css-pseudo/highlight-currentcolor-root-implicit-default-001.html [ Failure ] +crbug.com/626703 [ Mac11 ] virtual/fenced-frame-mparch/wpt_internal/fenced_frame/background-sync.https.html [ Timeout ] +crbug.com/626703 [ Mac11 ] virtual/fenced-frame-shadow-dom/wpt_internal/fenced_frame/background-sync.https.html [ Timeout ] crbug.com/626703 [ Mac10.15 ] external/wpt/fullscreen/api/document-fullscreen-enabled-cross-origin.sub.html [ Timeout ] crbug.com/626703 [ Win10.20h2 ] virtual/attribution-reporting-debug-mode/wpt_internal/attribution-reporting/debug-key.sub.https.html?include=trigger [ Failure Timeout ] crbug.com/626703 [ Mac11 ] virtual/attribution-reporting-debug-mode/wpt_internal/attribution-reporting/source-registration.sub.https.html?method=img&eligible [ Timeout ] @@ -7071,4 +7083,5 @@ # Sheriff 2022-08-06 crbug.com/1350336 [ Mac ] virtual/fenced-frame-mparch/wpt_internal/fenced_frame/visual-viewport.https.html [ Failure Pass ] -crbug.com/1350337 [ Linux ] external/wpt/web-locks/query-ordering.tentative.https.html [ Failure Pass ] \ No newline at end of file +crbug.com/1350337 [ Linux ] external/wpt/web-locks/query-ordering.tentative.https.html [ Failure Pass ] +crbug.com/1350341 [ Linux ] virtual/threaded-no-composited-antialiasing/animations/direction-and-fill/fill-mode-missing-from-to-keyframes.html [ Failure Pass ] \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/Version b/third_party/blink/web_tests/external/Version index c861d62..900beee2 100644 --- a/third_party/blink/web_tests/external/Version +++ b/third_party/blink/web_tests/external/Version
@@ -1 +1 @@ -Version: 8e5c6c20c3b9ef12d7b0486470fcf87cb160a8ea +Version: 9cfba6b9061d51e0b212cbcf24a35dc0237db093
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json index 5b7804e..ff046010 100644 --- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json +++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -185,6 +185,13 @@ {} ] ], + "object-with-unrendered-text-fallback.html": [ + "0128213bfc66aaddb473b8692d622613e6a253b0", + [ + null, + {} + ] + ], "serialize-with-no-document.html": [ "f7719cf2ff1838b1125e08c5f86cf57910732c0e", [ @@ -1062,6 +1069,13 @@ {} ] ], + "marker-gcs-after-disconnect-crash.html": [ + "3680c795122603312d8a5a63ea48bd69c402b204", + [ + null, + {} + ] + ], "math-block-container-child-crash.html": [ "00b6836655e904f1f0d64f7e3f42afaf02fc351b", [ @@ -2108,6 +2122,13 @@ {} ] ], + "size-containment-become-multicol-add-inline-child.html": [ + "6933592c7e386ba13ab1c56c336a4d2a35a0b355", + [ + null, + {} + ] + ], "spanner-in-overflowed-container-before-float.html": [ "c15d8aa0faf159d25f87dc76df745e18318ccc61", [ @@ -2876,6 +2897,17 @@ ] ] }, + "css-text-decor": { + "crashtests": { + "text-decoration-on-empty-first-line-crash.html": [ + "058cf9f8371d6e95965edcdf12f62a15e2c7f4b9", + [ + null, + {} + ] + ] + } + }, "css-transforms": { "crashtests": { "large-scale3d-001.html": [ @@ -94904,7 +94936,7 @@ ] ], "contain-inline-size-multicol.html": [ - "e6934232bb3b4953c334f54debd6fdd0844ce5e5", + "43510677f5d82362856ee2aeb069c5e25e4c6714", [ null, [ @@ -152179,6 +152211,84 @@ {} ] ], + "highlight-currentcolor-painting-properties-001.html": [ + "94e7e9b8f1143ebd65dcb10d02083c5885a9bc46", + [ + null, + [ + [ + "/css/css-pseudo/highlight-currentcolor-painting-properties-001-ref.html", + "==" + ] + ], + {} + ] + ], + "highlight-currentcolor-painting-properties-002.html": [ + "7dbc62415b8080c2fea5d5e19103c3d16a2e9e3f", + [ + null, + [ + [ + "/css/css-pseudo/highlight-currentcolor-painting-properties-002-ref.html", + "==" + ] + ], + {} + ] + ], + "highlight-currentcolor-root-explicit-default-001.html": [ + "a1512f014df4a38b81ac4c60cb1e2383542a60bd", + [ + null, + [ + [ + "/css/css-pseudo/highlight-currentcolor-root-explicit-default-001-ref.html", + "==" + ] + ], + {} + ] + ], + "highlight-currentcolor-root-explicit-default-002.html": [ + "fc5698faa1e794bde4ca69cf6b83a5f9868d1171", + [ + null, + [ + [ + "/css/css-pseudo/highlight-currentcolor-root-explicit-default-002-ref.html", + "==" + ] + ], + {} + ] + ], + "highlight-currentcolor-root-implicit-default-001.html": [ + "ecf787b9b41a3c684ea2d1175aafa9049c097f84", + [ + null, + [ + [ + "/css/css-pseudo/highlight-currentcolor-root-implicit-default-ref.html", + "==" + ] + ], + {} + ] + ], + "highlight-currentcolor-root-implicit-default-002.html": [ + "420cc5ba15e2f83e475db36f9574e2401a5c1217", + [ + null, + [ + [ + "/css/css-pseudo/highlight-currentcolor-root-implicit-default-ref.html", + "==" + ] + ], + {} + ] + ], "highlight-painting-001.html": [ "ef253e6117c94ef63f9be97eaac0d94667c9fce3", [ @@ -152239,58 +152349,6 @@ {} ] ], - "highlight-painting-currentcolor-001.html": [ - "da79d2d0ffa5f66c816960d7b02d0a4f2316066f", - [ - null, - [ - [ - "/css/css-pseudo/highlight-painting-currentcolor-001-ref.html", - "==" - ] - ], - {} - ] - ], - "highlight-painting-currentcolor-002.html": [ - "b3a27b72eda9f5e2546ff64bffd3cb0dc72d0fbc", - [ - null, - [ - [ - "/css/css-pseudo/highlight-painting-currentcolor-002-ref.html", - "==" - ] - ], - {} - ] - ], - "highlight-painting-currentcolor-003.html": [ - "935b8d1c5f9446e4a90e9628fbae734d31858c12", - [ - null, - [ - [ - "/css/css-pseudo/highlight-painting-currentcolor-003-ref.html", - "==" - ] - ], - {} - ] - ], - "highlight-painting-currentcolor-004.html": [ - "f72236993a344e6c60b89277128981d90b1b3a59", - [ - null, - [ - [ - "/css/css-pseudo/highlight-painting-currentcolor-004-ref.html", - "==" - ] - ], - {} - ] - ], "highlight-painting-currentcolor-005.html": [ "f5c15aafa99ac5b068bbf267bb8ea3583d7ba79a", [ @@ -152395,32 +152453,6 @@ {} ] ], - "highlight-pseudos-currentcolor-inheritance-computed-002.html": [ - "5336aa1c873993ea06658dbed57b8aece94bbb1e", - [ - null, - [ - [ - "/css/css-pseudo/reference/highlight-pseudos-currentcolor-inheritance-computed-002-ref.html", - "==" - ] - ], - {} - ] - ], - "highlight-pseudos-currentcolor-inheritance-computed-003.html": [ - "cd498025366243b16f35e713ce7c6f6fc1b60b79", - [ - null, - [ - [ - "/css/css-pseudo/reference/highlight-pseudos-currentcolor-inheritance-computed-002-ref.html", - "==" - ] - ], - {} - ] - ], "highlight-styling-001.html": [ "63d8ee1eda47dec0eeaf30f56316e4203e49f182", [ @@ -161260,7 +161292,7 @@ ] ], "replaced-element-003.html": [ - "83187fcd459582de54ca1b98c25295e0993d3235", + "306976ac992245e1b3a88ca824ca597e25ad1f59", [ null, [ @@ -161276,7 +161308,7 @@ [ [ 0, - 3 + 30 ], [ 0, @@ -209342,12 +209374,12 @@ ] ], "ic-unit-012.html": [ - "e8603570d2d7f05716b8a4f5c311f6ee7d5a1a25", + "e5d8027d17ba8f988d2f299bfae354e4d64eebd6", [ null, [ [ - "/css/css-values/reference/ic-unit-009-ref.html", + "/css/css-values/reference/ic-unit-012-ref.html", "==" ] ], @@ -284075,6 +284107,26 @@ "df0a56123e033dd4536bc0425353c82bd2d0156b", [] ], + "highlight-currentcolor-painting-properties-001-ref.html": [ + "47a028038b8a3fcd1b6a50d712f115c3c409e1b7", + [] + ], + "highlight-currentcolor-painting-properties-002-ref.html": [ + "19556f6e872a9da2e9ebe6c6e96f831b73fbfd4b", + [] + ], + "highlight-currentcolor-root-explicit-default-001-ref.html": [ + "794796a88f6a7b1e19c2cf9f8336838722b998b4", + [] + ], + "highlight-currentcolor-root-explicit-default-002-ref.html": [ + "31759483174842e7dcc6d0fcb1cea8883f593c06", + [] + ], + "highlight-currentcolor-root-implicit-default-ref.html": [ + "67ecb8df640f72e1725e42a648f2c6e1f33490e2", + [] + ], "highlight-painting-001-ref.html": [ "c5d8814a8252b0a8e4be1b43f635cd7b11f548fc", [] @@ -284099,22 +284151,6 @@ "732f6bfe0dbfe2be32bfa225e53c1da84fa8a98b", [] ], - "highlight-painting-currentcolor-001-ref.html": [ - "979e54a0459cb281bcd619935e100efb01de095a", - [] - ], - "highlight-painting-currentcolor-002-ref.html": [ - "8a61e9cbc40d1ae7fca80ac1811c619e1a8d8a1c", - [] - ], - "highlight-painting-currentcolor-003-ref.html": [ - "794796a88f6a7b1e19c2cf9f8336838722b998b4", - [] - ], - "highlight-painting-currentcolor-004-ref.html": [ - "31759483174842e7dcc6d0fcb1cea8883f593c06", - [] - ], "highlight-painting-currentcolor-005-ref.html": [ "39d26e8387204840d89318ef917d5df0c4021df4", [] @@ -284432,10 +284468,6 @@ "b3c89177591ad83476edd3616f135f1cd65700d8", [] ], - "highlight-pseudos-currentcolor-inheritance-computed-002-ref.html": [ - "67ecb8df640f72e1725e42a648f2c6e1f33490e2", - [] - ], "placeholder-excluded-properties-ref.html": [ "0e573cb3d6cbac837c9e10552e360aa713fee60b", [] @@ -294186,6 +294218,10 @@ "43300522726731474762479eaeb619cdb9320481", [] ], + "ic-unit-012-ref.html": [ + "43069859c7b3d5db091b949fad65bd1a6d52be66", + [] + ], "ic-unit-013-ref.html": [ "67e75b953f57bfb8e4cf0c937f0779e6485f3007", [] @@ -316058,6 +316094,10 @@ "27044c35374a6266cd54ae14a027e8051eeff494", [] ], + "range-restore-events.html.headers": [ + "4030ea1d3ddb186a2b5361eb1a3f2404a45531fc", + [] + ], "show-picker-child-iframe.html": [ "07b72f02cb69f2cb3af049a4f9cb65128428e4a4", [] @@ -316065,6 +316105,10 @@ "text-restore-events.html": [ "aa57bdebcca0b775216b2dd2e18e1269cbaef967", [] + ], + "text-restore-events.html.headers": [ + "4030ea1d3ddb186a2b5361eb1a3f2404a45531fc", + [] ] } }, @@ -320600,7 +320644,11 @@ [] ] } - } + }, + "update_properties.json": [ + "00909d956b30606a56b2ade6c44102de70f6f86e", + [] + ] }, "reftest": { "fuzzy-ref-1.html": [ @@ -376773,7 +376821,7 @@ ] ], "CSS-supports-L3.html": [ - "4c92275d041ad79e86994ce85b8539c1f49680ad", + "f94933422a31d8db9bf3c84c7fd1717887519796", [ null, {} @@ -377227,7 +377275,7 @@ ] ], "font-relative-units.html": [ - "b06951012e75ad741baf55b0675ab7867acbb6ea", + "2bd9eff0e0e0e6c280093e36819ae55be1635272", [ null, {} @@ -387829,6 +387877,27 @@ {} ] ], + "highlight-currentcolor-computed-inheritance.html": [ + "d67ae828818aab04a61d7e55cbdfb23222277f93", + [ + null, + {} + ] + ], + "highlight-currentcolor-computed-visited.html": [ + "207cb7b7dd1301672d550f63b2b91827bd57c6f1", + [ + null, + {} + ] + ], + "highlight-currentcolor-computed.html": [ + "97c31809dfc76cd3fdbd051e66fd7ec162f3708e", + [ + null, + {} + ] + ], "highlight-pseudos-computed.html": [ "f0d848e19c959293b8f0e03aee627914d3a9236c", [ @@ -387836,27 +387905,6 @@ {} ] ], - "highlight-pseudos-currentcolor-computed-001.html": [ - "2f8bbd4dec345a11a7b4305f85301009e11b22f5", - [ - null, - {} - ] - ], - "highlight-pseudos-currentcolor-inheritance-computed-001.html": [ - "673aeb8bcab5e998d1a88c7f49478c13bfb660f4", - [ - null, - {} - ] - ], - "highlight-pseudos-currentcolor-visited-computed-001.html": [ - "332fc9e55e15aba4d8af2fb2cdb26d5b6ab9a34d", - [ - null, - {} - ] - ], "highlight-pseudos-inheritance-computed-001.html": [ "84c4045a54c76f88e8ab59e8be4a0e601a580f2f", [ @@ -399209,7 +399257,7 @@ ] ], "sin-cos-tan-serialize.html": [ - "278940bdd7def9190a24561f0565275e95504cc4", + "e5d57c133fb95f67e7073dba12b547287d2a17cc", [ null, {} @@ -400489,6 +400537,13 @@ {} ] ], + "cssstyledeclaration-cssfontrule.tentative.html": [ + "2efab276c5bf3a7e66be5bdd0ae1c4d6b697944b", + [ + null, + {} + ] + ], "cssstyledeclaration-csstext-final-delimiter.html": [ "01b0a32c3fe2739f70377d7673b54a5fa7c50d61", [ @@ -400664,6 +400719,13 @@ {} ] ], + "getComputedStyle-getter-v-properties.tentative.html": [ + "e61241e57098de35a62554b6154f53e0a198bbe1", + [ + null, + {} + ] + ], "getComputedStyle-insets-absolute.html": [ "fae0a84a7b4a554b6cc182f48aee98bc7c196ad4", [ @@ -400904,6 +400966,13 @@ {} ] ], + "property-accessors.html": [ + "87c9df0b32401ae0b3ae7b58302f826304b015ac", + [ + null, + {} + ] + ], "rule-restrictions.html": [ "ce2dee37a0aa676882369d16ca589727a2c5fda9", [ @@ -402647,7 +402716,7 @@ ] ], "relative-units-005.html": [ - "91f85eca6d5dc5e64f45cf98a6e96a1028717f9a", + "8b344743dfc854563cc0ff42ac91cff6ea5d3112", [ null, {} @@ -409777,6 +409846,183 @@ {} ] ], + "formatblock-preserving-selection.tentative.html": [ + "d10e80b4ea67aed4a0884c04c337d4f52eacc622", + [ + "editing/other/formatblock-preserving-selection.tentative.html?styleWithCSS=false&block=address", + { + "testdriver": true, + "timeout": "long" + } + ], + [ + "editing/other/formatblock-preserving-selection.tentative.html?styleWithCSS=false&block=article", + { + "testdriver": true, + "timeout": "long" + } + ], + [ + "editing/other/formatblock-preserving-selection.tentative.html?styleWithCSS=false&block=blockquote", + { + "testdriver": true, + "timeout": "long" + } + ], + [ + "editing/other/formatblock-preserving-selection.tentative.html?styleWithCSS=false&block=dd", + { + "testdriver": true, + "timeout": "long" + } + ], + [ + "editing/other/formatblock-preserving-selection.tentative.html?styleWithCSS=false&block=div", + { + "testdriver": true, + "timeout": "long" + } + ], + [ + "editing/other/formatblock-preserving-selection.tentative.html?styleWithCSS=false&block=dt", + { + "testdriver": true, + "timeout": "long" + } + ], + [ + "editing/other/formatblock-preserving-selection.tentative.html?styleWithCSS=false&block=h1", + { + "testdriver": true, + "timeout": "long" + } + ], + [ + "editing/other/formatblock-preserving-selection.tentative.html?styleWithCSS=false&block=li", + { + "testdriver": true, + "timeout": "long" + } + ], + [ + "editing/other/formatblock-preserving-selection.tentative.html?styleWithCSS=false&block=pre", + { + "testdriver": true, + "timeout": "long" + } + ], + [ + "editing/other/formatblock-preserving-selection.tentative.html?styleWithCSS=true&block=address", + { + "testdriver": true, + "timeout": "long" + } + ], + [ + "editing/other/formatblock-preserving-selection.tentative.html?styleWithCSS=true&block=article", + { + "testdriver": true, + "timeout": "long" + } + ], + [ + "editing/other/formatblock-preserving-selection.tentative.html?styleWithCSS=true&block=blockquote", + { + "testdriver": true, + "timeout": "long" + } + ], + [ + "editing/other/formatblock-preserving-selection.tentative.html?styleWithCSS=true&block=dd", + { + "testdriver": true, + "timeout": "long" + } + ], + [ + "editing/other/formatblock-preserving-selection.tentative.html?styleWithCSS=true&block=div", + { + "testdriver": true, + "timeout": "long" + } + ], + [ + "editing/other/formatblock-preserving-selection.tentative.html?styleWithCSS=true&block=dt", + { + "testdriver": true, + "timeout": "long" + } + ], + [ + "editing/other/formatblock-preserving-selection.tentative.html?styleWithCSS=true&block=h1", + { + "testdriver": true, + "timeout": "long" + } + ], + [ + "editing/other/formatblock-preserving-selection.tentative.html?styleWithCSS=true&block=li", + { + "testdriver": true, + "timeout": "long" + } + ], + [ + "editing/other/formatblock-preserving-selection.tentative.html?styleWithCSS=true&block=pre", + { + "testdriver": true, + "timeout": "long" + } + ] + ], + "indent-preserving-selection.tentative.html": [ + "b3fae41faf06b4b1a62ead587bdbbd9c253cded1", + [ + "editing/other/indent-preserving-selection.tentative.html?styleWithCSS=false", + { + "testdriver": true, + "timeout": "long" + } + ], + [ + "editing/other/indent-preserving-selection.tentative.html?styleWithCSS=true", + { + "testdriver": true, + "timeout": "long" + } + ] + ], + "insert-list-preserving-selection.tentative.html": [ + "b7faf4f27ae012f192ad919a20773d59cff2db00", + [ + "editing/other/insert-list-preserving-selection.tentative.html?styleWithCSS=false&command=insertOrderedList", + { + "testdriver": true, + "timeout": "long" + } + ], + [ + "editing/other/insert-list-preserving-selection.tentative.html?styleWithCSS=false&command=insertUnorderedList", + { + "testdriver": true, + "timeout": "long" + } + ], + [ + "editing/other/insert-list-preserving-selection.tentative.html?styleWithCSS=true&command=insertOrderedList", + { + "testdriver": true, + "timeout": "long" + } + ], + [ + "editing/other/insert-list-preserving-selection.tentative.html?styleWithCSS=true&command=insertUnorderedList", + { + "testdriver": true, + "timeout": "long" + } + ] + ], "insert-paragraph-in-void-element.tentative.html": [ "c4f788a55093476c3ee3545a9032e5709709194e", [ @@ -410274,6 +410520,65 @@ } ] ], + "justify-preserving-selection.tentative.html": [ + "94a63e8505bad22a43fb2c15af4cb252287bc5e2", + [ + "editing/other/justify-preserving-selection.tentative.html?styleWithCSS=false&command=justifyCenter", + { + "testdriver": true, + "timeout": "long" + } + ], + [ + "editing/other/justify-preserving-selection.tentative.html?styleWithCSS=false&command=justifyFull", + { + "testdriver": true, + "timeout": "long" + } + ], + [ + "editing/other/justify-preserving-selection.tentative.html?styleWithCSS=false&command=justifyLeft", + { + "testdriver": true, + "timeout": "long" + } + ], + [ + "editing/other/justify-preserving-selection.tentative.html?styleWithCSS=false&command=justifyRight", + { + "testdriver": true, + "timeout": "long" + } + ], + [ + "editing/other/justify-preserving-selection.tentative.html?styleWithCSS=true&command=justifyCenter", + { + "testdriver": true, + "timeout": "long" + } + ], + [ + "editing/other/justify-preserving-selection.tentative.html?styleWithCSS=true&command=justifyFull", + { + "testdriver": true, + "timeout": "long" + } + ], + [ + "editing/other/justify-preserving-selection.tentative.html?styleWithCSS=true&command=justifyLeft", + { + "testdriver": true, + "timeout": "long" + } + ], + [ + "editing/other/justify-preserving-selection.tentative.html?styleWithCSS=true&command=justifyRight", + { + "testdriver": true, + "timeout": "long" + } + ] + ], "keeping-attributes-at-joining-elements.tentative.html": [ "99a0dab56ab43d8f9e96b7b6d9bc3a55f2d36210", [ @@ -410368,6 +410673,23 @@ {} ] ], + "outdent-preserving-selection.tentative.html": [ + "9f299bda49349947e328294562280689612e675e", + [ + "editing/other/outdent-preserving-selection.tentative.html?styleWithCSS=false", + { + "testdriver": true, + "timeout": "long" + } + ], + [ + "editing/other/outdent-preserving-selection.tentative.html?styleWithCSS=true", + { + "testdriver": true, + "timeout": "long" + } + ] + ], "recursive-exec-command-calls.tentative.html": [ "60a3b03099f358cf88e8e10c67347d9322cc9124", [ @@ -471142,6 +471464,13 @@ ] ], "the-autofocus-attribute": { + "autofocus-dialog.html": [ + "08a0913f42ff91f62af9b19e8c9a3959b63caffa", + [ + null, + {} + ] + ], "autofocus-in-not-fully-active-document.html": [ "a26a44dbfb6e8c3eb81c7b216f9aa1c0da8bb9ed", [ @@ -478487,7 +478816,7 @@ {} ] ], - "range-restore-oninput-onchange-event.html": [ + "range-restore-oninput-onchange-event.https.html": [ "f73c5e6f635f870286d75838f0a6df30a20a8d5a", [ null, @@ -480120,7 +480449,7 @@ ] ], "popup-hover-hide.tentative.html": [ - "e04c538f24da9aae33a8027cf63a3ea5a11e5197", + "64a81a449fe5eccb846461420f3cfed574f83972", [ null, { @@ -480130,7 +480459,7 @@ ] ], "popup-hoverpopup-attribute.tentative.html": [ - "b34e6df3f0d11883dac13949e78df609f2aca85e", + "56646d4a22032f4ef3725cc6312ac889688ceccf", [ null, { @@ -480157,7 +480486,7 @@ ] ], "popup-light-dismiss.tentative.html": [ - "2e94eedf1aa2821209765b56521e868828d2d24d", + "75539b08cfe26b7b2080747147a99d5283e6ce75", [ null, { @@ -492267,7 +492596,7 @@ ] ], "observe-css-generated-text.html": [ - "529e8eccded1ad1558e8519face535f35086333a", + "4869f4298cdde6fd7a6604c6a4cbf126cfa9b282", [ null, {} @@ -524971,7 +525300,7 @@ ] ], "block-view-timeline-current-time.tentative.html": [ - "6e60db2768b6a9cb2801d3beb51eb907b0e48c11", + "878b4a549a0876c2d218c797ee14ea1079c7a9fd", [ null, {} @@ -524985,7 +525314,7 @@ ] ], "inline-view-timeline-current-time.tentative.html": [ - "4cd6394e33f19f1995ae29560ee6c4248988f20a", + "538bffb1a3bf8dde2f7f9e582fe6ec5a217e5ade", [ null, {} @@ -539082,6 +539411,13 @@ {} ] ], + "SVGLength-ic.html": [ + "ed8a636411e956370868a340b19f7a809b347f35", + [ + null, + {} + ] + ], "SVGLength-px-with-context.html": [ "067948d5454d3b0ca715e58f72f7ab1840a4712d", [ @@ -551558,6 +551894,15 @@ } }, "webauthn": { + "conditional-mediation.https.html": [ + "0bec08ce45eddb1a336f421da4ed9a29b268453f", + [ + null, + { + "testdriver": true + } + ] + ], "createcredential-attachment.https.html": [ "e9458ad5604875e2ba430647cd434e561556a675", [
diff --git a/third_party/blink/web_tests/external/wpt/css/css-conditional/js/CSS-supports-L3.html b/third_party/blink/web_tests/external/wpt/css/css-conditional/js/CSS-supports-L3.html index 4c92275d0..f949334 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-conditional/js/CSS-supports-L3.html +++ b/third_party/blink/web_tests/external/wpt/css/css-conditional/js/CSS-supports-L3.html
@@ -6,6 +6,10 @@ <script src="/resources/testharnessreport.js"></script> <script> test(function() { + assert_equals(CSS.supports("(color: red)"), true); + }, "Single-argument form allows for declarations with enclosing parentheses"); + + test(function() { assert_equals(CSS.supports("color: red"), true); }, "Single-argument form allows for declarations without enclosing parentheses"); @@ -26,18 +30,51 @@ }, "Variable references in an unknown function always parse"); test(function() { + // no one-arg test for this as the with/without enclosing parentheses tests do this assert_equals(CSS.supports("color", "red"), true); }, "two argument form succeeds for known property"); test(function() { + assert_equals(CSS.supports("unknownproperty: blah"), false); + }, "one argument form fails for unknown property"); + + test(function() { assert_equals(CSS.supports("unknownproperty", "blah"), false); }, "two argument form fails for unknown property"); test(function() { + // https://github.com/w3c/csswg-drafts/issues/5929 + assert_equals(CSS.supports("unicode-range: U+0-7F"), false); + }, "one argument form fails for unknown property (but known descriptor)"); + + test(function() { + // https://github.com/w3c/csswg-drafts/issues/5929 + assert_equals(CSS.supports("unicode-range", "U+0-7F"), false); + }, "two argument form fails for unknown property (but known descriptor)"); + + test(function() { + // https://github.com/w3c/csswg-drafts/issues/5929 + assert_equals(CSS.supports("unicode-range: inherit"), false); + }, "one argument form fails for unknown property (but known descriptor, universal value)"); + + test(function() { + // https://github.com/w3c/csswg-drafts/issues/5929 + assert_equals(CSS.supports("unicode-range", "inherit"), false); + }, "two argument form fails for unknown property (but known descriptor, universal value)"); + + test(function() { + assert_equals(CSS.supports("width: blah"), false); + }, "one argument form fails for invalid value"); + + test(function() { assert_equals(CSS.supports("width", "blah"), false); }, "two argument form fails for invalid value"); test(function() { + assert_equals(CSS.supports("--foo: blah"), true); + }, "one argument form succeeds for custom property"); + + test(function() { assert_equals(CSS.supports("--foo", "blah"), true); }, "two argument form succeeds for custom property"); </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-pseudos-currentcolor-inheritance-computed-001.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-currentcolor-computed-inheritance.html similarity index 74% rename from third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-pseudos-currentcolor-inheritance-computed-001.html rename to third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-currentcolor-computed-inheritance.html index 673aeb8b..d67ae82 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-pseudos-currentcolor-inheritance-computed-001.html +++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-currentcolor-computed-inheritance.html
@@ -1,6 +1,7 @@ <!doctype html> <meta charset="utf-8"> <title>CSS Pseudo-Elements Test: highlight selectors inheritance getComputedStyle for currentcolor</title> +<meta name="assert" content="Checks the result of getComputedStyle for each kind of highlight pseudo, when ‘color’ and ‘background-color’ are set to ‘currentColor’ in the parent. The child should inherit both properties as if if they were directly set to ‘currentColor’, due to highlight inheritance and the fact that ‘currentColor’ computes to itself, and the result for both properties should equal the originating element ‘color’."> <link rel="help" href="https://drafts.csswg.org/css-pseudo/#highlight-selectors"> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-pseudos-currentcolor-visited-computed-001.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-currentcolor-computed-visited.html similarity index 77% rename from third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-pseudos-currentcolor-visited-computed-001.html rename to third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-currentcolor-computed-visited.html index 332fc9e5..207cb7b 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-pseudos-currentcolor-visited-computed-001.html +++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-currentcolor-computed-visited.html
@@ -1,6 +1,7 @@ <!doctype html> <meta charset="utf-8"> <title>CSS Pseudo-Elements Test: highlight selectors getComputedStyle for currentcolor on visited</title> +<meta name="assert" content="Checks the result of getComputedStyle for each kind of highlight pseudo, when ‘color’ is set to ‘currentColor’ for visited links (and for unvisited links, via implicit defaulting up to the root). The result for both links should equal the originating element ‘color’ as if the link was unvisited."> <link rel="help" href="https://drafts.csswg.org/css-pseudo/#highlight-selectors"> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-pseudos-currentcolor-computed-001.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-currentcolor-computed.html similarity index 87% rename from third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-pseudos-currentcolor-computed-001.html rename to third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-currentcolor-computed.html index 2f8bbd4d..97c31809d 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-pseudos-currentcolor-computed-001.html +++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-currentcolor-computed.html
@@ -1,6 +1,7 @@ <!doctype html> <meta charset="utf-8"> <title>CSS Pseudo-Elements Test: highlight selectors getComputedStyle for currentcolor</title> +<meta name="assert" content="Checks the result of getComputedStyle for each kind of highlight pseudo, when ‘color’ and ‘background-color’ are set to ‘currentColor’. The result for both properties should equal the originating element ‘color’."> <link rel="help" href="https://drafts.csswg.org/css-pseudo/#highlight-selectors"> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-painting-currentcolor-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-currentcolor-painting-properties-001-ref.html similarity index 81% rename from third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-painting-currentcolor-001-ref.html rename to third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-currentcolor-painting-properties-001-ref.html index 979e54a..47a0280 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-painting-currentcolor-001-ref.html +++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-currentcolor-painting-properties-001-ref.html
@@ -25,13 +25,6 @@ #textshadow-currentcolor > span { text-shadow: currentcolor 2px 2px; } -#textfillcolor-currentcolor > span { - -webkit-text-fill-color: currentcolor; -} -#textstrokecolor-currentcolor > span { - -webkit-text-stroke-width: 1px; - -webkit-text-stroke-color: currentcolor; -} #color-currentcolor-backgroundcolor-currentcolor > span { color: currentcolor; background-color: currentcolor; @@ -51,8 +44,6 @@ <div id="backgroundcolor-currentcolor" class="highlight_reftest"><span>example</span> - backgroundcolor-currentcolor</div> <div id="textdecorationcolor-currentcolor" class="highlight_reftest"><span>example</span> - textdecorationcolor-currentcolor</div> <div id="textshadow-currentcolor" class="highlight_reftest"><span>example</span> - textshadow-currentcolor</div> -<div id="textfillcolor-currentcolor" class="highlight_reftest"><span>example</span> - textfillcolor-currentcolor</div> -<div id="textstrokecolor-currentcolor" class="highlight_reftest"><span>example</span> - textstrokecolor-currentcolor</div> <div id="color-currentcolor-backgroundcolor-currentcolor" class="highlight_reftest"><span>example</span> - color-currentcolor-backgroundcolor-currentcolor</div> <div id="color-currentcolor-backgroundcolor-blue" class="highlight_reftest"><span>example</span> - color-currentcolor-backgroundcolor-blue</div> <div id="color-blue-backgroundcolor-currentcolor" class="highlight_reftest"><span>example</span> - color-blue-backgroundcolor-currentcolor</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-painting-currentcolor-001.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-currentcolor-painting-properties-001.html similarity index 76% rename from third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-painting-currentcolor-001.html rename to third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-currentcolor-painting-properties-001.html index da79d2d..94e7e9b 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-painting-currentcolor-001.html +++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-currentcolor-painting-properties-001.html
@@ -1,10 +1,10 @@ <!DOCTYPE html> <meta charset="utf-8" /> <title>CSS Pseudo-Elements Test: Custom Highlights currentcolor painting single layer</title> +<meta name="assert" content="Checks the painting for highlight pseudos (using ::highlight), when other properties are set to ‘currentColor’ (and ‘color’ is also ‘currentColor’, via implicit defaulting up to the root). The color of each property should equal the originating element ‘color’."> <link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com"> <link rel="help" href="https://drafts.csswg.org/css-pseudo/#highlight-text"> -<meta name="assert" content="Checks that currentcolor is properly resolved for the different color properites allowed for highlight pseudos (using custom highlights in this test), when we have only one highlight."> -<link rel="match" href="highlight-painting-currentcolor-001-ref.html"> +<link rel="match" href="highlight-currentcolor-painting-properties-001-ref.html"> <link rel="stylesheet" href="support/highlights.css"> <style> div { @@ -27,13 +27,6 @@ ::highlight(textshadow-currentcolor) { text-shadow: currentcolor 2px 2px; } -::highlight(textfillcolor-currentcolor) { - -webkit-text-fill-color: currentcolor; -} -::highlight(textstrokecolor-currentcolor) { - -webkit-text-stroke-width: 1px; - -webkit-text-stroke-color: currentcolor; -} ::highlight(color-currentcolor-backgroundcolor-currentcolor) { color: currentcolor; background-color: currentcolor; @@ -53,8 +46,6 @@ <div id="backgroundcolor-currentcolor" class="highlight_reftest">example - backgroundcolor-currentcolor</div> <div id="textdecorationcolor-currentcolor" class="highlight_reftest">example - textdecorationcolor-currentcolor</div> <div id="textshadow-currentcolor" class="highlight_reftest">example - textshadow-currentcolor</div> -<div id="textfillcolor-currentcolor" class="highlight_reftest">example - textfillcolor-currentcolor</div> -<div id="textstrokecolor-currentcolor" class="highlight_reftest">example - textstrokecolor-currentcolor</div> <div id="color-currentcolor-backgroundcolor-currentcolor" class="highlight_reftest">example - color-currentcolor-backgroundcolor-currentcolor</div> <div id="color-currentcolor-backgroundcolor-blue" class="highlight_reftest">example - color-currentcolor-backgroundcolor-blue</div> <div id="color-blue-backgroundcolor-currentcolor" class="highlight_reftest">example - color-blue-backgroundcolor-currentcolor</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-painting-currentcolor-002-ref.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-currentcolor-painting-properties-002-ref.html similarity index 81% rename from third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-painting-currentcolor-002-ref.html rename to third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-currentcolor-painting-properties-002-ref.html index 8a61e9c..19556f6 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-painting-currentcolor-002-ref.html +++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-currentcolor-painting-properties-002-ref.html
@@ -29,13 +29,6 @@ #textshadow-currentcolor > span > span { text-shadow: currentcolor 2px 2px; } -#textfillcolor-currentcolor > span > span { - -webkit-text-fill-color: currentcolor; -} -#textstrokecolor-currentcolor > span > span { - -webkit-text-stroke-width: 1px; - -webkit-text-stroke-color: currentcolor; -} #color-currentcolor-backgroundcolor-currentcolor > span > span { color: currentcolor; background-color: currentcolor; @@ -55,8 +48,6 @@ <div id="backgroundcolor-currentcolor" class="highlight_reftest"><span><span>ex</span>ample</span> - backgroundcolor-currentcolor</div> <div id="textdecorationcolor-currentcolor" class="highlight_reftest"><span><span>ex</span>ample</span> - textdecorationcolor-currentcolor</div> <div id="textshadow-currentcolor" class="highlight_reftest"><span><span>ex</span>ample</span> - textshadow-currentcolor</div> -<div id="textfillcolor-currentcolor" class="highlight_reftest"><span><span>ex</span>ample</span> - textfillcolor-currentcolor</div> -<div id="textstrokecolor-currentcolor" class="highlight_reftest"><span><span>ex</span>ample</span> - textstrokecolor-currentcolor</div> <div id="color-currentcolor-backgroundcolor-currentcolor" class="highlight_reftest"><span><span>ex</span>ample</span> - color-currentcolor-backgroundcolor-currentcolor</div> <div id="color-currentcolor-backgroundcolor-blue" class="highlight_reftest"><span><span>ex</span>ample</span> - color-currentcolor-backgroundcolor-blue</div> <div id="color-blue-backgroundcolor-currentcolor" class="highlight_reftest"><span><span>ex</span>ample</span> - color-blue-backgroundcolor-currentcolor</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-painting-currentcolor-002.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-currentcolor-painting-properties-002.html similarity index 77% rename from third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-painting-currentcolor-002.html rename to third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-currentcolor-painting-properties-002.html index b3a27b7..7dbc624 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-painting-currentcolor-002.html +++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-currentcolor-painting-properties-002.html
@@ -1,10 +1,10 @@ <!DOCTYPE html> <meta charset="utf-8" /> <title>CSS Pseudo-Elements Test: Custom Highlights currentcolor painting two layers</title> +<meta name="assert" content="Checks the painting for highlight pseudos (using ::highlight), when other properties are set to ‘currentColor’ (and ‘color’ is also ‘currentColor’, via implicit defaulting up to the root), and there is another active highlight below. The color of each property should equal the underlying highlight ‘color’."> <link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com"> <link rel="help" href="https://drafts.csswg.org/css-pseudo/#highlight-text"> -<meta name="assert" content="Checks that currentcolor is properly resolved for the different color properites allowed for highlight pseudos (using custom highlights in this test), when we have two highlights one of top of the other."> -<link rel="match" href="highlight-painting-currentcolor-002-ref.html"> +<link rel="match" href="highlight-currentcolor-painting-properties-002-ref.html"> <link rel="stylesheet" href="support/highlights.css"> <style> div { @@ -31,13 +31,6 @@ ::highlight(textshadow-currentcolor) { text-shadow: currentcolor 2px 2px; } -::highlight(textfillcolor-currentcolor) { - -webkit-text-fill-color: currentcolor; -} -::highlight(textstrokecolor-currentcolor) { - -webkit-text-stroke-width: 1px; - -webkit-text-stroke-color: currentcolor; -} ::highlight(color-currentcolor-backgroundcolor-currentcolor) { color: currentcolor; background-color: currentcolor; @@ -57,8 +50,6 @@ <div id="backgroundcolor-currentcolor" class="highlight_reftest">example - backgroundcolor-currentcolor</div> <div id="textdecorationcolor-currentcolor" class="highlight_reftest">example - textdecorationcolor-currentcolor</div> <div id="textshadow-currentcolor" class="highlight_reftest">example - textshadow-currentcolor</div> -<div id="textfillcolor-currentcolor" class="highlight_reftest">example - textfillcolor-currentcolor</div> -<div id="textstrokecolor-currentcolor" class="highlight_reftest">example - textstrokecolor-currentcolor</div> <div id="color-currentcolor-backgroundcolor-currentcolor" class="highlight_reftest">example - color-currentcolor-backgroundcolor-currentcolor</div> <div id="color-currentcolor-backgroundcolor-blue" class="highlight_reftest">example - color-currentcolor-backgroundcolor-blue</div> <div id="color-blue-backgroundcolor-currentcolor" class="highlight_reftest">example - color-blue-backgroundcolor-currentcolor</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-painting-currentcolor-003-ref.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-currentcolor-root-explicit-default-001-ref.html similarity index 100% rename from third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-painting-currentcolor-003-ref.html rename to third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-currentcolor-root-explicit-default-001-ref.html
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-painting-currentcolor-003.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-currentcolor-root-explicit-default-001.html similarity index 86% rename from third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-painting-currentcolor-003.html rename to third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-currentcolor-root-explicit-default-001.html index 935b8d1c..a1512f0 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-painting-currentcolor-003.html +++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-currentcolor-root-explicit-default-001.html
@@ -1,10 +1,10 @@ <!DOCTYPE html> <meta charset="utf-8" /> <title>CSS Pseudo-Elements Test: Custom Highlights currentcolor, initial, inherit, unset painting</title> +<meta name="assert" content="Checks the painting for highlight pseudos (using ::highlight), when ‘color’ is explicitly defaulted in a universal rule. ‘inherit’ (and ‘unset’, due to highlight inheritance) should equal the originating element ‘color’, because ‘color’ inherits through ancestor highlight pseudos up to the root, where the inherited value is defined as ‘currentColor’ for highlights. ‘initial’ should equal the initial value of ‘color’, which is ‘CanvasText’."> <link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com"> <link rel="help" href="https://drafts.csswg.org/css-pseudo/#highlight-text"> -<meta name="assert" content="Checks that color currentcolor, initial, inherit, unset are properly resolved when painting highlight pseudos."> -<link rel="match" href="highlight-painting-currentcolor-003-ref.html"> +<link rel="match" href="highlight-currentcolor-root-explicit-default-001-ref.html"> <link rel="stylesheet" href="support/highlights.css"> <style> div {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-painting-currentcolor-004-ref.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-currentcolor-root-explicit-default-002-ref.html similarity index 100% rename from third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-painting-currentcolor-004-ref.html rename to third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-currentcolor-root-explicit-default-002-ref.html
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-painting-currentcolor-004.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-currentcolor-root-explicit-default-002.html similarity index 72% rename from third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-painting-currentcolor-004.html rename to third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-currentcolor-root-explicit-default-002.html index f722369..fc5698f 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-painting-currentcolor-004.html +++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-currentcolor-root-explicit-default-002.html
@@ -1,10 +1,10 @@ <!DOCTYPE html> <meta charset="utf-8" /> <title>CSS Pseudo-Elements Test: Custom Highlights color inherit painting</title> +<meta name="assert" content="Checks the painting for highlight pseudos (using ::highlight), when ‘color’ is universally set to ‘inherit’. When the parent is explicitly set to ‘blue’, inheritance stops there, yielding blue. Otherwise inheritance reaches the root element, where the inherited value is defined as ‘currentColor’ for highlights, yielding green."> <link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com"> <link rel="help" href="https://drafts.csswg.org/css-pseudo/#highlight-text"> -<meta name="assert" content="Checks that color inherit is properly resolved when painting highlight pseudos. It works like currentcolor, unless some specific color has been defined."> -<link rel="match" href="highlight-painting-currentcolor-004-ref.html"> +<link rel="match" href="highlight-currentcolor-root-explicit-default-002-ref.html"> <link rel="stylesheet" href="support/highlights.css"> <style> .highlight_reftest {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-pseudos-currentcolor-inheritance-computed-002.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-currentcolor-root-implicit-default-001.html similarity index 65% rename from third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-pseudos-currentcolor-inheritance-computed-002.html rename to third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-currentcolor-root-implicit-default-001.html index 5336aa1..ecf787b 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-pseudos-currentcolor-inheritance-computed-002.html +++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-currentcolor-root-implicit-default-001.html
@@ -1,8 +1,9 @@ <!doctype html> <meta charset="utf-8"> <title>CSS Pseudo-Elements Test: implicit defaulting of ‘color’ in :root highlights</title> +<meta name="assert" content="Checks the painting for ::selection and ::highlight, when ‘background-color’ is set in the root element but ‘color’ is implicitly defaulted. ‘background-color’ suppresses the UA default ‘color’ for ::selection via paired cascade. The resultant ‘color’ inherits through ancestor highlight pseudos up to the root, where the inherited value is defined as ‘currentColor’ for highlights, yielding green."> <link rel="help" href="https://drafts.csswg.org/css-pseudo/#highlight-selectors"> -<link rel="match" href="reference/highlight-pseudos-currentcolor-inheritance-computed-002-ref.html"> +<link rel="match" href="highlight-currentcolor-root-implicit-default-ref.html"> <p>Pass if text below is green on lime, and the text itself represents green, not initial (black).</p> <main>FAIL</main> <main>FAIL</main>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-pseudos-currentcolor-inheritance-computed-003.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-currentcolor-root-implicit-default-002.html similarity index 66% rename from third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-pseudos-currentcolor-inheritance-computed-003.html rename to third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-currentcolor-root-implicit-default-002.html index cd49802..420cc5b 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-pseudos-currentcolor-inheritance-computed-003.html +++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-currentcolor-root-implicit-default-002.html
@@ -1,9 +1,10 @@ <!doctype html> <meta charset="utf-8"> <title>CSS Pseudo-Elements Test: implicit defaulting of ‘color’ in :root highlights</title> +<meta name="assert" content="Checks the painting for ::selection and ::highlight, when ‘background-color’ is set in the target element but ‘color’ is implicitly defaulted. ‘background-color’ suppresses the UA default ‘color’ for ::selection via paired cascade. The resultant ‘color’ inherits through ancestor highlight pseudos up to the root, where the inherited value is defined as ‘currentColor’ for highlights, yielding green."> <link rel="author" title="Delan Azabani" href="mailto:dazabani@igalia.com"> <link rel="help" href="https://drafts.csswg.org/css-pseudo/#highlight-selectors"> -<link rel="match" href="reference/highlight-pseudos-currentcolor-inheritance-computed-002-ref.html"> +<link rel="match" href="highlight-currentcolor-root-implicit-default-ref.html"> <p>Pass if text below is green on lime, and the text itself represents green, not initial (black).</p> <main>FAIL</main> <main>FAIL</main>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/reference/highlight-pseudos-currentcolor-inheritance-computed-002-ref.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-currentcolor-root-implicit-default-ref.html similarity index 100% rename from third_party/blink/web_tests/external/wpt/css/css-pseudo/reference/highlight-pseudos-currentcolor-inheritance-computed-002-ref.html rename to third_party/blink/web_tests/external/wpt/css/css-pseudo/highlight-currentcolor-root-implicit-default-ref.html
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom/cssstyledeclaration-cssfontrule.tentative.html b/third_party/blink/web_tests/external/wpt/css/cssom/cssstyledeclaration-cssfontrule.tentative.html new file mode 100644 index 0000000..2efab27 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/cssom/cssstyledeclaration-cssfontrule.tentative.html
@@ -0,0 +1,27 @@ +<!doctype html> +<meta charset="utf-8"> +<title>CSSStyleDeclaration for a CSSFontRule</title> +<link rel="help" href="https://drafts.csswg.org/cssom/#the-cssstyledeclaration-interface"> +<link rel="help" href="https://drafts.csswg.org/css-fonts-4/#cssfontfacerule"> +<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/5649#issuecomment-755796005"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<style> +@font-face {} +</style> +<script> + +const fontFaceRule = document.styleSheets[0].cssRules[0]; + +test(() => { + assert_true("unicode-range" in fontFaceRule.style); + assert_idl_attribute(fontFaceRule.style, "unicode-range"); +}, "a CSSStyleDeclaration for a CSSFontRule contains a unicode-range attribute"); + + +test(() => { + assert_true("flex-direction" in fontFaceRule.style); + assert_idl_attribute(fontFaceRule.style, "flex-direction"); +}, "a CSSStyleDeclaration for a CSSFontRule contains a flex-direction attribute"); + +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom/getComputedStyle-getter-v-properties.tentative.html b/third_party/blink/web_tests/external/wpt/css/cssom/getComputedStyle-getter-v-properties.tentative.html new file mode 100644 index 0000000..e61241e57 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/cssom/getComputedStyle-getter-v-properties.tentative.html
@@ -0,0 +1,34 @@ +<!doctype html> +<meta charset="utf-8"> +<title>CSSStyleDeclaration index getter v. attributes</title> +<link rel="help" href="https://drafts.csswg.org/cssom/#the-cssstyledeclaration-interface"> +<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/2529"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="testElement"></div> +<script> + +/* per spec, the indexed getter gives all supported longhand properties, whereas + attributes are created for all supported properties; this implies the indexed + getter gives a subset of the attributes */ + +const decl = window.getComputedStyle(document.getElementById("testElement")); +const declItems = Array.from(decl).sort(); + +const shorthands = ['border-top', 'border-right', 'border-bottom', 'border-left', 'border', 'font']; +const non_shorthands = ['margin-top', 'font-size', 'max-width', 'width']; + +for (const prop of shorthands) { + test(() => { + assert_true(prop in decl, "getComputedStyle attribute"); + assert_false(declItems.includes(prop), "getComputedStyle indexed getter"); + }, prop); +} + +for (const prop of non_shorthands) { + test(() => { + assert_true(prop in decl, "getComputedStyle attribute"); + assert_true(declItems.includes(prop), "getComputedStyle indexed getter"); + }, prop); +} +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom/property-accessors.html b/third_party/blink/web_tests/external/wpt/css/cssom/property-accessors.html new file mode 100644 index 0000000..87c9df0 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/cssom/property-accessors.html
@@ -0,0 +1,64 @@ +<!doctype html> +<html> +<meta charset="utf-8"> +<title>Accessing properties via CSSStyleDeclaration</title> +<link rel="help" href="https://drafts.csswg.org/cssom/#the-cssstyledeclaration-interface"> +<!-- this is really a crash test, but let's claim it's a testharness test --> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<style> +@font-face {} +</style> +<div id="testElement"></div> +<script> +// Goal here is to test a cross-section of prefixed, properties, and descriptors. +const properties = [ + "-apple-color-filter", "-apple-pay-button-style", "-epub-writing-mode", + "-webkit-flex", "gap", "grid-gap", "overscroll-behavior", + "src", "unicode-range", +]; + +const el = document.getElementById("testElement"); +const decls = [window.getComputedStyle(el), el.style, document.styleSheets[0].cssRules[0].style]; + +for (const prop of properties) { + test(() => { + for (const decl of decls) { + let _; + + _ = decl[prop]; + try { + decl[prop] = "nonsense"; + } catch { + assert_equals(decl, decls[0]); + } + + _ = decl.cssText; + try { + decl.cssText = `${prop}: nonsense`; + } catch { + assert_equals(decl, decls[0]); + } + + _ = decl.getPropertyValue(prop); + _ = decl.getPropertyPriority(prop); + + if ("getPropertyCSSValue" in decl) { + _ = decl.getPropertyCSSValue(prop); + } + + try { + decl.setProperty(prop, "nonsense", ""); + } catch { + assert_equals(decl, decls[0]); + } + + try { + decl.removeProperty(prop); + } catch { + assert_equals(decl, decls[0]); + } + } + }, prop); +} +</script>
diff --git a/third_party/blink/web_tests/external/wpt/editing/other/formatblock-preserving-selection.tentative.html b/third_party/blink/web_tests/external/wpt/editing/other/formatblock-preserving-selection.tentative.html new file mode 100644 index 0000000..d10e80b --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/editing/other/formatblock-preserving-selection.tentative.html
@@ -0,0 +1,136 @@ +<!doctype html> +<html> +<head> +<meta chareset="utf-8"> +<meta name="timeout" content="long"> +<meta name="variant" content="?styleWithCSS=false&block=address"> +<meta name="variant" content="?styleWithCSS=false&block=article"> +<meta name="variant" content="?styleWithCSS=false&block=blockquote"> +<meta name="variant" content="?styleWithCSS=false&block=dd"> +<meta name="variant" content="?styleWithCSS=false&block=div"> +<meta name="variant" content="?styleWithCSS=false&block=dt"> +<meta name="variant" content="?styleWithCSS=false&block=h1"> +<meta name="variant" content="?styleWithCSS=false&block=li"> +<meta name="variant" content="?styleWithCSS=false&block=pre"> +<meta name="variant" content="?styleWithCSS=true&block=address"> +<meta name="variant" content="?styleWithCSS=true&block=article"> +<meta name="variant" content="?styleWithCSS=true&block=blockquote"> +<meta name="variant" content="?styleWithCSS=true&block=dd"> +<meta name="variant" content="?styleWithCSS=true&block=div"> +<meta name="variant" content="?styleWithCSS=true&block=dt"> +<meta name="variant" content="?styleWithCSS=true&block=h1"> +<meta name="variant" content="?styleWithCSS=true&block=li"> +<meta name="variant" content="?styleWithCSS=true&block=pre"> +<title>Test preserving selection after formatBlock</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="../include/editor-test-utils.js"></script> +</head> +<body> +<div contenteditable></div> +<script> +"use strict"; + +const editor = document.querySelector("div[contenteditable]"); +const utils = new EditorTestUtils(editor); +const searchParams = new URLSearchParams(document.location.search); +const styleWithCSS = searchParams.get("styleWithCSS"); +const block = searchParams.get("block"); +document.execCommand("styleWithCSS", false, styleWithCSS); + +// Note that it's not scope of this test how browsers to convert the selected +// content to a block. + +// html: Initial HTML which will be set editor.innerHTML, it should contain +// selection range with a pair of "[" or "{" and "]" or "}". +// expectedSelectedString: After executing "outdent", compared with +// getSelection().toString().replace(/[ \n\r\t]+/g, "") +const tests = [ + { + html: "a[b]c", + expectedSelectedString: "b", + }, + { + html: "a[bc<br>de]f", + expectedSelectedString: "bcde", + }, + { + html: "<div>a[b]c</div>", + expectedSelectedString: "b", + }, + { + html: "<div>a[bc</div><div>de]f</div>", + expectedSelectedString: "bcde", + }, + { + html: "<div>a[bc<br>de]f</div>", + expectedSelectedString: "bcde", + }, + { + html: "<ul><li>a[b]c</li></ul>", + expectedSelectedString: "b", + }, + { + html: "<ul><li>a[bc</li><li>de]f</li></ul>", + expectedSelectedString: "bcde", + }, + { + html: "<ul><li>a[bc</li><li>de]f</li><li>ghi</li></ul>", + expectedSelectedString: "bcde", + }, + { + html: "<ul><li>abc</li><li>d[ef</li><li>gh]i</li></ul>", + expectedSelectedString: "efgh", + }, + { + html: "<ul><li>abc</li><li>d[ef</li></ul>" + + "<div>gh]i</div>", + expectedSelectedString: "efgh", + }, + { + html: "<div>a[bc</div>" + + "<ul><li>de]f</li><li>ghi</li></ul>", + expectedSelectedString: "bcde", + }, + { + html: "<table><tr><td>a[b]c</td></tr></table>", + expectedSelectedString: "b", + }, + { + html: "<table><tr><td>a[bc</td><td>de]f</td></tr></table>", + expectedSelectedString: "bcde", + }, + { + html: "<table><tr><td>a[bc</td></tr><tr><td>de]f</td></tr></table>", + expectedSelectedString: "bcde", + }, + { + html: "<div>a[bc</div>" + + "<table><tr><td>de]f</td></tr></table>", + expectedSelectedString: "bcde", + }, + { + html: "<table><tr><td>a[bc</td></tr></table>" + + "<div>de]f</div>", + expectedSelectedString: "bcde", + }, +]; + +for (const t of tests) { + test(() => { + utils.setupEditingHost(t.html); + document.execCommand("formatblock", false, block); + assert_equals( + getSelection().toString().replace(/[ \n\r\t]+/g, ""), + t.expectedSelectedString, + `Result: ${editor.innerHTML}` + ); + }, `Preserve selection after formatBlock with ${block} at ${t.html}`); +} + +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/editing/other/indent-preserving-selection.tentative.html b/third_party/blink/web_tests/external/wpt/editing/other/indent-preserving-selection.tentative.html new file mode 100644 index 0000000..b3fae41 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/editing/other/indent-preserving-selection.tentative.html
@@ -0,0 +1,103 @@ +<!doctype html> +<html> +<head> +<meta chareset="utf-8"> +<meta name="timeout" content="long"> +<meta name="variant" content="?styleWithCSS=false"> +<meta name="variant" content="?styleWithCSS=true"> +<title>Test preserving selection after indent</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="../include/editor-test-utils.js"></script> +</head> +<body> +<div contenteditable></div> +<script> +"use strict"; + +const editor = document.querySelector("div[contenteditable]"); +const utils = new EditorTestUtils(editor); +const styleWithCSS = + new URLSearchParams(document.location.search).get("styleWithCSS"); +document.execCommand("styleWithCSS", false, styleWithCSS); + +// Note that it's not scope of this test how browsers to indent the selected +// content. + +// html: Initial HTML which will be set editor.innerHTML, it should contain +// selection range with a pair of "[" or "{" and "]" or "}". +// expectedSelectedString: After executing "indent", compared with +// getSelection().toString().replace(/[ \n\r]+/g, "") +const tests = [ + { + html: "<div>a[b]c</div>", + expectedSelectedString: "b", + }, + { + html: "<div>a[bc</div><div>de]f</div>", + expectedSelectedString: "bcde", + }, + { + html: "<ul><li>a[b]c</li></ul>", + expectedSelectedString: "b", + }, + { + html: "<ul><li>a[bc</li><li>de]f</li></ul>", + expectedSelectedString: "bcde", + }, + { + html: "<div>a[bc</div>" + + "<ul><li>de]f</li></ul>", + expectedSelectedString: "bcde", + }, + { + html: "<ul><li>a[bc</li></ul>" + + "<ul><li>de]f</li></ul>", + expectedSelectedString: "bcde", + }, + { + html: "<ul><li>abc</li><li>d[ef</li></ul>" + + "<ul><li>gh]i</li></ul>", + expectedSelectedString: "efgh", + }, + { + html: "<ul><li>abc</li><li>d[ef</li></ul>" + + "<ul><li>gh]i</li><li>jkl</li></ul>", + expectedSelectedString: "efgh", + }, + { + html: "<ul><ul><li>a[bc</li></ul><li>de]f</li></ul>", + expectedSelectedString: "bcde", + }, + { + html: "<ol><ul><li>a[bc</li></ul><li>de]f</li></ol>", + expectedSelectedString: "bcde", + }, + { + html: "<ul><li>a[bc</li><ul><li>de]f</li></ul></ul>", + expectedSelectedString: "bcde", + }, + { + html: "<ol><li>a[bc</li><ul><li>de]f</li></ul></ol>", + expectedSelectedString: "bcde", + }, +]; + +for (const t of tests) { + test(() => { + utils.setupEditingHost(t.html); + document.execCommand("indent"); + assert_equals( + getSelection().toString().replace(/[ \n\r]+/g, ""), + t.expectedSelectedString, + `Result: ${editor.innerHTML}` + ); + }, `Preserve selection after indent at ${t.html}`); +} + +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/editing/other/insert-list-preserving-selection.tentative.html b/third_party/blink/web_tests/external/wpt/editing/other/insert-list-preserving-selection.tentative.html new file mode 100644 index 0000000..b7faf4f2 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/editing/other/insert-list-preserving-selection.tentative.html
@@ -0,0 +1,155 @@ +<!doctype html> +<html> +<head> +<meta chareset="utf-8"> +<meta name="timeout" content="long"> +<meta name="variant" content="?styleWithCSS=false&command=insertOrderedList"> +<meta name="variant" content="?styleWithCSS=false&command=insertUnorderedList"> +<meta name="variant" content="?styleWithCSS=true&command=insertOrderedList"> +<meta name="variant" content="?styleWithCSS=true&command=insertUnorderedList"> +<title>Test preserving selection after insert*List</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="../include/editor-test-utils.js"></script> +</head> +<body> +<div contenteditable></div> +<script> +"use strict"; + +const editor = document.querySelector("div[contenteditable]"); +const utils = new EditorTestUtils(editor); +const searchParams = new URLSearchParams(document.location.search); +const styleWithCSS = searchParams.get("styleWithCSS"); +const command = searchParams.get("command"); +document.execCommand("styleWithCSS", false, styleWithCSS); + +// Note that it's not scope of this test how browsers to convert the selected +// content to a list. + +// html: Initial HTML which will be set editor.innerHTML, it should contain +// selection range with a pair of "[" or "{" and "]" or "}". +// expectedSelectedString: After executing "outdent", compared with +// getSelection().toString().replace(/[ \n\r\t]+/g, "") +const tests = [ + { + html: "<div>a[b]c</div>", + expectedSelectedString: "b", + }, + { + html: "<div>a[bc</div><div>de]f</div>", + expectedSelectedString: "bcde", + }, + { + html: "<div>a[bc<br>de]f</div>", + expectedSelectedString: "bcde", + }, + { + html: "<ul><li>a[b]c</li></ul>", + expectedSelectedString: "b", + }, + { + html: "<ul><li>a[bc</li><li>de]f</li></ul>", + expectedSelectedString: "bcde", + }, + { + html: "<ul><li>a[bc</li><li>de]f</li><li>ghi</li></ul>", + expectedSelectedString: "bcde", + }, + { + html: "<ul><li>abc</li><li>d[ef</li><li>gh]i</li></ul>", + expectedSelectedString: "efgh", + }, + { + html: "<ol><li>a[b]c</li></ol>", + expectedSelectedString: "b", + }, + { + html: "<ol><li>a[bc</li><li>de]f</li></ol>", + expectedSelectedString: "bcde", + }, + { + html: "<ol><li>a[bc</li><li>de]f</li><li>ghi</li></ol>", + expectedSelectedString: "bcde", + }, + { + html: "<ol><li>abc</li><li>d[ef</li><li>gh]i</li></ol>", + expectedSelectedString: "efgh", + }, + { + html: "<ul><li>a[bc</li></ul>" + + "<ul><li>de]f</li></ul>", + expectedSelectedString: "bcde", + }, + { + html: "<ol><li>a[bc</li></ol>" + + "<ul><li>de]f</li></ul>", + expectedSelectedString: "bcde", + }, + { + html: "<ul><li>a[bc</li></ul>" + + "<ol><li>de]f</li></ol>", + expectedSelectedString: "bcde", + }, + { + html: "<div>a[bc</div>" + + "<ul><li>de]f</li><li>ghi</li></ul>", + expectedSelectedString: "bcde", + }, + { + html: "<ul><li>abc</li><li>d[ef</li></ul>" + + "<div>gh]i</div>", + expectedSelectedString: "efgh", + }, + { + html: "<div>a[bc</div>" + + "<ol><li>de]f</li><li>ghi</li></ol>", + expectedSelectedString: "bcde", + }, + { + html: "<ol><li>abc</li><li>d[ef</li></ol>" + + "<div>gh]i</div>", + expectedSelectedString: "efgh", + }, + { + html: "<table><tr><td>a[b]c</td></tr></table>", + expectedSelectedString: "b", + }, + { + html: "<table><tr><td>a[bc</td><td>de]f</td></tr></table>", + expectedSelectedString: "bcde", + }, + { + html: "<table><tr><td>a[bc</td></tr><tr><td>de]f</td></tr></table>", + expectedSelectedString: "bcde", + }, + { + html: "<div>a[bc</div>" + + "<table><tr><td>de]f</td></tr></table>", + expectedSelectedString: "bcde", + }, + { + html: "<table><tr><td>a[bc</td></tr></table>" + + "<div>de]f</div>", + expectedSelectedString: "bcde", + }, +]; + +for (const t of tests) { + test(() => { + utils.setupEditingHost(t.html); + document.execCommand(command); + assert_equals( + getSelection().toString().replace(/[ \n\r\t]+/g, ""), + t.expectedSelectedString, + `Result: ${editor.innerHTML}` + ); + }, `Preserve selection after ${command} at ${t.html}`); +} + +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/editing/other/justify-preserving-selection.tentative.html b/third_party/blink/web_tests/external/wpt/editing/other/justify-preserving-selection.tentative.html new file mode 100644 index 0000000..94a63e85 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/editing/other/justify-preserving-selection.tentative.html
@@ -0,0 +1,148 @@ +<!doctype html> +<html> +<head> +<meta chareset="utf-8"> +<meta name="timeout" content="long"> +<meta name="variant" content="?styleWithCSS=false&command=justifyCenter"> +<meta name="variant" content="?styleWithCSS=false&command=justifyFull"> +<meta name="variant" content="?styleWithCSS=false&command=justifyLeft"> +<meta name="variant" content="?styleWithCSS=false&command=justifyRight"> +<meta name="variant" content="?styleWithCSS=true&command=justifyCenter"> +<meta name="variant" content="?styleWithCSS=true&command=justifyFull"> +<meta name="variant" content="?styleWithCSS=true&command=justifyLeft"> +<meta name="variant" content="?styleWithCSS=true&command=justifyRight"> +<title>Test preserving selection after justifying selected content</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="../include/editor-test-utils.js"></script> +</head> +<body> +<div contenteditable></div> +<script> +"use strict"; + +const editor = document.querySelector("div[contenteditable]"); +const utils = new EditorTestUtils(editor); +const searchParams = new URLSearchParams(document.location.search); +const styleWithCSS = searchParams.get("styleWithCSS"); +const command = searchParams.get("command"); +document.execCommand("styleWithCSS", false, styleWithCSS); + +// Note that it's not scope of this test how browsers to align the selected +// content. + +// html: Initial HTML which will be set editor.innerHTML, it should contain +// selection range with a pair of "[" or "{" and "]" or "}". +// expectedSelectedString: After executing "outdent", compared with +// getSelection().toString().replace(/[ \n\r\t]+/g, "") +const tests = [ + { + html: "<div>a[b]c</div>", + expectedSelectedString: "b", + }, + { + html: "<address>a[b]c</address>", // <address> cannot have align attribute + expectedSelectedString: "b", + }, + { + html: "<div>a[bc</div>" + + "<div>de]f</div>", + expectedSelectedString: "bcde", + }, + { + html: "<div>a[bc</div>" + + "<address>de]f</address>", + expectedSelectedString: "bcde", + }, + { + html: "<address>a[bc</address>" + + "<div>de]f</div>", + expectedSelectedString: "bcde", + }, + { + html: "<address>a[bc</address>" + + "<address>de]f</address>", + expectedSelectedString: "bcde", + }, + { + html: "<ul><li>a[b]c</li></ul>", + expectedSelectedString: "b", + }, + { + html: "<ul><li>a[bc</li><li>de]f</li></ul>", + expectedSelectedString: "bcde", + }, + { + html: "<ul><li>a[bc</li><li>de]f</li><li>ghi</li></ul>", + expectedSelectedString: "bcde", + }, + { + html: "<ul><li>abc</li><li>d[ef</li><li>gh]i</li></ul>", + expectedSelectedString: "efgh", + }, + { + html: "<ul><li>abc</li><li>d[e]f</li><li>ghi</li></ul>", + expectedSelectedString: "e", + }, + { + html: "<ul><li>a[bc</li></ul>" + + "<div>de]f</div>", + expectedSelectedString: "bcde", + }, + { + html: "<ul><li>abc</li><li>d[ef</li></ul>" + + "<div>gh]i</div>", + expectedSelectedString: "efgh", + }, + { + html: "<div>a[bc</div>" + + "<ul><li>de]f</li></ul>", + expectedSelectedString: "bcde", + }, + { + html: "<div>a[bc</div>" + + "<ul><li>de]f</li><li>ghi</li></ul>", + expectedSelectedString: "bcde", + }, + { + html: "<table><tr><td>a[b]c</td></tr></table>", + expectedSelectedString: "b", + }, + { + html: "<table><tr><td>a[bc</td><td>de]f</td></tr></table>", + expectedSelectedString: "bcde", + }, + { + html: "<table><tr><td>a[bc</td></tr><tr><td>de]f</td></tr></table>", + expectedSelectedString: "bcde", + }, + { + html: "<div>a[bc</div>" + + "<table><tr><td>de]f</td></tr></table>", + expectedSelectedString: "bcde", + }, + { + html: "<table><tr><td>a[bc</td></tr></table>" + + "<div>de]f</div>", + expectedSelectedString: "bcde", + }, +]; + +for (const t of tests) { + test(() => { + utils.setupEditingHost(t.html); + document.execCommand(command); + assert_equals( + getSelection().toString().replace(/[ \n\r\t]+/g, ""), + t.expectedSelectedString, + `Result: ${editor.innerHTML}` + ); + }, `Preserve selection after ${command} at ${t.html}`); +} + +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/editing/other/outdent-preserving-selection.tentative.html b/third_party/blink/web_tests/external/wpt/editing/other/outdent-preserving-selection.tentative.html new file mode 100644 index 0000000..9f299bd --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/editing/other/outdent-preserving-selection.tentative.html
@@ -0,0 +1,192 @@ +<!doctype html> +<html> +<head> +<meta chareset="utf-8"> +<meta name="timeout" content="long"> +<meta name="variant" content="?styleWithCSS=false"> +<meta name="variant" content="?styleWithCSS=true"> +<title>Test preserving selection after outdent</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="../include/editor-test-utils.js"></script> +</head> +<body> +<div contenteditable></div> +<script> +"use strict"; + +const editor = document.querySelector("div[contenteditable]"); +const utils = new EditorTestUtils(editor); +const styleWithCSS = + new URLSearchParams(document.location.search).get("styleWithCSS"); +document.execCommand("styleWithCSS", false, styleWithCSS); + +// Note that it's not scope of this test how browsers to outdent the selected +// content. + +// html: Initial HTML which will be set editor.innerHTML, it should contain +// selection range with a pair of "[" or "{" and "]" or "}". +// expectedSelectedString: After executing "outdent", compared with +// getSelection().toString().replace(/[ \n\r]+/g, "") +const tests = [ + { + html: "<blockquote>a[b]c</blockquote>", + expectedSelectedString: "b", + }, + { + html: "<blockquote><div>a[b]c</div></blockquote>", + expectedSelectedString: "b", + }, + { + html: "<blockquote><div>a[bc</div><div>de]f</div></blockquote>", + expectedSelectedString: "bcde", + }, + { + html: "<blockquote>a[bc</blockquote>" + + "<blockquote>de]f</blockquote>", + expectedSelectedString: "bcde", + }, + { + html: '<div style="margin-left:15px">a[b]c</div>', + expectedSelectedString: "b", + }, + { + html: '<div style="margin-left:15px">a[bc</div>' + + '<div style="margin-left:15px">de]f</div>', + expectedSelectedString: "bcde", + }, + { + html: "<ul><li>a[b]c</li></ul>", + expectedSelectedString: "b", + }, + { + html: "<ul><li>a[bc</li><li>de]f</li></ul>", + expectedSelectedString: "bcde", + }, + { + html: "<ol><ul><li>a[b]c</li></ul></ol>", + expectedSelectedString: "b", + }, + { + html: "<ol><ul><li>a[bc</li><li>de]f</li></ul></ol>", + expectedSelectedString: "bcde", + }, + { + html: "<ul><ul><li>a[b]c</li></ul></ul>", + expectedSelectedString: "b", + }, + { + html: "<ul><ul><li>a[bc</li><li>de]f</li></ul></ul>", + expectedSelectedString: "bcde", + }, + { + html: "<ol><li><ul><li>a[b]c</li></ul></li></ol>", + expectedSelectedString: "b", + }, + { + html: "<ol><li><ul><li>a[bc</li><li>de]f</li></ul></li></ol>", + expectedSelectedString: "bcde", + }, + { + html: "<ul><li><ul><li>a[b]c</li></ul></li></ul>", + expectedSelectedString: "b", + }, + { + html: "<ul><li><ul><li>a[bc</li><li>de]f</li></ul></li></ul>", + expectedSelectedString: "bcde", + }, + { + html: "<blockquote><div>a[bc</div></blockquote>" + + "<ul><ul><li>de]f</li></ul></ul>", + expectedSelectedString: "bcde", + }, + { + html: "<blockquote><div>a[bc</div></blockquote>" + + "<ol><ul><li>de]f</li></ul></ol>", + expectedSelectedString: "bcde", + }, + { + html: '<div style="margin-left:15px">a[bc</div>' + + "<ul><ul><li>de]f</li></ul></ul>", + expectedSelectedString: "bcde", + }, + { + html: "<blockquote><div>a[bc</div></blockquote>" + + "<ul><li><ul><li>de]f</li></ul></li></ul>", + expectedSelectedString: "bcde", + }, + { + html: "<blockquote><div>a[bc</div></blockquote>" + + "<ol><li><ul><li>de]f</li></ul></li></ol>", + expectedSelectedString: "bcde", + }, + { + html: "<ol><ul><li>a[bc</li></ul></ol>" + + "<blockquote><div>de]f</div></blockquote>", + expectedSelectedString: "bcde", + }, + { + html: "<ul><ul><li>a[bc</li></ul></ul>" + + '<div style="margin-left:15px">de]f</div>', + expectedSelectedString: "bcde", + }, + { + html: "<ul><li><ul><li>a[bc</li></ul></li></ul>" + + "<blockquote><div>de]f</div></blockquote>", + expectedSelectedString: "bcde", + }, + { + html: "<ol><li><ul><li>a[bc</li></ul></li></ol>" + + "<blockquote><div>de]f</div></blockquote>", + expectedSelectedString: "bcde", + }, + { + html: "<ul><li>a[bc</li></ul>" + + "<ul><li>de]f</li></ul>", + expectedSelectedString: "bcde", + }, + { + html: "<ul><li>abc</li><li>d[ef</li></ul>" + + "<ul><li>gh]i</li></ul>", + expectedSelectedString: "efgh", + }, + { + html: "<ul><li>abc</li><li>d[ef</li></ul>" + + "<ul><li>gh]i</li><li>jkl</li></ul>", + expectedSelectedString: "efgh", + }, + { + html: "<ol><li>a[bc</li></ol>" + + "<ul><li>de]f</li></ul>", + expectedSelectedString: "bcde", + }, + { + html: "<ol><li>abc</li><li>d[ef</li></ol>" + + "<ul><li>gh]i</li></ul>", + expectedSelectedString: "efgh", + }, + { + html: "<ol><li>abc</li><li>d[ef</li></ol>" + + "<ul><li>gh]i</li><li>jkl</li></ul>", + expectedSelectedString: "efgh", + }, +]; + +for (const t of tests) { + test(() => { + utils.setupEditingHost(t.html); + document.execCommand("outdent"); + assert_equals( + getSelection().toString().replace(/[ \n\r]+/g, ""), + t.expectedSelectedString, + `Result: ${editor.innerHTML}` + ); + }, `Preserve selection after outdent at ${t.html}`); +} + +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-input-element/range-restore-oninput-onchange-event.html b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-input-element/range-restore-oninput-onchange-event.https.html similarity index 100% rename from third_party/blink/web_tests/external/wpt/html/semantics/forms/the-input-element/range-restore-oninput-onchange-event.html rename to third_party/blink/web_tests/external/wpt/html/semantics/forms/the-input-element/range-restore-oninput-onchange-event.https.html
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-input-element/resources/range-restore-events.html.headers b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-input-element/resources/range-restore-events.html.headers new file mode 100644 index 0000000..4030ea1d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-input-element/resources/range-restore-events.html.headers
@@ -0,0 +1 @@ +Cache-Control: no-store
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-input-element/resources/text-restore-events.html.headers b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-input-element/resources/text-restore-events.html.headers new file mode 100644 index 0000000..4030ea1d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-input-element/resources/text-restore-events.html.headers
@@ -0,0 +1 @@ +Cache-Control: no-store
diff --git a/third_party/blink/web_tests/external/wpt/infrastructure/metadata/update_properties.json b/third_party/blink/web_tests/external/wpt/infrastructure/metadata/update_properties.json new file mode 100644 index 0000000..00909d9 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/infrastructure/metadata/update_properties.json
@@ -0,0 +1 @@ +{"properties": ["product"]}
diff --git a/third_party/blink/web_tests/external/wpt/webauthn/idlharness.https.window.js.ini b/third_party/blink/web_tests/external/wpt/webauthn/idlharness.https.window.js.ini index 0159ec7..757d47fb 100644 --- a/third_party/blink/web_tests/external/wpt/webauthn/idlharness.https.window.js.ini +++ b/third_party/blink/web_tests/external/wpt/webauthn/idlharness.https.window.js.ini
@@ -140,7 +140,7 @@ expected: PASS [PublicKeyCredential interface: operation isConditionalMediationAvailable()] - expected: FAIL + expected: PASS [PublicKeyCredential interface: operation toJSON()] expected: FAIL
diff --git a/third_party/blink/web_tests/fast/frames/frame-set-zoom-expected.html b/third_party/blink/web_tests/fast/frames/frame-set-zoom-expected.html index e35cb9d..d6f2da1 100644 --- a/third_party/blink/web_tests/fast/frames/frame-set-zoom-expected.html +++ b/third_party/blink/web_tests/fast/frames/frame-set-zoom-expected.html
@@ -3,7 +3,7 @@ <head> <title>Tests that framesets scale according to full page zoom</title> </head> - <frameset rows="120,*"> + <frameset rows="120,*" border="12"> <frame id="top_frame" src="data:text/html,<!DOCTYPE html><html><body></body></html>"> <frame id="bottom_frame" src="data:text/html,<!DOCTYPE html><html><body></body></html>"> </frameset>
diff --git a/third_party/blink/web_tests/fast/frames/frame-set-zoom.html b/third_party/blink/web_tests/fast/frames/frame-set-zoom.html index 090ba98..1166307f6 100644 --- a/third_party/blink/web_tests/fast/frames/frame-set-zoom.html +++ b/third_party/blink/web_tests/fast/frames/frame-set-zoom.html
@@ -9,7 +9,7 @@ }; </script> </head> - <frameset rows="100,*"> + <frameset rows="100,*" border="10"> <frame id="top_frame" src="data:text/html,<!DOCTYPE html><html><body></body></html>"> <frame id="bottom_frame" src="data:text/html,<!DOCTYPE html><html><body></body></html>"> </frameset>
diff --git a/third_party/blink/web_tests/fast/frames/frameset-resize-reset.html b/third_party/blink/web_tests/fast/frames/frameset-resize-reset.html new file mode 100644 index 0000000..63dee17 --- /dev/null +++ b/third_party/blink/web_tests/fast/frames/frameset-resize-reset.html
@@ -0,0 +1,46 @@ +<!DOCTYPE html> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script src="../../resources/testdriver.js"></script> +<script src="../../resources/testdriver-actions.js"></script> +<script src="../../resources/testdriver-vendor.js"></script> +<style> +body { margin: 0; } +iframe { border: none; } +</style> +<iframe srcdoc=" + <frameset border=10 rows='100,100' cols='100,100'> + <frame src='about:blank'></frame> + <frame src='about:blank'></frame> + <frame src='about:blank'></frame> + <frame src='about:blank'></frame> + </frameset>" style="width:210px; height:210px"> +</iframe> +<script> +promise_test(async () => { + await new Promise(resolve => { window.addEventListener('load', resolve, {once:true}); }); + const frames = document.querySelector('iframe').contentDocument.querySelectorAll('frame'); + assert_equals(frames[0].offsetHeight, 100); + assert_equals(frames[2].offsetHeight, 100); + + // Drag-down the horizontal border. + await new test_driver.Actions() + .pointerMove(42, 105) + .pointerDown() + .pointerMove(42, 150) + .addTick().send(); + assert_greater_than(frames[0].offsetHeight, 100); + assert_less_than(frames[2].offsetHeight, 100); + + // Move under the bottom of frames[2] ==> Reset + await new test_driver.Actions() + .pointerMove(42, 220).addTick().send(); + assert_equals(frames[0].offsetHeight, 100); + assert_equals(frames[2].offsetHeight, 100); + + await new test_driver.Actions() + .pointerMove(42, 150).pointerUp().addTick().send(); + assert_greater_than(frames[0].offsetHeight, 100); + assert_less_than(frames[2].offsetHeight, 100); +}, 'Test resizing after over-resizing'); +</script>
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/resources/register-source-and-trigger.php b/third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/resources/register-source-and-trigger.php new file mode 100644 index 0000000..692c484f --- /dev/null +++ b/third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/resources/register-source-and-trigger.php
@@ -0,0 +1,4 @@ +<?php +header('Attribution-Reporting-Register-Source: {"source_event_id":"0","destination":"https://a.example"}'); +header('Attribution-Reporting-Register-Trigger: {}'); +?>
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/source-and-trigger-headers.js b/third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/source-and-trigger-headers.js new file mode 100644 index 0000000..060414f --- /dev/null +++ b/third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/source-and-trigger-headers.js
@@ -0,0 +1,22 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +(async function(testRunner) { + const {page, dp} = await testRunner.startBlank( + `Test that an attributionsrc request that is eligible for sources and triggers triggers an issue when it tries to register a source and trigger together.`); + + await dp.Audits.enable(); + await page.navigate( + 'https://devtools.test:8443/inspector-protocol/attribution-reporting/resources/impression.html'); + await page.loadHTML(`<body>`); + + const issuePromise = dp.Audits.onceIssueAdded(); + await dp.Runtime.evaluate({ + expression: + `fetch('/inspector-protocol/attribution-reporting/resources/register-source-and-trigger.php',{headers:{'Attribution-Reporting-Eligible':'event-source,trigger'}})`, + }); + const issue = await issuePromise; + testRunner.log(issue.params.issue, 'Issue reported: ', ['request']); + testRunner.completeTest(); +})
diff --git a/third_party/blink/web_tests/http/tests/websocket/slow-tcp-close.html b/third_party/blink/web_tests/http/tests/websocket/slow-tcp-close.html index 62718984..f8af352 100644 --- a/third_party/blink/web_tests/http/tests/websocket/slow-tcp-close.html +++ b/third_party/blink/web_tests/http/tests/websocket/slow-tcp-close.html
@@ -16,9 +16,7 @@ // Chromium closes the connection after waiting 2 seconds. This is not // standardised. assert_less_than(elapsed, 3000, 'browser should have closed connection'); - - // TODO(ricea): Change this to true to align with other browsers. - assert_false(evt.wasClean, 'wasClean should be correct'); + assert_true(evt.wasClean, 'wasClean should be correct'); }); }, 'verify that the browser closes TCP connections when the server is slow'); </script>
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/css/css-pseudo/highlight-currentcolor-computed-inheritance-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/css/css-pseudo/highlight-currentcolor-computed-inheritance-expected.txt new file mode 100644 index 0000000..e12026b --- /dev/null +++ b/third_party/blink/web_tests/platform/generic/external/wpt/css/css-pseudo/highlight-currentcolor-computed-inheritance-expected.txt
@@ -0,0 +1,8 @@ +This is a testharness.js-based test. +FAIL getComputedStyle() for ::selection assert_equals: Background color is lime. expected "rgb(0, 255, 0)" but got "rgba(0, 0, 0, 0)" +FAIL getComputedStyle() for ::target-text assert_equals: Background color is lime. expected "rgb(0, 255, 0)" but got "rgba(0, 0, 0, 0)" +PASS getComputedStyle() for ::spelling-error +PASS getComputedStyle() for ::grammar-error +PASS getComputedStyle() for ::highlight(foo) +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/css/cssom/cssstyledeclaration-cssfontrule.tentative-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/css/cssom/cssstyledeclaration-cssfontrule.tentative-expected.txt new file mode 100644 index 0000000..3c086eba --- /dev/null +++ b/third_party/blink/web_tests/platform/generic/external/wpt/css/cssom/cssstyledeclaration-cssfontrule.tentative-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +FAIL a CSSStyleDeclaration for a CSSFontRule contains a unicode-range attribute assert_idl_attribute: property "unicode-range" found on object expected in prototype chain +FAIL a CSSStyleDeclaration for a CSSFontRule contains a flex-direction attribute assert_idl_attribute: property "flex-direction" found on object expected in prototype chain +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/editing/other/formatblock-preserving-selection.tentative_styleWithCSS=false_block=address-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/editing/other/formatblock-preserving-selection.tentative_styleWithCSS=false_block=address-expected.txt new file mode 100644 index 0000000..6009f23 --- /dev/null +++ b/third_party/blink/web_tests/platform/generic/external/wpt/editing/other/formatblock-preserving-selection.tentative_styleWithCSS=false_block=address-expected.txt
@@ -0,0 +1,19 @@ +This is a testharness.js-based test. +PASS Preserve selection after formatBlock with address at a[b]c +PASS Preserve selection after formatBlock with address at a[bc<br>de]f +PASS Preserve selection after formatBlock with address at <div>a[b]c</div> +PASS Preserve selection after formatBlock with address at <div>a[bc</div><div>de]f</div> +PASS Preserve selection after formatBlock with address at <div>a[bc<br>de]f</div> +PASS Preserve selection after formatBlock with address at <ul><li>a[b]c</li></ul> +PASS Preserve selection after formatBlock with address at <ul><li>a[bc</li><li>de]f</li></ul> +PASS Preserve selection after formatBlock with address at <ul><li>a[bc</li><li>de]f</li><li>ghi</li></ul> +PASS Preserve selection after formatBlock with address at <ul><li>abc</li><li>d[ef</li><li>gh]i</li></ul> +PASS Preserve selection after formatBlock with address at <ul><li>abc</li><li>d[ef</li></ul><div>gh]i</div> +PASS Preserve selection after formatBlock with address at <div>a[bc</div><ul><li>de]f</li><li>ghi</li></ul> +PASS Preserve selection after formatBlock with address at <table><tr><td>a[b]c</td></tr></table> +PASS Preserve selection after formatBlock with address at <table><tr><td>a[bc</td><td>de]f</td></tr></table> +PASS Preserve selection after formatBlock with address at <table><tr><td>a[bc</td></tr><tr><td>de]f</td></tr></table> +PASS Preserve selection after formatBlock with address at <div>a[bc</div><table><tr><td>de]f</td></tr></table> +FAIL Preserve selection after formatBlock with address at <table><tr><td>a[bc</td></tr></table><div>de]f</div> assert_equals: Result: <address><table><tbody><tr><td><address>abc</address></td></tr></tbody></table>def</address> expected "bcde" but got "bcdef" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/editing/other/formatblock-preserving-selection.tentative_styleWithCSS=false_block=article-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/editing/other/formatblock-preserving-selection.tentative_styleWithCSS=false_block=article-expected.txt new file mode 100644 index 0000000..59aba98 --- /dev/null +++ b/third_party/blink/web_tests/platform/generic/external/wpt/editing/other/formatblock-preserving-selection.tentative_styleWithCSS=false_block=article-expected.txt
@@ -0,0 +1,19 @@ +This is a testharness.js-based test. +PASS Preserve selection after formatBlock with article at a[b]c +PASS Preserve selection after formatBlock with article at a[bc<br>de]f +PASS Preserve selection after formatBlock with article at <div>a[b]c</div> +PASS Preserve selection after formatBlock with article at <div>a[bc</div><div>de]f</div> +PASS Preserve selection after formatBlock with article at <div>a[bc<br>de]f</div> +PASS Preserve selection after formatBlock with article at <ul><li>a[b]c</li></ul> +PASS Preserve selection after formatBlock with article at <ul><li>a[bc</li><li>de]f</li></ul> +PASS Preserve selection after formatBlock with article at <ul><li>a[bc</li><li>de]f</li><li>ghi</li></ul> +PASS Preserve selection after formatBlock with article at <ul><li>abc</li><li>d[ef</li><li>gh]i</li></ul> +PASS Preserve selection after formatBlock with article at <ul><li>abc</li><li>d[ef</li></ul><div>gh]i</div> +PASS Preserve selection after formatBlock with article at <div>a[bc</div><ul><li>de]f</li><li>ghi</li></ul> +PASS Preserve selection after formatBlock with article at <table><tr><td>a[b]c</td></tr></table> +PASS Preserve selection after formatBlock with article at <table><tr><td>a[bc</td><td>de]f</td></tr></table> +PASS Preserve selection after formatBlock with article at <table><tr><td>a[bc</td></tr><tr><td>de]f</td></tr></table> +PASS Preserve selection after formatBlock with article at <div>a[bc</div><table><tr><td>de]f</td></tr></table> +FAIL Preserve selection after formatBlock with article at <table><tr><td>a[bc</td></tr></table><div>de]f</div> assert_equals: Result: <article><table><tbody><tr><td><article>abc</article></td></tr></tbody></table>def</article> expected "bcde" but got "bcdef" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/editing/other/formatblock-preserving-selection.tentative_styleWithCSS=false_block=blockquote-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/editing/other/formatblock-preserving-selection.tentative_styleWithCSS=false_block=blockquote-expected.txt new file mode 100644 index 0000000..71423c0e --- /dev/null +++ b/third_party/blink/web_tests/platform/generic/external/wpt/editing/other/formatblock-preserving-selection.tentative_styleWithCSS=false_block=blockquote-expected.txt
@@ -0,0 +1,19 @@ +This is a testharness.js-based test. +PASS Preserve selection after formatBlock with blockquote at a[b]c +PASS Preserve selection after formatBlock with blockquote at a[bc<br>de]f +PASS Preserve selection after formatBlock with blockquote at <div>a[b]c</div> +PASS Preserve selection after formatBlock with blockquote at <div>a[bc</div><div>de]f</div> +PASS Preserve selection after formatBlock with blockquote at <div>a[bc<br>de]f</div> +PASS Preserve selection after formatBlock with blockquote at <ul><li>a[b]c</li></ul> +PASS Preserve selection after formatBlock with blockquote at <ul><li>a[bc</li><li>de]f</li></ul> +PASS Preserve selection after formatBlock with blockquote at <ul><li>a[bc</li><li>de]f</li><li>ghi</li></ul> +PASS Preserve selection after formatBlock with blockquote at <ul><li>abc</li><li>d[ef</li><li>gh]i</li></ul> +PASS Preserve selection after formatBlock with blockquote at <ul><li>abc</li><li>d[ef</li></ul><div>gh]i</div> +PASS Preserve selection after formatBlock with blockquote at <div>a[bc</div><ul><li>de]f</li><li>ghi</li></ul> +PASS Preserve selection after formatBlock with blockquote at <table><tr><td>a[b]c</td></tr></table> +PASS Preserve selection after formatBlock with blockquote at <table><tr><td>a[bc</td><td>de]f</td></tr></table> +PASS Preserve selection after formatBlock with blockquote at <table><tr><td>a[bc</td></tr><tr><td>de]f</td></tr></table> +PASS Preserve selection after formatBlock with blockquote at <div>a[bc</div><table><tr><td>de]f</td></tr></table> +FAIL Preserve selection after formatBlock with blockquote at <table><tr><td>a[bc</td></tr></table><div>de]f</div> assert_equals: Result: <blockquote><table><tbody><tr><td><blockquote>abc</blockquote></td></tr></tbody></table>def</blockquote> expected "bcde" but got "bcdef" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/editing/other/formatblock-preserving-selection.tentative_styleWithCSS=false_block=dd-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/editing/other/formatblock-preserving-selection.tentative_styleWithCSS=false_block=dd-expected.txt new file mode 100644 index 0000000..2830c1d --- /dev/null +++ b/third_party/blink/web_tests/platform/generic/external/wpt/editing/other/formatblock-preserving-selection.tentative_styleWithCSS=false_block=dd-expected.txt
@@ -0,0 +1,19 @@ +This is a testharness.js-based test. +PASS Preserve selection after formatBlock with dd at a[b]c +PASS Preserve selection after formatBlock with dd at a[bc<br>de]f +PASS Preserve selection after formatBlock with dd at <div>a[b]c</div> +PASS Preserve selection after formatBlock with dd at <div>a[bc</div><div>de]f</div> +PASS Preserve selection after formatBlock with dd at <div>a[bc<br>de]f</div> +PASS Preserve selection after formatBlock with dd at <ul><li>a[b]c</li></ul> +PASS Preserve selection after formatBlock with dd at <ul><li>a[bc</li><li>de]f</li></ul> +PASS Preserve selection after formatBlock with dd at <ul><li>a[bc</li><li>de]f</li><li>ghi</li></ul> +PASS Preserve selection after formatBlock with dd at <ul><li>abc</li><li>d[ef</li><li>gh]i</li></ul> +PASS Preserve selection after formatBlock with dd at <ul><li>abc</li><li>d[ef</li></ul><div>gh]i</div> +PASS Preserve selection after formatBlock with dd at <div>a[bc</div><ul><li>de]f</li><li>ghi</li></ul> +PASS Preserve selection after formatBlock with dd at <table><tr><td>a[b]c</td></tr></table> +PASS Preserve selection after formatBlock with dd at <table><tr><td>a[bc</td><td>de]f</td></tr></table> +PASS Preserve selection after formatBlock with dd at <table><tr><td>a[bc</td></tr><tr><td>de]f</td></tr></table> +PASS Preserve selection after formatBlock with dd at <div>a[bc</div><table><tr><td>de]f</td></tr></table> +FAIL Preserve selection after formatBlock with dd at <table><tr><td>a[bc</td></tr></table><div>de]f</div> assert_equals: Result: <dd><table><tbody><tr><td><dd>abc</dd></td></tr></tbody></table>def</dd> expected "bcde" but got "bcdef" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/editing/other/formatblock-preserving-selection.tentative_styleWithCSS=false_block=dt-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/editing/other/formatblock-preserving-selection.tentative_styleWithCSS=false_block=dt-expected.txt new file mode 100644 index 0000000..5216aef --- /dev/null +++ b/third_party/blink/web_tests/platform/generic/external/wpt/editing/other/formatblock-preserving-selection.tentative_styleWithCSS=false_block=dt-expected.txt
@@ -0,0 +1,19 @@ +This is a testharness.js-based test. +PASS Preserve selection after formatBlock with dt at a[b]c +PASS Preserve selection after formatBlock with dt at a[bc<br>de]f +PASS Preserve selection after formatBlock with dt at <div>a[b]c</div> +PASS Preserve selection after formatBlock with dt at <div>a[bc</div><div>de]f</div> +PASS Preserve selection after formatBlock with dt at <div>a[bc<br>de]f</div> +PASS Preserve selection after formatBlock with dt at <ul><li>a[b]c</li></ul> +PASS Preserve selection after formatBlock with dt at <ul><li>a[bc</li><li>de]f</li></ul> +PASS Preserve selection after formatBlock with dt at <ul><li>a[bc</li><li>de]f</li><li>ghi</li></ul> +PASS Preserve selection after formatBlock with dt at <ul><li>abc</li><li>d[ef</li><li>gh]i</li></ul> +PASS Preserve selection after formatBlock with dt at <ul><li>abc</li><li>d[ef</li></ul><div>gh]i</div> +PASS Preserve selection after formatBlock with dt at <div>a[bc</div><ul><li>de]f</li><li>ghi</li></ul> +PASS Preserve selection after formatBlock with dt at <table><tr><td>a[b]c</td></tr></table> +PASS Preserve selection after formatBlock with dt at <table><tr><td>a[bc</td><td>de]f</td></tr></table> +PASS Preserve selection after formatBlock with dt at <table><tr><td>a[bc</td></tr><tr><td>de]f</td></tr></table> +PASS Preserve selection after formatBlock with dt at <div>a[bc</div><table><tr><td>de]f</td></tr></table> +FAIL Preserve selection after formatBlock with dt at <table><tr><td>a[bc</td></tr></table><div>de]f</div> assert_equals: Result: <dt><table><tbody><tr><td><dt>abc</dt></td></tr></tbody></table>def</dt> expected "bcde" but got "bcdef" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/editing/other/formatblock-preserving-selection.tentative_styleWithCSS=false_block=h1-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/editing/other/formatblock-preserving-selection.tentative_styleWithCSS=false_block=h1-expected.txt new file mode 100644 index 0000000..7d23deff --- /dev/null +++ b/third_party/blink/web_tests/platform/generic/external/wpt/editing/other/formatblock-preserving-selection.tentative_styleWithCSS=false_block=h1-expected.txt
@@ -0,0 +1,19 @@ +This is a testharness.js-based test. +PASS Preserve selection after formatBlock with h1 at a[b]c +PASS Preserve selection after formatBlock with h1 at a[bc<br>de]f +PASS Preserve selection after formatBlock with h1 at <div>a[b]c</div> +PASS Preserve selection after formatBlock with h1 at <div>a[bc</div><div>de]f</div> +PASS Preserve selection after formatBlock with h1 at <div>a[bc<br>de]f</div> +PASS Preserve selection after formatBlock with h1 at <ul><li>a[b]c</li></ul> +PASS Preserve selection after formatBlock with h1 at <ul><li>a[bc</li><li>de]f</li></ul> +PASS Preserve selection after formatBlock with h1 at <ul><li>a[bc</li><li>de]f</li><li>ghi</li></ul> +PASS Preserve selection after formatBlock with h1 at <ul><li>abc</li><li>d[ef</li><li>gh]i</li></ul> +PASS Preserve selection after formatBlock with h1 at <ul><li>abc</li><li>d[ef</li></ul><div>gh]i</div> +PASS Preserve selection after formatBlock with h1 at <div>a[bc</div><ul><li>de]f</li><li>ghi</li></ul> +PASS Preserve selection after formatBlock with h1 at <table><tr><td>a[b]c</td></tr></table> +PASS Preserve selection after formatBlock with h1 at <table><tr><td>a[bc</td><td>de]f</td></tr></table> +PASS Preserve selection after formatBlock with h1 at <table><tr><td>a[bc</td></tr><tr><td>de]f</td></tr></table> +PASS Preserve selection after formatBlock with h1 at <div>a[bc</div><table><tr><td>de]f</td></tr></table> +FAIL Preserve selection after formatBlock with h1 at <table><tr><td>a[bc</td></tr></table><div>de]f</div> assert_equals: Result: <h1><table><tbody><tr><td><h1>abc</h1></td></tr></tbody></table>def</h1> expected "bcde" but got "bcdef" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/editing/other/formatblock-preserving-selection.tentative_styleWithCSS=false_block=pre-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/editing/other/formatblock-preserving-selection.tentative_styleWithCSS=false_block=pre-expected.txt new file mode 100644 index 0000000..e43f514 --- /dev/null +++ b/third_party/blink/web_tests/platform/generic/external/wpt/editing/other/formatblock-preserving-selection.tentative_styleWithCSS=false_block=pre-expected.txt
@@ -0,0 +1,19 @@ +This is a testharness.js-based test. +PASS Preserve selection after formatBlock with pre at a[b]c +PASS Preserve selection after formatBlock with pre at a[bc<br>de]f +PASS Preserve selection after formatBlock with pre at <div>a[b]c</div> +PASS Preserve selection after formatBlock with pre at <div>a[bc</div><div>de]f</div> +PASS Preserve selection after formatBlock with pre at <div>a[bc<br>de]f</div> +PASS Preserve selection after formatBlock with pre at <ul><li>a[b]c</li></ul> +PASS Preserve selection after formatBlock with pre at <ul><li>a[bc</li><li>de]f</li></ul> +PASS Preserve selection after formatBlock with pre at <ul><li>a[bc</li><li>de]f</li><li>ghi</li></ul> +PASS Preserve selection after formatBlock with pre at <ul><li>abc</li><li>d[ef</li><li>gh]i</li></ul> +PASS Preserve selection after formatBlock with pre at <ul><li>abc</li><li>d[ef</li></ul><div>gh]i</div> +PASS Preserve selection after formatBlock with pre at <div>a[bc</div><ul><li>de]f</li><li>ghi</li></ul> +PASS Preserve selection after formatBlock with pre at <table><tr><td>a[b]c</td></tr></table> +PASS Preserve selection after formatBlock with pre at <table><tr><td>a[bc</td><td>de]f</td></tr></table> +PASS Preserve selection after formatBlock with pre at <table><tr><td>a[bc</td></tr><tr><td>de]f</td></tr></table> +PASS Preserve selection after formatBlock with pre at <div>a[bc</div><table><tr><td>de]f</td></tr></table> +FAIL Preserve selection after formatBlock with pre at <table><tr><td>a[bc</td></tr></table><div>de]f</div> assert_equals: Result: <pre><table><tbody><tr><td><pre>abc</pre></td></tr></tbody></table>def</pre> expected "bcde" but got "bcdef" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/editing/other/formatblock-preserving-selection.tentative_styleWithCSS=true_block=address-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/editing/other/formatblock-preserving-selection.tentative_styleWithCSS=true_block=address-expected.txt new file mode 100644 index 0000000..6009f23 --- /dev/null +++ b/third_party/blink/web_tests/platform/generic/external/wpt/editing/other/formatblock-preserving-selection.tentative_styleWithCSS=true_block=address-expected.txt
@@ -0,0 +1,19 @@ +This is a testharness.js-based test. +PASS Preserve selection after formatBlock with address at a[b]c +PASS Preserve selection after formatBlock with address at a[bc<br>de]f +PASS Preserve selection after formatBlock with address at <div>a[b]c</div> +PASS Preserve selection after formatBlock with address at <div>a[bc</div><div>de]f</div> +PASS Preserve selection after formatBlock with address at <div>a[bc<br>de]f</div> +PASS Preserve selection after formatBlock with address at <ul><li>a[b]c</li></ul> +PASS Preserve selection after formatBlock with address at <ul><li>a[bc</li><li>de]f</li></ul> +PASS Preserve selection after formatBlock with address at <ul><li>a[bc</li><li>de]f</li><li>ghi</li></ul> +PASS Preserve selection after formatBlock with address at <ul><li>abc</li><li>d[ef</li><li>gh]i</li></ul> +PASS Preserve selection after formatBlock with address at <ul><li>abc</li><li>d[ef</li></ul><div>gh]i</div> +PASS Preserve selection after formatBlock with address at <div>a[bc</div><ul><li>de]f</li><li>ghi</li></ul> +PASS Preserve selection after formatBlock with address at <table><tr><td>a[b]c</td></tr></table> +PASS Preserve selection after formatBlock with address at <table><tr><td>a[bc</td><td>de]f</td></tr></table> +PASS Preserve selection after formatBlock with address at <table><tr><td>a[bc</td></tr><tr><td>de]f</td></tr></table> +PASS Preserve selection after formatBlock with address at <div>a[bc</div><table><tr><td>de]f</td></tr></table> +FAIL Preserve selection after formatBlock with address at <table><tr><td>a[bc</td></tr></table><div>de]f</div> assert_equals: Result: <address><table><tbody><tr><td><address>abc</address></td></tr></tbody></table>def</address> expected "bcde" but got "bcdef" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/editing/other/formatblock-preserving-selection.tentative_styleWithCSS=true_block=article-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/editing/other/formatblock-preserving-selection.tentative_styleWithCSS=true_block=article-expected.txt new file mode 100644 index 0000000..59aba98 --- /dev/null +++ b/third_party/blink/web_tests/platform/generic/external/wpt/editing/other/formatblock-preserving-selection.tentative_styleWithCSS=true_block=article-expected.txt
@@ -0,0 +1,19 @@ +This is a testharness.js-based test. +PASS Preserve selection after formatBlock with article at a[b]c +PASS Preserve selection after formatBlock with article at a[bc<br>de]f +PASS Preserve selection after formatBlock with article at <div>a[b]c</div> +PASS Preserve selection after formatBlock with article at <div>a[bc</div><div>de]f</div> +PASS Preserve selection after formatBlock with article at <div>a[bc<br>de]f</div> +PASS Preserve selection after formatBlock with article at <ul><li>a[b]c</li></ul> +PASS Preserve selection after formatBlock with article at <ul><li>a[bc</li><li>de]f</li></ul> +PASS Preserve selection after formatBlock with article at <ul><li>a[bc</li><li>de]f</li><li>ghi</li></ul> +PASS Preserve selection after formatBlock with article at <ul><li>abc</li><li>d[ef</li><li>gh]i</li></ul> +PASS Preserve selection after formatBlock with article at <ul><li>abc</li><li>d[ef</li></ul><div>gh]i</div> +PASS Preserve selection after formatBlock with article at <div>a[bc</div><ul><li>de]f</li><li>ghi</li></ul> +PASS Preserve selection after formatBlock with article at <table><tr><td>a[b]c</td></tr></table> +PASS Preserve selection after formatBlock with article at <table><tr><td>a[bc</td><td>de]f</td></tr></table> +PASS Preserve selection after formatBlock with article at <table><tr><td>a[bc</td></tr><tr><td>de]f</td></tr></table> +PASS Preserve selection after formatBlock with article at <div>a[bc</div><table><tr><td>de]f</td></tr></table> +FAIL Preserve selection after formatBlock with article at <table><tr><td>a[bc</td></tr></table><div>de]f</div> assert_equals: Result: <article><table><tbody><tr><td><article>abc</article></td></tr></tbody></table>def</article> expected "bcde" but got "bcdef" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/editing/other/formatblock-preserving-selection.tentative_styleWithCSS=true_block=blockquote-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/editing/other/formatblock-preserving-selection.tentative_styleWithCSS=true_block=blockquote-expected.txt new file mode 100644 index 0000000..71423c0e --- /dev/null +++ b/third_party/blink/web_tests/platform/generic/external/wpt/editing/other/formatblock-preserving-selection.tentative_styleWithCSS=true_block=blockquote-expected.txt
@@ -0,0 +1,19 @@ +This is a testharness.js-based test. +PASS Preserve selection after formatBlock with blockquote at a[b]c +PASS Preserve selection after formatBlock with blockquote at a[bc<br>de]f +PASS Preserve selection after formatBlock with blockquote at <div>a[b]c</div> +PASS Preserve selection after formatBlock with blockquote at <div>a[bc</div><div>de]f</div> +PASS Preserve selection after formatBlock with blockquote at <div>a[bc<br>de]f</div> +PASS Preserve selection after formatBlock with blockquote at <ul><li>a[b]c</li></ul> +PASS Preserve selection after formatBlock with blockquote at <ul><li>a[bc</li><li>de]f</li></ul> +PASS Preserve selection after formatBlock with blockquote at <ul><li>a[bc</li><li>de]f</li><li>ghi</li></ul> +PASS Preserve selection after formatBlock with blockquote at <ul><li>abc</li><li>d[ef</li><li>gh]i</li></ul> +PASS Preserve selection after formatBlock with blockquote at <ul><li>abc</li><li>d[ef</li></ul><div>gh]i</div> +PASS Preserve selection after formatBlock with blockquote at <div>a[bc</div><ul><li>de]f</li><li>ghi</li></ul> +PASS Preserve selection after formatBlock with blockquote at <table><tr><td>a[b]c</td></tr></table> +PASS Preserve selection after formatBlock with blockquote at <table><tr><td>a[bc</td><td>de]f</td></tr></table> +PASS Preserve selection after formatBlock with blockquote at <table><tr><td>a[bc</td></tr><tr><td>de]f</td></tr></table> +PASS Preserve selection after formatBlock with blockquote at <div>a[bc</div><table><tr><td>de]f</td></tr></table> +FAIL Preserve selection after formatBlock with blockquote at <table><tr><td>a[bc</td></tr></table><div>de]f</div> assert_equals: Result: <blockquote><table><tbody><tr><td><blockquote>abc</blockquote></td></tr></tbody></table>def</blockquote> expected "bcde" but got "bcdef" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/editing/other/formatblock-preserving-selection.tentative_styleWithCSS=true_block=dd-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/editing/other/formatblock-preserving-selection.tentative_styleWithCSS=true_block=dd-expected.txt new file mode 100644 index 0000000..2830c1d --- /dev/null +++ b/third_party/blink/web_tests/platform/generic/external/wpt/editing/other/formatblock-preserving-selection.tentative_styleWithCSS=true_block=dd-expected.txt
@@ -0,0 +1,19 @@ +This is a testharness.js-based test. +PASS Preserve selection after formatBlock with dd at a[b]c +PASS Preserve selection after formatBlock with dd at a[bc<br>de]f +PASS Preserve selection after formatBlock with dd at <div>a[b]c</div> +PASS Preserve selection after formatBlock with dd at <div>a[bc</div><div>de]f</div> +PASS Preserve selection after formatBlock with dd at <div>a[bc<br>de]f</div> +PASS Preserve selection after formatBlock with dd at <ul><li>a[b]c</li></ul> +PASS Preserve selection after formatBlock with dd at <ul><li>a[bc</li><li>de]f</li></ul> +PASS Preserve selection after formatBlock with dd at <ul><li>a[bc</li><li>de]f</li><li>ghi</li></ul> +PASS Preserve selection after formatBlock with dd at <ul><li>abc</li><li>d[ef</li><li>gh]i</li></ul> +PASS Preserve selection after formatBlock with dd at <ul><li>abc</li><li>d[ef</li></ul><div>gh]i</div> +PASS Preserve selection after formatBlock with dd at <div>a[bc</div><ul><li>de]f</li><li>ghi</li></ul> +PASS Preserve selection after formatBlock with dd at <table><tr><td>a[b]c</td></tr></table> +PASS Preserve selection after formatBlock with dd at <table><tr><td>a[bc</td><td>de]f</td></tr></table> +PASS Preserve selection after formatBlock with dd at <table><tr><td>a[bc</td></tr><tr><td>de]f</td></tr></table> +PASS Preserve selection after formatBlock with dd at <div>a[bc</div><table><tr><td>de]f</td></tr></table> +FAIL Preserve selection after formatBlock with dd at <table><tr><td>a[bc</td></tr></table><div>de]f</div> assert_equals: Result: <dd><table><tbody><tr><td><dd>abc</dd></td></tr></tbody></table>def</dd> expected "bcde" but got "bcdef" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/editing/other/formatblock-preserving-selection.tentative_styleWithCSS=true_block=dt-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/editing/other/formatblock-preserving-selection.tentative_styleWithCSS=true_block=dt-expected.txt new file mode 100644 index 0000000..5216aef --- /dev/null +++ b/third_party/blink/web_tests/platform/generic/external/wpt/editing/other/formatblock-preserving-selection.tentative_styleWithCSS=true_block=dt-expected.txt
@@ -0,0 +1,19 @@ +This is a testharness.js-based test. +PASS Preserve selection after formatBlock with dt at a[b]c +PASS Preserve selection after formatBlock with dt at a[bc<br>de]f +PASS Preserve selection after formatBlock with dt at <div>a[b]c</div> +PASS Preserve selection after formatBlock with dt at <div>a[bc</div><div>de]f</div> +PASS Preserve selection after formatBlock with dt at <div>a[bc<br>de]f</div> +PASS Preserve selection after formatBlock with dt at <ul><li>a[b]c</li></ul> +PASS Preserve selection after formatBlock with dt at <ul><li>a[bc</li><li>de]f</li></ul> +PASS Preserve selection after formatBlock with dt at <ul><li>a[bc</li><li>de]f</li><li>ghi</li></ul> +PASS Preserve selection after formatBlock with dt at <ul><li>abc</li><li>d[ef</li><li>gh]i</li></ul> +PASS Preserve selection after formatBlock with dt at <ul><li>abc</li><li>d[ef</li></ul><div>gh]i</div> +PASS Preserve selection after formatBlock with dt at <div>a[bc</div><ul><li>de]f</li><li>ghi</li></ul> +PASS Preserve selection after formatBlock with dt at <table><tr><td>a[b]c</td></tr></table> +PASS Preserve selection after formatBlock with dt at <table><tr><td>a[bc</td><td>de]f</td></tr></table> +PASS Preserve selection after formatBlock with dt at <table><tr><td>a[bc</td></tr><tr><td>de]f</td></tr></table> +PASS Preserve selection after formatBlock with dt at <div>a[bc</div><table><tr><td>de]f</td></tr></table> +FAIL Preserve selection after formatBlock with dt at <table><tr><td>a[bc</td></tr></table><div>de]f</div> assert_equals: Result: <dt><table><tbody><tr><td><dt>abc</dt></td></tr></tbody></table>def</dt> expected "bcde" but got "bcdef" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/editing/other/formatblock-preserving-selection.tentative_styleWithCSS=true_block=h1-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/editing/other/formatblock-preserving-selection.tentative_styleWithCSS=true_block=h1-expected.txt new file mode 100644 index 0000000..7d23deff --- /dev/null +++ b/third_party/blink/web_tests/platform/generic/external/wpt/editing/other/formatblock-preserving-selection.tentative_styleWithCSS=true_block=h1-expected.txt
@@ -0,0 +1,19 @@ +This is a testharness.js-based test. +PASS Preserve selection after formatBlock with h1 at a[b]c +PASS Preserve selection after formatBlock with h1 at a[bc<br>de]f +PASS Preserve selection after formatBlock with h1 at <div>a[b]c</div> +PASS Preserve selection after formatBlock with h1 at <div>a[bc</div><div>de]f</div> +PASS Preserve selection after formatBlock with h1 at <div>a[bc<br>de]f</div> +PASS Preserve selection after formatBlock with h1 at <ul><li>a[b]c</li></ul> +PASS Preserve selection after formatBlock with h1 at <ul><li>a[bc</li><li>de]f</li></ul> +PASS Preserve selection after formatBlock with h1 at <ul><li>a[bc</li><li>de]f</li><li>ghi</li></ul> +PASS Preserve selection after formatBlock with h1 at <ul><li>abc</li><li>d[ef</li><li>gh]i</li></ul> +PASS Preserve selection after formatBlock with h1 at <ul><li>abc</li><li>d[ef</li></ul><div>gh]i</div> +PASS Preserve selection after formatBlock with h1 at <div>a[bc</div><ul><li>de]f</li><li>ghi</li></ul> +PASS Preserve selection after formatBlock with h1 at <table><tr><td>a[b]c</td></tr></table> +PASS Preserve selection after formatBlock with h1 at <table><tr><td>a[bc</td><td>de]f</td></tr></table> +PASS Preserve selection after formatBlock with h1 at <table><tr><td>a[bc</td></tr><tr><td>de]f</td></tr></table> +PASS Preserve selection after formatBlock with h1 at <div>a[bc</div><table><tr><td>de]f</td></tr></table> +FAIL Preserve selection after formatBlock with h1 at <table><tr><td>a[bc</td></tr></table><div>de]f</div> assert_equals: Result: <h1><table><tbody><tr><td><h1>abc</h1></td></tr></tbody></table>def</h1> expected "bcde" but got "bcdef" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/editing/other/formatblock-preserving-selection.tentative_styleWithCSS=true_block=pre-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/editing/other/formatblock-preserving-selection.tentative_styleWithCSS=true_block=pre-expected.txt new file mode 100644 index 0000000..e43f514 --- /dev/null +++ b/third_party/blink/web_tests/platform/generic/external/wpt/editing/other/formatblock-preserving-selection.tentative_styleWithCSS=true_block=pre-expected.txt
@@ -0,0 +1,19 @@ +This is a testharness.js-based test. +PASS Preserve selection after formatBlock with pre at a[b]c +PASS Preserve selection after formatBlock with pre at a[bc<br>de]f +PASS Preserve selection after formatBlock with pre at <div>a[b]c</div> +PASS Preserve selection after formatBlock with pre at <div>a[bc</div><div>de]f</div> +PASS Preserve selection after formatBlock with pre at <div>a[bc<br>de]f</div> +PASS Preserve selection after formatBlock with pre at <ul><li>a[b]c</li></ul> +PASS Preserve selection after formatBlock with pre at <ul><li>a[bc</li><li>de]f</li></ul> +PASS Preserve selection after formatBlock with pre at <ul><li>a[bc</li><li>de]f</li><li>ghi</li></ul> +PASS Preserve selection after formatBlock with pre at <ul><li>abc</li><li>d[ef</li><li>gh]i</li></ul> +PASS Preserve selection after formatBlock with pre at <ul><li>abc</li><li>d[ef</li></ul><div>gh]i</div> +PASS Preserve selection after formatBlock with pre at <div>a[bc</div><ul><li>de]f</li><li>ghi</li></ul> +PASS Preserve selection after formatBlock with pre at <table><tr><td>a[b]c</td></tr></table> +PASS Preserve selection after formatBlock with pre at <table><tr><td>a[bc</td><td>de]f</td></tr></table> +PASS Preserve selection after formatBlock with pre at <table><tr><td>a[bc</td></tr><tr><td>de]f</td></tr></table> +PASS Preserve selection after formatBlock with pre at <div>a[bc</div><table><tr><td>de]f</td></tr></table> +FAIL Preserve selection after formatBlock with pre at <table><tr><td>a[bc</td></tr></table><div>de]f</div> assert_equals: Result: <pre><table><tbody><tr><td><pre>abc</pre></td></tr></tbody></table>def</pre> expected "bcde" but got "bcdef" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/generic/http/tests/inspector-protocol/attribution-reporting/source-and-trigger-headers-expected.txt b/third_party/blink/web_tests/platform/generic/http/tests/inspector-protocol/attribution-reporting/source-and-trigger-headers-expected.txt new file mode 100644 index 0000000..7631359c --- /dev/null +++ b/third_party/blink/web_tests/platform/generic/http/tests/inspector-protocol/attribution-reporting/source-and-trigger-headers-expected.txt
@@ -0,0 +1,11 @@ +Test that an attributionsrc request that is eligible for sources and triggers triggers an issue when it tries to register a source and trigger together. +Issue reported: { + code : AttributionReportingIssue + details : { + attributionReportingIssueDetails : { + request : <object> + violationType : SourceAndTriggerHeaders + } + } +} +
diff --git a/third_party/blink/web_tests/platform/generic/virtual/css-highlight-inheritance/external/wpt/css/css-pseudo/highlight-currentcolor-computed-inheritance-expected.txt b/third_party/blink/web_tests/platform/generic/virtual/css-highlight-inheritance/external/wpt/css/css-pseudo/highlight-currentcolor-computed-inheritance-expected.txt new file mode 100644 index 0000000..5001aa4 --- /dev/null +++ b/third_party/blink/web_tests/platform/generic/virtual/css-highlight-inheritance/external/wpt/css/css-pseudo/highlight-currentcolor-computed-inheritance-expected.txt
@@ -0,0 +1,8 @@ +This is a testharness.js-based test. +PASS getComputedStyle() for ::selection +PASS getComputedStyle() for ::target-text +PASS getComputedStyle() for ::spelling-error +PASS getComputedStyle() for ::grammar-error +PASS getComputedStyle() for ::highlight(foo) +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/wpt_internal/prerender/resources/storage.https.html b/third_party/blink/web_tests/wpt_internal/prerender/resources/storage-estimate.https.html similarity index 78% rename from third_party/blink/web_tests/wpt_internal/prerender/resources/storage.https.html rename to third_party/blink/web_tests/wpt_internal/prerender/resources/storage-estimate.https.html index b0a8702..caf4019 100644 --- a/third_party/blink/web_tests/wpt_internal/prerender/resources/storage.https.html +++ b/third_party/blink/web_tests/wpt_internal/prerender/resources/storage-estimate.https.html
@@ -7,9 +7,9 @@ const params = new URLSearchParams(location.search); -// The main test page (restriction-storage.https.html) loads the initiator page, -// then the initiator page will prerender itself with the `prerendering` -// parameter. +// The main test page (restriction-storage-estimate.https.html) loads the +// initiator page, then the initiator page will prerender itself with the +// `prerendering` parameter. const isPrerendering = params.has('prerendering'); if (!isPrerendering) {
diff --git a/third_party/blink/web_tests/wpt_internal/prerender/resources/storage.https.html b/third_party/blink/web_tests/wpt_internal/prerender/resources/storage-persist.https.html similarity index 70% copy from third_party/blink/web_tests/wpt_internal/prerender/resources/storage.https.html copy to third_party/blink/web_tests/wpt_internal/prerender/resources/storage-persist.https.html index b0a8702..ab5fabd 100644 --- a/third_party/blink/web_tests/wpt_internal/prerender/resources/storage.https.html +++ b/third_party/blink/web_tests/wpt_internal/prerender/resources/storage-persist.https.html
@@ -7,9 +7,9 @@ const params = new URLSearchParams(location.search); -// The main test page (restriction-storage.https.html) loads the initiator page, -// then the initiator page will prerender itself with the `prerendering` -// parameter. +// The main test page (restriction-storage-persist.https.html) loads the +// initiator page, then the initiator page will prerender itself with the +// `prerendering` parameter. const isPrerendering = params.has('prerendering'); if (!isPrerendering) { @@ -17,7 +17,7 @@ } else { const prerenderEventCollector = new PrerenderEventCollector(); prerenderEventCollector.start( - navigator.storage.estimate(), 'navigator.storage.estimate'); + navigator.storage.persist(), 'navigator.storage.persist'); } </script>
diff --git a/third_party/blink/web_tests/wpt_internal/prerender/restriction-storage.https.html b/third_party/blink/web_tests/wpt_internal/prerender/restriction-storage-estimate.https.html similarity index 87% rename from third_party/blink/web_tests/wpt_internal/prerender/restriction-storage.https.html rename to third_party/blink/web_tests/wpt_internal/prerender/restriction-storage-estimate.https.html index f151a6a..e05f2c9 100644 --- a/third_party/blink/web_tests/wpt_internal/prerender/restriction-storage.https.html +++ b/third_party/blink/web_tests/wpt_internal/prerender/restriction-storage-estimate.https.html
@@ -1,5 +1,5 @@ <!DOCTYPE html> -<title>Access to the Storage API is deferred</title> +<title>Access to storage.estimate() is deferred</title> <meta name="timeout" content="long"> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> @@ -19,7 +19,7 @@ once: true }); }); - const url = `resources/storage.https.html?uid=${uid}`; + const url = `resources/storage-estimate.https.html?uid=${uid}`; window.open(url, '_blank', 'noopener'); const result = await gotMessage; @@ -47,7 +47,7 @@ // Send a close signal to PrerenderEventCollector on the prerendered page. new PrerenderChannel('close', uid).postMessage(''); -}, `the access to the Storage API should be deferred until the prerendered +}, `the access to storage.estimate() should be deferred until the prerendered page is activated`); </script>
diff --git a/third_party/blink/web_tests/wpt_internal/prerender/restriction-storage.https.html b/third_party/blink/web_tests/wpt_internal/prerender/restriction-storage-persist.https.html similarity index 79% copy from third_party/blink/web_tests/wpt_internal/prerender/restriction-storage.https.html copy to third_party/blink/web_tests/wpt_internal/prerender/restriction-storage-persist.https.html index f151a6a..c808142 100644 --- a/third_party/blink/web_tests/wpt_internal/prerender/restriction-storage.https.html +++ b/third_party/blink/web_tests/wpt_internal/prerender/restriction-storage-persist.https.html
@@ -1,5 +1,5 @@ <!DOCTYPE html> -<title>Access to the Storage API is deferred</title> +<title>Access to storage.persist() is deferred</title> <meta name="timeout" content="long"> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> @@ -19,13 +19,13 @@ once: true }); }); - const url = `resources/storage.https.html?uid=${uid}`; + const url = `resources/storage-persist.https.html?uid=${uid}`; window.open(url, '_blank', 'noopener'); const result = await gotMessage; const expected = [ { - event: 'started waiting navigator.storage.estimate', + event: 'started waiting navigator.storage.persist', prerendering: true }, { @@ -33,7 +33,7 @@ prerendering: false }, { - event: 'finished waiting navigator.storage.estimate', + event: 'finished waiting navigator.storage.persist', prerendering: false }, ]; @@ -47,7 +47,7 @@ // Send a close signal to PrerenderEventCollector on the prerendered page. new PrerenderChannel('close', uid).postMessage(''); -}, `the access to the Storage API should be deferred until the prerendered +}, `the access to the storage.persist() should be deferred until the prerendered page is activated`); </script>
diff --git a/third_party/gvr-android-sdk/libgvr_shim_static_arm64_Cr.a.sha1 b/third_party/gvr-android-sdk/libgvr_shim_static_arm64_Cr.a.sha1 index d1ce2c77..49f6e615 100644 --- a/third_party/gvr-android-sdk/libgvr_shim_static_arm64_Cr.a.sha1 +++ b/third_party/gvr-android-sdk/libgvr_shim_static_arm64_Cr.a.sha1
@@ -1 +1 @@ -3f645fcfaa1c3074a27e9450aa8da69444953876 \ No newline at end of file +4d7587416f234194cc64940d2d9a44b013ab6365 \ No newline at end of file
diff --git a/third_party/gvr-android-sdk/libgvr_shim_static_arm_Cr.a.sha1 b/third_party/gvr-android-sdk/libgvr_shim_static_arm_Cr.a.sha1 index a94c15a..3fa8ec3 100644 --- a/third_party/gvr-android-sdk/libgvr_shim_static_arm_Cr.a.sha1 +++ b/third_party/gvr-android-sdk/libgvr_shim_static_arm_Cr.a.sha1
@@ -1 +1 @@ -798349d9f536113ca5709f0cce2953308b46ddbb \ No newline at end of file +aab5e02dacc6dc66f5abdf0c3ce08b73cbf8b8e9 \ No newline at end of file
diff --git a/third_party/nearby/README.chromium b/third_party/nearby/README.chromium index 35e6cd38..6fc77e4 100644 --- a/third_party/nearby/README.chromium +++ b/third_party/nearby/README.chromium
@@ -1,7 +1,7 @@ Name: Nearby Connections Library Short Name: Nearby URL: https://github.com/google/nearby -Version: 5b3d4438150cbd4abefde95a2add15de5f634bfd +Version: 377dc47c9f2a54ec9b4df7dac3d0419a782f37e3 License: Apache 2.0 License File: LICENSE Security Critical: yes
diff --git a/tools/checkteamtags/PRESUBMIT.py b/tools/checkteamtags/PRESUBMIT.py index 857d3101..e389424 100644 --- a/tools/checkteamtags/PRESUBMIT.py +++ b/tools/checkteamtags/PRESUBMIT.py
@@ -44,15 +44,7 @@ def _RunPyLint(input_api, output_api): """Runs unit tests for checkteamtags.""" - tests = input_api.canned_checks.GetPylint( - input_api, - output_api, - version='2.7', - # Disabling certain python3-specific warnings until the conversion - # is complete. - disabled_warnings=[ - 'super-with-arguments', - 'raise-missing-from', - 'useless-object-inheritance', - ]) + tests = input_api.canned_checks.GetPylint(input_api, + output_api, + version='2.7') return input_api.RunTests(tests)
diff --git a/tools/checkteamtags/checkteamtags.py b/tools/checkteamtags/checkteamtags.py index 17aa5ad..f84f50e 100755 --- a/tools/checkteamtags/checkteamtags.py +++ b/tools/checkteamtags/checkteamtags.py
@@ -9,9 +9,8 @@ import json import logging -import optparse +import argparse import os -import posixpath import re import sys import urllib.request @@ -77,19 +76,20 @@ return rel_path, full_path -def validate_mappings(options, args): +def validate_mappings(arguments, owners_files): """Ensure team/component mapping remains consistent after patch. The main purpose of this check is to notify the user if any edited (or added) team tag makes a component map to multiple teams. Args: - options: Command line options from optparse - args: List of paths to affected OWNERS files + arguments: Command line arguments from argparse + owners_files: List of paths to affected OWNERS files Returns: A string containing the details of any multi-team per component. """ - mappings_file = json.load(urllib.request.urlopen(options.current_mapping_url)) + mappings_file = json.load( + urllib.request.urlopen(arguments.current_mapping_url)) new_dir_to_component = mappings_file.get('dir-to-component', {}) new_dir_to_team = mappings_file.get('dir-to-team', {}) @@ -98,8 +98,8 @@ affected_components = set() # Parse affected OWNERS files - for f in args: - rel, full = rel_and_full_paths(options.root, f) + for f in owners_files: + rel, full = rel_and_full_paths(arguments.root, f) if os.path.exists(full): affected[os.path.dirname(rel)] = parse(full) else: @@ -131,10 +131,9 @@ # For the components affected by this patch, compute the directories that map # to it. - affected_component_to_dirs = {} + affected_component_to_dirs = defaultdict(list) for d, component in new_dir_to_component.items(): if component in affected_components: - affected_component_to_dirs.setdefault(component, []) affected_component_to_dirs[component].append(d) # Convert component->[dirs], dir->team to component->[teams]. @@ -214,46 +213,47 @@ python %prog ./OWNERS """ - parser = optparse.OptionParser(usage=usage) - parser.add_option( - '--root', help='Specifies the repository root.') - parser.add_option( - '-v', '--verbose', action='count', default=0, help='Print debug logging') - parser.add_option( - '--bare', - action='store_true', - default=False, - help='Prints the bare filename triggering the checks') - parser.add_option( - '--current_mapping_url', default=DEFAULT_MAPPING_URL, + parser = argparse.ArgumentParser(usage=usage) + parser.add_argument('--root', help='Specifies the repository root.') + parser.add_argument('-v', + '--verbose', + action='count', + default=0, + help='Print debug logging') + parser.add_argument('--bare', + action='store_true', + default=False, + help='Prints the bare filename triggering the checks') + parser.add_argument( + '--current_mapping_url', + default=DEFAULT_MAPPING_URL, help='URL for existing dir/component and component/team mapping') - parser.add_option('--json', help='Path to JSON output file') - options, args = parser.parse_args() + parser.add_argument('--json', help='Path to JSON output file') + args, owners_files = parser.parse_known_args() levels = [logging.ERROR, logging.INFO, logging.DEBUG] - logging.basicConfig(level=levels[min(len(levels) - 1, options.verbose)]) + logging.basicConfig(level=levels[min(len(levels) - 1, args.verbose)]) errors = list( - filter(None, - [check_owners(*rel_and_full_paths(options.root, f)) - for f in args])) + filter(None, (check_owners(*rel_and_full_paths(args.root, f)) + for f in owners_files))) warnings = None if not errors: - warnings = validate_mappings(options, args) + warnings = validate_mappings(args, owners_files) - if options.json: - with open(options.json, 'w') as f: + if args.json: + with open(args.json, 'w') as f: json.dump(errors, f) if errors: - if options.bare: + if args.bare: print('\n'.join(e['full_path'] for e in errors)) else: print('\nFAILED\n') print('\n'.join('%s: %s' % (e['full_path'], e['error']) for e in errors)) return 1 - if not options.bare: + if not args.bare: if warnings: print(warnings) return 0
diff --git a/tools/checkteamtags/checkteamtags_test.py b/tools/checkteamtags/checkteamtags_test.py index efc9e0c..1b06b7b 100644 --- a/tools/checkteamtags/checkteamtags_test.py +++ b/tools/checkteamtags/checkteamtags_test.py
@@ -3,14 +3,11 @@ # found in the LICENSE file. import json -import os -import sys import unittest +import unittest.mock as mock import checkteamtags -import mock - def mock_file(lines): inner_mock = mock.MagicMock() @@ -37,7 +34,7 @@ if data is None: data = DEFAULT_MAPPING - class _MockJsonResponse(object): + class _MockJsonResponse: def __init__(self, data): self.data = data
diff --git a/tools/checkteamtags/extract_components.py b/tools/checkteamtags/extract_components.py index 007a3a3..043bdb0 100755 --- a/tools/checkteamtags/extract_components.py +++ b/tools/checkteamtags/extract_components.py
@@ -19,7 +19,7 @@ from __future__ import print_function import json -import optparse +import argparse import os import sys @@ -46,7 +46,7 @@ f.write(data) -def display_stat(stats, root, options): +def display_stat(stats, root, args): """"Display coverage statistic. The following three values are always displayed: @@ -57,16 +57,16 @@ - The number of OWNERS files (and its percentage of the total) that have both component and team information. - Optionally, if options.stat_coverage or options.complete_coverage are given, + Optionally, if args.stat_coverage or args.complete_coverage are given, the same information will be shown for each depth level. - (up to the level given by options.stat_coverage, if any). + (up to the level given by args.stat_coverage, if any). Args: stats (dict): Tha statistics in dictionary form as produced by the owners_file_tags module. root (str): The root directory from which the depth level is calculated. - options (optparse.Values): The command line options as returned by - optparse. + args (argparse.Values): The command line args as returned by + argparse. """ file_total = stats['OWNERS-count'] print("%d OWNERS files in total." % file_total) @@ -92,11 +92,11 @@ print("\nUnder directory %s " % root) # number of depth to display, default is max depth under root num_output_depth = len(stats['OWNERS-count-by-depth']) - if (options.stat_coverage and options.stat_coverage > 0 - and options.stat_coverage < num_output_depth): - num_output_depth = options.stat_coverage + if (args.stat_coverage and args.stat_coverage > 0 + and args.stat_coverage < num_output_depth): + num_output_depth = args.stat_coverage - for depth in range(0, num_output_depth): + for depth in range(num_output_depth): file_total_by_depth = stats['OWNERS-count-by-depth'][depth] file_with_component_by_depth =\ stats['OWNERS-with-component-only-count-by-depth'][depth] @@ -145,12 +145,12 @@ or num_output_depth > max_output_depth): num_output_depth = max_output_depth - for depth in range(0, num_output_depth): + for depth in range(num_output_depth): print('at depth %(depth)d' % {'depth': depth}) print(stats['OWNERS-missing-info-by-depth'][depth]) -def main(argv): +def main(): usage = """Usage: python %prog [options] [<root_dir>] root_dir specifies the topmost directory to traverse looking for OWNERS files, defaults to two levels up from this file's directory. @@ -166,48 +166,62 @@ python %prog -s 3 /b/build/src python %prog -m 2 /b/build/src """ - parser = optparse.OptionParser(usage=usage) - parser.add_option('-w', '--write', action='store_true', - help='If no errors occur, write the mappings to disk.') - parser.add_option('-v', '--verbose', action='store_true', - help='Print warnings.') - parser.add_option('-o', '--output_file', help='Specify file to write the ' - 'mappings to instead of the default: <CWD>/' - 'component_map.json (implies -w)') - parser.add_option('-c', '--complete_coverage', action='store_true', - help='Print complete coverage statistic') - parser.add_option('-s', '--stat_coverage', type="int", - help='Specify directory depth to display coverage stats') - parser.add_option('--include-subdirs', action='store_true', default=False, - help='List subdirectories without OWNERS file or component ' - 'tag as having same component as parent') - parser.add_option('-m', '--list_missing_info_by_depth', type="int", - help='List OWNERS files that have missing team and ' - 'component information by depth') - options, args = parser.parse_args(argv[1:]) - if args: - root = args[0] + parser = argparse.ArgumentParser(usage=usage) + parser.add_argument('-w', + '--write', + action='store_true', + help='If no errors occur, write the mappings to disk.') + parser.add_argument('-v', + '--verbose', + action='store_true', + help='Print warnings.') + parser.add_argument('-o', + '--output_file', + help='Specify file to write the ' + 'mappings to instead of the default: <CWD>/' + 'component_map.json (implies -w)') + parser.add_argument('-c', + '--complete_coverage', + action='store_true', + help='Print complete coverage statistic') + parser.add_argument('-s', + '--stat_coverage', + type=int, + help='Specify directory depth to display coverage stats') + parser.add_argument( + '--include-subdirs', + action='store_true', + default=False, + help='List subdirectories without OWNERS file or component ' + 'tag as having same component as parent') + parser.add_argument('-m', + '--list_missing_info_by_depth', + type=int, + help='List OWNERS files that have missing team and ' + 'component information by depth') + args, root_dir = parser.parse_known_args() + if root_dir: + root = root_dir[0] else: root = _DEFAULT_SRC_LOCATION - scrape_result = scrape_owners(root, include_subdirs=options.include_subdirs) + scrape_result = scrape_owners(root, include_subdirs=args.include_subdirs) mappings, warnings, stats = aggregate_components_from_owners(scrape_result, root) - if options.verbose: + if args.verbose: for w in warnings: print(w) - if options.stat_coverage or options.complete_coverage: - display_stat(stats, root, options) + if args.stat_coverage or args.complete_coverage: + display_stat(stats, root, args) - if options.list_missing_info_by_depth: - display_missing_info_OWNERS_files(stats, - options.list_missing_info_by_depth) + if args.list_missing_info_by_depth: + display_missing_info_OWNERS_files(stats, args.list_missing_info_by_depth) mappings['AAA-README']= _README mapping_file_contents = json.dumps(mappings, sort_keys=True, indent=2) - if options.write or options.output_file: - write_results(options.output_file, mapping_file_contents) + if args.write or args.output_file: + write_results(args.output_file, mapping_file_contents) else: print(mapping_file_contents) @@ -215,4 +229,4 @@ if __name__ == '__main__': - sys.exit(main(sys.argv)) + sys.exit(main())
diff --git a/tools/checkteamtags/extract_components_test.py b/tools/checkteamtags/extract_components_test.py index aa59491d..f0167cb 100644 --- a/tools/checkteamtags/extract_components_test.py +++ b/tools/checkteamtags/extract_components_test.py
@@ -2,24 +2,21 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -from collections import OrderedDict import json -import os -import sys import unittest +import unittest.mock as mock from io import StringIO import extract_components -import mock - class ExtractComponentsTest(unittest.TestCase): def setUp(self): - super(ExtractComponentsTest, self).setUp() + super().setUp() self.maxDiff = None + @mock.patch('sys.argv', ['extract_components', 'src']) def testBaseCase(self): with mock.patch('extract_components.scrape_owners', return_value={ '.': {}, @@ -38,7 +35,7 @@ }): saved_output = StringIO() with mock.patch('sys.stdout', saved_output): - error_code = extract_components.main(['%prog', 'src']) + error_code = extract_components.main() self.assertEqual(0, error_code) result_minus_readme = json.loads(saved_output.getvalue()) del result_minus_readme['AAA-README'] @@ -67,6 +64,7 @@ ['dummy-specialist-team@chromium.org'], }}) + @mock.patch('sys.argv', ['extract_components', 'src']) def testOsTagBreaksDuplication(self): with mock.patch('extract_components.scrape_owners', return_value={ '.': {}, @@ -86,7 +84,7 @@ }): saved_output = StringIO() with mock.patch('sys.stdout', saved_output): - error_code = extract_components.main(['%prog', 'src']) + error_code = extract_components.main() self.assertEqual(0, error_code) result_minus_readme = json.loads(saved_output.getvalue()) del result_minus_readme['AAA-README'] @@ -114,6 +112,7 @@ 'dummy-specialist-team@chromium.org'] }}) + @mock.patch('sys.argv', ['extract_components', 'src']) def testMultipleTeamsOneComponent(self): with mock.patch('extract_components.scrape_owners', return_value={ '.': {}, @@ -132,7 +131,7 @@ }): saved_output = StringIO() with mock.patch('sys.stdout', saved_output): - error_code = extract_components.main(['%prog', 'src']) + error_code = extract_components.main() self.assertEqual(0, error_code) result_minus_readme = json.loads(saved_output.getvalue()) del result_minus_readme['AAA-README'] @@ -160,6 +159,7 @@ 'other-dummy-team@chromium.org'], }}) + @mock.patch('sys.argv', ['extract_components', '-v', 'src']) def testVerbose(self): with mock.patch('extract_components.scrape_owners', return_value={ '.': {}, @@ -178,10 +178,11 @@ }): saved_output = StringIO() with mock.patch('sys.stdout', saved_output): - extract_components.main(['%prog', '-v', 'src']) + extract_components.main() output = saved_output.getvalue() self.assertIn('OWNERS has no COMPONENT tag', output) + @mock.patch('sys.argv', ['extract_components', '-s 2', 'src']) def testCoverage(self): with mock.patch('extract_components.scrape_owners', return_value={ '.': {}, @@ -199,12 +200,13 @@ }): saved_output = StringIO() with mock.patch('sys.stdout', saved_output): - extract_components.main(['%prog', '-s 2', 'src']) + extract_components.main() output = saved_output.getvalue() self.assertIn('4 OWNERS files in total.', output) self.assertIn('3 (75.00%) OWNERS files have COMPONENT', output) self.assertIn('2 (50.00%) OWNERS files have TEAM and COMPONENT', output) + @mock.patch('sys.argv', ['extract_components', '-c', '']) def testCompleteCoverage(self): with mock.patch('extract_components.scrape_owners', return_value={ '.': {}, @@ -222,7 +224,7 @@ }): saved_output = StringIO() with mock.patch('sys.stdout', saved_output): - extract_components.main(['%prog', '-c', '']) + extract_components.main() output = saved_output.getvalue() self.assertIn('4 OWNERS files in total.', output) self.assertIn('3 (75.00%) OWNERS files have COMPONENT', output) @@ -231,6 +233,7 @@ self.assertIn('2 OWNERS files at depth 1', output) self.assertIn('1 OWNERS files at depth 2', output) + @mock.patch('sys.argv', ['extract_components', '-m 2', 'src']) def testDisplayFile(self): with mock.patch('extract_components.scrape_owners', return_value={ '.': {}, @@ -245,7 +248,7 @@ }): saved_output = StringIO() with mock.patch('sys.stdout', saved_output): - extract_components.main(['%prog', '-m 2', 'src']) + extract_components.main() output = saved_output.getvalue() self.assertIn('OWNERS files that have missing team and component ' 'by depth:', output)
diff --git a/tools/checkteamtags/owners_file_tags_test.py b/tools/checkteamtags/owners_file_tags_test.py index 9d3b8706..e7996471 100644 --- a/tools/checkteamtags/owners_file_tags_test.py +++ b/tools/checkteamtags/owners_file_tags_test.py
@@ -5,12 +5,11 @@ from collections import OrderedDict from contextlib import contextmanager import os -import sys import unittest +import unittest.mock as mock import owners_file_tags -import mock @contextmanager def mock_file_tree(tree): @@ -28,7 +27,7 @@ ret_val = mock.MagicMock() if path in files_data and mode == 'r': - class mock_opened_file(object): + class mock_opened_file: def __enter__(self, *args, **kwargs): return self @@ -58,7 +57,7 @@ """os tag breaking dupe >>""" def setUp(self): - super(OwnersFileTagsTest, self).setUp() + super().setUp() self.maxDiff = None def testScrapeOwners(self):
diff --git a/tools/clang/scripts/build.py b/tools/clang/scripts/build.py index 69e45f1..970f53cf 100755 --- a/tools/clang/scripts/build.py +++ b/tools/clang/scripts/build.py
@@ -148,7 +148,10 @@ print('Removing %s.' % dir) RmTree(dir) - clone_cmd = ['git', 'clone', 'https://github.com/llvm/llvm-project/', dir] + clone_cmd = [ + 'git', 'clone', 'https://chromium.googlesource.com/external/' + + 'github.com/llvm/llvm-project', dir + ] if RunCommand(clone_cmd, fail_hard=False): os.chdir(dir) @@ -167,11 +170,11 @@ def GetLatestLLVMCommit(): """Get the latest commit hash in the LLVM monorepo.""" - ref = json.loads( - UrlOpen(('https://api.github.com/repos/' - 'llvm/llvm-project/git/refs/heads/main'))) - assert ref['object']['type'] == 'commit' - return ref['object']['sha'] + main = json.loads( + UrlOpen('https://chromium.googlesource.com/external/' + + 'github.com/llvm/llvm-project/' + + '+/refs/heads/main?format=JSON').replace(")]}'", "")) + return main['commit'] def GetCommitDescription(commit):
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 49770c31..53a6301 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -25079,6 +25079,10 @@ <int value="60" label="eyedropperColorPicker"/> <int value="61" label="instrumentationBreakpoints"/> <int value="62" label="cssAuthoringHints"/> + <int value="63" label="authoredDeployedGrouping"/> + <int value="64" label="importantDOMProperties"/> + <int value="65" label="justMyCode"/> + <int value="66" label="breakpointView"/> </enum> <enum name="DevToolsGridOverlayOpenedFrom"> @@ -57736,6 +57740,8 @@ <int value="-784199026" label="EnableFilesAppCopyImage:enabled"/> <int value="-783890018" label="LacrosProfileMigrationForAnyUser:disabled"/> <int value="-783093620" label="WebViewHitTestInBlinkOnTouchStart:enabled"/> + <int value="-781625651" + label="DisruptiveNotificationPermissionRevocation:enabled"/> <int value="-780798969" label="disable-single-click-autofill"/> <int value="-778126349" label="DownloadsLocationChange:enabled"/> <int value="-778098896" label="EnableAggregatedMlSearchRanking:disabled"/> @@ -58306,6 +58312,8 @@ <int value="-415186532" label="AndroidSiteSettingsUIRefresh:enabled"/> <int value="-414900505" label="ScrollCapture:enabled"/> <int value="-413562235" label="MessagesForAndroidUpdatePassword:disabled"/> + <int value="-413286115" + label="DisruptiveNotificationPermissionRevocation:disabled"/> <int value="-412736561" label="EnableZeroStateMixedTypesRanker:enabled"/> <int value="-412645531" label="AutofillTokenPrefixMatching:enabled"/> <int value="-410852857" label="ImprovedA2HS:disabled"/> @@ -91833,6 +91841,7 @@ <int value="6" label="kShaderCache"/> <int value="7" label="kPluginPrivate"/> <int value="8" label="kConversions"/> + <int value="11" label="kGpuCache"/> </enum> <enum name="StoragePressureBubbleUserAction">
diff --git a/tools/metrics/histograms/metadata/blink/histograms.xml b/tools/metrics/histograms/metadata/blink/histograms.xml index 8f9f1f0..45f10f32 100644 --- a/tools/metrics/histograms/metadata/blink/histograms.xml +++ b/tools/metrics/histograms/metadata/blink/histograms.xml
@@ -1231,7 +1231,7 @@ </summary> </histogram> -<histogram name="Blink.HTMLParsing.ParsingTimeTotal2" units="microseconds" +<histogram name="Blink.HTMLParsing.ParsingTimeTotal3" units="microseconds" expires_after="2023-06-30"> <owner>masonf@chromium.org</owner> <owner>dom-dev@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/ios/histograms.xml b/tools/metrics/histograms/metadata/ios/histograms.xml index 72168b6..0d477227 100644 --- a/tools/metrics/histograms/metadata/ios/histograms.xml +++ b/tools/metrics/histograms/metadata/ios/histograms.xml
@@ -1377,7 +1377,7 @@ </histogram> <histogram name="IOS.ReadingList.ImageTooLargeFailure" units="KB" - expires_after="2022-08-14"> + expires_after="2023-08-05"> <owner>olivierrobin@chromium.org</owner> <owner>justincohen@chromium.org</owner> <summary> @@ -1611,14 +1611,14 @@ </histogram> <histogram name="IOS.Spotlight.Action" enum="IOSSpotlightAction" - expires_after="2022-09-12"> + expires_after="2023-08-05"> <owner>olivierrobin@chromium.org</owner> <owner>rohitrao@chromium.org</owner> <summary>The Spotlight Action pressed by the user.</summary> </histogram> <histogram name="IOS.Spotlight.Availability" enum="IOSSpotlightAvailability" - expires_after="2022-11-20"> + expires_after="2023-08-05"> <owner>rohitrao@chromium.org</owner> <owner>olivierrobin@chromium.org</owner> <summary> @@ -1629,21 +1629,21 @@ </histogram> <histogram name="IOS.Spotlight.BookmarksIndexingDuration" units="ms" - expires_after="2022-11-20"> + expires_after="2023-08-05"> <owner>olivierrobin@chromium.org</owner> <owner>rohitrao@chromium.org</owner> <summary>Time spent in Spotlight initial indexation of bookmarks.</summary> </histogram> <histogram name="IOS.Spotlight.BookmarksInitialIndexSize" units="units" - expires_after="2022-09-12"> + expires_after="2023-08-05"> <owner>olivierrobin@chromium.org</owner> <owner>rohitrao@chromium.org</owner> <summary>Number of bookmarks indexed during initial indexation.</summary> </histogram> <histogram name="IOS.Spotlight.Origin" enum="IOSSpotlightOrigin" - expires_after="2022-09-12"> + expires_after="2023-08-05"> <owner>olivierrobin@chromium.org</owner> <owner>rohitrao@chromium.org</owner> <summary>
diff --git a/ui/accessibility/platform/ax_platform_atk_hyperlink.cc b/ui/accessibility/platform/ax_platform_atk_hyperlink.cc index c3a0bfeb..1635f46a 100644 --- a/ui/accessibility/platform/ax_platform_atk_hyperlink.cc +++ b/ui/accessibility/platform/ax_platform_atk_hyperlink.cc
@@ -116,120 +116,6 @@ klass->get_end_index = AXPlatformAtkHyperlinkGetEndIndex; } -// -// AtkAction interface. -// - -static AXPlatformNodeAuraLinux* ToAXPlatformNodeAuraLinuxFromHyperlinkAction( - AtkAction* atk_action) { - if (!IS_AX_PLATFORM_ATK_HYPERLINK(atk_action)) - return nullptr; - - return ToAXPlatformNodeAuraLinux(AX_PLATFORM_ATK_HYPERLINK(atk_action)); -} - -static gboolean ax_platform_atk_hyperlink_do_action(AtkAction* action, - gint index) { - g_return_val_if_fail(ATK_IS_ACTION(action), FALSE); - g_return_val_if_fail(!index, FALSE); - - AXPlatformNodeAuraLinux* obj = - ToAXPlatformNodeAuraLinuxFromHyperlinkAction(action); - if (!obj) - return FALSE; - - obj->DoDefaultAction(); - - return TRUE; -} - -static gint ax_platform_atk_hyperlink_get_n_actions(AtkAction* action) { - g_return_val_if_fail(ATK_IS_ACTION(action), FALSE); - - AXPlatformNodeAuraLinux* obj = - ToAXPlatformNodeAuraLinuxFromHyperlinkAction(action); - if (!obj) - return 0; - - return 1; -} - -static const gchar* ax_platform_atk_hyperlink_get_description(AtkAction* action, - gint index) { - g_return_val_if_fail(ATK_IS_ACTION(action), FALSE); - g_return_val_if_fail(!index, FALSE); - - AXPlatformNodeAuraLinux* obj = - ToAXPlatformNodeAuraLinuxFromHyperlinkAction(action); - if (!obj) - return nullptr; - - // Not implemented - return nullptr; -} - -static const gchar* ax_platform_atk_hyperlink_get_keybinding(AtkAction* action, - gint index) { - g_return_val_if_fail(ATK_IS_ACTION(action), FALSE); - g_return_val_if_fail(!index, FALSE); - - AXPlatformNodeAuraLinux* obj = - ToAXPlatformNodeAuraLinuxFromHyperlinkAction(action); - if (!obj) - return nullptr; - - return obj->GetStringAttribute(ax::mojom::StringAttribute::kAccessKey) - .c_str(); -} - -static const gchar* ax_platform_atk_hyperlink_get_name(AtkAction* atk_action, - gint index) { - g_return_val_if_fail(ATK_IS_ACTION(atk_action), FALSE); - g_return_val_if_fail(!index, FALSE); - - AXPlatformNodeAuraLinux* obj = - ToAXPlatformNodeAuraLinuxFromHyperlinkAction(atk_action); - if (!obj) - return nullptr; - - int action; - if (!obj->GetIntAttribute(ax::mojom::IntAttribute::kDefaultActionVerb, - &action)) - return nullptr; - std::string action_verb = - ui::ToString(static_cast<ax::mojom::DefaultActionVerb>(action)); - ATK_AURALINUX_RETURN_STRING(action_verb); -} - -static const gchar* ax_platform_atk_hyperlink_get_localized_name( - AtkAction* atk_action, - gint index) { - g_return_val_if_fail(ATK_IS_ACTION(atk_action), FALSE); - g_return_val_if_fail(!index, FALSE); - - AXPlatformNodeAuraLinux* obj = - ToAXPlatformNodeAuraLinuxFromHyperlinkAction(atk_action); - if (!obj) - return nullptr; - - int action; - if (!obj->GetIntAttribute(ax::mojom::IntAttribute::kDefaultActionVerb, - &action)) - return nullptr; - std::string action_verb = - ui::ToLocalizedString(static_cast<ax::mojom::DefaultActionVerb>(action)); - ATK_AURALINUX_RETURN_STRING(action_verb); -} - -static void atk_action_interface_init(AtkActionIface* iface) { - iface->do_action = ax_platform_atk_hyperlink_do_action; - iface->get_n_actions = ax_platform_atk_hyperlink_get_n_actions; - iface->get_description = ax_platform_atk_hyperlink_get_description; - iface->get_keybinding = ax_platform_atk_hyperlink_get_keybinding; - iface->get_name = ax_platform_atk_hyperlink_get_name; - iface->get_localized_name = ax_platform_atk_hyperlink_get_localized_name; -} - void ax_platform_atk_hyperlink_set_object( AXPlatformAtkHyperlink* atk_hyperlink, AXPlatformNodeAuraLinux* platform_node) { @@ -264,13 +150,8 @@ nullptr /* value table */ }; - static const GInterfaceInfo actionInfo = { - (GInterfaceInitFunc)(GInterfaceInitFunc)atk_action_interface_init, - (GInterfaceFinalizeFunc)0, 0}; - GType type = g_type_register_static( ATK_TYPE_HYPERLINK, "AXPlatformAtkHyperlink", &tinfo, GTypeFlags(0)); - g_type_add_interface_static(type, ATK_TYPE_ACTION, &actionInfo); g_once_init_leave(&type_volatile, type); }
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc b/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc index d61dcda..ca1ec870 100644 --- a/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc +++ b/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc
@@ -1264,6 +1264,38 @@ g_object_unref(root_obj); } +TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkHyperlinkActions) { + AXNodeData root; + root.id = 1; + root.role = ax::mojom::Role::kLink; + root.AddStringAttribute(ax::mojom::StringAttribute::kUrl, "http://foo.com"); + root.SetDefaultActionVerb(ax::mojom::DefaultActionVerb::kClick); + Init(root); + + AtkObject* root_obj(GetRootAtkObject()); + ASSERT_TRUE(ATK_IS_OBJECT(root_obj)); + ASSERT_TRUE(ATK_IS_HYPERLINK_IMPL(root_obj)); + ASSERT_TRUE(ATK_IS_ACTION(root_obj)); + g_object_ref(root_obj); + auto* root_node = GetRootAsAXNode(); + + gint number_of_actions = atk_action_get_n_actions(ATK_ACTION(root_obj)); + EXPECT_EQ(2, number_of_actions); + + // The index 0 is reserved for the default action, and the index 1 to the + // context menu action. The rest of actions are presented in the order they + // were added. + const gchar* action_name = atk_action_get_name(ATK_ACTION(root_obj), 0); + EXPECT_STREQ("click", action_name); + action_name = atk_action_get_name(ATK_ACTION(root_obj), 1); + EXPECT_STREQ("showContextMenu", action_name); + + EXPECT_TRUE(atk_action_do_action(ATK_ACTION(root_obj), 0)); + EXPECT_EQ(root_node, TestAXNodeWrapper::GetNodeFromLastDefaultAction()); + + g_object_unref(root_obj); +} + // // AtkText interface //
diff --git a/ui/ozone/platform/wayland/host/wayland_event_source.cc b/ui/ozone/platform/wayland/host/wayland_event_source.cc index 94cfe09..1379d5df 100644 --- a/ui/ozone/platform/wayland/host/wayland_event_source.cc +++ b/ui/ozone/platform/wayland/host/wayland_event_source.cc
@@ -86,8 +86,8 @@ // Number of fingers for scroll gestures. constexpr int kGestureScrollFingerCount = 2; -// Maximum size of the stored recent pointer frame information. -constexpr int kRecentPointerFrameMaxSize = 20; +// Maximum size of the latest pointer scroll data set to be stored. +constexpr int kPointerScrollDataSetMaxSize = 20; } // namespace @@ -105,15 +105,18 @@ DCHECK(window); } -WaylandEventSource::PointerFrame::PointerFrame() = default; -WaylandEventSource::PointerFrame::PointerFrame(const PointerFrame&) = default; -WaylandEventSource::PointerFrame::PointerFrame(PointerFrame&&) = default; -WaylandEventSource::PointerFrame::~PointerFrame() = default; +WaylandEventSource::PointerScrollData::PointerScrollData() = default; +WaylandEventSource::PointerScrollData::PointerScrollData( + const PointerScrollData&) = default; +WaylandEventSource::PointerScrollData::PointerScrollData(PointerScrollData&&) = + default; +WaylandEventSource::PointerScrollData::~PointerScrollData() = default; -WaylandEventSource::PointerFrame& WaylandEventSource::PointerFrame::operator=( - const PointerFrame&) = default; -WaylandEventSource::PointerFrame& WaylandEventSource::PointerFrame::operator=( - PointerFrame&&) = default; +WaylandEventSource::PointerScrollData& +WaylandEventSource::PointerScrollData::operator=(const PointerScrollData&) = + default; +WaylandEventSource::PointerScrollData& +WaylandEventSource::PointerScrollData::operator=(PointerScrollData&&) = default; WaylandEventSource::TouchFrame::TouchFrame(const TouchEvent& e, base::OnceCallback<void()> cb) @@ -250,7 +253,7 @@ // Save new pointer location. pointer_location_ = location; window_manager_->SetPointerFocusedWindow(window); - current_pointer_frame_.target = window; + pointer_scroll_data_.target = window; } auto* target = window_manager_->GetCurrentPointerFocusedWindow(); @@ -263,7 +266,7 @@ if (!focused) { window_manager_->SetPointerFocusedWindow(nullptr); - current_pointer_frame_.target = nullptr; + pointer_scroll_data_.target = nullptr; } } @@ -312,8 +315,8 @@ } void WaylandEventSource::OnPointerAxisEvent(const gfx::Vector2dF& offset) { - current_pointer_frame_.dx += offset.x(); - current_pointer_frame_.dy += offset.y(); + pointer_scroll_data_.dx += offset.x(); + pointer_scroll_data_.dy += offset.y(); } void WaylandEventSource::OnResetPointerFlags() { @@ -330,7 +333,7 @@ void WaylandEventSource::OnPointerFrameEvent() { base::TimeTicks now = EventTimeForNow(); - current_pointer_frame_.dt = now - last_pointer_frame_time_; + pointer_scroll_data_.dt = now - last_pointer_frame_time_; last_pointer_frame_time_ = now; int flags = pointer_flags_ | keyboard_modifiers_; @@ -341,14 +344,14 @@ #else false; #endif - auto* target = current_pointer_frame_.target; + auto* target = pointer_scroll_data_.target; if (!window_manager_->IsWindowValid(target)) return; // Dispatch Fling event if pointer.axis_stop is notified and the recent // pointer.axis events meets the criteria to start fling scroll. - if (current_pointer_frame_.dx == 0 && current_pointer_frame_.dy == 0 && - current_pointer_frame_.is_axis_stop && + if (pointer_scroll_data_.dx == 0 && pointer_scroll_data_.dy == 0 && + pointer_scroll_data_.is_axis_stop && supports_trackpad_kinetic_scrolling) { gfx::Vector2dF initial_velocity = ComputeFlingVelocity(); float vx = initial_velocity.x(); @@ -358,49 +361,48 @@ pointer_location_, pointer_location_, now, flags, vx, vy, vx, vy, kGestureScrollFingerCount); SetTargetAndDispatchEvent(&event, target); - recent_pointer_frames_.clear(); - } else if (current_pointer_frame_.axis_source) { - if (*current_pointer_frame_.axis_source == WL_POINTER_AXIS_SOURCE_WHEEL || - *current_pointer_frame_.axis_source == + } else if (pointer_scroll_data_.axis_source) { + if (*pointer_scroll_data_.axis_source == WL_POINTER_AXIS_SOURCE_WHEEL || + *pointer_scroll_data_.axis_source == WL_POINTER_AXIS_SOURCE_WHEEL_TILT) { MouseWheelEvent event( - gfx::Vector2d(current_pointer_frame_.dx, current_pointer_frame_.dy), + gfx::Vector2d(pointer_scroll_data_.dx, pointer_scroll_data_.dy), pointer_location_, pointer_location_, EventTimeForNow(), flags, 0); SetTargetAndDispatchEvent(&event, target); - } else if (*current_pointer_frame_.axis_source == + } else if (*pointer_scroll_data_.axis_source == WL_POINTER_AXIS_SOURCE_FINGER || - *current_pointer_frame_.axis_source == + *pointer_scroll_data_.axis_source == WL_POINTER_AXIS_SOURCE_CONTINUOUS) { ScrollEvent event(ET_SCROLL, pointer_location_, pointer_location_, - EventTimeForNow(), flags, current_pointer_frame_.dx, - current_pointer_frame_.dy, current_pointer_frame_.dx, - current_pointer_frame_.dy, kGestureScrollFingerCount); + EventTimeForNow(), flags, pointer_scroll_data_.dx, + pointer_scroll_data_.dy, pointer_scroll_data_.dx, + pointer_scroll_data_.dy, kGestureScrollFingerCount); SetTargetAndDispatchEvent(&event, target); } - if (recent_pointer_frames_.size() + 1 > kRecentPointerFrameMaxSize) - recent_pointer_frames_.pop_back(); - recent_pointer_frames_.push_front(current_pointer_frame_); + if (pointer_scroll_data_set_.size() + 1 > kPointerScrollDataSetMaxSize) + pointer_scroll_data_set_.pop_back(); + pointer_scroll_data_set_.push_front(pointer_scroll_data_); } - // Reset |current_pointer_frame_|. - current_pointer_frame_.dx = 0; - current_pointer_frame_.dy = 0; - current_pointer_frame_.is_axis_stop = false; - current_pointer_frame_.axis_source.reset(); + // Reset |pointer_scroll_data_|. + pointer_scroll_data_.dx = 0; + pointer_scroll_data_.dy = 0; + pointer_scroll_data_.is_axis_stop = false; + pointer_scroll_data_.axis_source.reset(); } void WaylandEventSource::OnPointerAxisSourceEvent(uint32_t axis_source) { - current_pointer_frame_.axis_source = axis_source; + pointer_scroll_data_.axis_source = axis_source; } void WaylandEventSource::OnPointerAxisStopEvent(uint32_t axis) { if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) { - current_pointer_frame_.dy = 0; + pointer_scroll_data_.dy = 0; } else if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) { - current_pointer_frame_.dx = 0; + pointer_scroll_data_.dx = 0; } - current_pointer_frame_.is_axis_stop = true; + pointer_scroll_data_.is_axis_stop = true; } void WaylandEventSource::OnTouchPressEvent( @@ -721,7 +723,7 @@ base::TimeDelta dt; float dx = 0.0f; float dy = 0.0f; - for (auto& frame : recent_pointer_frames_) { + for (auto& frame : pointer_scroll_data_set_) { if (frame.axis_source && *frame.axis_source != WL_POINTER_AXIS_SOURCE_FINGER) { break; @@ -735,6 +737,8 @@ dy += frame.dy; dt += frame.dt; } + pointer_scroll_data_set_.clear(); + float dt_inv = 1.0f / dt.InSecondsF(); return dt.is_zero() ? gfx::Vector2dF() : gfx::Vector2dF(dx * dt_inv, dy * dt_inv);
diff --git a/ui/ozone/platform/wayland/host/wayland_event_source.h b/ui/ozone/platform/wayland/host/wayland_event_source.h index 0bd3141e..f9b66c1 100644 --- a/ui/ozone/platform/wayland/host/wayland_event_source.h +++ b/ui/ozone/platform/wayland/host/wayland_event_source.h
@@ -156,14 +156,14 @@ void OnRelativePointerMotion(const gfx::Vector2dF& delta) override; private: - struct PointerFrame { - PointerFrame(); - PointerFrame(const PointerFrame& other); - PointerFrame(PointerFrame&&); - ~PointerFrame(); + struct PointerScrollData { + PointerScrollData(); + PointerScrollData(const PointerScrollData& other); + PointerScrollData(PointerScrollData&&); + ~PointerScrollData(); - PointerFrame& operator=(const PointerFrame&); - PointerFrame& operator=(PointerFrame&&); + PointerScrollData& operator=(const PointerScrollData&); + PointerScrollData& operator=(PointerScrollData&&); WaylandWindow* target = nullptr; absl::optional<uint32_t> axis_source; @@ -235,8 +235,12 @@ // Last known relative pointer location (used for pointer lock). absl::optional<gfx::PointF> relative_pointer_location_; - // Current frame - PointerFrame current_pointer_frame_; + // Accumulates the scroll data within a pointer frame internal. + PointerScrollData pointer_scroll_data_; + + // Latest set of pointer scroll data to compute fling scroll. + // Front is newer, and back is older. + std::deque<PointerScrollData> pointer_scroll_data_set_; // Time of the last pointer frame event. base::TimeTicks last_pointer_frame_time_; @@ -252,10 +256,6 @@ }; base::flat_map<PointerId, absl::optional<StylusData>> last_touch_stylus_data_; - // Recent pointer frames to compute fling scroll. - // Front is newer, and back is older. - std::deque<PointerFrame> recent_pointer_frames_; - // Order set of touch events to be dispatching on the next // wl_touch::frame event. std::deque<std::unique_ptr<TouchFrame>> touch_frames_;
diff --git a/ui/views/bubble/bubble_border.h b/ui/views/bubble/bubble_border.h index b688a30..dcbfcf6 100644 --- a/ui/views/bubble/bubble_border.h +++ b/ui/views/bubble/bubble_border.h
@@ -330,7 +330,7 @@ void Paint(gfx::Canvas* canvas, View* view) const override; private: - raw_ptr<BubbleBorder, DanglingUntriaged> border_; + raw_ptr<BubbleBorder> border_; }; } // namespace views
diff --git a/ui/views/view.h b/ui/views/view.h index ff9bb60f..3f5844b 100644 --- a/ui/views/view.h +++ b/ui/views/view.h
@@ -2101,12 +2101,13 @@ // Painting ------------------------------------------------------------------ - // Background - std::unique_ptr<Background> background_; - // Border. std::unique_ptr<Border> border_; + // Background may rely on Border, so it must be declared last and destroyed + // first. + std::unique_ptr<Background> background_; + // Cached output of painting to be reused in future frames until invalidated. ui::PaintCache paint_cache_;