diff --git a/.vpython3 b/.vpython3 index 1f38037..39206c2 100644 --- a/.vpython3 +++ b/.vpython3
@@ -28,7 +28,7 @@ # components/policy/test_support/policy_testserver.py wheel: < name: "infra/python/wheels/protobuf-py2_py3" - version: "version:3.6.1" + version: "version:3.15.8" > # TODO(https://crbug.com/898348): Add in necessary wheels as Python3 versions
diff --git a/DEPS b/DEPS index bb6c3250..f2cc73c 100644 --- a/DEPS +++ b/DEPS
@@ -209,7 +209,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': '42bee2d3d2a6c39d0c7956f137f4b42da7ee7552', + 'skia_revision': 'c6260f974261ee9fb5dc9573669559d728a856e8', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. @@ -221,7 +221,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - 'angle_revision': '88156d2686c8df127d1e5ba675221573a8a13b4c', + 'angle_revision': 'f871545d293f8fd55357eb2bcdaacea3cca9569f', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. @@ -280,7 +280,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': '64fcc4794c4e36bc60a2af6107e388bb6f6c166e', + 'catapult_revision': '7da48e9f874a0eec2d81aed2426c9da0af0d25ff', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -328,7 +328,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': 'ce3d4a5b094dce131453da9a5ef422671f20ad7d', + 'dawn_revision': 'b2527e6d9c03a4560ee5aff27c61de3b2a87b63d', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -895,7 +895,7 @@ }, 'src/third_party/breakpad/breakpad': - Var('chromium_git') + '/breakpad/breakpad.git' + '@' + '3bea2815bfea6e641d50aad15bde2c494ef8f34b', + Var('chromium_git') + '/breakpad/breakpad.git' + '@' + 'c484031f1f199ee53567241426efffee49008f82', 'src/third_party/byte_buddy': { 'packages': [ @@ -966,7 +966,7 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '3ffca4bed79f3b5336a93193c571484df09b1004', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'dd0076703b55ea14f15666c62759ea242906e4b7', 'src/third_party/devtools-frontend/src': Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), @@ -1438,7 +1438,7 @@ 'packages': [ { 'package': 'fuchsia/third_party/aemu/linux-amd64', - 'version': 'ZV7RwS9jPyaEWlNUpA8m6n3XwWC5ORRQMw8T_kUjsYEC' + 'version': 'uDQJbkoDWGwLYtnDu3A7LnRVwsKkaFQkUWtChrVO_hYC' }, ], 'condition': 'host_os == "linux" and checkout_fuchsia', @@ -1547,7 +1547,7 @@ 'src/third_party/usrsctp/usrsctplib': Var('chromium_git') + '/external/github.com/sctplab/usrsctp' + '@' + '22ba62ffe79c3881581ab430368bf3764d9533eb', - 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@108d5055b4a3068b1c71cb592a09698d4139c15b', + 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@02a51202ebfe6eae1f8af87e97f69bb6486f42e5', 'src/third_party/vulkan_memory_allocator': Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + '732a76d9d3c70d6aa487216495eeb28518349c3a', @@ -1635,7 +1635,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@210b0f0b51851d02d93d3424947d578c8bbbd09d', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@3e2ef08e4c5aa8a73b56bb12c6bc9c34845f0ed4', 'condition': 'checkout_src_internal', },
diff --git a/android_webview/browser/aw_browser_context.cc b/android_webview/browser/aw_browser_context.cc index 41493cd..dc4935c1 100644 --- a/android_webview/browser/aw_browser_context.cc +++ b/android_webview/browser/aw_browser_context.cc
@@ -173,7 +173,7 @@ form_database_service_ = std::make_unique<AwFormDatabaseService>(context_storage_path_); - EnsureResourceContextInitialized(this); + EnsureResourceContextInitialized(); // This constructor is entered during the creation of ContentBrowserClient, // before browser threads are created. Therefore any checks to enforce @@ -182,7 +182,7 @@ AwBrowserContext::~AwBrowserContext() { DCHECK_EQ(this, g_browser_context); - BrowserContext::NotifyWillBeDestroyed(this); + NotifyWillBeDestroyed(); SimpleKeyMap::GetInstance()->Dissociate(this); ShutdownStoragePartitions();
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc index d6bee0db..ae17246 100644 --- a/android_webview/browser/aw_content_browser_client.cc +++ b/android_webview/browser/aw_content_browser_client.cc
@@ -835,8 +835,7 @@ url::kFileScheme, content::CreateFileURLLoaderFactory( aw_browser_context->GetPath(), - content::BrowserContext::GetSharedCorsOriginAccessList( - aw_browser_context))); + aw_browser_context->GetSharedCorsOriginAccessList())); } }
diff --git a/android_webview/browser/aw_feature_list_creator.cc b/android_webview/browser/aw_feature_list_creator.cc index 6ae6f29..f63386f 100644 --- a/android_webview/browser/aw_feature_list_creator.cc +++ b/android_webview/browser/aw_feature_list_creator.cc
@@ -218,7 +218,7 @@ // able to break seed downloads. See https://crbug.com/801771 for more info. variations::SafeSeedManager ignored_safe_seed_manager(local_state_.get()); - // Populate FieldTrialList. Since low_entropy_provider is null, it will fall + // Populate FieldTrialList. Since |low_entropy_provider| is null, it will fall // back to the provider we previously gave to FieldTrialList, which is a low // entropy provider. The X-Client-Data header is not reported on WebView, so // we pass an empty object as the |low_entropy_source_value|. @@ -228,8 +228,8 @@ GetSwitchDependentFeatureOverrides( *base::CommandLine::ForCurrentProcess()), /*low_entropy_provider=*/nullptr, std::make_unique<base::FeatureList>(), - aw_field_trials_.get(), &ignored_safe_seed_manager, - /*low_entropy_source_value=*/absl::nullopt); + metrics_client->metrics_state_manager(), aw_field_trials_.get(), + &ignored_safe_seed_manager, /*low_entropy_source_value=*/absl::nullopt); } void AwFeatureListCreator::CreateLocalState() {
diff --git a/android_webview/docs/test-instructions.md b/android_webview/docs/test-instructions.md index f8f4e33..f602b37 100644 --- a/android_webview/docs/test-instructions.md +++ b/android_webview/docs/test-instructions.md
@@ -163,6 +163,42 @@ -f=AwContentsTest#testClearCacheInQuickSuccession ``` +#### Debugging hangs in instrumentation tests + +If an instrumentation test is hanging, it's possible to get a callstack from the +browser process. This requires running on a device with root. + +It's not possible to get a callstack from the renderer because the sandbox will +prevent the trace file from being written. A workaround if you want to see the +renderer threads is to run in single-process mode by adding +`@OnlyRunIn(SINGLE_PROCESS)` above the test. + +##### conventions + +| Label | | +|-----------|----------------------------------------------------------------| +| (shell) | in your workstation's shell | +| (phone) | inside the phone's shell which you entered through `adb shell` | + +```sh +# Find the pid +$ (shell) adb root +$ (shell) adb shell + +# Get the main WebView Shell pid, e.g. org.chromium.android_webview.shell and +# not org.chromium.android_webview.shell:sandboxed_process0 +$ (phone) ps -A | grep org.chromium.android_webview.shell +# Generate a callstack (this won't kill the process) +$ (phone) kill -3 pid +# Look for the latest trace +$ (phone) ls /data/anr/ -l +# Copy the trace locally +$ (shell) adb pull /data/anr/trace_01 /tmp/t1 +# Generate a callstack. Run this from the source directory. +$ (shell) third_party/android_platform/development/scripts/stack --output-directory=out/Release /tmp/t1 +``` + + ## External tests As WebView is an Android system component, we have some tests defined outside of
diff --git a/ash/app_list/views/search_result_list_view.cc b/ash/app_list/views/search_result_list_view.cc index dc7955d..608bc0e 100644 --- a/ash/app_list/views/search_result_list_view.cc +++ b/ash/app_list/views/search_result_list_view.cc
@@ -41,6 +41,10 @@ constexpr base::TimeDelta kImpressionThreshold = base::TimeDelta::FromSeconds(3); +// TODO(crbug.com/1199206): Move this into SharedAppListConfig once the UI for +// categories is more developed. +constexpr size_t kMaxResultsWithCategoricalSearch = 12; + SearchResultIdWithPositionIndices GetSearchResultsForLogging( std::vector<SearchResultView*> search_result_views) { SearchResultIdWithPositionIndices results; @@ -53,6 +57,12 @@ return results; } +size_t GetMaxSearchResultListItems() { + if (app_list_features::IsCategoricalSearchEnabled()) + return kMaxResultsWithCategoricalSearch; + return SharedAppListConfig::instance().max_search_result_list_items(); +} + } // namespace SearchResultListView::SearchResultListView(AppListMainView* main_view, @@ -65,7 +75,7 @@ views::BoxLayout::Orientation::kVertical)); size_t result_count = - SharedAppListConfig::instance().max_search_result_list_items() + + GetMaxSearchResultListItems() + SharedAppListConfig::instance().max_assistant_search_result_list_items(); for (size_t i = 0; i < result_count; ++i) { @@ -240,8 +250,7 @@ result.result_type() != AppListSearchResultType::kAssistantText; }), - /*max_results=*/ - SharedAppListConfig::instance().max_search_result_list_items()); + GetMaxSearchResultListItems()); std::vector<SearchResult*> assistant_results = GetAssistantResults();
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd index 737c272..01aa35b 100644 --- a/ash/ash_strings.grd +++ b/ash/ash_strings.grd
@@ -629,7 +629,7 @@ Mic is muted. </message> <message name="IDS_ASH_STATUS_TRAY_MIC_STATE_MUTED_BY_HW_SWITCH" desc="The text used as a tooltip for microphone mute button in Chrome OS quick settings when the mic gain button is muted because the device microphone mute switch is turned on. Used as a status text for IDS_ASH_STATUS_TRAY_MIC_GAIN."> - Device microphone button is muted. + Device's microphone button is turned off. </message> <message name="IDS_ASH_STATUS_AREA_TOAST_MIC_OFF" desc="The text in the toast that shows up when the mic is muted using a physical key or shortcut."> Microphone is off @@ -3551,7 +3551,7 @@ The Alt + click keyboard shortcut has changed. To use your keyboard to right-click, press the <ph name="LAUNCHER_KEY_NAME">$1<ex>Launcher</ex></ph> key + click. </message> <message name="IDS_ASH_SHORTCUT_DEPRECATION_FKEY" desc="Message telling user to use search/launcher + top row key instead of Search + a digit key to emulate a F-Key. The name of the launcher key varies by device and may be either Search or Launcher depending on the glyph on the keyboard."> - The <ph name="LAUNCHER_KEY_NAME">$1<ex>Launcher</ex></ph> + Number keyboard shortcut has changed. To use F-Keys, press the <ph name="LAUNCHER_KEY_NAME">$1<ex>Launcher</ex></ph> key + a key on the top row. + The <ph name="LAUNCHER_KEY_NAME">$1<ex>Launcher</ex></ph> + Number keyboard shortcut has changed. To use function keys, press the <ph name="LAUNCHER_KEY_NAME">$1<ex>Launcher</ex></ph> key + a key on the top row. </message> <message name="IDS_ASH_SHORTCUT_DEPRECATION_SEARCH_PERIOD_INSERT" desc="Message telling user to use search/launcher + shift + backspace instead of search/launcher + period to emulate the delete key. The name of the launcher key varies by device and may be either Search or Launcher depending on the glyph on the keyboard."> The <ph name="LAUNCHER_KEY_NAME">$1<ex>Launcher</ex></ph> + Period keyboard shortcut has changed. To use the Insert key, press the <ph name="LAUNCHER_KEY_NAME">$1<ex>Launcher</ex></ph> key + Shift + Backspace.
diff --git a/ash/ash_strings_grd/IDS_ASH_SHORTCUT_DEPRECATION_FKEY.png.sha1 b/ash/ash_strings_grd/IDS_ASH_SHORTCUT_DEPRECATION_FKEY.png.sha1 index 4bde087d..f69f7b4 100644 --- a/ash/ash_strings_grd/IDS_ASH_SHORTCUT_DEPRECATION_FKEY.png.sha1 +++ b/ash/ash_strings_grd/IDS_ASH_SHORTCUT_DEPRECATION_FKEY.png.sha1
@@ -1 +1 @@ -bfaf3221862d7f7675642f34eb15031142f93a6a \ No newline at end of file +1b9cd6f04d6d61a092be4fb5481a2866374609b9 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_MIC_STATE_MUTED_BY_HW_SWITCH.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_MIC_STATE_MUTED_BY_HW_SWITCH.png.sha1 index e86556f..6ff77de 100644 --- a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_MIC_STATE_MUTED_BY_HW_SWITCH.png.sha1 +++ b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_MIC_STATE_MUTED_BY_HW_SWITCH.png.sha1
@@ -1 +1 @@ -29406d3c186815f2d4699cb71e6b9fe597d78ff2 \ No newline at end of file +c7d932abd2fba64bb2ffc019400a528a02154451 \ No newline at end of file
diff --git a/ash/content/common/resources/BUILD.gn b/ash/content/common/resources/BUILD.gn index 50f4961..aa41ff7 100644 --- a/ash/content/common/resources/BUILD.gn +++ b/ash/content/common/resources/BUILD.gn
@@ -13,6 +13,7 @@ preprocessed_gen_manifest = "preprocessed_gen_manifest.json" polymer_element_files = [ + "navigation_icons.js", "navigation_selector.js", "navigation_view_panel.js", ] @@ -50,6 +51,7 @@ js_library("navigation_selector") { deps = [ + ":navigation_icons", "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", ] } @@ -61,6 +63,12 @@ ] } +js_library("navigation_icons") { + deps = [ + "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", + ] +} + preprocess_if_expr("preprocess_generated") { deps = [ ":web_components" ] in_folder = target_gen_dir
diff --git a/ash/content/common/resources/navigation_icons.html b/ash/content/common/resources/navigation_icons.html new file mode 100644 index 0000000..58dd798 --- /dev/null +++ b/ash/content/common/resources/navigation_icons.html
@@ -0,0 +1,8 @@ +<iron-iconset-svg name="navigation-selector" size="20"> + <svg> + <defs> + <!-- TODO(jimmyxgong): Replace this stub icon with actual icons. --> + <g id="laptop-chromebook" viewBox="0 0 24 24"><path d="M22 18V3H2v15H0v2h24v-2h-2zm-8 0h-4v-1h4v1zm6-3H4V5h16v10z"></path></g> + </defs> + </svg> +</iron-iconset-svg>
diff --git a/ash/content/common/resources/navigation_icons.js b/ash/content/common/resources/navigation_icons.js new file mode 100644 index 0000000..b401f8b --- /dev/null +++ b/ash/content/common/resources/navigation_icons.js
@@ -0,0 +1,10 @@ +// Copyright 2021 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 'chrome://resources/polymer/v3_0/iron-iconset-svg/iron-iconset-svg.js'; + +import {html} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; + +const template = html`{__html_template__}`; +document.head.appendChild(template.content); \ No newline at end of file
diff --git a/ash/content/common/resources/navigation_selector.html b/ash/content/common/resources/navigation_selector.html index c175093..cc526678 100644 --- a/ash/content/common/resources/navigation_selector.html +++ b/ash/content/common/resources/navigation_selector.html
@@ -31,6 +31,17 @@ color: var(--google-blue-600); } +iron-icon { + --iron-icon-fill-color: var(--google-grey-700); + margin-inline-end: 16px; + pointer-events: none; + vertical-align: top; +} + +.navigation-item.selected > iron-icon { + --iron-icon-fill-color: var(--google-blue-600); +} + cr-expand-button { padding-inline-start: 20px; } @@ -42,6 +53,8 @@ <template id="menuItems" is="dom-repeat" items="{{menuItems}}"> <template is="dom-if" if="[[!isCollapsible_(item)]]"> <div class="navigation-item" tabindex="0" on-click="onSelected_"> + <iron-icon class="icon" icon="[[item.selectorItem.icon]]" alt=""> + </iron-icon> [[item.selectorItem.name]] </div> </template> @@ -54,6 +67,8 @@ items="{{item.properties.subMenuItems}}"> <div class="navigation-item nested-item" tabindex="0" on-click="onNestedSelected_"> + <iron-icon class="icon" icon="[[getIcon_(item)]]" alt=""> + </iron-icon> [[item.name]] </div> </template>
diff --git a/ash/content/common/resources/navigation_selector.js b/ash/content/common/resources/navigation_selector.js index e5a92f2..17f4dd20 100644 --- a/ash/content/common/resources/navigation_selector.js +++ b/ash/content/common/resources/navigation_selector.js
@@ -4,15 +4,18 @@ import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import './navigation_icons.js'; import 'chrome://resources/cr_elements/cr_expand_button/cr_expand_button.m.js'; import 'chrome://resources/cr_elements/shared_style_css.m.js'; import 'chrome://resources/cr_elements/shared_vars_css.m.js'; import 'chrome://resources/polymer/v3_0/iron-collapse/iron-collapse.js'; +import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js'; /** * @typedef {{ * name: string, * pageIs: string, + * icon: string, * }} */ export let SelectorItem; @@ -140,6 +143,15 @@ isCollapsible_(item) { return item.properties.isCollapsible; } + + /** + * @param {!SelectorItem} item + * @return {string} + * @protected + */ + getIcon_(item) { + return item.icon; + } } customElements.define(NavigationSelectorElement.is, NavigationSelectorElement); \ No newline at end of file
diff --git a/ash/content/common/resources/navigation_view_panel.js b/ash/content/common/resources/navigation_view_panel.js index ca701f1..6fd24bd 100644 --- a/ash/content/common/resources/navigation_view_panel.js +++ b/ash/content/common/resources/navigation_view_panel.js
@@ -54,10 +54,12 @@ /** * @param {string} name * @param {string} pageIs + * @param {string} icon * @param {!Array<SelectorItem>} subItems */ - addSelector(name, pageIs, subItems=[]) { - let item = /** @type {SelectorItem} */ ({'name': name, 'pageIs': pageIs}); + addSelector(name, pageIs, icon='', subItems=[]) { + let item = /** @type {SelectorItem} */ ({ + 'name': name, 'pageIs': pageIs, 'icon': icon}); let property = /** @type {SelectorProperties} */ ({ 'isCollapsible': subItems.length, 'isExpanded': false, @@ -107,7 +109,7 @@ Array.from(components).map((c) => { const functionCall = c[functionName]; if (typeof functionCall === "function") { - functionCall({detail: params}); + functionCall.call(c, {detail: params}); } }); }
diff --git a/ash/content/shimless_rma/resources/BUILD.gn b/ash/content/shimless_rma/resources/BUILD.gn index ec236eb..6d6204b 100644 --- a/ash/content/shimless_rma/resources/BUILD.gn +++ b/ash/content/shimless_rma/resources/BUILD.gn
@@ -68,6 +68,7 @@ deps = [ ":shimless_rma_types", "//ash/content/common/resources:fake_method_resolver", + "//ash/content/common/resources:fake_observables", "//ui/webui/resources/js:cr.m", ] }
diff --git a/ash/content/shimless_rma/resources/fake_shimless_rma_service.js b/ash/content/shimless_rma/resources/fake_shimless_rma_service.js index 9f9f004..de01f163 100644 --- a/ash/content/shimless_rma/resources/fake_shimless_rma_service.js +++ b/ash/content/shimless_rma/resources/fake_shimless_rma_service.js
@@ -3,20 +3,22 @@ // found in the LICENSE file. import {FakeMethodResolver} from 'chrome://resources/ash/common/fake_method_resolver.js'; +import {FakeObservables} from 'chrome://resources/ash/common/fake_observables.js'; import {assert} from 'chrome://resources/js/assert.m.js'; -import {Component, ComponentRepairState, ComponentType, CurrentState, NextState, PrevState, RmadErrorCode, RmaState, ShimlessRmaServiceInterface, State} from './shimless_rma_types.js'; +import {CalibrationComponent, CalibrationObserver, Component, ComponentRepairState, ComponentType, CurrentState, ErrorObserver, HardwareWriteProtectionStateObserver, NextState, PowerCableStateObserver, PrevState, ProvisioningObserver, ProvisioningStep, RmadErrorCode, RmaState, ShimlessRmaServiceInterface, State} from './shimless_rma_types.js'; /** @implements {ShimlessRmaServiceInterface} */ export class FakeShimlessRmaService { constructor() { this.methods_ = new FakeMethodResolver(); + this.observables_ = new FakeObservables(); /** * The list of states for this RMA flow. * @private {!Array<!State>} */ - this.states_ = []; + this.states_ = []; /** * The index into states_ for the current fake state. @@ -165,28 +167,28 @@ } /** - * @return {!Promise<!{version: !string}>} + * @return {!Promise<!{version: string}>} */ getCurrentChromeVersion() { return this.methods_.resolveMethod('getCurrentChromeVersion'); } /** - * @param {!string} version + * @param {string} version */ setGetCurrentChromeVersionResult(version) { this.methods_.setResult('getCurrentChromeVersion', {version: version}); } /** - * @return {!Promise<!{updateAvailable: !boolean}>} + * @return {!Promise<!{updateAvailable: boolean}>} */ checkForChromeUpdates() { return this.methods_.resolveMethod('checkForChromeUpdates'); } /** - * @param {!boolean} available + * @param {boolean} available */ setCheckForChromeUpdatesResult(available) { this.methods_.setResult( @@ -224,14 +226,14 @@ } /** - * @return {!Promise<!{available: !boolean}>} + * @return {!Promise<!{available: boolean}>} */ manualDisableWriteProtectAvailable() { return this.methods_.resolveMethod('manualDisableWriteProtectAvailable'); } /** - * @param {!boolean} available} + * @param {boolean} available */ setManualDisableWriteProtectAvailableResult(available) { this.methods_.setResult( @@ -248,7 +250,7 @@ } /** - * @param {!string} code + * @param {string} code * @return {!Promise<!NextState>} */ rsuDisableWriteProtect(code) { @@ -293,14 +295,14 @@ } /** - * @return {!Promise<!{required: !boolean}>} + * @return {!Promise<!{required: boolean}>} */ reimageRequired() { return this.methods_.resolveMethod('reimageRequired'); } /** - * @param {!boolean} required + * @param {boolean} required */ setReimageRequiredResult(required) { this.methods_.setResult('reimageRequired', {required: required}); @@ -331,42 +333,42 @@ } /** - * @return {!Promise<!{regions: !Array<!string>}>} + * @return {!Promise<!{regions: !Array<string>}>} */ getRegionList() { return this.methods_.resolveMethod('getRegionList'); } /** - * @param {!Array<!string>} regions + * @param {!Array<string>} regions */ setGetRegionListResult(regions) { this.methods_.setResult('getRegionList', {regions: regions}); } /** - * @return {!Promise<!{skus: !Array<!string>}>} + * @return {!Promise<!{skus: !Array<string>}>} */ getSkuList() { return this.methods_.resolveMethod('getSkuList'); } /** - * @param {!Array<!string>} skus + * @param {!Array<string>} skus */ setGetSkuListResult(skus) { this.methods_.setResult('getSkuList', {skus: skus}); } /** - * @return {!Promise<!{serialNumber: !string}>} + * @return {!Promise<!{serialNumber: string}>} */ getOriginalSerialNumber() { return this.methods_.resolveMethod('getOriginalSerialNumber'); } /** - * @param {!string} serialNumber + * @param {string} serialNumber */ setGetOriginalSerialNumberResult(serialNumber) { this.serialNumber_ = serialNumber; @@ -375,7 +377,7 @@ } /** - * @return {!Promise<!{serialNumber: !string}>} + * @return {!Promise<!{serialNumber: string}>} */ getSerialNumber() { this.methods_.setResult( @@ -384,7 +386,7 @@ } /** - * @param {!string} serialNumber + * @param {string} serialNumber * @return {!Promise<!{error: !RmadErrorCode}>} */ setSerialNumber(serialNumber) { @@ -403,14 +405,14 @@ } /** - * @return {!Promise<!{regionIndex: !number}>} + * @return {!Promise<!{regionIndex: number}>} */ getOriginalRegion() { return this.methods_.resolveMethod('getOriginalRegion'); } /** - * @param {!number} regionIndex + * @param {number} regionIndex */ setGetOriginalRegionResult(regionIndex) { this.regionIndex_ = regionIndex; @@ -418,7 +420,7 @@ } /** - * @return {!Promise<!{regionIndex: !number}>} + * @return {!Promise<!{regionIndex: number}>} */ getRegion() { this.methods_.setResult('getRegion', {regionIndex: this.regionIndex_}); @@ -426,7 +428,7 @@ } /** - * @param {!number} regionIndex + * @param {number} regionIndex * @return {!Promise<!{error: !RmadErrorCode}>} */ setRegion(regionIndex) { @@ -446,14 +448,14 @@ } /** - * @return {!Promise<!{skuIndex: !number}>} + * @return {!Promise<!{skuIndex: number}>} */ getOriginalSku() { return this.methods_.resolveMethod('getOriginalSku'); } /** - * @param {!number} skuIndex + * @param {number} skuIndex */ setGetOriginalSkuResult(skuIndex) { this.skuIndex_ = skuIndex; @@ -461,7 +463,7 @@ } /** - * @return {!Promise<!{skuIndex: !number}>} + * @return {!Promise<!{skuIndex: number}>} */ getSku() { this.methods_.setResult('getSku', {skuIndex: this.skuIndex_}); @@ -469,7 +471,7 @@ } /** - * @param {!number} skuIndex + * @param {number} skuIndex * @return {!Promise<!{error: !RmadErrorCode}>} */ setSku(skuIndex) { @@ -503,10 +505,173 @@ } /** + * Implements ShimlessRmaServiceInterface.ObserveError. + * @param {!ErrorObserver} remote + */ + observeError(remote) { + this.observables_.observe('ErrorObserver_onError', (error) => { + remote.onError( + /** @type {!RmadErrorCode} */ (error)); + }); + } + + /** + * Implements ShimlessRmaServiceInterface.ObserveCalibration. + * @param {!CalibrationObserver} remote + */ + observeCalibration(remote) { + this.observables_.observe( + 'CalibrationObserver_onCalibrationUpdated', (component, progress) => { + remote.onCalibrationUpdated( + /** @type {!CalibrationComponent} */ (component), + /** @type {number} */ (progress)); + }); + } + + /** + * Implements ShimlessRmaServiceInterface.ObserveProvisioning. + * @param {!ProvisioningObserver} remote + */ + observeProvisioning(remote) { + this.observables_.observe( + 'ProvisioningObserver_onProvisioningUpdated', (step, progress) => { + remote.onProvisioningUpdated( + /** @type {!ProvisioningStep} */ (step), + /** @type {number} */ (progress)); + }); + } + + /** + * Implements ShimlessRmaServiceInterface.ObserveHardwareWriteProtectionState. + * @param {!HardwareWriteProtectionStateObserver} remote + */ + observeHardwareWriteProtectionState(remote) { + this.observables_.observe( + 'HardwareWriteProtectionStateObserver_onHardwareWriteProtectionStateChanged', + (enabled) => { + remote.onHardwareWriteProtectionStateChanged( + /** @type {boolean} */ (enabled)); + }); + } + + /** + * Implements ShimlessRmaServiceInterface.ObservePowerCableState. + * @param {!PowerCableStateObserver} remote + */ + observePowerCableState(remote) { + this.observables_.observe( + 'PowerCableStateObserver_onPowerCableStateChanged', (pluggedIn) => { + remote.onPowerCableStateChanged(/** @type {boolean} */ (pluggedIn)); + }); + } + + /** + * Causes the error observer to fire after a delay. + * @param {!RmadErrorCode} error + * @param {number} delayMs + */ + triggerErrorObserver(error, delayMs) { + return this.triggerObserverAfterMs('ErrorObserver_onError', error, delayMs); + } + + /** + * Causes the calibration observer to fire after a delay. + * @param {!CalibrationComponent} component + * @param {number} progress + * @param {number} delayMs + */ + triggerCalibrationObserver(component, progress, delayMs) { + return this.triggerObserverAfterMs( + 'CalibrationObserver_onCalibrationUpdated', [component, progress], + delayMs); + } + + /** + * Causes the provisioning observer to fire after a delay. + * @param {!ProvisioningStep} step + * @param {number} progress + * @param {number} delayMs + */ + triggerProvisioningObserver(step, progress, delayMs) { + return this.triggerObserverAfterMs( + 'ProvisioningObserver_onProvisioningUpdated', [step, progress], + delayMs); + } + + /** + * Causes the hardware write protection observer to fire after a delay. + * @param {boolean} enabled + * @param {number} delayMs + */ + triggerHardwareWriteProtectionObserver(enabled, delayMs) { + return this.triggerObserverAfterMs( + 'HardwareWriteProtectionStateObserver_onHardwareWriteProtectionStateChanged', + enabled, delayMs); + } + + /** + * Causes the power cable observer to fire after a delay. + * @param {boolean} pluggedIn + * @param {number} delayMs + */ + triggerPowerCableObserver(pluggedIn, delayMs) { + return this.triggerObserverAfterMs( + 'PowerCableStateObserver_onPowerCableStateChanged', pluggedIn, delayMs); + } + + /** + * Causes an observer to fire after a delay. + * @param {string} method + * @param {!T} result + * @param {number} delayMs + * @template T + */ + triggerObserverAfterMs(method, result, delayMs) { + let setDataTriggerAndResolve = function (service, resolve) { + service.observables_.setObservableData(method, [result]); + service.observables_.trigger(method); + resolve(); + } + return new Promise((resolve) => { + if (delayMs === 0) { + setDataTriggerAndResolve(this, resolve); + } else { + setTimeout(() => { + setDataTriggerAndResolve(this, resolve); + }, delayMs); + } + }); + } + + /** + * Disables all observers and resets provider to its initial state. + */ + reset() { + this.registerMethods_(); + this.registerObservables_(); + + this.states_ = []; + this.stateIndex_ = 0; + + // This state data is more complicated so the behavior of the get/set + // methods is a little different than other fakes in that they don't return + // undefined by default. + this.components_ = []; + this.serialNumber_ = ''; + this.setSetSerialNumberResult(RmadErrorCode.kOk); + this.regionIndex_ = 0; + this.setSetRegionResult(RmadErrorCode.kOk); + this.skuIndex_ = 0; + this.setSetSkuResult(RmadErrorCode.kOk); + } + + /** * Setup method resolvers. * @private */ registerMethods_() { + this.methods_ = new FakeMethodResolver(); + this.methods_.register('getCurrentState'); this.methods_.register('getNextState'); this.methods_.register('getPrevState'); @@ -548,30 +713,26 @@ } /** - * Disables all observers and resets provider to its initial state. + * Setup observables. + * @private */ - reset() { - this.methods_ = new FakeMethodResolver(); - this.registerMethods_(); - - this.states_ = []; - this.stateIndex_ = 0; - - // This state data is more complicated so the behavior of the get/set - // methods is a little different than other fakes in that they don't return - // undefined by default. - this.components_ = []; - this.serialNumber_ = ''; - this.setSetSerialNumberResult(RmadErrorCode.kOk); - this.regionIndex_ = 0; - this.setSetRegionResult(RmadErrorCode.kOk); - this.skuIndex_ = 0; - this.setSetSkuResult(RmadErrorCode.kOk); + registerObservables_() { + if (this.observables_) { + this.observables_.stopAllTriggerIntervals(); + } + this.observables_ = new FakeObservables(); + this.observables_.register('ErrorObserver_onError'); + this.observables_.register('CalibrationObserver_onCalibrationUpdated'); + this.observables_.register('ProvisioningObserver_onProvisioningUpdated'); + this.observables_.register( + 'HardwareWriteProtectionStateObserver_onHardwareWriteProtectionStateChanged'); + this.observables_.register( + 'PowerCableStateObserver_onPowerCableStateChanged'); } /** * @private - * @param {!string} method + * @param {string} method * @param {!RmaState} expectedState * @returns {!Promise<!NextState>} */ @@ -615,7 +776,7 @@ * Sets the value that will be returned when calling state specific functions * that progress state. e.g. setSameOwner() * @private - * @param {!string} method + * @param {string} method * @param {!RmaState} state * @param {!RmadErrorCode} error */
diff --git a/ash/content/shimless_rma/resources/shimless_rma.js b/ash/content/shimless_rma/resources/shimless_rma.js index 6b5a268..412cc61 100644 --- a/ash/content/shimless_rma/resources/shimless_rma.js +++ b/ash/content/shimless_rma/resources/shimless_rma.js
@@ -71,6 +71,8 @@ ready() { super.ready(); this.shimlessRmaService_ = getShimlessRmaService(); + + // Get the initial state. this.fetchState_().then((state) => this.loadState_(state)); }
diff --git a/ash/content/shimless_rma/resources/shimless_rma_types.js b/ash/content/shimless_rma/resources/shimless_rma_types.js index 63276ca..493bb6fd 100644 --- a/ash/content/shimless_rma/resources/shimless_rma_types.js +++ b/ash/content/shimless_rma/resources/shimless_rma_types.js
@@ -137,31 +137,60 @@ /** * @typedef {{state: !RmaState, error: !RmadErrorCode}} */ - export let State; - - /** - * @typedef {{currentState: !RmaState, error: !RmadErrorCode}} - */ - export let CurrentState; - - /** - * @typedef {{nextState: !RmaState, error: !RmadErrorCode}} - */ - export let NextState; - - /** - * @typedef {{prevState: !RmaState, error: !RmadErrorCode}} - */ - export let PrevState; +export let State; /** - * Type alias for NetworkListObserver. - * @typedef {{ - * onError: !function(!RmadErrorCode) - * }} + * @typedef {{currentState: !RmaState, error: !RmadErrorCode}} + */ +export let CurrentState; + +/** + * @typedef {{nextState: !RmaState, error: !RmadErrorCode}} + */ +export let NextState; + +/** + * @typedef {{prevState: !RmaState, error: !RmadErrorCode}} + */ +export let PrevState; + +/** + * Type alias for ErrorObserver. + * @typedef {{onError: !function(!RmadErrorCode)}} */ export let ErrorObserver; +/** + * Type alias for CalibrationProgressObserver. + * @typedef {{ + * onCalibrationUpdated: !function(!CalibrationComponent, number) + * }} + */ +export let CalibrationObserver; + +/** + * Type alias for ProvisioningProgressObserver. + * @typedef {{ + * onProvisioningUpdated: !function(!ProvisioningStep, number) + * }} + */ +export let ProvisioningObserver; + +/** + * Type alias for HardwareWriteProtectionState. + * @typedef {{ + * onHardwareWriteProtectionStateChanged: !function(boolean) + * }} + */ +export let HardwareWriteProtectionStateObserver; + +/** + * Type alias for PowerCableState. + * @typedef {{ + * onPowerCableStateChanged: !function(boolean) + * }} + */ +export let PowerCableStateObserver; /** * Type of ShimlessRmaServiceInterface.setStates function.
diff --git a/ash/content/shortcut_customization_ui/resources/shortcut_customization_app.js b/ash/content/shortcut_customization_ui/resources/shortcut_customization_app.js index e0ec642..c4a4a137 100644 --- a/ash/content/shortcut_customization_ui/resources/shortcut_customization_app.js +++ b/ash/content/shortcut_customization_ui/resources/shortcut_customization_app.js
@@ -28,11 +28,15 @@ ready() { super.ready(); this.$.navigationPanel.addSelector('Chrome OS', - 'chromeos-shortcuts-page'); - this.$.navigationPanel.addSelector('Browser', 'browser-shortcuts-page'); - this.$.navigationPanel.addSelector('Android', 'android-shortcuts-page'); + 'chromeos-shortcuts-page', + 'navigation-selector:laptop-chromebook'); + this.$.navigationPanel.addSelector('Browser', 'browser-shortcuts-page', + 'navigation-selector:laptop-chromebook'); + this.$.navigationPanel.addSelector('Android', 'android-shortcuts-page', + 'navigation-selector:laptop-chromebook'); this.$.navigationPanel.addSelector('Accessibility', - 'accessibility-shortcuts-page'); + 'accessibility-shortcuts-page', + 'navigation-selector:laptop-chromebook'); } }
diff --git a/ash/login/ui/lock_contents_view.cc b/ash/login/ui/lock_contents_view.cc index 3e4fc4f0..55de90b 100644 --- a/ash/login/ui/lock_contents_view.cc +++ b/ash/login/ui/lock_contents_view.cc
@@ -1639,17 +1639,26 @@ primary_big_view_ = main_view_->AddChildView(std::move(primary_big_view)); auto* spacing_middle = main_view_->AddChildView(std::make_unique<NonAccessibleView>()); - users_list_ = main_view_->AddChildView( - BuildScrollableUsersListView(users, LoginDisplayStyle::kSmall)); + users_list_ = + main_view_->AddChildView(std::make_unique<ScrollableUsersListView>( + users, + base::BindRepeating(&LockContentsView::SwapToBigUser, + base::Unretained(this)), + LoginDisplayStyle::kSmall)); auto* spacing_right = main_view_->AddChildView(std::make_unique<NonAccessibleView>()); // Set width for the |spacing_*| views. AddDisplayLayoutAction(base::BindRepeating( [](views::View* host_view, views::View* big_user_view, - views::View* users_list, views::View* spacing_left, + ScrollableUsersListView* users_list, views::View* spacing_left, views::View* spacing_middle, views::View* spacing_right, bool landscape) { + // `users_list` has margins that depend on the current orientation. + // Update these here so that the following calculations see the correct + // bounds. + users_list->UpdateUserViewHostLayoutInsets(); + int total_width = host_view->GetPreferredSize().width(); int available_width = total_width - (big_user_view->GetPreferredSize().width() + @@ -1694,8 +1703,12 @@ fill = main_view_->AddChildView(std::make_unique<NonAccessibleView>()); main_layout->SetFlexForView(fill, 1); - users_list_ = main_view_->AddChildView( - BuildScrollableUsersListView(users, LoginDisplayStyle::kExtraSmall)); + users_list_ = + main_view_->AddChildView(std::make_unique<ScrollableUsersListView>( + users, + base::BindRepeating(&LockContentsView::SwapToBigUser, + base::Unretained(this)), + LoginDisplayStyle::kExtraSmall)); // User list size may change after a display metric change. AddDisplayLayoutAction(base::BindRepeating( @@ -2248,20 +2261,6 @@ return users_list_->GetUserView(user); } -std::unique_ptr<ScrollableUsersListView> -LockContentsView::BuildScrollableUsersListView( - const std::vector<LoginUserInfo>& users, - LoginDisplayStyle display_style) { - auto user_list_view = std::make_unique<ScrollableUsersListView>( - users, - base::BindRepeating(&LockContentsView::SwapToBigUser, - base::Unretained(this)), - display_style); - user_list_view->ClipHeightTo(user_list_view->contents()->size().height(), - size().height()); - return user_list_view; -} - void LockContentsView::SetDisplayStyle(DisplayStyle style) { const bool show_expanded_view = style == DisplayStyle::kExclusivePublicAccountExpandedView;
diff --git a/ash/login/ui/lock_contents_view.h b/ash/login/ui/lock_contents_view.h index 2e5c68b..a569ff1 100644 --- a/ash/login/ui/lock_contents_view.h +++ b/ash/login/ui/lock_contents_view.h
@@ -390,11 +390,6 @@ // Returns the user view for |user|. LoginUserView* TryToFindUserView(const AccountId& user); - // Returns scrollable view with initialized size and rows for all |users|. - std::unique_ptr<ScrollableUsersListView> BuildScrollableUsersListView( - const std::vector<LoginUserInfo>& users, - LoginDisplayStyle display_style); - // Change the visibility of child views based on the |style|. void SetDisplayStyle(DisplayStyle style);
diff --git a/ash/login/ui/lock_contents_view_unittest.cc b/ash/login/ui/lock_contents_view_unittest.cc index be64b497..0711dd9 100644 --- a/ash/login/ui/lock_contents_view_unittest.cc +++ b/ash/login/ui/lock_contents_view_unittest.cc
@@ -278,9 +278,9 @@ mojom::TrayActionState::kNotAvailable, LockScreen::ScreenType::kLock, DataDispatcher(), std::make_unique<FakeLoginDetachableBaseModel>(DataDispatcher())); + std::unique_ptr<views::Widget> widget = CreateWidgetWithContent(contents); LockContentsView::TestApi lock_contents(contents); SetUserCount(3); - std::unique_ptr<views::Widget> widget = CreateWidgetWithContent(contents); // Returns the distance between the auth user view and the user view. auto calculate_distance = [&]() { @@ -298,11 +298,13 @@ widget->GetNativeWindow()); for (int i = 2; i < 10; ++i) { SetUserCount(i); + SCOPED_TRACE(testing::Message() << "User count: " << i); // Start at 0 degrees (landscape). display_manager()->SetDisplayRotation( display.id(), display::Display::ROTATE_0, display::Display::RotationSource::ACTIVE); + widget->LayoutRootViewIfNecessary(); int distance_0deg = calculate_distance(); EXPECT_NE(distance_0deg, 0); @@ -310,16 +312,18 @@ display_manager()->SetDisplayRotation( display.id(), display::Display::ROTATE_90, display::Display::RotationSource::ACTIVE); + widget->LayoutRootViewIfNecessary(); int distance_90deg = calculate_distance(); - EXPECT_GT(distance_0deg, distance_90deg); + EXPECT_LT(distance_90deg, distance_0deg); // Rotate the display back to 0 degrees (landscape). display_manager()->SetDisplayRotation( display.id(), display::Display::ROTATE_0, display::Display::RotationSource::ACTIVE); - int distance_180deg = calculate_distance(); - EXPECT_EQ(distance_0deg, distance_180deg); - EXPECT_NE(distance_0deg, distance_90deg); + widget->LayoutRootViewIfNecessary(); + int distance_0deg_2 = calculate_distance(); + EXPECT_EQ(distance_0deg_2, distance_0deg); + EXPECT_NE(distance_0deg_2, distance_90deg); } } @@ -329,10 +333,10 @@ mojom::TrayActionState::kNotAvailable, LockScreen::ScreenType::kLock, DataDispatcher(), std::make_unique<FakeLoginDetachableBaseModel>(DataDispatcher())); + std::unique_ptr<views::Widget> widget = CreateWidgetWithContent(contents); SetUserCount(9); ScrollableUsersListView* users_list = LockContentsView::TestApi(contents).users_list(); - std::unique_ptr<views::Widget> widget = CreateWidgetWithContent(contents); // Users list in extra small layout should adjust its height to parent. EXPECT_EQ(contents->height(), users_list->height()); @@ -366,10 +370,10 @@ mojom::TrayActionState::kNotAvailable, LockScreen::ScreenType::kLock, DataDispatcher(), std::make_unique<FakeLoginDetachableBaseModel>(DataDispatcher())); + std::unique_ptr<views::Widget> widget = CreateWidgetWithContent(contents); SetUserCount(4); ScrollableUsersListView* users_list = LockContentsView::TestApi(contents).users_list(); - std::unique_ptr<views::Widget> widget = CreateWidgetWithContent(contents); // Calculate top spacing between users list and lock screen contents. auto top_margin = [&]() { @@ -547,11 +551,11 @@ mojom::TrayActionState::kNotAvailable, LockScreen::ScreenType::kLock, DataDispatcher(), std::make_unique<FakeLoginDetachableBaseModel>(DataDispatcher())); + std::unique_ptr<views::Widget> widget = CreateWidgetWithContent(contents); LockContentsView::TestApi lock_contents(contents); SetUserCount(5); ScrollableUsersListView::TestApi users_list(lock_contents.users_list()); EXPECT_EQ(users().size() - 1, users_list.user_views().size()); - std::unique_ptr<views::Widget> widget = CreateWidgetWithContent(contents); LoginBigUserView* auth_view = lock_contents.primary_big_view(); @@ -1896,9 +1900,9 @@ mojom::TrayActionState::kNotAvailable, LockScreen::ScreenType::kLock, DataDispatcher(), std::make_unique<FakeLoginDetachableBaseModel>(DataDispatcher())); + std::unique_ptr<views::Widget> widget = CreateWidgetWithContent(contents); LockContentsView::TestApi contents_test_api(contents); AddUsers(3); - std::unique_ptr<views::Widget> widget = CreateWidgetWithContent(contents); LoginPasswordView* password_view = LoginAuthUserView::TestApi( @@ -1922,8 +1926,8 @@ auto* contents = new LockContentsView( mojom::TrayActionState::kNotAvailable, LockScreen::ScreenType::kLock, DataDispatcher(), std::move(fake_detachable_base_model)); - SetUserCount(3); std::unique_ptr<views::Widget> widget = CreateWidgetWithContent(contents); + SetUserCount(3); LockContentsView::TestApi test_api(contents); LoginBigUserView* primary_view = test_api.primary_big_view(); @@ -2672,8 +2676,8 @@ mojom::TrayActionState::kNotAvailable, LockScreen::ScreenType::kLogin, DataDispatcher(), std::make_unique<FakeLoginDetachableBaseModel>(DataDispatcher())); - SetUserCount(3); SetWidget(CreateWidgetWithContent(contents)); + SetUserCount(3); LockContentsView::TestApi lock_contents(contents); ScrollableUsersListView::TestApi users_list(lock_contents.users_list());
diff --git a/ash/login/ui/scrollable_users_list_view.cc b/ash/login/ui/scrollable_users_list_view.cc index 9be492f..aa3ce621 100644 --- a/ash/login/ui/scrollable_users_list_view.cc +++ b/ash/login/ui/scrollable_users_list_view.cc
@@ -353,6 +353,16 @@ return nullptr; } +void ScrollableUsersListView::UpdateUserViewHostLayoutInsets() { + DCHECK(GetWidget()); + bool should_show_landscape = + login_views_utils::ShouldShowLandscape(GetWidget()); + LayoutParams layout_params = BuildLayoutForStyle(display_style_); + user_view_host_layout_->set_inside_border_insets( + should_show_landscape ? layout_params.insets_landscape + : layout_params.insets_portrait); +} + void ScrollableUsersListView::Layout() { DCHECK(user_view_host_layout_); @@ -364,13 +374,7 @@ PreferredSizeChanged(); } - // Update the user view layout. - bool should_show_landscape = - login_views_utils::ShouldShowLandscape(GetWidget()); - LayoutParams layout_params = BuildLayoutForStyle(display_style_); - user_view_host_layout_->set_inside_border_insets( - should_show_landscape ? layout_params.insets_landscape - : layout_params.insets_portrait); + UpdateUserViewHostLayoutInsets(); // Layout everything. ScrollView::Layout();
diff --git a/ash/login/ui/scrollable_users_list_view.h b/ash/login/ui/scrollable_users_list_view.h index a5e7ee9..11034f2 100644 --- a/ash/login/ui/scrollable_users_list_view.h +++ b/ash/login/ui/scrollable_users_list_view.h
@@ -63,6 +63,10 @@ // Returns user view with |account_id| if it exists or nullptr otherwise. LoginUserView* GetUserView(const AccountId& account_id); + // Updates the insets for the `user_view_host_layout_` based on whether the + // view is in landscape or portrait mode. + void UpdateUserViewHostLayoutInsets(); + // views::View: void Layout() override; void OnPaintBackground(gfx::Canvas* canvas) override;
diff --git a/ash/public/cpp/holding_space/holding_space_image.cc b/ash/public/cpp/holding_space/holding_space_image.cc index adb4ce41..8ff85e1 100644 --- a/ash/public/cpp/holding_space/holding_space_image.cc +++ b/ash/public/cpp/holding_space/holding_space_image.cc
@@ -115,6 +115,7 @@ gfx::Size size; switch (type) { case HoldingSpaceItem::Type::kArcDownload: + case HoldingSpaceItem::Type::kDiagnosticsLog: case HoldingSpaceItem::Type::kDownload: case HoldingSpaceItem::Type::kNearbyShare: case HoldingSpaceItem::Type::kPinnedFile:
diff --git a/ash/public/cpp/holding_space/holding_space_item.cc b/ash/public/cpp/holding_space/holding_space_item.cc index 46c2a58..86d50ee0 100644 --- a/ash/public/cpp/holding_space/holding_space_item.cc +++ b/ash/public/cpp/holding_space/holding_space_item.cc
@@ -70,6 +70,7 @@ bool HoldingSpaceItem::IsDownload(HoldingSpaceItem::Type type) { switch (type) { case Type::kArcDownload: + case Type::kDiagnosticsLog: case Type::kDownload: return true; case Type::kNearbyShare: @@ -198,6 +199,7 @@ case Type::kScreenshot: return true; case Type::kArcDownload: + case Type::kDiagnosticsLog: case Type::kDownload: case Type::kNearbyShare: case Type::kPinnedFile:
diff --git a/ash/public/cpp/holding_space/holding_space_item.h b/ash/public/cpp/holding_space/holding_space_item.h index 528ce97..8abf670 100644 --- a/ash/public/cpp/holding_space/holding_space_item.h +++ b/ash/public/cpp/holding_space/holding_space_item.h
@@ -38,7 +38,8 @@ kScreenRecording = 4, kArcDownload = 5, kPrintedPdf = 6, - kMaxValue = kPrintedPdf, + kDiagnosticsLog = 7, + kMaxValue = kDiagnosticsLog, }; HoldingSpaceItem(const HoldingSpaceItem&) = delete;
diff --git a/ash/public/cpp/holding_space/holding_space_metrics.cc b/ash/public/cpp/holding_space/holding_space_metrics.cc index beff27b6..583b3dd 100644 --- a/ash/public/cpp/holding_space/holding_space_metrics.cc +++ b/ash/public/cpp/holding_space/holding_space_metrics.cc
@@ -70,6 +70,8 @@ switch (type) { case HoldingSpaceItem::Type::kArcDownload: return "ArcDownload"; + case HoldingSpaceItem::Type::kDiagnosticsLog: + return "DiagnosticsLog"; case HoldingSpaceItem::Type::kDownload: return "Download"; case HoldingSpaceItem::Type::kNearbyShare:
diff --git a/ash/resources/vector_icons/BUILD.gn b/ash/resources/vector_icons/BUILD.gn index 9448bf4..e62d97c 100644 --- a/ash/resources/vector_icons/BUILD.gn +++ b/ash/resources/vector_icons/BUILD.gn
@@ -9,6 +9,8 @@ icon_directory = "." sources = [ + "add_cellular_network.icon", + "add_cellular_network_rtl.icon", "always_show_shelf.icon", "auto_hide.icon", "autoclick.icon",
diff --git a/components/vector_icons/add_cellular_network.icon b/ash/resources/vector_icons/add_cellular_network.icon similarity index 100% rename from components/vector_icons/add_cellular_network.icon rename to ash/resources/vector_icons/add_cellular_network.icon
diff --git a/ash/resources/vector_icons/add_cellular_network_rtl.icon b/ash/resources/vector_icons/add_cellular_network_rtl.icon new file mode 100644 index 0000000..7f2fa1f --- /dev/null +++ b/ash/resources/vector_icons/add_cellular_network_rtl.icon
@@ -0,0 +1,28 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +CANVAS_DIMENSIONS, 20, +MOVE_TO, 3, 16, +CUBIC_TO, 3, 16.55f, 3.45f, 17, 4, 17, +H_LINE_TO, 11, +CUBIC_TO, 10.37f, 16.17f, 10, 15.13f, 10, 14, +CUBIC_TO, 10, 12.77f, 10.44f, 11.64f, 11.18f, 10.77f, +LINE_TO, 4.71f, 4.29f, +CUBIC_TO, 4.08f, 3.66f, 3, 4.11f, 3, 5, +V_LINE_TO, 16, +CLOSE, +MOVE_TO, 16, 17, +V_LINE_TO, 15, +H_LINE_TO, 18, +V_LINE_TO, 13, +H_LINE_TO, 16, +V_LINE_TO, 11, +H_LINE_TO, 14, +V_LINE_TO, 13, +H_LINE_TO, 12, +V_LINE_TO, 15, +H_LINE_TO, 14, +V_LINE_TO, 17, +H_LINE_TO, 16, +CLOSE \ No newline at end of file
diff --git a/ash/system/holding_space/downloads_section.cc b/ash/system/holding_space/downloads_section.cc index 464c5f3..08c769b 100644 --- a/ash/system/holding_space/downloads_section.cc +++ b/ash/system/holding_space/downloads_section.cc
@@ -130,6 +130,7 @@ : HoldingSpaceItemViewsSection(delegate, /*supported_types=*/ {HoldingSpaceItem::Type::kArcDownload, + HoldingSpaceItem::Type::kDiagnosticsLog, HoldingSpaceItem::Type::kDownload, HoldingSpaceItem::Type::kNearbyShare, HoldingSpaceItem::Type::kPrintedPdf},
diff --git a/ash/system/holding_space/holding_space_tray_unittest.cc b/ash/system/holding_space/holding_space_tray_unittest.cc index 7e74880..74d2fb6 100644 --- a/ash/system/holding_space/holding_space_tray_unittest.cc +++ b/ash/system/holding_space/holding_space_tray_unittest.cc
@@ -955,6 +955,7 @@ All, HoldingSpaceTrayDownloadsSectionTest, ::testing::Values(HoldingSpaceItem::Type::kArcDownload, + HoldingSpaceItem::Type::kDiagnosticsLog, HoldingSpaceItem::Type::kDownload, HoldingSpaceItem::Type::kNearbyShare, HoldingSpaceItem::Type::kPrintedPdf));
diff --git a/ash/system/network/cellular_setup_notifier.cc b/ash/system/network/cellular_setup_notifier.cc index ded72dfd..b5b18d8e 100644 --- a/ash/system/network/cellular_setup_notifier.cc +++ b/ash/system/network/cellular_setup_notifier.cc
@@ -8,6 +8,7 @@ #include "ash/public/cpp/network_config_service.h" #include "ash/public/cpp/notification_utils.h" #include "ash/public/cpp/system_tray_client.h" +#include "ash/resources/vector_icons/vector_icons.h" #include "ash/session/session_controller_impl.h" #include "ash/shell.h" #include "ash/strings/grit/ash_strings.h" @@ -183,7 +184,7 @@ message_center::RichNotificationData(), base::MakeRefCounted<message_center::HandleNotificationClickDelegate>( base::BindRepeating(&OnCellularSetupNotificationClicked)), - vector_icons::kAddCellularNetworkIcon, + kAddCellularNetworkIcon, message_center::SystemNotificationWarningLevel::NORMAL); message_center::MessageCenter* message_center =
diff --git a/ash/system/network/network_section_header_view.cc b/ash/system/network/network_section_header_view.cc index ab86945a..4cb0e16 100644 --- a/ash/system/network/network_section_header_view.cc +++ b/ash/system/network/network_section_header_view.cc
@@ -7,6 +7,7 @@ #include "ash/constants/ash_features.h" #include "ash/metrics/user_metrics_recorder.h" #include "ash/public/cpp/system_tray_client.h" +#include "ash/resources/vector_icons/vector_icons.h" #include "ash/session/session_controller_impl.h" #include "ash/shell.h" #include "ash/strings/grit/ash_strings.h" @@ -353,10 +354,12 @@ int tooltip_message_id = IsCellularDeviceInhibited() ? IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR : IDS_ASH_STATUS_TRAY_ADD_CELLULAR_LABEL; + const gfx::VectorIcon& icon = base::i18n::IsRTL() ? kAddCellularNetworkRtlIcon + : kAddCellularNetworkIcon; add_esim_button_ = new TopShortcutButton( base::BindRepeating(&MobileSectionHeaderView::AddCellularButtonPressed, base::Unretained(this)), - vector_icons::kAddCellularNetworkIcon, tooltip_message_id); + icon, tooltip_message_id); add_esim_button_->SetEnabled(enabled && !IsCellularDeviceInhibited());
diff --git a/ash/wm/container_finder.cc b/ash/wm/container_finder.cc index 499c66ade..171d5f0 100644 --- a/ash/wm/container_finder.cc +++ b/ash/wm/container_finder.cc
@@ -12,6 +12,7 @@ #include "ash/wm/always_on_top_controller.h" #include "ash/wm/window_state.h" #include "ash/wm/window_util.h" +#include "components/full_restore/full_restore_utils.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/window.h" #include "ui/gfx/geometry/rect.h" @@ -91,6 +92,15 @@ target_root = FindContainerRoot(bounds_in_screen); } + // For full restore, the window may be created before the associated full + // restore data can be retrieved. In this case, we will place it in a hidden + // container and will move it to a desk container when the full restore data + // can be retrieved. An example would be ARC windows, which can be created + // before their associated tasks are, which are required to retrieve full + // restore data. + if (window->GetProperty(full_restore::kParentToHiddenContainerKey)) + return target_root->GetChildById(kShellWindowId_UnparentedControlContainer); + switch (window->GetType()) { case aura::client::WINDOW_TYPE_NORMAL: case aura::client::WINDOW_TYPE_POPUP:
diff --git a/ash/wm/full_restore/full_restore_controller.cc b/ash/wm/full_restore/full_restore_controller.cc index a09b753..9cc11d3 100644 --- a/ash/wm/full_restore/full_restore_controller.cc +++ b/ash/wm/full_restore/full_restore_controller.cc
@@ -12,6 +12,7 @@ #include "ash/public/cpp/shell_window_ids.h" #include "ash/public/cpp/window_properties.h" #include "ash/shell.h" +#include "ash/wm/container_finder.h" #include "ash/wm/desks/desks_util.h" #include "ash/wm/mru_window_tracker.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h" @@ -24,6 +25,7 @@ #include "components/full_restore/full_restore_utils.h" #include "components/prefs/pref_service.h" #include "ui/aura/client/aura_constants.h" +#include "ui/aura/client/window_parenting_client.h" #include "ui/aura/window.h" #include "ui/display/display.h" #include "ui/display/screen.h" @@ -63,6 +65,12 @@ constexpr AppType kSupportedAppTypes[3] = { AppType::BROWSER, AppType::CHROME_APP, AppType::ARC_APP}; +std::unique_ptr<full_restore::WindowInfo> GetWindowInfo(aura::Window* window) { + return g_read_window_callback_for_testing + ? g_read_window_callback_for_testing.Run(window) + : full_restore::GetWindowInfo(window); +} + // Returns the sibling of `window` that `window` should be stacked below based // on restored activation indices. Returns nullptr if `window` does not need // to be moved in the z-ordering. Should be called after `window` is added as @@ -199,15 +207,38 @@ void FullRestoreController::OnWidgetInitialized(views::Widget* widget) { DCHECK(widget); + + aura::Window* window = widget->GetNativeWindow(); + if (window->GetProperty(full_restore::kParentToHiddenContainerKey)) + return; + UpdateAndObserveWindow(widget->GetNativeWindow()); } void FullRestoreController::OnARCTaskReadyForUnparentedWindow( aura::Window* window) { DCHECK(window); - window->SetProperty(full_restore::kParentToHiddenContainerKey, false); + DCHECK(window->GetProperty(full_restore::kParentToHiddenContainerKey)); - // TODO(crbug.com/1205148): Reparent and call `UpdateAndObserveWindow()`. + std::unique_ptr<full_restore::WindowInfo> window_info = GetWindowInfo(window); + if (window_info) { + const int desk_id = window_info->desk_id + ? int{*window_info->desk_id} + : aura::client::kUnassignedWorkspace; + window->SetProperty(aura::client::kWindowWorkspaceKey, desk_id); + window->SetProperty(aura::client::kVisibleOnAllWorkspacesKey, + window_info->visible_on_all_workspaces.has_value()); + } + + // Now that the hidden container key is cleared, + // `aura::client::ParentWindowWithContext` should parent `window` to a valid + // desk container. + window->SetProperty(full_restore::kParentToHiddenContainerKey, false); + aura::client::ParentWindowWithContext(window, + /*context=*/window->GetRootWindow(), + window->GetBoundsInScreen()); + + UpdateAndObserveWindow(window); } void FullRestoreController::OnWindowStackingChanged(aura::Window* window) {
diff --git a/ash/wm/full_restore/full_restore_controller_unittest.cc b/ash/wm/full_restore/full_restore_controller_unittest.cc index cbaffc0..6e6f54e 100644 --- a/ash/wm/full_restore/full_restore_controller_unittest.cc +++ b/ash/wm/full_restore/full_restore_controller_unittest.cc
@@ -119,7 +119,8 @@ aura::Window* root_window = Shell::GetPrimaryRootWindow(), absl::optional<int32_t> restore_window_id = absl::nullopt, chromeos::WindowStateType window_state_type = - chromeos::WindowStateType::kNormal) { + chromeos::WindowStateType::kNormal, + bool is_taskless_arc_app = false) { // Full restore widgets are inactive when created as we do not want to take // activation from a possible activated window, and we want to stack them in // a certain order. @@ -140,9 +141,17 @@ *restore_window_id); } + if (is_taskless_arc_app) { + widget_builder + .SetWindowProperty(full_restore::kParentToHiddenContainerKey, true) + .SetWindowProperty(aura::client::kAppType, + static_cast<int>(AppType::ARC_APP)); + } + views::Widget* widget = widget_builder.BuildOwnedByNativeWidget(); SetResizable(widget); - FullRestoreController::Get()->OnWidgetInitialized(widget); + if (!is_taskless_arc_app) + FullRestoreController::Get()->OnWidgetInitialized(widget); if (window_state_type != chromeos::WindowStateType::kMinimized) widget->Show(); return widget; @@ -152,7 +161,8 @@ // `fake_full_restore_file_`. Returns nullptr if there is not an entry that // matches `restore_window_id`. views::Widget* CreateTestFullRestoredWidgetFromRestoreId( - int32_t restore_window_id) { + int32_t restore_window_id, + bool is_taskless_arc_app) { if (!fake_full_restore_file_.contains(restore_window_id)) return nullptr; @@ -162,9 +172,16 @@ const int32_t activation_index = info->activation_index.value_or(-1); const auto window_state_type = info->window_state_type.value_or(chromeos::WindowStateType::kNormal); - return CreateTestFullRestoredWidget(activation_index, bounds, - Shell::GetPrimaryRootWindow(), - restore_window_id, window_state_type); + return CreateTestFullRestoredWidget( + activation_index, bounds, Shell::GetPrimaryRootWindow(), + restore_window_id, window_state_type, is_taskless_arc_app); + } + + views::Widget* CreateTestFullRestoredWidgetFromRestoreId( + int32_t restore_window_id) { + return CreateTestFullRestoredWidgetFromRestoreId( + restore_window_id, + /*is_taskless_arc_app=*/false); } void VerifyStackingOrder(aura::Window* parent, @@ -179,21 +196,48 @@ // Adds an entry to the fake full restore file. Calling // If `CreateTestFullRestoreWidget` is called with a matching // `restore_window_id`, it will read and set the values set here. - void AddEntryToFakeFile( - int restore_window_id, - const gfx::Rect& bounds, - chromeos::WindowStateType window_state_type, - int32_t activation_index = -1, - int64_t display_id = WindowTreeHostManager::GetPrimaryDisplayId()) { + void AddEntryToFakeFile(int restore_window_id, + const gfx::Rect& bounds, + chromeos::WindowStateType window_state_type, + int32_t activation_index, + int64_t display_id, + int32_t desk_id) { DCHECK(!fake_full_restore_file_.contains(restore_window_id)); auto window_info = std::make_unique<full_restore::WindowInfo>(); window_info->current_bounds = bounds; window_info->window_state_type = window_state_type; window_info->activation_index = activation_index; window_info->display_id = display_id; + window_info->desk_id = desk_id; fake_full_restore_file_[restore_window_id].info = std::move(window_info); } + void AddEntryToFakeFile(int restore_window_id, + const gfx::Rect& bounds, + chromeos::WindowStateType window_state_type, + int32_t activation_index, + int64_t display_id) { + AddEntryToFakeFile(restore_window_id, bounds, window_state_type, + activation_index, display_id, /*desk_id=*/1); + } + + void AddEntryToFakeFile(int restore_window_id, + const gfx::Rect& bounds, + chromeos::WindowStateType window_state_type) { + AddEntryToFakeFile( + restore_window_id, bounds, window_state_type, /*activation_index=*/-1, + WindowTreeHostManager::GetPrimaryDisplayId(), /*desk_id=*/1); + } + + void AddEntryToFakeFile(int restore_window_id, + const gfx::Rect& bounds, + chromeos::WindowStateType window_state_type, + int32_t desk_id) { + AddEntryToFakeFile(restore_window_id, bounds, window_state_type, + /*activation_index=*/-1, + WindowTreeHostManager::GetPrimaryDisplayId(), desk_id); + } + // AshTestBase: void SetUp() override { scoped_feature_list_.InitAndEnableFeature(features::kFullRestore); @@ -955,4 +999,102 @@ EXPECT_EQ(0u, GetRestorePropertyClearCallbacks().size()); } +// Tests full restore behavior for when a ARC window is created without an +// associated task. +TEST_F(FullRestoreControllerTest, ArcAppWindowCreatedWithoutTask) { + constexpr int kRestoreId = 1; + + // Create enough desks so that we can parent to the expected desk. + auto* desks_controller = DesksController::Get(); + for (int i = 0; i < 4; ++i) + desks_controller->NewDesk(DesksCreationRemovalSource::kButton); + + // Add a normal window to the fake file. The target desk is desk 3. + AddEntryToFakeFile(kRestoreId, gfx::Rect(400, 400), + chromeos::WindowStateType::kNormal, 3); + + aura::Window* root_window = Shell::GetPrimaryRootWindow(); + + // Restore the window, it should go to the invisible unparented container for + // now. + auto* restored_window = CreateTestFullRestoredWidgetFromRestoreId( + kRestoreId, /*is_taskless_arc_app=*/true) + ->GetNativeWindow(); + EXPECT_EQ(Shell::GetContainer(root_window, + kShellWindowId_UnparentedControlContainer), + restored_window->parent()); + + // Simulate having the task ready. Our `restored_window` should now be + // parented to the desk associated with desk 3, which is desk D. + FullRestoreController::Get()->OnARCTaskReadyForUnparentedWindow( + restored_window); + EXPECT_EQ(Shell::GetContainer(root_window, kShellWindowId_DeskContainerD), + restored_window->parent()); +} + +// Tests that parenting ARC windows to hidden container works in the multi +// display scenario, including if a display gets disconnected partway through. +TEST_F(FullRestoreControllerTest, ArcAppWindowCreatedWithoutTaskMultiDisplay) { + UpdateDisplay("800x800,801+0-800x800"); + + const int64_t primary_id = WindowTreeHostManager::GetPrimaryDisplayId(); + const int64_t second_id = display_manager()->GetDisplayAt(1).id(); + display::ManagedDisplayInfo primary_info = + display_manager()->GetDisplayInfo(primary_id); + display::ManagedDisplayInfo second_info = + display_manager()->GetDisplayInfo(second_id); + + aura::Window* primary_root_window = Shell::GetPrimaryRootWindow(); + aura::Window* secondary_root_window = Shell::GetAllRootWindows()[1]; + + // Create enough desks so that we can parent to the expected desk. + auto* desks_controller = DesksController::Get(); + for (int i = 0; i < 4; ++i) + desks_controller->NewDesk(DesksCreationRemovalSource::kButton); + + // Add two normal windows to the fake file. The target desk is desk 3 and the + // target display is the secondary one. + constexpr int kRestoreId1 = 1; + constexpr int kRestoreId2 = 2; + AddEntryToFakeFile(kRestoreId1, gfx::Rect(900, 0, 400, 400), + chromeos::WindowStateType::kNormal, 3); + AddEntryToFakeFile(kRestoreId2, gfx::Rect(900, 0, 400, 400), + chromeos::WindowStateType::kNormal, 3); + + // Restore the first window, it should go to the invisible unparented + // container for the secondary display until the ARC task is ready. + auto* restored_window1 = CreateTestFullRestoredWidgetFromRestoreId( + kRestoreId1, /*is_taskless_arc_app=*/true) + ->GetNativeWindow(); + EXPECT_EQ(Shell::GetContainer(secondary_root_window, + kShellWindowId_UnparentedControlContainer), + restored_window1->parent()); + FullRestoreController::Get()->OnARCTaskReadyForUnparentedWindow( + restored_window1); + EXPECT_EQ( + Shell::GetContainer(secondary_root_window, kShellWindowId_DeskContainerD), + restored_window1->parent()); + + // Restore the second window, it should also go to the invisible unparented + // container for the secondary display. + auto* restored_window2 = CreateTestFullRestoredWidgetFromRestoreId( + kRestoreId2, /*is_taskless_arc_app=*/true) + ->GetNativeWindow(); + EXPECT_EQ(Shell::GetContainer(secondary_root_window, + kShellWindowId_UnparentedControlContainer), + restored_window2->parent()); + + // Remove the secondary display. When the ARC task is ready, it should go to + // container associated with desk 3 on the primary display. + std::vector<display::ManagedDisplayInfo> display_info_list; + display_info_list.push_back(primary_info); + display_manager()->OnNativeDisplaysChanged(display_info_list); + + FullRestoreController::Get()->OnARCTaskReadyForUnparentedWindow( + restored_window2); + EXPECT_EQ( + Shell::GetContainer(primary_root_window, kShellWindowId_DeskContainerD), + restored_window2->parent()); +} + } // namespace ash
diff --git a/ash/wm/window_state.cc b/ash/wm/window_state.cc index 1825874..844910c 100644 --- a/ash/wm/window_state.cc +++ b/ash/wm/window_state.cc
@@ -34,6 +34,7 @@ #include "chromeos/ui/base/window_pin_type.h" #include "chromeos/ui/base/window_properties.h" #include "chromeos/ui/base/window_state_type.h" +#include "components/full_restore/full_restore_utils.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/layout_manager.h" #include "ui/aura/window.h" @@ -74,6 +75,13 @@ container_id == kShellWindowId_ArcVirtualKeyboardContainer; } +// ARC windows will not be in a top level container until they are associated +// with a task. We still want a WindowState created for these windows as they +// will be moved to a top level container soon. +bool IsTemporarilyHiddenForFullrestore(aura::Window* window) { + return window->GetProperty(full_restore::kParentToHiddenContainerKey); +} + // A tentative class to set the bounds on the window. // TODO(oshima): Once all logic is cleaned up, move this to the real layout // manager with proper friendship. @@ -917,8 +925,13 @@ DCHECK(window->parent()); - if (!IsToplevelContainer(window->parent())) + // WindowState is only for windows in top level container, unless they are + // temporarily hidden when launched by full restore. The will be reparented to + // a top level container soon, and need a WindowState. + if (!IsToplevelContainer(window->parent()) && + !IsTemporarilyHiddenForFullrestore(window)) { return nullptr; + } state = new WindowState(window); window->SetProperty(kWindowStateKey, state);
diff --git a/base/BUILD.gn b/base/BUILD.gn index 2e85cd0e..df24024 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn
@@ -1280,6 +1280,7 @@ "files/file_path_watcher_linux.cc", "files/file_path_watcher_linux.h", "files/file_util_linux.cc", + "files/scoped_file_linux.cc", "process/internal_linux.cc", "process/internal_linux.h", "process/memory_linux.cc", @@ -1936,6 +1937,8 @@ "allocator/partition_allocator/starscan/starscan_fwd.h", "allocator/partition_allocator/starscan/stats_collector.cc", "allocator/partition_allocator/starscan/stats_collector.h", + "allocator/partition_allocator/starscan/write_protector.cc", + "allocator/partition_allocator/starscan/write_protector.h", "allocator/partition_allocator/thread_cache.cc", "allocator/partition_allocator/thread_cache.h", "allocator/partition_allocator/yield_processor.h", @@ -3326,7 +3329,10 @@ } if (is_linux || is_chromeos) { - sources += [ "debug/proc_maps_linux_unittest.cc" ] + sources += [ + "debug/proc_maps_linux_unittest.cc", + "files/scoped_file_linux_unittest.cc", + ] } if (is_mac) {
diff --git a/base/allocator/allocator_shim.h b/base/allocator/allocator_shim.h index 4ec8919..080029d 100644 --- a/base/allocator/allocator_shim.h +++ b/base/allocator/allocator_shim.h
@@ -167,7 +167,7 @@ #endif #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && PA_ALLOW_PCSCAN -BASE_EXPORT void EnablePCScan(); +BASE_EXPORT void EnablePCScan(bool dcscan); #endif } // namespace allocator
diff --git a/base/allocator/allocator_shim_default_dispatch_to_partition_alloc.cc b/base/allocator/allocator_shim_default_dispatch_to_partition_alloc.cc index 049fda0..dc834318c 100644 --- a/base/allocator/allocator_shim_default_dispatch_to_partition_alloc.cc +++ b/base/allocator/allocator_shim_default_dispatch_to_partition_alloc.cc
@@ -484,8 +484,10 @@ #endif // BUILDFLAG(ENABLE_RUNTIME_BACKUP_REF_PTR_CONTROL) #if PA_ALLOW_PCSCAN -void EnablePCScan() { - internal::PCScan::Initialize(); +void EnablePCScan(bool dcscan) { + internal::PCScan::Initialize( + dcscan ? internal::PCScan::WantedWriteProtectionMode::kEnabled + : internal::PCScan::WantedWriteProtectionMode::kDisabled); internal::PCScan::RegisterScannableRoot(Allocator()); if (Allocator() != AlignedAllocator()) internal::PCScan::RegisterScannableRoot(AlignedAllocator());
diff --git a/base/allocator/partition_allocator/partition_alloc_config.h b/base/allocator/partition_allocator/partition_alloc_config.h index 26aa0be..254476f9 100644 --- a/base/allocator/partition_allocator/partition_alloc_config.h +++ b/base/allocator/partition_allocator/partition_alloc_config.h
@@ -34,6 +34,12 @@ #define PA_STARSCAN_NEON_SUPPORTED #endif +#if defined(PA_HAS_64_BITS_POINTERS) && \ + (defined(OS_LINUX) || defined(OS_ANDROID)) +// TODO(bikineev): Enable for ChromeOS. +#define PA_STARSCAN_UFFD_WRITE_PROTECTOR_SUPPORTED +#endif + // POSIX is not only UNIX, e.g. macOS and other OSes. We do use Linux-specific // features such as futex(2). #if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
diff --git a/base/allocator/partition_allocator/partition_alloc_features.cc b/base/allocator/partition_allocator/partition_alloc_features.cc index 75dda64..00c093a34 100644 --- a/base/allocator/partition_allocator/partition_alloc_features.cc +++ b/base/allocator/partition_allocator/partition_alloc_features.cc
@@ -54,5 +54,8 @@ #endif // defined(PA_PCSCAN_STACK_SUPPORTED) }; +const Feature kPartitionAllocDCScan{"PartitionAllocDCScan", + FEATURE_DISABLED_BY_DEFAULT}; + } // namespace features } // namespace base
diff --git a/base/allocator/partition_allocator/partition_alloc_features.h b/base/allocator/partition_allocator/partition_alloc_features.h index d4f290da..baff1f55 100644 --- a/base/allocator/partition_allocator/partition_alloc_features.h +++ b/base/allocator/partition_allocator/partition_alloc_features.h
@@ -28,6 +28,7 @@ extern const BASE_EXPORT Feature kPartitionAllocPCScanMUAwareScheduler; extern const BASE_EXPORT Feature kPartitionAllocPCScanStackScanning; +extern const BASE_EXPORT Feature kPartitionAllocDCScan; extern const BASE_EXPORT Feature kPartitionAllocLazyCommit;
diff --git a/base/allocator/partition_allocator/partition_page.h b/base/allocator/partition_allocator/partition_page.h index a19d74ae..c927888 100644 --- a/base/allocator/partition_allocator/partition_page.h +++ b/base/allocator/partition_allocator/partition_page.h
@@ -367,8 +367,8 @@ reinterpret_cast<uintptr_t>(maybe_inner_ptr) & kSuperPageBaseMask); auto* extent = reinterpret_cast<PartitionSuperPageExtentEntry<thread_safe>*>( PartitionSuperPageToMetadataArea(super_page_ptr)); - PA_DCHECK( - IsWithinSuperPagePayload(maybe_inner_ptr, extent->root->IsScanEnabled())); + PA_DCHECK(IsWithinSuperPagePayload(maybe_inner_ptr, + extent->root->IsQuarantineAllowed())); #endif auto* slot_span = SlotSpanMetadata<thread_safe>::FromSlotInnerPtr(maybe_inner_ptr);
diff --git a/base/allocator/partition_allocator/starscan/pcscan.cc b/base/allocator/partition_allocator/starscan/pcscan.cc index 0b843724..fe343661 100644 --- a/base/allocator/partition_allocator/starscan/pcscan.cc +++ b/base/allocator/partition_allocator/starscan/pcscan.cc
@@ -9,8 +9,8 @@ namespace base { namespace internal { -void PCScan::Initialize() { - PCScanInternal::Instance().Initialize(); +void PCScan::Initialize(WantedWriteProtectionMode wpmode) { + PCScanInternal::Instance().Initialize(wpmode); } void PCScan::RegisterScannableRoot(Root* root) { @@ -68,8 +68,8 @@ ReinitPCScanMetadataAllocatorForTesting(); // IN-TEST } -void PCScan::ReinitForTesting() { - PCScanInternal::Instance().ReinitForTesting(); // IN-TEST +void PCScan::ReinitForTesting(WantedWriteProtectionMode wpmode) { + PCScanInternal::Instance().ReinitForTesting(wpmode); // IN-TEST } void PCScan::FinishScanForTesting() {
diff --git a/base/allocator/partition_allocator/starscan/pcscan.h b/base/allocator/partition_allocator/starscan/pcscan.h index 1c43430..23035c0 100644 --- a/base/allocator/partition_allocator/starscan/pcscan.h +++ b/base/allocator/partition_allocator/starscan/pcscan.h
@@ -52,11 +52,18 @@ kEager, }; + // Based on the provided mode, PCScan will try to use a certain + // WriteProtector, if supported by the system. + enum class WantedWriteProtectionMode : uint8_t { + kDisabled, + kEnabled, + }; + PCScan(const PCScan&) = delete; PCScan& operator=(const PCScan&) = delete; // Initializes PCScan and prepares internal data structures. - static void Initialize(); + static void Initialize(WantedWriteProtectionMode); // Registers a root for scanning. static void RegisterScannableRoot(Root* root); @@ -132,7 +139,7 @@ static void FinishScanForTesting(); // Reinitialize internal structures (e.g. card table). - static void ReinitForTesting(); + static void ReinitForTesting(WantedWriteProtectionMode); size_t epoch() const { return scheduler_.epoch(); }
diff --git a/base/allocator/partition_allocator/starscan/pcscan_internal.cc b/base/allocator/partition_allocator/starscan/pcscan_internal.cc index 1467042e..c2a1db4f 100644 --- a/base/allocator/partition_allocator/starscan/pcscan_internal.cc +++ b/base/allocator/partition_allocator/starscan/pcscan_internal.cc
@@ -22,6 +22,7 @@ #include "base/allocator/partition_allocator/partition_address_space.h" #include "base/allocator/partition_allocator/partition_alloc.h" #include "base/allocator/partition_allocator/partition_alloc_check.h" +#include "base/allocator/partition_allocator/partition_alloc_config.h" #include "base/allocator/partition_allocator/partition_alloc_constants.h" #include "base/allocator/partition_allocator/partition_alloc_features.h" #include "base/allocator/partition_allocator/partition_page.h" @@ -303,14 +304,11 @@ typename Root::ScopedGuard guard(root->lock_); // Take a snapshot of all super pages and scannable slot spans. - // TODO(bikineev): Consider making current_extent lock-free and moving it - // to the concurrent thread. for (auto* super_page_extent = root->first_extent; super_page_extent; super_page_extent = super_page_extent->next) { for (char* super_page = super_page_extent->super_page_base; super_page != super_page_extent->super_pages_end; super_page += kSuperPageSize) { - // TODO(bikineev): Consider following freelists instead of slot spans. const size_t visited_slot_spans = IterateSlotSpans<ThreadSafe>( super_page, true /*with_quarantine*/, [this](SlotSpan* slot_span) -> bool { @@ -424,11 +422,13 @@ } } ~SyncScope() { - // First, notify other scanning threads that this thread is done. + // First, notify the scanning thread that this thread is done. NotifyThreads(); + // Then, unprotect all scanned pages, if needed. + task_.UnprotectPartitions(); if (context == Context::kScanner) { // The scanner thread must wait here until all safepoints leave. - // Otherwise, sweeping may free a page that can be accessed by a + // Otherwise, sweeping may free a page that can later be accessed by a // descheduled mutator. WaitForOtherThreads(); } @@ -491,6 +491,9 @@ // Clear quarantined objects and prepare card table for fast lookup void ClearQuarantinedObjectsAndPrepareCardTable(); + // Unprotect all slot spans from all partitions. + void UnprotectPartitions(); + // Sweeps (frees) unreachable quarantined entries. Returns the size of swept // objects. void SweepQuarantine(); @@ -507,6 +510,8 @@ std::mutex mutex_; std::condition_variable condvar_; std::atomic<size_t> number_of_scanning_threads_{0u}; + // We can unprotect only once to reduce context-switches. + std::once_flag unprotect_once_flag_; PCScan& pcscan_; }; @@ -608,6 +613,19 @@ }); } +void PCScanTask::UnprotectPartitions() { + std::call_once(unprotect_once_flag_, [this] { + auto& pcscan = PCScanInternal::Instance(); + const auto unprotect = [&pcscan](const auto& slot_span) { + pcscan.UnprotectPages( + reinterpret_cast<uintptr_t>(slot_span.begin), + (slot_span.end - slot_span.begin) * sizeof(uintptr_t)); + }; + snapshot_.large_scan_areas_worklist().VisitNonConcurrently(unprotect); + snapshot_.scan_areas_worklist().VisitNonConcurrently(unprotect); + }); +} + class PCScanScanLoop final : public ScanLoop<PCScanScanLoop> { friend class ScanLoop<PCScanScanLoop>; @@ -696,7 +714,11 @@ // is scanned contains quarantined objects. PCScanSnapshot::LargeScanAreasWorklist::RandomizedView large_scan_areas( snapshot_.large_scan_areas_worklist()); - large_scan_areas.Visit([this, &scan_loop](auto scan_area) { + auto& pcscan = PCScanInternal::Instance(); + large_scan_areas.Visit([this, &scan_loop, &pcscan](auto scan_area) { + // Protect slot span before scanning it. + pcscan.ProtectPages(reinterpret_cast<uintptr_t>(scan_area.begin), + (scan_area.end - scan_area.begin) * sizeof(uintptr_t)); // The bitmap is (a) always guaranteed to exist and (b) the same for all // objects in a given slot span. // TODO(chromium:1129751): Check mutator bitmap as well if performance @@ -722,7 +744,10 @@ // Scan areas with regular size slots. PCScanSnapshot::ScanAreasWorklist::RandomizedView scan_areas( snapshot_.scan_areas_worklist()); - scan_areas.Visit([&scan_loop](auto scan_area) { + scan_areas.Visit([&scan_loop, &pcscan](auto scan_area) { + // Protect slot span before scanning it. + pcscan.ProtectPages(reinterpret_cast<uintptr_t>(scan_area.begin), + (scan_area.end - scan_area.begin) * sizeof(uintptr_t)); scan_loop.Run(scan_area.begin, scan_area.end); }); @@ -970,10 +995,18 @@ PCScanInternal::~PCScanInternal() = default; -void PCScanInternal::Initialize() { +void PCScanInternal::Initialize(PCScan::WantedWriteProtectionMode wpmode) { PA_DCHECK(!is_initialized_); CommitCardTable(); - PCScan::SetClearType(PCScan::ClearType::kLazy); +#if defined(PA_STARSCAN_UFFD_WRITE_PROTECTOR_SUPPORTED) + if (wpmode == PCScan::WantedWriteProtectionMode::kEnabled) + write_protector_ = std::make_unique<UserFaultFDWriteProtector>(); + else + write_protector_ = std::make_unique<NoWriteProtector>(); +#else + write_protector_ = std::make_unique<NoWriteProtector>(); +#endif // defined(PA_STARSCAN_UFFD_WRITE_PROTECTOR_SUPPORTED) + PCScan::SetClearType(write_protector_->SupportedClearType()); is_initialized_ = true; } @@ -1137,6 +1170,23 @@ return it != stack_tops_.end() ? it->second : nullptr; } +void PCScanInternal::ProtectPages(uintptr_t begin, size_t size) { + // Slot-span sizes are multiple of system page size. However, the ranges that + // are recorded are not, since in the snapshot we only record the used + // payload. Therefore we align up the incoming range by 4k. The unused part of + // slot-spans doesn't need to be protected (the allocator will enter the + // safepoint before trying to allocate from it). + PA_DCHECK(write_protector_.get()); + write_protector_->ProtectPages( + begin, (size + SystemPageSize() - 1) & ~(SystemPageSize() - 1)); +} + +void PCScanInternal::UnprotectPages(uintptr_t begin, size_t size) { + PA_DCHECK(write_protector_.get()); + write_protector_->UnprotectPages( + begin, (size + SystemPageSize() - 1) & ~(SystemPageSize() - 1)); +} + void PCScanInternal::ClearRootsForTesting() { // Set all roots as non-scannable and non-quarantinable. for (auto* root : scannable_roots_) { @@ -1150,9 +1200,9 @@ nonscannable_roots_.ClearForTesting(); // IN-TEST } -void PCScanInternal::ReinitForTesting() { +void PCScanInternal::ReinitForTesting(PCScan::WantedWriteProtectionMode mode) { is_initialized_ = false; - Initialize(); + Initialize(mode); } void PCScanInternal::FinishScanForTesting() {
diff --git a/base/allocator/partition_allocator/starscan/pcscan_internal.h b/base/allocator/partition_allocator/starscan/pcscan_internal.h index 991add4..22545dd 100644 --- a/base/allocator/partition_allocator/starscan/pcscan_internal.h +++ b/base/allocator/partition_allocator/starscan/pcscan_internal.h
@@ -12,6 +12,7 @@ #include "base/allocator/partition_allocator/starscan/metadata_allocator.h" #include "base/allocator/partition_allocator/starscan/pcscan.h" #include "base/allocator/partition_allocator/starscan/starscan_fwd.h" +#include "base/allocator/partition_allocator/starscan/write_protector.h" #include "base/memory/scoped_refptr.h" #include "base/no_destructor.h" @@ -69,7 +70,7 @@ ~PCScanInternal(); - void Initialize(); + void Initialize(PCScan::WantedWriteProtectionMode); bool is_initialized() const { return is_initialized_; } void PerformScan(PCScan::InvocationMode); @@ -107,9 +108,12 @@ void* GetCurrentThreadStackTop() const; - void ClearRootsForTesting(); // IN-TEST - void ReinitForTesting(); // IN-TEST - void FinishScanForTesting(); // IN-TEST + void ProtectPages(uintptr_t begin, size_t size); + void UnprotectPages(uintptr_t begin, size_t size); + + void ClearRootsForTesting(); // IN-TEST + void ReinitForTesting(PCScan::WantedWriteProtectionMode); // IN-TEST + void FinishScanForTesting(); // IN-TEST private: friend base::NoDestructor<PCScanInternal>; @@ -138,6 +142,8 @@ const char* process_name_ = nullptr; const SimdSupport simd_support_; + std::unique_ptr<WriteProtector> write_protector_; + bool is_initialized_ = false; };
diff --git a/base/allocator/partition_allocator/starscan/pcscan_unittest.cc b/base/allocator/partition_allocator/starscan/pcscan_unittest.cc index 82b0433..fa689980 100644 --- a/base/allocator/partition_allocator/starscan/pcscan_unittest.cc +++ b/base/allocator/partition_allocator/starscan/pcscan_unittest.cc
@@ -44,7 +44,7 @@ PartitionAllocGlobalInit([](size_t) { LOG(FATAL) << "Out of memory"; }); // Previous test runs within the same process decommit GigaCage, therefore // we need to make sure that the card table is recommitted for each run. - PCScan::ReinitForTesting(); + PCScan::ReinitForTesting(PCScan::WantedWriteProtectionMode::kDisabled); allocator_.init({PartitionOptions::AlignedAlloc::kAllowed, PartitionOptions::ThreadCache::kDisabled, PartitionOptions::Quarantine::kAllowed,
diff --git a/base/allocator/partition_allocator/starscan/raceful_worklist.h b/base/allocator/partition_allocator/starscan/raceful_worklist.h index b51ed0d..d73fdd61 100644 --- a/base/allocator/partition_allocator/starscan/raceful_worklist.h +++ b/base/allocator/partition_allocator/starscan/raceful_worklist.h
@@ -60,6 +60,9 @@ void Push(const T& t) { data_.push_back(Node(t)); } + template <typename Function> + void VisitNonConcurrently(Function) const; + private: Underlying data_; std::atomic<bool> fully_visited_{false}; @@ -67,6 +70,13 @@ template <typename T> template <typename Function> +void RacefulWorklist<T>::VisitNonConcurrently(Function f) const { + for (const auto& t : data_) + f(t.value); +} + +template <typename T> +template <typename Function> void RacefulWorklist<T>::RandomizedView::Visit(Function f) { auto& data = worklist_.data_; std::vector<typename Underlying::iterator,
diff --git a/base/allocator/partition_allocator/starscan/write_protector.cc b/base/allocator/partition_allocator/starscan/write_protector.cc new file mode 100644 index 0000000..cb0d0b0b --- /dev/null +++ b/base/allocator/partition_allocator/starscan/write_protector.cc
@@ -0,0 +1,135 @@ +// Copyright (c) 2021 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/partition_allocator/starscan/write_protector.h" + +#include <mutex> +#include <thread> + +#include "base/allocator/partition_allocator/address_pool_manager.h" +#include "base/allocator/partition_allocator/partition_address_space.h" +#include "base/allocator/partition_allocator/partition_alloc_check.h" +#include "base/logging.h" +#include "base/posix/eintr_wrapper.h" +#include "base/threading/platform_thread.h" +#include "build/build_config.h" + +#if defined(PA_STARSCAN_UFFD_WRITE_PROTECTOR_SUPPORTED) +#include <fcntl.h> +#include <linux/userfaultfd.h> +#include <poll.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/syscall.h> +#include <sys/types.h> +#endif // defined(PA_STARSCAN_UFFD_WRITE_PROTECTOR_SUPPORTED) + +namespace base { +namespace internal { + +PCScan::ClearType NoWriteProtector::SupportedClearType() const { + return PCScan::ClearType::kLazy; +} + +#if defined(PA_STARSCAN_UFFD_WRITE_PROTECTOR_SUPPORTED) +namespace { +void UserFaultFDThread(int uffd) { + PA_DCHECK(-1 != uffd); + + static constexpr char kThreadName[] = "PCScanPFHandler"; + base::PlatformThread::SetName(kThreadName); + + while (true) { + // Pool on the uffd descriptor for page fault events. + pollfd pollfd{.fd = uffd, .events = POLLIN}; + const int nready = HANDLE_EINTR(poll(&pollfd, 1, -1)); + PA_CHECK(-1 != nready); + + // Get page fault info. + uffd_msg msg; + const int nread = HANDLE_EINTR(read(uffd, &msg, sizeof(msg))); + PA_CHECK(0 != nread); + + // We only expect page faults. + PA_DCHECK(UFFD_EVENT_PAGEFAULT == msg.event); + // We have subscribed only to wp-fault events. + PA_DCHECK(UFFD_PAGEFAULT_FLAG_WP & msg.arg.pagefault.flags); + + // Enter the safepoint. Concurrent faulted writes will wait until safepoint + // finishes. + PCScan::JoinScanIfNeeded(); + } +} +} // namespace + +UserFaultFDWriteProtector::UserFaultFDWriteProtector() + : uffd_(syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK)) { + if (uffd_ == -1) { + LOG(WARNING) << "userfaultfd is not supported by the current kernel"; + return; + } + + PA_PCHECK(-1 != uffd_); + + uffdio_api uffdio_api; + uffdio_api.api = UFFD_API; + uffdio_api.features = 0; + PA_CHECK(-1 != ioctl(uffd_, UFFDIO_API, &uffdio_api)); + PA_CHECK(UFFD_API == uffdio_api.api); + + // Register the giga-cage to listen uffd events. + struct uffdio_register uffdio_register; + uffdio_register.range.start = PartitionAddressSpace::BRPPoolBase(); + uffdio_register.range.len = AddressPoolManager::kBRPPoolMaxSize; + uffdio_register.mode = UFFDIO_REGISTER_MODE_WP; + PA_CHECK(-1 != ioctl(uffd_, UFFDIO_REGISTER, &uffdio_register)); + + // Start uffd thread. + std::thread(UserFaultFDThread, uffd_).detach(); +} + +namespace { +enum class UserFaultFDWPMode { + kProtect, + kUnprotect, +}; + +void UserFaultFDWPSet(int uffd, + uintptr_t begin, + size_t length, + UserFaultFDWPMode mode) { + PA_DCHECK(0 == (begin % SystemPageSize())); + PA_DCHECK(0 == (length % SystemPageSize())); + + uffdio_writeprotect wp; + wp.range.start = begin; + wp.range.len = length; + wp.mode = + (mode == UserFaultFDWPMode::kProtect) ? UFFDIO_WRITEPROTECT_MODE_WP : 0; + PA_PCHECK(-1 != ioctl(uffd, UFFDIO_WRITEPROTECT, &wp)); +} +} // namespace + +void UserFaultFDWriteProtector::ProtectPages(uintptr_t begin, size_t length) { + if (IsSupported()) + UserFaultFDWPSet(uffd_, begin, length, UserFaultFDWPMode::kProtect); +} + +void UserFaultFDWriteProtector::UnprotectPages(uintptr_t begin, size_t length) { + if (IsSupported()) + UserFaultFDWPSet(uffd_, begin, length, UserFaultFDWPMode::kUnprotect); +} + +PCScan::ClearType UserFaultFDWriteProtector::SupportedClearType() const { + return IsSupported() ? PCScan::ClearType::kEager : PCScan::ClearType::kLazy; +} + +bool UserFaultFDWriteProtector::IsSupported() const { + return uffd_ != -1; +} + +#endif // defined(PA_STARSCAN_UFFD_WRITE_PROTECTOR_SUPPORTED) + +} // namespace internal +} // namespace base
diff --git a/base/allocator/partition_allocator/starscan/write_protector.h b/base/allocator/partition_allocator/starscan/write_protector.h new file mode 100644 index 0000000..5817b1e --- /dev/null +++ b/base/allocator/partition_allocator/starscan/write_protector.h
@@ -0,0 +1,64 @@ +// Copyright (c) 2021 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_PARTITION_ALLOCATOR_STARSCAN_WRITE_PROTECTOR_H_ +#define BASE_ALLOCATOR_PARTITION_ALLOCATOR_STARSCAN_WRITE_PROTECTOR_H_ + +#include <cstddef> +#include <cstdint> +#include <mutex> + +#include "base/allocator/partition_allocator/starscan/metadata_allocator.h" +#include "base/allocator/partition_allocator/starscan/pcscan.h" +#include "base/allocator/partition_allocator/starscan/raceful_worklist.h" +#include "build/build_config.h" + +namespace base { +namespace internal { + +// Interface for page protection/unprotection. This is used in DCScan to catch +// concurrent mutator writes. Protection is done when the scanner starts +// scanning a range. Unprotection happens at the end of the scanning phase. +class WriteProtector : public AllocatedOnPCScanMetadataPartition { + public: + virtual ~WriteProtector() = default; + + virtual void ProtectPages(uintptr_t begin, size_t length) = 0; + virtual void UnprotectPages(uintptr_t begin, size_t length) = 0; + + virtual PCScan::ClearType SupportedClearType() const = 0; +}; + +class NoWriteProtector final : public WriteProtector { + public: + void ProtectPages(uintptr_t, size_t) final {} + void UnprotectPages(uintptr_t, size_t) final {} + PCScan::ClearType SupportedClearType() const final; +}; + +#if defined(PA_STARSCAN_UFFD_WRITE_PROTECTOR_SUPPORTED) +class UserFaultFDWriteProtector final : public WriteProtector { + public: + UserFaultFDWriteProtector(); + + UserFaultFDWriteProtector(const UserFaultFDWriteProtector&) = delete; + UserFaultFDWriteProtector& operator=(const UserFaultFDWriteProtector&) = + delete; + + void ProtectPages(uintptr_t, size_t) final; + void UnprotectPages(uintptr_t, size_t) final; + + PCScan::ClearType SupportedClearType() const final; + + private: + bool IsSupported() const; + + const int uffd_ = 0; +}; +#endif // defined(PA_STARSCAN_UFFD_WRITE_PROTECTOR_SUPPORTED) + +} // namespace internal +} // namespace base + +#endif // BASE_ALLOCATOR_PARTITION_ALLOCATOR_STARSCAN_WRITE_PROTECTOR_H_
diff --git a/base/files/scoped_file.h b/base/files/scoped_file.h index ee49fd7e..427dd3ed 100644 --- a/base/files/scoped_file.h +++ b/base/files/scoped_file.h
@@ -26,11 +26,21 @@ static void Release(const ScopedGeneric<int, ScopedFDCloseTraits>&, int); }; #elif defined(OS_POSIX) || defined(OS_FUCHSIA) +#if defined(OS_CHROMEOS) || defined(OS_LINUX) +// On ChromeOS and Linux we guard FD lifetime with a global table and hook into +// libc close() to perform checks. +struct BASE_EXPORT ScopedFDCloseTraits : public ScopedGenericOwnershipTracking { +#else struct BASE_EXPORT ScopedFDCloseTraits { +#endif static int InvalidValue() { return -1; } static void Free(int fd); +#if defined(OS_CHROMEOS) || defined(OS_LINUX) + static void Acquire(const ScopedGeneric<int, ScopedFDCloseTraits>&, int); + static void Release(const ScopedGeneric<int, ScopedFDCloseTraits>&, int); +#endif }; #endif @@ -44,6 +54,36 @@ } // namespace internal +#if defined(OS_CHROMEOS) || defined(OS_LINUX) +namespace subtle { + +// Enables or disables enforcement of FD ownership as tracked by ScopedFD +// objects. Enforcement is disabled by default since it proves unwieldy in some +// test environments, but tracking is always done. It's best to enable this as +// early as possible in a process's lifetime. +void BASE_EXPORT EnableFDOwnershipEnforcement(bool enabled); + +// Resets ownership state of all FDs. The only permissible use of this API is +// in a forked child process between the fork() and a subsequent exec() call. +// +// For one issue, it is common to mass-close most open FDs before calling +// exec(), to avoid leaking FDs into the new executable's environment. For +// processes which have enabled FD ownership enforcement, this reset operation +// is necessary before performing such closures. +// +// Furthermore, fork()+exec() may be used in a multithreaded context, and +// because fork() is not atomic, the FD ownership state in the child process may +// be inconsistent with the actual set of opened file descriptors once fork() +// returns in the child process. +// +// It is therefore especially important to call this ASAP after fork() in the +// child process if any FD manipulation will be done prior to the subsequent +// exec call. +void BASE_EXPORT ResetFDOwnership(); + +} // namespace subtle +#endif + // ----------------------------------------------------------------------------- #if defined(OS_POSIX) || defined(OS_FUCHSIA) @@ -64,6 +104,12 @@ // Automatically closes |FILE*|s. typedef std::unique_ptr<FILE, internal::ScopedFILECloser> ScopedFILE; +#if defined(OS_CHROMEOS) || defined(OS_LINUX) +// Queries the ownership status of an FD, i.e. whether it is currently owned by +// a ScopedFD in the calling process. +bool BASE_EXPORT IsFDOwned(int fd); +#endif // defined(OS_CHROMEOS) || defined(OS_LINUX) + } // namespace base #endif // BASE_FILES_SCOPED_FILE_H_
diff --git a/base/files/scoped_file_linux.cc b/base/files/scoped_file_linux.cc new file mode 100644 index 0000000..26bc18e6 --- /dev/null +++ b/base/files/scoped_file_linux.cc
@@ -0,0 +1,91 @@ +// Copyright 2021 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/files/scoped_file.h" + +#include <algorithm> +#include <array> +#include <atomic> + +#include "base/compiler_specific.h" +#include "base/debug/stack_trace.h" +#include "base/immediate_crash.h" +#include "base/logging.h" +#include "base/strings/string_piece.h" + +namespace { + +// We want to avoid any kind of allocations in our close() implementation, so we +// use a fixed-size table. Given our common FD limits and the preference for new +// FD allocations to use the lowest available descriptor, this should be +// sufficient to guard most FD lifetimes. The worst case scenario if someone +// attempts to own a higher FD is that we don't track it. +const int kMaxTrackedFds = 4096; + +std::atomic_bool g_is_ownership_enforced{false}; +std::array<std::atomic_bool, kMaxTrackedFds> g_is_fd_owned; + +NOINLINE void CrashOnFdOwnershipViolation() { + RAW_LOG(ERROR, "Crashing due to FD ownership violation:\n"); + base::debug::StackTrace().Print(); + IMMEDIATE_CRASH(); +} + +bool CanTrack(int fd) { + return fd >= 0 && fd < kMaxTrackedFds; +} + +void UpdateAndCheckFdOwnership(int fd, bool owned) { + if (CanTrack(fd) && g_is_fd_owned[fd].exchange(owned) == owned && + g_is_ownership_enforced) { + CrashOnFdOwnershipViolation(); + } +} + +} // namespace + +namespace base { +namespace internal { + +// static +void ScopedFDCloseTraits::Acquire(const ScopedFD& owner, int fd) { + UpdateAndCheckFdOwnership(fd, /*owned=*/true); +} + +// static +void ScopedFDCloseTraits::Release(const ScopedFD& owner, int fd) { + UpdateAndCheckFdOwnership(fd, /*owned=*/false); +} + +} // namespace internal + +namespace subtle { + +void EnableFDOwnershipEnforcement(bool enabled) { + g_is_ownership_enforced = enabled; +} + +void ResetFDOwnership() { + std::fill(g_is_fd_owned.begin(), g_is_fd_owned.end(), false); +} + +} // namespace subtle + +bool IsFDOwned(int fd) { + return CanTrack(fd) && g_is_fd_owned[fd]; +} + +} // namespace base + +extern "C" { + +int __close(int); + +__attribute__((visibility("default"), noinline)) int close(int fd) { + if (base::IsFDOwned(fd) && g_is_ownership_enforced) + CrashOnFdOwnershipViolation(); + return __close(fd); +} + +} // extern "C"
diff --git a/base/files/scoped_file_linux_unittest.cc b/base/files/scoped_file_linux_unittest.cc new file mode 100644 index 0000000..7cac627 --- /dev/null +++ b/base/files/scoped_file_linux_unittest.cc
@@ -0,0 +1,54 @@ +// Copyright 2021 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/files/scoped_file.h" + +#include "base/files/file_util.h" +#include "base/files/scoped_temp_dir.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace base { +namespace { + +class ScopedFDOwnershipTrackingTest : public testing::Test { + public: + void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); } + void TearDown() override { ASSERT_TRUE(temp_dir_.Delete()); } + + ScopedFD OpenFD() { + FilePath dont_care; + return CreateAndOpenFdForTemporaryFileInDir(temp_dir_.GetPath(), + &dont_care); + } + + private: + ScopedTempDir temp_dir_; +}; + +TEST_F(ScopedFDOwnershipTrackingTest, BasicTracking) { + ScopedFD fd = OpenFD(); + EXPECT_TRUE(IsFDOwned(fd.get())); + int fd_value = fd.get(); + fd.reset(); + EXPECT_FALSE(IsFDOwned(fd_value)); +} + +#if defined(GTEST_HAS_DEATH_TEST) + +TEST_F(ScopedFDOwnershipTrackingTest, NoDoubleOwnership) { + ScopedFD fd = OpenFD(); + subtle::EnableFDOwnershipEnforcement(true); + EXPECT_DEATH(ScopedFD(fd.get()), ""); +} + +TEST_F(ScopedFDOwnershipTrackingTest, CrashOnUnownedClose) { + ScopedFD fd = OpenFD(); + subtle::EnableFDOwnershipEnforcement(true); + EXPECT_DEATH(close(fd.get()), ""); +} + +#endif // defined(GTEST_HAS_DEATH_TEST) + +} // namespace +} // namespace base
diff --git a/base/process/launch_posix.cc b/base/process/launch_posix.cc index 944b1d70..86fb840 100644 --- a/base/process/launch_posix.cc +++ b/base/process/launch_posix.cc
@@ -358,19 +358,27 @@ // might do things like block waiting for threads that don't even exist // in the child. - // If a child process uses the readline library, the process block forever. - // In BSD like OSes including OS X it is safe to assign /dev/null as stdin. - // See http://crbug.com/56596. - base::ScopedFD null_fd(HANDLE_EINTR(open("/dev/null", O_RDONLY))); - if (!null_fd.is_valid()) { - RAW_LOG(ERROR, "Failed to open /dev/null"); - _exit(127); - } +#if defined(OS_LINUX) || defined(OS_CHROMEOS) + // See comments on the ResetFDOwnership() declaration in + // base/files/scoped_file.h regarding why this is called early here. + subtle::ResetFDOwnership(); +#endif - int new_fd = HANDLE_EINTR(dup2(null_fd.get(), STDIN_FILENO)); - if (new_fd != STDIN_FILENO) { - RAW_LOG(ERROR, "Failed to dup /dev/null for stdin"); - _exit(127); + { + // If a child process uses the readline library, the process block + // forever. In BSD like OSes including OS X it is safe to assign /dev/null + // as stdin. See http://crbug.com/56596. + base::ScopedFD null_fd(HANDLE_EINTR(open("/dev/null", O_RDONLY))); + if (!null_fd.is_valid()) { + RAW_LOG(ERROR, "Failed to open /dev/null"); + _exit(127); + } + + int new_fd = HANDLE_EINTR(dup2(null_fd.get(), STDIN_FILENO)); + if (new_fd != STDIN_FILENO) { + RAW_LOG(ERROR, "Failed to dup /dev/null for stdin"); + _exit(127); + } } if (options.new_process_group) { @@ -550,6 +558,12 @@ // DANGER: no calls to malloc or locks are allowed from now on: // http://crbug.com/36678 +#if defined(OS_LINUX) || defined(OS_CHROMEOS) + // See comments on the ResetFDOwnership() declaration in + // base/files/scoped_file.h regarding why this is called early here. + subtle::ResetFDOwnership(); +#endif + // Obscure fork() rule: in the child, if you don't end up doing exec*(), // you call _exit() instead of exit(). This is because _exit() does not // call any previously-registered (in the parent) exit handlers, which
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1 index 8862a80..6a5b8b2 100644 --- a/build/fuchsia/linux.sdk.sha1 +++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@ -4.20210519.2.1 +4.20210519.3.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1 index 8862a80..6a5b8b2 100644 --- a/build/fuchsia/mac.sdk.sha1 +++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@ -4.20210519.2.1 +4.20210519.3.1
diff --git a/buildtools/checkdeps/java_checker.py b/buildtools/checkdeps/java_checker.py index 75f41f1..93ae49de 100644 --- a/buildtools/checkdeps/java_checker.py +++ b/buildtools/checkdeps/java_checker.py
@@ -81,6 +81,9 @@ # Skip unwanted subdirectories. TODO(husky): it would be better to do # this via the skip_child_includes flag in DEPS files. Maybe hoist this # prescan logic into checkdeps.py itself? + root = root.decode('utf-8') + dirs = [d.decode('utf-8') for d in dirs] + files = [f.decode('utf-8') for f in files] dirs[:] = [d for d in dirs if not self._IgnoreDir(d)] for f in files: if f.endswith('.java'):
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni index c2de7c1..57c9cc3c 100644 --- a/chrome/android/chrome_java_sources.gni +++ b/chrome/android/chrome_java_sources.gni
@@ -949,6 +949,7 @@ "java/src/org/chromium/chrome/browser/omnibox/styles/OmniboxResourceProvider.java", "java/src/org/chromium/chrome/browser/omnibox/styles/OmniboxTheme.java", "java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteController.java", + "java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteControllerFactory.java", "java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinator.java", "java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteDelegate.java", "java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java",
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/DEPS b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/DEPS index 3f7a03a2..e7e62825 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/DEPS +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/DEPS
@@ -5,6 +5,7 @@ "+chrome/android/java/src/org/chromium/chrome/browser/omnibox", "+chrome/android/java/src/org/chromium/chrome/browser/AppHooks.java", + "+chrome/android/java/src/org/chromium/chrome/browser/WarmupManager.java", "+base/android/java/src/org/chromium/base", "+chrome/browser/feature_engagement",
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarCoordinator.java index a485512d..b6b9d7b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarCoordinator.java
@@ -140,8 +140,7 @@ OverrideUrlLoadingDelegate overrideUrlLoadingDelegate, BackKeyBehaviorDelegate backKeyBehavior, SearchEngineLogoUtils searchEngineLogoUtils, @NonNull Runnable launchAssistanceSettingsAction, - @NonNull PageInfoAction pageInfoAction, @NonNull Callback<Profile> spareRendererCreator, - @NonNull Callback<Tab> bringTabToFrontCallback, + @NonNull PageInfoAction pageInfoAction, @NonNull Callback<Tab> bringTabToFrontCallback, @NonNull SaveOfflineButtonState saveOfflineButtonState, @NonNull OmniboxUma omniboxUma, @NonNull Supplier<TabWindowManager> tabWindowManagerSupplier, @NonNull BookmarkState bookmarkState) { @@ -169,7 +168,7 @@ mAutocompleteCoordinator = new AutocompleteCoordinator(mLocationBarLayout, this, this, mUrlCoordinator, activityLifecycleDispatcher, modalDialogManagerSupplier, activityTabSupplier, shareDelegateSupplier, locationBarDataProvider, - spareRendererCreator, bringTabToFrontCallback, tabWindowManagerSupplier, + profileObservableSupplier, bringTabToFrontCallback, tabWindowManagerSupplier, bookmarkState); StatusView statusView = mLocationBarLayout.findViewById(R.id.location_bar_status); mStatusCoordinator = new StatusCoordinator(isTablet(), statusView, mUrlCoordinator,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediator.java index 5c13335a..f61b4dbb 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediator.java
@@ -856,7 +856,6 @@ private void setProfile(Profile profile) { if (profile == null || !mNativeInitialized) return; - mAutocompleteCoordinator.setAutocompleteProfile(profile); mOmniboxPrerender.initializeForProfile(profile); mLocationBarLayout.setShowIconsWhenUrlFocused(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteController.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteController.java index 64f7602..1754c8e4 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteController.java
@@ -20,16 +20,31 @@ import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.tab.Tab; import org.chromium.components.embedder_support.util.UrlUtilities; +import org.chromium.components.metrics.OmniboxEventProtos.OmniboxEventProto.PageClassification; import org.chromium.components.omnibox.AutocompleteMatch; import org.chromium.components.omnibox.AutocompleteResult; import org.chromium.content_public.browser.UiThreadTaskTraits; import org.chromium.content_public.browser.WebContents; import org.chromium.url.GURL; +import java.util.HashSet; import java.util.List; +import java.util.Set; /** * Bridge to the native AutocompleteControllerAndroid. + * + * The bridge is created and maintained by the AutocompleteControllerAndroid native class. + * The Native class is created on request for supplied profiles and remains available until the + * Profile gets destroyed, making this instance follow the same life cycle. + * + * Instances of this class should not be acquired directly; instead, when a profile-specific + * AutocompleteController is required, please acquire one using the AutocompleteControllerFactory. + * + * When User Profile gets destroyed, native class gets destroyed as well, and during the + * destruction calls the #notifyNativeDestroyed() method, which signals the Java + * AutocompleteController is no longer valid, and removes it from the AutocompleteControllerFactory + * cache. */ public class AutocompleteController { // Maximum number of voice suggestions to show. @@ -43,10 +58,11 @@ private static final int OMNIBOX_SPARE_RENDERER_DELAY_MS = 1000; private final @NonNull Callback<Profile> mSpareRendererCreator; - private long mNativeAutocompleteControllerAndroid; - private OnSuggestionsReceivedListener mListener; + private final @NonNull Profile mProfile; + private final @NonNull Runnable mControllerDestroyedCallback; + private final long mNativeAutocompleteControllerAndroid; + private final Set<OnSuggestionsReceivedListener> mListeners = new HashSet<>(); - private Profile mProfile; private @NonNull AutocompleteResult mAutocompleteResult = AutocompleteResult.EMPTY_RESULT; /** @@ -57,52 +73,38 @@ AutocompleteResult autocompleteResult, String inlineAutocompleteText); } - public AutocompleteController(@NonNull Callback<Profile> spareRendererCreator) { + @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) + protected AutocompleteController(@NonNull Profile profile, + @NonNull Callback<Profile> spareRendererCreator, + @NonNull Runnable controllerDestroyedCallback) { + assert profile != null : "Invalid profile used to construct AutocompleteController"; + mProfile = profile; + mNativeAutocompleteControllerAndroid = + AutocompleteControllerJni.get().init(AutocompleteController.this, profile); + + // Note: this may fire when building integration tests that mock JNI calls. + // When mocking JNI calls, please make sure to supply a Mock AutocompleteController to + // AutocompleteControllerFactory. + assert mNativeAutocompleteControllerAndroid != 0 : "Could not acquire Native Controller."; mSpareRendererCreator = spareRendererCreator; + mControllerDestroyedCallback = controllerDestroyedCallback; } /** * @param listener The listener to be notified when new suggestions are available. */ - public void setOnSuggestionsReceivedListener(@NonNull OnSuggestionsReceivedListener listener) { - mListener = listener; - } - - void destroy() { - if (mNativeAutocompleteControllerAndroid != 0) { - AutocompleteControllerJni.get().releaseJavaObject(mNativeAutocompleteControllerAndroid); - } - mNativeAutocompleteControllerAndroid = 0; + @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) + public void addOnSuggestionsReceivedListener(@NonNull OnSuggestionsReceivedListener listener) { + mListeners.add(listener); } /** - * Resets the underlying autocomplete controller based on the specified profile. This function - * returns early if there are no profile changes. - * - * <p>This will implicitly stop the autocomplete suggestions, so - * {@link #start(Profile, String, String, boolean)} must be called again to start them flowing - * again. This should not be an issue as changing profiles should not normally occur while - * waiting on omnibox suggestions. - * - * @param profile The profile to reset the AutocompleteController with. + * @param listener A previously registered new suggestions listener to be removed. */ - public void setProfile(Profile profile) { - assert mListener != null : "Ensure a listener is set prior to calling."; - if (mProfile == profile) { - mNativeAutocompleteControllerAndroid = - AutocompleteControllerJni.get().init(AutocompleteController.this, profile); - return; - } - - mProfile = profile; - stop(true); - if (profile == null) { - mNativeAutocompleteControllerAndroid = 0; - return; - } - - mNativeAutocompleteControllerAndroid = - AutocompleteControllerJni.get().init(AutocompleteController.this, profile); + @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) + public void removeOnSuggestionsReceivedListener( + @NonNull OnSuggestionsReceivedListener listener) { + mListeners.remove(listener); } /** @@ -121,10 +123,10 @@ public void start(Profile profile, String url, int pageClassification, String text, int cursorPosition, boolean preventInlineAutocomplete, @Nullable String queryTileId, boolean isQueryStartedFromTiles) { - assert mListener != null : "Ensure a listener is set prior to calling."; + // TODO(crbug.com/1138587): investigate whether we need profiles and drop the null check. if (profile == null || TextUtils.isEmpty(url)) return; - setProfile(profile); + assert profile == mProfile; // Initializing the native counterpart might still fail. if (mNativeAutocompleteControllerAndroid != 0) { @@ -169,7 +171,6 @@ */ public void startZeroSuggest( Profile profile, String omniboxText, String url, int pageClassification, String title) { - assert mListener != null : "Ensure a listener is set prior to calling."; if (profile == null || TextUtils.isEmpty(url)) return; // Proactively start up a renderer, to reduce the time to display search results, @@ -179,6 +180,7 @@ // renderer will be started after the next navigation if the delay is too long, but the // spare renderer will probably get used anyways by a later navigation. if (!profile.isOffTheRecord() && !UrlUtilities.isNTPUrl(url) + && pageClassification != PageClassification.ANDROID_SEARCH_WIDGET_VALUE && ChromeFeatureList.isEnabled(ChromeFeatureList.OMNIBOX_SPARE_RENDERER)) { // It is ok for this to get called multiple times since all the requests will get // de-duplicated to the first one. @@ -193,7 +195,7 @@ ChromeFeatureList.OMNIBOX_SPARE_RENDERER, "omnibox_spare_renderer_delay_ms", OMNIBOX_SPARE_RENDERER_DELAY_MS)); } - setProfile(profile); + assert profile == mProfile; if (mNativeAutocompleteControllerAndroid != 0) { AutocompleteControllerJni.get().onOmniboxFocused(mNativeAutocompleteControllerAndroid, @@ -210,7 +212,6 @@ * empty result set. */ public void stop(boolean clear) { - assert mListener != null : "Ensure a listener is set prior to calling."; if (mNativeAutocompleteControllerAndroid != 0) { AutocompleteControllerJni.get().stop( mNativeAutocompleteControllerAndroid, AutocompleteController.this, clear); @@ -251,18 +252,19 @@ @CalledByNative protected void onSuggestionsReceived( AutocompleteResult autocompleteResult, String inlineAutocompleteText) { - assert mListener != null : "Ensure a listener is set prior generating suggestions."; final AutocompleteResult originalResult = autocompleteResult; mAutocompleteResult = autocompleteResult; // Notify callbacks of suggestions. - mListener.onSuggestionsReceived(autocompleteResult, inlineAutocompleteText); + for (OnSuggestionsReceivedListener listener : mListeners) { + listener.onSuggestionsReceived(autocompleteResult, inlineAutocompleteText); + } } @CalledByNative private void notifyNativeDestroyed() { - mNativeAutocompleteControllerAndroid = 0; + mControllerDestroyedCallback.run(); } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteControllerFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteControllerFactory.java new file mode 100644 index 0000000..520f5ed --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteControllerFactory.java
@@ -0,0 +1,71 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.omnibox.suggestions; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import org.chromium.chrome.browser.WarmupManager; +import org.chromium.chrome.browser.profiles.Profile; + +import java.util.HashMap; +import java.util.Map; + +/** + * The factory building/retrieving the AutocompleteController objects. + * + * Facilitates construction or retrieval of AutocompleteController instances associated with + * particular user Profiles. + * The factory may be shared between multiple individual activities, typically Search and regular + * Chrome activities. To prevent the instances from being separately constructed, this factory + * operates within singleton realms, replicating the KeyedServiceFactory used on the Native (C++) + * side. + */ +public class AutocompleteControllerFactory { + /** A map associating individual Profile objects with their corresponding Controllers */ + private static Map<Profile, AutocompleteController> sControllers = new HashMap<>(); + + /** AutocompleteController instance returned for testing purposes. */ + private static AutocompleteController sAutocompleteControllerForTesting; + + /** + * Retrieve the AutocompleteController associated with the supplied profile. + * + * @param profile Profile to request AutocompleteController for. + * @return AutocompleteController for supplied profile. + */ + static AutocompleteController getController(Profile profile) { + if (sAutocompleteControllerForTesting != null) return sAutocompleteControllerForTesting; + + AutocompleteController controller = sControllers.get(profile); + if (controller != null) return controller; + + controller = new AutocompleteController(profile, + WarmupManager.getInstance()::createSpareRenderProcessHost, + () -> removeController(profile)); + + sControllers.put(profile, controller); + return controller; + } + + /** + * Remove the controller associated with supplied profile. + * + * @param profile Profile for which the controller should be dropped. + */ + private static void removeController(@NonNull Profile profile) { + sControllers.remove(profile); + } + + /** + * Set the instance of AutocompleteController that will be used for testing purposes. + * Supplied instance will always be returned, regardless of profile information. + * + * @param controller The controller to return, or null to remove test instance. + */ + public static void setControllerForTesting(@Nullable AutocompleteController controller) { + sAutocompleteControllerForTesting = controller; + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinator.java index 36a537c3..b6847390 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinator.java
@@ -18,6 +18,7 @@ import org.chromium.base.Callback; import org.chromium.base.StrictModeContext; +import org.chromium.base.supplier.ObservableSupplier; import org.chromium.base.supplier.Supplier; import org.chromium.chrome.R; import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; @@ -63,10 +64,12 @@ * Coordinator that handles the interactions with the autocomplete system. */ public class AutocompleteCoordinator implements UrlFocusChangeListener, UrlTextChangeListener { - private final ViewGroup mParent; - private OmniboxQueryTileCoordinator mQueryTileCoordinator; - private AutocompleteMediator mMediator; - private OmniboxSuggestionsDropdown mDropdown; + private final @NonNull ViewGroup mParent; + private final @NonNull ObservableSupplier<Profile> mProfileSupplier; + private final @NonNull Callback<Profile> mProfileChangeCallback; + private final @NonNull OmniboxQueryTileCoordinator mQueryTileCoordinator; + private final @NonNull AutocompleteMediator mMediator; + private @Nullable OmniboxSuggestionsDropdown mDropdown; public AutocompleteCoordinator(@NonNull ViewGroup parent, @NonNull AutocompleteDelegate delegate, @@ -77,7 +80,7 @@ @NonNull Supplier<Tab> activityTabSupplier, @Nullable Supplier<ShareDelegate> shareDelegateSupplier, @NonNull LocationBarDataProvider locationBarDataProvider, - @NonNull Callback<Profile> spareRendererCreator, + @NonNull ObservableSupplier<Profile> profileObservableSupplier, @NonNull Callback<Tab> bringToForegroundCallback, @NonNull Supplier<TabWindowManager> tabWindowManagerSupplier, @NonNull BookmarkState bookmarkState) { @@ -93,10 +96,9 @@ mQueryTileCoordinator = new OmniboxQueryTileCoordinator(context, this::onTileSelected); mMediator = new AutocompleteMediator(context, delegate, urlBarEditingTextProvider, - new AutocompleteController(spareRendererCreator), listModel, new Handler(), - lifecycleDispatcher, modalDialogManagerSupplier, activityTabSupplier, - shareDelegateSupplier, locationBarDataProvider, bringToForegroundCallback, - tabWindowManagerSupplier, bookmarkState); + listModel, new Handler(), lifecycleDispatcher, modalDialogManagerSupplier, + activityTabSupplier, shareDelegateSupplier, locationBarDataProvider, + bringToForegroundCallback, tabWindowManagerSupplier, bookmarkState); mMediator.initDefaultProcessors(mQueryTileCoordinator::setTiles); listModel.set(SuggestionListProperties.OBSERVER, mMediator); @@ -107,6 +109,10 @@ LazyConstructionPropertyMcp.create(listModel, SuggestionListProperties.VISIBLE, viewProvider, SuggestionListViewBinder::bind); + mProfileSupplier = profileObservableSupplier; + mProfileChangeCallback = this::setAutocompleteProfile; + mProfileSupplier.addObserver(mProfileChangeCallback); + // https://crbug.com/966227 Set initial layout direction ahead of inflating the suggestions. updateSuggestionListLayoutDirection(); } @@ -115,10 +121,9 @@ * Clean up resources used by this class. */ public void destroy() { + mProfileSupplier.removeObserver(mProfileChangeCallback); mQueryTileCoordinator.destroy(); - mQueryTileCoordinator = null; mMediator.destroy(); - mMediator = null; } private ViewProvider<SuggestionListViewHolder> createViewProvider( @@ -234,6 +239,7 @@ * Updates the profile used for generating autocomplete suggestions. * @param profile The profile to be used. */ + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) public void setAutocompleteProfile(Profile profile) { mMediator.setAutocompleteProfile(profile); mQueryTileCoordinator.setProfile(profile); @@ -388,12 +394,6 @@ return mDropdown; } - /** @param controller The instance of AutocompleteController to be used. */ - @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) - public void setAutocompleteControllerForTest(AutocompleteController controller) { - mMediator.setAutocompleteControllerForTest(controller); - } - /** @return The current receiving OnSuggestionsReceived events. */ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) public OnSuggestionsReceivedListener getSuggestionsReceivedListenerForTest() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java index 6bf35911..7f12d7c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java
@@ -152,7 +152,6 @@ public AutocompleteMediator(@NonNull Context context, @NonNull AutocompleteDelegate delegate, @NonNull UrlBarEditingTextStateProvider textProvider, - @NonNull AutocompleteController autocompleteController, @NonNull PropertyModel listPropertyModel, @NonNull Handler handler, @NonNull ActivityLifecycleDispatcher lifecycleDispatcher, @NonNull Supplier<ModalDialogManager> modalDialogManagerSupplier, @@ -169,15 +168,13 @@ mLifecycleDispatcher = lifecycleDispatcher; mLifecycleDispatcher.register(this); mModalDialogManagerSupplier = modalDialogManagerSupplier; - mAutocomplete = autocompleteController; - mAutocomplete.setOnSuggestionsReceivedListener(this); mHandler = handler; mDataProvider = locationBarDataProvider; mBringTabToFrontCallback = bringTabToFrontCallback; mTabWindowManagerSupplier = tabWindowManagerSupplier; mSuggestionModels = mListPropertyModel.get(SuggestionListProperties.SUGGESTION_MODELS); - mDropdownViewInfoListBuilder = new DropdownItemViewInfoListBuilder( - mAutocomplete, activityTabSupplier, bookmarkState); + mDropdownViewInfoListBuilder = + new DropdownItemViewInfoListBuilder(activityTabSupplier, bookmarkState); mDropdownViewInfoListBuilder.setShareDelegateSupplier(shareDelegateSupplier); mDropdownViewInfoListManager = new DropdownItemViewInfoListManager(mSuggestionModels); } @@ -201,7 +198,7 @@ public void destroy() { if (mAutocomplete != null) { stopAutocomplete(false); - mAutocomplete.destroy(); + mAutocomplete.removeOnSuggestionsReceivedListener(this); } mDropdownViewInfoListBuilder.destroy(); if (mLifecycleDispatcher != null) { @@ -387,7 +384,13 @@ * @param profile The profile to be used. */ void setAutocompleteProfile(Profile profile) { - mAutocomplete.setProfile(profile); + if (mAutocomplete != null) { + stopAutocomplete(true); + mAutocomplete.removeOnSuggestionsReceivedListener(this); + } + mAutocomplete = AutocompleteControllerFactory.getController(profile); + + mAutocomplete.addOnSuggestionsReceivedListener(this); mDropdownViewInfoListBuilder.setProfile(profile); } @@ -927,18 +930,6 @@ } /** - * Sets the autocomplete controller for the location bar. - * - * @param controller The controller that will handle autocomplete/omnibox suggestions. - * @note Only used for testing. - */ - public void setAutocompleteControllerForTest(AutocompleteController controller) { - if (mAutocomplete != null) stopAutocomplete(true); - mAutocomplete = controller; - mDropdownViewInfoListBuilder.setAutocompleteControllerForTest(controller); - } - - /** * Respond to Suggestion list height change and update list of presented suggestions. * * This typically happens as a result of soft keyboard being shown or hidden.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/DropdownItemViewInfoListBuilder.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/DropdownItemViewInfoListBuilder.java index 9a8adf7..208580a0d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/DropdownItemViewInfoListBuilder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/DropdownItemViewInfoListBuilder.java
@@ -53,7 +53,6 @@ private final @NonNull List<SuggestionProcessor> mPriorityOrderedSuggestionProcessors; private final @NonNull Supplier<Tab> mActivityTabSupplier; - private @NonNull AutocompleteController mAutocompleteController; private @Nullable HeaderProcessor mHeaderProcessor; private @Nullable Supplier<ShareDelegate> mShareDelegateSupplier; @@ -65,11 +64,10 @@ private boolean mEnableAdaptiveSuggestionsCount; private boolean mBuiltListHasFullyConcealedElements; - DropdownItemViewInfoListBuilder(AutocompleteController controller, + DropdownItemViewInfoListBuilder( @NonNull Supplier<Tab> tabSupplier, BookmarkState bookmarkState) { mPriorityOrderedSuggestionProcessors = new ArrayList<>(); mDropdownHeight = DROPDOWN_HEIGHT_UNKNOWN; - mAutocompleteController = controller; mActivityTabSupplier = tabSupplier; mBookmarkState = bookmarkState; } @@ -361,13 +359,4 @@ assert false : "No default handler for suggestions"; return null; } - - /** - * Change the AutocompleteController instance that will be used by this class. - * - * @param controller New AutocompleteController to use. - */ - void setAutocompleteControllerForTest(@NonNull AutocompleteController controller) { - mAutocompleteController = controller; - } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java index 19f5f67d..963095a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java
@@ -179,6 +179,7 @@ loadUrl(url, transition, postDataType, postData); return true; }; + // clang-format off mLocationBarCoordinator = new LocationBarCoordinator(mSearchBox, anchorView, mProfileSupplier, PrivacyPreferencesManagerImpl.getInstance(), mSearchBoxDataProvider, null, new WindowDelegate(getWindow()), getWindowAndroid(), @@ -187,9 +188,10 @@ getLifecycleDispatcher(), overrideUrlLoadingDelegate, /*backKeyBehavior=*/this, SearchEngineLogoUtils.getInstance(), /*launchAssistanceSettingsAction=*/() -> {}, /*pageInfoAction=*/(tab, permission) -> {}, - /*spareRendererCreator=*/(profile) -> {}, IntentHandler::bringTabToFront, + IntentHandler::bringTabToFront, /*saveOfflineButtonState=*/(tab) -> false, /*omniboxUma*/(url, transition) -> {}, TabWindowManagerSingleton::getInstance, /*bookmarkState=*/(url) -> false); + // clang-format on mLocationBarCoordinator.setUrlBarFocusable(true); mLocationBarCoordinator.setShouldShowMicButtonWhenUnfocused(true); mLocationBarCoordinator.getOmniboxStub().addUrlFocusChangeListener(this);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java index 47b27f5..073a020 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -39,7 +39,6 @@ import org.chromium.chrome.R; import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.IntentHandler; -import org.chromium.chrome.browser.WarmupManager; import org.chromium.chrome.browser.app.tabmodel.TabWindowManagerSingleton; import org.chromium.chrome.browser.autofill_assistant.AutofillAssistantPreferenceFragment; import org.chromium.chrome.browser.bookmarks.BookmarkBridge; @@ -541,7 +540,6 @@ new BackKeyBehaviorDelegate() {}, SearchEngineLogoUtils.getInstance(), () -> AutofillAssistantPreferenceFragment.launchSettings(mActivity), toolbarPageInfo::show, - WarmupManager.getInstance()::createSpareRenderProcessHost, IntentHandler::bringTabToFront, DownloadUtils::isAllowedToDownloadPage, NewTabPageUma::recordOmniboxNavigation, TabWindowManagerSingleton::getInstance, (url) -> mBookmarkBridgeSupplier.hasValue() @@ -908,7 +906,9 @@ || mLocationBar.getOmniboxStub().isUrlBarFocused()) { return; } - setUrlBarFocus(true, OmniboxFocusReason.FOCUS_ON_NEW_TAB); + // Note: this is executed during native initialization. + // Defer Omnibox focus, giving Autocomplete time to finish initialization. + mHandler.post(() -> setUrlBarFocus(true, OmniboxFocusReason.FOCUS_ON_NEW_TAB)); if (shouldShowCursorInLocationBar()) { mLocationBar.showUrlBarCursorWithoutFocusAnimations(); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/incognito/IncognitoProfileDestroyerIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/incognito/IncognitoProfileDestroyerIntegrationTest.java index 406f62e..dfacabf0 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/incognito/IncognitoProfileDestroyerIntegrationTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/incognito/IncognitoProfileDestroyerIntegrationTest.java
@@ -24,6 +24,8 @@ import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.JniMocker; import org.chromium.chrome.browser.flags.ChromeSwitches; +import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteController; +import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteControllerFactory; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.profiles.ProfileManager; import org.chromium.chrome.browser.tab.Tab; @@ -50,10 +52,15 @@ @Mock ProfileManager.Observer mMockProfileManagerObserver; + @Mock + AutocompleteController mAutocompleteController; + @Before public void setUp() throws InterruptedException { MockitoAnnotations.initMocks(this); + AutocompleteControllerFactory.setControllerForTesting(mAutocompleteController); + mActivityTestRule.startMainActivityOnBlankPage(); ProfileManager.addObserver(mMockProfileManagerObserver); mIncognitoTabModel = mActivityTestRule.getActivity().getTabModelSelector().getModel(true);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediatorUnitTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediatorUnitTest.java index 8875e46d..750ca18e6 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediatorUnitTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediatorUnitTest.java
@@ -57,6 +57,7 @@ import org.chromium.components.omnibox.AutocompleteResult; import org.chromium.components.query_tiles.QueryTile; import org.chromium.content_public.browser.test.NativeLibraryTestUtils; +import org.chromium.content_public.browser.test.util.TestThreadUtils; import org.chromium.ui.base.PageTransition; import org.chromium.ui.modaldialog.ModalDialogManager; import org.chromium.ui.modelutil.MVCListAdapter.ModelList; @@ -208,10 +209,17 @@ mListModel = new PropertyModel(SuggestionListProperties.ALL_KEYS); mListModel.set(SuggestionListProperties.SUGGESTION_MODELS, mSuggestionModels); + AutocompleteControllerFactory.setControllerForTesting(mAutocompleteController); + // clang-format off mMediator = new AutocompleteMediator(ContextUtils.getApplicationContext(), - mAutocompleteDelegate, mTextStateProvider, mAutocompleteController, mListModel, + mAutocompleteDelegate, mTextStateProvider, mListModel, mHandler, mLifecycleDispatcher, () -> mModalDialogManager, null, null, mLocationBarDataProvider, tab -> {}, null, url -> false); + + TestThreadUtils.runOnUiThreadBlocking(() -> { + mMediator.setAutocompleteProfile(mProfile); + }); + // clang-format on mMediator.getDropdownItemViewInfoListBuilderForTest().registerSuggestionProcessor( mMockProcessor); mMediator.getDropdownItemViewInfoListBuilderForTest().setHeaderProcessorForTest(
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/DropdownItemViewInfoListBuilderUnitTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/DropdownItemViewInfoListBuilderUnitTest.java index b021b73..37938a3 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/DropdownItemViewInfoListBuilderUnitTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/DropdownItemViewInfoListBuilderUnitTest.java
@@ -81,8 +81,7 @@ .thenAnswer((mock) -> new PropertyModel(SuggestionCommonProperties.ALL_KEYS)); when(mMockHeaderProcessor.getViewTypeId()).thenReturn(OmniboxSuggestionUiType.HEADER); - mBuilder = new DropdownItemViewInfoListBuilder( - mAutocompleteController, () -> null, (url) -> false); + mBuilder = new DropdownItemViewInfoListBuilder(() -> null, (url) -> false); mBuilder.registerSuggestionProcessor(mMockSuggestionProcessor); mBuilder.setHeaderProcessorForTest(mMockHeaderProcessor); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/mostvisited/MostVisitedTilesTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/mostvisited/MostVisitedTilesTest.java index 35db870..70ceebf 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/mostvisited/MostVisitedTilesTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/mostvisited/MostVisitedTilesTest.java
@@ -4,6 +4,12 @@ package org.chromium.chrome.browser.omnibox.suggestions.mostvisited; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.verify; + import android.support.test.InstrumentationRegistry; import android.view.KeyEvent; import android.view.View; @@ -18,6 +24,10 @@ import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import org.chromium.base.test.util.Batch; import org.chromium.base.test.util.CommandLineFlags; @@ -29,15 +39,17 @@ import org.chromium.chrome.browser.omnibox.LocationBarLayout; import org.chromium.chrome.browser.omnibox.OmniboxSuggestionType; import org.chromium.chrome.browser.omnibox.UrlBar; +import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteController; +import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteControllerFactory; import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteCoordinator; import org.chromium.chrome.browser.omnibox.suggestions.carousel.BaseCarouselSuggestionView; +import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.chrome.test.ChromeTabbedActivityTestRule; import org.chromium.chrome.test.batch.BlankCTATabInitialStateRule; import org.chromium.chrome.test.util.ChromeTabUtils; import org.chromium.chrome.test.util.OmniboxTestUtils; -import org.chromium.chrome.test.util.OmniboxTestUtils.TestAutocompleteController; import org.chromium.chrome.test.util.WaitForFocusHelper; import org.chromium.chrome.test.util.browser.Features.EnableFeatures; import org.chromium.components.omnibox.AutocompleteMatch.NavsuggestTile; @@ -81,10 +93,19 @@ public final BlankCTATabInitialStateRule mInitialStateRule = new BlankCTATabInitialStateRule(sActivityTestRule, false); + @Mock + private Profile mProfile; + + @Mock + private AutocompleteController mController; + + @Captor + private ArgumentCaptor<AutocompleteController.OnSuggestionsReceivedListener> mListener; + private ChromeTabbedActivity mActivity; private UrlBar mUrlBar; private LocationBarLayout mLocationBarLayout; - private TestAutocompleteController mController; + private AutocompleteCoordinator mAutocomplete; private EmbeddedTestServer mTestServer; private Tab mTab; @@ -96,6 +117,7 @@ @Before public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); sActivityTestRule.waitForActivityNativeInitializationComplete(); mActivity = sActivityTestRule.getActivity(); mLocationBarLayout = mActivity.findViewById(R.id.location_bar); @@ -108,9 +130,15 @@ ChromeTabUtils.waitForTabPageLoaded(mTab, null); // Set up a fake AutocompleteController that will supply the suggestions. - mController = new OmniboxTestUtils.TestAutocompleteController( - mAutocomplete.getSuggestionsReceivedListenerForTest()); - mAutocomplete.setAutocompleteControllerForTest(mController); + AutocompleteControllerFactory.setControllerForTesting(mController); + + // clang-format off + TestThreadUtils.runOnUiThreadBlocking(() -> { + mAutocomplete.setAutocompleteProfile(mProfile); + }); + // clang-format on + + verify(mController).addOnSuggestionsReceivedListener(mListener.capture()); setUpSuggestionsToShow(); focusOmniboxAndWaitForSuggestions(); @@ -160,7 +188,12 @@ autocompleteResult.getGroupsDetails().put( 1, new AutocompleteResult.GroupDetails("See also", false)); - mController.addAutocompleteResult(PAGE_URL, PAGE_URL, autocompleteResult); + doAnswer(invocation -> { + mListener.getValue().onSuggestionsReceived(autocompleteResult, PAGE_URL); + return null; + }) + .when(mController) + .startZeroSuggest(any(), eq(PAGE_URL), any(), anyInt(), any()); } private void focusOmniboxAndWaitForSuggestions() {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/voice/VoiceRecognitionHandlerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/voice/VoiceRecognitionHandlerTest.java index d4b7624..4e92a30 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/voice/VoiceRecognitionHandlerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/voice/VoiceRecognitionHandlerTest.java
@@ -413,9 +413,11 @@ public TestAutocompleteCoordinator(ViewGroup parent, AutocompleteDelegate delegate, OmniboxSuggestionsDropdownEmbedder dropdownEmbedder, UrlBarEditingTextStateProvider urlBarEditingTextProvider) { + // clang-format off super(parent, delegate, dropdownEmbedder, urlBarEditingTextProvider, mLifecycleDispatcher, () -> mModalDialogManager, null, null, mDataProvider, - (profile) -> {}, (tab) -> {}, null, (url) -> false); + mProfileSupplier, (tab) -> {}, null, (url) -> false); + // clang-format on } @Override
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/browserservices/ui/controller/webapps/WebappDisclosureControllerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/browserservices/ui/controller/webapps/WebappDisclosureControllerTest.java index d997af23..7cd81e1 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/browserservices/ui/controller/webapps/WebappDisclosureControllerTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/browserservices/ui/controller/webapps/WebappDisclosureControllerTest.java
@@ -27,6 +27,7 @@ import org.mockito.MockitoAnnotations; import org.robolectric.android.util.concurrent.RoboExecutorService; import org.robolectric.annotation.Config; +import org.robolectric.annotation.LooperMode; import org.chromium.base.task.PostTask; import org.chromium.base.test.BaseRobolectricTestRunner; @@ -49,6 +50,8 @@ */ @RunWith(BaseRobolectricTestRunner.class) @Config(manifest = Config.NONE) +// TODO(crbug.com/1210371): Change to use paused looper. See crbug for details. +@LooperMode(LooperMode.Mode.LEGACY) public class WebappDisclosureControllerTest { private static final String UNBOUND_PACKAGE = "unbound"; private static final String BOUND_PACKAGE = WebApkConstants.WEBAPK_PACKAGE_PREFIX + ".bound";
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/firstrun/PolicyLoadListenerUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/firstrun/PolicyLoadListenerUnitTest.java index fbc350b..b150a41 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/firstrun/PolicyLoadListenerUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/firstrun/PolicyLoadListenerUnitTest.java
@@ -19,6 +19,7 @@ import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; import org.robolectric.annotation.Config; +import org.robolectric.annotation.LooperMode; import org.robolectric.shadows.ShadowLooper; import org.robolectric.shadows.ShadowProcess; @@ -169,6 +170,8 @@ } @Test + // TODO(crbug.com/1210371): Change to use paused loop. See crbug for details. + @LooperMode(LooperMode.Mode.LEGACY) public void testDestroyAfterStart_PolicyInitializedInterleaved() { Assert.assertNull(LOADING_NOT_FINISHED, mPolicyLoadListener.onAvailable(mListener));
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/gcore/GoogleApiClientHelperTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/gcore/GoogleApiClientHelperTest.java index 9c7a607..8f1b1e5 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/gcore/GoogleApiClientHelperTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/gcore/GoogleApiClientHelperTest.java
@@ -9,6 +9,7 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import org.robolectric.annotation.LooperMode; import android.app.Activity; @@ -51,6 +52,8 @@ /** Tests that connection attempts are delayed. */ @Test @Feature({"GCore"}) + // TODO(crbug.com/1210371): Change to use paused loop. See crbug for details. + @LooperMode(LooperMode.Mode.LEGACY) public void connectionAttemptDelayTest() { GoogleApiClientHelper helper = new GoogleApiClientHelper(mMockClient);
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/survey/ChromeSurveyControllerFlowTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/survey/ChromeSurveyControllerFlowTest.java index 3a045aa..b628920 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/survey/ChromeSurveyControllerFlowTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/survey/ChromeSurveyControllerFlowTest.java
@@ -23,6 +23,7 @@ import org.robolectric.annotation.Config; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; +import org.robolectric.annotation.LooperMode; import org.robolectric.annotation.RealObject; import org.robolectric.shadows.ShadowLooper; @@ -60,6 +61,8 @@ ChromeSurveyControllerFlowTest.ShadowSurveyInfoBar.class, ChromeSurveyControllerFlowTest.ShadowInfoBarContainer.class }) +//TODO(crbug.com/1210371): Rewrite using paused loop. See crbug for details. +@LooperMode(LooperMode.Mode.LEGACY) public class ChromeSurveyControllerFlowTest { // clang-format on private static final String TEST_TRIGGER_ID = "test_trigger_id";
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp index 48f0e355..8d508920 100644 --- a/chrome/app/chromeos_strings.grdp +++ b/chrome/app/chromeos_strings.grdp
@@ -315,8 +315,8 @@ <message name="IDS_CELLULAR_SETUP_ESIM_PROFILE_DETECT_MESSAGE" desc="Message displayed during loading page in eSIM setup flow when looking for eSIM profiles."> Looking for available profiles... </message> - <message name="IDS_CELLULAR_SETUP_ESIM_CONNECTION_WARNING" desc="Message displayed during loading page in eSIM setup flow when looking for eSIM profiles informing the user that cellular setup may disconnect their current cellular network connection."> - This may cause your mobile network to briefly disconnect + <message name="IDS_CELLULAR_SETUP_ESIM_PROFILE_DETECT_DURING_ACTIVE_CELLULAR_CONNECTION_MESSAGE" desc="Message displayed during loading page in eSIM setup flow when looking for eSIM profiles informing the user that cellular setup may disconnect their current cellular network connection."> + Looking for available profiles. This may cause your mobile network to disconnect for a few minutes. </message> <message name="IDS_CELLULAR_SETUP_PROFILE_LIST_PAGE_MESSAGE" desc="Label informing the user that they are able to select multiple eSIM profiles for downloading."> We've found multiple profiles available to download. Select the ones you would like to download before proceeding.
diff --git a/chrome/app/chromeos_strings_grdp/IDS_CELLULAR_SETUP_ESIM_CONNECTION_WARNING.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_CELLULAR_SETUP_ESIM_CONNECTION_WARNING.png.sha1 deleted file mode 100644 index de7f9a53..0000000 --- a/chrome/app/chromeos_strings_grdp/IDS_CELLULAR_SETUP_ESIM_CONNECTION_WARNING.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -9d01cc22fe3233eaf079c7ae82057ad2a0b2e829 \ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_CELLULAR_SETUP_ESIM_PROFILE_DETECT_DURING_ACTIVE_CELLULAR_CONNECTION_MESSAGE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_CELLULAR_SETUP_ESIM_PROFILE_DETECT_DURING_ACTIVE_CELLULAR_CONNECTION_MESSAGE.png.sha1 new file mode 100644 index 0000000..aed39a7 --- /dev/null +++ b/chrome/app/chromeos_strings_grdp/IDS_CELLULAR_SETUP_ESIM_PROFILE_DETECT_DURING_ACTIVE_CELLULAR_CONNECTION_MESSAGE.png.sha1
@@ -0,0 +1 @@ +c30a1b8bae5ded451e6a8efd6ca98dc993604ce2 \ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_CELLULAR_SETUP_ESIM_PROFILE_DETECT_MESSAGE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_CELLULAR_SETUP_ESIM_PROFILE_DETECT_MESSAGE.png.sha1 index 1665de8..311eac4 100644 --- a/chrome/app/chromeos_strings_grdp/IDS_CELLULAR_SETUP_ESIM_PROFILE_DETECT_MESSAGE.png.sha1 +++ b/chrome/app/chromeos_strings_grdp/IDS_CELLULAR_SETUP_ESIM_PROFILE_DETECT_MESSAGE.png.sha1
@@ -1 +1 @@ -50d98ca9d86f9d8fe780771b4de96d4edeb154dc \ No newline at end of file +ac77a7010623072630a82e3903bad1d220a10f0e \ No newline at end of file
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 05d993db..c6d09b2 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -1235,6 +1235,9 @@ <message name="IDS_TAKE_SCREENSHOT" desc="The text label of the Take Screenshot menu item"> T&ake screenshot </message> + <message name="IDS_RESTORE_ALL_TABS" desc="The text label of the Restore All Tabs menu item."> + R&estore all tabs + </message> <message name="IDS_RESTORE_TAB" desc="The text label of the Restore Tab menu item"> R&eopen closed tab </message> @@ -1273,6 +1276,9 @@ <message name="IDS_TAKE_SCREENSHOT" desc="The text label of the Take Screenshot menu item"> T&ake Screenshot </message> + <message name="IDS_RESTORE_ALL_TABS" desc="In Title Case: The text label of the Restore All Tabs menu item."> + R&estore All Tabs + </message> <message name="IDS_RESTORE_TAB" desc="In Title Case: The text label of the Restore Tab menu item"> R&eopen Closed Tab </message>
diff --git a/chrome/app/generated_resources_grd/IDS_RESTORE_ALL_TABS.png.sha1 b/chrome/app/generated_resources_grd/IDS_RESTORE_ALL_TABS.png.sha1 new file mode 100644 index 0000000..61a5b433 --- /dev/null +++ b/chrome/app/generated_resources_grd/IDS_RESTORE_ALL_TABS.png.sha1
@@ -0,0 +1 @@ +2f5e9d03f9f0de8965d079c981475b7c8c00e9f7 \ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 82833c7..0605834 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -3397,12 +3397,12 @@ } else { #!is_android sources += [ - "accessibility/caption_controller.cc", - "accessibility/caption_controller.h", - "accessibility/caption_controller_factory.cc", - "accessibility/caption_controller_factory.h", "accessibility/invert_bubble_prefs.cc", "accessibility/invert_bubble_prefs.h", + "accessibility/live_caption_controller.cc", + "accessibility/live_caption_controller.h", + "accessibility/live_caption_controller_factory.cc", + "accessibility/live_caption_controller_factory.h", "accessibility/live_caption_speech_recognition_host.cc", "accessibility/live_caption_speech_recognition_host.h", "apps/app_service/app_icon_factory.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index df2c8c33..c75598f 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -7057,10 +7057,6 @@ FEATURE_VALUE_TYPE(net::features::kSplitCacheByNetworkIsolationKey)}, #if BUILDFLAG(IS_CHROMEOS_ASH) - {"enable-scalable-status-area", flag_descriptions::kScalableStatusAreaName, - flag_descriptions::kScalableStatusAreaDescription, kOsCrOS, - FEATURE_VALUE_TYPE(ash::features::kScalableStatusArea)}, - {"enable-show-date-in-tray", flag_descriptions::kShowDateInTrayName, flag_descriptions::kShowDateInTrayDescription, kOsCrOS, FEATURE_VALUE_TYPE(ash::features::kShowDateInTrayButton)},
diff --git a/chrome/browser/accessibility/caption_controller_factory.cc b/chrome/browser/accessibility/caption_controller_factory.cc deleted file mode 100644 index 28085388..0000000 --- a/chrome/browser/accessibility/caption_controller_factory.cc +++ /dev/null
@@ -1,52 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/accessibility/caption_controller_factory.h" - -#include "build/build_config.h" -#include "chrome/browser/accessibility/caption_controller.h" -#include "chrome/browser/profiles/incognito_helpers.h" -#include "chrome/browser/profiles/profile.h" -#include "components/keyed_service/content/browser_context_dependency_manager.h" - -namespace captions { - -// static -CaptionController* CaptionControllerFactory::GetForProfile(Profile* profile) { - return static_cast<CaptionController*>( - GetInstance()->GetServiceForBrowserContext(profile, true)); -} - -// static -CaptionController* CaptionControllerFactory::GetForProfileIfExists( - Profile* profile) { - return static_cast<CaptionController*>( - GetInstance()->GetServiceForBrowserContext(profile, /*create=*/false)); -} - -// static -CaptionControllerFactory* CaptionControllerFactory::GetInstance() { - static base::NoDestructor<CaptionControllerFactory> factory; - return factory.get(); -} - -CaptionControllerFactory::CaptionControllerFactory() - : BrowserContextKeyedServiceFactory( - "CaptionController", - BrowserContextDependencyManager::GetInstance()) {} - -CaptionControllerFactory::~CaptionControllerFactory() = default; - -content::BrowserContext* CaptionControllerFactory::GetBrowserContextToUse( - content::BrowserContext* context) const { - return chrome::GetBrowserContextRedirectedInIncognito(context); -} - -KeyedService* CaptionControllerFactory::BuildServiceInstanceFor( - content::BrowserContext* context) const { - return new CaptionController( - Profile::FromBrowserContext(context)->GetPrefs()); -} - -} // namespace captions
diff --git a/chrome/browser/accessibility/caption_controller_factory.h b/chrome/browser/accessibility/caption_controller_factory.h deleted file mode 100644 index 1caf078..0000000 --- a/chrome/browser/accessibility/caption_controller_factory.h +++ /dev/null
@@ -1,41 +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_ACCESSIBILITY_CAPTION_CONTROLLER_FACTORY_H_ -#define CHROME_BROWSER_ACCESSIBILITY_CAPTION_CONTROLLER_FACTORY_H_ - -#include "base/no_destructor.h" -#include "components/keyed_service/content/browser_context_keyed_service_factory.h" - -class Profile; - -namespace captions { - -class CaptionController; - -// Factory to get or create an instance of CaptionController from a Profile. -class CaptionControllerFactory : public BrowserContextKeyedServiceFactory { - public: - static CaptionController* GetForProfile(Profile* profile); - - static CaptionController* GetForProfileIfExists(Profile* profile); - - static CaptionControllerFactory* GetInstance(); - - private: - friend base::NoDestructor<CaptionControllerFactory>; - - CaptionControllerFactory(); - ~CaptionControllerFactory() override; - - // BrowserContextKeyedServiceFactory: - content::BrowserContext* GetBrowserContextToUse( - content::BrowserContext* context) const override; - KeyedService* BuildServiceInstanceFor( - content::BrowserContext* profile) const override; -}; - -} // namespace captions - -#endif // CHROME_BROWSER_ACCESSIBILITY_CAPTION_CONTROLLER_FACTORY_H_
diff --git a/chrome/browser/accessibility/caption_controller.cc b/chrome/browser/accessibility/live_caption_controller.cc similarity index 85% rename from chrome/browser/accessibility/caption_controller.cc rename to chrome/browser/accessibility/live_caption_controller.cc index 5e67ea81..0fbf024 100644 --- a/chrome/browser/accessibility/caption_controller.cc +++ b/chrome/browser/accessibility/live_caption_controller.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/accessibility/caption_controller.h" +#include "chrome/browser/accessibility/live_caption_controller.h" #include <memory> @@ -39,10 +39,10 @@ namespace captions { -CaptionController::CaptionController(PrefService* profile_prefs) +LiveCaptionController::LiveCaptionController(PrefService* profile_prefs) : profile_prefs_(profile_prefs) {} -CaptionController::~CaptionController() { +LiveCaptionController::~LiveCaptionController() { if (enabled_) { enabled_ = false; StopLiveCaption(); @@ -50,7 +50,7 @@ } // static -void CaptionController::RegisterProfilePrefs( +void LiveCaptionController::RegisterProfilePrefs( user_prefs::PrefRegistrySyncable* registry) { registry->RegisterBooleanPref( prefs::kLiveCaptionEnabled, false, @@ -61,7 +61,7 @@ user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); } -void CaptionController::Init() { +void LiveCaptionController::Init() { base::UmaHistogramBoolean("Accessibility.LiveCaption.FeatureEnabled", media::IsLiveCaptionFeatureEnabled()); @@ -82,11 +82,11 @@ pref_change_registrar_->Add( prefs::kLiveCaptionEnabled, - base::BindRepeating(&CaptionController::OnLiveCaptionEnabledChanged, + base::BindRepeating(&LiveCaptionController::OnLiveCaptionEnabledChanged, base::Unretained(this))); pref_change_registrar_->Add( prefs::kLiveCaptionLanguageCode, - base::BindRepeating(&CaptionController::OnLiveCaptionLanguageChanged, + base::BindRepeating(&LiveCaptionController::OnLiveCaptionLanguageChanged, base::Unretained(this))); enabled_ = IsLiveCaptionEnabled(); @@ -100,11 +100,11 @@ // callback is not called on destroyed object. content::BrowserAccessibilityState::GetInstance() ->AddUIThreadHistogramCallback(base::BindOnce( - &CaptionController::UpdateAccessibilityCaptionHistograms, + &LiveCaptionController::UpdateAccessibilityCaptionHistograms, weak_ptr_factory_.GetWeakPtr())); } -void CaptionController::OnLiveCaptionEnabledChanged() { +void LiveCaptionController::OnLiveCaptionEnabledChanged() { bool enabled = IsLiveCaptionEnabled(); if (enabled == enabled_) return; @@ -119,19 +119,19 @@ } } -void CaptionController::OnLiveCaptionLanguageChanged() { +void LiveCaptionController::OnLiveCaptionLanguageChanged() { if (enabled_) speech::SodaInstaller::GetInstance()->InstallLanguage( profile_prefs_->GetString(prefs::kLiveCaptionLanguageCode), g_browser_process->local_state()); } -bool CaptionController::IsLiveCaptionEnabled() { +bool LiveCaptionController::IsLiveCaptionEnabled() { PrefService* profile_prefs = profile_prefs_; return profile_prefs->GetBoolean(prefs::kLiveCaptionEnabled); } -void CaptionController::StartLiveCaption() { +void LiveCaptionController::StartLiveCaption() { DCHECK(enabled_); if (!base::FeatureList::IsEnabled(media::kUseSodaForLiveCaption)) { CreateUI(); @@ -151,13 +151,13 @@ } } -void CaptionController::StopLiveCaption() { +void LiveCaptionController::StopLiveCaption() { DCHECK(!enabled_); speech::SodaInstaller::GetInstance()->RemoveObserver(this); DestroyUI(); } -void CaptionController::OnSodaInstalled() { +void LiveCaptionController::OnSodaInstalled() { // Live Caption should always be enabled when this is called. If Live Caption // has been disabled, then this should not be observing the SodaInstaller // anymore. @@ -166,7 +166,7 @@ CreateUI(); } -void CaptionController::CreateUI() { +void LiveCaptionController::CreateUI() { DCHECK(enabled_); if (is_ui_constructed_) return; @@ -185,13 +185,13 @@ DCHECK(!pref_change_registrar_->IsObserved(pref_name)); pref_change_registrar_->Add( pref_name, - base::BindRepeating(&CaptionController::OnCaptionStyleUpdated, + base::BindRepeating(&LiveCaptionController::OnCaptionStyleUpdated, base::Unretained(this))); } OnCaptionStyleUpdated(); } -void CaptionController::DestroyUI() { +void LiveCaptionController::DestroyUI() { DCHECK(!enabled_); if (!is_ui_constructed_) return; @@ -208,11 +208,11 @@ } } -void CaptionController::UpdateAccessibilityCaptionHistograms() { +void LiveCaptionController::UpdateAccessibilityCaptionHistograms() { base::UmaHistogramBoolean("Accessibility.LiveCaption", enabled_); } -bool CaptionController::DispatchTranscription( +bool LiveCaptionController::DispatchTranscription( LiveCaptionSpeechRecognitionHost* live_caption_speech_recognition_host, const media::mojom::SpeechRecognitionResultPtr& result) { if (!caption_bubble_controller_) @@ -221,14 +221,14 @@ live_caption_speech_recognition_host, result); } -void CaptionController::OnError( +void LiveCaptionController::OnError( LiveCaptionSpeechRecognitionHost* live_caption_speech_recognition_host) { if (!caption_bubble_controller_) return; caption_bubble_controller_->OnError(live_caption_speech_recognition_host); } -void CaptionController::OnAudioStreamEnd( +void LiveCaptionController::OnAudioStreamEnd( LiveCaptionSpeechRecognitionHost* live_caption_speech_recognition_host) { if (!caption_bubble_controller_) return; @@ -236,12 +236,12 @@ live_caption_speech_recognition_host); } -void CaptionController::OnLanguageIdentificationEvent( +void LiveCaptionController::OnLanguageIdentificationEvent( const media::mojom::LanguageIdentificationEventPtr& event) { // TODO(crbug.com/1175357): Implement the UI for language identification. } -void CaptionController::OnCaptionStyleUpdated() { +void LiveCaptionController::OnCaptionStyleUpdated() { // Metrics are recorded when passing the caption prefs to the browser, so do // not duplicate them here. caption_style_ = GetCaptionStyleFromUserSettings(profile_prefs_,
diff --git a/chrome/browser/accessibility/caption_controller.h b/chrome/browser/accessibility/live_caption_controller.h similarity index 75% rename from chrome/browser/accessibility/caption_controller.h rename to chrome/browser/accessibility/live_caption_controller.h index e0cd6c6..101f639f 100644 --- a/chrome/browser/accessibility/caption_controller.h +++ b/chrome/browser/accessibility/live_caption_controller.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_ACCESSIBILITY_CAPTION_CONTROLLER_H_ -#define CHROME_BROWSER_ACCESSIBILITY_CAPTION_CONTROLLER_H_ +#ifndef CHROME_BROWSER_ACCESSIBILITY_LIVE_CAPTION_CONTROLLER_H_ +#define CHROME_BROWSER_ACCESSIBILITY_LIVE_CAPTION_CONTROLLER_H_ #include <memory> @@ -31,22 +31,22 @@ class LiveCaptionSpeechRecognitionHost; /////////////////////////////////////////////////////////////////////////////// -// Caption Controller +// Live Caption Controller // // The controller of the live caption feature. It enables the captioning -// service when the preference is enabled. The caption controller is a -// KeyedService. There exists one caption controller per profile and it lasts -// for the duration of the session. The caption controller owns the live -// caption UI, which is a caption bubble controller. +// service when the preference is enabled. The live caption controller is a +// KeyedService. There exists one live caption controller per profile and it +// lasts for the duration of the session. The live caption controller owns the +// live caption UI, which is a caption bubble controller. // -class CaptionController : public KeyedService, - public speech::SodaInstaller::Observer, - public ui::NativeThemeObserver { +class LiveCaptionController : public KeyedService, + public speech::SodaInstaller::Observer, + public ui::NativeThemeObserver { public: - explicit CaptionController(PrefService* profile_prefs); - ~CaptionController() override; - CaptionController(const CaptionController&) = delete; - CaptionController& operator=(const CaptionController&) = delete; + explicit LiveCaptionController(PrefService* profile_prefs); + ~LiveCaptionController() override; + LiveCaptionController(const LiveCaptionController&) = delete; + LiveCaptionController& operator=(const LiveCaptionController&) = delete; static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry); @@ -72,8 +72,8 @@ LiveCaptionSpeechRecognitionHost* live_caption_speech_recognition_host); private: - friend class CaptionControllerFactory; - friend class CaptionControllerTest; + friend class LiveCaptionControllerFactory; + friend class LiveCaptionControllerTest; // SodaInstaller::Observer: void OnSodaInstalled() override; @@ -113,9 +113,9 @@ // ensures that the UI is not constructed or deconstructed twice. bool is_ui_constructed_ = false; - base::WeakPtrFactory<CaptionController> weak_ptr_factory_{this}; + base::WeakPtrFactory<LiveCaptionController> weak_ptr_factory_{this}; }; } // namespace captions -#endif // CHROME_BROWSER_ACCESSIBILITY_CAPTION_CONTROLLER_H_ +#endif // CHROME_BROWSER_ACCESSIBILITY_LIVE_CAPTION_CONTROLLER_H_
diff --git a/chrome/browser/accessibility/caption_controller_browsertest.cc b/chrome/browser/accessibility/live_caption_controller_browsertest.cc similarity index 91% rename from chrome/browser/accessibility/caption_controller_browsertest.cc rename to chrome/browser/accessibility/live_caption_controller_browsertest.cc index b434f95..54e616c 100644 --- a/chrome/browser/accessibility/caption_controller_browsertest.cc +++ b/chrome/browser/accessibility/live_caption_controller_browsertest.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/accessibility/caption_controller.h" +#include "chrome/browser/accessibility/live_caption_controller.h" #include "base/feature_list.h" #include "base/files/file_path.h" @@ -10,7 +10,7 @@ #include "base/test/scoped_feature_list.h" #include "build/build_config.h" #include "build/chromeos_buildflags.h" -#include "chrome/browser/accessibility/caption_controller_factory.h" +#include "chrome/browser/accessibility/live_caption_controller_factory.h" #include "chrome/browser/accessibility/live_caption_speech_recognition_host.h" #include "chrome/browser/browser_features.h" #include "chrome/browser/browser_process.h" @@ -68,12 +68,13 @@ return profile_manager->GetProfileByPath(profile_path); } -class CaptionControllerTest : public InProcessBrowserTest { +class LiveCaptionControllerTest : public InProcessBrowserTest { public: - CaptionControllerTest() = default; - ~CaptionControllerTest() override = default; - CaptionControllerTest(const CaptionControllerTest&) = delete; - CaptionControllerTest& operator=(const CaptionControllerTest&) = delete; + LiveCaptionControllerTest() = default; + ~LiveCaptionControllerTest() override = default; + LiveCaptionControllerTest(const LiveCaptionControllerTest&) = delete; + LiveCaptionControllerTest& operator=(const LiveCaptionControllerTest&) = + delete; // InProcessBrowserTest overrides: void SetUp() override { @@ -94,12 +95,12 @@ speech::SodaInstaller::GetInstance()->NotifySodaInstalledForTesting(); } - CaptionController* GetController() { + LiveCaptionController* GetController() { return GetControllerForProfile(browser()->profile()); } - CaptionController* GetControllerForProfile(Profile* profile) { - return CaptionControllerFactory::GetForProfile(profile); + LiveCaptionController* GetControllerForProfile(Profile* profile) { + return LiveCaptionControllerFactory::GetForProfile(profile); } CaptionBubbleController* GetBubbleController() { @@ -184,7 +185,7 @@ live_caption_speech_recognition_host_; }; -IN_PROC_BROWSER_TEST_F(CaptionControllerTest, ProfilePrefsAreRegistered) { +IN_PROC_BROWSER_TEST_F(LiveCaptionControllerTest, ProfilePrefsAreRegistered) { EXPECT_FALSE( browser()->profile()->GetPrefs()->GetBoolean(prefs::kLiveCaptionEnabled)); @@ -198,7 +199,7 @@ #endif // !defined(OS_CHROMEOS) } -IN_PROC_BROWSER_TEST_F(CaptionControllerTest, +IN_PROC_BROWSER_TEST_F(LiveCaptionControllerTest, ProfilePrefsAreRegistered_Incognito) { // Set live caption enabled on the regular profile. SetLiveCaptionEnabled(true); @@ -228,7 +229,7 @@ #endif // !defined(OS_CHROMEOS) } -IN_PROC_BROWSER_TEST_F(CaptionControllerTest, LiveCaptionEnabledChanged) { +IN_PROC_BROWSER_TEST_F(LiveCaptionControllerTest, LiveCaptionEnabledChanged) { EXPECT_EQ(nullptr, GetBubbleController()); EXPECT_FALSE(HasBubbleController()); @@ -241,7 +242,7 @@ EXPECT_FALSE(HasBubbleController()); } -IN_PROC_BROWSER_TEST_F(CaptionControllerTest, +IN_PROC_BROWSER_TEST_F(LiveCaptionControllerTest, LiveCaptionEnabledChanged_BubbleVisible) { SetLiveCaptionEnabled(true); // Make the bubble visible by dispatching a transcription. @@ -254,7 +255,7 @@ EXPECT_FALSE(HasBubbleController()); } -IN_PROC_BROWSER_TEST_F(CaptionControllerTest, OnSodaInstalled) { +IN_PROC_BROWSER_TEST_F(LiveCaptionControllerTest, OnSodaInstalled) { EXPECT_FALSE(HasBubbleController()); browser()->profile()->GetPrefs()->SetBoolean(prefs::kLiveCaptionEnabled, true); @@ -265,7 +266,7 @@ EXPECT_TRUE(HasBubbleController()); } -IN_PROC_BROWSER_TEST_F(CaptionControllerTest, DispatchTranscription) { +IN_PROC_BROWSER_TEST_F(LiveCaptionControllerTest, DispatchTranscription) { bool success = DispatchTranscription("A baby spider is called a spiderling."); EXPECT_FALSE(success); EXPECT_FALSE(HasBubbleController()); @@ -286,7 +287,7 @@ EXPECT_FALSE(HasBubbleController()); } -IN_PROC_BROWSER_TEST_F(CaptionControllerTest, OnError) { +IN_PROC_BROWSER_TEST_F(LiveCaptionControllerTest, OnError) { OnError(); EXPECT_FALSE(HasBubbleController()); @@ -299,7 +300,7 @@ EXPECT_FALSE(HasBubbleController()); } -IN_PROC_BROWSER_TEST_F(CaptionControllerTest, OnAudioStreamEnd) { +IN_PROC_BROWSER_TEST_F(LiveCaptionControllerTest, OnAudioStreamEnd) { OnAudioStreamEnd(); EXPECT_FALSE(HasBubbleController()); @@ -317,7 +318,7 @@ #if !BUILDFLAG(IS_CHROMEOS_ASH) // No multi-profile on ChromeOS. -IN_PROC_BROWSER_TEST_F(CaptionControllerTest, +IN_PROC_BROWSER_TEST_F(LiveCaptionControllerTest, LiveCaptionEnabledChanged_MultipleProfiles) { Profile* profile1 = browser()->profile(); Profile* profile2 = CreateProfile(); @@ -347,7 +348,7 @@ EXPECT_FALSE(HasBubbleControllerOnProfile(profile2)); } -IN_PROC_BROWSER_TEST_F(CaptionControllerTest, +IN_PROC_BROWSER_TEST_F(LiveCaptionControllerTest, DispatchTranscription_MultipleProfiles) { Profile* profile1 = browser()->profile(); Profile* profile2 = CreateProfile(); @@ -375,7 +376,7 @@ "Mosquitos were around at the time of the dinosaurs.", profile2); } -IN_PROC_BROWSER_TEST_F(CaptionControllerTest, OnError_MultipleProfiles) { +IN_PROC_BROWSER_TEST_F(LiveCaptionControllerTest, OnError_MultipleProfiles) { Profile* profile1 = browser()->profile(); Profile* profile2 = CreateProfile(); @@ -393,7 +394,7 @@ ExpectIsWidgetVisibleOnProfile(true, profile2); } -IN_PROC_BROWSER_TEST_F(CaptionControllerTest, +IN_PROC_BROWSER_TEST_F(LiveCaptionControllerTest, OnAudioStreamEnd_MultipleProfiles) { Profile* profile1 = browser()->profile(); Profile* profile2 = CreateProfile();
diff --git a/chrome/browser/accessibility/live_caption_controller_factory.cc b/chrome/browser/accessibility/live_caption_controller_factory.cc new file mode 100644 index 0000000..36551a3 --- /dev/null +++ b/chrome/browser/accessibility/live_caption_controller_factory.cc
@@ -0,0 +1,53 @@ +// 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/accessibility/live_caption_controller_factory.h" + +#include "build/build_config.h" +#include "chrome/browser/accessibility/live_caption_controller.h" +#include "chrome/browser/profiles/incognito_helpers.h" +#include "chrome/browser/profiles/profile.h" +#include "components/keyed_service/content/browser_context_dependency_manager.h" + +namespace captions { + +// static +LiveCaptionController* LiveCaptionControllerFactory::GetForProfile( + Profile* profile) { + return static_cast<LiveCaptionController*>( + GetInstance()->GetServiceForBrowserContext(profile, true)); +} + +// static +LiveCaptionController* LiveCaptionControllerFactory::GetForProfileIfExists( + Profile* profile) { + return static_cast<LiveCaptionController*>( + GetInstance()->GetServiceForBrowserContext(profile, /*create=*/false)); +} + +// static +LiveCaptionControllerFactory* LiveCaptionControllerFactory::GetInstance() { + static base::NoDestructor<LiveCaptionControllerFactory> factory; + return factory.get(); +} + +LiveCaptionControllerFactory::LiveCaptionControllerFactory() + : BrowserContextKeyedServiceFactory( + "LiveCaptionController", + BrowserContextDependencyManager::GetInstance()) {} + +LiveCaptionControllerFactory::~LiveCaptionControllerFactory() = default; + +content::BrowserContext* LiveCaptionControllerFactory::GetBrowserContextToUse( + content::BrowserContext* context) const { + return chrome::GetBrowserContextRedirectedInIncognito(context); +} + +KeyedService* LiveCaptionControllerFactory::BuildServiceInstanceFor( + content::BrowserContext* context) const { + return new LiveCaptionController( + Profile::FromBrowserContext(context)->GetPrefs()); +} + +} // namespace captions
diff --git a/chrome/browser/accessibility/live_caption_controller_factory.h b/chrome/browser/accessibility/live_caption_controller_factory.h new file mode 100644 index 0000000..72cde4b --- /dev/null +++ b/chrome/browser/accessibility/live_caption_controller_factory.h
@@ -0,0 +1,41 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_ACCESSIBILITY_LIVE_CAPTION_CONTROLLER_FACTORY_H_ +#define CHROME_BROWSER_ACCESSIBILITY_LIVE_CAPTION_CONTROLLER_FACTORY_H_ + +#include "base/no_destructor.h" +#include "components/keyed_service/content/browser_context_keyed_service_factory.h" + +class Profile; + +namespace captions { + +class LiveCaptionController; + +// Factory to get or create an instance of LiveCaptionController from a Profile. +class LiveCaptionControllerFactory : public BrowserContextKeyedServiceFactory { + public: + static LiveCaptionController* GetForProfile(Profile* profile); + + static LiveCaptionController* GetForProfileIfExists(Profile* profile); + + static LiveCaptionControllerFactory* GetInstance(); + + private: + friend base::NoDestructor<LiveCaptionControllerFactory>; + + LiveCaptionControllerFactory(); + ~LiveCaptionControllerFactory() override; + + // BrowserContextKeyedServiceFactory: + content::BrowserContext* GetBrowserContextToUse( + content::BrowserContext* context) const override; + KeyedService* BuildServiceInstanceFor( + content::BrowserContext* profile) const override; +}; + +} // namespace captions + +#endif // CHROME_BROWSER_ACCESSIBILITY_LIVE_CAPTION_CONTROLLER_FACTORY_H_
diff --git a/chrome/browser/accessibility/live_caption_speech_recognition_host.cc b/chrome/browser/accessibility/live_caption_speech_recognition_host.cc index a488705..7407b3b 100644 --- a/chrome/browser/accessibility/live_caption_speech_recognition_host.cc +++ b/chrome/browser/accessibility/live_caption_speech_recognition_host.cc
@@ -7,8 +7,8 @@ #include <memory> #include <utility> -#include "chrome/browser/accessibility/caption_controller.h" -#include "chrome/browser/accessibility/caption_controller_factory.h" +#include "chrome/browser/accessibility/live_caption_controller.h" +#include "chrome/browser/accessibility/live_caption_controller_factory.h" #include "chrome/browser/profiles/profile.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" @@ -36,35 +36,36 @@ } LiveCaptionSpeechRecognitionHost::~LiveCaptionSpeechRecognitionHost() { - CaptionController* caption_controller = GetCaptionController(); - if (caption_controller) - caption_controller->OnAudioStreamEnd(this); + LiveCaptionController* live_caption_controller = GetLiveCaptionController(); + if (live_caption_controller) + live_caption_controller->OnAudioStreamEnd(this); } void LiveCaptionSpeechRecognitionHost::OnSpeechRecognitionRecognitionEvent( media::mojom::SpeechRecognitionResultPtr result, OnSpeechRecognitionRecognitionEventCallback reply) { - CaptionController* caption_controller = GetCaptionController(); - if (!caption_controller) { + LiveCaptionController* live_caption_controller = GetLiveCaptionController(); + if (!live_caption_controller) { std::move(reply).Run(false); return; } - std::move(reply).Run(caption_controller->DispatchTranscription(this, result)); + std::move(reply).Run( + live_caption_controller->DispatchTranscription(this, result)); } void LiveCaptionSpeechRecognitionHost::OnLanguageIdentificationEvent( media::mojom::LanguageIdentificationEventPtr event) { - CaptionController* caption_controller = GetCaptionController(); - if (!caption_controller) + LiveCaptionController* live_caption_controller = GetLiveCaptionController(); + if (!live_caption_controller) return; - caption_controller->OnLanguageIdentificationEvent(std::move(event)); + live_caption_controller->OnLanguageIdentificationEvent(std::move(event)); } void LiveCaptionSpeechRecognitionHost::OnSpeechRecognitionError() { - CaptionController* caption_controller = GetCaptionController(); - if (caption_controller) - caption_controller->OnError(this); + LiveCaptionController* live_caption_controller = GetLiveCaptionController(); + if (live_caption_controller) + live_caption_controller->OnError(this); } void LiveCaptionSpeechRecognitionHost::RenderFrameDeleted( @@ -83,7 +84,8 @@ return web_contents; } -CaptionController* LiveCaptionSpeechRecognitionHost::GetCaptionController() { +LiveCaptionController* +LiveCaptionSpeechRecognitionHost::GetLiveCaptionController() { content::WebContents* web_contents = GetWebContents(); if (!web_contents) return nullptr; @@ -91,7 +93,7 @@ Profile::FromBrowserContext(web_contents->GetBrowserContext()); if (!profile) return nullptr; - return CaptionControllerFactory::GetForProfile(profile); + return LiveCaptionControllerFactory::GetForProfile(profile); } } // namespace captions
diff --git a/chrome/browser/accessibility/live_caption_speech_recognition_host.h b/chrome/browser/accessibility/live_caption_speech_recognition_host.h index dcc3e06..3db8765 100644 --- a/chrome/browser/accessibility/live_caption_speech_recognition_host.h +++ b/chrome/browser/accessibility/live_caption_speech_recognition_host.h
@@ -15,7 +15,7 @@ namespace captions { -class CaptionController; +class LiveCaptionController; /////////////////////////////////////////////////////////////////////////////// // Live Caption Speech Recognition Host @@ -59,9 +59,9 @@ void RenderFrameDeleted(content::RenderFrameHost* frame_host) override; private: - // Returns the CaptionController for frame_host_. Returns nullptr if it does - // not exist. - CaptionController* GetCaptionController(); + // Returns the LiveCaptionController for frame_host_. Returns nullptr if it + // does not exist. + LiveCaptionController* GetLiveCaptionController(); content::RenderFrameHost* frame_host_; };
diff --git a/chrome/browser/apps/app_service/publishers/standalone_browser_apps.cc b/chrome/browser/apps/app_service/publishers/standalone_browser_apps.cc index baebe0ad..95af91f 100644 --- a/chrome/browser/apps/app_service/publishers/standalone_browser_apps.cc +++ b/chrome/browser/apps/app_service/publishers/standalone_browser_apps.cc
@@ -45,7 +45,7 @@ app->show_in_launcher = apps::mojom::OptionalBool::kTrue; app->show_in_shelf = apps::mojom::OptionalBool::kTrue; app->show_in_search = apps::mojom::OptionalBool::kTrue; - app->show_in_management = apps::mojom::OptionalBool::kFalse; + app->show_in_management = apps::mojom::OptionalBool::kTrue; return app; }
diff --git a/chrome/browser/ash/accessibility/switch_access_browsertest.cc b/chrome/browser/ash/accessibility/switch_access_browsertest.cc index ba06316b..d578394c 100644 --- a/chrome/browser/ash/accessibility/switch_access_browsertest.cc +++ b/chrome/browser/ash/accessibility/switch_access_browsertest.cc
@@ -122,8 +122,6 @@ std::unique_ptr<ExtensionConsoleErrorObserver> console_observer_; }; -// TODO(anastasi): Add a test for typing with the virtual keyboard. - IN_PROC_BROWSER_TEST_F(SwitchAccessTest, ConsumesKeyEvents) { EnableSwitchAccess({'1', 'A'} /* select */, {'2', 'B'} /* next */, {'3', 'C'} /* previous */); @@ -254,4 +252,38 @@ WaitForFocusRing("primary", "button", "Keyboard"); } +IN_PROC_BROWSER_TEST_F(SwitchAccessTest, TypeIntoVirtualKeyboard) { + EnableSwitchAccess({'1', 'A'} /* select */, {'2', 'B'} /* next */, + {'3', 'C'} /* previous */); + + // Load a webpage with a text box. + ui_test_utils::NavigateToURL( + browser(), + GURL("data:text/html,<input autofocus aria-label=MyTextField>")); + + // Wait for switch access to focus on the text field. + WaitForFocusRing("primary", "textField", "MyTextField"); + + // Send "select", which opens the switch access menu. + SendVirtualKeyPress(ui::KeyboardCode::VKEY_1); + + // Wait for the switch access menu to appear and for focus to land on + // the first item, the "keyboard" button. + // + // Note that we don't try to also call WaitForSwitchAccessMenuAndGetActions + // here because by the time it returns, we may have already received the focus + // ring for the menu and so the following WaitForFocusRing would fail / loop + // forever. + WaitForFocusRing("primary", "button", "Keyboard"); + + // Send "select", which opens the virtual keyboard. + SendVirtualKeyPress(ui::KeyboardCode::VKEY_1); + + // Finally, we should land on a keyboard key. + WaitForFocusRing("primary", "keyboard", ""); + + // Actually typing and verifying text field value should be covered by + // js-based tests that have the ability to ask the text field for its value. +} + } // namespace ash
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index 4b4d66f..45ea243 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -3717,7 +3717,7 @@ additional_backends) { #if BUILDFLAG(IS_CHROMEOS_ASH) storage::ExternalMountPoints* external_mount_points = - content::BrowserContext::GetMountPoints(browser_context); + browser_context->GetMountPoints(); DCHECK(external_mount_points); auto backend = std::make_unique<chromeos::FileSystemBackend>( Profile::FromBrowserContext(browser_context), @@ -4985,6 +4985,56 @@ #endif } +void ChromeContentBrowserClient::WillCreateWebTransport( + content::RenderFrameHost* frame, + const GURL& url, + WillCreateWebTransportCallback callback) { +#if BUILDFLAG(SAFE_BROWSING_AVAILABLE) + if (!frame) { + std::move(callback).Run(absl::nullopt); + return; + } + int frame_tree_node_id = frame->GetFrameTreeNodeId(); + content::WebContents* web_contents = + content::WebContents::FromFrameTreeNodeId(frame_tree_node_id); + DCHECK(web_contents); + Profile* profile = + Profile::FromBrowserContext(web_contents->GetBrowserContext()); + DCHECK(profile); + auto checker = std::make_unique<safe_browsing::WebApiHandshakeChecker>( + base::BindOnce( + &ChromeContentBrowserClient::GetSafeBrowsingUrlCheckerDelegate, + base::Unretained(this), + safe_browsing::IsSafeBrowsingEnabled(*profile->GetPrefs()), + /*should_check_on_sb_disabled=*/false, + safe_browsing::GetURLAllowlistByPolicy(profile->GetPrefs())), + base::BindRepeating(&content::WebContents::FromFrameTreeNodeId, + frame_tree_node_id), + frame_tree_node_id); + auto* raw_checker = checker.get(); + raw_checker->Check( + url, + base::BindOnce( + &ChromeContentBrowserClient::SafeBrowsingWebApiHandshakeChecked, + weak_factory_.GetWeakPtr(), std::move(checker), std::move(callback))); +#else + std::move(callback).Run(absl::nullopt); +#endif +} + +void ChromeContentBrowserClient::SafeBrowsingWebApiHandshakeChecked( + std::unique_ptr<safe_browsing::WebApiHandshakeChecker> checker, + WillCreateWebTransportCallback callback, + safe_browsing::WebApiHandshakeChecker::CheckResult result) { + if (result == safe_browsing::WebApiHandshakeChecker::CheckResult::kProceed) { + std::move(callback).Run(absl::nullopt); + } else { + std::move(callback).Run(network::mojom::WebTransportError::New( + net::ERR_ABORTED, quic::QUIC_INTERNAL_ERROR, + "SafeBrowsing check failed", false)); + } +} + bool ChromeContentBrowserClient::WillCreateRestrictedCookieManager( network::mojom::RestrictedCookieManagerRole role, content::BrowserContext* browser_context,
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h index 0413cd7a..dc56756c 100644 --- a/chrome/browser/chrome_content_browser_client.h +++ b/chrome/browser/chrome_content_browser_client.h
@@ -23,6 +23,7 @@ #include "build/build_config.h" #include "build/chromeos_buildflags.h" #include "chrome/browser/startup_data.h" +#include "components/safe_browsing/content/browser/web_api_handshake_checker.h" #include "content/public/browser/child_process_security_policy.h" #include "content/public/browser/content_browser_client.h" #include "content/public/browser/web_contents.h" @@ -519,6 +520,10 @@ const absl::optional<std::string>& user_agent, mojo::PendingRemote<network::mojom::WebSocketHandshakeClient> handshake_client) override; + void WillCreateWebTransport(content::RenderFrameHost* frame, + const GURL& url, + WillCreateWebTransportCallback callback) override; + bool WillCreateRestrictedCookieManager( network::mojom::RestrictedCookieManagerRole role, content::BrowserContext* browser_context, @@ -793,6 +798,11 @@ bool is_enterprise_lookup_enabled, bool is_consumer_lookup_enabled); + void SafeBrowsingWebApiHandshakeChecked( + std::unique_ptr<safe_browsing::WebApiHandshakeChecker> checker, + WillCreateWebTransportCallback callback, + safe_browsing::WebApiHandshakeChecker::CheckResult result); + #if !defined(OS_ANDROID) void OnKeepaliveTimerFired( std::unique_ptr<ScopedKeepAlive> keep_alive_handle);
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index 9eff32e6..ae8d3f98 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -2205,8 +2205,6 @@ "extensions/install_limiter.h", "extensions/install_limiter_factory.cc", "extensions/install_limiter_factory.h", - "extensions/launcher_search_provider.cc", - "extensions/launcher_search_provider.h", "extensions/media_player_event_router.cc", "extensions/media_player_event_router.h", "extensions/permissions_updater_delegate_chromeos.cc",
diff --git a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_apitest.cc b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_apitest.cc index af0a8f2..50fa8be 100644 --- a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_apitest.cc +++ b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_apitest.cc
@@ -10,6 +10,7 @@ #include "ash/public/cpp/test/shell_test_api.h" #include "base/macros.h" #include "base/test/bind.h" +#include "base/test/scoped_feature_list.h" #include "build/build_config.h" #include "chrome/browser/ash/arc/arc_util.h" #include "chrome/browser/ash/arc/session/arc_session_manager.h" @@ -27,6 +28,7 @@ #include "components/arc/session/connection_holder.h" #include "components/arc/test/connection_holder_util.h" #include "components/arc/test/fake_app_instance.h" +#include "components/feature_engagement/public/feature_constants.h" #include "components/policy/core/browser/browser_policy_connector.h" #include "components/policy/core/common/mock_configuration_policy_provider.h" #include "components/policy/core/common/policy_map.h" @@ -56,6 +58,17 @@ // due to app pin syncing code. Sync isn't relevant to this test, so skip // pinned app sync. https://crbug.com/1085597 SkipPinnedAppsFromSyncForTest(); + + // Switching to tablet mode can cause in-product help (IPH) to show. The IPH + // bubble can affect window activation when a browser window closes: if + // browser A has the IPH bubble, and browser B is active, closing browser B + // will lead to the IPH bubble being activated instead of browser A. This + // affects some tests that expect browser A to be active. + // + // Disable the IPH to avoid this issue. TODO(crbug.com/1209011): fix the + // issue more generally and remove this feature override. + scoped_feature_list_.InitAndDisableFeature( + feature_engagement::kIPHWebUITabStripFeature); } ~AutotestPrivateApiTest() override = default; @@ -81,6 +94,8 @@ ash::ScopedTestingCrosSettings scoped_testing_cros_settings_; private: + base::test::ScopedFeatureList scoped_feature_list_; + DISALLOW_COPY_AND_ASSIGN(AutotestPrivateApiTest); };
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_browser_handler_api_test.cc b/chrome/browser/chromeos/extensions/file_manager/file_browser_handler_api_test.cc index 7ff9744..e7484962 100644 --- a/chrome/browser/chromeos/extensions/file_manager/file_browser_handler_api_test.cc +++ b/chrome/browser/chromeos/extensions/file_manager/file_browser_handler_api_test.cc
@@ -181,10 +181,9 @@ // Creates new, test mount point. void AddTmpMountPoint(const std::string& extension_id) { - BrowserContext::GetMountPoints(browser()->profile()) - ->RegisterFileSystem("tmp", storage::kFileSystemTypeLocal, - storage::FileSystemMountOption(), - tmp_mount_point_); + browser()->profile()->GetMountPoints()->RegisterFileSystem( + "tmp", storage::kFileSystemTypeLocal, storage::FileSystemMountOption(), + tmp_mount_point_); } base::FilePath GetFullPathOnTmpMountPoint(
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc b/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc index 6e79975..58c82c07 100644 --- a/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc +++ b/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc
@@ -158,10 +158,9 @@ kTestFileContent)); } - ASSERT_TRUE( - content::BrowserContext::GetMountPoints(profile)->RegisterFileSystem( - kLocalMountPointName, storage::kFileSystemTypeLocal, - storage::FileSystemMountOption(), root)); + ASSERT_TRUE(profile->GetMountPoints()->RegisterFileSystem( + kLocalMountPointName, storage::kFileSystemTypeLocal, + storage::FileSystemMountOption(), root)); file_manager::VolumeManager::Get(profile)->AddVolumeForTesting( root, file_manager::VOLUME_TYPE_TESTING, chromeos::DEVICE_TYPE_UNKNOWN, false /* read_only */);
diff --git a/chrome/browser/chromeos/extensions/launcher_search_provider.cc b/chrome/browser/chromeos/extensions/launcher_search_provider.cc deleted file mode 100644 index ff9c94a..0000000 --- a/chrome/browser/chromeos/extensions/launcher_search_provider.cc +++ /dev/null
@@ -1,23 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/chromeos/extensions/launcher_search_provider.h" - -#include <memory> -#include <utility> - -#include "chrome/common/extensions/api/launcher_search_provider.h" -#include "content/public/browser/render_frame_host.h" - -namespace extensions { - -LauncherSearchProviderSetSearchResultsFunction:: - ~LauncherSearchProviderSetSearchResultsFunction() {} - -ExtensionFunction::ResponseAction -LauncherSearchProviderSetSearchResultsFunction::Run() { - return RespondNow(NoArguments()); -} - -} // namespace extensions
diff --git a/chrome/browser/chromeos/extensions/launcher_search_provider.h b/chrome/browser/chromeos/extensions/launcher_search_provider.h deleted file mode 100644 index a9713474..0000000 --- a/chrome/browser/chromeos/extensions/launcher_search_provider.h +++ /dev/null
@@ -1,28 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_CHROMEOS_EXTENSIONS_LAUNCHER_SEARCH_PROVIDER_H_ -#define CHROME_BROWSER_CHROMEOS_EXTENSIONS_LAUNCHER_SEARCH_PROVIDER_H_ - -#include "extensions/browser/extension_function.h" - -namespace extensions { - -// Implements chrome.launcherSearchProvider.setSearchResults method. -// TODO(crbug.com/1208731): This is unused but needs to be defined while the -// launcher files extension still exists. It should be removed along with the -// extension. -class LauncherSearchProviderSetSearchResultsFunction - : public ExtensionFunction { - public: - DECLARE_EXTENSION_FUNCTION("launcherSearchProvider.setSearchResults", - LAUNCHERSEARCHPROVIDER_SETSEARCHRESULTS) - protected: - ~LauncherSearchProviderSetSearchResultsFunction() override; - ResponseAction Run() override; -}; - -} // namespace extensions - -#endif // CHROME_BROWSER_CHROMEOS_EXTENSIONS_LAUNCHER_SEARCH_PROVIDER_H_
diff --git a/chrome/browser/chromeos/file_manager/external_filesystem_apitest.cc b/chrome/browser/chromeos/file_manager/external_filesystem_apitest.cc index 6b978f4..62279d6 100644 --- a/chrome/browser/chromeos/file_manager/external_filesystem_apitest.cc +++ b/chrome/browser/chromeos/file_manager/external_filesystem_apitest.cc
@@ -425,10 +425,9 @@ // FileSystemExtensionApiTestBase override. void AddTestMountPoint() override { - EXPECT_TRUE( - content::BrowserContext::GetMountPoints(profile())->RegisterFileSystem( - kLocalMountPointName, storage::kFileSystemTypeLocal, - storage::FileSystemMountOption(), mount_point_dir_)); + EXPECT_TRUE(profile()->GetMountPoints()->RegisterFileSystem( + kLocalMountPointName, storage::kFileSystemTypeLocal, + storage::FileSystemMountOption(), mount_point_dir_)); VolumeManager::Get(profile())->AddVolumeForTesting( mount_point_dir_, VOLUME_TYPE_TESTING, chromeos::DEVICE_TYPE_UNKNOWN, false /* read_only */); @@ -456,10 +455,9 @@ // FileSystemExtensionApiTestBase override. void AddTestMountPoint() override { - EXPECT_TRUE( - content::BrowserContext::GetMountPoints(profile())->RegisterFileSystem( - kRestrictedMountPointName, storage::kFileSystemTypeRestrictedLocal, - storage::FileSystemMountOption(), mount_point_dir_)); + EXPECT_TRUE(profile()->GetMountPoints()->RegisterFileSystem( + kRestrictedMountPointName, storage::kFileSystemTypeRestrictedLocal, + storage::FileSystemMountOption(), mount_point_dir_)); VolumeManager::Get(profile())->AddVolumeForTesting( mount_point_dir_, VOLUME_TYPE_TESTING, chromeos::DEVICE_TYPE_UNKNOWN, true /* read_only */); @@ -663,10 +661,9 @@ // FileSystemExtensionApiTestBase override. void AddTestMountPoint() override { - EXPECT_TRUE( - content::BrowserContext::GetMountPoints(profile())->RegisterFileSystem( - kLocalMountPointName, storage::kFileSystemTypeLocal, - storage::FileSystemMountOption(), local_mount_point_dir_)); + EXPECT_TRUE(profile()->GetMountPoints()->RegisterFileSystem( + kLocalMountPointName, storage::kFileSystemTypeLocal, + storage::FileSystemMountOption(), local_mount_point_dir_)); VolumeManager::Get(profile())->AddVolumeForTesting( local_mount_point_dir_, VOLUME_TYPE_TESTING, chromeos::DEVICE_TYPE_UNKNOWN, false /* read_only */);
diff --git a/chrome/browser/chromeos/full_restore/app_launch_handler.cc b/chrome/browser/chromeos/full_restore/app_launch_handler.cc index bbe88f77..403b62a 100644 --- a/chrome/browser/chromeos/full_restore/app_launch_handler.cc +++ b/chrome/browser/chromeos/full_restore/app_launch_handler.cc
@@ -39,6 +39,8 @@ namespace { constexpr char kRestoredAppLaunchHistogramPrefix[] = "Apps.RestoredAppLaunch"; +constexpr char kArcGhostWindowLaunchHistogramPrefix[] = + "Apps.ArcGhostWindowLaunch"; // Returns apps::AppTypeName used for metrics. apps::AppTypeName GetHistogrameAppType(apps::mojom::AppType app_type) { @@ -198,7 +200,7 @@ return; } - RecordRestoredAppsCount(apps::AppTypeName::kChromeBrowser); + RecordRestoredAppLaunch(apps::AppTypeName::kChromeBrowser); restore_data_->RemoveApp(extension_misc::kChromeAppId); @@ -270,7 +272,7 @@ return; for (const auto& it : launch_list) { - RecordRestoredAppsCount(GetHistogrameAppType(app_type)); + RecordRestoredAppLaunch(GetHistogrameAppType(app_type)); DCHECK(it.second->container.has_value()); DCHECK(it.second->disposition.has_value()); @@ -298,7 +300,7 @@ auto* arc_handler = FullRestoreArcTaskHandler::GetForProfile(profile_); for (const auto& it : launch_list) { - RecordRestoredAppsCount(apps::AppTypeName::kArc); + RecordRestoredAppLaunch(apps::AppTypeName::kArc); DCHECK(it.second->event_flag.has_value()); @@ -317,8 +319,11 @@ #if BUILDFLAG(ENABLE_WAYLAND_SERVER) if (!window_info->bounds.is_null() && arc_handler && arc_handler->window_handler()) { + RecordArcGhostWindowLaunch(/*is_arc_ghost_window=*/true); arc_handler->window_handler()->LaunchArcGhostWindow( app_id, arc_session_id, it.second.get()); + } else { + RecordArcGhostWindowLaunch(/*is_arc_ghost_window=*/false); } #endif @@ -335,11 +340,16 @@ } } -void AppLaunchHandler::RecordRestoredAppsCount( +void AppLaunchHandler::RecordRestoredAppLaunch( apps::AppTypeName app_type_name) { base::UmaHistogramEnumeration(kRestoredAppLaunchHistogramPrefix, app_type_name); } +void AppLaunchHandler::RecordArcGhostWindowLaunch(bool is_arc_ghost_window) { + base::UmaHistogramBoolean(kArcGhostWindowLaunchHistogramPrefix, + is_arc_ghost_window); +} + } // namespace full_restore } // namespace chromeos
diff --git a/chrome/browser/chromeos/full_restore/app_launch_handler.h b/chrome/browser/chromeos/full_restore/app_launch_handler.h index 5a5b64f..d0e41d9 100644 --- a/chrome/browser/chromeos/full_restore/app_launch_handler.h +++ b/chrome/browser/chromeos/full_restore/app_launch_handler.h
@@ -77,7 +77,8 @@ void LaunchArcApp(const std::string& app_id, const ::full_restore::RestoreData::LaunchList& launch_list); - void RecordRestoredAppsCount(apps::AppTypeName app_type_name); + void RecordRestoredAppLaunch(apps::AppTypeName app_type_name); + void RecordArcGhostWindowLaunch(bool is_arc_ghost_window); Profile* profile_ = nullptr;
diff --git a/chrome/browser/chromeos/full_restore/app_launch_handler_browsertest.cc b/chrome/browser/chromeos/full_restore/app_launch_handler_browsertest.cc index 3164c5d..4695439a 100644 --- a/chrome/browser/chromeos/full_restore/app_launch_handler_browsertest.cc +++ b/chrome/browser/chromeos/full_restore/app_launch_handler_browsertest.cc
@@ -10,6 +10,7 @@ #include "ash/public/cpp/ash_features.h" #include "ash/public/cpp/autotest_desks_api.h" +#include "ash/public/cpp/shell_window_ids.h" #include "ash/public/cpp/split_view_test_api.h" #include "ash/public/cpp/tablet_mode.h" #include "ash/shell.h" @@ -240,6 +241,13 @@ views::Widget* widget = new views::Widget(); widget->Init(std::move(params)); + + // Make the window resizeable. + widget->GetNativeWindow()->SetProperty( + aura::client::kResizeBehaviorKey, + aura::client::kResizeBehaviorCanResize | + aura::client::kResizeBehaviorCanMaximize); + exo::SetShellApplicationId(widget->GetNativeWindow(), window_app_id); widget->Show(); widget->Activate(); @@ -1021,12 +1029,24 @@ int32_t session_id2 = ::full_restore::kArcSessionIdOffsetForRestoredLaunching + 1; + // Create some desks so we can test that the exo window is placed in the + // correct desk container after the task is created. + ash::AutotestDesksApi().CreateNewDesk(); + ash::AutotestDesksApi().CreateNewDesk(); + ash::AutotestDesksApi().CreateNewDesk(); + // Create the window to simulate the restoration for the app. The task id // needs to match the |window_app_id| arg of CreateExoWindow. int32_t kTaskId2 = 200; widget = CreateExoWindow("org.chromium.arc.200"); window = widget->GetNativeWindow(); + // The task is not ready, so the window is currently in a hidden container. + EXPECT_EQ( + ash::Shell::GetContainer(window->GetRootWindow(), + ash::kShellWindowId_UnparentedControlContainer), + window->parent()); + VerifyObserver(window, /*launch_count=*/0, /*init_count=*/1); VerifyWindowProperty(window, kTaskId2, ::full_restore::kParentToHiddenContainer, @@ -1035,6 +1055,12 @@ // Simulate creating the task for the restored window. CreateTask(app_id, kTaskId2, session_id2); + // Tests that after the task is created, the window is placed in the container + // associated with `kDeskId` (2), which is desk C. + EXPECT_EQ(ash::Shell::GetContainer(window->GetRootWindow(), + ash::kShellWindowId_DeskContainerC), + window->parent()); + VerifyObserver(window, /*launch_count=*/1, /*init_count=*/1); VerifyWindowProperty(window, kTaskId2, kTaskId1, /*hidden=*/false); VerifyWindowInfo(window, kActivationIndex); @@ -1048,6 +1074,8 @@ ::full_restore::FullRestoreInfo::GetInstance()->RemoveObserver( test_full_restore_info_observer()); StopInstance(); + + RemoveInactiveDesks(); } // Test restoration with multiple ARC apps, when the ARC windows are created
diff --git a/chrome/browser/chromeos/launcher_search_provider/launcher_search_provider_service.cc b/chrome/browser/chromeos/launcher_search_provider/launcher_search_provider_service.cc deleted file mode 100644 index db212089..0000000 --- a/chrome/browser/chromeos/launcher_search_provider/launcher_search_provider_service.cc +++ /dev/null
@@ -1,196 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/chromeos/launcher_search_provider/launcher_search_provider_service.h" - -#include <stdint.h> - -#include <memory> -#include <utility> - -#include "base/containers/contains.h" -#include "base/numerics/ranges.h" -#include "base/strings/utf_string_conversions.h" -#include "chrome/browser/chromeos/launcher_search_provider/launcher_search_provider_service_factory.h" -#include "chrome/browser/ui/app_list/search/launcher_search/launcher_search_provider.h" -#include "chrome/browser/ui/app_list/search/launcher_search/launcher_search_result.h" -#include "chromeos/components/string_matching/tokenized_string.h" -#include "chromeos/components/string_matching/tokenized_string_match.h" -#include "extensions/browser/extension_registry.h" -#include "extensions/common/extension_set.h" -#include "extensions/common/permissions/permissions_data.h" - -namespace api_launcher_search_provider = - extensions::api::launcher_search_provider; -using chromeos::string_matching::TokenizedString; -using chromeos::string_matching::TokenizedStringMatch; -using extensions::ExtensionId; -using extensions::ExtensionSet; - -namespace chromeos { -namespace launcher_search_provider { - -Service::Service(Profile* profile, - extensions::ExtensionRegistry* extension_registry) - : profile_(profile), extension_registry_(extension_registry) { - extension_registry_->AddObserver(this); -} - -Service::~Service() { - extension_registry_->RemoveObserver(this); -} - -// static -Service* Service::Get(content::BrowserContext* context) { - return ServiceFactory::Get(context); -} - -void Service::OnQueryStarted(app_list::LauncherSearchProvider* provider, - const std::string& query, - const int max_result) { - DCHECK(!is_query_running_); - query_ = query; - is_query_running_ = true; - provider_ = provider; - - ++query_id_; - - extensions::EventRouter* event_router = - extensions::EventRouter::Get(profile_); - - CacheListenerExtensionIds(); - for (const ExtensionId& extension_id : - *cached_listener_extension_ids_.get()) { - // Convert query_id_ to string here since queryId is defined as string in - // javascript side API while we use uint32_t internally to generate it. - event_router->DispatchEventToExtension( - extension_id, - std::make_unique<extensions::Event>( - extensions::events::LAUNCHER_SEARCH_PROVIDER_ON_QUERY_STARTED, - api_launcher_search_provider::OnQueryStarted::kEventName, - api_launcher_search_provider::OnQueryStarted::Create( - query_id_, query, max_result))); - } -} - -void Service::OnQueryEnded() { - DCHECK(is_query_running_); - provider_ = nullptr; - - extensions::EventRouter* event_router = - extensions::EventRouter::Get(profile_); - - CacheListenerExtensionIds(); - for (const ExtensionId& extension_id : - *cached_listener_extension_ids_.get()) { - event_router->DispatchEventToExtension( - extension_id, - std::make_unique<extensions::Event>( - extensions::events::LAUNCHER_SEARCH_PROVIDER_ON_QUERY_ENDED, - api_launcher_search_provider::OnQueryEnded::kEventName, - api_launcher_search_provider::OnQueryEnded::Create(query_id_))); - } - - is_query_running_ = false; -} - -void Service::OnOpenResult(const ExtensionId& extension_id, - const std::string& item_id) { - CacheListenerExtensionIds(); - CHECK(base::Contains(*cached_listener_extension_ids_.get(), extension_id)); - - extensions::EventRouter* event_router = - extensions::EventRouter::Get(profile_); - event_router->DispatchEventToExtension( - extension_id, - std::make_unique<extensions::Event>( - extensions::events::LAUNCHER_SEARCH_PROVIDER_ON_OPEN_RESULT, - api_launcher_search_provider::OnOpenResult::kEventName, - api_launcher_search_provider::OnOpenResult::Create(item_id))); -} - -void Service::SetSearchResults( - const extensions::Extension* extension, - std::unique_ptr<ErrorReporter> error_reporter, - const int query_id, - const std::vector<extensions::api::launcher_search_provider::SearchResult>& - results) { - // If query is not running or query_id is different from current query id, - // discard the results. - if (!is_query_running_ || query_id != query_id_) - return; - - // If |extension| is not in the listener extensions list, ignore it. - CacheListenerExtensionIds(); - if (!base::Contains(*cached_listener_extension_ids_.get(), extension->id())) { - return; - } - - // Set search results to provider. - DCHECK(provider_); - std::vector<std::unique_ptr<app_list::LauncherSearchResult>> search_results; - for (const auto& result : results) { - const int relevance = - base::ClampToRange(result.relevance, 0, kMaxSearchResultScore); - - const std::string icon_type = - result.icon_type ? *result.icon_type.get() : std::string(); - - // Calculate the relevance score by matching the query with the title. - // Results with a match score of 0 are discarded. This will also be used to - // set the title tags (highlighting which parts of the title matched the - // search query). - const std::u16string title = base::UTF8ToUTF16(result.title); - TokenizedString tokenized_title(title); - TokenizedStringMatch match; - TokenizedString tokenized_query(base::UTF8ToUTF16(query_)); - if (!match.Calculate(tokenized_query, tokenized_title)) - continue; - - auto search_result = std::make_unique<app_list::LauncherSearchResult>( - result.item_id, icon_type, relevance, profile_, extension, - error_reporter->Duplicate()); - search_result->UpdateFromMatch(tokenized_title, match); - search_results.push_back(std::move(search_result)); - } - provider_->SetSearchResults(extension->id(), std::move(search_results)); -} - -bool Service::IsQueryRunning() const { - return is_query_running_; -} - -void Service::OnExtensionLoaded(content::BrowserContext* browser_context, - const extensions::Extension* extension) { - // Invalidate cache. - cached_listener_extension_ids_.reset(); -} - -void Service::OnExtensionUnloaded(content::BrowserContext* browser_context, - const extensions::Extension* extension, - extensions::UnloadedExtensionReason reason) { - // Invalidate cache. - cached_listener_extension_ids_.reset(); -} - -void Service::CacheListenerExtensionIds() { - // If it's already cached, do nothing. - if (cached_listener_extension_ids_) - return; - - cached_listener_extension_ids_ = std::make_unique<std::set<ExtensionId>>(); - - const ExtensionSet& extension_set = extension_registry_->enabled_extensions(); - for (scoped_refptr<const extensions::Extension> extension : extension_set) { - const extensions::PermissionsData* permission_data = - extension->permissions_data(); - const bool has_permission = permission_data->HasAPIPermission( - extensions::mojom::APIPermissionID::kLauncherSearchProvider); - if (has_permission) - cached_listener_extension_ids_->insert(extension->id()); - } -} - -} // namespace launcher_search_provider -} // namespace chromeos
diff --git a/chrome/browser/continuous_search/BUILD.gn b/chrome/browser/continuous_search/BUILD.gn index 6c5d2604..177e9ee 100644 --- a/chrome/browser/continuous_search/BUILD.gn +++ b/chrome/browser/continuous_search/BUILD.gn
@@ -120,8 +120,13 @@ testonly = true sources = [ + "android/junit/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchContainerCoordinatorTest.java", "android/junit/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchContainerMediatorTest.java", + "android/junit/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchContainerViewBinderTest.java", "android/junit/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchListMediatorTest.java", + "android/junit/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchListViewBinderTest.java", + "android/junit/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchSceneLayerTest.java", + "android/junit/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchTabHelperJUnitTest.java", ] deps = [ @@ -132,12 +137,17 @@ "//base:base_junit_test_support", "//chrome/browser/browser_controls/android:java", "//chrome/browser/continuous_search/internal:java", + "//chrome/browser/flags:java", "//chrome/browser/tab:java", "//chrome/browser/ui/android/layouts:java", "//chrome/browser/ui/android/theme:java", + "//chrome/test/android:chrome_java_test_support", + "//components/embedder_support/android:util_java", "//content/public/android:content_java", "//third_party/android_deps:robolectric_all_java", + "//third_party/androidx:androidx_recyclerview_recyclerview_java", "//third_party/androidx:androidx_test_core_java", + "//third_party/hamcrest:hamcrest_library_java", "//third_party/junit", "//third_party/mockito:mockito_java", "//ui/android:ui_no_recycler_view_java",
diff --git a/chrome/browser/continuous_search/android/java/src/org/chromium/chrome/browser/continuous_search/ContinuousNavigationMetadata.java b/chrome/browser/continuous_search/android/java/src/org/chromium/chrome/browser/continuous_search/ContinuousNavigationMetadata.java index a983cb89..117e5bf 100644 --- a/chrome/browser/continuous_search/android/java/src/org/chromium/chrome/browser/continuous_search/ContinuousNavigationMetadata.java +++ b/chrome/browser/continuous_search/android/java/src/org/chromium/chrome/browser/continuous_search/ContinuousNavigationMetadata.java
@@ -63,8 +63,9 @@ if (!(o instanceof ContinuousNavigationMetadata)) return false; ContinuousNavigationMetadata other = (ContinuousNavigationMetadata) o; - return mRootUrl.equals(other.mRootUrl) && mQuery.equals(other.mQuery) - && mCategory == other.mCategory && mGroups.equals(other.mGroups); + + return mRootUrl.equals(other.getRootUrl()) && mQuery.equals(other.getQuery()) + && mCategory == other.getCategory() && mGroups.equals(other.getGroups()); } @Override
diff --git a/chrome/browser/continuous_search/android/java/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchContainerCoordinator.java b/chrome/browser/continuous_search/android/java/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchContainerCoordinator.java index 3ea35d2..81327ab 100644 --- a/chrome/browser/continuous_search/android/java/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchContainerCoordinator.java +++ b/chrome/browser/continuous_search/android/java/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchContainerCoordinator.java
@@ -8,6 +8,8 @@ import android.view.View; import android.view.ViewStub; +import androidx.annotation.VisibleForTesting; + import org.chromium.base.Callback; import org.chromium.base.supplier.ObservableSupplier; import org.chromium.base.supplier.Supplier; @@ -141,4 +143,9 @@ mContainerMediator.destroy(); mListCoordinator.destroy(); } + + @VisibleForTesting + ContinuousSearchViewResourceFrameLayout getRootViewForTesting() { + return mRootView; + } }
diff --git a/chrome/browser/continuous_search/android/java/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchTabHelper.java b/chrome/browser/continuous_search/android/java/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchTabHelper.java index 4752ff3..c06f1a8 100644 --- a/chrome/browser/continuous_search/android/java/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchTabHelper.java +++ b/chrome/browser/continuous_search/android/java/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchTabHelper.java
@@ -19,9 +19,11 @@ * @param tab to enable continuous search support for. */ public static void createForTab(Tab tab) { - if (!FeatureList.isNativeInitialized()) return; + if (!FeatureList.isInitialized()) return; - if (!tab.isIncognito()) new BackNavigationTabObserver(tab); + if (tab.isIncognito()) return; + + new BackNavigationTabObserver(tab); if (!ChromeFeatureList.isEnabled(ChromeFeatureList.CONTINUOUS_SEARCH)) return;
diff --git a/chrome/browser/continuous_search/android/java/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchViewResourceFrameLayout.java b/chrome/browser/continuous_search/android/java/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchViewResourceFrameLayout.java index 06264c1..60eadb2 100644 --- a/chrome/browser/continuous_search/android/java/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchViewResourceFrameLayout.java +++ b/chrome/browser/continuous_search/android/java/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchViewResourceFrameLayout.java
@@ -57,4 +57,4 @@ public int getShadowHeight() { return mShadowHeightPx; } -} \ No newline at end of file +}
diff --git a/chrome/browser/continuous_search/android/java/src/org/chromium/chrome/browser/continuous_search/PageGroup.java b/chrome/browser/continuous_search/android/java/src/org/chromium/chrome/browser/continuous_search/PageGroup.java index 3eee2264..fb2f779cf 100644 --- a/chrome/browser/continuous_search/android/java/src/org/chromium/chrome/browser/continuous_search/PageGroup.java +++ b/chrome/browser/continuous_search/android/java/src/org/chromium/chrome/browser/continuous_search/PageGroup.java
@@ -41,8 +41,8 @@ PageGroup other = (PageGroup) o; - return mLabel.equals(other.mLabel) && mIsAdGroup == other.mIsAdGroup - && mPageItems.equals(other.mPageItems); + return mLabel.equals(other.getLabel()) && mIsAdGroup == other.isAdGroup() + && mPageItems.equals(other.getPageItems()); } @Override
diff --git a/chrome/browser/continuous_search/android/java/src/org/chromium/chrome/browser/continuous_search/PageItem.java b/chrome/browser/continuous_search/android/java/src/org/chromium/chrome/browser/continuous_search/PageItem.java index fd4e37f..3fb32f7 100644 --- a/chrome/browser/continuous_search/android/java/src/org/chromium/chrome/browser/continuous_search/PageItem.java +++ b/chrome/browser/continuous_search/android/java/src/org/chromium/chrome/browser/continuous_search/PageItem.java
@@ -42,7 +42,7 @@ PageItem other = (PageItem) o; - return mUrl.equals(other.mUrl) && mTitle.equals(other.mTitle); + return mUrl.equals(other.getUrl()) && mTitle.equals(other.getTitle()); } @Override
diff --git a/chrome/browser/continuous_search/android/junit/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchContainerCoordinatorTest.java b/chrome/browser/continuous_search/android/junit/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchContainerCoordinatorTest.java new file mode 100644 index 0000000..668d4c8 --- /dev/null +++ b/chrome/browser/continuous_search/android/junit/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchContainerCoordinatorTest.java
@@ -0,0 +1,265 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.continuous_search; + +import static org.hamcrest.Matchers.lessThan; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.Rect; +import android.view.View; +import android.view.ViewStub; +import android.widget.LinearLayout; + +import androidx.recyclerview.widget.RecyclerView; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InOrder; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.mockito.quality.Strictness; + +import org.chromium.base.ContextUtils; +import org.chromium.base.UserDataHost; +import org.chromium.base.supplier.ObservableSupplierImpl; +import org.chromium.base.supplier.Supplier; +import org.chromium.base.test.BaseRobolectricTestRunner; +import org.chromium.base.test.util.JniMocker; +import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider; +import org.chromium.chrome.browser.layouts.LayoutManager; +import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.browser.theme.ThemeColorProvider; +import org.chromium.components.embedder_support.util.UrlUtilities; +import org.chromium.components.embedder_support.util.UrlUtilitiesJni; +import org.chromium.ui.resources.ResourceManager; +import org.chromium.ui.resources.dynamics.DynamicResourceLoader; +import org.chromium.ui.resources.dynamics.ViewResourceAdapter; +import org.chromium.url.GURL; +import org.chromium.url.JUnitTestGURLs; + +import java.util.ArrayList; +import java.util.List; + +/** + * Test of {@link ContinuousSearchContainerCoordinator}. + */ +@RunWith(BaseRobolectricTestRunner.class) +public class ContinuousSearchContainerCoordinatorTest { + private static final String TEST_QUERY = "Foo"; + private static final int TEST_RESULT_TYPE = 1; + private static final long FAKE_NATIVE_ADDR = 123456L; + private static final int STUB_ID = 123; + private static final int INFLATED_ID = 456; + + @Mock + private Tab mTabMock; + @Mock + private LayoutManager mLayoutManagerMock; + @Mock + private ResourceManager mResourceManagerMock; + @Mock + private DynamicResourceLoader mResourceLoaderMock; + @Mock + private BrowserControlsStateProvider mStateProviderMock; + @Mock + private ThemeColorProvider mThemeColorProviderMock; + @Mock + private Resources mResources; + @Mock + private SearchUrlHelper.Natives mSearchUrlHelperJniMock; + @Mock + private ContinuousSearchSceneLayer.Natives mContinuousSearchSceneLayerJniMock; + @Mock + private UrlUtilities.Natives mUrlUtilitiesJniMock; + + private ObservableSupplierImpl<Tab> mTabSupplier = new ObservableSupplierImpl<Tab>(); + + private Supplier<Boolean> mAnimateNativeControls; + private boolean mAnimateNativeControlsValue; + + private Supplier<Integer> mDefaultTopHeight; + private int mDefaultTopHeightValue; + + private boolean mAnimateHidingState; + private int mAnimateHidingStateCount; + private GURL mSrpUrl; + private UserDataHost mUserDataHost = new UserDataHost(); + private ContinuousSearchContainerCoordinator mCoordinator; + private ContinuousNavigationUserDataImpl mUserData; + private LinearLayout mRoot; + + @Rule + public JniMocker mJniMocker = new JniMocker(); + @Rule + public MockitoRule mMockitoRule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS); + + @Before + public void setUp() { + mSrpUrl = JUnitTestGURLs.getGURL(JUnitTestGURLs.SEARCH_URL); + mJniMocker.mock(SearchUrlHelperJni.TEST_HOOKS, mSearchUrlHelperJniMock); + mJniMocker.mock( + ContinuousSearchSceneLayerJni.TEST_HOOKS, mContinuousSearchSceneLayerJniMock); + mJniMocker.mock(UrlUtilitiesJni.TEST_HOOKS, mUrlUtilitiesJniMock); + doReturn(TEST_QUERY).when(mSearchUrlHelperJniMock).getQueryIfValidSrpUrl(eq(mSrpUrl)); + doReturn(TEST_RESULT_TYPE) + .when(mSearchUrlHelperJniMock) + .getSrpPageCategoryFromUrl(eq(mSrpUrl)); + doReturn(FAKE_NATIVE_ADDR).when(mContinuousSearchSceneLayerJniMock).init(any()); + doReturn(mResourceLoaderMock).when(mResourceManagerMock).getDynamicResourceLoader(); + + mRoot = new LinearLayout(ContextUtils.getApplicationContext()); + mRoot.setLayoutParams(new LinearLayout.LayoutParams(100, 100)); + mRoot.setOrientation(LinearLayout.VERTICAL); + ViewStub viewStub = new ViewStub(ContextUtils.getApplicationContext()); + viewStub.setId(STUB_ID); + viewStub.setInflatedId(INFLATED_ID); + viewStub.setLayoutResource( + org.chromium.chrome.browser.continuous_search.R.layout.continuous_search_container); + mRoot.addView(viewStub); + mAnimateNativeControls = () -> { + return mAnimateNativeControlsValue; + }; + mDefaultTopHeight = () -> { + return mDefaultTopHeightValue; + }; + + doReturn(mUserDataHost).when(mTabMock).getUserDataHost(); + mUserData = ContinuousNavigationUserDataImpl.getOrCreateForTab(mTabMock); + mUserData.mAllowNativeUrlChecks = false; + mCoordinator = new ContinuousSearchContainerCoordinator(viewStub, mLayoutManagerMock, + mResourceManagerMock, mTabSupplier, mStateProviderMock, mAnimateNativeControls, + mDefaultTopHeight, mThemeColorProviderMock, mResources, (state) -> { + mAnimateHidingState = state; + mAnimateHidingStateCount++; + }); + + Assert.assertEquals(ContinuousSearchSceneLayer.class, + ContinuousSearchContainerCoordinator.getSceneOverlayClass()); + } + + @After + public void tearDown() { + mCoordinator.destroy(); + } + + @Test + public void testShowAndDismiss() { + Assert.assertNotNull(mRoot.findViewById(STUB_ID)); + Assert.assertNull(mRoot.findViewById(INFLATED_ID)); + + // Create data. + GURL resultUrl = JUnitTestGURLs.getGURL(JUnitTestGURLs.RED_1); + List<PageGroup> groups = new ArrayList<PageGroup>(); + List<PageItem> results1 = new ArrayList<PageItem>(); + results1.add(new PageItem(resultUrl, "Red 1")); + groups.add(new PageGroup("Red Group", false, results1)); + ContinuousNavigationMetadata metadata = + new ContinuousNavigationMetadata(mSrpUrl, TEST_QUERY, TEST_RESULT_TYPE, groups); + + mTabSupplier.set(mTabMock); + mUserData.updateData(metadata, mSrpUrl); + mUserData.updateCurrentUrl(resultUrl); + ContinuousSearchViewResourceFrameLayout rootView = mCoordinator.getRootViewForTesting(); + Assert.assertNotNull(rootView); + rootView.layout(0, 0, 100, 100); + View view = mock(View.class); + when(view.getHeight()) + .thenReturn(40 + mCoordinator.getRootViewForTesting().getShadowHeight()); + mRoot.findViewById(INFLATED_ID).layout(0, 0, 100, 100); + mCoordinator.onLayoutChange(view, 0, 0, 0, 0, 0, 0, 0, 0); + + when(mUrlUtilitiesJniMock.getDomainAndRegistry(any(), anyBoolean())) + .thenAnswer((invocation) -> { return (String) invocation.getArguments()[0]; }); + RecyclerView recyclerView = rootView.findViewById(R.id.recycler_view); + Assert.assertNotNull(recyclerView); + recyclerView.layout(0, 0, 100, 100); + + // View should now be inflated. + Assert.assertNull(mRoot.findViewById(STUB_ID)); + Assert.assertNotNull(mRoot.findViewById(INFLATED_ID)); + // UI is still in flux so just assert that the items exist. + Assert.assertEquals(2, recyclerView.getAdapter().getItemCount()); + + // Invalidate. + mUserData.invalidateData(); + Assert.assertEquals(0, recyclerView.getAdapter().getItemCount()); + } + + @Test + public void testObserveHeightChanges() { + ContinuousSearchContainerCoordinator.HeightObserver observer = + mock(ContinuousSearchContainerCoordinator.HeightObserver.class); + InOrder inOrder = inOrder(observer); + mCoordinator.addHeightObserver(observer); + mTabSupplier.set(mTabMock); + + GURL resultUrl = JUnitTestGURLs.getGURL(JUnitTestGURLs.RED_1); + List<PageGroup> groups = new ArrayList<PageGroup>(); + List<PageItem> results1 = new ArrayList<PageItem>(); + results1.add(new PageItem(resultUrl, "Red 1")); + groups.add(new PageGroup("Red Group", false, results1)); + ContinuousNavigationMetadata metadata = + new ContinuousNavigationMetadata(mSrpUrl, TEST_QUERY, TEST_RESULT_TYPE, groups); + + mUserData.updateData(metadata, mSrpUrl); + mUserData.updateCurrentUrl(resultUrl); + View view = mock(View.class); + when(view.getHeight()) + .thenReturn(5 + mCoordinator.getRootViewForTesting().getShadowHeight()); + mCoordinator.onLayoutChange(view, 0, 0, 0, 0, 0, 0, 0, 0); + inOrder.verify(observer).onHeightChange(5, false); + mCoordinator.removeHeightObserver(observer); + + inOrder.verifyNoMoreInteractions(); + } + + /** + * Verifies that {@link ContinuousSearchViewResourceFrameLayout} captures correctly. + */ + @Test + public void testCapture() { + GURL resultUrl = JUnitTestGURLs.getGURL(JUnitTestGURLs.RED_1); + List<PageGroup> groups = new ArrayList<PageGroup>(); + List<PageItem> results1 = new ArrayList<PageItem>(); + results1.add(new PageItem(resultUrl, "Red 1")); + groups.add(new PageGroup("Red Group", false, results1)); + ContinuousNavigationMetadata metadata = + new ContinuousNavigationMetadata(mSrpUrl, TEST_QUERY, TEST_RESULT_TYPE, groups); + + mTabSupplier.set(mTabMock); + mUserData.updateData(metadata, mSrpUrl); + mUserData.updateCurrentUrl(resultUrl); + View view = mock(View.class); + ContinuousSearchViewResourceFrameLayout rootView = mCoordinator.getRootViewForTesting(); + when(view.getHeight()).thenReturn(5 + rootView.getShadowHeight()); + mCoordinator.onLayoutChange(view, 0, 0, 0, 0, 0, 0, 0, 0); + + // Force a resize since robolectric view sizes are technically 0x0 by default. + rootView.layout(0, 0, 100, 100); + ViewResourceAdapter adapter = rootView.createResourceAdapter(); + adapter.invalidate(new Rect(0, rootView.getHeight() - rootView.getShadowHeight(), + rootView.getWidth(), rootView.getHeight())); + Bitmap bitmap = adapter.getBitmap(); + + // This isn't intended to be a pixel test so just check that the content was actually + // captured. + Assert.assertNotNull(bitmap); + Assert.assertThat(1, lessThan(bitmap.getHeight())); + Assert.assertThat(1, lessThan(bitmap.getWidth())); + } +}
diff --git a/chrome/browser/continuous_search/android/junit/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchContainerViewBinderTest.java b/chrome/browser/continuous_search/android/junit/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchContainerViewBinderTest.java new file mode 100644 index 0000000..e9f405f6 --- /dev/null +++ b/chrome/browser/continuous_search/android/junit/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchContainerViewBinderTest.java
@@ -0,0 +1,70 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.continuous_search; + +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.mock; + +import android.view.View; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InOrder; + +import org.chromium.base.test.BaseRobolectricTestRunner; +import org.chromium.ui.modelutil.PropertyModel; +import org.chromium.ui.modelutil.PropertyModelChangeProcessor; + +/** + * Test of {@link ContinuousSearchContainerViewBinder}. + */ +@RunWith(BaseRobolectricTestRunner.class) +public class ContinuousSearchContainerViewBinderTest { + private PropertyModel mModel; + + @Before + public void setUp() { + mModel = new PropertyModel(ContinuousSearchContainerProperties.ALL_KEYS); + } + + /** + * Tests that property updates to the Java view work correctly. + */ + @Test + public void testBindJavaView() { + View view = mock(View.class); + InOrder inOrder = inOrder(view); + PropertyModelChangeProcessor.create( + mModel, view, ContinuousSearchContainerViewBinder::bindJavaView); + + final int yValue = 10; + mModel.set(ContinuousSearchContainerProperties.VERTICAL_OFFSET, yValue); + inOrder.verify(view).setY((float) yValue); + + final int visibility = View.VISIBLE; + mModel.set(ContinuousSearchContainerProperties.ANDROID_VIEW_VISIBILITY, visibility); + inOrder.verify(view).setVisibility(visibility); + } + + /** + * Tests that property updates to the composited view work correctly. + */ + @Test + public void testBindCompositedView() { + ContinuousSearchSceneLayer sceneLayer = mock(ContinuousSearchSceneLayer.class); + InOrder inOrder = inOrder(sceneLayer); + + final int yValue = 10; + mModel.set(ContinuousSearchContainerProperties.VERTICAL_OFFSET, yValue); + final boolean visibility = true; + mModel.set(ContinuousSearchContainerProperties.COMPOSITED_VIEW_VISIBLE, visibility); + + ContinuousSearchContainerViewBinder.bindCompositedView( + mModel, sceneLayer, ContinuousSearchContainerProperties.COMPOSITED_VIEW_VISIBLE); + inOrder.verify(sceneLayer).setVerticalOffset(yValue); + inOrder.verify(sceneLayer).setIsVisible(visibility); + } +}
diff --git a/chrome/browser/continuous_search/android/junit/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchListMediatorTest.java b/chrome/browser/continuous_search/android/junit/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchListMediatorTest.java index 20f8369..bdb4393 100644 --- a/chrome/browser/continuous_search/android/junit/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchListMediatorTest.java +++ b/chrome/browser/continuous_search/android/junit/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchListMediatorTest.java
@@ -11,6 +11,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mockito; import org.chromium.base.test.BaseRobolectricTestRunner; @@ -18,6 +19,7 @@ import org.chromium.chrome.browser.continuous_search.ContinuousSearchListProperties.ListItemType; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.theme.ThemeColorProvider; +import org.chromium.content_public.browser.LoadUrlParams; import org.chromium.content_public.browser.NavigationController; import org.chromium.content_public.browser.NavigationEntry; import org.chromium.content_public.browser.WebContents; @@ -58,12 +60,19 @@ ApplicationProvider.getApplicationContext().getResources()); ContinuousNavigationUserDataImpl continuousNavigationUserData = Mockito.mock(ContinuousNavigationUserDataImpl.class); + Mockito.doAnswer((invocation) -> { + mMediator.onInvalidate(); + return null; + }) + .when(continuousNavigationUserData) + .invalidateData(); ContinuousNavigationUserDataImpl.setInstanceForTesting(continuousNavigationUserData); } @After public void tearDown() { ContinuousNavigationUserDataImpl.setInstanceForTesting(null); + mMediator.destroy(); } /** @@ -84,6 +93,7 @@ mLayoutVisibilityFalse.getCallCount()); // UI should hide on invalidate. + mMediator.onScrolled(); mMediator.onInvalidate(); Assert.assertEquals("mLayoutVisibilityTrue should not have been called.", 0, mLayoutVisibilityTrue.getCallCount()); @@ -179,8 +189,11 @@ */ @Test public void testModelList() { + Tab tab = Mockito.mock(Tab.class); + mMediator.onResult(tab); // Mock 3 SearchResultGroups, with 1, 2 and 3 SearchResults. The first group is an ad group. - PageItem pageItem11 = new PageItem(Mockito.mock(GURL.class), "result 11"); + GURL url11 = JUnitTestGURLs.getGURL(JUnitTestGURLs.RED_1); + PageItem pageItem11 = new PageItem(url11, "result 11"); PageItem pageItem21 = new PageItem(Mockito.mock(GURL.class), "result 21"); PageItem pageItem22 = new PageItem(Mockito.mock(GURL.class), "result 22"); PageItem pageItem31 = new PageItem(Mockito.mock(GURL.class), "result 31"); @@ -217,6 +230,72 @@ assertListItemEqualsSearchResult(mModelList.get(4), pageItem31, false); assertListItemEqualsSearchResult(mModelList.get(5), pageItem32, false); assertListItemEqualsSearchResult(mModelList.get(6), pageItem33, false); + + mModelList.get(1).model.get(ContinuousSearchListProperties.CLICK_LISTENER).onClick(null); + ArgumentCaptor<LoadUrlParams> params = ArgumentCaptor.forClass(LoadUrlParams.class); + Mockito.verify(tab, Mockito.times(1)).loadUrl(params.capture()); + Assert.assertEquals(url11.getSpec(), params.getValue().getUrl()); + } + + /** + * Tests that the data is invalidated on user dismissal. + */ + @Test + public void testUserInvalidate() { + mMediator.onResult(Mockito.mock(Tab.class)); + PageItem pageItem = new PageItem(Mockito.mock(GURL.class), "result"); + PageGroup pageGroup = new PageGroup("group", true, Arrays.asList(pageItem)); + ContinuousNavigationMetadata continuousNavigationMetadata = + new ContinuousNavigationMetadata( + Mockito.mock(GURL.class), "query", 1, Arrays.asList(pageGroup)); + mMediator.onUpdate(continuousNavigationMetadata); + Assert.assertEquals("ModelList length is incorrect.", 2, mModelList.size()); + + mRootViewModel.get(ContinuousSearchListProperties.DISMISS_CLICK_CALLBACK).onClick(null); + Assert.assertEquals("ModelList length is incorrect.", 0, mModelList.size()); + } + + /** + * Tests that the data is invalidated if a new tab is observed. + */ + @Test + public void testObserveNewTab() { + PageItem pageItem = new PageItem(Mockito.mock(GURL.class), "result"); + PageGroup pageGroup = new PageGroup("group", true, Arrays.asList(pageItem)); + ContinuousNavigationMetadata continuousNavigationMetadata = + new ContinuousNavigationMetadata( + Mockito.mock(GURL.class), "query", 1, Arrays.asList(pageGroup)); + mMediator.onUpdate(continuousNavigationMetadata); + Assert.assertEquals("ModelList length is incorrect.", 2, mModelList.size()); + + mMediator.onResult(null); + Assert.assertEquals("ModelList length is incorrect.", 0, mModelList.size()); + } + + /** + * Tests that theme color is updated correctly. + */ + @Test + public void testThemeColorChanged() { + PageItem pageItem = new PageItem(Mockito.mock(GURL.class), "result"); + PageGroup pageGroup = new PageGroup("group", true, Arrays.asList(pageItem)); + ContinuousNavigationMetadata continuousNavigationMetadata = + new ContinuousNavigationMetadata( + Mockito.mock(GURL.class), "query", 1, Arrays.asList(pageGroup)); + mMediator.onUpdate(continuousNavigationMetadata); + Assert.assertEquals("ModelList length is incorrect.", 2, mModelList.size()); + + // Use a dark color. + int color = 0xFFFFFF; + mMediator.onThemeColorChanged(color, false); + Assert.assertEquals("Background color incorrect.", color, + mRootViewModel.get(ContinuousSearchListProperties.BACKGROUND_COLOR)); + + // Use a light color. + color = 0x000000; + mMediator.onThemeColorChanged(color, false); + Assert.assertEquals("Background color incorrect.", color, + mRootViewModel.get(ContinuousSearchListProperties.BACKGROUND_COLOR)); } private void assertListItemEqualsSearchResult(
diff --git a/chrome/browser/continuous_search/android/junit/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchListViewBinderTest.java b/chrome/browser/continuous_search/android/junit/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchListViewBinderTest.java new file mode 100644 index 0000000..4f7123e --- /dev/null +++ b/chrome/browser/continuous_search/android/junit/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchListViewBinderTest.java
@@ -0,0 +1,114 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.continuous_search; + +import static org.mockito.AdditionalMatchers.gt; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.when; + +import android.graphics.drawable.GradientDrawable; +import android.view.View; +import android.widget.TextView; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InOrder; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.mockito.quality.Strictness; + +import org.chromium.base.test.BaseRobolectricTestRunner; +import org.chromium.base.test.util.JniMocker; +import org.chromium.components.embedder_support.util.UrlUtilities; +import org.chromium.components.embedder_support.util.UrlUtilitiesJni; +import org.chromium.ui.modelutil.PropertyModel; +import org.chromium.ui.modelutil.PropertyModelChangeProcessor; +import org.chromium.url.GURL; +import org.chromium.url.JUnitTestGURLs; + +/** + * Test of {@link ContinuousSearchContainerViewBinder}. + */ +@RunWith(BaseRobolectricTestRunner.class) +public class ContinuousSearchListViewBinderTest { + @Mock + private UrlUtilities.Natives mUrlUtilitiesJniMock; + + private PropertyModel mModel; + + @Rule + public JniMocker mJniMocker = new JniMocker(); + @Rule + public MockitoRule mMockitoRule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS); + + @Before + public void setUp() { + mModel = new PropertyModel(ContinuousSearchListProperties.ITEM_KEYS); + mJniMocker.mock(UrlUtilitiesJni.TEST_HOOKS, mUrlUtilitiesJniMock); + } + + @Test + public void testBindListItem() { + View view = mock(View.class); + TextView textView = mock(TextView.class); + GradientDrawable drawable = mock(GradientDrawable.class); + InOrder inOrder = inOrder(view, textView, drawable); + PropertyModelChangeProcessor.create( + mModel, view, ContinuousSearchListViewBinder::bindListItem); + + doReturn(textView).when(view).findViewById(anyInt()); + + final String label = "Label"; + mModel.set(ContinuousSearchListProperties.LABEL, label); + inOrder.verify(textView).setText(eq(label)); + + GURL url = JUnitTestGURLs.getGURL(JUnitTestGURLs.EXAMPLE_URL); + final String domain = "example.com"; + doReturn(domain) + .when(mUrlUtilitiesJniMock) + .getDomainAndRegistry(eq(url.getSpec()), anyBoolean()); + mModel.set(ContinuousSearchListProperties.URL, url); + inOrder.verify(textView).setText(eq(domain)); + + int color = 0xAABBCC; + mModel.set(ContinuousSearchListProperties.IS_SELECTED, false); + inOrder.verify(view).getBackground(); + mModel.set(ContinuousSearchListProperties.BORDER_COLOR, color); + inOrder.verify(view).getBackground(); + when(view.getBackground()).thenReturn(drawable); + mModel.set(ContinuousSearchListProperties.IS_SELECTED, true); + inOrder.verify(view, times(2)).getBackground(); + inOrder.verify(drawable).mutate(); + inOrder.verify(drawable).setStroke(gt(0), eq(color)); + + View.OnClickListener listener = (v) -> {}; + mModel.set(ContinuousSearchListProperties.CLICK_LISTENER, listener); + inOrder.verify(view).setOnClickListener(eq(listener)); + + color = 0xCCBBAA; + mModel.set(ContinuousSearchListProperties.BACKGROUND_COLOR, color); + inOrder.verify(view, times(2)).getBackground(); + inOrder.verify(drawable).mutate(); + inOrder.verify(drawable).setColor(color); + + int id = 90; + mModel.set(ContinuousSearchListProperties.TITLE_TEXT_STYLE, id); + inOrder.verify(textView).setTextAppearance(any(), eq(id)); + + id = 67; + mModel.set(ContinuousSearchListProperties.DESCRIPTION_TEXT_STYLE, id); + inOrder.verify(textView).setTextAppearance(any(), eq(id)); + } +}
diff --git a/chrome/browser/continuous_search/android/junit/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchSceneLayerTest.java b/chrome/browser/continuous_search/android/junit/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchSceneLayerTest.java new file mode 100644 index 0000000..2e0631b --- /dev/null +++ b/chrome/browser/continuous_search/android/junit/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchSceneLayerTest.java
@@ -0,0 +1,118 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.continuous_search; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InOrder; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.mockito.quality.Strictness; + +import org.chromium.base.test.BaseRobolectricTestRunner; +import org.chromium.base.test.util.JniMocker; +import org.chromium.chrome.browser.layouts.components.VirtualView; +import org.chromium.chrome.browser.layouts.scene_layer.SceneLayer; +import org.chromium.ui.resources.ResourceManager; + +import java.util.ArrayList; +import java.util.List; + +/** + * Test of {@link ContinuousSearchSceneLayer}. + */ +@RunWith(BaseRobolectricTestRunner.class) +public class ContinuousSearchSceneLayerTest { + private static final long FAKE_NATIVE_ADDRESS = 123L; + @Mock + private ResourceManager mResourceManagerMock; + @Mock + private SceneLayer mContentTree; + @Mock + private ContinuousSearchSceneLayer.Natives mContinuousSearchSceneLayerJniMock; + + private ContinuousSearchSceneLayer mSceneLayer; + + @Rule + public JniMocker mJniMocker = new JniMocker(); + @Rule + public MockitoRule mMockitoRule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS); + + @Before + public void setUp() { + mJniMocker.mock( + ContinuousSearchSceneLayerJni.TEST_HOOKS, mContinuousSearchSceneLayerJniMock); + when(mContinuousSearchSceneLayerJniMock.init(any())).thenReturn(FAKE_NATIVE_ADDRESS); + + mSceneLayer = new ContinuousSearchSceneLayer(mResourceManagerMock); + + verify(mContinuousSearchSceneLayerJniMock, times(1)).init(eq(mSceneLayer)); + mSceneLayer.initializeNative(); + } + + /** + * Tests setting visibility. + */ + @Test + public void testVisibility() { + mSceneLayer.setIsVisible(true); + Assert.assertTrue(mSceneLayer.isSceneOverlayTreeShowing()); + + mSceneLayer.setIsVisible(false); + Assert.assertFalse(mSceneLayer.isSceneOverlayTreeShowing()); + } + + /** + * Tests setting and updating native. + */ + @Test + public void testSetAndUpdate() { + InOrder inOrder = inOrder(mContinuousSearchSceneLayerJniMock); + mSceneLayer.setContentTree(mContentTree); + inOrder.verify(mContinuousSearchSceneLayerJniMock) + .setContentTree(eq(FAKE_NATIVE_ADDRESS), eq(mContentTree)); + + final int verticalOffset = 5; + mSceneLayer.setVerticalOffset(verticalOffset); + final int resourceId = 10; + mSceneLayer.setResourceId(resourceId); + + mSceneLayer.onSizeChanged(1f, 2f, 3f, 0); // Should have no effect. + Assert.assertEquals( + mSceneLayer, mSceneLayer.getUpdatedSceneOverlayTree(null, null, null, 0f)); + inOrder.verify(mContinuousSearchSceneLayerJniMock) + .updateContinuousSearchLayer(eq(FAKE_NATIVE_ADDRESS), eq(mResourceManagerMock), + eq(resourceId), eq(verticalOffset)); + } + + /** + * Tests the required overrides that default to no-ops. + */ + @Test + public void testDefaultBehaviors() { + Assert.assertNull(mSceneLayer.getEventFilter()); + + List<VirtualView> views = new ArrayList<>(); + mSceneLayer.getVirtualViews(views); + Assert.assertEquals(0, views.size()); + + Assert.assertFalse(mSceneLayer.shouldHideAndroidBrowserControls()); + + Assert.assertFalse(mSceneLayer.onBackPressed()); + + Assert.assertFalse(mSceneLayer.handlesTabCreating()); + } +}
diff --git a/chrome/browser/continuous_search/android/junit/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchTabHelperJUnitTest.java b/chrome/browser/continuous_search/android/junit/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchTabHelperJUnitTest.java new file mode 100644 index 0000000..8912b91 --- /dev/null +++ b/chrome/browser/continuous_search/android/junit/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchTabHelperJUnitTest.java
@@ -0,0 +1,80 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.continuous_search; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestRule; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.mockito.quality.Strictness; + +import org.chromium.base.test.BaseRobolectricTestRunner; +import org.chromium.chrome.browser.flags.ChromeFeatureList; +import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.test.util.browser.Features; +import org.chromium.chrome.test.util.browser.Features.DisableFeatures; +import org.chromium.chrome.test.util.browser.Features.EnableFeatures; + +/** + * Test of {@link ContinuousSearchTabHelper}. + */ +@RunWith(BaseRobolectricTestRunner.class) +public class ContinuousSearchTabHelperJUnitTest { + @Mock + private Tab mTabMock; + + @Rule + public MockitoRule mMockitoRule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS); + @Rule + public TestRule mProcessor = new Features.JUnitProcessor(); + + /** + * Tests initialization success of all tab observers. + */ + @Test + @EnableFeatures({ChromeFeatureList.CONTINUOUS_SEARCH}) + public void testInitializeSuccess() { + when(mTabMock.isIncognito()).thenReturn(false); + + ContinuousSearchTabHelper.createForTab(mTabMock); + + verify(mTabMock, times(2)).addObserver(any()); + } + + /** + * Tests initialization is skipped for incognito tabs even if the feature is on. + */ + @Test + @EnableFeatures({ChromeFeatureList.CONTINUOUS_SEARCH}) + public void testNoInitializeIfIncognito() { + when(mTabMock.isIncognito()).thenReturn(true); + + ContinuousSearchTabHelper.createForTab(mTabMock); + + verify(mTabMock, never()).addObserver(any()); + } + + /** + * Tests only metrics observer is initialized if the feature flag is off. + */ + @Test + @DisableFeatures({ChromeFeatureList.CONTINUOUS_SEARCH}) + public void testInitializeOnlyNavigationObserver() { + when(mTabMock.isIncognito()).thenReturn(false); + + ContinuousSearchTabHelper.createForTab(mTabMock); + + verify(mTabMock, times(1)).addObserver(any()); + } +}
diff --git a/chrome/browser/extensions/api/file_system/file_system_apitest_chromeos.cc b/chrome/browser/extensions/api/file_system/file_system_apitest_chromeos.cc index a443710..c48ce9d 100644 --- a/chrome/browser/extensions/api/file_system/file_system_apitest_chromeos.cc +++ b/chrome/browser/extensions/api/file_system/file_system_apitest_chromeos.cc
@@ -274,10 +274,9 @@ ASSERT_TRUE(base::CreateDirectory(mount_point_path)); ASSERT_TRUE( base::CreateDirectory(mount_point_path.Append(kChildDirectory))); - ASSERT_TRUE(content::BrowserContext::GetMountPoints(browser()->profile()) - ->RegisterFileSystem( - mount_point_name, storage::kFileSystemTypeLocal, - storage::FileSystemMountOption(), mount_point_path)); + ASSERT_TRUE(browser()->profile()->GetMountPoints()->RegisterFileSystem( + mount_point_name, storage::kFileSystemTypeLocal, + storage::FileSystemMountOption(), mount_point_path)); VolumeManager* const volume_manager = VolumeManager::Get(browser()->profile()); ASSERT_TRUE(volume_manager);
diff --git a/chrome/browser/extensions/api/socket/socket_apitest.cc b/chrome/browser/extensions/api/socket/socket_apitest.cc index fc3495a..ff2083b 100644 --- a/chrome/browser/extensions/api/socket/socket_apitest.cc +++ b/chrome/browser/extensions/api/socket/socket_apitest.cc
@@ -4,6 +4,7 @@ #include "base/memory/ref_counted.h" #include "base/strings/stringprintf.h" +#include "build/build_config.h" #include "chrome/browser/extensions/extension_apitest.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/ui/browser.h" @@ -108,7 +109,13 @@ EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); } -IN_PROC_BROWSER_TEST_F(SocketApiTest, SocketMulticast) { +// Fails on MacOS 11, crbug.com/1211141 . +#if defined(OS_MAC) +#define MAYBE_SocketMulticast DISABLED_SocketMulticast +#else +#define MAYBE_SocketMulticast SocketMulticast +#endif +IN_PROC_BROWSER_TEST_F(SocketApiTest, MAYBE_SocketMulticast) { ResultCatcher catcher; catcher.RestrictToBrowserContext(browser()->profile()); ExtensionTestMessageListener listener("info_please", true);
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index 7e70f210..8847ea2 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -2320,11 +2320,6 @@ "expiry_milestone": -1 }, { - "name": "enable-scalable-status-area", - "owners": [ "leandre" ], - "expiry_milestone": 91 - }, - { "name": "enable-sharesheet", "owners": [ "chromeos-apps-foundation-team@google.com" ], "expiry_milestone": 92
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 1634b30..341a15c 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -4707,11 +4707,6 @@ "Enable compatibility mode for Android apps that are not optimized for " "large screens, and impose restrictions on resizing the apps"; -const char kScalableStatusAreaName[] = "Enable Scalable Status Area"; -const char kScalableStatusAreaDescription[] = - "Showing important notification icons in status area when the screen is " - "sufficiently large."; - const char kScanAppMediaLinkName[] = "Show Media app link in Scan app"; const char kScanAppMediaLinkDescription[] = "Enables showing a link in the Scan app to open scanned images in the Media"
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 2c1524d5..fcb9d8e 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -2747,9 +2747,6 @@ extern const char kArcResizeLockName[]; extern const char kArcResizeLockDescription[]; -extern const char kScalableStatusAreaName[]; -extern const char kScalableStatusAreaDescription[]; - extern const char kScanAppMediaLinkName[]; extern const char kScanAppMediaLinkDescription[];
diff --git a/chrome/browser/lifetime/application_lifetime.cc b/chrome/browser/lifetime/application_lifetime.cc index f12891c..3824ae3 100644 --- a/chrome/browser/lifetime/application_lifetime.cc +++ b/chrome/browser/lifetime/application_lifetime.cc
@@ -144,7 +144,7 @@ // TODO(beng): Can this use ProfileManager::GetLoadedProfiles instead? // TODO(crbug.com/1205798): Unset SaveSessionState if the restart fails. for (auto* browser : *BrowserList::GetInstance()) { - content::BrowserContext::SaveSessionState(browser->profile()); + browser->profile()->SaveSessionState(); #if BUILDFLAG(ENABLE_SESSION_SERVICE) auto* session_data_service = SessionDataServiceFactory::GetForProfile(browser->profile());
diff --git a/chrome/browser/media/media_engagement_autoplay_browsertest.cc b/chrome/browser/media/media_engagement_autoplay_browsertest.cc index 12149380..96c2f6ccf 100644 --- a/chrome/browser/media/media_engagement_autoplay_browsertest.cc +++ b/chrome/browser/media/media_engagement_autoplay_browsertest.cc
@@ -28,18 +28,8 @@ namespace { base::FilePath GetPythonPath() { -#if defined(OS_WIN) - // Windows bots do not have python installed and available on the PATH. - // Please see infra/doc/users/python.md - base::FilePath bot_path = - base::FilePath(FILE_PATH_LITERAL("c:/infra-system/bin/python.exe")); - - if (base::PathExists(bot_path)) - return bot_path; - return base::FilePath(FILE_PATH_LITERAL("python.exe")); -#else - return base::FilePath(FILE_PATH_LITERAL("python")); -#endif + // Every environment should have vpython3. + return base::FilePath(FILE_PATH_LITERAL("vpython3")); } const base::FilePath kTestDataPath = base::FilePath(
diff --git a/chrome/browser/media/webrtc/webrtc_disable_encryption_flag_browsertest.cc b/chrome/browser/media/webrtc/webrtc_disable_encryption_flag_browsertest.cc index adff52b..1ca502d0 100644 --- a/chrome/browser/media/webrtc/webrtc_disable_encryption_flag_browsertest.cc +++ b/chrome/browser/media/webrtc/webrtc_disable_encryption_flag_browsertest.cc
@@ -49,7 +49,8 @@ // Makes a call and checks that there's encryption or not in the SDP offer. // TODO(crbug.com/910216): De-flake this for ChromeOs. // TODO(crbug.com/984879): De-flake this for ASAN/MSAN Linux. -#if defined(OS_CHROMEOS) || \ +// TODO(crbug.com/1211144): De-flake this for MacOS. +#if defined(OS_CHROMEOS) || defined(OS_MAC) || \ (defined(OS_LINUX) && \ (defined(MEMORY_SANITIZER) || defined(ADDRESS_SANITIZER))) || \ (defined(OS_WIN) && defined(ADDRESS_SANITIZER))
diff --git a/chrome/browser/net/profile_network_context_service.cc b/chrome/browser/net/profile_network_context_service.cc index d0555514..99455d0c 100644 --- a/chrome/browser/net/profile_network_context_service.cc +++ b/chrome/browser/net/profile_network_context_service.cc
@@ -840,7 +840,7 @@ // Should be initialized with existing per-profile CORS access lists. network_context_params->cors_origin_access_list = - content::BrowserContext::GetSharedCorsOriginAccessList(profile_) + profile_->GetSharedCorsOriginAccessList() ->GetOriginAccessList() .CreateCorsOriginAccessPatternsList();
diff --git a/chrome/browser/page_load_metrics/observers/back_forward_cache_page_load_metrics_observer_browsertest.cc b/chrome/browser/page_load_metrics/observers/back_forward_cache_page_load_metrics_observer_browsertest.cc index 2fb9875..08da8ea 100644 --- a/chrome/browser/page_load_metrics/observers/back_forward_cache_page_load_metrics_observer_browsertest.cc +++ b/chrome/browser/page_load_metrics/observers/back_forward_cache_page_load_metrics_observer_browsertest.cc
@@ -536,7 +536,7 @@ content::RenderFrameHost::LifecycleState::kInBackForwardCache); // Go back to A. - double next_score; + float next_score; { auto waiter = CreatePageLoadMetricsTestWaiter(); waiter->AddPageExpectation(
diff --git a/chrome/browser/platform_util_unittest.cc b/chrome/browser/platform_util_unittest.cc index 5212e4f..4456b23 100644 --- a/chrome/browser/platform_util_unittest.cc +++ b/chrome/browser/platform_util_unittest.cc
@@ -54,7 +54,7 @@ std::vector<std::unique_ptr<storage::FileSystemBackend>>* additional_backends) override { storage::ExternalMountPoints* external_mount_points = - content::BrowserContext::GetMountPoints(browser_context); + browser_context->GetMountPoints(); // New FileSystemBackend that uses our MockSpecialStoragePolicy. additional_backends->push_back( @@ -81,9 +81,9 @@ content::SetBrowserClientForTesting(content_browser_client_.get()); // The test_directory needs to be mounted for it to be accessible. - content::BrowserContext::GetMountPoints(GetProfile()) - ->RegisterFileSystem("test", storage::kFileSystemTypeLocal, - storage::FileSystemMountOption(), test_directory); + GetProfile()->GetMountPoints()->RegisterFileSystem( + "test", storage::kFileSystemTypeLocal, storage::FileSystemMountOption(), + test_directory); // To test opening a file, we are going to register a mock extension that // handles .txt files. The extension doesn't actually need to exist due to
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc index 21cf3c2..9ce6fcbb 100644 --- a/chrome/browser/prefs/browser_prefs.cc +++ b/chrome/browser/prefs/browser_prefs.cc
@@ -226,7 +226,7 @@ #include "components/permissions/contexts/geolocation_permission_context_android.h" #include "components/query_tiles/tile_service_prefs.h" #else // defined(OS_ANDROID) -#include "chrome/browser/accessibility/caption_controller.h" +#include "chrome/browser/accessibility/live_caption_controller.h" #include "chrome/browser/cart/cart_service.h" #include "chrome/browser/enterprise/reporting/prefs.h" #include "chrome/browser/gcm/gcm_product_util.h" @@ -1079,7 +1079,7 @@ #else // defined(OS_ANDROID) AppShortcutManager::RegisterProfilePrefs(registry); browser_sync::ForeignSessionHandler::RegisterProfilePrefs(registry); - captions::CaptionController::RegisterProfilePrefs(registry); + captions::LiveCaptionController::RegisterProfilePrefs(registry); ChromeAuthenticatorRequestDelegate::RegisterProfilePrefs(registry); DevToolsWindow::RegisterProfilePrefs(registry); DriveService::RegisterProfilePrefs(registry);
diff --git a/chrome/browser/profiles/profile.cc b/chrome/browser/profiles/profile.cc index 7f6c64b..7ee045c 100644 --- a/chrome/browser/profiles/profile.cc +++ b/chrome/browser/profiles/profile.cc
@@ -457,7 +457,7 @@ if (!sent_destroyed_notification_) { sent_destroyed_notification_ = true; - NotifyWillBeDestroyed(this); + NotifyWillBeDestroyed(); for (auto& observer : observers_) observer.OnProfileWillBeDestroyed(this);
diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc index f3d8a10d..e5227bb 100644 --- a/chrome/browser/profiles/profile_manager.cc +++ b/chrome/browser/profiles/profile_manager.cc
@@ -131,8 +131,8 @@ #endif #if !defined(OS_ANDROID) -#include "chrome/browser/accessibility/caption_controller.h" -#include "chrome/browser/accessibility/caption_controller_factory.h" +#include "chrome/browser/accessibility/live_caption_controller.h" +#include "chrome/browser/accessibility/live_caption_controller_factory.h" #include "chrome/browser/browsing_data/chrome_browsing_data_lifetime_manager.h" #include "chrome/browser/browsing_data/chrome_browsing_data_lifetime_manager_factory.h" #include "chrome/browser/first_run/first_run.h" @@ -1628,9 +1628,9 @@ #if BUILDFLAG(IS_CHROMEOS_ASH) if (!chromeos::ProfileHelper::IsSigninProfile(profile)) - captions::CaptionControllerFactory::GetForProfile(profile)->Init(); + captions::LiveCaptionControllerFactory::GetForProfile(profile)->Init(); #elif !defined(OS_ANDROID) // !OS_ANDROID && !IS_CHROMEOS_ASH - captions::CaptionControllerFactory::GetForProfile(profile)->Init(); + captions::LiveCaptionControllerFactory::GetForProfile(profile)->Init(); #endif #if defined(OS_WIN) && BUILDFLAG(ENABLE_DICE_SUPPORT)
diff --git a/chrome/browser/resources/chromeos/accessibility/switch_access/item_scan_manager.js b/chrome/browser/resources/chromeos/accessibility/switch_access/item_scan_manager.js index 23b2c2d3..f8429568 100644 --- a/chrome/browser/resources/chromeos/accessibility/switch_access/item_scan_manager.js +++ b/chrome/browser/resources/chromeos/accessibility/switch_access/item_scan_manager.js
@@ -50,6 +50,9 @@ /** @private {!FocusHistory} */ this.history_ = new FocusHistory(); + /** @private {boolean} */ + this.ignoreFocusInKeyboard_ = false; + this.init_(); } @@ -75,6 +78,7 @@ /** @override */ enterKeyboard() { + this.ignoreFocusInKeyboard_ = true; this.node_.automationNode.focus(); const keyboard = KeyboardRootNode.buildTree(); this.jumpTo_(keyboard); @@ -94,6 +98,7 @@ /** @override */ exitKeyboard() { + this.ignoreFocusInKeyboard_ = false; const isKeyboard = (data) => data.group instanceof KeyboardRootNode; // If we are not in the keyboard, do nothing. if (!(this.group_ instanceof KeyboardRootNode) && @@ -270,6 +275,14 @@ return; } + // To be safe, let's ignore focus when we're in the SA menu or over the + // keyboard. + if (this.ignoreFocusInKeyboard_ || + this.group_ instanceof KeyboardRootNode || MenuManager.isMenuOpen()) { + return; + } + + if (this.node_.isEquivalentTo(event.target)) { return; }
diff --git a/chrome/browser/resources/chromeos/accessibility/switch_access/nodes/keyboard_node.js b/chrome/browser/resources/chromeos/accessibility/switch_access/nodes/keyboard_node.js index 72c0439..90b5c1f 100644 --- a/chrome/browser/resources/chromeos/accessibility/switch_access/nodes/keyboard_node.js +++ b/chrome/browser/resources/chromeos/accessibility/switch_access/nodes/keyboard_node.js
@@ -165,10 +165,13 @@ return; } - KeyboardRootNode.isVisible_ = - SwitchAccessPredicate.isVisible(keyboardObject); + KeyboardRootNode.isVisible_ = KeyboardRootNode.isKeyboardVisible_(); new EventHandler( + keyboardObject, chrome.automation.EventType.LOAD_COMPLETE, + KeyboardRootNode.checkVisibilityChanged_) + .start(); + new EventHandler( keyboardObject, chrome.automation.EventType.STATE_CHANGED, KeyboardRootNode.checkVisibilityChanged_, {exactMatch: true}) .start(); @@ -177,12 +180,23 @@ // ================= Private static methods ================= /** + * @return {boolean} + * @private + */ + static isKeyboardVisible_() { + const keyboardObject = KeyboardRootNode.getKeyboardObject(); + return !!keyboardObject && + SwitchAccessPredicate.isVisible(keyboardObject) && + !!keyboardObject.find({role: chrome.automation.RoleType.ROOT_WEB_AREA}); + } + + /** * @param {chrome.automation.AutomationEvent} event * @private */ static checkVisibilityChanged_(event) { - const currentlyVisible = - SwitchAccessPredicate.isVisible(KeyboardRootNode.getKeyboardObject()); + const keyboardObject = KeyboardRootNode.getKeyboardObject(); + const currentlyVisible = KeyboardRootNode.isKeyboardVisible_(); if (currentlyVisible === KeyboardRootNode.isVisible_) { return; } @@ -241,7 +255,6 @@ return; } - KeyboardRootNode.explicitStateChange_ = true; chrome.accessibilityPrivate.setVirtualKeyboardVisible(true); } }
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.html b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.html index 865519ca..0ff5a14 100644 --- a/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.html +++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.html
@@ -143,6 +143,10 @@ flex-shrink: 0; width: var(--emoji-group-button-size); } + + .sr-only { + user-select: none; + } </style> <div class="sr-only" aria-live="polite">
diff --git a/chrome/browser/resources/chromeos/emoji_picker/store.js b/chrome/browser/resources/chromeos/emoji_picker/store.js index 468d27c..500a2a1 100644 --- a/chrome/browser/resources/chromeos/emoji_picker/store.js +++ b/chrome/browser/resources/chromeos/emoji_picker/store.js
@@ -57,10 +57,10 @@ * @param {!StoredEmoji} newEmoji most recently used emoji. */ bumpEmoji(newEmoji) { - // find and remove newEmoji from array if it previously existed. + // Find and remove newEmoji from array if it previously existed. // Note, this explicitly allows for multiple recent emoji entries for the // same "base" emoji just with a different variant. - const oldIndex = this.data.history.findIndex(x => x === newEmoji); + const oldIndex = this.data.history.findIndex(x => x.base === newEmoji.base); if (oldIndex !== -1) { this.data.history.splice(oldIndex, 1); }
diff --git a/chrome/browser/resources/new_tab_page/modules/drive/module.html b/chrome/browser/resources/new_tab_page/modules/drive/module.html index 6d17f8f..2a061910 100644 --- a/chrome/browser/resources/new_tab_page/modules/drive/module.html +++ b/chrome/browser/resources/new_tab_page/modules/drive/module.html
@@ -66,6 +66,18 @@ color: var(--cr-secondary-text-color); font-size: 12px; } + + ntp-info-dialog a { + color: var(--cr-link-color); + cursor: pointer; + text-decoration: none; + } + + ntp-info-dialog a:focus { + border-radius: 2px; + box-shadow: var(--ntp-focus-shadow); + outline: none; + } </style> <ntp-module-header dismiss-text="[[i18nRecursive('',
diff --git a/chrome/browser/resources/new_tab_page/modules/info_dialog.html b/chrome/browser/resources/new_tab_page/modules/info_dialog.html index bea3fa2..01e4a156 100644 --- a/chrome/browser/resources/new_tab_page/modules/info_dialog.html +++ b/chrome/browser/resources/new_tab_page/modules/info_dialog.html
@@ -7,11 +7,6 @@ cr-dialog [slot='body'] { line-height: 20px; } - - cr-dialog [slot='body'] a[href] { - color: var(--cr-link-color); - text-decoration: none; - } </style> <cr-dialog id="dialog" consume-keydown-event> <div slot="title">[[i18n('modulesTasksInfoTitle')]]</div>
diff --git a/chrome/browser/resources/new_tab_page/modules/task_module/module.html b/chrome/browser/resources/new_tab_page/modules/task_module/module.html index 6d6ad0f..e99f60f 100644 --- a/chrome/browser/resources/new_tab_page/modules/task_module/module.html +++ b/chrome/browser/resources/new_tab_page/modules/task_module/module.html
@@ -184,6 +184,18 @@ margin-inline-end: 12px; margin-inline-start: 8px; } + + ntp-info-dialog a { + color: var(--cr-link-color); + cursor: pointer; + text-decoration: none; + } + + ntp-info-dialog a:focus { + border-radius: 2px; + box-shadow: var(--ntp-focus-shadow); + outline: none; + } </style> <ntp-module-header dismiss-text="[[i18n('modulesDismissButtonText', dismissName_)]]"
diff --git a/chrome/browser/resources/settings/chromeos/internet_page/esim_remove_profile_dialog.html b/chrome/browser/resources/settings/chromeos/internet_page/esim_remove_profile_dialog.html index abeda1b..4418b0dd 100644 --- a/chrome/browser/resources/settings/chromeos/internet_page/esim_remove_profile_dialog.html +++ b/chrome/browser/resources/settings/chromeos/internet_page/esim_remove_profile_dialog.html
@@ -44,6 +44,10 @@ #cancel { margin-inline-end: 8px; } + + #cancel:focus { + box-shadow: 0 0 0 2px var(--focus-shadow-color); + } </style> <cr-dialog id="dialog" show-on-attach> <div id="title" slot="title">
diff --git a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/app_detail_view.js b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/app_detail_view.js index 806eeecb..79caf03 100644 --- a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/app_detail_view.js +++ b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/app_detail_view.js
@@ -88,6 +88,7 @@ case (AppType.kWeb): return 'pwa-detail-view'; case (AppType.kExtension): + case (AppType.kStandaloneBrowser): return 'chrome-app-detail-view'; case (AppType.kArc): return 'arc-detail-view';
diff --git a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/app_item.js b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/app_item.js index fc0f2a2a..81010a49a 100644 --- a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/app_item.js +++ b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/app_item.js
@@ -48,6 +48,7 @@ case AppType.kArc: return AppManagementEntryPoint.MainViewArc; case AppType.kExtension: + case AppType.kStandaloneBrowser: return AppManagementEntryPoint.MainViewChromeApp; case AppType.kWeb: return AppManagementEntryPoint.MainViewWebApp;
diff --git a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/util.js b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/util.js index 4208433..2ef822e 100644 --- a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/util.js +++ b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/util.js
@@ -225,6 +225,7 @@ case AppType.kArc: return 'AppManagement.AppDetailViews.ArcApp'; case AppType.kExtension: + case AppType.kStandaloneBrowser: return 'AppManagement.AppDetailViews.ChromeApp'; case AppType.kWeb: return 'AppManagement.AppDetailViews.WebApp';
diff --git a/chrome/browser/sessions/better_session_restore_browsertest.cc b/chrome/browser/sessions/better_session_restore_browsertest.cc index 11d21a2c..18a1f133 100644 --- a/chrome/browser/sessions/better_session_restore_browsertest.cc +++ b/chrome/browser/sessions/better_session_restore_browsertest.cc
@@ -561,7 +561,7 @@ void Restart() { // Simulate restarting the browser, but let the test exit peacefully. for (auto* browser : *BrowserList::GetInstance()) { - content::BrowserContext::SaveSessionState(browser->profile()); + browser->profile()->SaveSessionState(); SessionDataServiceFactory::GetForProfile(browser->profile()) ->SetForceKeepSessionState(); } @@ -731,7 +731,7 @@ // Disable cookie and storage deletion on shutdown to simulate the // process being killed before cleanup is finished. - content::BrowserContext::SaveSessionState(browser()->profile()); + browser()->profile()->SaveSessionState(); } IN_PROC_BROWSER_TEST_F(NoSessionRestoreTest, CookiesClearedOnStartup) { @@ -748,7 +748,7 @@ // Disable cookie and storage deletion on shutdown to simulate the // process being killed before cleanup is finished. - content::BrowserContext::SaveSessionState(browser()->profile()); + browser()->profile()->SaveSessionState(); } IN_PROC_BROWSER_TEST_F(NoSessionRestoreTest, LocalStorageClearedOnStartup) { @@ -778,7 +778,7 @@ // Disable cookie and storage deletion handling on shutdown to simulate the // process being killed before cleanup is finished. - content::BrowserContext::SaveSessionState(browser()->profile()); + browser()->profile()->SaveSessionState(); } IN_PROC_BROWSER_TEST_F(NoSessionRestoreTestWithStartupDeletionDisabled, @@ -797,7 +797,7 @@ // Disable cookie and storage deletion handling on shutdown to simulate the // process being killed before cleanup is finished. - content::BrowserContext::SaveSessionState(browser()->profile()); + browser()->profile()->SaveSessionState(); } IN_PROC_BROWSER_TEST_F(NoSessionRestoreTestWithStartupDeletionDisabled,
diff --git a/chrome/browser/signin/signin_util_win.cc b/chrome/browser/signin/signin_util_win.cc index 790a4412..0ffc61d 100644 --- a/chrome/browser/signin/signin_util_win.cc +++ b/chrome/browser/signin/signin_util_win.cc
@@ -141,30 +141,13 @@ profile->GetPrefs()->SetBoolean(prefs::kSignedInWithCredentialProvider, true); } -// Extracts preferences to consider while signing in through credential -// provider. The preferences are set by credential provider after a successful -// login. They manipulate the behavior of Chrome when importing refresh_token -// provided by credential provider. When |allow_import_only_on_first_run| is -// set to true, importing refresh_token is only allowed during Chrome -// first time run. If it is false, refresh_token is allowed to be imported in -// subsequent runs. When |allow_import_when_primary_account_exists| is set to -// false, importing refresh_token is only allowed when profile doesn't have a -// primary account. If |allow_import_when_primary_account_exists| is set to -// true, importing refresh_token is allowed even if the profile has primary -// account for the user authenticated through credential provider. -void ExtractCredentialImportPreferences( - std::wstring* cred_provider_gaia_id, - std::wstring* cred_provider_email, - bool* allow_import_only_on_first_run, - bool* allow_import_when_primary_account_exists) { +// Extracts the |cred_provider_gaia_id| and |cred_provider_email| for the user +// signed in throuhg credential provider. +void ExtractCredentialProviderUser(std::wstring* cred_provider_gaia_id, + std::wstring* cred_provider_email) { DCHECK(cred_provider_gaia_id); DCHECK(cred_provider_email); - DCHECK(allow_import_only_on_first_run); - DCHECK(allow_import_when_primary_account_exists); - // Initialize to more restricted configuration. - *allow_import_only_on_first_run = true; - *allow_import_when_primary_account_exists = false; cred_provider_gaia_id->clear(); cred_provider_email->clear(); @@ -189,23 +172,8 @@ return; } - // No need to return immediately if reading following registries fail. They - // will set to be stricter by default. cred_provider_gaia_id and - // cred_provider_email will be correctly set, though. - DWORD reg_import_only_on_first_run = 1; - key_account.ReadValueDW(credential_provider::kAllowImportOnlyOnFirstRun, - ®_import_only_on_first_run); - - DWORD reg_import_when_primary_account_exists = 0; - key_account.ReadValueDW( - credential_provider::kAllowImportWhenPrimaryAccountExists, - ®_import_when_primary_account_exists); - *cred_provider_gaia_id = it.Name(); *cred_provider_email = email; - *allow_import_only_on_first_run = (reg_import_only_on_first_run == 1); - *allow_import_when_primary_account_exists = - (reg_import_when_primary_account_exists == 1); } // Attempt to sign in with a credentials from a system installed credential @@ -306,14 +274,16 @@ } void SigninWithCredentialProviderIfPossible(Profile* profile) { - bool import_only_on_first_run = true; - bool import_when_primary_account_exists = false; + // This flow is used for first time signin through credential provider. Any + // subsequent signin for the credential provider user needs to go through + // reauth flow. + if (profile->GetPrefs()->GetBoolean(prefs::kSignedInWithCredentialProvider)) + return; + std::wstring cred_provider_gaia_id; std::wstring cred_provider_email; - ExtractCredentialImportPreferences( - &cred_provider_gaia_id, &cred_provider_email, &import_only_on_first_run, - &import_when_primary_account_exists); + ExtractCredentialProviderUser(&cred_provider_gaia_id, &cred_provider_email); if (cred_provider_gaia_id.empty() || cred_provider_email.empty()) return; @@ -326,19 +296,12 @@ return; } - if (import_only_on_first_run && !first_run::IsChromeFirstRun()) - return; - auto* identity_manager = IdentityManagerFactory::GetForProfile(profile); std::wstring gaia_id; if (identity_manager->HasPrimaryAccount(signin::ConsentLevel::kSync)) { gaia_id = base::UTF8ToWide( identity_manager->GetPrimaryAccountInfo(signin::ConsentLevel::kSync) .gaia); - - if (!import_when_primary_account_exists) { - return; - } } TrySigninWithCredentialProvider(profile, gaia_id, gaia_id.empty());
diff --git a/chrome/browser/signin/signin_util_win_browsertest.cc b/chrome/browser/signin/signin_util_win_browsertest.cc index 7b8e0a2..45ce132 100644 --- a/chrome/browser/signin/signin_util_win_browsertest.cc +++ b/chrome/browser/signin/signin_util_win_browsertest.cc
@@ -109,14 +109,8 @@ public: BrowserTestHelper(const std::wstring& gaia_id, const std::wstring& email, - const std::string& refresh_token, - int import_only_on_first_run, - int import_on_primary_account) - : gaia_id_(gaia_id), - email_(email), - refresh_token_(refresh_token), - import_only_on_first_run_(import_only_on_first_run), - import_on_primary_account_(import_on_primary_account) {} + const std::string& refresh_token) + : gaia_id_(gaia_id), email_(email), refresh_token_(refresh_token) {} protected: void CreateRegKey(base::win::RegKey* key) { @@ -168,21 +162,6 @@ base::win::RegKey key; CreateRegKey(&key); - if (import_only_on_first_run_ != 2) { - EXPECT_TRUE(key.Valid()); - EXPECT_EQ(ERROR_SUCCESS, - key.WriteValue(credential_provider::kAllowImportOnlyOnFirstRun, - import_only_on_first_run_)); - } - - if (import_on_primary_account_ != 2) { - EXPECT_TRUE(key.Valid()); - EXPECT_EQ(ERROR_SUCCESS, - key.WriteValue( - credential_provider::kAllowImportWhenPrimaryAccountExists, - import_on_primary_account_)); - } - if (!email_.empty()) { EXPECT_TRUE(key.Valid()); EXPECT_EQ(ERROR_SUCCESS, @@ -213,8 +192,6 @@ std::wstring gaia_id_; std::wstring email_; std::string refresh_token_; - int import_only_on_first_run_; - int import_on_primary_account_; }; class SigninUtilWinBrowserTest @@ -225,9 +202,7 @@ SigninUtilWinBrowserTest() : BrowserTestHelper(GetParam().gaia_id, GetParam().email, - GetParam().refresh_token, - 2, - 2) {} + GetParam().refresh_token) {} protected: void SetUpCommandLine(base::CommandLine* command_line) override { @@ -391,15 +366,13 @@ /*gaia_id=*/L"gaia-123456", /*email=*/L"foo@gmail.com", /*refresh_token=*/"lst-123456", - /*expect_is_started=*/false))); + /*expect_is_started=*/true))); struct ExistingWinBrowserSigninUtilTestParams : SigninUtilWinBrowserTestParams { ExistingWinBrowserSigninUtilTestParams( const std::wstring& gaia_id, const std::wstring& email, const std::string& refresh_token, - const int allow_import_only_on_first_run, - const int allow_import_on_primary_account, const std::wstring& existing_email, bool expect_is_started) : SigninUtilWinBrowserTestParams(false, @@ -407,12 +380,8 @@ email, refresh_token, expect_is_started), - import_only_on_first_run(allow_import_only_on_first_run), - import_on_primary_account(allow_import_on_primary_account), existing_email(existing_email) {} - int import_only_on_first_run; - int import_on_primary_account; std::wstring existing_email; }; @@ -425,9 +394,7 @@ ExistingWinBrowserSigninUtilTest() : BrowserTestHelper(GetParam().gaia_id, GetParam().email, - GetParam().refresh_token, - GetParam().import_only_on_first_run, - GetParam().import_on_primary_account) {} + GetParam().refresh_token) {} protected: bool SetUpUserDataDirectory() override { @@ -482,25 +449,12 @@ ExpectRefreshTokenExists(false); } -INSTANTIATE_TEST_SUITE_P(OnlyAllowFirstRun, - ExistingWinBrowserSigninUtilTest, - testing::Values(ExistingWinBrowserSigninUtilTestParams( - /*gaia_id=*/L"gaia-123456", - /*email=*/L"foo@gmail.com", - /*refresh_token=*/"lst-123456", - /*import_only_on_first_run=*/1, - /*import_on_primary_account=*/0, - /*existing_email=*/std::wstring(), - /*expect_is_started=*/false))); - INSTANTIATE_TEST_SUITE_P(AllowSubsequentRun, ExistingWinBrowserSigninUtilTest, testing::Values(ExistingWinBrowserSigninUtilTestParams( /*gaia_id=*/L"gaia-123456", /*email=*/L"foo@gmail.com", /*refresh_token=*/"lst-123456", - /*import_only_on_first_run=*/0, - /*import_on_primary_account=*/0, /*existing_email=*/std::wstring(), /*expect_is_started=*/true))); @@ -510,8 +464,6 @@ /*gaia_id=*/L"gaia_id_for_foo_gmail.com", /*email=*/L"foo@gmail.com", /*refresh_token=*/"lst-123456", - /*import_only_on_first_run=*/0, - /*import_on_primary_account=*/0, /*existing_email=*/L"bar@gmail.com", /*expect_is_started=*/false))); @@ -521,21 +473,9 @@ /*gaia_id=*/L"gaia_id_for_foo_gmail.com", /*email=*/L"foo@gmail.com", /*refresh_token=*/"lst-123456", - /*import_only_on_first_run=*/0, - /*import_on_primary_account=*/1, /*existing_email=*/L"bar@gmail.com", /*expect_is_started=*/false))); -INSTANTIATE_TEST_SUITE_P(AllowProfileWithPrimaryAccount_DisabledImport, - ExistingWinBrowserSigninUtilTest, - testing::Values(ExistingWinBrowserSigninUtilTestParams( - /*gaia_id=*/L"gaia_id_for_foo_gmail.com", - /*email=*/L"foo@gmail.com", - /*refresh_token=*/"lst-123456", - /*import_only_on_first_run=*/0, - /*import_on_primary_account=*/0, - /*existing_email=*/L"foo@gmail.com", - /*expect_is_started=*/false))); INSTANTIATE_TEST_SUITE_P(AllowProfileWithPrimaryAccount_SameUser, ExistingWinBrowserSigninUtilTest, @@ -543,8 +483,6 @@ /*gaia_id=*/L"gaia_id_for_foo_gmail.com", /*email=*/L"foo@gmail.com", /*refresh_token=*/"lst-123456", - /*import_only_on_first_run=*/0, - /*import_on_primary_account=*/1, /*existing_email=*/L"foo@gmail.com", /*expect_is_started=*/true))); @@ -605,9 +543,7 @@ ExistingWinBrowserProfilesSigninUtilTest() : BrowserTestHelper(L"gaia_id_for_foo_gmail.com", L"foo@gmail.com", - "lst-123456", - 0, - 1) { + "lst-123456") { // TODO(droger): Disable the profile picker using the local state preference // instead. feature_list_.InitAndDisableFeature(features::kNewProfilePicker); @@ -624,7 +560,7 @@ SetSigninUtilRegistry(); } else if (IsPrePreTest() && GetParam().cred_provider_used_other_profile) { BrowserTestHelper(L"gaia_id_for_bar_gmail.com", L"bar@gmail.com", - "lst-123456", 0, 1) + "lst-123456") .SetSigninUtilRegistry(); }
diff --git a/chrome/browser/speech/speech_recognition_service_browsertest.cc b/chrome/browser/speech/speech_recognition_service_browsertest.cc index ddfb8d520..5f59117 100644 --- a/chrome/browser/speech/speech_recognition_service_browsertest.cc +++ b/chrome/browser/speech/speech_recognition_service_browsertest.cc
@@ -25,6 +25,7 @@ #include "content/public/browser/audio_service.h" #include "content/public/common/content_switches.h" #include "content/public/test/browser_test.h" +#include "media/audio/audio_device_description.h" #include "media/audio/wav_audio_handler.h" #include "media/base/media_switches.h" #include "media/mojo/mojom/audio_input_stream.mojom.h"
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.cc b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.cc index 7d9fae4..0bcaecc 100644 --- a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.cc +++ b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.cc
@@ -228,6 +228,11 @@ return pinned_files; } +void HoldingSpaceKeyedService::AddDiagnosticsLog( + const base::FilePath& diagnostics_log_path) { + AddItemOfType(HoldingSpaceItem::Type::kDiagnosticsLog, diagnostics_log_path); +} + void HoldingSpaceKeyedService::AddDownload( HoldingSpaceItem::Type type, const base::FilePath& download_file,
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.h b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.h index 0f3173c..358e5e5 100644 --- a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.h +++ b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.h
@@ -83,6 +83,9 @@ // files system URLs as GURLs. std::vector<GURL> GetPinnedFiles() const; + // Adds a diagnostics log item backed by the provided absolute file path. + void AddDiagnosticsLog(const base::FilePath& diagnostics_log_path); + // Adds a download item of the specified `type` backed by the provided // absolute file path. // NOTE: `type` must refer to a download type.
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_unittest.cc b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_unittest.cc index e494ad74..fa02773f 100644 --- a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_unittest.cc +++ b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_unittest.cc
@@ -1731,6 +1731,9 @@ ASSERT_TRUE(holding_space_service); switch (type) { + case HoldingSpaceItem::Type::kDiagnosticsLog: + holding_space_service->AddDiagnosticsLog(file_path); + break; case HoldingSpaceItem::Type::kArcDownload: case HoldingSpaceItem::Type::kDownload: holding_space_service->AddDownload(type, file_path);
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_ui_browsertest.cc b/chrome/browser/ui/ash/holding_space/holding_space_ui_browsertest.cc index 79d7386..54dd429 100644 --- a/chrome/browser/ui/ash/holding_space/holding_space_ui_browsertest.cc +++ b/chrome/browser/ui/ash/holding_space/holding_space_ui_browsertest.cc
@@ -980,6 +980,7 @@ // Right clicking a pinned item should cause a context menu to show. ASSERT_FALSE(views::MenuController::GetActiveInstance()); + ViewDrawnWaiter().Wait(pinned_file_chips.front()); RightClick(pinned_file_chips.front()); ASSERT_TRUE(views::MenuController::GetActiveInstance()); @@ -994,6 +995,7 @@ ASSERT_GT(download_chips.size(), 1u); // Add a download item to the selection and show the context menu. + ViewDrawnWaiter().Wait(download_chips.front()); Click(download_chips.front(), ui::EF_CONTROL_DOWN); RightClick(download_chips.front()); ASSERT_TRUE(views::MenuController::GetActiveInstance()); @@ -1048,6 +1050,7 @@ ASSERT_GT(screen_capture_views.size(), 1u); // Select a screen capture item and show the context menu. + ViewDrawnWaiter().Wait(screen_capture_views.front()); Click(screen_capture_views.front()); RightClick(screen_capture_views.front()); ASSERT_TRUE(views::MenuController::GetActiveInstance()); @@ -1085,12 +1088,16 @@ // due to max visibility count restrictions. while (!download_chips.empty() || !screen_capture_views.empty()) { // Select all visible download items. - for (views::View* download_chip : download_chips) + for (views::View* download_chip : download_chips) { + ViewDrawnWaiter().Wait(download_chip); Click(download_chip, ui::EF_CONTROL_DOWN); + } // Select all visible screen capture items. - for (views::View* screen_capture_view : screen_capture_views) + for (views::View* screen_capture_view : screen_capture_views) { + ViewDrawnWaiter().Wait(screen_capture_view); Click(screen_capture_view, ui::EF_CONTROL_DOWN); + } // Show the context menu. There should be a `kRemoveItem` command. RightClick(download_chips.size() ? download_chips.front() @@ -1230,6 +1237,7 @@ // Right click the tray icon, and expect a context menu to be shown which will // allow the user to hide previews. + ViewDrawnWaiter().Wait(previews_tray_icon); RightClick(previews_tray_icon); ASSERT_TRUE(views::MenuController::GetActiveInstance()); @@ -1249,6 +1257,7 @@ // Right click the tray icon, and expect a context menu to be shown which will // allow the user to show previews. + ViewDrawnWaiter().Wait(default_tray_icon); RightClick(default_tray_icon); ASSERT_TRUE(views::MenuController::GetActiveInstance());
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.cc b/chrome/browser/ui/autofill/chrome_autofill_client.cc index 0c2e0d3..edd45b7 100644 --- a/chrome/browser/ui/autofill/chrome_autofill_client.cc +++ b/chrome/browser/ui/autofill/chrome_autofill_client.cc
@@ -31,6 +31,7 @@ #include "chrome/browser/sync/profile_sync_service_factory.h" #include "chrome/browser/translate/chrome_translate_client.h" #include "chrome/browser/ui/autofill/autofill_popup_controller_impl.h" +#include "chrome/browser/ui/autofill/payments/autofill_snackbar_controller_impl.h" #include "chrome/browser/ui/autofill/payments/create_card_unmask_prompt_view.h" #include "chrome/browser/ui/autofill/payments/credit_card_scanner_controller.h" #include "chrome/browser/ui/autofill/save_update_address_profile_bubble_controller_impl.h" @@ -684,10 +685,11 @@ #endif } -void ChromeAutofillClient::ShowVirtualCardManualFallbackBubble( - const CreditCard* credit_card, - const std::u16string& cvc) { -#if !defined(OS_ANDROID) // Desktop only +void ChromeAutofillClient::OnVirtualCardFetched(const CreditCard* credit_card, + const std::u16string& cvc) { +#if defined(OS_ANDROID) + (new AutofillSnackbarControllerImpl(web_contents()))->Show(); +#else VirtualCardManualFallbackBubbleControllerImpl::CreateForWebContents( web_contents()); VirtualCardManualFallbackBubbleControllerImpl* controller =
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.h b/chrome/browser/ui/autofill/chrome_autofill_client.h index 66d8d708..013a18e3 100644 --- a/chrome/browser/ui/autofill/chrome_autofill_client.h +++ b/chrome/browser/ui/autofill/chrome_autofill_client.h
@@ -150,8 +150,8 @@ void HideAutofillPopup(PopupHidingReason reason) override; void ShowOfferNotificationIfApplicable( const AutofillOfferData* offer) override; - void ShowVirtualCardManualFallbackBubble(const CreditCard* card, - const std::u16string& cvc) override; + void OnVirtualCardFetched(const CreditCard* card, + const std::u16string& cvc) override; bool IsAutofillAssistantShowing() override; bool IsAutocompleteEnabled() override; void PropagateAutofillPredictions(
diff --git a/chrome/browser/ui/caption_bubble_controller.h b/chrome/browser/ui/caption_bubble_controller.h index 645e754..026ea73 100644 --- a/chrome/browser/ui/caption_bubble_controller.h +++ b/chrome/browser/ui/caption_bubble_controller.h
@@ -53,7 +53,7 @@ absl::optional<ui::CaptionStyle> caption_style) = 0; private: - friend class CaptionControllerTest; + friend class LiveCaptionControllerTest; virtual bool IsWidgetVisibleForTesting() = 0; virtual std::string GetBubbleLabelTextForTesting() = 0;
diff --git a/chrome/browser/ui/tabs/tab_renderer_data.cc b/chrome/browser/ui/tabs/tab_renderer_data.cc index 01df75e..fdf7acb 100644 --- a/chrome/browser/ui/tabs/tab_renderer_data.cc +++ b/chrome/browser/ui/tabs/tab_renderer_data.cc
@@ -13,9 +13,31 @@ #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/tabs/tab_strip_model_delegate.h" #include "chrome/browser/ui/thumbnails/thumbnail_tab_helper.h" +#include "chrome/common/webui_url_constants.h" +#include "content/public/browser/navigation_entry.h" #include "content/public/browser/web_contents.h" #include "content/public/common/url_constants.h" +namespace { + +bool ShouldThemifyFaviconForEntryUrl(const GURL& url) { + // Themify favicon for the default NTP and incognito NTP. + return url.SchemeIs(content::kChromeUIScheme) && + (url.host_piece() == chrome::kChromeUINewTabPageHost || + url.host_piece() == chrome::kChromeUINewTabHost); +} + +bool ShouldThemifyFaviconForVisibleUrl(const GURL& visible_url) { + return visible_url.SchemeIs(content::kChromeUIScheme) && + visible_url.host_piece() != chrome::kChromeUIAppLauncherPageHost && + visible_url.host_piece() != chrome::kChromeUIHelpHost && + visible_url.host_piece() != chrome::kChromeUIVersionHost && + visible_url.host_piece() != chrome::kChromeUINetExportHost && + visible_url.host_piece() != chrome::kChromeUINewTabHost; +} + +} // namespace + // static TabRendererData TabRendererData::FromTabInModel(TabStripModel* model, int index) { @@ -45,6 +67,13 @@ data.blocked = model->IsTabBlocked(index); data.should_hide_throbber = tab_ui_helper->ShouldHideThrobber(); data.alert_state = chrome::GetTabAlertStatesForContents(contents); + + content::NavigationEntry* entry = + contents->GetController().GetLastCommittedEntry(); + data.should_themify_favicon = + (entry && ShouldThemifyFaviconForEntryUrl(entry->GetURL())) || + ShouldThemifyFaviconForVisibleUrl(contents->GetVisibleURL()); + return data; }
diff --git a/chrome/browser/ui/tabs/tab_renderer_data.h b/chrome/browser/ui/tabs/tab_renderer_data.h index 9f4f9ecd..260e988 100644 --- a/chrome/browser/ui/tabs/tab_renderer_data.h +++ b/chrome/browser/ui/tabs/tab_renderer_data.h
@@ -52,6 +52,7 @@ std::vector<TabAlertState> alert_state; bool should_hide_throbber = false; bool should_render_empty_title = false; + bool should_themify_favicon = false; }; #endif // CHROME_BROWSER_UI_TABS_TAB_RENDERER_DATA_H_
diff --git a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.cc b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.cc index 247a351e..fc00e3a 100644 --- a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.cc +++ b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.cc
@@ -7,6 +7,7 @@ #include <stddef.h> #include <algorithm> +#include <memory> #include "base/bind.h" #include "base/metrics/histogram_macros.h" @@ -42,6 +43,7 @@ #include "components/sync_sessions/session_sync_service.h" #include "components/sync_sessions/synced_session.h" #include "components/tab_groups/tab_group_id.h" +#include "components/vector_icons/vector_icons.h" #include "ui/base/accelerators/accelerator.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/models/image_model.h" @@ -63,6 +65,7 @@ // only have navigatabale/executable tab items. // - |local_window_items_| only has executable open window items. // - |local_group_items_| only has executable open group items. +// - |local_sub_menu_items_| only has non-executable sub menu items. // Using initial command IDs for local tab, local window, local group, and other // devices' tab items makes it easier and less error-prone to manipulate the // menumodel and storage structures. @@ -75,11 +78,15 @@ // |AppMenuModel::kMinRecentTabsCommandId| i.e. 1001 and 1200 // (|AppMenuModel::kMaxRecentTabsCommandId|) inclusively. const int kFirstLocalTabCommandId = AppMenuModel::kMinRecentTabsCommandId; -const int kFirstLocalWindowCommandId = 1031; -const int kFirstLocalGroupCommandId = 1051; -const int kFirstOtherDevicesTabCommandId = 1071; +const int kFirstLocalWindowCommandId = kFirstLocalTabCommandId + 30; +const int kFirstLocalGroupCommandId = kFirstLocalWindowCommandId + 20; +const int kFirstLocalSubMenuCommandId = kFirstLocalGroupCommandId + 20; +const int kFirstOtherDevicesTabCommandId = kFirstLocalSubMenuCommandId + 20; const int kMinDeviceNameCommandId = 1120; const int kMaxDeviceNameCommandId = 1130; +static_assert(kMaxDeviceNameCommandId <= AppMenuModel::kMaxRecentTabsCommandId, + "Final command id within RecentTabsSubMenuModel must not exceed " + "those allocated to it within AppMenuModel"); // The maximum number of local recently closed entries (tab or window) to be // shown in the menu. @@ -109,6 +116,12 @@ // Returns true if the command id identifies a group menu item. bool IsGroupModelCommandId(int command_id) { return command_id >= kFirstLocalGroupCommandId && + command_id < kFirstLocalSubMenuCommandId; +} + +// Returns true if the command id identifies a sub menu item. +bool IsSubMenuModelCommandId(int command_id) { + return command_id >= kFirstLocalSubMenuCommandId && command_id < kFirstOtherDevicesTabCommandId; } @@ -145,6 +158,13 @@ return command_id; } +// Convert |sub_menu_vector_index| to command id of menu item. +int SubMenuVectorIndexToCommandId(int sub_menu_vector_index) { + int command_id = sub_menu_vector_index + kFirstLocalSubMenuCommandId; + DCHECK(IsSubMenuModelCommandId(command_id)); + return command_id; +} + // Convert |command_id| of menu item to index in |local_group_items_|. int CommandIdToGroupVectorIndex(int command_id) { DCHECK(IsGroupModelCommandId(command_id)); @@ -192,6 +212,29 @@ GURL url; }; +// An element in |RecentTabsSubMenuModel::sub_menu_items_| that records a sub +// menu item's model and its own command id. +// TODO(emshack): This solution, where sub menus are represented by a +// SimpleMenuModel and managed by the parent RecentTabsSubMenuModel, is not +// ideal. However, AppMenuModel requires unique ids across its descendant sub +// menus, and queries a single model for these ids. This doesn't work well with +// our preferred approach, which would decouple sub menus from their parent and +// allow them to manage their own items and command ids. +struct RecentTabsSubMenuModel::SubMenuItem { + SubMenuItem(int command_id, + std::unique_ptr<ui::SimpleMenuModel> sub_menu_model) + : parent_id(command_id), menu_model(std::move(sub_menu_model)) { + const int child_id_count = menu_model->GetItemCount(); + for (int i = 0; i < child_id_count; i++) { + child_ids.insert(menu_model->GetCommandIdAt(i)); + } + } + + const int parent_id; + std::unordered_set<int> child_ids; + std::unique_ptr<ui::SimpleMenuModel> menu_model; +}; + RecentTabsSubMenuModel::RecentTabsSubMenuModel( ui::AcceleratorProvider* accelerator_provider, Browser* browser) @@ -230,7 +273,7 @@ } } -RecentTabsSubMenuModel::~RecentTabsSubMenuModel() {} +RecentTabsSubMenuModel::~RecentTabsSubMenuModel() = default; bool RecentTabsSubMenuModel::IsCommandIdChecked(int command_id) const { return false; @@ -248,10 +291,19 @@ ui::Accelerator* accelerator) const { // If there are no recently closed items, we show the accelerator beside // the header, otherwise, we show it beside the first item underneath it. - int index_in_menu = GetIndexOfCommandId(command_id); - int header_index = GetIndexOfCommandId(kRecentlyClosedHeaderCommandId); + // If the first item underneath it is a submenu, we instead show it beside + // the first item in that submenu. + const int index_in_menu = GetIndexOfCommandId(command_id); + const int header_index = GetIndexOfCommandId(kRecentlyClosedHeaderCommandId); + const int parent_id = GetParentCommandId(command_id); + const int parent_index = + parent_id == -1 ? -1 : GetIndexOfCommandId(parent_id); if ((command_id == kDisabledRecentlyClosedHeaderCommandId || - (header_index != -1 && index_in_menu == header_index + 1)) && + ((header_index != -1 && (!IsSubMenuModelCommandId(command_id) && + index_in_menu == header_index + 1)) || + ((IsWindowModelCommandId(command_id) || + IsGroupModelCommandId(command_id)) && + parent_index == header_index + 1))) && reopen_closed_tab_accelerator_.key_code() != ui::VKEY_UNKNOWN) { *accelerator = reopen_closed_tab_accelerator_; return true; @@ -292,8 +344,8 @@ BrowserLiveTabContext::FindContextForWebContents( browser_->tab_strip_model()->GetActiveWebContents()); if (IsTabModelCommandId(command_id)) { - TabNavigationItems* tab_items = NULL; - int tab_items_idx = CommandIdToTabVectorIndex(command_id, &tab_items); + TabNavigationItems* tab_items = nullptr; + const int tab_items_idx = CommandIdToTabVectorIndex(command_id, &tab_items); const TabNavigationItem& item = (*tab_items)[tab_items_idx]; DCHECK(item.tab_id.is_valid() && item.url.is_valid()); @@ -324,7 +376,7 @@ } } else if (IsWindowModelCommandId(command_id)) { if (service && context) { - int window_items_idx = CommandIdToWindowVectorIndex(command_id); + const int window_items_idx = CommandIdToWindowVectorIndex(command_id); DCHECK(window_items_idx >= 0 && window_items_idx < static_cast<int>(local_window_items_.size())); base::RecordAction( @@ -335,7 +387,7 @@ disposition); } } else if (IsGroupModelCommandId(command_id)) { - int group_items_idx = CommandIdToGroupVectorIndex(command_id); + const int group_items_idx = CommandIdToGroupVectorIndex(command_id); DCHECK(group_items_idx >= 0 && group_items_idx < static_cast<int>(local_group_items_.size())); base::RecordAction(base::UserMetricsAction("WrenchMenu_OpenRecentGroup")); @@ -343,6 +395,8 @@ LIMIT_RECENT_TAB_ACTION); service->RestoreEntryById(context, local_group_items_[group_items_idx], disposition); + } else if (IsSubMenuModelCommandId(command_id)) { + return; } else { NOTREACHED(); } @@ -361,17 +415,17 @@ const gfx::FontList* RecentTabsSubMenuModel::GetLabelFontListAt( int index) const { - int command_id = GetCommandIdAt(index); + const int command_id = GetCommandIdAt(index); if (command_id == kRecentlyClosedHeaderCommandId || IsDeviceNameCommandId(command_id)) { return &ui::ResourceBundle::GetSharedInstance().GetFontList( ui::ResourceBundle::BoldFont); } - return NULL; + return nullptr; } int RecentTabsSubMenuModel::GetMaxWidthForItemAtIndex(int item_index) const { - int command_id = GetCommandIdAt(item_index); + const int command_id = GetCommandIdAt(item_index); if (command_id == IDC_RECENT_TABS_NO_DEVICE_TABS || command_id == kRecentlyClosedHeaderCommandId || command_id == kDisabledRecentlyClosedHeaderCommandId) { @@ -384,10 +438,10 @@ int index, std::string* url, std::u16string* title) { - int command_id = GetCommandIdAt(index); + const int command_id = GetCommandIdAt(index); if (IsTabModelCommandId(command_id)) { - TabNavigationItems* tab_items = NULL; - int tab_items_idx = CommandIdToTabVectorIndex(command_id, &tab_items); + TabNavigationItems* tab_items = nullptr; + const int tab_items_idx = CommandIdToTabVectorIndex(command_id, &tab_items); const TabNavigationItem& item = (*tab_items)[tab_items_idx]; *url = item.url.possibly_invalid_spec(); *title = item.title; @@ -453,21 +507,17 @@ break; } case sessions::TabRestoreService::WINDOW: { - // TODO(chrisha): Make this menu entry better. When windows contain a - // single tab, display that tab directly in the menu. Otherwise, offer - // a hover over or alternative mechanism for seeing which tabs were in - // the window. - BuildLocalWindowItem( - entry->id, - static_cast<const sessions::TabRestoreService::Window&>(*entry) - .tabs.size(), - ++last_local_model_index_); + auto& window = + static_cast<sessions::TabRestoreService::Window&>(*entry); + BuildLocalWindowItem(entry->id, CreateWindowSubMenuModel(window), + window.tabs.size(), ++last_local_model_index_); break; } case sessions::TabRestoreService::GROUP: { auto& group = static_cast<const sessions::TabRestoreService::Group&>(*entry); - BuildLocalGroupItem(group.id, group.visual_data, group.tabs.size(), + BuildLocalGroupItem(group.id, group.visual_data, + CreateGroupSubMenuModel(group), group.tabs.size(), ++last_local_model_index_); break; } @@ -510,7 +560,7 @@ // Add the header for the device session. DCHECK(!session->session_name.empty()); AddSeparator(ui::NORMAL_SEPARATOR); - int command_id = kMinDeviceNameCommandId + i; + const int command_id = kMinDeviceNameCommandId + i; DCHECK_LE(command_id, kMaxDeviceNameCommandId); AddItem(command_id, base::UTF8ToUTF16(session->session_name)); AddDeviceFavicon(GetItemCount() - 1, session->device_type); @@ -537,7 +587,7 @@ const GURL& url, int curr_model_index) { TabNavigationItem item(std::string(), session_id, title, url); - int command_id = TabVectorIndexToCommandId( + const int command_id = TabVectorIndexToCommandId( local_tab_navigation_items_.size(), kFirstLocalTabCommandId); // See comments in BuildLocalEntries() about usage of InsertItem*At(). // There may be no tab title, in which case, use the url as tab title. @@ -562,24 +612,29 @@ local_tab_navigation_items_.push_back(item); } -void RecentTabsSubMenuModel::BuildLocalWindowItem(SessionID window_id, - int num_tabs, - int curr_model_index) { - int command_id = WindowVectorIndexToCommandId(local_window_items_.size()); - // See comments in BuildLocalEntries() about usage of InsertItem*At(). - InsertItemAt(curr_model_index, command_id, l10n_util::GetPluralStringFUTF16( - IDS_RECENTLY_CLOSED_WINDOW, num_tabs)); +void RecentTabsSubMenuModel::BuildLocalWindowItem( + SessionID window_id, + std::unique_ptr<ui::SimpleMenuModel> window_model, + int num_tabs, + int curr_model_index) { + const int command_id = + SubMenuVectorIndexToCommandId(local_sub_menu_items_.size()); + InsertSubMenuAt( + curr_model_index, command_id, + l10n_util::GetPluralStringFUTF16(IDS_RECENTLY_CLOSED_WINDOW, num_tabs), + window_model.get()); SetIcon(curr_model_index, CreateFavicon(kTabIcon)); - local_window_items_.push_back(window_id); + SubMenuItem sub_menu_item = SubMenuItem(command_id, std::move(window_model)); + local_sub_menu_items_.push_back(std::move(sub_menu_item)); } void RecentTabsSubMenuModel::BuildLocalGroupItem( SessionID session_id, tab_groups::TabGroupVisualData visual_data, + std::unique_ptr<ui::SimpleMenuModel> group_model, int num_tabs, int curr_model_index) { - int command_id = GroupVectorIndexToCommandId(local_group_items_.size()); - + int command_id = SubMenuVectorIndexToCommandId(local_sub_menu_items_.size()); // Set the item label to the name of the group and the number of tabs. std::u16string item_label; if (visual_data.title().empty()) { @@ -591,9 +646,7 @@ item_label = base::ReplaceStringPlaceholders( item_label, {visual_data.title()}, nullptr); } - - // See comments in BuildLocalEntries() about usage of InsertItem*At(). - InsertItemAt(curr_model_index, command_id, item_label); + InsertSubMenuAt(curr_model_index, command_id, item_label, group_model.get()); // Set the item icon to the group color. const auto& theme = @@ -602,8 +655,8 @@ ui::ImageModel group_icon = ui::ImageModel::FromVectorIcon( kTabGroupIcon, theme.GetColor(color_id), gfx::kFaviconSize); SetIcon(curr_model_index, group_icon); - - local_group_items_.push_back(session_id); + SubMenuItem sub_menu_item = SubMenuItem(command_id, std::move(group_model)); + local_sub_menu_items_.push_back(std::move(sub_menu_item)); } void RecentTabsSubMenuModel::BuildOtherDevicesTabItem( @@ -613,9 +666,9 @@ tab.navigations.at(tab.normalized_navigation_index()); TabNavigationItem item(session_tag, tab.tab_id, current_navigation.title(), current_navigation.virtual_url()); - int command_id = TabVectorIndexToCommandId( - other_devices_tab_navigation_items_.size(), - kFirstOtherDevicesTabCommandId); + const int command_id = + TabVectorIndexToCommandId(other_devices_tab_navigation_items_.size(), + kFirstOtherDevicesTabCommandId); // See comments in BuildTabsFromOtherDevices() about usage of AddItem*(). // There may be no tab title, in which case, use the url as tab title. AddItem(command_id, @@ -625,6 +678,43 @@ other_devices_tab_navigation_items_.push_back(item); } +std::unique_ptr<ui::SimpleMenuModel> +RecentTabsSubMenuModel::CreateWindowSubMenuModel( + const sessions::TabRestoreService::Window& window) { + std::unique_ptr<ui::SimpleMenuModel> window_model = + std::make_unique<ui::SimpleMenuModel>(this); + const int command_id = + WindowVectorIndexToCommandId(local_window_items_.size()); + window_model->AddItemWithStringIdAndIcon( + command_id, IDS_RESTORE_ALL_TABS, + ui::ImageModel::FromVectorIcon(vector_icons::kLaunchIcon)); + local_window_items_.push_back(window.id); + return window_model; +} + +std::unique_ptr<ui::SimpleMenuModel> +RecentTabsSubMenuModel::CreateGroupSubMenuModel( + const sessions::TabRestoreService::Group& group) { + std::unique_ptr<ui::SimpleMenuModel> group_model = + std::make_unique<ui::SimpleMenuModel>(this); + const int command_id = GroupVectorIndexToCommandId(local_group_items_.size()); + group_model->AddItemWithStringIdAndIcon( + command_id, IDS_RESTORE_ALL_TABS, + ui::ImageModel::FromVectorIcon(vector_icons::kLaunchIcon)); + local_group_items_.push_back(group.id); + return group_model; +} + +int RecentTabsSubMenuModel::GetParentCommandId(int command_id) const { + for (const SubMenuItem& sub_menu_item : local_sub_menu_items_) { + if (sub_menu_item.child_ids.find(command_id) != + sub_menu_item.child_ids.end()) { + return sub_menu_item.parent_id; + } + } + return -1; +} + void RecentTabsSubMenuModel::AddDeviceFavicon( int index_in_menu, sync_pb::SyncEnums::DeviceType device_type) { @@ -652,13 +742,13 @@ } void RecentTabsSubMenuModel::AddTabFavicon(int command_id, const GURL& url) { - int index_in_menu = GetIndexOfCommandId(command_id); + const int index_in_menu = GetIndexOfCommandId(command_id); // Set default icon first. SetIcon(index_in_menu, ui::ImageModel::FromImage(favicon::GetDefaultFavicon())); - bool is_local_tab = command_id < kFirstOtherDevicesTabCommandId; + const bool is_local_tab = command_id < kFirstOtherDevicesTabCommandId; if (is_local_tab) { // Request only from local storage to avoid leaking user data. favicon::FaviconService* favicon_service = @@ -697,7 +787,7 @@ // Default icon has already been set. return; } - int index_in_menu = GetIndexOfCommandId(command_id); + const int index_in_menu = GetIndexOfCommandId(command_id); DCHECK_GT(index_in_menu, -1); SetIcon(index_in_menu, ui::ImageModel::FromImage(image_result.image)); ui::MenuModelDelegate* delegate = menu_model_delegate(); @@ -732,11 +822,14 @@ // Remove all local window items. local_window_items_.clear(); + + // Remove all local sub menu items. + local_sub_menu_items_.clear(); } void RecentTabsSubMenuModel::ClearTabsFromOtherDevices() { DCHECK_GE(last_local_model_index_, 0); - int count = GetItemCount(); + const int count = GetItemCount(); for (int index = count - 1; index > last_local_model_index_; --index) RemoveItemAt(index);
diff --git a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.h b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.h index 064e38f..041c858 100644 --- a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.h +++ b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.h
@@ -81,6 +81,8 @@ using TabNavigationItems = std::vector<TabNavigationItem>; using WindowItems = std::vector<SessionID>; using GroupItems = std::vector<SessionID>; + struct SubMenuItem; + using SubMenuItems = std::vector<SubMenuItem>; // Index of the separator that follows the history menu item. Used as a // reference position for inserting local entries. @@ -107,6 +109,7 @@ // Build the recently closed window item with parameters needed to restore it, // and add it to the menumodel at |curr_model_index|. void BuildLocalWindowItem(SessionID window_id, + std::unique_ptr<ui::SimpleMenuModel> window_model, int num_tabs, int curr_model_index); @@ -114,6 +117,7 @@ // and add it to the menumodel at |curr_model_index|. void BuildLocalGroupItem(SessionID session_id, tab_groups::TabGroupVisualData visual_data, + std::unique_ptr<ui::SimpleMenuModel> group_model, int num_tabs, int curr_model_index); @@ -121,6 +125,19 @@ void BuildOtherDevicesTabItem(const std::string& session_tag, const sessions::SessionTab& tab); + // Create a submenu model representing the tabs within a window. + std::unique_ptr<ui::SimpleMenuModel> CreateWindowSubMenuModel( + const sessions::TabRestoreService::Window& window); + + // Create a submenu model representing the tabs within a tab group. + std::unique_ptr<ui::SimpleMenuModel> CreateGroupSubMenuModel( + const sessions::TabRestoreService::Group& group); + + // Return the command id of the given id's parent submenu, if it has one that + // is created by this menu model. Otherwise, return -1. This will be the case + // for all items whose parent is the RecentTabsSubMenuModel itself. + int GetParentCommandId(int command_id) const; + // Add the favicon for the device section header. void AddDeviceFavicon(int index_in_menu, sync_pb::SyncEnums::DeviceType device_type); @@ -187,6 +204,12 @@ // |local_group_items_| and used to create the specified group. GroupItems local_group_items_; + // SubMenu items for submenu entry points representing local recently + // closed groups and windows. The |command_id| for these is set to + // |kFirstLocalSubMenuCommandId| plus the index into the vector. These are + // not executable. + SubMenuItems local_sub_menu_items_; + // Index of the last local entry (recently closed tab or window or group) in // the menumodel. int last_local_model_index_ = kHistorySeparatorIndex;
diff --git a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model_unittest.cc b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model_unittest.cc index 1a306e3..55816dfb4 100644 --- a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model_unittest.cc +++ b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model_unittest.cc
@@ -303,7 +303,9 @@ EXPECT_TRUE(model.IsEnabledAt(1)); EXPECT_FALSE(model.IsEnabledAt(2)); EXPECT_TRUE(model.IsEnabledAt(3)); + EXPECT_EQ(ui::MenuModel::TYPE_SUBMENU, model.GetTypeAt(3)); EXPECT_TRUE(model.IsEnabledAt(4)); + EXPECT_EQ(ui::MenuModel::TYPE_SUBMENU, model.GetTypeAt(4)); model.ActivatedAt(3); model.ActivatedAt(4); EXPECT_FALSE(model.IsEnabledAt(6)); @@ -420,6 +422,7 @@ EXPECT_EQ(ui::MenuModel::TYPE_SEPARATOR, model.GetTypeAt(1)); EXPECT_FALSE(model.IsEnabledAt(2)); EXPECT_TRUE(model.IsEnabledAt(3)); + EXPECT_EQ(ui::MenuModel::TYPE_SUBMENU, model.GetTypeAt(3)); EXPECT_TRUE(model.IsEnabledAt(4)); EXPECT_TRUE(model.IsEnabledAt(5)); model.ActivatedAt(3);
diff --git a/chrome/browser/ui/views/accessibility/caption_bubble_controller_views.cc b/chrome/browser/ui/views/accessibility/caption_bubble_controller_views.cc index 5dabb0a..54d97ad 100644 --- a/chrome/browser/ui/views/accessibility/caption_bubble_controller_views.cc +++ b/chrome/browser/ui/views/accessibility/caption_bubble_controller_views.cc
@@ -8,8 +8,8 @@ #include <string> #include "base/bind.h" -#include "chrome/browser/accessibility/caption_controller.h" -#include "chrome/browser/accessibility/caption_controller_factory.h" +#include "chrome/browser/accessibility/live_caption_controller.h" +#include "chrome/browser/accessibility/live_caption_controller_factory.h" #include "chrome/browser/accessibility/live_caption_speech_recognition_host.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_finder.h"
diff --git a/chrome/browser/ui/views/autofill/address_editor_view.cc b/chrome/browser/ui/views/autofill/address_editor_view.cc index 599757c..e421535 100644 --- a/chrome/browser/ui/views/autofill/address_editor_view.cc +++ b/chrome/browser/ui/views/autofill/address_editor_view.cc
@@ -50,63 +50,44 @@ void AddressEditorView::CreateEditorView() { text_fields_.clear(); - constexpr int kRowHorizontalInsets = 16; - // The editor view is padded horizontally. - SetBorder(views::CreateEmptyBorder(0, kRowHorizontalInsets, 0, - kRowHorizontalInsets)); - - // All views have fixed size except the Field which stretches. The fixed - // padding at the end is computed so that Field views have a minimum of - // 176/272dp (short/long fields) as per spec. - // ______________________________________________________ - // |Label | 16dp pad | Field (flex) | Computed Padding | - // |______|__________|______________|___________________| + // Field views have a width of 196/260dp (short/long fields) as per spec. + // __________________________________ + // |Label | 16dp pad | Field (flex) | + // |______|__________|______________| constexpr int kLabelWidth = 140; - constexpr int kDialogMinWidth = 512; // This is the horizontal padding between the label and the field. constexpr int kLabelInputFieldHorizontalPadding = 16; - constexpr int kShortFieldMinimumWidth = 176; - constexpr int kLongFieldMinimumWidth = 272; + constexpr int kShortFieldWidth = 196; + constexpr int kLongFieldWidth = 260; using ColumnSize = views::GridLayout::ColumnSize; views::GridLayout* editor_layout = SetLayoutManager(std::make_unique<views::GridLayout>()); // Column set for short fields. - views::ColumnSet* columns_short = editor_layout->AddColumnSet(0); + views::ColumnSet* columns_short = editor_layout->AddColumnSet( + /*id=*/static_cast<int>(EditorField::LengthHint::HINT_SHORT)); columns_short->AddColumn( views::GridLayout::LEADING, views::GridLayout::CENTER, views::GridLayout::kFixedSize, ColumnSize::kFixed, kLabelWidth, 0); columns_short->AddPaddingColumn(views::GridLayout::kFixedSize, kLabelInputFieldHorizontalPadding); - // The field view column stretches. columns_short->AddColumn(views::GridLayout::LEADING, - views::GridLayout::CENTER, 1.0, - ColumnSize::kUsePreferred, 0, 0); - // The padding at the end is fixed, computed to make sure the short field - // maintains its minimum width. - int short_padding = kDialogMinWidth - kShortFieldMinimumWidth - kLabelWidth - - (2 * kRowHorizontalInsets) - - kLabelInputFieldHorizontalPadding; - columns_short->AddPaddingColumn(views::GridLayout::kFixedSize, short_padding); + views::GridLayout::CENTER, + views::GridLayout::kFixedSize, ColumnSize::kFixed, + kShortFieldWidth, /*min_width=*/0); // Column set for long fields. - views::ColumnSet* columns_long = editor_layout->AddColumnSet(1); + views::ColumnSet* columns_long = editor_layout->AddColumnSet( + /*id=*/static_cast<int>(EditorField::LengthHint::HINT_LONG)); columns_long->AddColumn(views::GridLayout::LEADING, views::GridLayout::CENTER, views::GridLayout::kFixedSize, ColumnSize::kFixed, kLabelWidth, 0); columns_long->AddPaddingColumn(views::GridLayout::kFixedSize, kLabelInputFieldHorizontalPadding); - // The field view column stretches. columns_long->AddColumn(views::GridLayout::LEADING, views::GridLayout::CENTER, - 1.0, ColumnSize::kUsePreferred, 0, 0); - - // The padding at the end is fixed, computed to make sure the long field - // maintains its minimum width. - int long_padding = kDialogMinWidth - kLongFieldMinimumWidth - kLabelWidth - - (2 * kRowHorizontalInsets) - - kLabelInputFieldHorizontalPadding; - columns_long->AddPaddingColumn(views::GridLayout::kFixedSize, long_padding); + views::GridLayout::kFixedSize, ColumnSize::kFixed, + kLongFieldWidth, /*min_width=*/0); for (const auto& field : controller_->editor_fields()) { CreateInputField(editor_layout, field); @@ -119,13 +100,12 @@ // +----------------------------------------------------------+ views::View* AddressEditorView::CreateInputField(views::GridLayout* layout, const EditorField& field) { - int column_set = - field.length_hint == EditorField::LengthHint::HINT_SHORT ? 0 : 1; - // This is the top padding for every row. constexpr int kInputRowSpacing = 6; - layout->StartRowWithPadding(views::GridLayout::kFixedSize, column_set, - views::GridLayout::kFixedSize, kInputRowSpacing); + layout->StartRowWithPadding( + views::GridLayout::kFixedSize, + /*column_set_id=*/static_cast<int>(field.length_hint), + views::GridLayout::kFixedSize, kInputRowSpacing); std::unique_ptr<views::Label> label = std::make_unique<views::Label>(field.label);
diff --git a/chrome/browser/ui/views/location_bar/content_setting_image_view.cc b/chrome/browser/ui/views/location_bar/content_setting_image_view.cc index cb45c14..07afb24e 100644 --- a/chrome/browser/ui/views/location_bar/content_setting_image_view.cc +++ b/chrome/browser/ui/views/location_bar/content_setting_image_view.cc
@@ -241,7 +241,7 @@ IDS_NOTIFICATIONS_QUIET_PERMISSION_NEW_REQUEST_PROMO; bubble_params.anchor_view = this; bubble_params.arrow = views::BubbleBorder::TOP_RIGHT; - bubble_params.allow_focus = true; + bubble_params.focus_on_create = true; bubble_params.persist_on_blur = false; bubble_params.preferred_width = promo_width;
diff --git a/chrome/browser/ui/views/passwords/password_save_update_with_account_store_view.cc b/chrome/browser/ui/views/passwords/password_save_update_with_account_store_view.cc index 805f53b..a06b1a58 100644 --- a/chrome/browser/ui/views/passwords/password_save_update_with_account_store_view.cc +++ b/chrome/browser/ui/views/passwords/password_save_update_with_account_store_view.cc
@@ -673,9 +673,9 @@ FeaturePromoBubbleParams bubble_params; bubble_params.anchor_view = destination_dropdown_; bubble_params.arrow = views::BubbleBorder::RIGHT_CENTER; - bubble_params.preferred_width = kAccountStoragePromoWidth; - bubble_params.allow_focus = true; + bubble_params.focus_on_create = true; bubble_params.persist_on_blur = false; + bubble_params.preferred_width = kAccountStoragePromoWidth; bubble_params.timeout_default = GetRegularIPHTimeout(); bubble_params.timeout_short = GetShortIPHTimeout();
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc index cf21a73..1ae42fa 100644 --- a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc +++ b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
@@ -2539,6 +2539,9 @@ ASSERT_TRUE(PressInput(tab_1_center)); ASSERT_TRUE(DragInputTo(tab_1_center + gfx::Vector2d(TabStyle::GetStandardWidth(), 0))); + BrowserView::GetBrowserViewForBrowser(browser()) + ->GetWidget() + ->LayoutRootViewIfNecessary(); EXPECT_EQ(tab_strip_width + TabStyle::GetStandardWidth(), tab_strip->width()); ASSERT_TRUE(ReleaseInput()); }
diff --git a/chrome/browser/ui/views/tabs/tab_icon.cc b/chrome/browser/ui/views/tabs/tab_icon.cc index 7317e662..55545e1 100644 --- a/chrome/browser/ui/views/tabs/tab_icon.cc +++ b/chrome/browser/ui/views/tabs/tab_icon.cc
@@ -41,16 +41,6 @@ constexpr int kAttentionIndicatorRadius = 3; constexpr int kLoadingAnimationStrokeWidthDp = 2; -// Returns whether the favicon for the given URL should be colored according to -// the browser theme. -bool ShouldThemifyFaviconForUrl(const GURL& url) { - return url.SchemeIs(content::kChromeUIScheme) && - url.host_piece() != chrome::kChromeUIAppLauncherPageHost && - url.host_piece() != chrome::kChromeUIHelpHost && - url.host_piece() != chrome::kChromeUIVersionHost && - url.host_piece() != chrome::kChromeUINetExportHost; -} - bool NetworkStateIsAnimated(TabNetworkState network_state) { return network_state != TabNetworkState::kNone && network_state != TabNetworkState::kError; @@ -109,7 +99,7 @@ const bool was_showing_load = GetShowingLoadingAnimation(); inhibit_loading_animation_ = data.should_hide_throbber; - SetIcon(data.visible_url, data.favicon); + SetIcon(data.favicon, data.should_themify_favicon); SetNetworkState(data.network_state); SetCrashed(data.IsCrashed()); has_tab_renderer_data_ = true; @@ -361,7 +351,7 @@ favicon::GetDefaultFavicon().AsImageSkia()); } -void TabIcon::SetIcon(const GURL& url, const gfx::ImageSkia& icon) { +void TabIcon::SetIcon(const gfx::ImageSkia& icon, bool should_themify_favicon) { // Detect when updating to the same icon. This avoids re-theming and // re-painting. if (favicon_.BackedBySameObjectAs(icon)) @@ -369,7 +359,7 @@ favicon_ = icon; - if (!GetNonDefaultFavicon() || ShouldThemifyFaviconForUrl(url)) { + if (!GetNonDefaultFavicon() || should_themify_favicon) { themed_favicon_ = ThemeImage(icon); } else { themed_favicon_ = gfx::ImageSkia();
diff --git a/chrome/browser/ui/views/tabs/tab_icon.h b/chrome/browser/ui/views/tabs/tab_icon.h index 76a6c5fb..f8f4a3e 100644 --- a/chrome/browser/ui/views/tabs/tab_icon.h +++ b/chrome/browser/ui/views/tabs/tab_icon.h
@@ -18,7 +18,6 @@ class TickClock; } -class GURL; struct TabRendererData; // View that displays the favicon, sad tab, throbber, and attention indicator @@ -99,8 +98,8 @@ const gfx::Rect& bounds); bool GetNonDefaultFavicon() const; - // Sets the icon. Depending on the URL the icon may be automatically themed. - void SetIcon(const GURL& url, const gfx::ImageSkia& favicon); + // Sets the icon. + void SetIcon(const gfx::ImageSkia& icon, bool should_themify_favicon); // For certain types of tabs the loading animation is not desired so the // caller can set inhibit_loading_animation to true. When false, the loading
diff --git a/chrome/browser/ui/views/user_education/feature_promo_bubble_params.h b/chrome/browser/ui/views/user_education/feature_promo_bubble_params.h index b4dda25..7841a1ca 100644 --- a/chrome/browser/ui/views/user_education/feature_promo_bubble_params.h +++ b/chrome/browser/ui/views/user_education/feature_promo_bubble_params.h
@@ -66,15 +66,13 @@ // possible. absl::optional<int> preferred_width; - // Determines if this bubble can be focused. If true, it will get - // focused on creation. - bool allow_focus = false; + // Determines if the bubble will get focused on creation. + bool focus_on_create = false; // Determines if this bubble will be dismissed when it loses focus. - // Only meaningful when |allow_focus| is true. When |allow_focus| - // is false, the bubble will always persist because it will never - // get blurred. - bool persist_on_blur = false; + // Only meaningful when |focus_on_create| is true. If it's false then it + // starts out blurred. + bool persist_on_blur = true; // Determines if this IPH can be snoozed and reactivated later. // If true, |allow_focus| must be true for keyboard accessibility.
diff --git a/chrome/browser/ui/views/user_education/feature_promo_bubble_view.cc b/chrome/browser/ui/views/user_education/feature_promo_bubble_view.cc index 489f0d9..a48a2893 100644 --- a/chrome/browser/ui/views/user_education/feature_promo_bubble_view.cc +++ b/chrome/browser/ui/views/user_education/feature_promo_bubble_view.cc
@@ -182,15 +182,10 @@ : BubbleDialogDelegateView(params.anchor_view, params.arrow, views::BubbleBorder::STANDARD_SHADOW), - focusable_(params.focusable), - persist_on_blur_(params.persist_on_blur), preferred_width_(params.preferred_width) { DCHECK(params.anchor_view); - DCHECK(params.buttons.empty() || params.focusable) - << "A snoozable bubble must be focusable to allow keyboard " - "accessibility."; - DCHECK(!params.persist_on_blur || params.focusable) - << "A bubble that persists on blur must be focusable."; + DCHECK(params.persist_on_blur || params.focus_on_create) + << "A bubble that closes on blur must be initially focused."; UseCompactMargins(); // Bubble will not auto-dismiss if there's buttons. @@ -321,10 +316,7 @@ } } - if (!focusable_) - SetCanActivate(false); - - set_close_on_deactivate(!persist_on_blur_); + set_close_on_deactivate(!params.persist_on_blur); set_margins(gfx::Insets()); set_title_margins(gfx::Insets()); @@ -338,7 +330,11 @@ ChromeLayoutProvider::Get()->GetCornerRadiusMetric( views::Emphasis::kHigh)); - widget->Show(); + if (params.focus_on_create) + widget->Show(); + else + widget->ShowInactive(); + if (feature_promo_bubble_timeout_) feature_promo_bubble_timeout_->OnBubbleShown(this); }
diff --git a/chrome/browser/ui/views/user_education/feature_promo_bubble_view.h b/chrome/browser/ui/views/user_education/feature_promo_bubble_view.h index e5234c9..f2d5f7e4 100644 --- a/chrome/browser/ui/views/user_education/feature_promo_bubble_view.h +++ b/chrome/browser/ui/views/user_education/feature_promo_bubble_view.h
@@ -66,8 +66,8 @@ absl::optional<int> preferred_width; - bool focusable = false; - bool persist_on_blur = false; + bool focus_on_create = false; + bool persist_on_blur = true; // Determines how progress indicators for tutorials will be rendered. If not // provided, no progress indicator will be visible. @@ -105,16 +105,6 @@ } gfx::Size CalculatePreferredSize() const override; - // Determines if this bubble can be focused. If true, it will get - // focus on creation. - bool focusable_ = false; - - // Determines if this bubble will be dismissed when it loses focus. - // Only meaningful when |focusable_| is true. When |allow_focus| - // is false, the bubble will always persist because it will never - // get blurred. - bool persist_on_blur_ = false; - // If the bubble has buttons, it must be focusable. std::vector<views::MdTextButton*> buttons_;
diff --git a/chrome/browser/ui/views/user_education/feature_promo_bubble_view_interactive_uitest.cc b/chrome/browser/ui/views/user_education/feature_promo_bubble_view_interactive_uitest.cc new file mode 100644 index 0000000..44add555 --- /dev/null +++ b/chrome/browser/ui/views/user_education/feature_promo_bubble_view_interactive_uitest.cc
@@ -0,0 +1,68 @@ +// Copyright 2021 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/user_education/feature_promo_bubble_view.h" + +#include "chrome/browser/ui/view_ids.h" +#include "chrome/browser/ui/views/frame/browser_view.h" +#include "chrome/browser/ui/views/toolbar/browser_app_menu_button.h" +#include "chrome/browser/ui/views/toolbar/toolbar_view.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "chrome/test/base/interactive_test_utils.h" +#include "content/public/test/browser_test.h" +#include "ui/views/focus/focus_manager.h" +#include "ui/views/test/widget_test.h" + +class FeaturePromoBubbleViewInteractiveTest : public InProcessBrowserTest { + public: + FeaturePromoBubbleViewInteractiveTest() = default; + ~FeaturePromoBubbleViewInteractiveTest() override = default; + + protected: + FeaturePromoBubbleView::CreateParams GetBubbleParams() { + FeaturePromoBubbleView::CreateParams params; + params.body_text = u"To X, do Y"; + params.anchor_view = BrowserView::GetBrowserViewForBrowser(browser()) + ->toolbar() + ->app_menu_button(); + params.arrow = views::BubbleBorder::TOP_RIGHT; + params.timeout_default = absl::nullopt; + params.timeout_short = absl::nullopt; + return params; + } +}; + +IN_PROC_BROWSER_TEST_F(FeaturePromoBubbleViewInteractiveTest, + WidgetNotActivatedByDefault) { + auto params = GetBubbleParams(); + params.focus_on_create = false; + + auto* const browser_view = BrowserView::GetBrowserViewForBrowser(browser()); + auto* const focus_manager = browser_view->GetWidget()->GetFocusManager(); + EXPECT_TRUE(browser_view->GetWidget()->IsActive()); + + browser_view->FocusToolbar(); + views::View* const initial_focused_view = focus_manager->GetFocusedView(); + EXPECT_NE(nullptr, initial_focused_view); + + auto* const bubble = FeaturePromoBubbleView::Create(std::move(params)); + views::test::WidgetVisibleWaiter(bubble->GetWidget()).Wait(); + + EXPECT_TRUE(browser_view->GetWidget()->IsActive()); + EXPECT_FALSE(bubble->GetWidget()->IsActive()); +} + +IN_PROC_BROWSER_TEST_F(FeaturePromoBubbleViewInteractiveTest, + WidgetActivatedWhenRequested) { + auto params = GetBubbleParams(); + params.focus_on_create = true; + + auto* const browser_view = BrowserView::GetBrowserViewForBrowser(browser()); + EXPECT_TRUE(browser_view->GetWidget()->IsActive()); + + auto* const bubble = FeaturePromoBubbleView::Create(std::move(params)); + views::test::WidgetVisibleWaiter(bubble->GetWidget()).Wait(); + + EXPECT_TRUE(bubble->GetWidget()->IsActive()); +}
diff --git a/chrome/browser/ui/views/user_education/feature_promo_bubble_view_unittest.cc b/chrome/browser/ui/views/user_education/feature_promo_bubble_view_unittest.cc index 5e73fd8..ae61e43 100644 --- a/chrome/browser/ui/views/user_education/feature_promo_bubble_view_unittest.cc +++ b/chrome/browser/ui/views/user_education/feature_promo_bubble_view_unittest.cc
@@ -39,7 +39,7 @@ params.arrow = views::BubbleBorder::TOP_RIGHT; if (button_callback) { - params.focusable = true; + params.focus_on_create = true; params.persist_on_blur = true; FeaturePromoBubbleView::ButtonParams button_params;
diff --git a/chrome/browser/ui/views/user_education/feature_promo_controller_views.cc b/chrome/browser/ui/views/user_education/feature_promo_controller_views.cc index 3f9edac..6eddedab 100644 --- a/chrome/browser/ui/views/user_education/feature_promo_controller_views.cc +++ b/chrome/browser/ui/views/user_education/feature_promo_controller_views.cc
@@ -275,7 +275,7 @@ l10n_util::GetStringUTF16(*params.screenreader_string_specifier); } - create_params.focusable = params.allow_focus; + create_params.focus_on_create = params.focus_on_create; create_params.persist_on_blur = params.persist_on_blur; create_params.arrow = params.arrow;
diff --git a/chrome/browser/ui/views/user_education/feature_promo_registry.cc b/chrome/browser/ui/views/user_education/feature_promo_registry.cc index 6c315d2..299f3c7a 100644 --- a/chrome/browser/ui/views/user_education/feature_promo_registry.cc +++ b/chrome/browser/ui/views/user_education/feature_promo_registry.cc
@@ -198,8 +198,7 @@ // Turn on IPH Snooze for Tab Group. if (base::FeatureList::IsEnabled( feature_engagement::kIPHDesktopSnoozeFeature)) { - params.allow_focus = true; - params.persist_on_blur = true; + params.focus_on_create = true; params.allow_snooze = true; } @@ -227,9 +226,6 @@ IDS_PROFILE_SWITCH_PROMO_SCREENREADER; params.feature_command_id = IDC_SHOW_AVATAR_MENU; params.arrow = views::BubbleBorder::Arrow::TOP_RIGHT; - // Focusable for accessibility (https://crbug.com/1198049). - params.allow_focus = true; - params.persist_on_blur = true; RegisterFeature(feature_engagement::kIPHProfileSwitchFeature, params, base::BindRepeating(GetAvatarToolbarButton)); @@ -255,8 +251,7 @@ // Turn on IPH Snooze for Read Later entry point. if (base::FeatureList::IsEnabled( feature_engagement::kIPHDesktopSnoozeFeature)) { - params.allow_focus = true; - params.persist_on_blur = true; + params.focus_on_create = true; params.allow_snooze = true; }
diff --git a/chrome/browser/ui/views/user_education/tutorial_dialog_browsertest.cc b/chrome/browser/ui/views/user_education/tutorial_dialog_browsertest.cc index e74230b..0de3f41 100644 --- a/chrome/browser/ui/views/user_education/tutorial_dialog_browsertest.cc +++ b/chrome/browser/ui/views/user_education/tutorial_dialog_browsertest.cc
@@ -22,7 +22,6 @@ params.anchor_view = browser_view->toolbar()->app_menu_button(); params.arrow = views::BubbleBorder::TOP_RIGHT; params.body_text = u"Hello world, I am a tutorial"; - params.focusable = true; params.persist_on_blur = true; params.tutorial_progress_current = 3; params.tutorial_progress_max = 5;
diff --git a/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_base.cc b/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_base.cc index 8505595..8c275f2 100644 --- a/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_base.cc +++ b/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_base.cc
@@ -411,10 +411,20 @@ if (action_base == "add_policy_app_internal_tabbed") { AddPolicyAppInternal(action_param, - base::Value(kDefaultLaunchContainerTabValue)); + base::Value(kDefaultLaunchContainerTabValue), + /*create_shortcut=*/true); + } else if (action_base == "add_policy_app_internal_tabbed_no_shortcut") { + AddPolicyAppInternal(action_param, + base::Value(kDefaultLaunchContainerTabValue), + /*create_shortcut=*/false); } else if (action_base == "add_policy_app_internal_windowed") { AddPolicyAppInternal(action_param, - base::Value(kDefaultLaunchContainerWindowValue)); + base::Value(kDefaultLaunchContainerWindowValue), + /*create_shortcut=*/true); + } else if (action_base == "add_policy_app_internal_windowed_no_shortcut") { + AddPolicyAppInternal(action_param, + base::Value(kDefaultLaunchContainerWindowValue), + /*create_shortcut=*/false); } else if (action_base == "close_pwa") { ClosePWA(); } else if (action_base == "install_create_shortcut_tabbed") { @@ -510,7 +520,8 @@ // Automated Testing Actions void WebAppIntegrationBrowserTestBase::AddPolicyAppInternal( const std::string& action_param, - base::Value default_launch_container) { + base::Value default_launch_container, + const bool create_shortcut) { GURL url = GetInstallableAppURL(action_param); auto* web_app_registrar = WebAppProvider::Get(profile())->registrar().AsWebAppRegistrar(); @@ -531,6 +542,7 @@ item.SetKey(kUrlKey, base::Value(url.spec())); item.SetKey(kDefaultLaunchContainerKey, std::move(default_launch_container)); + item.SetKey(kCreateDesktopShortcutKey, base::Value(create_shortcut)); ListPrefUpdate update(profile()->GetPrefs(), prefs::kWebAppInstallForceList); update->Append(item.Clone());
diff --git a/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_base.h b/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_base.h index c938a4b..0b9e383 100644 --- a/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_base.h +++ b/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_base.h
@@ -150,7 +150,8 @@ // Automated Testing Actions void AddPolicyAppInternal(const std::string& action_param, - base::Value default_launch_container); + base::Value default_launch_container, + const bool create_shortcut); void ClosePWA(); void InstallCreateShortcut(bool open_in_window); void InstallLocally();
diff --git a/chrome/browser/ui/webui/app_management/app_management_page_handler.cc b/chrome/browser/ui/webui/app_management/app_management_page_handler.cc index 9c90b090..99f5ec36 100644 --- a/chrome/browser/ui/webui/app_management/app_management_page_handler.cc +++ b/chrome/browser/ui/webui/app_management/app_management_page_handler.cc
@@ -42,7 +42,8 @@ }; constexpr char const* kAppIdsWithHiddenPinToShelf[] = { - extension_misc::kChromeAppId, + extension_misc::kChromeAppId, + extension_misc::kLacrosAppId, }; #if BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/ui/webui/chromeos/cellular_setup/cellular_setup_localized_strings_provider.cc b/chrome/browser/ui/webui/chromeos/cellular_setup/cellular_setup_localized_strings_provider.cc index 2073bbf..d618c6d 100644 --- a/chrome/browser/ui/webui/chromeos/cellular_setup/cellular_setup_localized_strings_provider.cc +++ b/chrome/browser/ui/webui/chromeos/cellular_setup/cellular_setup_localized_strings_provider.cc
@@ -57,7 +57,8 @@ IDS_CELLULAR_SETUP_ESIM_FINAL_PAGE_ERROR_MESSAGE}, {"eSimProfileDetectMessage", IDS_CELLULAR_SETUP_ESIM_PROFILE_DETECT_MESSAGE}, - {"eSimConnectionWarning", IDS_CELLULAR_SETUP_ESIM_CONNECTION_WARNING}, + {"eSimProfileDetectDuringActiveCellularConnectionMessage", + IDS_CELLULAR_SETUP_ESIM_PROFILE_DETECT_DURING_ACTIVE_CELLULAR_CONNECTION_MESSAGE}, {"scanQRCode", IDS_CELLULAR_SETUP_ESIM_PAGE_SCAN_QR_CODE}, {"scanQRCodeEnterActivationCode", IDS_CELLULAR_SETUP_ESIM_PAGE_SCAN_QR_CODE_ENTER_ACTIVATION_CODE},
diff --git a/chrome/browser/web_applications/components/web_app_helpers.cc b/chrome/browser/web_applications/components/web_app_helpers.cc index a39db1b..fcbfc9f 100644 --- a/chrome/browser/web_applications/components/web_app_helpers.cc +++ b/chrome/browser/web_applications/components/web_app_helpers.cc
@@ -69,8 +69,10 @@ // <start_url_origin>/<manifest_id>. // Note: start_url.GetOrigin().spec() returns the origin ending with slash. if (manifest_id.has_value()) { - return crx_file::id_util::GenerateId(crypto::SHA256HashString( - start_url.GetOrigin().spec() + manifest_id.value())); + GURL app_id(start_url.GetOrigin().spec() + manifest_id.value()); + DCHECK(app_id.is_valid()); + return crx_file::id_util::GenerateId( + crypto::SHA256HashString(app_id.spec())); } return GenerateAppIdFromURL(start_url); }
diff --git a/chrome/browser/web_applications/components/web_app_helpers_unittest.cc b/chrome/browser/web_applications/components/web_app_helpers_unittest.cc index 1b4194f..f6a871dd7 100644 --- a/chrome/browser/web_applications/components/web_app_helpers_unittest.cc +++ b/chrome/browser/web_applications/components/web_app_helpers_unittest.cc
@@ -72,4 +72,18 @@ GURL("filesystem:http://example.com/path/file.html"))); } +TEST(WebAppHelpers, ManifestIdEncoding) { + GURL start_url("https://example.com/abc"); + // ASCII character. + EXPECT_EQ(GenerateAppId("j", start_url), GenerateAppId("%6a", start_url)); + EXPECT_EQ(GenerateAppId("%6Ax", start_url), GenerateAppId("%6ax", start_url)); + + // Special characters. + EXPECT_EQ(GenerateAppId("a😀b", start_url), + GenerateAppId("a%F0%9F%98%80b", start_url)); + EXPECT_EQ(GenerateAppId("a b", start_url), GenerateAppId("a%20b", start_url)); + + // "/"" is excluded from encoding according to url spec. + EXPECT_NE(GenerateAppId("a/b", start_url), GenerateAppId("a%2Fb", start_url)); +} } // namespace web_app
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index b3424ee..228bb12 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-master-1621447189-bda12fafea78e5ddeafef2f6099b794eeb4ffb44.profdata +chrome-win32-master-1621457572-e60d595e49521ac06da03b86bcaef384d8be53cc.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index 69715c0..a4d1a92d 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-master-1621447189-0acc1aeb3b834bdede092c7b4e776bb25a5fa9c0.profdata +chrome-win64-master-1621457572-764acf1b3fb28a91d1007d86e7f3479c23440a11.profdata
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc index bbdfc370..a10f7f9 100644 --- a/chrome/common/chrome_features.cc +++ b/chrome/common/chrome_features.cc
@@ -20,7 +20,7 @@ // If enabled device status collector will add the type of session (Affiliated // User, Kiosks, Managed Guest Sessions) to the device status report. const base::Feature kActivityReportingSessionType{ - "ActivityReportingSessionType", base::FEATURE_DISABLED_BY_DEFAULT}; + "ActivityReportingSessionType", base::FEATURE_ENABLED_BY_DEFAULT}; #endif // defined(IS_CHROMEOS_ASH) #if BUILDFLAG(IS_CHROMEOS_ASH) @@ -748,14 +748,8 @@ "PredictivePrefetchingAllowedOnAllConnectionTypes", base::FEATURE_ENABLED_BY_DEFAULT}; -const base::Feature kPrefixWebAppWindowsWithAppName { - "PrefixWebAppWindowsWithAppName", -#if BUILDFLAG(IS_CHROMEOS_ASH) - base::FEATURE_ENABLED_BY_DEFAULT -#else - base::FEATURE_DISABLED_BY_DEFAULT -#endif -}; +const base::Feature kPrefixWebAppWindowsWithAppName{ + "PrefixWebAppWindowsWithAppName", base::FEATURE_DISABLED_BY_DEFAULT}; // Allows Chrome to do preconnect when prerender fails. const base::Feature kPrerenderFallbackToPreconnect{
diff --git a/chrome/common/extensions/api/_api_features.json b/chrome/common/extensions/api/_api_features.json index 6f36f6a..e503946 100644 --- a/chrome/common/extensions/api/_api_features.json +++ b/chrome/common/extensions/api/_api_features.json
@@ -591,10 +591,6 @@ "chrome://settings/*" ] }], - "launcherSearchProvider": { - "dependencies": ["permission:launcherSearchProvider"], - "contexts": ["blessed_extension"] - }, "login": { "dependencies": ["permission:login"], "contexts": ["blessed_extension"],
diff --git a/chrome/common/extensions/api/_permission_features.json b/chrome/common/extensions/api/_permission_features.json index 0853789..5701a97 100644 --- a/chrome/common/extensions/api/_permission_features.json +++ b/chrome/common/extensions/api/_permission_features.json
@@ -430,14 +430,6 @@ "extension_types": ["extension", "platform_app"], "location": "component" }, - "launcherSearchProvider": { - "channel": "stable", - "extension_types": ["extension", "platform_app"], - "platforms": ["chromeos"], - "allowlist": [ - "A948368FC53BE437A55FEB414106E207925482F5" // File Manager - ] - }, "lockWindowFullscreenPrivate": { "channel": "stable", "component_extensions_auto_granted": false,
diff --git a/chrome/common/extensions/api/api_sources.gni b/chrome/common/extensions/api/api_sources.gni index ec83475..27fc40b 100644 --- a/chrome/common/extensions/api/api_sources.gni +++ b/chrome/common/extensions/api/api_sources.gni
@@ -100,7 +100,6 @@ "file_system_provider_internal.idl", "input_ime.json", "input_method_private.json", - "launcher_search_provider.idl", "login.idl", "login_screen_storage.idl", "login_screen_ui.idl",
diff --git a/chrome/common/extensions/api/launcher_search_provider.idl b/chrome/common/extensions/api/launcher_search_provider.idl deleted file mode 100644 index 2521a83..0000000 --- a/chrome/common/extensions/api/launcher_search_provider.idl +++ /dev/null
@@ -1,45 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// An API to listen queries of the Chrome Launcher and provide search results -// to it. -[platforms=("chromeos"), - implemented_in="chrome/browser/chromeos/extensions/launcher_search_provider.h", - nodoc] -namespace launcherSearchProvider { - dictionary SearchResult { - DOMString itemId; - DOMString title; - // If iconType is not provided, a generic icon is used automatically. - DOMString? iconType; - // Relevance ranges from 0 to 4. 0 is the lowest relevance, 4 is highest. - long relevance; - }; - - interface Functions { - // Sets search result of this extension for the query. Setting a new search - // results overwrites any previous results of this extension. If queryId is - // invalid, the results are discarded. Since the space is limited, it is not - // guranteed that all provided results are shown to a user. The search - // results will be sorted by relevance, with ties broken by the order of the - // results in this list (highest priority first). - static void setSearchResults(long queryId, SearchResult[] results); - }; - - interface Events { - // Called when a user typed a query. maxResult is the maximum number of - // results the extension should provide. - static void onQueryStarted(long queryId, - DOMString query, - long maxResult); - - // Called when query of |queryId| is ended. After this call, - // setSearchResults no longer accept the results for queryId. - static void onQueryEnded(long queryId); - - // Called when a user clicks a search result which is provided by - // setSearchResults. - static void onOpenResult(DOMString itemId); - }; -};
diff --git a/chrome/common/extensions/permissions/chrome_api_permissions.cc b/chrome/common/extensions/permissions/chrome_api_permissions.cc index 2df23190..815285a1 100644 --- a/chrome/common/extensions/permissions/chrome_api_permissions.cc +++ b/chrome/common/extensions/permissions/chrome_api_permissions.cc
@@ -225,7 +225,6 @@ // Platform-app permissions. {APIPermissionID::kFileSystemProvider, "fileSystemProvider", APIPermissionInfo::kFlagDoesNotRequireManagedSessionFullLoginWarning}, - {APIPermissionID::kLauncherSearchProvider, "launcherSearchProvider"}, // Settings override permissions. {APIPermissionID::kHomepage, "homepage",
diff --git a/chrome/common/extensions/permissions/permission_set_unittest.cc b/chrome/common/extensions/permissions/permission_set_unittest.cc index 99e347da..46f95f0 100644 --- a/chrome/common/extensions/permissions/permission_set_unittest.cc +++ b/chrome/common/extensions/permissions/permission_set_unittest.cc
@@ -869,7 +869,6 @@ skip.insert(APIPermissionID::kSocket); skip.insert(APIPermissionID::kUsb); skip.insert(APIPermissionID::kVirtualKeyboard); - skip.insert(APIPermissionID::kLauncherSearchProvider); // The lock screen apps are set by user through settings, no need to warn at // installation time.
diff --git a/chrome/renderer/safe_browsing/phishing_classifier_browsertest.cc b/chrome/renderer/safe_browsing/phishing_classifier_browsertest.cc index 68d5f4c..d38db44 100644 --- a/chrome/renderer/safe_browsing/phishing_classifier_browsertest.cc +++ b/chrome/renderer/safe_browsing/phishing_classifier_browsertest.cc
@@ -104,7 +104,7 @@ // Add an empty visual target to ensure visual detection runs. model.mutable_vision_model()->add_targets(); - scorer_.reset(Scorer::Create(model.SerializeAsString())); + scorer_.reset(Scorer::Create(model.SerializeAsString(), base::File())); ASSERT_TRUE(scorer_.get()); }
diff --git a/chrome/renderer/safe_browsing/phishing_classifier_delegate_browsertest.cc b/chrome/renderer/safe_browsing/phishing_classifier_delegate_browsertest.cc index 12ef8e1..24b5d75 100644 --- a/chrome/renderer/safe_browsing/phishing_classifier_delegate_browsertest.cc +++ b/chrome/renderer/safe_browsing/phishing_classifier_delegate_browsertest.cc
@@ -7,6 +7,7 @@ #include <memory> #include "base/bind.h" +#include "base/files/scoped_temp_dir.h" #include "base/strings/utf_string_conversions.h" #include "chrome/test/base/chrome_render_view_test.h" #include "chrome/test/base/chrome_unit_test_suite.h" @@ -248,6 +249,26 @@ EXPECT_CALL(*classifier_, CancelPendingClassification()); } +TEST_F(PhishingClassifierDelegateTest, HasVisualTfLiteModel) { + ASSERT_FALSE(classifier_->is_ready()); + + base::ScopedTempDir temp_dir; + ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); + base::FilePath file_path = + temp_dir.GetPath().AppendASCII("visual_model.tflite"); + base::File file(file_path, base::File::FLAG_OPEN_ALWAYS | + base::File::FLAG_READ | + base::File::FLAG_WRITE); + std::string file_contents = "visual model file"; + file.WriteAtCurrentPos(file_contents.data(), file_contents.size()); + + delegate_->SetPhishingModel("", std::move(file)); + ASSERT_TRUE(classifier_->is_ready()); + + // The delegate will cancel pending classification on destruction. + EXPECT_CALL(*classifier_, CancelPendingClassification()); +} + TEST_F(PhishingClassifierDelegateTest, NoScorer) { // For this test, we'll create the delegate with no scorer available yet. ASSERT_FALSE(classifier_->is_ready());
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 72c9ce5..a582e12 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -1083,9 +1083,9 @@ "../../apps/load_and_launch_browsertest.cc", "../browser/accessibility/accessibility_labels_service_browsertest.cc", "../browser/accessibility/browser_accessibility_state_browsertest.cc", - "../browser/accessibility/caption_controller_browsertest.cc", "../browser/accessibility/image_annotation_browsertest.cc", "../browser/accessibility/interstitial_accessibility_browsertest.cc", + "../browser/accessibility/live_caption_controller_browsertest.cc", "../browser/accessibility/live_caption_speech_recognition_host_browsertest.cc", "../browser/apps/guest_view/app_view_browsertest.cc", "../browser/apps/guest_view/web_view_browsertest.cc", @@ -7032,6 +7032,7 @@ "../browser/ui/views/test/view_event_test_base.h", "../browser/ui/views/toolbar/toolbar_view_interactive_uitest.cc", "../browser/ui/views/translate/translate_bubble_test_utils_views.cc", + "../browser/ui/views/user_education/feature_promo_bubble_view_interactive_uitest.cc", "../browser/ui/views/user_education/feature_promo_snooze_interactive_uitest.cc", ] deps += [
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/OmniboxTestUtils.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/OmniboxTestUtils.java index fa2fd8c..4e6e03f 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/OmniboxTestUtils.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/OmniboxTestUtils.java
@@ -5,7 +5,6 @@ package org.chromium.chrome.test.util; import android.content.Context; -import android.util.Pair; import android.view.View; import android.view.inputmethod.InputMethodManager; @@ -25,14 +24,10 @@ import org.chromium.chrome.browser.omnibox.suggestions.header.HeaderView; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.components.omnibox.AutocompleteResult; -import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.test.util.TestThreadUtils; import org.chromium.content_public.browser.test.util.TouchCommon; import org.chromium.ui.modelutil.MVCListAdapter.ModelList; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; import java.util.concurrent.Callable; /** @@ -42,76 +37,12 @@ private OmniboxTestUtils() {} /** - * AutocompleteController instance that allows for easy testing. - */ - public static class TestAutocompleteController extends AutocompleteController { - private final Map<String, Pair<String, AutocompleteResult>> mAutocompleteResults; - - /** - * Create new Autocomplete controller. - * @param listener - */ - public TestAutocompleteController(OnSuggestionsReceivedListener listener) { - super(profile -> {}); - mAutocompleteResults = new HashMap<>(); - setOnSuggestionsReceivedListener(listener); - } - - /** - * Register new AutocompleteResult offered when the test user input matches the - * forInputText. - * - * @param forInputText String to match against: user query. - * @param autocompleteText Recommended default autocompletion. - * @param autocompleteResult List of suggestions associated with the query. - */ - public void addAutocompleteResult(String forInputText, String autocompleteText, - AutocompleteResult autocompleteResult) { - mAutocompleteResults.put(forInputText, new Pair(autocompleteText, autocompleteResult)); - } - - /** - * Suppress any suggestion logging mechanisms so that artificially created suggestions - * do not attempt to log selection. - */ - @Override - public void onSuggestionSelected(int selectedIndex, int disposition, int type, - String currentPageUrl, int pageClassification, long elapsedTimeSinceModified, - int completedLength, WebContents webContents) {} - - @Override - public void start(Profile profile, String url, int pageClassification, final String text, - int cursorPosition, boolean preventInlineAutocomplete, String queryTileId, - boolean isQueryStartedFromTiles) { - if (sendSuggestions(text)) return; - super.start(profile, url, pageClassification, text, cursorPosition, - preventInlineAutocomplete, queryTileId, isQueryStartedFromTiles); - } - - @Override - public void startZeroSuggest(Profile profile, String omniboxText, String url, - int pageClassification, String title) { - if (sendSuggestions(omniboxText)) return; - super.startZeroSuggest(profile, omniboxText, url, pageClassification, title); - } - - private boolean sendSuggestions(String forText) { - String autocompleteText = forText.toLowerCase(Locale.US); - Pair<String, AutocompleteResult> autocompleteSet = - mAutocompleteResults.get(autocompleteText); - if (autocompleteSet == null) return false; - onSuggestionsReceived(autocompleteSet.second, autocompleteSet.first); - return true; - } - } - - /** * AutocompleteController instance that will trigger no suggestions. */ public static class StubAutocompleteController extends AutocompleteController { public StubAutocompleteController() { - super(profile -> {}); - setOnSuggestionsReceivedListener(new OnSuggestionsReceivedListener() { + super(null, profile -> {}, () -> {}); + addOnSuggestionsReceivedListener(new OnSuggestionsReceivedListener() { @Override public void onSuggestionsReceived( AutocompleteResult autocompleteResult, String inlineAutocompleteText) { @@ -131,9 +62,6 @@ @Override public void stop(boolean clear) {} - - @Override - public void setProfile(Profile profile) {} } /**
diff --git a/chrome/test/data/media/engagement/preload/BUILD.gn b/chrome/test/data/media/engagement/preload/BUILD.gn index 597329be..f3f9634 100644 --- a/chrome/test/data/media/engagement/preload/BUILD.gn +++ b/chrome/test/data/media/engagement/preload/BUILD.gn
@@ -3,11 +3,9 @@ # found in the LICENSE file. import("//build/compiled_action.gni") -import("//build/config/python.gni") # Generates a proto file based on the real list. -# TODO(crbug.com/1112471): Get this to run cleanly under Python 3. -python2_action_foreach("generate_preload_list") { +action_foreach("generate_preload_list") { script = "//tools/media_engagement_preload/make_dafsa.py" sources = [ "test.json" ]
diff --git a/chrome/test/data/webui/chromeos/ash_common/navigation_selector_test.js b/chrome/test/data/webui/chromeos/ash_common/navigation_selector_test.js index 56ae6669..1430487 100644 --- a/chrome/test/data/webui/chromeos/ash_common/navigation_selector_test.js +++ b/chrome/test/data/webui/chromeos/ash_common/navigation_selector_test.js
@@ -26,10 +26,12 @@ /** * @param {string} name * @param {string} pageIs + * @param {string} icon * @return {!SelectorItem} */ - function createSelectorItem(name, pageIs) { - let item = /** @type{SelectorItem} */ ({'name': name, 'pageIs': pageIs}); + function createSelectorItem(name, pageIs, icon) { + let item = /** @type{SelectorItem} */ ( + {'name': name, 'pageIs': pageIs, 'icon': icon}); return item; } @@ -62,8 +64,8 @@ } test('navigationSelectorLoadEntries', async () => { - const item1 = createSelectorItem('test1', 'test-page1'); - const item2 = createSelectorItem('test2', 'test-page2'); + const item1 = createSelectorItem('test1', 'test-page1', ''); + const item2 = createSelectorItem('test2', 'test-page2', ''); const property1 = createProperty(false, false, []); const property2 = createProperty(false, false, []); @@ -85,8 +87,12 @@ }); test('navigationSelectorLoadsCollapsibleEntries', async () => { - const item1 = createSelectorItem('test1', 'test-page1'); - const item2 = createSelectorItem('Advanced', ''); + const item1 = createSelectorItem( + 'test1', + 'test-page1', + '', + ); + const item2 = createSelectorItem('Advanced', '', ''); const property = createProperty(true, false, [item1]);
diff --git a/chrome/test/data/webui/chromeos/ash_common/navigation_view_panel_test.js b/chrome/test/data/webui/chromeos/ash_common/navigation_view_panel_test.js index a3bead1b..5d4bd7d 100644 --- a/chrome/test/data/webui/chromeos/ash_common/navigation_view_panel_test.js +++ b/chrome/test/data/webui/chromeos/ash_common/navigation_view_panel_test.js
@@ -151,7 +151,7 @@ let subItem = /** @type {SelectorItem} */ ({'name': 'subItem', 'pageIs': subPage}); - viewElement.addSelector('dummyPage1', dummyPage1, [subItem]); + viewElement.addSelector('dummyPage1', dummyPage1, '', [subItem]); viewElement.addSelector('dummyPage2', dummyPage2); assertFalse(viewElement.shadowRoot.querySelector(`#${subPage}`).hidden);
diff --git a/chrome/test/data/webui/chromeos/shimless_rma/fake_shimless_rma_service_test.js b/chrome/test/data/webui/chromeos/shimless_rma/fake_shimless_rma_service_test.js index c2a4e76..8b9b3a0 100644 --- a/chrome/test/data/webui/chromeos/shimless_rma/fake_shimless_rma_service_test.js +++ b/chrome/test/data/webui/chromeos/shimless_rma/fake_shimless_rma_service_test.js
@@ -3,9 +3,9 @@ // found in the LICENSE file. import {FakeShimlessRmaService} from 'chrome://shimless-rma/fake_shimless_rma_service.js'; -import {ComponentRepairState, ComponentType, RmadErrorCode, RmaState, ShimlessRmaServiceInterface} from 'chrome://shimless-rma/shimless_rma_types.js'; +import {CalibrationComponent, CalibrationObserver, ComponentRepairState, ComponentType, ErrorObserver, HardwareWriteProtectionStateObserver, PowerCableStateObserver, ProvisioningObserver, ProvisioningStep, RmadErrorCode, RmaState, ShimlessRmaServiceInterface} from 'chrome://shimless-rma/shimless_rma_types.js'; -import {assertDeepEquals, assertEquals} from '../../chai_assert.js'; +import {assertDeepEquals, assertEquals, assertGE, assertLE} from '../../chai_assert.js'; export function fakeShimlessRmaServiceTestSuite() { /** @type {?FakeShimlessRmaService} */ @@ -19,6 +19,7 @@ service = null; }); + test('GetCurrentStateDefaultRmaNotRequired', () => { return service.getCurrentState().then((state) => { assertEquals(state.currentState, RmaState.kUnknown); @@ -674,4 +675,89 @@ assertEquals(error.error, RmadErrorCode.kRequestInvalid); }); }); + + test('ObserveError', () => { + /** @type {!ErrorObserver} */ + const errorObserver = /** @type {!ErrorObserver} */ ({ + /** + * Implements ErrorObserver.onError() + * @param {!RmadErrorCode} error + */ + onError(error) { + assertEquals(error, RmadErrorCode.kRequestInvalid); + } + }); + service.observeError(errorObserver); + return service.triggerErrorObserver(RmadErrorCode.kRequestInvalid, 0); + }); + + test('ObserveCalibrationUpdate', () => { + /** @type {!CalibrationObserver} */ + const calibrationObserver = /** @type {!CalibrationObserver} */ ({ + /** + * Implements CalibrationObserver.onCalibrationUpdated() + * @param {!CalibrationComponent} component + * @param {number} progress + */ + onCalibrationUpdated(component, progress) { + assertEquals(component, CalibrationComponent.kAccelerometer); + assertEquals(progress, 0.5); + } + }); + service.observeCalibration(calibrationObserver); + return service.triggerCalibrationObserver( + CalibrationComponent.kAccelerometer, 0.5, 0); + }); + + test('ObserveProvisioningUpdate', () => { + /** @type {!ProvisioningObserver} */ + const provisioningObserver = /** @type {!ProvisioningObserver} */ ({ + /** + * Implements ProvisioningObserver.onProvisioningUpdated() + * @param {!ProvisioningStep} step + * @param {number} progress + */ + onProvisioningUpdated(step, progress) { + assertEquals(step, ProvisioningStep.kTwiddleSettings); + assertEquals(progress, 0.25); + } + }); + service.observeProvisioning(provisioningObserver); + return service.triggerProvisioningObserver( + ProvisioningStep.kTwiddleSettings, 0.25, 0); + }); + + test('ObserveHardwareWriteProtectionStateChange', () => { + /** @type {!HardwareWriteProtectionStateObserver} */ + const hardwareWriteProtectionStateObserver = + /** @type {!HardwareWriteProtectionStateObserver} */ ({ + /** + * Implements + * HardwareWriteProtectionStateObserver. + * onHardwareWriteProtectionStateChanged() + * @param {boolean} enable + */ + onHardwareWriteProtectionStateChanged(enable) { + assertEquals(enable, true); + } + }); + service.observeHardwareWriteProtectionState( + hardwareWriteProtectionStateObserver); + return service.triggerHardwareWriteProtectionObserver(true, 0); + }); + + test('ObservePowerCableStateChange', () => { + /** @type {!PowerCableStateObserver} */ + const powerCableStateObserver = /** @type {!PowerCableStateObserver} */ ({ + /** + * Implements PowerCableStateObserver.onPowerCableStateChanged() + * @param {boolean} enable + */ + onPowerCableStateChanged(enable) { + assertEquals(enable, true); + } + }); + service.observePowerCableState(powerCableStateObserver); + return service.triggerPowerCableObserver(true, 0); + }); }
diff --git a/chrome/test/data/webui/cr_components/chromeos/cellular_setup/esim_flow_ui_test.js b/chrome/test/data/webui/cr_components/chromeos/cellular_setup/esim_flow_ui_test.js index 9badf3c..18f36e2 100644 --- a/chrome/test/data/webui/cr_components/chromeos/cellular_setup/esim_flow_ui_test.js +++ b/chrome/test/data/webui/cr_components/chromeos/cellular_setup/esim_flow_ui_test.js
@@ -17,7 +17,6 @@ // #import {FakeNetworkConfig} from 'chrome://test/chromeos/fake_network_config_mojom.m.js'; // #import {OncMojo} from 'chrome://resources/cr_components/chromeos/network/onc_mojo.m.js'; // #import {MojoInterfaceProviderImpl} from 'chrome://resources/cr_components/chromeos/network/mojo_interface_provider.m.js'; -// #import {LoadingPageState} from 'chrome://resources/cr_components/chromeos/cellular_setup/setup_loading_page.m.js'; // #import {MockMetricsPrivate} from './mock_metrics_private.m.js'; // clang-format on @@ -752,6 +751,10 @@ test( 'Show cellular disconnect warning if connected to pSIM network', async function() { + assertEquals( + profileLoadingPage.loadingMessage, + eSimPage.i18n('eSimProfileDetectMessage')); + const pSimNetwork = OncMojo.getDefaultNetworkState( chromeos.networkConfig.mojom.NetworkType.kCellular, 'cellular'); pSimNetwork.connectionState = @@ -762,8 +765,9 @@ await flushAsync(); assertEquals( - profileLoadingPage.state, - LoadingPageState.CELLULAR_DISCONNECT_WARNING); + profileLoadingPage.loadingMessage, + eSimPage.i18n( + 'eSimProfileDetectDuringActiveCellularConnectionMessage')); // Disconnect from the network. networkConfigRemote.removeNetworkForTest(pSimNetwork); @@ -771,8 +775,9 @@ // The warning should still be showing. assertEquals( - profileLoadingPage.state, - LoadingPageState.CELLULAR_DISCONNECT_WARNING); + profileLoadingPage.loadingMessage, + eSimPage.i18n( + 'eSimProfileDetectDuringActiveCellularConnectionMessage')); }); test('Show final page with error if no EUICC', async function() {
diff --git a/chrome/test/data/webui/cr_components/chromeos/cellular_setup/setup_loading_page_test.js b/chrome/test/data/webui/cr_components/chromeos/cellular_setup/setup_loading_page_test.js index b0dd77d..06036b4 100644 --- a/chrome/test/data/webui/cr_components/chromeos/cellular_setup/setup_loading_page_test.js +++ b/chrome/test/data/webui/cr_components/chromeos/cellular_setup/setup_loading_page_test.js
@@ -8,50 +8,30 @@ // #import {flush, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; // #import {assertFalse, assertTrue} from '../../../chai_assert.js'; -// #import {LoadingPageState} from 'chrome://resources/cr_components/chromeos/cellular_setup/setup_loading_page.m.js'; -// #import {FakeCellularSetupDelegate} from './fake_cellular_setup_delegate.m.js'; // clang-format on suite('CrComponentsSetupLoadingPageTest', function() { - let simDetectPage; + let setupLoadingPage; let basePage; - let messageIcon; setup(function() { - simDetectPage = document.createElement('setup-loading-page'); - simDetectPage.delegate = new cellular_setup.FakeCellularSetupDelegate(); - document.body.appendChild(simDetectPage); + setupLoadingPage = document.createElement('setup-loading-page'); + document.body.appendChild(setupLoadingPage); Polymer.dom.flush(); - basePage = simDetectPage.$$('base-page'); + basePage = setupLoadingPage.$$('base-page'); assertTrue(!!basePage); - messageIcon = basePage.$$('iron-icon'); - assertTrue(!!messageIcon); }); - test('No message is shown', function() { - simDetectPage.state = LoadingPageState.LOADING; - assertFalse(!!basePage.message); - assertTrue(messageIcon.hidden); - }); + test('Loading animation and error graphic shown correctly', function() { + setupLoadingPage.isSimDetectError = false; + Polymer.dom.flush(); + assertTrue(!!setupLoadingPage.$$('#animationContainer')); + assertTrue(setupLoadingPage.$$('#simDetectError').hidden); - test('Warning message is shown', function() { - simDetectPage.state = LoadingPageState.CELLULAR_DISCONNECT_WARNING; - assertEquals(basePage.message, simDetectPage.i18n('eSimConnectionWarning')); - assertFalse(messageIcon.hidden); - }); - - test('Retry error message is shown', function() { - simDetectPage.state = LoadingPageState.SIM_DETECT_ERROR; - assertEquals( - basePage.message, simDetectPage.i18n('simDetectPageErrorMessage')); - assertTrue(messageIcon.hidden); - }); - - test('Final error message is shown', function() { - simDetectPage.state = LoadingPageState.FINAL_SIM_DETECT_ERROR; - assertEquals( - basePage.message, simDetectPage.i18n('simDetectPageFinalErrorMessage')); - assertTrue(messageIcon.hidden); + setupLoadingPage.isSimDetectError = true; + Polymer.dom.flush(); + assertFalse(!!setupLoadingPage.$$('#animationContainer')); + assertFalse(setupLoadingPage.$$('#simDetectError').hidden); }); });
diff --git a/chrome/test/data/webui/cr_components/chromeos/network/network_list_item_test.js b/chrome/test/data/webui/cr_components/chromeos/network/network_list_item_test.js index e278131..d8a62fe4 100644 --- a/chrome/test/data/webui/cr_components/chromeos/network/network_list_item_test.js +++ b/chrome/test/data/webui/cr_components/chromeos/network/network_list_item_test.js
@@ -271,6 +271,12 @@ listItem.$.divOuter.click(); const showDetailEvent = await showDetailPromise; assertEquals(showDetailEvent.detail, networkState); + + // Setting showButtons to false should hide activate and arrow button. + listItem.showButtons = false; + await flushAsync(); + assertFalse(!!listItem.$$('#activateButton')); + assertFalse(!!listItem.$$('#subpageButton')); }); test('Unavailable pSIM UI visibility', async () => { @@ -428,6 +434,11 @@ await flushAsync(); assertEquals(installProfileEventIccid, 'iccid'); + + // Setting showButtons to false should hide install button. + listItem.showButtons = false; + await flushAsync(); + assertFalse(!!listItem.$$('#installButton')); }); test( @@ -538,6 +549,11 @@ networkStateText = listItem.$$('#networkStateText'); assertTrue(!!networkStateText); assertEquals(networkStateLockedText, networkStateText.textContent.trim()); + + // Setting showButtons to false should hide unlock button. + listItem.showButtons = false; + await flushAsync(); + assertFalse(!!listItem.$$('#unlockButton')); }); test('Disable sim lock button when device is inhibited', async () => {
diff --git a/chrome/test/data/webui/js/cr/ui/context_menu_handler_test.html b/chrome/test/data/webui/js/cr/ui/context_menu_handler_test.html index 9b55781..92b432583 100644 --- a/chrome/test/data/webui/js/cr/ui/context_menu_handler_test.html +++ b/chrome/test/data/webui/js/cr/ui/context_menu_handler_test.html
@@ -2,8 +2,8 @@ <html> <body> <script src="chrome://resources/js/assert.js"></script> -<script src="chrome://resources/js/event_tracker.js"></script> <script src="chrome://resources/js/cr.js"></script> +<script src="chrome://resources/js/event_tracker.js"></script> <script src="chrome://resources/js/cr/event_target.js"></script> <script src="chrome://resources/js/cr/ui.js"></script> <script src="chrome://resources/js/cr/ui/position_util.js"></script>
diff --git a/chrome/test/data/webui/js/cr/ui/menu_button_test.html b/chrome/test/data/webui/js/cr/ui/menu_button_test.html index 8ee6e854..1a6d8820 100644 --- a/chrome/test/data/webui/js/cr/ui/menu_button_test.html +++ b/chrome/test/data/webui/js/cr/ui/menu_button_test.html
@@ -2,8 +2,8 @@ <html> <body> <script src="chrome://resources/js/assert.js"></script> -<script src="chrome://resources/js/event_tracker.js"></script> <script src="chrome://resources/js/cr.js"></script> +<script src="chrome://resources/js/event_tracker.js"></script> <script src="chrome://resources/js/cr/ui.js"></script> <script src="chrome://resources/js/cr/ui/position_util.js"></script> <script src="chrome://resources/js/cr/ui/menu_button.js"></script>
diff --git a/chrome/test/ppapi/ppapi_browsertest.cc b/chrome/test/ppapi/ppapi_browsertest.cc index 9053f35..8c81f45 100644 --- a/chrome/test/ppapi/ppapi_browsertest.cc +++ b/chrome/test/ppapi/ppapi_browsertest.cc
@@ -987,7 +987,12 @@ PPAPI_SOCKET_TEST(UDPSocket_SetOption) PPAPI_SOCKET_TEST(UDPSocket_SetOption_1_0) PPAPI_SOCKET_TEST(UDPSocket_SetOption_1_1) + +// Fails on MacOS 11, crbug.com/1211138 . +#if !defined(OS_MAC) PPAPI_SOCKET_TEST(UDPSocket_Broadcast) +#endif + PPAPI_SOCKET_TEST(UDPSocket_ParallelSend) PPAPI_SOCKET_TEST(UDPSocket_Multicast) @@ -998,7 +1003,12 @@ TEST_PPAPI_OUT_OF_PROCESS_VIA_HTTP(UDPSocketPrivate_SetSocketFeatureErrors) TEST_PPAPI_NACL(UDPSocketPrivate_Connect) TEST_PPAPI_NACL(UDPSocketPrivate_ConnectFailure) + +// Fails on MacOS 11, crbug.com/1211138 . +#if !defined(OS_MAC) TEST_PPAPI_NACL(UDPSocketPrivate_Broadcast) +#endif + TEST_PPAPI_NACL(UDPSocketPrivate_SetSocketFeatureErrors) namespace {
diff --git a/chrome/updater/BUILD.gn b/chrome/updater/BUILD.gn index 13793d6..dc8ad07 100644 --- a/chrome/updater/BUILD.gn +++ b/chrome/updater/BUILD.gn
@@ -59,8 +59,6 @@ "enum_traits.h", "persisted_data.cc", "persisted_data.h", - "policy_manager.cc", - "policy_manager.h", "registration_data.cc", "registration_data.h", "splash_screen.h", @@ -128,8 +126,6 @@ "installer.cc", "installer.h", "lib_util.h", - "policy_service.cc", - "policy_service.h", "prefs.cc", "prefs.h", "prefs_impl.h", @@ -200,6 +196,7 @@ ":version_header", "//base", "//base:i18n", + "//chrome/updater/policy", "//components/crash/core/common:crash_key", "//components/crx_file:crx_file", "//components/prefs", @@ -229,7 +226,6 @@ if (is_mac) { deps += [ "//chrome/updater/app/server/mac:protocol", - "//chrome/updater/mac:enterprise", "//chrome/updater/mac:installer_sources", "//chrome/updater/mac:network_fetcher_sources", "//chrome/updater/mac:updater_setup_sources", @@ -354,8 +350,6 @@ "external_constants_override_unittest.cc", "lib_util_unittest.cc", "persisted_data_unittest.cc", - "policy_manager_unittest.cc", - "policy_service_unittest.cc", "prefs_unittest.cc", "tag_unittest.cc", "test/integration_test_commands.h", @@ -384,6 +378,7 @@ "//base/test:test_support", "//chrome/common:constants", "//chrome/updater/device_management:unittest", + "//chrome/updater/policy:unittest", "//chrome/updater/test/test_app:constants", "//chrome/updater/test/test_app:version_header", "//chrome/updater/tools:unittest", @@ -423,7 +418,6 @@ deps += [ "//chrome/common/mac:launchd", "//chrome/updater/app/server/mac:protocol", - "//chrome/updater/mac:enterprise_tests", "//chrome/updater/mac:network_fetcher_sources", "//chrome/updater/mac:updater_bundle", "//chrome/updater/mac:updater_setup_tests",
diff --git a/chrome/updater/device_management/BUILD.gn b/chrome/updater/device_management/BUILD.gn index adf109a..89f9c6e5 100644 --- a/chrome/updater/device_management/BUILD.gn +++ b/chrome/updater/device_management/BUILD.gn
@@ -16,8 +16,6 @@ "dm_client.h", "dm_message.cc", "dm_message.h", - "dm_policy_manager.cc", - "dm_policy_manager.h", "dm_response_validator.cc", "dm_response_validator.h", "dm_storage.cc", @@ -61,7 +59,6 @@ "dm_message_unittest.cc", "dm_policy_builder_for_testing.cc", "dm_policy_builder_for_testing.h", - "dm_policy_manager_unittest.cc", "dm_response_validator_unittest.cc", "dm_storage_unittest.cc", ]
diff --git a/chrome/updater/device_management/dm_client_unittest.cc b/chrome/updater/device_management/dm_client_unittest.cc index 8c8ea1a1..31b36ba2 100644 --- a/chrome/updater/device_management/dm_client_unittest.cc +++ b/chrome/updater/device_management/dm_client_unittest.cc
@@ -25,7 +25,7 @@ #include "chrome/updater/device_management/dm_policy_builder_for_testing.h" #include "chrome/updater/device_management/dm_response_validator.h" #include "chrome/updater/device_management/dm_storage.h" -#include "chrome/updater/policy_manager.h" +#include "chrome/updater/protos/omaha_settings.pb.h" #include "chrome/updater/unittest_util.h" #include "components/policy/proto/device_management_backend.pb.h" #include "components/update_client/network.h" @@ -220,23 +220,20 @@ EXPECT_EQ(info->public_key(), GetTestKey1()->GetPublicKeyString()); if (result == DMClient::RequestResult::kSuccess) { - std::unique_ptr<PolicyManagerInterface> policy_manager = - storage_->GetOmahaPolicyManager(); - EXPECT_NE(policy_manager, nullptr); + std::unique_ptr<::wireless_android_enterprise_devicemanagement:: + OmahaSettingsClientProto> + omaha_settings = storage_->GetOmahaPolicySettings(); + EXPECT_NE(omaha_settings, nullptr); // Sample some of the policy values and check they are expected. - EXPECT_TRUE(policy_manager->IsManaged()); - std::string proxy_mode; - EXPECT_TRUE(policy_manager->GetProxyMode(&proxy_mode)); - EXPECT_EQ(proxy_mode, "pac_script"); - int update_policy = 0; - EXPECT_TRUE(policy_manager->GetEffectivePolicyForAppUpdates( - kChromeAppId, &update_policy)); - EXPECT_EQ(update_policy, kPolicyAutomaticUpdatesOnly); - std::string target_version_prefix; - EXPECT_TRUE(policy_manager->GetTargetVersionPrefix( - kChromeAppId, &target_version_prefix)); - EXPECT_EQ(target_version_prefix, "81."); + EXPECT_EQ(omaha_settings->proxy_mode(), "pac_script"); + const ::wireless_android_enterprise_devicemanagement::ApplicationSettings& + chrome_settings = omaha_settings->application_settings()[0]; + EXPECT_EQ(chrome_settings.app_guid(), kChromeAppId); + EXPECT_EQ(chrome_settings.update(), + ::wireless_android_enterprise_devicemanagement:: + AUTOMATIC_UPDATES_ONLY); + EXPECT_EQ(chrome_settings.target_version_prefix(), "81."); } EXPECT_EQ(expected_validation_results_, validation_results);
diff --git a/chrome/updater/device_management/dm_storage.cc b/chrome/updater/device_management/dm_storage.cc index 622b0b04..9023c71 100644 --- a/chrome/updater/device_management/dm_storage.cc +++ b/chrome/updater/device_management/dm_storage.cc
@@ -4,6 +4,7 @@ #include "chrome/updater/device_management/dm_storage.h" +#include <memory> #include <set> #include <string> #include <utility> @@ -15,7 +16,7 @@ #include "base/strings/sys_string_conversions.h" #include "chrome/updater/device_management/dm_cached_policy_info.h" #include "chrome/updater/device_management/dm_message.h" -#include "chrome/updater/device_management/dm_policy_manager.h" +#include "chrome/updater/protos/omaha_settings.pb.h" #include "chrome/updater/util.h" #include "components/policy/proto/device_management_backend.pb.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -140,7 +141,7 @@ return DeleteObsoletePolicies(policy_cache_root_, policy_types_base64); } -std::unique_ptr<CachedPolicyInfo> DMStorage::GetCachedPolicyInfo() { +std::unique_ptr<CachedPolicyInfo> DMStorage::GetCachedPolicyInfo() const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); auto cached_info = std::make_unique<CachedPolicyInfo>(); @@ -159,7 +160,9 @@ return cached_info; } -std::unique_ptr<PolicyManagerInterface> DMStorage::GetOmahaPolicyManager() { +std::unique_ptr< + ::wireless_android_enterprise_devicemanagement::OmahaSettingsClientProto> +DMStorage::GetOmahaPolicySettings() const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (!IsValidDMToken()) @@ -174,18 +177,19 @@ std::string response_data; ::enterprise_management::PolicyFetchResponse response; ::enterprise_management::PolicyData policy_data; - ::wireless_android_enterprise_devicemanagement::OmahaSettingsClientProto - omaha_settings; + auto omaha_settings = + std::make_unique<::wireless_android_enterprise_devicemanagement:: + OmahaSettingsClientProto>(); if (!base::PathExists(omaha_policy_file) || !base::ReadFileToString(omaha_policy_file, &response_data) || response_data.empty() || !response.ParseFromString(response_data) || !policy_data.ParseFromString(response.policy_data()) || !policy_data.has_policy_value() || - !omaha_settings.ParseFromString(policy_data.policy_value())) { + !omaha_settings->ParseFromString(policy_data.policy_value())) { return nullptr; } - return std::make_unique<DMPolicyManager>(omaha_settings); + return omaha_settings; } scoped_refptr<DMStorage> GetDefaultDMStorage() {
diff --git a/chrome/updater/device_management/dm_storage.h b/chrome/updater/device_management/dm_storage.h index ca04ab0..31ff82a 100644 --- a/chrome/updater/device_management/dm_storage.h +++ b/chrome/updater/device_management/dm_storage.h
@@ -7,6 +7,7 @@ #include <memory> #include <string> + #include "base/containers/flat_map.h" #include "base/files/file_path.h" #include "base/memory/ref_counted.h" @@ -14,10 +15,13 @@ #include "build/build_config.h" #include "chrome/updater/device_management/dm_message.h" +namespace wireless_android_enterprise_devicemanagement { +class OmahaSettingsClientProto; +} + namespace updater { class CachedPolicyInfo; -class PolicyManagerInterface; // The token service interface defines how to serialize tokens. class TokenServiceInterface { @@ -117,12 +121,13 @@ // Creates a CachedPolicyInfo object and populates it with the public key // information loaded from file |policy_cache_root_|\CachedPolicyInfo. - std::unique_ptr<CachedPolicyInfo> GetCachedPolicyInfo(); + std::unique_ptr<CachedPolicyInfo> GetCachedPolicyInfo() const; - // Creates a policy manager and populates it with the Omaha policies loaded - // from PolicyFetchResponse file within + // Returns the Omaha policy settings loaded from PolicyFetchResponse file in // |policy_cache_root_|\{Base64Encoded{kGoogleUpdatePolicyType}} directory. - std::unique_ptr<PolicyManagerInterface> GetOmahaPolicyManager(); + std::unique_ptr< + ::wireless_android_enterprise_devicemanagement::OmahaSettingsClientProto> + GetOmahaPolicySettings() const; private: friend class base::RefCountedThreadSafe<DMStorage>;
diff --git a/chrome/updater/device_management/dm_storage_unittest.cc b/chrome/updater/device_management/dm_storage_unittest.cc index ee9c39b..fc83d08a 100644 --- a/chrome/updater/device_management/dm_storage_unittest.cc +++ b/chrome/updater/device_management/dm_storage_unittest.cc
@@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <memory> #include <utility> #include "base/files/file_util.h" @@ -10,7 +11,6 @@ #include "chrome/updater/constants.h" #include "chrome/updater/device_management/dm_cached_policy_info.h" #include "chrome/updater/device_management/dm_storage.h" -#include "chrome/updater/policy_manager.h" #include "chrome/updater/protos/omaha_settings.pb.h" #include "chrome/updater/unittest_util.h" #include "components/policy/proto/device_management_backend.pb.h" @@ -184,80 +184,38 @@ cache_root.GetPath(), std::make_unique<TestTokenService>()); EXPECT_TRUE(storage->PersistPolicies(policies)); - auto policy_manager = storage->GetOmahaPolicyManager(); - ASSERT_NE(policy_manager, nullptr); + std::unique_ptr< + ::wireless_android_enterprise_devicemanagement::OmahaSettingsClientProto> + omaha_settings = storage->GetOmahaPolicySettings(); + ASSERT_NE(omaha_settings, nullptr); + EXPECT_EQ(omaha_settings->auto_update_check_period_minutes(), 111); - int check_interval = 0; - EXPECT_TRUE(policy_manager->GetLastCheckPeriodMinutes(&check_interval)); - EXPECT_EQ(check_interval, 111); + EXPECT_EQ(omaha_settings->updates_suppressed().start_hour(), 8); + EXPECT_EQ(omaha_settings->updates_suppressed().start_minute(), 8); + EXPECT_EQ(omaha_settings->updates_suppressed().duration_min(), 47); - UpdatesSuppressedTimes suppressed_times; - EXPECT_TRUE(policy_manager->GetUpdatesSuppressedTimes(&suppressed_times)); - EXPECT_EQ(suppressed_times.start_hour, 8); - EXPECT_EQ(suppressed_times.start_minute, 8); - EXPECT_EQ(suppressed_times.duration_minute, 47); + EXPECT_EQ(omaha_settings->proxy_mode(), "proxy_pac_script"); + EXPECT_EQ(omaha_settings->proxy_pac_url(), "foo.c/proxy.pa"); + EXPECT_FALSE(omaha_settings->has_proxy_server()); - // Proxy policies. - std::string proxy_mode; - EXPECT_TRUE(policy_manager->GetProxyMode(&proxy_mode)); - EXPECT_EQ(proxy_mode, "proxy_pac_script"); - std::string proxy_pac_url; - EXPECT_TRUE(policy_manager->GetProxyPacUrl(&proxy_pac_url)); - EXPECT_EQ(proxy_pac_url, "foo.c/proxy.pa"); - std::string proxy_server; - EXPECT_FALSE(policy_manager->GetProxyServer(&proxy_server)); - - // Download preference. - std::string download_preference; - EXPECT_TRUE( - policy_manager->GetDownloadPreferenceGroupPolicy(&download_preference)); - EXPECT_EQ(download_preference, "cacheable"); - - // Cache policies. - int cache_size = 0; - EXPECT_FALSE(policy_manager->GetPackageCacheSizeLimitMBytes(&cache_size)); - int cache_life = 0; - EXPECT_FALSE(policy_manager->GetPackageCacheExpirationTimeDays(&cache_life)); + EXPECT_EQ(omaha_settings->download_preference(), "cacheable"); // Chrome policies. - int chrome_install_policy = -1; - EXPECT_TRUE(policy_manager->GetEffectivePolicyForAppInstalls( - kChromeAppId, &chrome_install_policy)); - EXPECT_EQ(chrome_install_policy, kPolicyDisabled); - int chrome_update_policy = -1; - EXPECT_TRUE(policy_manager->GetEffectivePolicyForAppUpdates( - kChromeAppId, &chrome_update_policy)); - EXPECT_EQ(chrome_update_policy, kPolicyAutomaticUpdatesOnly); - std::string target_version_prefix; - EXPECT_TRUE(policy_manager->GetTargetVersionPrefix(kChromeAppId, - &target_version_prefix)); - EXPECT_EQ(target_version_prefix, "3.6.55"); - bool rollback_allowed = false; - EXPECT_TRUE(policy_manager->IsRollbackToTargetVersionAllowed( - kChromeAppId, &rollback_allowed)); - EXPECT_TRUE(rollback_allowed); + const auto& chrome_settings = omaha_settings->application_settings()[0]; + EXPECT_EQ(chrome_settings.install(), + ::wireless_android_enterprise_devicemanagement::INSTALL_DISABLED); + EXPECT_EQ( + chrome_settings.update(), + ::wireless_android_enterprise_devicemanagement::AUTOMATIC_UPDATES_ONLY); + EXPECT_EQ(chrome_settings.target_version_prefix(), "3.6.55"); + EXPECT_EQ(chrome_settings.rollback_to_target_version(), + ::wireless_android_enterprise_devicemanagement:: + ROLLBACK_TO_TARGET_VERSION_ENABLED); - // No app-specific policy should fallback to global. - const std::string non_exist_appid = "{00000000-1111-2222-3333-444444444444}"; - int app_install_policy = -1; - EXPECT_TRUE(policy_manager->GetEffectivePolicyForAppInstalls( - non_exist_appid, &app_install_policy)); - EXPECT_EQ(app_install_policy, kPolicyDisabled); - int app_update_policy = -1; - EXPECT_TRUE(policy_manager->GetEffectivePolicyForAppUpdates( - non_exist_appid, &app_update_policy)); - EXPECT_EQ(app_update_policy, kPolicyManualUpdatesOnly); - std::string app_target_version_prefix; - EXPECT_FALSE(policy_manager->GetTargetVersionPrefix( - non_exist_appid, &app_target_version_prefix)); - bool app_rollback_allowed = false; - EXPECT_FALSE(policy_manager->IsRollbackToTargetVersionAllowed( - non_exist_appid, &app_rollback_allowed)); - - // Verify no policy manager once device is deregistered. + // Verify no policy settings once device is de-registered. EXPECT_TRUE(storage->DeregisterDevice()); EXPECT_FALSE(storage->IsValidDMToken()); - ASSERT_EQ(storage->GetOmahaPolicyManager(), nullptr); + ASSERT_EQ(storage->GetOmahaPolicySettings(), nullptr); } } // namespace updater
diff --git a/chrome/updater/installer.cc b/chrome/updater/installer.cc index 01d982a..9a6f7c5 100644 --- a/chrome/updater/installer.cc +++ b/chrome/updater/installer.cc
@@ -18,7 +18,7 @@ #include "build/build_config.h" #include "chrome/updater/action_handler.h" #include "chrome/updater/constants.h" -#include "chrome/updater/policy_service.h" +#include "chrome/updater/policy/service.h" #include "chrome/updater/util.h" #include "components/crx_file/crx_verifier.h" #include "components/update_client/update_client_errors.h"
diff --git a/chrome/updater/mac/BUILD.gn b/chrome/updater/mac/BUILD.gn index b1d0aad..6192d50 100644 --- a/chrome/updater/mac/BUILD.gn +++ b/chrome/updater/mac/BUILD.gn
@@ -190,34 +190,3 @@ "//testing/gtest", ] } - -source_set("enterprise") { - sources = [ - "managed_preference_policy_manager.h", - "managed_preference_policy_manager.mm", - "managed_preference_policy_manager_impl.h", - "managed_preference_policy_manager_impl.mm", - ] - - deps = [ - "//base", - "//chrome/updater:base", - ] -} - -source_set("enterprise_tests") { - testonly = true - - sources = [ - "managed_preference_policy_manager_impl_unittest.mm", - "managed_preference_policy_manager_unittest.cc", - ] - - deps = [ - ":enterprise", - "//base", - "//base/test:test_support", - "//chrome/updater:base", - "//testing/gtest", - ] -}
diff --git a/chrome/updater/mac/managed_preference_policy_manager.h b/chrome/updater/mac/managed_preference_policy_manager.h deleted file mode 100644 index 43b0be5..0000000 --- a/chrome/updater/mac/managed_preference_policy_manager.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_UPDATER_MAC_MANAGED_PREFERENCE_POLICY_MANAGER_H_ -#define CHROME_UPDATER_MAC_MANAGED_PREFERENCE_POLICY_MANAGER_H_ - -#include <memory> - -#include "chrome/updater/policy_manager.h" - -namespace updater { - -// A factory method to create a managed preference policy manager. -std::unique_ptr<PolicyManagerInterface> CreateManagedPreferencePolicyManager(); - -} // namespace updater - -#endif // CHROME_UPDATER_MAC_MANAGED_PREFERENCE_POLICY_MANAGER_H_
diff --git a/chrome/updater/policy/BUILD.gn b/chrome/updater/policy/BUILD.gn new file mode 100644 index 0000000..0efcee3e --- /dev/null +++ b/chrome/updater/policy/BUILD.gn
@@ -0,0 +1,78 @@ +# Copyright 2021 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/chrome_build.gni") +import("//build/config/sanitizers/sanitizers.gni") +import("//build/util/process_version.gni") +import("//chrome/updater/branding.gni") +import("//testing/test.gni") + +source_set("policy") { + sources = [ + "dm_policy_manager.cc", + "dm_policy_manager.h", + "manager.cc", + "manager.h", + "service.cc", + "service.h", + ] + + deps = [ + "//base", + "//chrome/updater:base", + "//chrome/updater:branding_header", + "//chrome/updater:version_header", + "//chrome/updater/protos:omaha_proto", + ] + public_deps = [ "//components/policy/proto" ] + + if (is_mac) { + sources += [ + "mac/managed_preference_policy_manager.h", + "mac/managed_preference_policy_manager.mm", + "mac/managed_preference_policy_manager_impl.h", + "mac/managed_preference_policy_manager_impl.mm", + ] + } + if (is_win) { + sources += [ + "win/group_policy_manager.cc", + "win/group_policy_manager.h", + ] + deps += [ "//chrome/updater/win:constants" ] + } +} + +source_set("unittest") { + testonly = true + + sources = [ + "dm_policy_manager_unittest.cc", + "manager_unittest.cc", + "service_unittest.cc", + ] + + deps = [ + ":policy", + "//base", + "//base/test:test_support", + "//chrome/updater:base", + "//chrome/updater:updater_tests_support", + "//chrome/updater/protos:omaha_proto", + "//net:test_support", + "//testing/gtest", + ] + + if (is_mac) { + sources += [ + "mac/managed_preference_policy_manager_impl_unittest.mm", + "mac/managed_preference_policy_manager_unittest.cc", + ] + } + + if (is_win) { + sources += [ "win/group_policy_manager_unittest.cc" ] + deps += [ "//chrome/updater/win:constants" ] + } +}
diff --git a/chrome/updater/device_management/dm_policy_manager.cc b/chrome/updater/policy/dm_policy_manager.cc similarity index 98% rename from chrome/updater/device_management/dm_policy_manager.cc rename to chrome/updater/policy/dm_policy_manager.cc index d3fd9ab..5e85ad8 100644 --- a/chrome/updater/device_management/dm_policy_manager.cc +++ b/chrome/updater/policy/dm_policy_manager.cc
@@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/updater/device_management/dm_policy_manager.h" +#include "chrome/updater/policy/dm_policy_manager.h" #include "base/enterprise_util.h" #include "base/strings/string_util.h" #include "build/build_config.h" #include "chrome/updater/constants.h" -#include "chrome/updater/policy_manager.h" +#include "chrome/updater/policy/manager.h" namespace updater {
diff --git a/chrome/updater/device_management/dm_policy_manager.h b/chrome/updater/policy/dm_policy_manager.h similarity index 90% rename from chrome/updater/device_management/dm_policy_manager.h rename to chrome/updater/policy/dm_policy_manager.h index 0d94fc9..96cc54b 100644 --- a/chrome/updater/device_management/dm_policy_manager.h +++ b/chrome/updater/policy/dm_policy_manager.h
@@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_UPDATER_DEVICE_MANAGEMENT_DM_POLICY_MANAGER_H_ -#define CHROME_UPDATER_DEVICE_MANAGEMENT_DM_POLICY_MANAGER_H_ +#ifndef CHROME_UPDATER_POLICY_DM_POLICY_MANAGER_H_ +#define CHROME_UPDATER_POLICY_DM_POLICY_MANAGER_H_ #include <memory> #include <string> -#include "chrome/updater/policy_manager.h" +#include "chrome/updater/policy/manager.h" #include "chrome/updater/protos/omaha_settings.pb.h" namespace updater { @@ -61,4 +61,4 @@ } // namespace updater -#endif // CHROME_UPDATER_DEVICE_MANAGEMENT_DM_POLICY_MANAGER_H_ +#endif // CHROME_UPDATER_POLICY_DM_POLICY_MANAGER_H_
diff --git a/chrome/updater/device_management/dm_policy_manager_unittest.cc b/chrome/updater/policy/dm_policy_manager_unittest.cc similarity index 99% rename from chrome/updater/device_management/dm_policy_manager_unittest.cc rename to chrome/updater/policy/dm_policy_manager_unittest.cc index a553c9e..1999b0d 100644 --- a/chrome/updater/device_management/dm_policy_manager_unittest.cc +++ b/chrome/updater/policy/dm_policy_manager_unittest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/updater/device_management/dm_policy_manager.h" +#include "chrome/updater/policy/dm_policy_manager.h" #include "build/build_config.h" #include "chrome/updater/constants.h"
diff --git a/chrome/updater/policy/mac/managed_preference_policy_manager.h b/chrome/updater/policy/mac/managed_preference_policy_manager.h new file mode 100644 index 0000000..28304e3 --- /dev/null +++ b/chrome/updater/policy/mac/managed_preference_policy_manager.h
@@ -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. + +#ifndef CHROME_UPDATER_POLICY_MAC_MANAGED_PREFERENCE_POLICY_MANAGER_H_ +#define CHROME_UPDATER_POLICY_MAC_MANAGED_PREFERENCE_POLICY_MANAGER_H_ + +#include <memory> + +#include "chrome/updater/policy/manager.h" + +namespace updater { + +// A factory method to create a managed preference policy manager. +std::unique_ptr<PolicyManagerInterface> CreateManagedPreferencePolicyManager(); + +} // namespace updater + +#endif // CHROME_UPDATER_POLICY_MAC_MANAGED_PREFERENCE_POLICY_MANAGER_H_
diff --git a/chrome/updater/mac/managed_preference_policy_manager.mm b/chrome/updater/policy/mac/managed_preference_policy_manager.mm similarity index 97% rename from chrome/updater/mac/managed_preference_policy_manager.mm rename to chrome/updater/policy/mac/managed_preference_policy_manager.mm index 0e3dcfb..1e71181b 100644 --- a/chrome/updater/mac/managed_preference_policy_manager.mm +++ b/chrome/updater/policy/mac/managed_preference_policy_manager.mm
@@ -2,15 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/updater/mac/managed_preference_policy_manager.h" +#include "chrome/updater/policy/mac/managed_preference_policy_manager.h" #include <string> #include "base/mac/scoped_cftyperef.h" #include "base/mac/scoped_nsobject.h" #include "base/strings/sys_string_conversions.h" -#include "chrome/updater/mac/managed_preference_policy_manager_impl.h" -#include "chrome/updater/policy_manager.h" +#include "chrome/updater/policy/mac/managed_preference_policy_manager_impl.h" +#include "chrome/updater/policy/manager.h" namespace updater {
diff --git a/chrome/updater/mac/managed_preference_policy_manager_impl.h b/chrome/updater/policy/mac/managed_preference_policy_manager_impl.h similarity index 89% rename from chrome/updater/mac/managed_preference_policy_manager_impl.h rename to chrome/updater/policy/mac/managed_preference_policy_manager_impl.h index 925ccc0..7adcfad 100644 --- a/chrome/updater/mac/managed_preference_policy_manager_impl.h +++ b/chrome/updater/policy/mac/managed_preference_policy_manager_impl.h
@@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_UPDATER_MAC_MANAGED_PREFERENCE_POLICY_MANAGER_IMPL_H_ -#define CHROME_UPDATER_MAC_MANAGED_PREFERENCE_POLICY_MANAGER_IMPL_H_ +#ifndef CHROME_UPDATER_POLICY_MAC_MANAGED_PREFERENCE_POLICY_MANAGER_IMPL_H_ +#define CHROME_UPDATER_POLICY_MAC_MANAGED_PREFERENCE_POLICY_MANAGER_IMPL_H_ #import <Foundation/Foundation.h> -#include "chrome/updater/policy_manager.h" +#include "chrome/updater/policy/manager.h" // TODO: crbug/1073980 // Add a doc link for the managed preferences dictionary format. @@ -72,4 +72,4 @@ @end -#endif // CHROME_UPDATER_MAC_MANAGED_PREFERENCE_POLICY_MANAGER_IMPL_H_ +#endif // CHROME_UPDATER_POLICY_MAC_MANAGED_PREFERENCE_POLICY_MANAGER_IMPL_H_
diff --git a/chrome/updater/mac/managed_preference_policy_manager_impl.mm b/chrome/updater/policy/mac/managed_preference_policy_manager_impl.mm similarity index 98% rename from chrome/updater/mac/managed_preference_policy_manager_impl.mm rename to chrome/updater/policy/mac/managed_preference_policy_manager_impl.mm index fb15bec1..20803cbf 100644 --- a/chrome/updater/mac/managed_preference_policy_manager_impl.mm +++ b/chrome/updater/policy/mac/managed_preference_policy_manager_impl.mm
@@ -2,11 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#import "chrome/updater/mac/managed_preference_policy_manager_impl.h" +#import "chrome/updater/policy/mac/managed_preference_policy_manager_impl.h" #include "base/mac/scoped_nsobject.h" #include "chrome/updater/constants.h" -#include "chrome/updater/policy_manager.h" +#include "chrome/updater/policy/manager.h" // Constants for managed preference policy keys. static NSString* kGlobalPolicyKey = @"global";
diff --git a/chrome/updater/mac/managed_preference_policy_manager_impl_unittest.mm b/chrome/updater/policy/mac/managed_preference_policy_manager_impl_unittest.mm similarity index 98% rename from chrome/updater/mac/managed_preference_policy_manager_impl_unittest.mm rename to chrome/updater/policy/mac/managed_preference_policy_manager_impl_unittest.mm index dbd5be68e..34639989 100644 --- a/chrome/updater/mac/managed_preference_policy_manager_impl_unittest.mm +++ b/chrome/updater/policy/mac/managed_preference_policy_manager_impl_unittest.mm
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/updater/mac/managed_preference_policy_manager_impl.h" +#include "chrome/updater/policy/mac/managed_preference_policy_manager_impl.h" #include "base/mac/scoped_nsobject.h" #include "chrome/updater/constants.h"
diff --git a/chrome/updater/mac/managed_preference_policy_manager_unittest.cc b/chrome/updater/policy/mac/managed_preference_policy_manager_unittest.cc similarity index 84% rename from chrome/updater/mac/managed_preference_policy_manager_unittest.cc rename to chrome/updater/policy/mac/managed_preference_policy_manager_unittest.cc index d7e74268..33ceec96 100644 --- a/chrome/updater/mac/managed_preference_policy_manager_unittest.cc +++ b/chrome/updater/policy/mac/managed_preference_policy_manager_unittest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/updater/mac/managed_preference_policy_manager.h" +#include "chrome/updater/policy/mac/managed_preference_policy_manager.h" #include <memory>
diff --git a/chrome/updater/policy_manager.cc b/chrome/updater/policy/manager.cc similarity index 98% rename from chrome/updater/policy_manager.cc rename to chrome/updater/policy/manager.cc index fed631d..34cc1a8b 100644 --- a/chrome/updater/policy_manager.cc +++ b/chrome/updater/policy/manager.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/updater/policy_manager.h" +#include "chrome/updater/policy/manager.h" namespace updater {
diff --git a/chrome/updater/policy_manager.h b/chrome/updater/policy/manager.h similarity index 100% rename from chrome/updater/policy_manager.h rename to chrome/updater/policy/manager.h
diff --git a/chrome/updater/policy_manager_unittest.cc b/chrome/updater/policy/manager_unittest.cc similarity index 90% rename from chrome/updater/policy_manager_unittest.cc rename to chrome/updater/policy/manager_unittest.cc index 298f014..3d4b24d 100644 --- a/chrome/updater/policy_manager_unittest.cc +++ b/chrome/updater/policy/manager_unittest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/updater/policy_manager.h" +#include "chrome/updater/policy/manager.h" #include "testing/gtest/include/gtest/gtest.h" namespace updater {
diff --git a/chrome/updater/policy_service.cc b/chrome/updater/policy/service.cc similarity index 97% rename from chrome/updater/policy_service.cc rename to chrome/updater/policy/service.cc index 5a190dc..10dfc8a 100644 --- a/chrome/updater/policy_service.cc +++ b/chrome/updater/policy/service.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/updater/policy_service.h" +#include "chrome/updater/policy/service.h" #include <algorithm> @@ -13,9 +13,9 @@ #include "build/build_config.h" #if defined(OS_WIN) -#include "chrome/updater/win/group_policy_manager.h" +#include "chrome/updater/policy/win/group_policy_manager.h" #elif defined(OS_MAC) -#include "chrome/updater/mac/managed_preference_policy_manager.h" +#include "chrome/updater/policy/mac/managed_preference_policy_manager.h" #endif namespace updater {
diff --git a/chrome/updater/policy_service.h b/chrome/updater/policy/service.h similarity index 98% rename from chrome/updater/policy_service.h rename to chrome/updater/policy/service.h index 0ec97b6..15daf60b 100644 --- a/chrome/updater/policy_service.h +++ b/chrome/updater/policy/service.h
@@ -10,7 +10,7 @@ #include <vector> #include "base/callback_forward.h" -#include "chrome/updater/policy_manager.h" +#include "chrome/updater/policy/manager.h" #include "third_party/abseil-cpp/absl/types/optional.h" namespace updater {
diff --git a/chrome/updater/policy_service_unittest.cc b/chrome/updater/policy/service_unittest.cc similarity index 98% rename from chrome/updater/policy_service_unittest.cc rename to chrome/updater/policy/service_unittest.cc index 0eaebb5..4ff3513 100644 --- a/chrome/updater/policy_service_unittest.cc +++ b/chrome/updater/policy/service_unittest.cc
@@ -7,8 +7,8 @@ #include <utility> #include <vector> -#include "chrome/updater/policy_manager.h" -#include "chrome/updater/policy_service.h" +#include "chrome/updater/policy/manager.h" +#include "chrome/updater/policy/service.h" #include "testing/gtest/include/gtest/gtest.h" namespace updater {
diff --git a/chrome/updater/win/group_policy_manager.cc b/chrome/updater/policy/win/group_policy_manager.cc similarity index 98% rename from chrome/updater/win/group_policy_manager.cc rename to chrome/updater/policy/win/group_policy_manager.cc index cee913b..11ddbba 100644 --- a/chrome/updater/win/group_policy_manager.cc +++ b/chrome/updater/policy/win/group_policy_manager.cc
@@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/updater/win/group_policy_manager.h" +#include "chrome/updater/policy/win/group_policy_manager.h" #include <string> #include "base/strings/sys_string_conversions.h" #include "base/win/win_util.h" -#include "chrome/updater/policy_manager.h" +#include "chrome/updater/policy/manager.h" #include "chrome/updater/win/constants.h" namespace updater {
diff --git a/chrome/updater/win/group_policy_manager.h b/chrome/updater/policy/win/group_policy_manager.h similarity index 90% rename from chrome/updater/win/group_policy_manager.h rename to chrome/updater/policy/win/group_policy_manager.h index d96839db..7245a67 100644 --- a/chrome/updater/win/group_policy_manager.h +++ b/chrome/updater/policy/win/group_policy_manager.h
@@ -2,14 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_UPDATER_WIN_GROUP_POLICY_MANAGER_H_ -#define CHROME_UPDATER_WIN_GROUP_POLICY_MANAGER_H_ +#ifndef CHROME_UPDATER_POLICY_WIN_GROUP_POLICY_MANAGER_H_ +#define CHROME_UPDATER_POLICY_WIN_GROUP_POLICY_MANAGER_H_ #include <memory> #include <string> #include "base/win/registry.h" -#include "chrome/updater/policy_manager.h" +#include "chrome/updater/policy/manager.h" namespace updater { @@ -58,4 +58,4 @@ } // namespace updater -#endif // CHROME_UPDATER_WIN_GROUP_POLICY_MANAGER_H_ +#endif // CHROME_UPDATER_POLICY_WIN_GROUP_POLICY_MANAGER_H_
diff --git a/chrome/updater/win/group_policy_manager_unittest.cc b/chrome/updater/policy/win/group_policy_manager_unittest.cc similarity index 92% rename from chrome/updater/win/group_policy_manager_unittest.cc rename to chrome/updater/policy/win/group_policy_manager_unittest.cc index 70ab7e4..6e1be2e4 100644 --- a/chrome/updater/win/group_policy_manager_unittest.cc +++ b/chrome/updater/policy/win/group_policy_manager_unittest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/updater/win/group_policy_manager.h" +#include "chrome/updater/policy/win/group_policy_manager.h" #include <memory>
diff --git a/chrome/updater/win/BUILD.gn b/chrome/updater/win/BUILD.gn index 94849fa..e731ac1 100644 --- a/chrome/updater/win/BUILD.gn +++ b/chrome/updater/win/BUILD.gn
@@ -102,8 +102,6 @@ sources = [ "action_handler.cc", - "group_policy_manager.cc", - "group_policy_manager.h", "installer.cc", "installer.h", "net/net_util.cc", @@ -161,6 +159,7 @@ "//chrome/updater/app/server/win:updater_idl_idl", "//chrome/updater/app/server/win:updater_internal_idl_idl", "//chrome/updater/app/server/win:updater_legacy_idl_idl", + "//chrome/updater/policy", "//components/update_client", "//url:url", ] @@ -225,7 +224,6 @@ testonly = true sources = [ - "group_policy_manager_unittest.cc", "installer_unittest.cc", "net/network_unittest.cc", "net/proxy_configuration_unittest.cc",
diff --git a/chrome/updater/win/net/proxy_configuration.cc b/chrome/updater/win/net/proxy_configuration.cc index 8e9441b..7fb9686 100644 --- a/chrome/updater/win/net/proxy_configuration.cc +++ b/chrome/updater/win/net/proxy_configuration.cc
@@ -9,7 +9,7 @@ #include "base/win/scoped_handle.h" #include "base/win/windows_version.h" #include "chrome/updater/constants.h" -#include "chrome/updater/policy_manager.h" +#include "chrome/updater/policy/service.h" #include "chrome/updater/win/net/net_util.h" #include "chrome/updater/win/net/proxy_info.h" #include "chrome/updater/win/net/scoped_winttp_proxy_info.h" @@ -164,9 +164,10 @@ } scoped_refptr<ProxyConfiguration> GetProxyConfiguration() { - std::unique_ptr<PolicyManagerInterface> policy_manager = GetPolicyManager(); + std::unique_ptr<PolicyService> policy_service = GetUpdaterPolicyService(); + std::string policy_proxy_mode; - if (policy_manager->GetProxyMode(&policy_proxy_mode) && + if (policy_service->GetProxyMode(nullptr, &policy_proxy_mode) && policy_proxy_mode.compare(kProxyModeSystem) != 0) { DVLOG(3) << "Using policy proxy " << policy_proxy_mode; bool auto_detect = false; @@ -176,7 +177,7 @@ if (policy_proxy_mode.compare(kProxyModeFixedServers) == 0) { std::string policy_proxy_url; - if (!policy_manager->GetProxyServer(&policy_proxy_url)) { + if (!policy_service->GetProxyServer(nullptr, &policy_proxy_url)) { VLOG(1) << "Fixed server mode proxy has no URL specified."; is_policy_config_valid = false; } else { @@ -184,7 +185,7 @@ } } else if (policy_proxy_mode.compare(kProxyModePacScript) == 0) { std::string policy_pac_url; - if (!policy_manager->GetProxyServer(&policy_pac_url)) { + if (!policy_service->GetProxyServer(nullptr, &policy_pac_url)) { VLOG(1) << "PAC proxy policy has no PAC URL specified."; is_policy_config_valid = false; } else {
diff --git a/chromecast/browser/cast_browser_context.cc b/chromecast/browser/cast_browser_context.cc index 205a340..f7a73bc 100644 --- a/chromecast/browser/cast_browser_context.cc +++ b/chromecast/browser/cast_browser_context.cc
@@ -52,7 +52,7 @@ CastBrowserContext::~CastBrowserContext() { SimpleKeyMap::GetInstance()->Dissociate(this); - BrowserContext::NotifyWillBeDestroyed(this); + NotifyWillBeDestroyed(); ShutdownStoragePartitions(); content::GetIOThreadTaskRunner({})->DeleteSoon(FROM_HERE, resource_context_.release());
diff --git a/chromecast/browser/webview/webview_browser_context.cc b/chromecast/browser/webview/webview_browser_context.cc index 616e1774..51414ee 100644 --- a/chromecast/browser/webview/webview_browser_context.cc +++ b/chromecast/browser/webview/webview_browser_context.cc
@@ -30,7 +30,7 @@ } WebviewBrowserContext::~WebviewBrowserContext() { - BrowserContext::NotifyWillBeDestroyed(this); + NotifyWillBeDestroyed(); ShutdownStoragePartitions(); BrowserContextDependencyManager::GetInstance()->DestroyBrowserContextServices( this);
diff --git a/chromeos/ime/BUILD.gn b/chromeos/ime/BUILD.gn index a8086cd..7f07c98 100644 --- a/chromeos/ime/BUILD.gn +++ b/chromeos/ime/BUILD.gn
@@ -2,10 +2,7 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -import("//build/config/python.gni") - -# TODO(crbug.com/1112471): Get this to run cleanly under Python 3. -python2_action("gencode") { +action("gencode") { script = "gen_input_methods.py" sources = [ "//chromeos/ime/input_methods.txt" ] outputs = [ "$target_gen_dir/input_methods.h" ]
diff --git a/chromeos/ime/gen_input_methods.py b/chromeos/ime/gen_input_methods.py index 93a14b8..04eaf349 100755 --- a/chromeos/ime/gen_input_methods.py +++ b/chromeos/ime/gen_input_methods.py
@@ -36,6 +36,8 @@ """ +from __future__ import print_function + import fileinput import re import sys @@ -78,7 +80,7 @@ def main(argv): if len(argv) != 3: - print 'Usage: gen_input_methods.py [input_methods.txt] [output]' + print('Usage: gen_input_methods.py [input_methods.txt] [output]') sys.exit(1) login_xkb_layout_ids = [] for line in fileinput.input(sys.argv[1]):
diff --git a/chromeos/network/network_state.cc b/chromeos/network/network_state.cc index 76ce1585..5269887 100644 --- a/chromeos/network/network_state.cc +++ b/chromeos/network/network_state.cc
@@ -533,8 +533,6 @@ network_config::mojom::ActivationStateType NetworkState::GetMojoActivationState() const { using network_config::mojom::ActivationStateType; - if (IsNonShillCellularNetwork()) - return ActivationStateType::kNoService; if (activation_state_.empty()) return ActivationStateType::kUnknown; if (activation_state_ == shill::kActivationStateActivated) @@ -626,6 +624,7 @@ new_state->iccid_ = iccid; new_state->eid_ = eid; new_state->guid_ = guid; + new_state->activation_state_ = shill::kActivationStateActivated; return new_state; }
diff --git a/chromeos/services/nearby/public/cpp/nearby_process_manager.h b/chromeos/services/nearby/public/cpp/nearby_process_manager.h index 42734f2c..684c09a 100644 --- a/chromeos/services/nearby/public/cpp/nearby_process_manager.h +++ b/chromeos/services/nearby/public/cpp/nearby_process_manager.h
@@ -62,6 +62,9 @@ // shutting down. virtual std::unique_ptr<NearbyProcessReference> GetNearbyProcessReference( NearbyProcessStoppedCallback on_process_stopped_callback) = 0; + + private: + using KeyedService::Shutdown; }; std::ostream& operator<<(
diff --git a/codelabs/DIR_METADATA b/codelabs/DIR_METADATA index 2217bb55..fba861d7 100644 --- a/codelabs/DIR_METADATA +++ b/codelabs/DIR_METADATA
@@ -1,10 +1,10 @@ # Metadata information for this directory. # # For more information on DIR_METADATA files, see: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md # # For the schema of this file, see Metadata message: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto monorail { component: "Infra>Documentation"
diff --git a/codelabs/cpp101/codelab.md b/codelabs/cpp101/codelab.md index 13cd52b7..4c30533 100644 --- a/codelabs/cpp101/codelab.md +++ b/codelabs/cpp101/codelab.md
@@ -9,10 +9,10 @@ As always, consider the following resources as of primary importance: -- [Coding Style](https://chromium.googlesource.com/chromium/src/+/master/styleguide/styleguide.md) +- [Coding Style](https://chromium.googlesource.com/chromium/src/+/main/styleguide/styleguide.md) - [Callback<> and Bind()](https://chromium.googlesource.com/chromium/src/+/HEAD/docs/callback.md) -- [Threading and Tasks in Chrome](https://chromium.googlesource.com/chromium/src/+/master/docs/threading_and_tasks.md) -- [Intro to Mojo & Services](https://chromium.googlesource.com/chromium/src.git/+/master/docs/mojo_and_services.md) +- [Threading and Tasks in Chrome](https://chromium.googlesource.com/chromium/src/+/main/docs/threading_and_tasks.md) +- [Intro to Mojo & Services](https://chromium.googlesource.com/chromium/src.git/+/main/docs/mojo_and_services.md) - [Important Abstractions and Data Structures](https://sites.google.com/a/chromium.org/dev/developers/coding-style/important-abstractions-and-data-structures) (badly needs updating) This tutorial does not assume you have read any of the above, @@ -49,8 +49,8 @@ ### More information -[Git Tips](https://chromium.googlesource.com/chromium/src.git/+/master/docs/git_tips.md) -and [Git Cookbook](https://chromium.googlesource.com/chromium/src.git/+/master/docs/git_cookbook.md) +[Git Tips](https://chromium.googlesource.com/chromium/src.git/+/main/docs/git_tips.md) +and [Git Cookbook](https://chromium.googlesource.com/chromium/src.git/+/main/docs/git_cookbook.md) [Life of a Chromium Developer](https://docs.google.com/a/google.com/presentation/d/1abnqM9j6zFodPHA38JG1061rG2iGj_GABxEDgZsdbJg/) @@ -193,7 +193,7 @@ ## Part 3: Threads and task runners Chromium has a number of abstractions for sequencing and threading. -[Threading and Tasks in Chrome](https://chromium.googlesource.com/chromium/src/+/master/docs/threading_and_tasks.md) +[Threading and Tasks in Chrome](https://chromium.googlesource.com/chromium/src/+/main/docs/threading_and_tasks.md) is a must-read and go-to reference for anything related to tasks, thread pools, task runners, and more. @@ -261,22 +261,22 @@ ### More information -[Threading and Tasks in Chrome](https://chromium.googlesource.com/chromium/src/+/master/docs/threading_and_tasks.md) +[Threading and Tasks in Chrome](https://chromium.googlesource.com/chromium/src/+/main/docs/threading_and_tasks.md) ## Part 4: Mojo Mojo is Chromium's abstraction of IPC. Mojo allows for developers to easily connect interface clients and implementations across arbitrary intra- and inter-process boundaries. See the -[Intro to Mojo and Services](https://chromium.googlesource.com/chromium/src.git/+/master/docs/mojo_and_services.md) +[Intro to Mojo and Services](https://chromium.googlesource.com/chromium/src.git/+/main/docs/mojo_and_services.md) guide to get started. ### Exercise 4: Building a simple out-of-process service -See the [building a simple out-of-process service](https://chromium.googlesource.com/chromium/src.git/+/master/docs/mojo_and_services.md#example_building-a-simple-out_of_process-service) +See the [building a simple out-of-process service](https://chromium.googlesource.com/chromium/src.git/+/main/docs/mojo_and_services.md#example_building-a-simple-out_of_process-service) tutorial on using Mojo to define, hook up, and launch an out-of-process service. ### More Information -[Mojo C++ Bindings API Docs](https://chromium.googlesource.com/chromium/src.git/+/master/mojo/public/cpp/bindings/README.md) -[Mojo Docs](https://chromium.googlesource.com/chromium/src.git/+/master/mojo/README.md) +[Mojo C++ Bindings API Docs](https://chromium.googlesource.com/chromium/src.git/+/main/mojo/public/cpp/bindings/README.md) +[Mojo Docs](https://chromium.googlesource.com/chromium/src.git/+/main/mojo/README.md)
diff --git a/components/arc/mojom/payment_app.mojom b/components/arc/mojom/payment_app.mojom index a52ba82..d206f0d4 100644 --- a/components/arc/mojom/payment_app.mojom +++ b/components/arc/mojom/payment_app.mojom
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Next MinVersion: 3 +// Next MinVersion: 4 module arc.mojom; @@ -85,6 +85,11 @@ // not currently need this parameter. [MinVersion=2] string? payment_request_id; + + // Opaque, browser-generated identifier for this payment request. Used to + // identify a particular request across calls. + [MinVersion=3] + string? request_token; }; // After the browser calls IsReadyToPay(), ARC sends back this result. @@ -165,4 +170,14 @@ [MinVersion=2] InvokePaymentApp@2(PaymentParameters parameters) => (InvokePaymentAppResult response); + + // Requests to abort a previous payment flow (identified by |request_token|) + // which was opened with InvokePaymentApp(). + // + // This may be called by the website if a payment should no longer be made + // (e.g., when an item goes out of stock), or by the browser if the payment is + // no longer available (e.g., the page was refreshed). + [MinVersion=3] + AbortPaymentApp@3(string request_token) + => (bool aborted); };
diff --git a/components/arc/pay/arc_payment_app_bridge.cc b/components/arc/pay/arc_payment_app_bridge.cc index 33c435d0..c869700 100644 --- a/components/arc/pay/arc_payment_app_bridge.cc +++ b/components/arc/pay/arc_payment_app_bridge.cc
@@ -100,4 +100,16 @@ payment_app->InvokePaymentApp(std::move(parameters), std::move(callback)); } +void ArcPaymentAppBridge::AbortPaymentApp(const std::string& request_token, + AbortPaymentAppCallback callback) { + mojom::PaymentAppInstance* payment_app = ARC_GET_INSTANCE_FOR_METHOD( + arc_bridge_service_->payment_app(), AbortPaymentApp); + if (!payment_app) { + std::move(callback).Run(false); + return; + } + + payment_app->AbortPaymentApp(request_token, std::move(callback)); +} + } // namespace arc
diff --git a/components/arc/pay/arc_payment_app_bridge.h b/components/arc/pay/arc_payment_app_bridge.h index 2d8583bd..d0b5c55 100644 --- a/components/arc/pay/arc_payment_app_bridge.h +++ b/components/arc/pay/arc_payment_app_bridge.h
@@ -28,6 +28,7 @@ base::OnceCallback<void(mojom::IsReadyToPayResultPtr)>; using InvokePaymentAppCallback = base::OnceCallback<void(mojom::InvokePaymentAppResultPtr)>; + using AbortPaymentAppCallback = base::OnceCallback<void(bool)>; // Returns the instance owned by the given BrowserContext, or nullptr if the // browser |context| is not allowed to use ARC. @@ -60,6 +61,10 @@ void InvokePaymentApp(mojom::PaymentParametersPtr parameters, InvokePaymentAppCallback callback); + // Aborts an existing TWA payment app flow. + void AbortPaymentApp(const std::string& request_token, + AbortPaymentAppCallback callback); + private: ArcBridgeService* const arc_bridge_service_; // Owned by ArcServiceManager. };
diff --git a/components/arc/pay/arc_payment_app_bridge_unittest.cc b/components/arc/pay/arc_payment_app_bridge_unittest.cc index 57876c4e..2017520e 100644 --- a/components/arc/pay/arc_payment_app_bridge_unittest.cc +++ b/components/arc/pay/arc_payment_app_bridge_unittest.cc
@@ -13,6 +13,7 @@ #include "content/public/test/browser_task_environment.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace arc { namespace { @@ -39,10 +40,13 @@ invoke_app_ = std::move(response); } + void OnAbortPaymentAppResponse(bool response) { abort_app_ = response; } + ArcPaymentAppBridgeTestSupport support_; mojom::IsPaymentImplementedResultPtr is_implemented_; mojom::IsReadyToPayResultPtr is_ready_to_pay_; mojom::InvokePaymentAppResultPtr invoke_app_; + absl::optional<bool> abort_app_; }; TEST_F(ArcPaymentAppBridgeTest, UnableToConnectInIsImplemented) { @@ -305,5 +309,41 @@ EXPECT_EQ("Error message.", invoke_app_->get_error()); } +TEST_F(ArcPaymentAppBridgeTest, UnableToConnectAbortPaymentApp) { + // Intentionally do not set an instance. + + EXPECT_CALL(*support_.instance(), AbortPaymentApp(testing::_, testing::_)) + .Times(0); + + ArcPaymentAppBridge::GetForBrowserContextForTesting(support_.context()) + ->AbortPaymentApp( + "some token", + base::BindOnce(&ArcPaymentAppBridgeTest::OnAbortPaymentAppResponse, + base::Unretained(this))); + + ASSERT_TRUE(abort_app_.has_value()); + ASSERT_FALSE(abort_app_.value()); +} + +TEST_F(ArcPaymentAppBridgeTest, AbortPaymentAppOK) { + auto scoped_set_instance = support_.CreateScopedSetInstance(); + + EXPECT_CALL(*support_.instance(), AbortPaymentApp(testing::_, testing::_)) + .WillOnce(testing::Invoke( + [](const std::string& request_token, + ArcPaymentAppBridge::AbortPaymentAppCallback callback) { + std::move(callback).Run(true); + })); + + ArcPaymentAppBridge::GetForBrowserContextForTesting(support_.context()) + ->AbortPaymentApp( + "some token", + base::BindOnce(&ArcPaymentAppBridgeTest::OnAbortPaymentAppResponse, + base::Unretained(this))); + + ASSERT_TRUE(abort_app_.has_value()); + ASSERT_TRUE(abort_app_.value()); +} + } // namespace } // namespace arc
diff --git a/components/arc/test/arc_payment_app_bridge_test_support.h b/components/arc/test/arc_payment_app_bridge_test_support.h index 7c14fa2..5315566 100644 --- a/components/arc/test/arc_payment_app_bridge_test_support.h +++ b/components/arc/test/arc_payment_app_bridge_test_support.h
@@ -44,6 +44,9 @@ MOCK_METHOD2(InvokePaymentApp, void(mojom::PaymentParametersPtr, ArcPaymentAppBridge::InvokePaymentAppCallback)); + MOCK_METHOD2(AbortPaymentApp, + void(const std::string&, + ArcPaymentAppBridge::AbortPaymentAppCallback)); }; // Sets up the payment_app.mojom connection in the constructor and disconnects
diff --git a/components/autofill/core/browser/autofill_client.cc b/components/autofill/core/browser/autofill_client.cc index f8ffc93..a13ad261 100644 --- a/components/autofill/core/browser/autofill_client.cc +++ b/components/autofill/core/browser/autofill_client.cc
@@ -66,11 +66,10 @@ // ChromeAutofillClient (Chrome Desktop and Clank) implements this. } -void AutofillClient::ShowVirtualCardManualFallbackBubble( - const CreditCard* credit_card, - const std::u16string& cvc) { +void AutofillClient::OnVirtualCardFetched(const CreditCard* credit_card, + const std::u16string& cvc) { // This is overridden by platform subclasses. Currently only - // ChromeAutofillClient (Chrome Desktop) implements this. + // ChromeAutofillClient (Chrome Desktop & Android) implements this. } bool AutofillClient::IsAutofillAssistantShowing() {
diff --git a/components/autofill/core/browser/autofill_client.h b/components/autofill/core/browser/autofill_client.h index 6eedae2..98c2b6c 100644 --- a/components/autofill/core/browser/autofill_client.h +++ b/components/autofill/core/browser/autofill_client.h
@@ -545,11 +545,10 @@ virtual void ShowOfferNotificationIfApplicable( const AutofillOfferData* offer); - // Shows the manual fallback bubble and displya card information in - // |credit_card| and |cvc|. - virtual void ShowVirtualCardManualFallbackBubble( - const CreditCard* credit_card, - const std::u16string& cvc); + // Indicates that the virtual card was fetched in order to allow the user to + // manually fill payment form with the fetched |credit_card| and |cvc|. + virtual void OnVirtualCardFetched(const CreditCard* credit_card, + const std::u16string& cvc); // Returns true if the Autofill Assistant UI is currently being shown. virtual bool IsAutofillAssistantShowing();
diff --git a/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.cc b/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.cc index 6d56793..f5ca074d 100644 --- a/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.cc +++ b/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.cc
@@ -9,7 +9,6 @@ #include "base/stl_util.h" #include "base/strings/utf_string_conversions.h" #include "components/autofill/core/browser/autofill_address_util.h" -#include "components/autofill/core/browser/data_model/autofill_profile_comparator.h" #include "components/autofill/core/common/autofill_constants.h" #include "components/grit/components_scaled_resources.h" #include "components/infobars/core/infobar.h" @@ -99,10 +98,10 @@ return profile_.GetInfo(type, locale_); } -base::flat_map<ServerFieldType, std::pair<std::u16string, std::u16string>> +std::vector<ProfileValueDifference> AutofillSaveUpdateAddressProfileDelegateIOS::GetProfileDiff() const { - return AutofillProfileComparator::GetSettingsVisibleProfileDifferenceMap( - *GetProfile(), *GetOriginalProfile(), locale_); + return GetProfileDifferenceForUi(*GetProfile(), *GetOriginalProfile(), + locale_); } bool AutofillSaveUpdateAddressProfileDelegateIOS::EditAccepted() {
diff --git a/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.h b/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.h index ae3378a..037a82a5 100644 --- a/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.h +++ b/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.h
@@ -11,6 +11,7 @@ #include "base/containers/flat_map.h" #include "components/autofill/core/browser/autofill_client.h" #include "components/autofill/core/browser/data_model/autofill_profile.h" +#include "components/autofill/core/browser/data_model/autofill_profile_comparator.h" #include "components/infobars/core/confirm_infobar_delegate.h" namespace autofill { @@ -54,10 +55,9 @@ // Returns the data stored in the |profile_| corresponding to |type|. std::u16string GetProfileInfo(ServerFieldType type) const; - // Uses |AutofillProfileComparator::GetSettingsVisibleProfileDifferenceMap| to - // get profile difference map between |profile_| and |original_profile_|; - base::flat_map<ServerFieldType, std::pair<std::u16string, std::u16string>> - GetProfileDiff() const; + // Returns the profile difference map between |profile_| and + // |original_profile_|. + std::vector<ProfileValueDifference> GetProfileDiff() const; // Calls |RunSaveAddressProfilePromptCallback| with the kEditAccepted| // decision.
diff --git a/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios_unittest.cc b/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios_unittest.cc index f34fb216..15d20e3 100644 --- a/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios_unittest.cc +++ b/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios_unittest.cc
@@ -60,29 +60,4 @@ std::u16string(u"John Doe, 666 Erebus St.")); } -// Tests that delegate returns the correct profile difference. -TEST(AutofillSaveUpdateAddressProfileDelegateIOSTest, TestProfileDiff) { - AutofillProfile profile = test::GetFullProfile(); - AutofillProfile original_profile = test::GetFullProfile2(); - original_profile.SetInfo(NAME_FULL, u"John Doe", "en-US"); - auto delegate = std::make_unique<AutofillSaveUpdateAddressProfileDelegateIOS>( - profile, &original_profile, /*locale=*/"en-US", base::DoNothing()); - - base::flat_map<ServerFieldType, std::pair<std::u16string, std::u16string>> - expected_difference; - expected_difference.insert({NAME_FULL, {u"John H. Doe", u"John Doe"}}); - expected_difference.insert( - {EMAIL_ADDRESS, {u"johndoe@hades.com", u"jsmith@example.com"}}); - expected_difference.insert( - {PHONE_HOME_WHOLE_NUMBER, {u"16502111111", u"13105557889"}}); - expected_difference.insert({ADDRESS_HOME_CITY, {u"Elysium", u"Greensdale"}}); - expected_difference.insert({ADDRESS_HOME_STATE, {u"CA", u"MI"}}); - expected_difference.insert({ADDRESS_HOME_ZIP, {u"91111", u"48838"}}); - expected_difference.insert({COMPANY_NAME, {u"Underworld", u"ACME"}}); - expected_difference.insert( - {ADDRESS_HOME_STREET_ADDRESS, - {u"666 Erebus St.\nApt 8", u"123 Main Street\nUnit 1"}}); - EXPECT_EQ(delegate->GetProfileDiff(), expected_difference); -} - } // namespace autofill
diff --git a/components/autofill/core/browser/browser_autofill_manager.cc b/components/autofill/core/browser/browser_autofill_manager.cc index 7f970d9..55789c8 100644 --- a/components/autofill/core/browser/browser_autofill_manager.cc +++ b/components/autofill/core/browser/browser_autofill_manager.cc
@@ -1471,11 +1471,10 @@ DCHECK(credit_card); - // If synced down card is a virtual card, show a manual fallback bubble for - // it in addition to filling the card. - if (credit_card->record_type() == CreditCard::VIRTUAL_CARD) { - client()->ShowVirtualCardManualFallbackBubble(credit_card, cvc); - } + // If synced down card is a virtual card, let the client know so that it can + // show the UI to help user to manually fill the form, if needed. + if (credit_card->record_type() == CreditCard::VIRTUAL_CARD) + client()->OnVirtualCardFetched(credit_card, cvc); FillCreditCardForm(credit_card_query_id_, credit_card_form_, credit_card_field_, *credit_card, cvc);
diff --git a/components/browser_ui/widget/android/BUILD.gn b/components/browser_ui/widget/android/BUILD.gn index c574de52..ec8c8cd 100644 --- a/components/browser_ui/widget/android/BUILD.gn +++ b/components/browser_ui/widget/android/BUILD.gn
@@ -270,6 +270,7 @@ "java/src/org/chromium/components/browser_ui/widget/RadioButtonWithDescriptionAndAuxButtonTest.java", "java/src/org/chromium/components/browser_ui/widget/RadioButtonWithDescriptionLayoutTest.java", "java/src/org/chromium/components/browser_ui/widget/RadioButtonWithEditTextTest.java", + "java/src/org/chromium/components/browser_ui/widget/RadioButtonWithIconRenderTest.java", "java/src/org/chromium/components/browser_ui/widget/RoundedIconGeneratorTest.java", "java/src/org/chromium/components/browser_ui/widget/WrappingLayoutTest.java", "java/src/org/chromium/components/browser_ui/widget/highlight/ViewHighlighterTest.java", @@ -320,6 +321,7 @@ "test/java/res/layout/radio_button_with_description_and_aux_button_test.xml", "test/java/res/layout/radio_button_with_description_layout_test.xml", "test/java/res/layout/radio_button_with_edit_text_test.xml", + "test/java/res/layout/radio_button_with_icon_render_test.xml", "test/java/res/values/strings.xml", ] deps = [
diff --git a/components/browser_ui/widget/android/java/res/layout/radio_button_with_description.xml b/components/browser_ui/widget/android/java/res/layout/radio_button_with_description.xml index 97f6c58..dffe06b 100644 --- a/components/browser_ui/widget/android/java/res/layout/radio_button_with_description.xml +++ b/components/browser_ui/widget/android/java/res/layout/radio_button_with_description.xml
@@ -24,11 +24,22 @@ android:focusable="false" android:background="@null" /> + <org.chromium.ui.widget.ChromeImageView + android:id="@+id/icon" + android:layout_width="@dimen/radio_button_with_description_icon_size" + android:layout_height="@dimen/radio_button_with_description_icon_size" + android:layout_marginEnd="16dp" + android:layout_toEndOf="@id/radio_button" + android:layout_centerVertical="true" + android:scaleType="fitCenter" + android:tint="@color/default_icon_color" + android:visibility="gone" /> + <TextView android:id="@+id/primary" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_toEndOf="@id/radio_button" + android:layout_toEndOf="@id/icon" android:textAppearance="@style/TextAppearance.TextLarge.Primary" /> <!-- This TextView is hidden if it has no text, so the initial visibility should be "gone". -->
diff --git a/components/browser_ui/widget/android/java/res/values/attrs.xml b/components/browser_ui/widget/android/java/res/values/attrs.xml index fbfc960..5a0cd87 100644 --- a/components/browser_ui/widget/android/java/res/values/attrs.xml +++ b/components/browser_ui/widget/android/java/res/values/attrs.xml
@@ -53,6 +53,7 @@ <declare-styleable name="RadioButtonWithDescription"> <attr name="primaryText" format="string" /> <attr name="descriptionText" format="string" /> + <attr name="iconSrc" format="reference" /> </declare-styleable> <declare-styleable name="RadioButtonWithEditText">
diff --git a/components/browser_ui/widget/android/java/res/values/dimens.xml b/components/browser_ui/widget/android/java/res/values/dimens.xml index 80a8990..5233ea8 100644 --- a/components/browser_ui/widget/android/java/res/values/dimens.xml +++ b/components/browser_ui/widget/android/java/res/values/dimens.xml
@@ -26,6 +26,7 @@ <!-- RadioButtonWithDescription --> <dimen name="radio_button_with_description_lateral_padding">16dp</dimen> <dimen name="radio_button_with_description_vertical_padding">10dp</dimen> + <dimen name="radio_button_with_description_icon_size">24dp</dimen> <!-- RadioButtonWithDescriptionAndAuxButton --> <dimen name="radio_button_with_description_and_aux_button_spacing">10dp</dimen>
diff --git a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/RadioButtonWithDescription.java b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/RadioButtonWithDescription.java index 143a520..faec3e02 100644 --- a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/RadioButtonWithDescription.java +++ b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/RadioButtonWithDescription.java
@@ -6,6 +6,7 @@ import android.content.Context; import android.content.res.TypedArray; +import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.Parcelable; import android.text.TextUtils; @@ -20,6 +21,9 @@ import android.widget.RelativeLayout; import android.widget.TextView; +import org.chromium.ui.UiUtils; +import org.chromium.ui.widget.ChromeImageView; + import java.util.List; /** @@ -48,6 +52,7 @@ * android:id="@+id/system_default" * android:layout_width="match_parent" * android:layout_height="wrap_content" + * app:iconSrc="@drawable/ic_foo" <-- optional --> * app:primaryText="@string/feature_foo_option_one" * app:descriptionText="@string/feature_foo_option_one_description" /> * } </pre> @@ -66,6 +71,7 @@ } private RadioButton mRadioButton; + private ChromeImageView mIcon; private TextView mPrimary; private TextView mDescription; @@ -133,6 +139,7 @@ */ protected void setViewsInternal() { mRadioButton = getRadioButtonView(); + mIcon = getIcon(); mPrimary = getPrimaryTextView(); mDescription = getDescriptionTextView(); @@ -159,6 +166,13 @@ } /** + * @return ChromeImageView inside this {@link RadioButtonWithDescription}. + */ + protected ChromeImageView getIcon() { + return (ChromeImageView) findViewById(R.id.icon); + } + + /** * @return TextView displayed as primary inside this {@link RadioButtonWithDescription}. */ protected TextView getPrimaryTextView() { @@ -188,6 +202,14 @@ TypedArray a = getContext().getTheme().obtainStyledAttributes( attrs, R.styleable.RadioButtonWithDescription, 0, 0); + Drawable iconDrawable = UiUtils.getDrawable( + getContext(), a, R.styleable.RadioButtonWithDescription_iconSrc); + + if (iconDrawable != null) { + mIcon.setImageDrawable(iconDrawable); + mIcon.setVisibility(View.VISIBLE); + } + String primaryText = a.getString(R.styleable.RadioButtonWithDescription_primaryText); if (primaryText != null) mPrimary.setText(primaryText);
diff --git a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/RadioButtonWithIconRenderTest.java b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/RadioButtonWithIconRenderTest.java new file mode 100644 index 0000000..c04f678 --- /dev/null +++ b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/RadioButtonWithIconRenderTest.java
@@ -0,0 +1,91 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.components.browser_ui.widget; + +import android.app.Activity; +import android.graphics.Color; +import android.view.LayoutInflater; +import android.view.View; + +import androidx.test.filters.SmallTest; + +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.test.params.BaseJUnit4RunnerDelegate; +import org.chromium.base.test.params.ParameterAnnotations.ClassParameter; +import org.chromium.base.test.params.ParameterAnnotations.UseRunnerDelegate; +import org.chromium.base.test.params.ParameterSet; +import org.chromium.base.test.params.ParameterizedRunner; +import org.chromium.base.test.util.Feature; +import org.chromium.components.browser_ui.widget.test.R; +import org.chromium.content_public.browser.test.util.TestThreadUtils; +import org.chromium.ui.test.util.DummyUiActivityTestCase; +import org.chromium.ui.test.util.NightModeTestUtils; +import org.chromium.ui.test.util.RenderTestRule; + +import java.util.List; + +/** + * Render test for {@link RadioButtonWithDescription} with the icon. + */ +@RunWith(ParameterizedRunner.class) +@UseRunnerDelegate(BaseJUnit4RunnerDelegate.class) +public class RadioButtonWithIconRenderTest extends DummyUiActivityTestCase { + @ClassParameter + private static List<ParameterSet> sClassParams = + new NightModeTestUtils.NightModeParams().getParameters(); + + @Rule + public RenderTestRule mRenderTestRule = RenderTestRule.Builder.withPublicCorpus().build(); + + private RadioButtonWithDescriptionLayout mLayout; + + private RadioButtonWithDescription mRadioButtonWithIcon1; + private RadioButtonWithDescription mRadioButtonWithIcon2; + private RadioButtonWithDescription mRadioButtonWithIcon3; + + private final int mFakeBgColor; + + public RadioButtonWithIconRenderTest(boolean nightModeEnabled) { + mFakeBgColor = nightModeEnabled ? Color.BLACK : Color.WHITE; + NightModeTestUtils.setUpNightModeForDummyUiActivity(nightModeEnabled); + mRenderTestRule.setNightModeEnabled(nightModeEnabled); + } + + @Override + public void setUpTest() throws Exception { + super.setUpTest(); + Activity activity = getActivity(); + TestThreadUtils.runOnUiThreadBlocking(() -> { + View content = LayoutInflater.from(activity).inflate( + R.layout.radio_button_with_icon_render_test, null, false); + activity.setContentView(content); + + mLayout = content.findViewById(R.id.test_radio_button_layout); + mLayout.setBackgroundColor(mFakeBgColor); + + mRadioButtonWithIcon1 = content.findViewById(R.id.test_radio_icon_1); + mRadioButtonWithIcon2 = content.findViewById(R.id.test_radio_icon_2); + mRadioButtonWithIcon3 = content.findViewById(R.id.test_radio_icon_3); + }); + + Assert.assertNotNull(mLayout); + Assert.assertNotNull(mRadioButtonWithIcon1); + Assert.assertNotNull(mRadioButtonWithIcon2); + Assert.assertNotNull(mRadioButtonWithIcon3); + } + + @Test + @SmallTest + @Feature({"RenderTest", "RadioButton"}) + public void testRadioButtonWithIcon() throws Exception { + mRenderTestRule.render(mRadioButtonWithIcon1, "test_radio_icon_1"); + mRenderTestRule.render(mRadioButtonWithIcon2, "test_radio_icon_2"); + mRenderTestRule.render(mRadioButtonWithIcon3, "test_radio_icon_3"); + } +} \ No newline at end of file
diff --git a/components/browser_ui/widget/android/test/java/res/layout/radio_button_with_icon_render_test.xml b/components/browser_ui/widget/android/test/java/res/layout/radio_button_with_icon_render_test.xml new file mode 100644 index 0000000..1d479a0c --- /dev/null +++ b/components/browser_ui/widget/android/test/java/res/layout/radio_button_with_icon_render_test.xml
@@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2021 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. --> + +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <org.chromium.components.browser_ui.widget.RadioButtonWithDescriptionLayout + android:id="@+id/test_radio_button_layout" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <!-- RadioButtonWithDescription - With icon and primary, without description. --> + <org.chromium.components.browser_ui.widget.RadioButtonWithDescription + android:id="@+id/test_radio_icon_1" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:iconSrc="@drawable/test_ic_more_vert_black_24dp" + app:primaryText="@string/test_string" /> + + <!-- RadioButtonWithDescription - With icon, primary and description. --> + <org.chromium.components.browser_ui.widget.RadioButtonWithDescription + android:id="@+id/test_radio_icon_2" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:iconSrc="@drawable/test_ic_more_vert_black_24dp" + app:primaryText="@string/test_string" + app:descriptionText="@string/test_string" /> + + <!-- RadioButtonWithDescription - With background override. --> + <org.chromium.components.browser_ui.widget.RadioButtonWithDescription + android:id="@+id/test_radio_icon_3" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="@color/background_color_non_empty" + app:iconSrc="@drawable/test_ic_more_vert_black_24dp" + app:primaryText="@string/test_string" + app:descriptionText="@string/test_string" /> + + </org.chromium.components.browser_ui.widget.RadioButtonWithDescriptionLayout> +</FrameLayout> \ No newline at end of file
diff --git a/components/full_restore/arc_save_handler.cc b/components/full_restore/arc_save_handler.cc index 45480cd..51f28af3 100644 --- a/components/full_restore/arc_save_handler.cc +++ b/components/full_restore/arc_save_handler.cc
@@ -19,7 +19,7 @@ // Repeat timer interval between each checking that whether a task is created // for each app launching. constexpr base::TimeDelta kCheckCycleInterval = - base::TimeDelta::FromSeconds(30); + base::TimeDelta::FromSeconds(600); } // namespace
diff --git a/components/full_restore/full_restore_read_and_save_unittest.cc b/components/full_restore/full_restore_read_and_save_unittest.cc index f53808c6..7ec3817 100644 --- a/components/full_restore/full_restore_read_and_save_unittest.cc +++ b/components/full_restore/full_restore_read_and_save_unittest.cc
@@ -116,11 +116,11 @@ if (it == session_id_to_app_launch_info.end()) return; - // If there is no task created for the session id in 30 seconds, the session - // id record is removed. So set the record time as 31 seconds ago, so that - // CheckTasksForAppLaunching can remove the session id record to simulate - // the task is not created for the session id. - it->second.second = it->second.second - base::TimeDelta::FromSeconds(31); + // If there is no task created for the session id in 600 seconds, the + // session id record is removed. So set the record time as 601 seconds ago, + // so that CheckTasksForAppLaunching can remove the session id record to + // simulate the task is not created for the session id. + it->second.second = it->second.second - base::TimeDelta::FromSeconds(601); } base::RepeatingTimer* GetArcCheckTimer() {
diff --git a/components/keyed_service/core/keyed_service.h b/components/keyed_service/core/keyed_service.h index 2bd32cf..df300b3 100644 --- a/components/keyed_service/core/keyed_service.h +++ b/components/keyed_service/core/keyed_service.h
@@ -30,6 +30,8 @@ virtual ~KeyedService(); // The first pass is to call Shutdown on a KeyedService. + // Shutdown will be called automatically for you. Don't directly invoke this + // unless you have a specific reason and understand the implications. virtual void Shutdown(); private:
diff --git a/components/os_crypt/key_storage_config_linux.h b/components/os_crypt/key_storage_config_linux.h index a8566047..72c16682 100644 --- a/components/os_crypt/key_storage_config_linux.h +++ b/components/os_crypt/key_storage_config_linux.h
@@ -26,6 +26,12 @@ std::string store; // The product name to use for permission prompts. std::string product_name; + // The application name to store the key under. For Chromium/Chrome builds + // leave this unset and it will default correctly. This config option is + // for embedders to provide their application name in place of "Chromium". + // Only used when the allow_runtime_configurable_key_storage feature is + // enabled. + std::string application_name; // A runner on the main thread for gnome-keyring to be called from. // TODO(crbug/466975): Libsecret and KWallet don't need this. We can remove // this when we stop supporting keyring.
diff --git a/components/os_crypt/key_storage_keyring.cc b/components/os_crypt/key_storage_keyring.cc index 29720b8e..3ad654c 100644 --- a/components/os_crypt/key_storage_keyring.cc +++ b/components/os_crypt/key_storage_keyring.cc
@@ -15,12 +15,6 @@ namespace { -#if BUILDFLAG(GOOGLE_CHROME_BRANDING) -const char kApplicationName[] = "chrome"; -#else -const char kApplicationName[] = "chromium"; -#endif - const GnomeKeyringPasswordSchema kSchema = { GNOME_KEYRING_ITEM_GENERIC_SECRET, {{"application", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING}, {nullptr}}}; @@ -28,8 +22,10 @@ } // namespace KeyStorageKeyring::KeyStorageKeyring( - scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner) - : main_thread_runner_(main_thread_runner) {} + scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner, + std::string application_name) + : main_thread_runner_(main_thread_runner), + application_name_(std::move(application_name)) {} KeyStorageKeyring::~KeyStorageKeyring() {} @@ -49,7 +45,8 @@ gchar* password_c = nullptr; GnomeKeyringResult result = GnomeKeyringLoader::gnome_keyring_find_password_sync_ptr( - &kSchema, &password_c, "application", kApplicationName, nullptr); + &kSchema, &password_c, "application", application_name_.c_str(), + nullptr); if (result == GNOME_KEYRING_RESULT_OK) { password = password_c; GnomeKeyringLoader::gnome_keyring_free_password_ptr(password_c); @@ -71,7 +68,7 @@ GnomeKeyringResult result = GnomeKeyringLoader::gnome_keyring_store_password_sync_ptr( &kSchema, nullptr /* default keyring */, KeyStorageLinux::kKey, - password.c_str(), "application", kApplicationName, nullptr); + password.c_str(), "application", application_name_.c_str(), nullptr); if (result != GNOME_KEYRING_RESULT_OK) { VLOG(1) << "OSCrypt failed to store generated password to gnome-keyring"; return absl::nullopt;
diff --git a/components/os_crypt/key_storage_keyring.h b/components/os_crypt/key_storage_keyring.h index 26a3f58..598c8b8a 100644 --- a/components/os_crypt/key_storage_keyring.h +++ b/components/os_crypt/key_storage_keyring.h
@@ -20,8 +20,9 @@ // Specialisation of KeyStorageLinux that uses Libsecret. class COMPONENT_EXPORT(OS_CRYPT) KeyStorageKeyring : public KeyStorageLinux { public: - explicit KeyStorageKeyring( - scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner); + KeyStorageKeyring( + scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner, + std::string application_name); ~KeyStorageKeyring() override; protected: @@ -37,6 +38,8 @@ // Keyring calls need to originate from the main thread. scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner_; + const std::string application_name_; + DISALLOW_COPY_AND_ASSIGN(KeyStorageKeyring); };
diff --git a/components/os_crypt/key_storage_keyring_unittest.cc b/components/os_crypt/key_storage_keyring_unittest.cc index aba3197..93fc216 100644 --- a/components/os_crypt/key_storage_keyring_unittest.cc +++ b/components/os_crypt/key_storage_keyring_unittest.cc
@@ -130,7 +130,7 @@ }; GnomeKeyringTest::GnomeKeyringTest() - : task_runner_(new base::TestSimpleTaskRunner()), keyring_(task_runner_) { + : task_runner_(new base::TestSimpleTaskRunner()), keyring_(task_runner_, "chromium") { MockGnomeKeyringLoader::ResetForOSCrypt(); }
diff --git a/components/os_crypt/key_storage_libsecret.cc b/components/os_crypt/key_storage_libsecret.cc index 0857cc1..ccc6052 100644 --- a/components/os_crypt/key_storage_libsecret.cc +++ b/components/os_crypt/key_storage_libsecret.cc
@@ -14,12 +14,6 @@ namespace { -#if BUILDFLAG(GOOGLE_CHROME_BRANDING) -const char kApplicationName[] = "chrome"; -#else -const char kApplicationName[] = "chromium"; -#endif - const SecretSchema kKeystoreSchemaV2 = { "chrome_libsecret_os_crypt_password_v2", SECRET_SCHEMA_DONT_MATCH_NAME, @@ -64,6 +58,9 @@ } // namespace +KeyStorageLibsecret::KeyStorageLibsecret(std::string application_name) + : application_name_(std::move(application_name)) {} + absl::optional<std::string> KeyStorageLibsecret::AddRandomPasswordInLibsecret() { std::string password; @@ -71,7 +68,7 @@ GError* error = nullptr; bool success = LibsecretLoader::secret_password_store_sync( &kKeystoreSchemaV2, nullptr, KeyStorageLinux::kKey, password.c_str(), - nullptr, &error, "application", kApplicationName, nullptr); + nullptr, &error, "application", application_name_.c_str(), nullptr); if (error) { VLOG(1) << "Libsecret lookup failed: " << error->message; g_error_free(error); @@ -88,7 +85,7 @@ absl::optional<std::string> KeyStorageLibsecret::GetKeyImpl() { LibsecretAttributesBuilder attrs; - attrs.Append("application", kApplicationName); + attrs.Append("application", application_name_); LibsecretLoader::SearchHelper helper; helper.Search(&kKeystoreSchemaV2, attrs.Get(),
diff --git a/components/os_crypt/key_storage_libsecret.h b/components/os_crypt/key_storage_libsecret.h index 4759d07..5292e21 100644 --- a/components/os_crypt/key_storage_libsecret.h +++ b/components/os_crypt/key_storage_libsecret.h
@@ -15,7 +15,7 @@ // Specialisation of KeyStorageLinux that uses Libsecret. class COMPONENT_EXPORT(OS_CRYPT) KeyStorageLibsecret : public KeyStorageLinux { public: - KeyStorageLibsecret() = default; + explicit KeyStorageLibsecret(std::string application_name); ~KeyStorageLibsecret() override = default; protected: @@ -26,6 +26,8 @@ private: absl::optional<std::string> AddRandomPasswordInLibsecret(); + const std::string application_name_; + DISALLOW_COPY_AND_ASSIGN(KeyStorageLibsecret); };
diff --git a/components/os_crypt/key_storage_libsecret_unittest.cc b/components/os_crypt/key_storage_libsecret_unittest.cc index ebe9a6b..a17bbc1f 100644 --- a/components/os_crypt/key_storage_libsecret_unittest.cc +++ b/components/os_crypt/key_storage_libsecret_unittest.cc
@@ -236,7 +236,7 @@ }; TEST_F(LibsecretTest, LibsecretRepeats) { - KeyStorageLibsecret libsecret; + KeyStorageLibsecret libsecret("chromium"); MockLibsecretLoader::ResetForOSCrypt(); g_password_store.Pointer()->SetPassword("initial password"); absl::optional<std::string> password = libsecret.GetKey(); @@ -248,7 +248,7 @@ } TEST_F(LibsecretTest, LibsecretCreatesRandomised) { - KeyStorageLibsecret libsecret; + KeyStorageLibsecret libsecret("chromium"); MockLibsecretLoader::ResetForOSCrypt(); absl::optional<std::string> password = libsecret.GetKey(); MockLibsecretLoader::ResetForOSCrypt();
diff --git a/components/os_crypt/key_storage_linux.cc b/components/os_crypt/key_storage_linux.cc index 8feb147c..53b1903 100644 --- a/components/os_crypt/key_storage_linux.cc +++ b/components/os_crypt/key_storage_linux.cc
@@ -11,6 +11,7 @@ #include "base/logging.h" #include "base/metrics/histogram_macros.h" #include "base/nix/xdg_util.h" +#include "base/no_destructor.h" #include "base/sequenced_task_runner.h" #include "base/synchronization/waitable_event.h" #include "base/task_runner_util.h" @@ -147,12 +148,29 @@ std::unique_ptr<KeyStorageLinux> KeyStorageLinux::CreateServiceInternal( os_crypt::SelectedLinuxBackend selected_backend, const os_crypt::Config& config) { +#if BUILDFLAG(GOOGLE_CHROME_BRANDING) + static const base::NoDestructor<std::string> kDefaultApplicationName("chrome"); +#else + static const base::NoDestructor<std::string> kDefaultApplicationName("chromium"); +#endif + std::unique_ptr<KeyStorageLinux> key_storage; +#if defined(USE_LIBSECRET) || defined(USE_KEYRING) +#if defined(ALLOW_RUNTIME_CONFIGURABLE_KEY_STORAGE) + std::string application_name = config.application_name; + if (application_name.empty()) { + application_name = *kDefaultApplicationName; + } +#else + std::string application_name = *kDefaultApplicationName; +#endif +#endif + #if defined(USE_LIBSECRET) if (selected_backend == os_crypt::SelectedLinuxBackend::GNOME_ANY || selected_backend == os_crypt::SelectedLinuxBackend::GNOME_LIBSECRET) { - key_storage = std::make_unique<KeyStorageLibsecret>(); + key_storage = std::make_unique<KeyStorageLibsecret>(std::move(application_name)); if (key_storage->WaitForInitOnTaskRunner()) { VLOG(1) << "OSCrypt using Libsecret as backend."; return key_storage; @@ -164,8 +182,8 @@ #if defined(USE_KEYRING) if (selected_backend == os_crypt::SelectedLinuxBackend::GNOME_ANY || selected_backend == os_crypt::SelectedLinuxBackend::GNOME_KEYRING) { - key_storage = - std::make_unique<KeyStorageKeyring>(config.main_thread_runner); + key_storage = std::make_unique<KeyStorageKeyring>(config.main_thread_runner, + std::move(application_name)); if (key_storage->WaitForInitOnTaskRunner()) { VLOG(1) << "OSCrypt using Keyring as backend."; return key_storage;
diff --git a/components/page_load_metrics/browser/layout_shift_normalization.cc b/components/page_load_metrics/browser/layout_shift_normalization.cc index 3ec674bc..d6df8846 100644 --- a/components/page_load_metrics/browser/layout_shift_normalization.cc +++ b/components/page_load_metrics/browser/layout_shift_normalization.cc
@@ -25,7 +25,7 @@ void LayoutShiftNormalization::AddNewLayoutShifts( const std::vector<page_load_metrics::mojom::LayoutShiftPtr>& new_shifts, base::TimeTicks current_time, - double cumulative_layout_shift_score) { + float cumulative_layout_shift_score) { if (new_shifts.empty() || normalized_cls_data_.data_tainted) return; @@ -115,7 +115,7 @@ std::vector<std::pair<base::TimeTicks, double>>::const_iterator begin, std::vector<std::pair<base::TimeTicks, double>>::const_iterator end, std::vector<base::TimeTicks>& input_timestamps, - double& max_score, + float& max_score, uint32_t& count) { for (auto it = begin; it != end; ++it) { if ((it->first - session_window->last_time > gap) || @@ -156,8 +156,8 @@ std::vector<std::pair<base::TimeTicks, double>>::const_iterator first_non_stale, std::vector<std::pair<base::TimeTicks, double>>::const_iterator last, - double cumulative_layout_shift_score) { - double dummy_max = 0.0; + float cumulative_layout_shift_score) { + float dummy_max = 0.0; uint32_t dummy_count = 0; std::vector<base::TimeTicks> dummy_input_timestamps; // Update Sliding Windows.
diff --git a/components/page_load_metrics/browser/layout_shift_normalization.h b/components/page_load_metrics/browser/layout_shift_normalization.h index f202d3ed..4f70683 100644 --- a/components/page_load_metrics/browser/layout_shift_normalization.h +++ b/components/page_load_metrics/browser/layout_shift_normalization.h
@@ -26,7 +26,7 @@ void AddNewLayoutShifts( const std::vector<page_load_metrics::mojom::LayoutShiftPtr>& new_shifts, base::TimeTicks current_time, - /*Whole page CLS*/ double cumulative_layout_shift_score); + /*Whole page CLS*/ float cumulative_layout_shift_score); void ClearAllLayoutShifts(); @@ -39,7 +39,7 @@ struct SessionWindow { base::TimeTicks start_time; base::TimeTicks last_time; - double layout_shift_score = 0.0; + float layout_shift_score = 0.0; }; void UpdateWindowCLS( @@ -48,7 +48,7 @@ std::vector<std::pair<base::TimeTicks, double>>::const_iterator first_non_stale, std::vector<std::pair<base::TimeTicks, double>>::const_iterator last, - double cumulative_layout_shift_score); + float cumulative_layout_shift_score); void UpdateSlidingWindow( std::vector<SlidingWindow>* sliding_windows, @@ -65,7 +65,7 @@ std::vector<std::pair<base::TimeTicks, double>>::const_iterator begin, std::vector<std::pair<base::TimeTicks, double>>::const_iterator end, std::vector<base::TimeTicks>& input_timestamps, - double& max_score, + float& max_score, uint32_t& count); // CLS normalization @@ -87,7 +87,7 @@ // A new input in non-stale data can split the session window and make the // max_cls smaller. We need to store the "max_cls" calculated by the stale // data. - double potential_max_cls_session_by_inputs_gap1000ms_max5000ms_ = 0.0; + float potential_max_cls_session_by_inputs_gap1000ms_max5000ms_ = 0.0; uint32_t session_gap5000ms_count_ = 0; DISALLOW_COPY_AND_ASSIGN(LayoutShiftNormalization);
diff --git a/components/page_load_metrics/browser/layout_shift_normalization_unittest.cc b/components/page_load_metrics/browser/layout_shift_normalization_unittest.cc index 857f9cd3..53617ff 100644 --- a/components/page_load_metrics/browser/layout_shift_normalization_unittest.cc +++ b/components/page_load_metrics/browser/layout_shift_normalization_unittest.cc
@@ -44,7 +44,7 @@ private: page_load_metrics::LayoutShiftNormalization layout_shift_normalization_; - double cumulative_layoutshift_score_ = 0.0; + float cumulative_layoutshift_score_ = 0.0; }; TEST_F(LayoutShiftNormalizationTest, MultipleShifts) {
diff --git a/components/page_load_metrics/browser/page_load_metrics_observer.h b/components/page_load_metrics/browser/page_load_metrics_observer.h index c67e356e..1be339f 100644 --- a/components/page_load_metrics/browser/page_load_metrics_observer.h +++ b/components/page_load_metrics/browser/page_load_metrics_observer.h
@@ -144,20 +144,20 @@ // Maximum CLS of session windows. The gap between two consecutive shifts is // not bigger than 1000ms and the maximum window size is 5000ms. - double session_windows_gap1000ms_max5000ms_max_cls = 0.0; + float session_windows_gap1000ms_max5000ms_max_cls = 0.0; // Maximum CLS of session windows. The gap between two consecutive shifts is // not bigger than 1000ms. - double session_windows_gap1000ms_maxMax_max_cls = 0.0; + float session_windows_gap1000ms_maxMax_max_cls = 0.0; // The average CLS of session windows. The gap between two consecutive shifts // is not bigger than 5000ms. - double session_windows_gap5000ms_maxMax_average_cls = 0.0; + float session_windows_gap5000ms_maxMax_average_cls = 0.0; // Maximum CLS of session windows. The gap between two consecutive shifts is // not bigger than 1000ms or segmented by a user input. The maximum window // size is 5000ms. - double session_windows_by_inputs_gap1000ms_max5000ms_max_cls = 0.0; + float session_windows_by_inputs_gap1000ms_max5000ms_max_cls = 0.0; // If true, will not report the data in UKM. bool data_tainted = false;
diff --git a/components/paint_preview/browser/DEPS b/components/paint_preview/browser/DEPS index 7fb995ef..fea23bd7 100644 --- a/components/paint_preview/browser/DEPS +++ b/components/paint_preview/browser/DEPS
@@ -7,7 +7,6 @@ "+components/ukm/content", "+components/ukm/test_ukm_recorder.h", "+content/public/browser", - "+content/public/common", "+content/public/test", "+services/metrics/public/cpp", "+sandbox/policy/sandbox_type.h",
diff --git a/components/paint_preview/browser/compositor_utils.cc b/components/paint_preview/browser/compositor_utils.cc index 78e95b6..f8ce150a 100644 --- a/components/paint_preview/browser/compositor_utils.cc +++ b/components/paint_preview/browser/compositor_utils.cc
@@ -17,19 +17,16 @@ #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/service_process_host.h" -#include "content/public/common/content_features.h" #include "mojo/public/cpp/bindings/remote.h" namespace paint_preview { namespace { -void BindDiscardableSharedMemoryManagerOnProcessThread( +void BindDiscardableSharedMemoryManagerOnIOThread( mojo::PendingReceiver< discardable_memory::mojom::DiscardableSharedMemoryManager> receiver) { - DCHECK_CURRENTLY_ON(base::FeatureList::IsEnabled(features::kProcessHostOnUI) - ? content::BrowserThread::UI - : content::BrowserThread::IO); + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); discardable_memory::DiscardableSharedMemoryManager::Get()->Bind( std::move(receiver)); } @@ -87,13 +84,10 @@ discardable_memory_manager; // Set up the discardable memory manager. - auto task_runner = base::FeatureList::IsEnabled(features::kProcessHostOnUI) - ? content::GetUIThreadTaskRunner({}) - : content::GetIOThreadTaskRunner({}); - task_runner->PostTask( + content::GetIOThreadTaskRunner({})->PostTask( FROM_HERE, base::BindOnce( - &BindDiscardableSharedMemoryManagerOnProcessThread, + &BindDiscardableSharedMemoryManagerOnIOThread, discardable_memory_manager.InitWithNewPipeAndPassReceiver())); collection->get()->SetDiscardableSharedMemoryManager( std::move(discardable_memory_manager));
diff --git a/components/payments/content/android_app_communication.h b/components/payments/content/android_app_communication.h index a2a1dda..af99e9b 100644 --- a/components/payments/content/android_app_communication.h +++ b/components/payments/content/android_app_communication.h
@@ -14,6 +14,7 @@ #include "base/callback_forward.h" #include "base/memory/weak_ptr.h" #include "base/supports_user_data.h" +#include "base/unguessable_token.h" #include "components/payments/core/android_app_description.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -44,6 +45,8 @@ const std::string& payment_method_identifier, const std::string& stringified_details)>; + using AbortPaymentAppCallback = base::OnceCallback<void(bool)>; + // Returns a weak pointer to the instance of AndroidAppCommunication that is // owned by the given |context|, which should not be null. static base::WeakPtr<AndroidAppCommunication> GetForBrowserContext( @@ -82,9 +85,14 @@ const GURL& top_level_origin, const GURL& payment_request_origin, const std::string& payment_request_id, + const base::UnguessableToken& request_token, content::WebContents* web_contents, InvokePaymentAppCallback callback) = 0; + // Aborts a payment flow which was previously started with InvokePaymentApp(). + virtual void AbortPaymentApp(const base::UnguessableToken& request_token, + AbortPaymentAppCallback callback) = 0; + // Allows usage of a test browser context. virtual void SetForTesting() = 0;
diff --git a/components/payments/content/android_app_communication_chrome_os.cc b/components/payments/content/android_app_communication_chrome_os.cc index 5a060729..34e1aa19 100644 --- a/components/payments/content/android_app_communication_chrome_os.cc +++ b/components/payments/content/android_app_communication_chrome_os.cc
@@ -279,6 +279,7 @@ const GURL& top_level_origin, const GURL& payment_request_origin, const std::string& payment_request_id, + const base::UnguessableToken& request_token, content::WebContents* web_contents, InvokePaymentAppCallback callback) override { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); @@ -286,8 +287,8 @@ // Create and register a token with ArcOverlayManager for the // browser window. Doing so is required to allow the Android Play Billing // interface to be overlaid on top of the browser window. - // TODO(b/172592701): Use base::UnguessableToken::Create().ToString() and - // send the same value to the Android service. + // TODO(crbug.com/1209716): Reuse the request_token for coordinating the + // overlay. std::string billing_token = payment_request_origin.spec() + "#" + payment_request_id; ash::ArcOverlayManager* const overlay_manager = @@ -323,6 +324,7 @@ /*stringified_details=*/kEmptyDictionaryJson); return; } + parameters->request_token = request_token.ToString(); payment_app_service->InvokePaymentApp( std::move(parameters), @@ -330,6 +332,17 @@ std::move(overlay_state))); } + void AbortPaymentApp(const base::UnguessableToken& token, + AbortPaymentAppCallback callback) override { + auto* payment_app_service = get_app_service_.Run(context()); + if (!payment_app_service) { + std::move(callback).Run(false); + return; + } + + payment_app_service->AbortPaymentApp(token.ToString(), std::move(callback)); + } + // AndroidAppCommunication implementation. void SetForTesting() override { DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
diff --git a/components/payments/content/android_app_communication_stub.cc b/components/payments/content/android_app_communication_stub.cc index 15120c2..cb695366 100644 --- a/components/payments/content/android_app_communication_stub.cc +++ b/components/payments/content/android_app_communication_stub.cc
@@ -48,6 +48,7 @@ const GURL& top_level_origin, const GURL& payment_request_origin, const std::string& payment_request_id, + const base::UnguessableToken& request_token, content::WebContents* web_contents, InvokePaymentAppCallback callback) override { std::move(callback).Run(errors::kUnableToInvokeAndroidPaymentApps, @@ -56,6 +57,11 @@ /*stringified_details=*/"{}"); } + void AbortPaymentApp(const base::UnguessableToken& request_token, + AbortPaymentAppCallback callback) override { + std::move(callback).Run(false); + } + // AndroidAppCommunication implementation. void SetForTesting() override {}
diff --git a/components/payments/content/android_app_communication_test_support.h b/components/payments/content/android_app_communication_test_support.h index 22617d8..1b9794f6 100644 --- a/components/payments/content/android_app_communication_test_support.h +++ b/components/payments/content/android_app_communication_test_support.h
@@ -90,6 +90,16 @@ const std::string& payment_method_identifier, const std::string& stringified_details) = 0; + // Sets up the expectation that the test case will invoke a PAY activity, and + // then subsequently abort that payment. The invoke callback will be called + // when the payment is aborted with an error result, and then the abort will + // be reported as successful. + virtual void ExpectInvokeAndAbortPaymentApp() = 0; + + // Sets up the expectation that the test case will not abort any payment + // flows. + virtual void ExpectNoAbortPaymentApp() = 0; + // Returns the browser context to use. virtual content::BrowserContext* context() = 0;
diff --git a/components/payments/content/android_app_communication_test_support_chrome_os.cc b/components/payments/content/android_app_communication_test_support_chrome_os.cc index 4377752..341a7f3 100644 --- a/components/payments/content/android_app_communication_test_support_chrome_os.cc +++ b/components/payments/content/android_app_communication_test_support_chrome_os.cc
@@ -116,6 +116,33 @@ })); } + void ExpectInvokeAndAbortPaymentApp() override { + EXPECT_CALL(*support_.instance(), InvokePaymentApp(testing::_, testing::_)) + .WillOnce(testing::Invoke( + [this]( + arc::mojom::PaymentParametersPtr parameters, + arc::ArcPaymentAppBridge::InvokePaymentAppCallback callback) { + pending_invoke_callback_ = std::move(callback); + })); + + EXPECT_CALL(*support_.instance(), AbortPaymentApp(testing::_, testing::_)) + .WillOnce(testing::Invoke( + [this](const std::string& request_token, + arc::ArcPaymentAppBridge::AbortPaymentAppCallback callback) { + if (!pending_invoke_callback_.is_null()) { + std::move(pending_invoke_callback_) + .Run(arc::mojom::InvokePaymentAppResult::NewError( + "Payment was aborted.")); + } + std::move(callback).Run(true); + })); + } + + void ExpectNoAbortPaymentApp() override { + EXPECT_CALL(*support_.instance(), AbortPaymentApp(testing::_, testing::_)) + .Times(0); + } + content::BrowserContext* context() override { return support_.context(); } private: @@ -147,6 +174,8 @@ arc::ArcPaymentAppBridgeTestSupport support_; std::vector<std::unique_ptr<AndroidAppDescription>> apps_; ash::TestArcOverlayManager overlay_manager_; + + arc::ArcPaymentAppBridge::InvokePaymentAppCallback pending_invoke_callback_; }; } // namespace
diff --git a/components/payments/content/android_app_communication_test_support_stub.cc b/components/payments/content/android_app_communication_test_support_stub.cc index 93df4287..bf7d33f 100644 --- a/components/payments/content/android_app_communication_test_support_stub.cc +++ b/components/payments/content/android_app_communication_test_support_stub.cc
@@ -45,6 +45,10 @@ const std::string& payment_method_identifier, const std::string& stringified_details) override {} + void ExpectInvokeAndAbortPaymentApp() override {} + + void ExpectNoAbortPaymentApp() override {} + content::BrowserContext* context() override { return &context_; } private:
diff --git a/components/payments/content/android_app_communication_unittest.cc b/components/payments/content/android_app_communication_unittest.cc index 8f1109a..c7075998 100644 --- a/components/payments/content/android_app_communication_unittest.cc +++ b/components/payments/content/android_app_communication_unittest.cc
@@ -11,6 +11,7 @@ #include "base/bind.h" #include "base/callback.h" +#include "base/unguessable_token.h" #include "components/payments/content/android_app_communication_test_support.h" #include "components/payments/core/android_app_description.h" #include "content/public/browser/web_contents.h" @@ -472,7 +473,7 @@ "com.example.app", "com.example.app.Activity", stringified_method_data, GURL("https://top-level-origin.com"), GURL("https://payment-request-origin.com"), "payment-request-id", - web_contents_, + base::UnguessableToken::Create(), web_contents_, base::BindOnce(&AndroidAppCommunicationTest::OnPaymentAppResponse, base::Unretained(this))); @@ -497,7 +498,7 @@ "com.example.app", "com.example.app.Activity", stringified_method_data, GURL("https://top-level-origin.com"), GURL("https://payment-request-origin.com"), "payment-request-id", - web_contents_, + base::UnguessableToken::Create(), web_contents_, base::BindOnce(&AndroidAppCommunicationTest::OnPaymentAppResponse, base::Unretained(this))); @@ -530,7 +531,7 @@ "com.example.app", "com.example.app.Activity", stringified_method_data, GURL("https://top-level-origin.com"), GURL("https://payment-request-origin.com"), "payment-request-id", - web_contents_, + base::UnguessableToken::Create(), web_contents_, base::BindOnce(&AndroidAppCommunicationTest::OnPaymentAppResponse, base::Unretained(this))); @@ -566,7 +567,7 @@ "com.example.app", "com.example.app.Activity", stringified_method_data, GURL("https://top-level-origin.com"), GURL("https://payment-request-origin.com"), "payment-request-id", - web_contents_, + base::UnguessableToken::Create(), web_contents_, base::BindOnce(&AndroidAppCommunicationTest::OnPaymentAppResponse, base::Unretained(this))); @@ -599,7 +600,7 @@ "com.example.app", "com.example.app.Activity", stringified_method_data, GURL("https://top-level-origin.com"), GURL("https://payment-request-origin.com"), "payment-request-id", - web_contents_, + base::UnguessableToken::Create(), web_contents_, base::BindOnce(&AndroidAppCommunicationTest::OnPaymentAppResponse, base::Unretained(this))); @@ -632,7 +633,7 @@ "com.example.app", "com.example.app.Activity", stringified_method_data, GURL("https://top-level-origin.com"), GURL("https://payment-request-origin.com"), "payment-request-id", - web_contents_, + base::UnguessableToken::Create(), web_contents_, base::BindOnce(&AndroidAppCommunicationTest::OnPaymentAppResponse, base::Unretained(this)));
diff --git a/components/payments/content/android_payment_app.cc b/components/payments/content/android_payment_app.cc index 6556205..60456849 100644 --- a/components/payments/content/android_payment_app.cc +++ b/components/payments/content/android_payment_app.cc
@@ -32,7 +32,9 @@ payment_request_id_(payment_request_id), description_(std::move(description)), communication_(communication), - frame_routing_id_(frame_routing_id) { + frame_routing_id_(frame_routing_id), + payment_app_token_(base::UnguessableToken::Create()), + payment_app_open_(false) { DCHECK(!payment_method_names.empty()); DCHECK_EQ(payment_method_names.size(), stringified_method_data_->size()); DCHECK_EQ(*payment_method_names.begin(), @@ -45,7 +47,11 @@ app_method_names_ = payment_method_names; } -AndroidPaymentApp::~AndroidPaymentApp() = default; +AndroidPaymentApp::~AndroidPaymentApp() { + if (payment_app_open_) { + AbortPaymentApp(base::DoNothing()); + } +} void AndroidPaymentApp::InvokePaymentApp(base::WeakPtr<Delegate> delegate) { // Browser is closing, so no need to invoke a callback. @@ -61,10 +67,11 @@ if (!web_contents) return; + payment_app_open_ = true; communication_->InvokePaymentApp( description_->package, description_->activities.front()->name, *stringified_method_data_, top_level_origin_, payment_request_origin_, - payment_request_id_, web_contents, + payment_request_id_, payment_app_token_, web_contents, base::BindOnce(&AndroidPaymentApp::OnPaymentAppResponse, weak_ptr_factory_.GetWeakPtr(), delegate)); } @@ -155,6 +162,19 @@ void AndroidPaymentApp::OnPaymentDetailsNotUpdated() {} +void AndroidPaymentApp::AbortPaymentApp( + base::OnceCallback<void(bool)> abort_callback) { + // Browser is closing or no payment app active, so no need to invoke a + // callback. + if (!communication_ || !payment_app_open_) + return; + + payment_app_open_ = false; + + communication_->AbortPaymentApp(payment_app_token_, + std::move(abort_callback)); +} + bool AndroidPaymentApp::IsPreferred() const { // This class used only on Chrome OS, where the only Android payment app // available is the trusted web application (TWA) that launched this instance @@ -174,6 +194,7 @@ bool is_activity_result_ok, const std::string& payment_method_identifier, const std::string& stringified_details) { + payment_app_open_ = false; if (!delegate) return;
diff --git a/components/payments/content/android_payment_app.h b/components/payments/content/android_payment_app.h index 861e9b6..21f31116 100644 --- a/components/payments/content/android_payment_app.h +++ b/components/payments/content/android_payment_app.h
@@ -10,6 +10,7 @@ #include <string> #include "base/memory/weak_ptr.h" +#include "base/unguessable_token.h" #include "components/payments/content/android_app_communication.h" #include "components/payments/content/payment_app.h" #include "components/payments/core/android_app_description.h" @@ -74,6 +75,7 @@ void UpdateWith( mojom::PaymentRequestDetailsUpdatePtr details_update) override; void OnPaymentDetailsNotUpdated() override; + void AbortPaymentApp(base::OnceCallback<void(bool)> abort_callback) override; bool IsPreferred() const override; private: @@ -92,6 +94,13 @@ base::WeakPtr<AndroidAppCommunication> communication_; content::GlobalFrameRoutingId frame_routing_id_; + // Token used to uniquely identify a particular payment app instance between + // Android and Chrome. + base::UnguessableToken payment_app_token_; + // True when InvokePaymentApp() has been called but no response has been + // received yet. + bool payment_app_open_; + base::WeakPtrFactory<AndroidPaymentApp> weak_ptr_factory_{this}; };
diff --git a/components/payments/content/android_payment_app_unittest.cc b/components/payments/content/android_payment_app_unittest.cc index 55afa9b..21978b8 100644 --- a/components/payments/content/android_payment_app_unittest.cc +++ b/components/payments/content/android_payment_app_unittest.cc
@@ -13,6 +13,7 @@ #include "base/bind.h" #include "base/callback.h" +#include "base/test/bind.h" #include "components/payments/content/android_app_communication.h" #include "components/payments/content/android_app_communication_test_support.h" #include "components/payments/core/android_app_description.h" @@ -171,5 +172,58 @@ } } +TEST_F(AndroidPaymentAppTest, AbortWithPaymentAppOpen) { + communication_ = + AndroidAppCommunication::GetForBrowserContext(support_->context()); + communication_->SetForTesting(); + scoped_initialization_ = support_->CreateScopedInitialization(); + + support_->ExpectInvokeAndAbortPaymentApp(); + + auto app = CreateAndroidPaymentApp(communication_, web_contents_); + app->InvokePaymentApp(/*delegate=*/weak_ptr_factory_.GetWeakPtr()); + + bool aborted = false; + app->AbortPaymentApp(base::BindLambdaForTesting( + [&aborted](bool abort_success) { aborted = abort_success; })); + + if (support_->AreAndroidAppsSupportedOnThisPlatform()) { + EXPECT_EQ("Payment was aborted.", error_message_); + EXPECT_TRUE(aborted); + } else { + EXPECT_EQ("Unable to invoke Android apps.", error_message_); + } +} + +TEST_F(AndroidPaymentAppTest, AbortWhenAppDestroyed) { + communication_ = + AndroidAppCommunication::GetForBrowserContext(support_->context()); + communication_->SetForTesting(); + scoped_initialization_ = support_->CreateScopedInitialization(); + + support_->ExpectInvokeAndAbortPaymentApp(); + + auto app = CreateAndroidPaymentApp(communication_, web_contents_); + app->InvokePaymentApp(/*delegate=*/weak_ptr_factory_.GetWeakPtr()); + // Payment app will be aborted when |app| is destroyed. +} + +TEST_F(AndroidPaymentAppTest, NoAbortWhenDestroyedWithCompletedFlow) { + communication_ = + AndroidAppCommunication::GetForBrowserContext(support_->context()); + communication_->SetForTesting(); + scoped_initialization_ = support_->CreateScopedInitialization(); + + support_->ExpectInvokePaymentAppAndRespond( + /*is_activity_result_ok=*/false, + /*payment_method_identifier=*/methods::kGooglePlayBilling, + /*stringified_details=*/"{}"); + support_->ExpectNoAbortPaymentApp(); + + auto app = CreateAndroidPaymentApp(communication_, web_contents_); + app->InvokePaymentApp(/*delegate=*/weak_ptr_factory_.GetWeakPtr()); + // Payment app will not be aborted when |app| is destroyed. +} + } // namespace } // namespace payments
diff --git a/components/printing/browser/print_composite_client.cc b/components/printing/browser/print_composite_client.cc index 8acc4a8..df55bb2b 100644 --- a/components/printing/browser/print_composite_client.cc +++ b/components/printing/browser/print_composite_client.cc
@@ -19,7 +19,6 @@ #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/service_process_host.h" -#include "content/public/common/content_features.h" #include "printing/common/metafile_utils.h" #include "printing/printing_utils.h" #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h" @@ -63,12 +62,10 @@ return content_frame_map; } -void BindDiscardableSharedMemoryManagerOnProcessThread( +void BindDiscardableSharedMemoryManagerOnIOThread( mojo::PendingReceiver< discardable_memory::mojom::DiscardableSharedMemoryManager> receiver) { - DCHECK_CURRENTLY_ON(base::FeatureList::IsEnabled(features::kProcessHostOnUI) - ? content::BrowserThread::UI - : content::BrowserThread::IO); + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); discardable_memory::DiscardableSharedMemoryManager::Get()->Bind( std::move(receiver)); } @@ -373,13 +370,10 @@ mojo::PendingRemote<discardable_memory::mojom::DiscardableSharedMemoryManager> discardable_memory_manager; - auto task_runner = base::FeatureList::IsEnabled(features::kProcessHostOnUI) - ? content::GetUIThreadTaskRunner({}) - : content::GetIOThreadTaskRunner({}); - task_runner->PostTask( + content::GetIOThreadTaskRunner({})->PostTask( FROM_HERE, base::BindOnce( - &BindDiscardableSharedMemoryManagerOnProcessThread, + &BindDiscardableSharedMemoryManagerOnIOThread, discardable_memory_manager.InitWithNewPipeAndPassReceiver())); compositor_->SetDiscardableSharedMemoryManager( std::move(discardable_memory_manager));
diff --git a/components/printing/browser/print_manager.cc b/components/printing/browser/print_manager.cc index 3e95b473..44ddf64 100644 --- a/components/printing/browser/print_manager.cc +++ b/components/printing/browser/print_manager.cc
@@ -24,9 +24,8 @@ void PrintManager::DidGetPrintedPagesCount(int32_t cookie, uint32_t number_pages) { - if (!IsValidCookie(cookie) || number_pages == 0) - return; - + DCHECK_GT(cookie, 0); + DCHECK_GT(number_pages, 0u); number_pages_ = number_pages; }
diff --git a/components/resources/BUILD.gn b/components/resources/BUILD.gn index fb82ba643..9b87aa1 100644 --- a/components/resources/BUILD.gn +++ b/components/resources/BUILD.gn
@@ -3,7 +3,6 @@ # found in the LICENSE file. import("//build/config/android/config.gni") -import("//build/config/python.gni") import("//components/safe_browsing/buildflags.gni") import("//printing/buildflags/buildflags.gni") import("//tools/grit/grit_rule.gni") @@ -84,8 +83,7 @@ output_dir = "$root_gen_dir/components" } -# TODO(crbug.com/1112471): Get this to run cleanly under Python 3. -python2_action("about_credits") { +action("about_credits") { script = "//tools/licenses.py" depfile = "$target_gen_dir/$target_name.d"
diff --git a/components/safe_browsing/DEPS b/components/safe_browsing/DEPS index 09bc03f..09fb3f1 100644 --- a/components/safe_browsing/DEPS +++ b/components/safe_browsing/DEPS
@@ -31,6 +31,8 @@ "+testing/gtest", "+third_party/blink/public/common/loader/url_loader_throttle.h", "+third_party/blink/public/mojom/loader/resource_load_info.mojom-shared.h", + "+third_party/tflite-support", + "+third_party/tflite", "+third_party/protobuf", "+ui/base/resource/resource_bundle.h", "+ui/android/view_android.h",
diff --git a/components/safe_browsing/content/browser/BUILD.gn b/components/safe_browsing/content/browser/BUILD.gn index 1eb4af6..070aa6f 100644 --- a/components/safe_browsing/content/browser/BUILD.gn +++ b/components/safe_browsing/content/browser/BUILD.gn
@@ -16,6 +16,8 @@ "threat_details_cache.h", "threat_details_history.cc", "threat_details_history.h", + "web_api_handshake_checker.cc", + "web_api_handshake_checker.h", ] deps = [ "//components/back_forward_cache", @@ -69,6 +71,7 @@ sources = [ "client_side_model_loader_unittest.cc", "client_side_phishing_model_unittest.cc", + "web_api_handshake_checker_unittest.cc", ] deps = [ @@ -77,9 +80,13 @@ "//base:base", "//base/test:test_support", "//components/safe_browsing:buildflags", + "//components/safe_browsing/content/browser:browser", "//components/safe_browsing/core:client_model_proto", "//components/safe_browsing/core:csd_proto", "//components/safe_browsing/core:features", + "//components/safe_browsing/core/browser:browser", + "//components/safe_browsing/core/db:test_database_manager", + "//components/security_interstitials/core:unsafe_resource", "//components/variations", "//content/test:test_support", "//services/network:test_support",
diff --git a/components/safe_browsing/content/browser/web_api_handshake_checker.cc b/components/safe_browsing/content/browser/web_api_handshake_checker.cc new file mode 100644 index 0000000..c27d442 --- /dev/null +++ b/components/safe_browsing/content/browser/web_api_handshake_checker.cc
@@ -0,0 +1,133 @@ +// Copyright 2021 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/safe_browsing/content/browser/web_api_handshake_checker.h" + +#include "components/safe_browsing/core/browser/safe_browsing_url_checker_impl.h" +#include "components/safe_browsing/core/browser/url_checker_delegate.h" +#include "content/public/browser/browser_task_traits.h" +#include "content/public/browser/browser_thread.h" +#include "net/http/http_request_headers.h" + +namespace safe_browsing { + +class WebApiHandshakeChecker::CheckerOnIO + : public base::SupportsWeakPtr<WebApiHandshakeChecker::CheckerOnIO> { + public: + CheckerOnIO(base::WeakPtr<WebApiHandshakeChecker> handshake_checker, + GetDelegateCallback delegate_getter, + const GetWebContentsCallback& web_contents_getter, + int frame_tree_node_id) + : handshake_checker_(std::move(handshake_checker)), + delegate_getter_(std::move(delegate_getter)), + web_contents_getter_(web_contents_getter), + frame_tree_node_id_(frame_tree_node_id) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + DCHECK(handshake_checker_); + DCHECK(delegate_getter_); + DCHECK(web_contents_getter_); + } + + void Check(const GURL& url) { + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + DCHECK(delegate_getter_); + DCHECK(web_contents_getter_); + + scoped_refptr<UrlCheckerDelegate> url_checker_delegate = + std::move(delegate_getter_).Run(); + bool skip_checks = + !url_checker_delegate || + !url_checker_delegate->GetDatabaseManager()->IsSupported() || + url_checker_delegate->ShouldSkipRequestCheck( + url, frame_tree_node_id_, /*render_process_id=*/-1, + /*render_frame_id=*/-1, /*originated_from_service_worker=*/false); + if (skip_checks) { + OnCompleteCheck(/*slow_check=*/false, /*proceed=*/true, + /*showed_interstitial=*/false); + return; + } + + url_checker_ = std::make_unique<SafeBrowsingUrlCheckerImpl>( + net::HttpRequestHeaders(), /*load_flags=*/0, + network::mojom::RequestDestination::kEmpty, /*has_user_gesture=*/false, + url_checker_delegate, web_contents_getter_, + /*real_time_lookup_enabled=*/false, + /*can_rt_check_subresource_url=*/false, + /*can_check_db=*/true, /*url_lookup_service=*/nullptr); + url_checker_->CheckUrl( + url, "GET", + base::BindOnce(&WebApiHandshakeChecker::CheckerOnIO::OnCheckUrlResult, + base::Unretained(this))); + } + + private: + // See comments in BrowserUrlLoaderThrottle::OnCheckUrlResult(). + void OnCheckUrlResult( + SafeBrowsingUrlCheckerImpl::NativeUrlCheckNotifier* slow_check_notifier, + bool proceed, + bool showed_interstitial) { + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + if (!slow_check_notifier) { + OnCompleteCheck(/*slow_check=*/false, proceed, showed_interstitial); + return; + } + + *slow_check_notifier = + base::BindOnce(&WebApiHandshakeChecker::CheckerOnIO::OnCompleteCheck, + base::Unretained(this), /*slow_check=*/true); + } + + void OnCompleteCheck(bool slow_check, + bool proceed, + bool showed_interstitial) { + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + content::GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(&WebApiHandshakeChecker::OnCompleteCheck, + handshake_checker_, slow_check, proceed, + showed_interstitial)); + } + + base::WeakPtr<WebApiHandshakeChecker> handshake_checker_; + GetDelegateCallback delegate_getter_; + GetWebContentsCallback web_contents_getter_; + const int frame_tree_node_id_; + std::unique_ptr<SafeBrowsingUrlCheckerImpl> url_checker_; +}; + +WebApiHandshakeChecker::WebApiHandshakeChecker( + GetDelegateCallback delegate_getter, + const GetWebContentsCallback& web_contents_getter, + int frame_tree_node_id) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + io_checker_ = std::make_unique<CheckerOnIO>( + weak_factory_.GetWeakPtr(), std::move(delegate_getter), + web_contents_getter, frame_tree_node_id); +} + +WebApiHandshakeChecker::~WebApiHandshakeChecker() { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + content::GetIOThreadTaskRunner({})->DeleteSoon(FROM_HERE, + std::move(io_checker_)); +} + +void WebApiHandshakeChecker::Check(const GURL& url, CheckCallback callback) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + DCHECK(!check_callback_); + check_callback_ = std::move(callback); + content::GetIOThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(&WebApiHandshakeChecker::CheckerOnIO::Check, + io_checker_->AsWeakPtr(), url)); +} + +void WebApiHandshakeChecker::OnCompleteCheck(bool slow_check, + bool proceed, + bool showed_interstitial) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + DCHECK(check_callback_); + + CheckResult result = proceed ? CheckResult::kProceed : CheckResult::kBlocked; + std::move(check_callback_).Run(result); +} + +} // namespace safe_browsing
diff --git a/components/safe_browsing/content/browser/web_api_handshake_checker.h b/components/safe_browsing/content/browser/web_api_handshake_checker.h new file mode 100644 index 0000000..381aa13 --- /dev/null +++ b/components/safe_browsing/content/browser/web_api_handshake_checker.h
@@ -0,0 +1,64 @@ +// Copyright 2021 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_SAFE_BROWSING_CONTENT_BROWSER_WEB_API_HANDSHAKE_CHECKER_H_ +#define COMPONENTS_SAFE_BROWSING_CONTENT_BROWSER_WEB_API_HANDSHAKE_CHECKER_H_ + +#include <memory> + +#include "base/callback.h" +#include "base/memory/scoped_refptr.h" +#include "base/memory/weak_ptr.h" +#include "url/gurl.h" + +namespace content { +class WebContents; +} // namespace content + +namespace safe_browsing { + +class UrlCheckerDelegate; + +// Performs SafeBrowsing checks for Web API handshakes such as WebTransport. +class WebApiHandshakeChecker { + public: + using GetDelegateCallback = + base::OnceCallback<scoped_refptr<UrlCheckerDelegate>()>; + using GetWebContentsCallback = + base::RepeatingCallback<content::WebContents*()>; + + enum class CheckResult { + kProceed, + kBlocked, + }; + using CheckCallback = base::OnceCallback<void(CheckResult)>; + + WebApiHandshakeChecker(GetDelegateCallback delegate_getter, + const GetWebContentsCallback& web_contents_getter, + int frame_tree_node_id); + ~WebApiHandshakeChecker(); + + WebApiHandshakeChecker(const WebApiHandshakeChecker&) = delete; + WebApiHandshakeChecker& operator=(const WebApiHandshakeChecker&) = delete; + WebApiHandshakeChecker(WebApiHandshakeChecker&&) = delete; + WebApiHandshakeChecker& operator=(WebApiHandshakeChecker&&) = delete; + + void Check(const GURL& url, CheckCallback callback); + + private: + // Performs checks on the IO thread by using SafeBrowsingUrlCheckerImpl, which + // must live on the IO thread. + class CheckerOnIO; + + void OnCompleteCheck(bool slow_check, bool proceed, bool showed_interstitial); + + std::unique_ptr<CheckerOnIO> io_checker_; + CheckCallback check_callback_; + + base::WeakPtrFactory<WebApiHandshakeChecker> weak_factory_{this}; +}; + +} // namespace safe_browsing + +#endif // COMPONENTS_SAFE_BROWSING_CONTENT_BROWSER_WEB_API_HANDSHAKE_CHECKER_H_
diff --git a/components/safe_browsing/content/browser/web_api_handshake_checker_unittest.cc b/components/safe_browsing/content/browser/web_api_handshake_checker_unittest.cc new file mode 100644 index 0000000..e261cc2a --- /dev/null +++ b/components/safe_browsing/content/browser/web_api_handshake_checker_unittest.cc
@@ -0,0 +1,129 @@ +// Copyright 2021 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/safe_browsing/content/browser/web_api_handshake_checker.h" + +#include "base/memory/scoped_refptr.h" +#include "base/test/bind.h" +#include "components/safe_browsing/core/browser/url_checker_delegate.h" +#include "components/safe_browsing/core/db/fake_database_manager.h" +#include "components/security_interstitials/core/unsafe_resource.h" +#include "content/public/test/browser_task_environment.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace safe_browsing { + +class FakeUrlCheckerDelegate : public UrlCheckerDelegate { + public: + explicit FakeUrlCheckerDelegate( + scoped_refptr<SafeBrowsingDatabaseManager> database_manager) + : database_manager_(database_manager), + threat_types_( + SBThreatTypeSet({safe_browsing::SB_THREAT_TYPE_URL_PHISHING})) {} + + // UrlCheckerDelegate overrides: + void MaybeDestroyNoStatePrefetchContents( + base::OnceCallback<content::WebContents*()> web_contents_getter) + override {} + + void StartDisplayingBlockingPageHelper( + const security_interstitials::UnsafeResource& resource, + const std::string& method, + const net::HttpRequestHeaders& headers, + bool is_main_frame, + bool has_user_gesture) override { + resource.callback.Run(/*proceed=*/false, /*showed_intersitial=*/false); + } + + void StartObservingInteractionsForDelayedBlockingPageHelper( + const security_interstitials::UnsafeResource& resource, + bool is_main_frame) override {} + + bool IsUrlAllowlisted(const GURL& url) override { return false; } + + void SetPolicyAllowlistDomains( + const std::vector<std::string>& allowlist_domains) override {} + + bool ShouldSkipRequestCheck(const GURL& original_url, + int frame_tree_node_id, + int render_process_id, + int render_frame_id, + bool originated_from_service_worker) override { + return false; + } + + void NotifySuspiciousSiteDetected( + const base::RepeatingCallback<content::WebContents*()>& + web_contents_getter) override {} + + const SBThreatTypeSet& GetThreatTypes() override { return threat_types_; } + + SafeBrowsingDatabaseManager* GetDatabaseManager() override { + return database_manager_.get(); + } + + BaseUIManager* GetUIManager() override { return nullptr; } + + protected: + friend class base::RefCountedThreadSafe<FakeUrlCheckerDelegate>; + ~FakeUrlCheckerDelegate() override = default; + + private: + scoped_refptr<SafeBrowsingDatabaseManager> database_manager_; + SBThreatTypeSet threat_types_; +}; + +class WebApiHandshakeCheckerTest : public testing::Test { + protected: + void SetUp() override { + database_manager_ = base::MakeRefCounted<FakeSafeBrowsingDatabaseManager>(); + delegate_ = base::MakeRefCounted<FakeUrlCheckerDelegate>(database_manager_); + handshake_checker_ = std::make_unique<WebApiHandshakeChecker>( + base::BindOnce(&WebApiHandshakeCheckerTest::GetDelegate, + base::Unretained(this)), + base::BindRepeating(&WebApiHandshakeCheckerTest::GetWebContents, + base::Unretained(this)), + /*frame_tree_node_id=*/-1); + } + + FakeSafeBrowsingDatabaseManager* database_manager() { + return database_manager_.get(); + } + + WebApiHandshakeChecker::CheckResult Check(const GURL& url) { + WebApiHandshakeChecker::CheckResult out; + base::RunLoop loop; + handshake_checker_->Check( + url, base::BindLambdaForTesting( + [&](WebApiHandshakeChecker::CheckResult result) { + out = result; + loop.Quit(); + })); + loop.Run(); + return out; + } + + private: + scoped_refptr<UrlCheckerDelegate> GetDelegate() { return delegate_; } + + content::WebContents* GetWebContents() { return nullptr; } + + content::BrowserTaskEnvironment task_environment_; + scoped_refptr<FakeSafeBrowsingDatabaseManager> database_manager_; + scoped_refptr<FakeUrlCheckerDelegate> delegate_; + std::unique_ptr<WebApiHandshakeChecker> handshake_checker_; +}; + +TEST_F(WebApiHandshakeCheckerTest, CheckSafeUrl) { + const GURL kUrl("https://example.test"); + EXPECT_EQ(Check(kUrl), WebApiHandshakeChecker::CheckResult::kProceed); +} + +TEST_F(WebApiHandshakeCheckerTest, CheckDangerousUrl) { + const GURL kUrl("https://example.test"); + database_manager()->AddDangerousUrl(kUrl, SB_THREAT_TYPE_URL_PHISHING); + EXPECT_EQ(Check(kUrl), WebApiHandshakeChecker::CheckResult::kBlocked); +} + +} // namespace safe_browsing
diff --git a/components/safe_browsing/content/renderer/phishing_classifier/BUILD.gn b/components/safe_browsing/content/renderer/phishing_classifier/BUILD.gn index 77d460c..c07127a 100644 --- a/components/safe_browsing/content/renderer/phishing_classifier/BUILD.gn +++ b/components/safe_browsing/content/renderer/phishing_classifier/BUILD.gn
@@ -39,6 +39,10 @@ "//skia", "//third_party/blink/public:blink_headers", "//third_party/smhasher:murmurhash3", + "//third_party/tflite", + "//third_party/tflite:tflite_public_headers", + "//third_party/tflite-support", + "//third_party/tflite-support:tflite-support-proto", "//ui/base", "//ui/gfx/geometry:geometry", "//url",
diff --git a/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier.cc b/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier.cc index 3db29d2..8854544 100644 --- a/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier.cc +++ b/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier.cc
@@ -166,7 +166,11 @@ #if BUILDFLAG(FULL_SAFE_BROWSING) ExtractVisualFeatures(); #else - VisualExtractionFinished(true); + if (scorer_->HasVisualTfLiteModel()) { + ExtractVisualFeatures(); + } else { + VisualExtractionFinished(true); + } #endif } else { RunFailureCallback(); @@ -243,7 +247,9 @@ base::BindOnce(&PhishingClassifier::OnVisualTargetsMatched, weak_factory_.GetWeakPtr())); #else - RunCallback(*verdict); + scorer_->ApplyVisualTfLiteModel( + *bitmap_, base::BindOnce(&PhishingClassifier::OnVisualTfLiteModelDone, + weak_factory_.GetWeakPtr(), std::move(verdict))); #endif } @@ -256,6 +262,33 @@ base::UmaHistogramTimes("SBClientPhishing.VisualComparisonTime", base::TimeTicks::Now() - visual_matching_start_); + scorer_->ApplyVisualTfLiteModel( + *bitmap_, base::BindOnce(&PhishingClassifier::OnVisualTfLiteModelDone, + weak_factory_.GetWeakPtr(), std::move(verdict))); +} + +void PhishingClassifier::OnVisualTfLiteModelDone( + std::unique_ptr<ClientPhishingRequest> verdict, + std::vector<double> result) { + if (static_cast<int>(result.size()) > scorer_->tflite_thresholds().size()) { + // Model is misconfigured, so bail out. + RunFailureCallback(); + return; + } + + verdict->set_tflite_model_version(scorer_->tflite_model_version()); + for (size_t i = 0; i < result.size(); i++) { + ClientPhishingRequest::CategoryScore* category = + verdict->add_tflite_model_scores(); + category->set_label(scorer_->tflite_thresholds().at(i).label()); + category->set_value(result[i]); + + if (result[i] >= scorer_->tflite_thresholds().at(i).threshold()) { + verdict->set_is_phishing(true); + verdict->set_is_tflite_match(true); + } + } + RunCallback(*verdict); }
diff --git a/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier.h b/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier.h index cd4e943..a15faa0 100644 --- a/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier.h +++ b/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier.h
@@ -125,6 +125,11 @@ // model. void OnVisualTargetsMatched(std::unique_ptr<ClientPhishingRequest> verdict); + // Callback when the visual TFLite model has been applied, and returned a list + // of scores. + void OnVisualTfLiteModelDone(std::unique_ptr<ClientPhishingRequest> verdict, + std::vector<double> result); + // Helper method to run the DoneCallback and clear the state. void RunCallback(const ClientPhishingRequest& verdict);
diff --git a/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier_delegate.cc b/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier_delegate.cc index 659a29f..c6b03f9 100644 --- a/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier_delegate.cc +++ b/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier_delegate.cc
@@ -83,10 +83,11 @@ const std::string& model, base::File tflite_visual_model) { safe_browsing::Scorer* scorer = nullptr; - // An empty model string means we should disable client-side phishing - // detection. - if (!model.empty()) { - scorer = safe_browsing::Scorer::Create(model); + // An empty model string and invalid model file means we should disable + // client-side phishing detection. + if (!model.empty() || tflite_visual_model.IsValid()) { + scorer = + safe_browsing::Scorer::Create(model, std::move(tflite_visual_model)); if (!scorer) return; }
diff --git a/components/safe_browsing/content/renderer/phishing_classifier/scorer.cc b/components/safe_browsing/content/renderer/phishing_classifier/scorer.cc index 2d73557a..440bb3b 100644 --- a/components/safe_browsing/content/renderer/phishing_classifier/scorer.cc +++ b/components/safe_browsing/content/renderer/phishing_classifier/scorer.cc
@@ -22,10 +22,15 @@ #include "content/public/renderer/render_thread.h" #include "crypto/sha2.h" #include "third_party/skia/include/core/SkBitmap.h" +#include "third_party/tflite-support/src/tensorflow_lite_support/cc/task/core/task_api_factory.h" +#include "third_party/tflite-support/src/tensorflow_lite_support/cc/task/vision/image_classifier.h" +#include "third_party/tflite/src/tensorflow/lite/kernels/builtin_op_kernels.h" +#include "third_party/tflite/src/tensorflow/lite/op_resolver.h" namespace safe_browsing { namespace { + // Enum used to keep stats about the status of the Scorer creation. enum ScorerCreationStatus { SCORER_SUCCESS, @@ -34,6 +39,7 @@ SCORER_FAIL_MODEL_FILE_TOO_LARGE, // Not used anymore SCORER_FAIL_MODEL_PARSE_ERROR, SCORER_FAIL_MODEL_MISSING_FIELDS, + SCORER_FAIL_MAP_VISUAL_TFLITE_MODEL, SCORER_STATUS_MAX // Always add new values before this one. }; @@ -79,6 +85,104 @@ return request; } +std::unique_ptr<tflite::MutableOpResolver> CreateOpResolver() { + tflite::MutableOpResolver resolver; + // The minimal set of OPs required to run the visual model. + resolver.AddBuiltin(tflite::BuiltinOperator_ADD, + tflite::ops::builtin::Register_ADD()); + resolver.AddBuiltin(tflite::BuiltinOperator_CONV_2D, + tflite::ops::builtin::Register_CONV_2D()); + resolver.AddBuiltin(tflite::BuiltinOperator_DEPTHWISE_CONV_2D, + tflite::ops::builtin::Register_DEPTHWISE_CONV_2D()); + resolver.AddBuiltin(tflite::BuiltinOperator_FULLY_CONNECTED, + tflite::ops::builtin::Register_FULLY_CONNECTED()); + resolver.AddBuiltin(tflite::BuiltinOperator_MEAN, + tflite::ops::builtin::Register_MEAN()); + resolver.AddBuiltin(tflite::BuiltinOperator_SOFTMAX, + tflite::ops::builtin::Register_SOFTMAX()); + return std::make_unique<tflite::MutableOpResolver>(resolver); +} + +std::unique_ptr<tflite::task::vision::ImageClassifier> CreateClassifier( + const std::string& model_data) { + tflite::task::vision::ImageClassifierOptions options; + options.mutable_model_file_with_metadata()->set_file_content(model_data); + auto statusor_classifier = + tflite::task::vision::ImageClassifier::CreateFromOptions( + options, CreateOpResolver()); + if (!statusor_classifier.ok()) { + VLOG(1) << statusor_classifier.status().ToString(); + return nullptr; + } + + return std::move(*statusor_classifier); +} + +std::string GetModelInput(const SkBitmap& bitmap, int width, int height) { + // Use the Rec. 2020 color space, in case the user input is wide-gamut. + sk_sp<SkColorSpace> rec2020 = SkColorSpace::MakeRGB( + {2.22222f, 0.909672f, 0.0903276f, 0.222222f, 0.0812429f, 0, 0}, + SkNamedGamut::kRec2020); + + SkImageInfo downsampled_info = SkImageInfo::MakeN32( + width, height, SkAlphaType::kUnpremul_SkAlphaType, rec2020); + SkBitmap downsampled; + if (!downsampled.tryAllocPixels(downsampled_info)) + return std::string(); + bitmap.pixmap().scalePixels( + downsampled.pixmap(), + SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNearest)); + + // Format as an RGB buffer for input into the model + std::string data; + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) { + SkColor color = downsampled.getColor(x, y); + data += static_cast<char>(SkColorGetR(color)); + data += static_cast<char>(SkColorGetG(color)); + data += static_cast<char>(SkColorGetB(color)); + } + } + + return data; +} + +std::vector<double> ApplyVisualTfLiteModelHelper( + const SkBitmap& bitmap, + int input_width, + int input_height, + const std::string& model_data) { + std::unique_ptr<tflite::task::vision::ImageClassifier> classifier = + CreateClassifier(model_data); + if (!classifier) + return std::vector<double>(); + + std::string model_input = GetModelInput(bitmap, input_width, input_height); + if (model_input.empty()) + return std::vector<double>(); + + tflite::task::vision::FrameBuffer::Plane plane{ + reinterpret_cast<const tflite::uint8*>(model_input.data()), + {3 * input_width, 3}}; + auto frame_buffer = tflite::task::vision::FrameBuffer::Create( + {plane}, {input_width, input_height}, + tflite::task::vision::FrameBuffer::Format::kRGB, + tflite::task::vision::FrameBuffer::Orientation::kTopLeft); + auto statusor_result = classifier->Classify(*frame_buffer); + if (!statusor_result.ok()) { + VLOG(1) << statusor_result.status().ToString(); + return std::vector<double>(); + } else { + std::vector<double> scores( + statusor_result->classifications(0).classes().size()); + for (const tflite::task::vision::Class& clas : + statusor_result->classifications(0).classes()) { + scores[clas.index()] = clas.score(); + } + return scores; + } +} + } // namespace // Helper function which converts log odds to a probability in the range @@ -98,25 +202,40 @@ Scorer::~Scorer() {} /* static */ -Scorer* Scorer::Create(const base::StringPiece& model_str) { +Scorer* Scorer::Create(const base::StringPiece& model_str, + base::File visual_tflite_model) { std::unique_ptr<Scorer> scorer(new Scorer()); ClientSideModel& model = scorer->model_; // Parse the phishing model. - if (!model.ParseFromArray(model_str.data(), model_str.size())) { + if (!model_str.empty() && + !model.ParseFromArray(model_str.data(), model_str.size())) { RecordScorerCreationStatus(SCORER_FAIL_MODEL_PARSE_ERROR); - return NULL; - } else if (!model.IsInitialized()) { + return nullptr; + } + + if (!model_str.empty() && !model.IsInitialized()) { // The model may be missing some required fields. RecordScorerCreationStatus(SCORER_FAIL_MODEL_MISSING_FIELDS); - return NULL; + return nullptr; } + + if (!model_str.empty()) { + for (int i = 0; i < model.page_term_size(); ++i) { + scorer->page_terms_.insert(model.hashes(model.page_term(i))); + } + for (int i = 0; i < model.page_word_size(); ++i) { + scorer->page_words_.insert(model.page_word(i)); + } + } + + // Only do this part if the visual model file exists + if (visual_tflite_model.IsValid() && !scorer->visual_tflite_model_.Initialize( + std::move(visual_tflite_model))) { + RecordScorerCreationStatus(SCORER_FAIL_MAP_VISUAL_TFLITE_MODEL); + return nullptr; + } + RecordScorerCreationStatus(SCORER_SUCCESS); - for (int i = 0; i < model.page_term_size(); ++i) { - scorer->page_terms_.insert(model.hashes(model.page_term(i))); - } - for (int i = 0; i < model.page_word_size(); ++i) { - scorer->page_words_.insert(model.page_word(i)); - } return scorer.release(); } @@ -143,10 +262,33 @@ std::move(callback)); } +void Scorer::ApplyVisualTfLiteModel( + const SkBitmap& bitmap, + base::OnceCallback<void(std::vector<double>)> callback) const { + DCHECK(content::RenderThread::IsMainThread()); + if (visual_tflite_model_.IsValid()) { + base::ThreadPool::PostTaskAndReplyWithResult( + FROM_HERE, {base::TaskPriority::BEST_EFFORT}, + base::BindOnce(&ApplyVisualTfLiteModelHelper, bitmap, + model_.tflite_model_input_width(), + model_.tflite_model_input_height(), + std::string(reinterpret_cast<const char*>( + visual_tflite_model_.data()), + visual_tflite_model_.length())), + std::move(callback)); + } else { + std::move(callback).Run(std::vector<double>()); + } +} + int Scorer::model_version() const { return model_.version(); } +bool Scorer::HasVisualTfLiteModel() const { + return visual_tflite_model_.IsValid(); +} + const std::unordered_set<std::string>& Scorer::page_terms() const { return page_terms_; } @@ -175,6 +317,15 @@ return model_.threshold_probability(); } +int Scorer::tflite_model_version() const { + return model_.tflite_model_version(); +} + +const google::protobuf::RepeatedPtrField<ClientSideModel::Threshold>& +Scorer::tflite_thresholds() const { + return model_.tflite_thresholds(); +} + double Scorer::ComputeRuleScore(const ClientSideModel::Rule& rule, const FeatureMap& features) const { const std::unordered_map<std::string, double>& feature_map =
diff --git a/components/safe_browsing/content/renderer/phishing_classifier/scorer.h b/components/safe_browsing/content/renderer/phishing_classifier/scorer.h index cbfb4f6..52e1ae5 100644 --- a/components/safe_browsing/content/renderer/phishing_classifier/scorer.h +++ b/components/safe_browsing/content/renderer/phishing_classifier/scorer.h
@@ -21,6 +21,8 @@ #include <unordered_set> #include "base/callback.h" +#include "base/files/file.h" +#include "base/files/memory_mapped_file.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/strings/string_piece.h" @@ -38,7 +40,8 @@ // Factory method which creates a new Scorer object by parsing the given // model. If parsing fails this method returns NULL. - static Scorer* Create(const base::StringPiece& model_str); + static Scorer* Create(const base::StringPiece& model_str, + base::File visual_tflite_model); // This method computes the probability that the given features are indicative // of phishing. It returns a score value that falls in the range [0.0,1.0] @@ -55,9 +58,18 @@ base::OnceCallback<void(std::unique_ptr<ClientPhishingRequest>)> callback) const; + // This method applies the TfLite visual model to the given bitmap. It + // asynchronously returns the list of scores for each category, in the same + // order as `tflite_thresholds()`. + void ApplyVisualTfLiteModel( + const SkBitmap& bitmap, + base::OnceCallback<void(std::vector<double>)> callback) const; + // Returns the version number of the loaded client model. int model_version() const; + bool HasVisualTfLiteModel() const; + // -- Accessors used by the page feature extractor --------------------------- // Returns a set of hashed page terms that appear in the model in binary @@ -83,6 +95,13 @@ // Returns the threshold probability above which we send a CSD ping. float threshold_probability() const; + // Returns the version of the visual TFLite model. + int tflite_model_version() const; + + // Returns the thresholds configured for the visual TFLite model categories. + const google::protobuf::RepeatedPtrField<ClientSideModel::Threshold>& + tflite_thresholds() const; + protected: // Most clients should use the factory method. This constructor is public // to allow for mock implementations. @@ -103,6 +122,8 @@ std::unordered_set<std::string> page_terms_; std::unordered_set<uint32_t> page_words_; + base::MemoryMappedFile visual_tflite_model_; + base::WeakPtrFactory<Scorer> weak_ptr_factory_{this}; DISALLOW_COPY_AND_ASSIGN(Scorer);
diff --git a/components/safe_browsing/content/renderer/phishing_classifier/scorer_unittest.cc b/components/safe_browsing/content/renderer/phishing_classifier/scorer_unittest.cc index 3aa1927..0c56273 100644 --- a/components/safe_browsing/content/renderer/phishing_classifier/scorer_unittest.cc +++ b/components/safe_browsing/content/renderer/phishing_classifier/scorer_unittest.cc
@@ -110,21 +110,22 @@ TEST_F(PhishingScorerTest, HasValidModel) { std::unique_ptr<Scorer> scorer; - scorer.reset(Scorer::Create(model_.SerializeAsString())); - EXPECT_TRUE(scorer.get() != NULL); + scorer.reset(Scorer::Create(model_.SerializeAsString(), base::File())); + EXPECT_TRUE(scorer.get() != nullptr); // Invalid model string. - scorer.reset(Scorer::Create("bogus string")); + scorer.reset(Scorer::Create("bogus string", base::File())); EXPECT_FALSE(scorer.get()); // Mode is missing a required field. model_.clear_max_words_per_term(); - scorer.reset(Scorer::Create(model_.SerializePartialAsString())); + scorer.reset(Scorer::Create(model_.SerializePartialAsString(), base::File())); EXPECT_FALSE(scorer.get()); } TEST_F(PhishingScorerTest, PageTerms) { - std::unique_ptr<Scorer> scorer(Scorer::Create(model_.SerializeAsString())); + std::unique_ptr<Scorer> scorer( + Scorer::Create(model_.SerializeAsString(), base::File())); ASSERT_TRUE(scorer.get()); // Use std::vector instead of std::unordered_set for comparison. @@ -143,7 +144,8 @@ } TEST_F(PhishingScorerTest, PageWords) { - std::unique_ptr<Scorer> scorer(Scorer::Create(model_.SerializeAsString())); + std::unique_ptr<Scorer> scorer( + Scorer::Create(model_.SerializeAsString(), base::File())); ASSERT_TRUE(scorer.get()); std::vector<uint32_t> expected_page_words; expected_page_words.push_back(1000U); @@ -164,7 +166,8 @@ } TEST_F(PhishingScorerTest, ComputeScore) { - std::unique_ptr<Scorer> scorer(Scorer::Create(model_.SerializeAsString())); + std::unique_ptr<Scorer> scorer( + Scorer::Create(model_.SerializeAsString(), base::File())); ASSERT_TRUE(scorer.get()); // An empty feature map should match the empty rule. @@ -191,7 +194,8 @@ } TEST_F(PhishingScorerTest, GetMatchingVisualTargetsMatchOne) { - std::unique_ptr<Scorer> scorer(Scorer::Create(model_.SerializeAsString())); + std::unique_ptr<Scorer> scorer( + Scorer::Create(model_.SerializeAsString(), base::File())); // Make the whole image white for (int x = 0; x < 1000; x++) @@ -220,7 +224,8 @@ } TEST_F(PhishingScorerTest, GetMatchingVisualTargetsMatchBoth) { - std::unique_ptr<Scorer> scorer(Scorer::Create(model_.SerializeAsString())); + std::unique_ptr<Scorer> scorer( + Scorer::Create(model_.SerializeAsString(), base::File())); // Make the whole image white for (int x = 0; x < 1000; x++)
diff --git a/components/safe_browsing/core/proto/client_model.proto b/components/safe_browsing/core/proto/client_model.proto index d924076..4a89a31 100644 --- a/components/safe_browsing/core/proto/client_model.proto +++ b/components/safe_browsing/core/proto/client_model.proto
@@ -119,7 +119,11 @@ // Safe Browsing for a more definitive classification. repeated Threshold tflite_thresholds = 14; - // next available tag number: 15 + // The width and height of the input tensor to the corresponding TFLite model. + optional int32 tflite_model_input_width = 15; + optional int32 tflite_model_input_height = 16; + + // next available tag number: 17 } // Wrapper of the vision model for the similarity check target images.
diff --git a/components/segmentation_platform/internal/BUILD.gn b/components/segmentation_platform/internal/BUILD.gn index ce85f6d..7b7f9b0 100644 --- a/components/segmentation_platform/internal/BUILD.gn +++ b/components/segmentation_platform/internal/BUILD.gn
@@ -26,59 +26,30 @@ ] deps = [ - ":content", "//base", "//components/keyed_service/core", "//components/leveldb_proto", - "//components/optimization_guide/proto:optimization_guide_proto", "//components/segmentation_platform/internal/proto", "//components/segmentation_platform/public", ] -} -source_set("content") { - visibility = [ ":*" ] + public_deps = + [ "//components/optimization_guide/proto:optimization_guide_proto" ] if (build_with_tflite_lib) { - sources = [ - "content/segmentation_model_executor.cc", - "content/segmentation_model_executor.h", - "content/segmentation_model_handler.cc", - "content/segmentation_model_handler.h", + sources += [ + "execution/segmentation_model_executor.cc", + "execution/segmentation_model_executor.h", + "execution/segmentation_model_handler.cc", + "execution/segmentation_model_handler.h", ] - deps = [ - "//base", + deps += [ "//third_party/tflite:tflite_public_headers", "//third_party/tflite-support", ] - public_deps = [ - "//components/optimization_guide/core", - "//components/optimization_guide/proto:optimization_guide_proto", - ] - } -} - -source_set("content_unit_tests") { - testonly = true - - visibility = [ ":unit_tests" ] - - if (build_with_tflite_lib) { - # IMPORTANT NOTE: When adding new tests, also remember to update the list of - # tests in //components/segmentation_platform/components_unittests.filter - sources = [ "content/segmentation_model_executor_unittest.cc" ] - - deps = [ - ":content", - ":internal", - "//base", - "//base/test:test_support", - "//components/optimization_guide/core:test_support", - "//testing/gmock", - "//testing/gtest", - ] + public_deps += [ "//components/optimization_guide/core" ] } } @@ -98,7 +69,6 @@ ] deps = [ - ":content_unit_tests", ":internal", "//base/test:test_support", "//components/leveldb_proto:test_support", @@ -106,6 +76,17 @@ "//testing/gmock", "//testing/gtest", ] + + if (build_with_tflite_lib) { + # IMPORTANT NOTE: When adding new tests, also remember to update the list of + # tests in //components/segmentation_platform/components_unittests.filter + sources += [ "execution/segmentation_model_executor_unittest.cc" ] + + deps += [ + "//base", + "//components/optimization_guide/core:test_support", + ] + } } if (is_android) {
diff --git a/components/segmentation_platform/internal/content/DEPS b/components/segmentation_platform/internal/content/DEPS deleted file mode 100644 index 3477af99..0000000 --- a/components/segmentation_platform/internal/content/DEPS +++ /dev/null
@@ -1,3 +0,0 @@ -include_rules = [ - "+components/optimization_guide/content", -]
diff --git a/components/segmentation_platform/internal/content/segmentation_model_executor.cc b/components/segmentation_platform/internal/execution/segmentation_model_executor.cc similarity index 94% rename from components/segmentation_platform/internal/content/segmentation_model_executor.cc rename to components/segmentation_platform/internal/execution/segmentation_model_executor.cc index becdd8910..54ed888 100644 --- a/components/segmentation_platform/internal/content/segmentation_model_executor.cc +++ b/components/segmentation_platform/internal/execution/segmentation_model_executor.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 "components/segmentation_platform/internal/content/segmentation_model_executor.h" +#include "components/segmentation_platform/internal/execution/segmentation_model_executor.h" #include <vector>
diff --git a/components/segmentation_platform/internal/content/segmentation_model_executor.h b/components/segmentation_platform/internal/execution/segmentation_model_executor.h similarity index 85% rename from components/segmentation_platform/internal/content/segmentation_model_executor.h rename to components/segmentation_platform/internal/execution/segmentation_model_executor.h index a3cf4c72..f03fc51e 100644 --- a/components/segmentation_platform/internal/content/segmentation_model_executor.h +++ b/components/segmentation_platform/internal/execution/segmentation_model_executor.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 COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_CONTENT_SEGMENTATION_MODEL_EXECUTOR_H_ -#define COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_CONTENT_SEGMENTATION_MODEL_EXECUTOR_H_ +#ifndef COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_EXECUTION_SEGMENTATION_MODEL_EXECUTOR_H_ +#define COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_EXECUTION_SEGMENTATION_MODEL_EXECUTOR_H_ #include <memory> #include <vector> @@ -45,4 +45,4 @@ } // namespace segmentation_platform -#endif // COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_CONTENT_SEGMENTATION_MODEL_EXECUTOR_H_ +#endif // COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_EXECUTION_SEGMENTATION_MODEL_EXECUTOR_H_
diff --git a/components/segmentation_platform/internal/content/segmentation_model_executor_unittest.cc b/components/segmentation_platform/internal/execution/segmentation_model_executor_unittest.cc similarity index 94% rename from components/segmentation_platform/internal/content/segmentation_model_executor_unittest.cc rename to components/segmentation_platform/internal/execution/segmentation_model_executor_unittest.cc index 27a454f..511a427 100644 --- a/components/segmentation_platform/internal/content/segmentation_model_executor_unittest.cc +++ b/components/segmentation_platform/internal/execution/segmentation_model_executor_unittest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/segmentation_platform/internal/content/segmentation_model_executor.h" +#include "components/segmentation_platform/internal/execution/segmentation_model_executor.h" #include <memory> @@ -15,7 +15,7 @@ #include "components/optimization_guide/core/optimization_guide_model_provider.h" #include "components/optimization_guide/core/test_optimization_guide_model_provider.h" #include "components/optimization_guide/proto/models.pb.h" -#include "components/segmentation_platform/internal/content/segmentation_model_handler.h" +#include "components/segmentation_platform/internal/execution/segmentation_model_handler.h" #include "testing/gtest/include/gtest/gtest.h" namespace {
diff --git a/components/segmentation_platform/internal/content/segmentation_model_handler.cc b/components/segmentation_platform/internal/execution/segmentation_model_handler.cc similarity index 84% rename from components/segmentation_platform/internal/content/segmentation_model_handler.cc rename to components/segmentation_platform/internal/execution/segmentation_model_handler.cc index 9af032d1..5762f60 100644 --- a/components/segmentation_platform/internal/content/segmentation_model_handler.cc +++ b/components/segmentation_platform/internal/execution/segmentation_model_handler.cc
@@ -2,14 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/segmentation_platform/internal/content/segmentation_model_handler.h" +#include "components/segmentation_platform/internal/execution/segmentation_model_handler.h" #include <memory> #include <vector> #include "components/optimization_guide/core/model_executor.h" #include "components/optimization_guide/proto/models.pb.h" -#include "components/segmentation_platform/internal/content/segmentation_model_executor.h" +#include "components/segmentation_platform/internal/execution/segmentation_model_executor.h" namespace segmentation_platform {
diff --git a/components/segmentation_platform/internal/content/segmentation_model_handler.h b/components/segmentation_platform/internal/execution/segmentation_model_handler.h similarity index 84% rename from components/segmentation_platform/internal/content/segmentation_model_handler.h rename to components/segmentation_platform/internal/execution/segmentation_model_handler.h index 0c6412f..0f6f6ea 100644 --- a/components/segmentation_platform/internal/content/segmentation_model_handler.h +++ b/components/segmentation_platform/internal/execution/segmentation_model_handler.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_CONTENT_SEGMENTATION_MODEL_HANDLER_H_ -#define COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_CONTENT_SEGMENTATION_MODEL_HANDLER_H_ +#ifndef COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_EXECUTION_SEGMENTATION_MODEL_HANDLER_H_ +#define COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_EXECUTION_SEGMENTATION_MODEL_HANDLER_H_ #include <memory> #include <vector> @@ -39,4 +39,4 @@ } // namespace segmentation_platform -#endif // COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_CONTENT_SEGMENTATION_MODEL_HANDLER_H_ +#endif // COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_EXECUTION_SEGMENTATION_MODEL_HANDLER_H_
diff --git a/components/soda/soda_installer.h b/components/soda/soda_installer.h index 6d5f2bb..efc790c 100644 --- a/components/soda/soda_installer.h +++ b/components/soda/soda_installer.h
@@ -80,11 +80,11 @@ // other platforms. virtual base::FilePath GetLanguagePath() const = 0; - // Installs the user-selected SODA language model. Called by CaptionController - // when the kLiveCaptionEnabled or kLiveCaptionLanguageCode preferences - // change. `language` is a localized language e.g. "en-US". `global_prefs` is - // passed as part of component registration for the non-ChromeOS - // implementation. + // Installs the user-selected SODA language model. Called by + // LiveCaptionController when the kLiveCaptionEnabled or + // kLiveCaptionLanguageCode preferences change. `language` is a localized + // language e.g. "en-US". `global_prefs` is passed as part of component + // registration for the non-ChromeOS implementation. virtual void InstallLanguage(const std::string& language, PrefService* global_prefs) = 0;
diff --git a/components/variations/service/variations_field_trial_creator.cc b/components/variations/service/variations_field_trial_creator.cc index bbbc279..30611ab6 100644 --- a/components/variations/service/variations_field_trial_creator.cc +++ b/components/variations/service/variations_field_trial_creator.cc
@@ -28,6 +28,7 @@ #include "build/build_config.h" #include "build/chromeos_buildflags.h" #include "components/language/core/browser/locale_util.h" +#include "components/metrics/metrics_state_manager.h" #include "components/prefs/pref_service.h" #include "components/variations/field_trial_config/field_trial_util.h" #include "components/variations/platform_field_trials.h" @@ -40,6 +41,7 @@ #include "components/variations/variations_ids_provider.h" #include "components/variations/variations_seed_processor.h" #include "components/variations/variations_switches.h" +#include "components/version_info/channel.h" #include "ui/base/device_form_factor.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" @@ -180,6 +182,7 @@ std::unique_ptr<const base::FieldTrial::EntropyProvider> low_entropy_provider, std::unique_ptr<base::FeatureList> feature_list, + metrics::MetricsStateManager* metrics_state_manager, PlatformFieldTrials* platform_field_trials, SafeSeedManager* safe_seed_manager, absl::optional<int> low_entropy_source_value) {
diff --git a/components/variations/service/variations_field_trial_creator.h b/components/variations/service/variations_field_trial_creator.h index da5a1f5..093a5d0 100644 --- a/components/variations/service/variations_field_trial_creator.h +++ b/components/variations/service/variations_field_trial_creator.h
@@ -19,6 +19,10 @@ #include "components/variations/service/ui_string_overrider.h" #include "components/variations/variations_seed_store.h" +namespace metrics { +class MetricsStateManager; +} + namespace variations { enum LoadPermanentConsistencyCountryResult { @@ -59,25 +63,29 @@ // Sets up field trials based on stored variations seed data. Returns whether // setup completed successfully. + // // |kEnableGpuBenchmarking|, |kEnableFeatures|, |kDisableFeatures| are - // feature controlling flags not directly accesible from variations. + // feature-controlling flags not directly accessible from variations. // |variation_ids| allows for forcing ids selected in chrome://flags and/or // specified using the command-line flag. + // |extra_overrides| gives a list of feature overrides that should be applied + // after the features explicitly disabled/enabled from the command line via + // --disable-features and --enable-features, but before field trials. // |low_entropy_provider| allows for field trial randomization. // |feature_list| contains the list of all active features for this client. - // |platform_field_trials| provides the platform specific field trial set up + // |metrics_state_manager| facilitates signaling that Chrome has not yet + // exited cleanly. + // |platform_field_trials| provides the platform-specific field trial set up // for Chrome. // |safe_seed_manager| should be notified of the combined server and client // state that was activated to create the field trials (only when the return // value is true). // |low_entropy_source_value| contains the low entropy source value that was // used for client-side randomization of variations. - // |extra_overrides| gives a list of feature overrides that should be applied - // after the features explicitly disabled/enabled from the command line via - // --disable-features and --enable-features, but before field trials. - // Note: The ordering of the FeatureList method calls is such that the + // + // NOTE: The ordering of the FeatureList method calls is such that the // explicit --disable-features and --enable-features from the command line - // take precedence over the |extra_overrides|, which take precedence over the + // take precedence over |extra_overrides|, which takes precedence over the // field trials. bool SetupFieldTrials( const char* kEnableGpuBenchmarking, @@ -89,6 +97,7 @@ std::unique_ptr<const base::FieldTrial::EntropyProvider> low_entropy_provider, std::unique_ptr<base::FeatureList> feature_list, + metrics::MetricsStateManager* metrics_state_manager, PlatformFieldTrials* platform_field_trials, SafeSeedManager* safe_seed_manager, absl::optional<int> low_entropy_source_value);
diff --git a/components/variations/service/variations_field_trial_creator_unittest.cc b/components/variations/service/variations_field_trial_creator_unittest.cc index 0118dbc..86c6d0cd 100644 --- a/components/variations/service/variations_field_trial_creator_unittest.cc +++ b/components/variations/service/variations_field_trial_creator_unittest.cc
@@ -16,6 +16,9 @@ #include "base/version.h" #include "build/build_config.h" #include "components/metrics/clean_exit_beacon.h" +#include "components/metrics/client_info.h" +#include "components/metrics/metrics_state_manager.h" +#include "components/metrics/test/test_enabled_state_provider.h" #include "components/prefs/testing_pref_service.h" #include "components/variations/platform_field_trials.h" #include "components/variations/pref_names.h" @@ -51,6 +54,12 @@ const char kTestSeedData[] = "a serialized seed, 100% realistic"; const char kTestSeedSignature[] = "a totally valid signature, I swear!"; +// No-op functions used to create a MetricsStateManager. +void NoOpStoreClientInfoBackup(const metrics::ClientInfo&) {} +std::unique_ptr<metrics::ClientInfo> NoOpLoadClientInfoBackup() { + return nullptr; +} + // Populates |seed| with simple test data. The resulting seed will contain one // study called "test", which contains one experiment called "abc" with // probability weight 100. @@ -238,8 +247,14 @@ client, std::make_unique<VariationsSeedStore>(local_state), UIStringOverrider()), + enabled_state_provider_(/*consent=*/true, /*enabled=*/true), seed_store_(local_state), - safe_seed_manager_(safe_seed_manager) {} + safe_seed_manager_(safe_seed_manager) { + metrics_state_manager_ = metrics::MetricsStateManager::Create( + local_state, &enabled_state_provider_, std::wstring(), + base::BindRepeating(&NoOpStoreClientInfoBackup), + base::BindRepeating(&NoOpLoadClientInfoBackup)); + } ~TestVariationsFieldTrialCreator() override = default; @@ -250,8 +265,8 @@ return VariationsFieldTrialCreator::SetupFieldTrials( "", "", "", std::vector<std::string>(), std::vector<base::FeatureList::FeatureOverrideInfo>(), nullptr, - std::make_unique<base::FeatureList>(), &platform_field_trials, - safe_seed_manager_, absl::nullopt); + std::make_unique<base::FeatureList>(), metrics_state_manager_.get(), + &platform_field_trials, safe_seed_manager_, absl::nullopt); } TestVariationsSeedStore* seed_store() { return &seed_store_; } @@ -259,8 +274,10 @@ private: VariationsSeedStore* GetSeedStore() override { return &seed_store_; } + metrics::TestEnabledStateProvider enabled_state_provider_; TestVariationsSeedStore seed_store_; SafeSeedManager* const safe_seed_manager_; + std::unique_ptr<metrics::MetricsStateManager> metrics_state_manager_; DISALLOW_COPY_AND_ASSIGN(TestVariationsFieldTrialCreator); }; @@ -271,6 +288,7 @@ protected: FieldTrialCreatorTest() { metrics::CleanExitBeacon::RegisterPrefs(prefs_.registry()); + metrics::MetricsStateManager::RegisterPrefs(prefs_.registry()); VariationsService::RegisterPrefs(prefs_.registry()); global_feature_list_ = base::FeatureList::ClearInstanceForTesting(); } @@ -495,6 +513,13 @@ &prefs_, &variations_service_client, std::move(seed_store), UIStringOverrider()); + metrics::TestEnabledStateProvider enabled_state_provider(/*consent=*/true, + /*enabled=*/true); + auto metrics_state_manager = metrics::MetricsStateManager::Create( + &prefs_, &enabled_state_provider, std::wstring(), + base::BindRepeating(&NoOpStoreClientInfoBackup), + base::BindRepeating(&NoOpLoadClientInfoBackup)); + // Check that field trials are created from the seed. The test seed contains a // single study with an experiment targeting 100% of users in India. Since // |initial_seed| included the country code for India, this study should be @@ -502,8 +527,8 @@ EXPECT_TRUE(field_trial_creator.SetupFieldTrials( "", "", "", std::vector<std::string>(), std::vector<base::FeatureList::FeatureOverrideInfo>(), nullptr, - std::make_unique<base::FeatureList>(), &platform_field_trials, - &safe_seed_manager, absl::nullopt)); + std::make_unique<base::FeatureList>(), metrics_state_manager.get(), + &platform_field_trials, &safe_seed_manager, absl::nullopt)); EXPECT_EQ(kTestSeedExperimentName, base::FieldTrialList::FindFullName(kTestSeedStudyName));
diff --git a/components/variations/service/variations_service.cc b/components/variations/service/variations_service.cc index 98baea86..e7bf9b1 100644 --- a/components/variations/service/variations_service.cc +++ b/components/variations/service/variations_service.cc
@@ -1005,7 +1005,7 @@ return field_trial_creator_.SetupFieldTrials( kEnableGpuBenchmarking, kEnableFeatures, kDisableFeatures, variation_ids, extra_overrides, CreateLowEntropyProvider(), std::move(feature_list), - platform_field_trials, &safe_seed_manager_, + state_manager_, platform_field_trials, &safe_seed_manager_, state_manager_->GetLowEntropySource()); }
diff --git a/components/vector_icons/BUILD.gn b/components/vector_icons/BUILD.gn index 80047676..2cafc730 100644 --- a/components/vector_icons/BUILD.gn +++ b/components/vector_icons/BUILD.gn
@@ -8,7 +8,6 @@ icon_directory = "." sources = [ - "add_cellular_network.icon", "ads.icon", "back_arrow.icon", "blocked_badge.icon",
diff --git a/content/app/content_main.cc b/content/app/content_main.cc index 2c2619b..e953579 100644 --- a/content/app/content_main.cc +++ b/content/app/content_main.cc
@@ -62,6 +62,10 @@ #include "base/posix/global_descriptors.h" #endif +#if defined(OS_CHROMEOS) || defined(OS_LINUX) +#include "base/files/scoped_file.h" +#endif + #if defined(OS_MAC) #include "base/mac/scoped_nsautorelease_pool.h" #include "content/app/mac_init.h" @@ -304,6 +308,10 @@ InitializeMac(); #endif +#if defined(OS_CHROMEOS) || defined(OS_LINUX) + base::subtle::EnableFDOwnershipEnforcement(true); +#endif + mojo::core::Configuration mojo_config; mojo_config.max_message_num_bytes = kMaximumMojoMessageSize; InitializeMojo(&mojo_config);
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index 44225be..4d7432f 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn
@@ -1021,8 +1021,6 @@ "indexed_db/transaction_impl.h", "installedapp/installed_app_provider_impl.cc", "installedapp/installed_app_provider_impl.h", - "interest_group/ad_auction.cc", - "interest_group/ad_auction.h", "interest_group/ad_auction_service_impl.cc", "interest_group/ad_auction_service_impl.h", "interest_group/auction_runner.cc",
diff --git a/content/browser/accessibility/hit_testing_browsertest.cc b/content/browser/accessibility/hit_testing_browsertest.cc index 2bc35ae..56f6025 100644 --- a/content/browser/accessibility/hit_testing_browsertest.cc +++ b/content/browser/accessibility/hit_testing_browsertest.cc
@@ -56,6 +56,8 @@ base::StringPrintf("%.2f", device_scale_factor)); base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( switches::kEnableUseZoomForDSF, use_zoom_for_dsf ? "true" : "false"); + base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( + switches::kEnableBlinkFeatures, "AccessibilityAriaTouchPassthrough"); } std::string AccessibilityHitTestingBrowserTest::TestPassToString::operator()(
diff --git a/content/browser/browser_child_process_host_impl_receiver_bindings.cc b/content/browser/browser_child_process_host_impl_receiver_bindings.cc index a10a83f..c1a7cf3 100644 --- a/content/browser/browser_child_process_host_impl_receiver_bindings.cc +++ b/content/browser/browser_child_process_host_impl_receiver_bindings.cc
@@ -18,6 +18,7 @@ #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/device_service.h" +#include "content/public/common/content_features.h" #include "services/device/public/mojom/power_monitor.mojom.h" #include "services/metrics/public/cpp/ukm_recorder.h" #include "services/metrics/public/mojom/ukm_interface.mojom.h" @@ -95,12 +96,26 @@ if (auto r = receiver.As< discardable_memory::mojom::DiscardableSharedMemoryManager>()) { - discardable_memory::DiscardableSharedMemoryManager::Get()->Bind( - std::move(r)); + if (base::FeatureList::IsEnabled(features::kProcessHostOnUI)) { + GetIOThreadTaskRunner({})->PostTask( + FROM_HERE, + base::BindOnce( + [](mojo::PendingReceiver< + discardable_memory::mojom::DiscardableSharedMemoryManager> + r) { + discardable_memory::DiscardableSharedMemoryManager::Get()->Bind( + std::move(r)); + }, + std::move(r))); + } else { + discardable_memory::DiscardableSharedMemoryManager::Get()->Bind( + std::move(r)); + } return; } if (auto r = receiver.As<device::mojom::PowerMonitor>()) { + // TODO(jam): When ProcessHostOnUI is the default just remove this PostTask. GetUIThreadTaskRunner({})->PostTask( FROM_HERE, base::BindOnce(
diff --git a/content/browser/browser_context.cc b/content/browser/browser_context.cc index ec825b66..a7734981 100644 --- a/content/browser/browser_context.cc +++ b/content/browser/browser_context.cc
@@ -111,13 +111,10 @@ return impl()->GetDownloadManager(); } -// static -storage::ExternalMountPoints* BrowserContext::GetMountPoints( - BrowserContext* self) { - return self->impl()->GetMountPoints(); +storage::ExternalMountPoints* BrowserContext::GetMountPoints() { + return impl()->GetMountPoints(); } -// static BrowsingDataRemover* BrowserContext::GetBrowsingDataRemover() { return impl()->GetBrowsingDataRemover(); } @@ -246,13 +243,11 @@ std::move(old_subscription), std::move(callback)); } -// static -void BrowserContext::NotifyWillBeDestroyed(BrowserContext* self) { - self->impl()->NotifyWillBeDestroyed(); +void BrowserContext::NotifyWillBeDestroyed() { + impl()->NotifyWillBeDestroyed(); } -// static -void BrowserContext::EnsureResourceContextInitialized(BrowserContext* self) { +void BrowserContext::EnsureResourceContextInitialized() { // This will be enough to tickle initialization of BrowserContext if // necessary, which initializes ResourceContext. The reason we don't call // ResourceContext::InitializeResourceContext() directly here is that @@ -261,12 +256,11 @@ // end up rewriting the same value but this still causes a race condition. // // See http://crbug.com/115678. - self->GetDefaultStoragePartition(); + GetDefaultStoragePartition(); } -// static -void BrowserContext::SaveSessionState(BrowserContext* self) { - StoragePartition* storage_partition = self->GetDefaultStoragePartition(); +void BrowserContext::SaveSessionState() { + StoragePartition* storage_partition = GetDefaultStoragePartition(); storage::DatabaseTracker* database_tracker = storage_partition->GetDatabaseTracker(); @@ -310,10 +304,8 @@ std::move(permission_controller)); } -// static -SharedCorsOriginAccessList* BrowserContext::GetSharedCorsOriginAccessList( - BrowserContext* self) { - return self->impl()->shared_cors_origin_access_list(); +SharedCorsOriginAccessList* BrowserContext::GetSharedCorsOriginAccessList() { + return impl()->shared_cors_origin_access_list(); } void BrowserContext::ShutdownStoragePartitions() {
diff --git a/content/browser/child_process_security_policy_impl.cc b/content/browser/child_process_security_policy_impl.cc index dda4cd01..d548b3d 100644 --- a/content/browser/child_process_security_policy_impl.cc +++ b/content/browser/child_process_security_policy_impl.cc
@@ -2083,6 +2083,10 @@ if (!matches_profile) continue; + // Do not include origins that only apply to specific BrowsingInstances. + if (!isolated_origin_entry.applies_to_future_browsing_instances()) + continue; + origins.push_back(isolated_origin_entry.origin()); } }
diff --git a/content/browser/download/download_manager_impl.cc b/content/browser/download/download_manager_impl.cc index 049f1ef..d62a36a 100644 --- a/content/browser/download/download_manager_impl.cc +++ b/content/browser/download/download_manager_impl.cc
@@ -1300,7 +1300,7 @@ std::make_unique<network::WrapperPendingSharedURLLoaderFactory>( FileURLLoaderFactory::Create( browser_context_->GetPath(), - BrowserContext::GetSharedCorsOriginAccessList(browser_context_), + browser_context_->GetSharedCorsOriginAccessList(), // USER_VISIBLE because download should progress // even when there is high priority work to do. base::TaskPriority::USER_VISIBLE));
diff --git a/content/browser/download/save_file_manager.cc b/content/browser/download/save_file_manager.cc index 0a6f1b0..bb32282 100644 --- a/content/browser/download/save_file_manager.cc +++ b/content/browser/download/save_file_manager.cc
@@ -266,8 +266,7 @@ factory = factory_remote.get(); } else if (url.SchemeIsFile()) { factory_remote.Bind(FileURLLoaderFactory::Create( - context->GetPath(), - BrowserContext::GetSharedCorsOriginAccessList(context), + context->GetPath(), context->GetSharedCorsOriginAccessList(), base::TaskPriority::USER_VISIBLE)); factory = factory_remote.get(); } else if (url.SchemeIsFileSystem() && rfh) {
diff --git a/content/browser/file_system/browser_file_system_helper.cc b/content/browser/file_system/browser_file_system_helper.cc index 4ed9e3a..c55a873 100644 --- a/content/browser/file_system/browser_file_system_helper.cc +++ b/content/browser/file_system/browser_file_system_helper.cc
@@ -137,7 +137,7 @@ scoped_refptr<storage::FileSystemContext> file_system_context = new storage::FileSystemContext( GetIOThreadTaskRunner({}).get(), g_fileapi_task_runner.Get().get(), - BrowserContext::GetMountPoints(browser_context), + browser_context->GetMountPoints(), browser_context->GetSpecialStoragePolicy(), quota_manager_proxy, std::move(additional_backends), url_request_auto_mount_handlers, profile_path, options);
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc index f0689a03..4f7de561 100644 --- a/content/browser/gpu/gpu_process_host.cc +++ b/content/browser/gpu/gpu_process_host.cc
@@ -1120,8 +1120,7 @@ mojo::PendingReceiver< discardable_memory::mojom::DiscardableSharedMemoryManager> receiver) { if (base::FeatureList::IsEnabled(features::kProcessHostOnUI)) { - discardable_memory::DiscardableSharedMemoryManager::Get()->Bind( - std::move(receiver)); + BindDiscardableMemoryReceiverOnUI(std::move(receiver)); return; }
diff --git a/content/browser/interest_group/ad_auction.cc b/content/browser/interest_group/ad_auction.cc deleted file mode 100644 index 4ef9d7a..0000000 --- a/content/browser/interest_group/ad_auction.cc +++ /dev/null
@@ -1,225 +0,0 @@ -// Copyright 2021 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/browser/interest_group/ad_auction.h" - -#include <memory> -#include <string> -#include <vector> - -#include "base/bind.h" -#include "base/callback.h" -#include "base/check.h" -#include "base/memory/weak_ptr.h" -#include "base/strings/stringprintf.h" -#include "content/browser/devtools/devtools_instrumentation.h" -#include "content/browser/interest_group/ad_auction_service_impl.h" -#include "content/browser/interest_group/auction_runner.h" -#include "content/browser/interest_group/auction_url_loader_factory_proxy.h" -#include "content/browser/interest_group/interest_group_manager.h" -#include "content/browser/renderer_host/render_frame_host_impl.h" -#include "content/public/browser/content_browser_client.h" -#include "content/public/browser/render_frame_host.h" -#include "content/public/common/content_client.h" -#include "content/services/auction_worklet/public/mojom/bidder_worklet.mojom.h" -#include "services/network/public/mojom/url_loader_factory.mojom.h" -#include "third_party/abseil-cpp/absl/types/optional.h" -#include "third_party/blink/public/mojom/interest_group/interest_group_types.mojom.h" -#include "url/gurl.h" -#include "url/origin.h" -#include "url/url_constants.h" - -namespace content { - -namespace { - -bool IsAuctionValid(const blink::mojom::AuctionAdConfig& config) { - // The seller origin has to be HTTPS and match the `decision_logic_url` - // origin. - if (config.seller.scheme() != url::kHttpsScheme || - !config.decision_logic_url.SchemeIs(url::kHttpsScheme) || - config.seller != url::Origin::Create(config.decision_logic_url)) { - return false; - } - - if (!config.interest_group_buyers || - config.interest_group_buyers->is_all_buyers()) { - return false; - } - DCHECK(config.interest_group_buyers->is_buyers()); - - // All interest group owners must be HTTPS. - for (const url::Origin& buyer : config.interest_group_buyers->get_buyers()) { - if (buyer.scheme() != url::kHttpsScheme) - return false; - } - - // All buyer signals must be for listed buyers. - if (config.per_buyer_signals) { - for (const auto& it : config.per_buyer_signals.value()) { - if (!base::Contains(config.interest_group_buyers->get_buyers(), - it.first)) { - return false; - } - } - } - - return true; -} - -} // namespace - -AdAuction::AdAuction(AdAuctionServiceImpl* ad_auction_service, - blink::mojom::AuctionAdConfigPtr config, - AuctionCompleteCallback callback) - : ad_auction_service_(ad_auction_service), - config_(std::move(config)), - callback_(std::move(callback)) { - DCHECK(ad_auction_service_); - DCHECK(config_); - DCHECK(callback_); -} - -AdAuction::~AdAuction() = default; - -void AdAuction::StartAuction() { - if (!IsAuctionValid(*config_)) { - OnAuctionFailed(); - return; - } - - const url::Origin& frame_origin = ad_auction_service_->origin(); - BrowserContext* browser_context = - ad_auction_service_->render_frame_host()->GetBrowserContext(); - // If the interest group API is not allowed for this seller do nothing. - if (!GetContentClient()->browser()->IsInterestGroupAPIAllowed( - browser_context, frame_origin, config_->seller.GetURL())) { - OnAuctionFailed(); - return; - } - - // Filter out buyers for whom the interest group API is not allowed. - const auto& buyers = config_->interest_group_buyers->get_buyers(); - std::copy_if( - buyers.begin(), buyers.end(), std::back_inserter(pending_buyers_), - [browser_context, &frame_origin](const url::Origin& buyer) { - return GetContentClient()->browser()->IsInterestGroupAPIAllowed( - browser_context, frame_origin, buyer.GetURL()); - }); - - // If there are no buyers (either due to filtering, or in the original auction - // request), fail the auction. - if (pending_buyers_.empty()) { - OnAuctionFailed(); - return; - } - - ReadNextInterestGroup(); -} - -void AdAuction::ReadNextInterestGroup() { - DCHECK(!pending_buyers_.empty()); - - url::Origin buyer = std::move(pending_buyers_.back()); - pending_buyers_.pop_back(); - - ad_auction_service_->GetInterestGroupManager()->GetInterestGroupsForOwner( - buyer, base::BindOnce(&AdAuction::OnInterestGroupRead, - weak_ptr_factory_.GetWeakPtr())); -} - -void AdAuction::OnInterestGroupRead( - std::vector<auction_worklet::mojom::BiddingInterestGroupPtr> - interest_groups) { - bidders_.insert(bidders_.end(), - std::make_move_iterator(interest_groups.begin()), - std::make_move_iterator(interest_groups.end())); - - // If more buyers in the queue, load the next one. - if (!pending_buyers_.empty()) { - ReadNextInterestGroup(); - return; - } - - // If there are no found interest groups, end the auction without a winner. - if (bidders_.empty()) { - OnAuctionFailed(); - return; - } - - StartWorklets(); -} - -void AdAuction::StartWorklets() { - DCHECK(pending_buyers_.empty()); - DCHECK(!bidders_.empty()); - - // TODO(mmenke): This should be top frame origin, not frame origin. - auto browser_signals = auction_worklet::mojom::BrowserSignals::New( - ad_auction_service_->origin(), config_->seller); - - std::vector<auction_worklet::mojom::BiddingInterestGroupPtr> bidders_copy; - bidders_copy.reserve(bidders_.size()); - for (auto& bidder : bidders_) - bidders_copy.emplace_back(bidder.Clone()); - - // `config_` is no longer needed after this point, so pass ownership of it - // over to the AuctionRunner, instead of copying it. - auction_runner_ = AuctionRunner::CreateAndStart( - ad_auction_service_, std::move(config_), std::move(bidders_copy), - std::move(browser_signals), ad_auction_service_->origin(), - base::BindOnce(&AdAuction::WorkletComplete, - weak_ptr_factory_.GetWeakPtr())); -} - -void AdAuction::WorkletComplete(const GURL& render_url, - const std::string& ad_metadata, - const url::Origin& owner, - const std::string& name, - const GURL& bidder_report_url, - const GURL& seller_report_url, - const std::vector<std::string>& errors) { - DCHECK(callback_); - - // Forward debug information to devtools. - for (const std::string& error : errors) { - devtools_instrumentation::LogWorkletError( - static_cast<RenderFrameHostImpl*>( - ad_auction_service_->render_frame_host()), - error); - } - - if (!render_url.is_valid()) { - OnAuctionFailed(); - return; - } - - absl::optional<GURL> opt_bidder_report_url; - if (bidder_report_url.is_valid()) - opt_bidder_report_url = bidder_report_url; - - absl::optional<GURL> opt_seller_report_url; - if (seller_report_url.is_valid()) - opt_seller_report_url = seller_report_url; - - ad_auction_service_->GetInterestGroupManager()->RecordInterestGroupWin( - owner, name, ad_metadata); - // TODO(qingxin): Decide if we should record a bid if the auction fails, or - // the interest group doesn't make a bid. - for (const auto& bidder : bidders_) { - ad_auction_service_->GetInterestGroupManager()->RecordInterestGroupBid( - bidder->group->owner, bidder->group->name); - } - - std::move(callback_).Run(this, render_url, opt_bidder_report_url, - opt_seller_report_url); -} - -void AdAuction::OnAuctionFailed() { - DCHECK(callback_); - - std::move(callback_).Run(this, absl::nullopt, absl::nullopt, absl::nullopt); -} - -} // namespace content
diff --git a/content/browser/interest_group/ad_auction.h b/content/browser/interest_group/ad_auction.h deleted file mode 100644 index bd066b5..0000000 --- a/content/browser/interest_group/ad_auction.h +++ /dev/null
@@ -1,99 +0,0 @@ -// Copyright 2021 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_BROWSER_INTEREST_GROUP_AD_AUCTION_H_ -#define CONTENT_BROWSER_INTEREST_GROUP_AD_AUCTION_H_ - -#include <memory> -#include <string> -#include <vector> - -#include "base/callback_forward.h" -#include "base/memory/weak_ptr.h" -#include "content/services/auction_worklet/public/mojom/bidder_worklet.mojom-forward.h" -#include "third_party/abseil-cpp/absl/types/optional.h" -#include "third_party/blink/public/mojom/interest_group/interest_group_types.mojom.h" -#include "url/gurl.h" -#include "url/origin.h" - -namespace content { - -class AdAuctionServiceImpl; -class AuctionRunner; - -// Class for running a single FLEDGE auction. -class AdAuction { - public: - // Callback for completion, invoked on both success and error. On success, - // when the auction had a winner, `render_url` is non-null. On failure or when - // an auction had no winner, all URLs are null. - using AuctionCompleteCallback = - base::OnceCallback<void(AdAuction* auction, - absl::optional<GURL> render_url, - absl::optional<GURL> bidder_report_url, - absl::optional<GURL> seller_report_url)>; - - // `ad_auction_service` must remain valid for the lifetime of the AdAuction. - AdAuction(AdAuctionServiceImpl* ad_auction_service, - blink::mojom::AuctionAdConfigPtr config, - AuctionCompleteCallback callback); - ~AdAuction(); - - // May invoke `AuctionCompleteCallback` synchronously. - void StartAuction(); - - private: - // Retrieves the next interest group in `pending_buyers_` from storage, - // removing it from the vector. OnInterestGroupRead() will be invoked - // with the lookup results. - void ReadNextInterestGroup(); - - // Adds `interest_groups` to `bidders_`. Continues retrieving bidders from - // `pending_buyers_` if non-empty. Otherwise, starts running the worklets. - void OnInterestGroupRead( - std::vector<auction_worklet::mojom::BiddingInterestGroupPtr> - interest_groups); - - // Starts running the auction out of process. - void StartWorklets(); - - // Called from the worklet service once a worklet is complete. - // - // Validates the results, reports them to `callback_`, and updates the - // InterestGroupStorage as needed. - void WorkletComplete(const GURL& render_url, - const std::string& ad_metadata, - const url::Origin& owner, - const std::string& name, - const GURL& bidder_report_url, - const GURL& seller_report_url, - const std::vector<std::string>& errors); - - // Invokes `callback_` with empty parameters, to inform it of the failure. - void OnAuctionFailed(); - - AdAuctionServiceImpl* ad_auction_service_; - - // Populated on construction, moved to the worklet service when running an - // auction, since it's not used afterwards. - blink::mojom::AuctionAdConfigPtr config_; - - // List of loaded interest groups. Populated by the calls to - // OnInterestGroupRead(). - std::vector<auction_worklet::mojom::BiddingInterestGroupPtr> bidders_; - - AuctionCompleteCallback callback_; - - // Buyers from `config->interest_group_buyers` that have yet to be retrieved - // from interest group storage. - std::vector<url::Origin> pending_buyers_; - - std::unique_ptr<AuctionRunner> auction_runner_; - - base::WeakPtrFactory<AdAuction> weak_ptr_factory_{this}; -}; - -} // namespace content - -#endif // CONTENT_BROWSER_INTEREST_GROUP_AD_AUCTION_H_
diff --git a/content/browser/interest_group/ad_auction_service_impl.cc b/content/browser/interest_group/ad_auction_service_impl.cc index 3d676b2f..669745d 100644 --- a/content/browser/interest_group/ad_auction_service_impl.cc +++ b/content/browser/interest_group/ad_auction_service_impl.cc
@@ -11,7 +11,7 @@ #include "base/containers/contains.h" #include "base/strings/stringprintf.h" #include "content/browser/devtools/devtools_instrumentation.h" -#include "content/browser/interest_group/ad_auction.h" +#include "content/browser/interest_group/auction_runner.h" #include "content/browser/renderer_host/render_frame_host_impl.h" #include "content/browser/service_sandbox_type.h" #include "content/browser/storage_partition_impl.h" @@ -91,6 +91,40 @@ std::move(simple_url_loader))); } +bool IsAuctionValid(const blink::mojom::AuctionAdConfig& config) { + // The seller origin has to be HTTPS and match the `decision_logic_url` + // origin. + if (config.seller.scheme() != url::kHttpsScheme || + !config.decision_logic_url.SchemeIs(url::kHttpsScheme) || + config.seller != url::Origin::Create(config.decision_logic_url)) { + return false; + } + + if (!config.interest_group_buyers || + config.interest_group_buyers->is_all_buyers()) { + return false; + } + DCHECK(config.interest_group_buyers->is_buyers()); + + // All interest group owners must be HTTPS. + for (const url::Origin& buyer : config.interest_group_buyers->get_buyers()) { + if (buyer.scheme() != url::kHttpsScheme) + return false; + } + + // All buyer signals must be for listed buyers. + if (config.per_buyer_signals) { + for (const auto& it : config.per_buyer_signals.value()) { + if (!base::Contains(config.interest_group_buyers->get_buyers(), + it.first)) { + return false; + } + } + } + + return true; +} + } // namespace AdAuctionServiceImpl::AdAuctionServiceImpl( @@ -113,19 +147,51 @@ void AdAuctionServiceImpl::RunAdAuction(blink::mojom::AuctionAdConfigPtr config, RunAdAuctionCallback callback) { - std::unique_ptr<AdAuction> auction = std::make_unique<AdAuction>( - this, std::move(config), + if (!IsAuctionValid(*config)) { + std::move(callback).Run(absl::nullopt); + return; + } + + const url::Origin& frame_origin = origin(); + BrowserContext* browser_context = render_frame_host()->GetBrowserContext(); + // If the interest group API is not allowed for this seller do nothing. + if (!GetContentClient()->browser()->IsInterestGroupAPIAllowed( + browser_context, frame_origin, config->seller.GetURL())) { + std::move(callback).Run(absl::nullopt); + return; + } + + // Filter out buyers for whom the interest group API is not allowed. + std::vector<url::Origin> filtered_buyers; + const auto& buyers = config->interest_group_buyers->get_buyers(); + std::copy_if( + buyers.begin(), buyers.end(), std::back_inserter(filtered_buyers), + [browser_context, &frame_origin](const url::Origin& buyer) { + return GetContentClient()->browser()->IsInterestGroupAPIAllowed( + browser_context, frame_origin, buyer.GetURL()); + }); + + // If there are no buyers (either due to filtering, or in the original auction + // request), fail the auction. + if (filtered_buyers.empty()) { + std::move(callback).Run(absl::nullopt); + return; + } + + // TODO(mmenke): This should be top frame origin, not frame origin. + auto browser_signals = + auction_worklet::mojom::BrowserSignals::New(frame_origin, config->seller); + + std::unique_ptr<AuctionRunner> auction = AuctionRunner::CreateAndStart( + this, + static_cast<StoragePartitionImpl*>( + render_frame_host()->GetStoragePartition()) + ->GetInterestGroupStorage(), + std::move(config), std::move(filtered_buyers), std::move(browser_signals), + frame_origin, base::BindOnce(&AdAuctionServiceImpl::OnAuctionComplete, base::Unretained(this), std::move(callback))); - AdAuction* auction_ptr = auction.get(); auctions_.insert(std::move(auction)); - auction_ptr->StartAuction(); -} - -InterestGroupManager* AdAuctionServiceImpl::GetInterestGroupManager() { - return static_cast<StoragePartitionImpl*>( - render_frame_host()->GetStoragePartition()) - ->GetInterestGroupStorage(); } network::mojom::URLLoaderFactory* @@ -186,10 +252,13 @@ void AdAuctionServiceImpl::OnAuctionComplete( RunAdAuctionCallback callback, - AdAuction* auction, + AuctionRunner* auction, absl::optional<GURL> render_url, absl::optional<GURL> bidder_report_url, - absl::optional<GURL> seller_report_url) { + absl::optional<GURL> seller_report_url, + std::vector<std::string> errors) { + // Delete the AuctionRunner. Since all arguments are passed by value, they're + // all safe to used after this has been done. auto auction_it = auctions_.find(auction); DCHECK(auction_it != auctions_.end()); auctions_.erase(auction_it); @@ -197,6 +266,12 @@ if (auctions_.empty()) auction_worklet_service_.reset(); + // Forward debug information to devtools. + for (const std::string& error : errors) { + devtools_instrumentation::LogWorkletError( + static_cast<RenderFrameHostImpl*>(render_frame_host()), error); + } + std::move(callback).Run(render_url); if (!render_url) {
diff --git a/content/browser/interest_group/ad_auction_service_impl.h b/content/browser/interest_group/ad_auction_service_impl.h index 0acf619..13bf2fc 100644 --- a/content/browser/interest_group/ad_auction_service_impl.h +++ b/content/browser/interest_group/ad_auction_service_impl.h
@@ -25,7 +25,7 @@ namespace content { -class AdAuction; +class AuctionRunner; class RenderFrameHost; // Implements the AdAuctionService service called by Blink code. @@ -43,8 +43,6 @@ void RunAdAuction(blink::mojom::AuctionAdConfigPtr config, RunAdAuctionCallback callback) override; - InterestGroupManager* GetInterestGroupManager(); - // AuctionRunner::Delegate implementation: network::mojom::URLLoaderFactory* GetFrameURLLoaderFactory() override; network::mojom::URLLoaderFactory* GetTrustedURLLoaderFactory() override; @@ -65,15 +63,16 @@ // Deletes `auction`. void OnAuctionComplete(RunAdAuctionCallback callback, - AdAuction* auction, + AuctionRunner* auction, absl::optional<GURL> render_url, absl::optional<GURL> bidder_report_url, - absl::optional<GURL> seller_report_url); + absl::optional<GURL> seller_report_url, + std::vector<std::string> errors); // This must be above `auction_worklet_service_`, since auctions may own // callbacks over the AuctionWorkletService pipe, and mojo pipes must be // destroyed before any callbacks that are bound to them. - std::set<std::unique_ptr<AdAuction>, base::UniquePtrComparator> auctions_; + std::set<std::unique_ptr<AuctionRunner>, base::UniquePtrComparator> auctions_; mojo::Remote<auction_worklet::mojom::AuctionWorkletService> auction_worklet_service_;
diff --git a/content/browser/interest_group/auction_runner.cc b/content/browser/interest_group/auction_runner.cc index 8955c24..b71daa3 100644 --- a/content/browser/interest_group/auction_runner.cc +++ b/content/browser/interest_group/auction_runner.cc
@@ -13,6 +13,7 @@ #include "base/strings/stringprintf.h" #include "base/time/time.h" #include "content/browser/interest_group/auction_url_loader_factory_proxy.h" +#include "content/browser/interest_group/interest_group_manager.h" #include "content/services/auction_worklet/public/mojom/auction_worklet_service.mojom.h" #include "content/services/auction_worklet/public/mojom/bidder_worklet.mojom.h" #include "content/services/auction_worklet/public/mojom/seller_worklet.mojom.h" @@ -74,34 +75,74 @@ std::unique_ptr<AuctionRunner> AuctionRunner::CreateAndStart( Delegate* delegate, + InterestGroupManager* interest_group_manager, blink::mojom::AuctionAdConfigPtr auction_config, - std::vector<auction_worklet::mojom::BiddingInterestGroupPtr> bidders, + std::vector<url::Origin> filtered_buyers, auction_worklet::mojom::BrowserSignalsPtr browser_signals, const url::Origin& frame_origin, RunAuctionCallback callback) { + DCHECK(!filtered_buyers.empty()); std::unique_ptr<AuctionRunner> instance(new AuctionRunner( - delegate, std::move(auction_config), std::move(bidders), - std::move(browser_signals), frame_origin, std::move(callback))); - instance->StartBidding(); + delegate, interest_group_manager, std::move(auction_config), + std::move(filtered_buyers), std::move(browser_signals), frame_origin, + std::move(callback))); + instance->ReadNextInterestGroup(); return instance; } AuctionRunner::AuctionRunner( Delegate* delegate, + InterestGroupManager* interest_group_manager, blink::mojom::AuctionAdConfigPtr auction_config, - std::vector<auction_worklet::mojom::BiddingInterestGroupPtr> bidders, + std::vector<url::Origin> filtered_buyers, auction_worklet::mojom::BrowserSignalsPtr browser_signals, const url::Origin& frame_origin, RunAuctionCallback callback) : delegate_(delegate), + interest_group_manager_(interest_group_manager), auction_config_(std::move(auction_config)), - bidders_(std::move(bidders)), + pending_buyers_(std::move(filtered_buyers)), browser_signals_(std::move(browser_signals)), frame_origin_(frame_origin), callback_(std::move(callback)) {} AuctionRunner::~AuctionRunner() = default; +void AuctionRunner::ReadNextInterestGroup() { + DCHECK_LT(next_pending_buyer_, pending_buyers_.size()); + + interest_group_manager_->GetInterestGroupsForOwner( + pending_buyers_[next_pending_buyer_], + base::BindOnce(&AuctionRunner::OnInterestGroupRead, + weak_ptr_factory_.GetWeakPtr())); +} + +void AuctionRunner::OnInterestGroupRead( + std::vector<auction_worklet::mojom::BiddingInterestGroupPtr> + interest_groups) { + bidders_.insert(bidders_.end(), + std::make_move_iterator(interest_groups.begin()), + std::make_move_iterator(interest_groups.end())); + next_pending_buyer_++; + + // If more buyers in the queue, load the next one. + if (next_pending_buyer_ < pending_buyers_.size()) { + ReadNextInterestGroup(); + return; + } + + // Pending buyers are no longer needed. + pending_buyers_.clear(); + + // If no interest groups were found, end the auction without a winner. + if (bidders_.empty()) { + FailAuction(); + return; + } + + StartBidding(); +} + void AuctionRunner::StartBidding() { // Auctions are only run when there are bidders participating. As-is, and // empty bidder vector here would result in synchronously calling back into @@ -406,8 +447,8 @@ DCHECK(callback_); ClosePipes(); - std::move(callback_).Run(GURL(), std::string(), url::Origin(), std::string(), - GURL(), GURL(), errors_); + std::move(callback_).Run(this, absl::nullopt, absl::nullopt, absl::nullopt, + errors_); } void AuctionRunner::FailAuctionWithError(std::string error) { @@ -432,11 +473,18 @@ R"({"render_url":"%s"})", state->bid_result->render_url.spec().c_str()); } - std::move(callback_).Run( - state->bid_result->render_url, ad_metadata, state->bidder->group->owner, - state->bidder->group->name, - bidder_report_url_.has_value() ? *bidder_report_url_ : GURL(), - seller_report_url_.has_value() ? *seller_report_url_ : GURL(), errors_); + interest_group_manager_->RecordInterestGroupWin( + state->bidder->group->owner, state->bidder->group->name, ad_metadata); + + // TODO(mmenke): Don't record a bid if the interest group doesn't make a bid. + for (const auto& bidder : bidders_) { + interest_group_manager_->RecordInterestGroupBid(bidder->group->owner, + bidder->group->name); + } + + std::move(callback_).Run(this, state->bid_result->render_url, + std::move(bidder_report_url_), + std::move(seller_report_url_), std::move(errors_)); } void AuctionRunner::ClosePipes() {
diff --git a/content/browser/interest_group/auction_runner.h b/content/browser/interest_group/auction_runner.h index e2fc0db..70ac7e0 100644 --- a/content/browser/interest_group/auction_runner.h +++ b/content/browser/interest_group/auction_runner.h
@@ -27,6 +27,7 @@ namespace content { class AuctionURLLoaderFactoryProxy; +class InterestGroupManager; // An AuctionRunner loads and runs the bidder and seller worklets, along with // their reporting phases and produces the result via a callback. @@ -47,33 +48,23 @@ public: // Invoked when a FLEDGE auction is complete. // - // `render_url` URL of auction winning ad to render. - // An empty URL is used if there is no winner. + // `render_url` URL of auction winning ad to render. Null if there is no + // winner. // - // `ad_metadata` The metadata for the winning ad. - // - // `winning_interest_group_owner` owner of the winning interest group. - // An opaque origin if there is no winner. - // - // `winning_interest_group_name` name of winning interest group. Empty if - // there is no winner. - // - // `bidder_report_url` URL to use for reporting result to the bidder. Empty if + // `bidder_report_url` URL to use for reporting result to the bidder. Null if // no report should be sent. // - // `seller_report` URL to use for reporting result to the seller. Empty if no + // `seller_report` URL to use for reporting result to the seller. Null if no // report should be sent. // // `errors` are various error messages to be used for debugging. These are too // sensitive for the renderers to see. using RunAuctionCallback = - base::OnceCallback<void(const GURL& render_url, - const std::string& ad_metadata, - const url::Origin& winning_interest_group_owner, - const std::string& winning_interest_group_name, - const GURL& bidder_report_url, - const GURL& seller_report_url, - const std::vector<std::string>& errors)>; + base::OnceCallback<void(AuctionRunner* auction_runner, + const absl::optional<GURL> render_url, + const absl::optional<GURL> bidder_report_url, + const absl::optional<GURL> seller_report_url, + std::vector<std::string> errors)>; // Delegate class to allow dependency injection in tests. Note that all // objects this returns can crash and be restarted, so passing in raw pointers @@ -101,17 +92,16 @@ // Runs an entire FLEDGE auction. // // Arguments: - // `delegate` must remain valid until the AuctionRunner is destroyed. + // `delegate` and `interest_group_manager` must remain valid until the + // AuctionRunner is destroyed. // // `auction_config` is the configuration provided by client JavaScript in // the renderer in order to initiate the auction. // - // `bidders` includes definitions of the interest groups that are selected to - // participate in this auction (initially added by client JS in the renderer, - // but managed by the browser's interest group store), as well as some - // bidding history collected by the interest group store. The bidding - // worklets of these groups will be fetched and executed. `bidders` must not - // be empty. + // `filtered_buyers` owners of bidders allowed to participate in this auction. + // These should be a subset of `auction_config`'s `interest_group_buyers`, + // filtered to account for browser configuration (like cookie blocking). Must + // not be empty. // // `browser_signals` signals from the browser about the auction that are the // same for all worklets. @@ -120,8 +110,9 @@ // origin), used as the initiator in network requests. static std::unique_ptr<AuctionRunner> CreateAndStart( Delegate* delegate, + InterestGroupManager* interest_group_manager, blink::mojom::AuctionAdConfigPtr auction_config, - std::vector<auction_worklet::mojom::BiddingInterestGroupPtr> bidders, + std::vector<url::Origin> filtered_buyers, auction_worklet::mojom::BrowserSignalsPtr browser_signals, const url::Origin& frame_origin, RunAuctionCallback callback); @@ -149,15 +140,28 @@ double seller_score = 0; }; - AuctionRunner( - Delegate* delegate, - blink::mojom::AuctionAdConfigPtr auction_config, - std::vector<auction_worklet::mojom::BiddingInterestGroupPtr> bidders, - auction_worklet::mojom::BrowserSignalsPtr browser_signals, - const url::Origin& frame_origin, - RunAuctionCallback callback); + AuctionRunner(Delegate* delegate, + InterestGroupManager* interest_group_manager, + blink::mojom::AuctionAdConfigPtr auction_config, + std::vector<url::Origin> filtered_buyers, + auction_worklet::mojom::BrowserSignalsPtr browser_signals, + const url::Origin& frame_origin, + RunAuctionCallback callback); + // Retrieves the next interest group in `pending_buyers_` from storage. + // OnInterestGroupRead() will be invoked with the lookup results. + void ReadNextInterestGroup(); + + // Adds `interest_groups` to `bidders_`. Continues retrieving bidders from + // `pending_buyers_` if any have not been retrieved yet. Otherwise, invokes + // StartBidding(). + void OnInterestGroupRead( + std::vector<auction_worklet::mojom::BiddingInterestGroupPtr> + interest_groups); + + // Starts loading worklets and generating bids. void StartBidding(); + void OnGenerateBidCrashed(BidState* state); void OnGenerateBidComplete(BidState* state, auction_worklet::mojom::BidderWorkletBidPtr bid, @@ -210,9 +214,15 @@ void ClosePipes(); Delegate* const delegate_; + InterestGroupManager* const interest_group_manager_; // Configuration. blink::mojom::AuctionAdConfigPtr auction_config_; + // Buyers whose interest groups need to be looked up to be added to + // `bidders_`. + std::vector<url::Origin> pending_buyers_; + // Next entry in `pending_buyers_` to fetch the interest group for. + size_t next_pending_buyer_ = 0; std::vector<auction_worklet::mojom::BiddingInterestGroupPtr> bidders_; auction_worklet::mojom::BrowserSignalsPtr browser_signals_; const url::Origin frame_origin_;
diff --git a/content/browser/interest_group/auction_runner_unittest.cc b/content/browser/interest_group/auction_runner_unittest.cc index fa519bb..98fd069 100644 --- a/content/browser/interest_group/auction_runner_unittest.cc +++ b/content/browser/interest_group/auction_runner_unittest.cc
@@ -8,11 +8,13 @@ #include <vector> #include "base/callback_helpers.h" +#include "base/files/file_path.h" #include "base/run_loop.h" #include "base/strings/stringprintf.h" #include "base/test/bind.h" #include "base/test/task_environment.h" #include "base/time/time.h" +#include "content/browser/interest_group/interest_group_manager.h" #include "content/services/auction_worklet/auction_worklet_service_impl.h" #include "content/services/auction_worklet/public/mojom/auction_worklet_service.mojom.h" #include "content/services/auction_worklet/public/mojom/bidder_worklet.mojom.h" @@ -210,6 +212,16 @@ return std::string(kAuctionScriptRejects2) + kReportResultScript; } +// Sorts a vector of PreviousWinPtr so that the most recent wins are last. +void SortPrevWins( + std::vector<auction_worklet::mojom::PreviousWinPtr>& prev_wins) { + std::sort(prev_wins.begin(), prev_wins.end(), + [](const auction_worklet::mojom::PreviousWinPtr& prev_win1, + const auction_worklet::mojom::PreviousWinPtr& prev_win2) { + return prev_win1->time < prev_win2->time; + }); +} + // BidderWorklet that holds onto passed in callbacks, to let the test fixture // invoke them. class MockBidderWorklet : public auction_worklet::mojom::BidderWorklet { @@ -558,17 +570,29 @@ protected: // Output of the RunAuctionCallback passed to AuctionRunner::CreateAndStart(). struct Result { - GURL ad_url; - std::string ad_metadata; - url::Origin interest_group_owner; - std::string interest_group_name; - GURL bidder_report_url; - GURL seller_report_url; + Result() = default; + // Can't use default copy logic, since it contains Mojo types. + Result(const Result&) = delete; + Result& operator=(const Result&) = delete; + + absl::optional<GURL> ad_url; + absl::optional<GURL> bidder_report_url; + absl::optional<GURL> seller_report_url; std::vector<std::string> errors; + + // Metadata about `bidder1` and `bidder2`, pulled from the + // InterestGroupManager on auction complete. Used to make sure number of + // bids and win list are updated on auction complete. Previous wins arrays + // are guaranteed to be sorted in chronological order. + int bidder1_bid_count; + std::vector<auction_worklet::mojom::PreviousWinPtr> bidder1_prev_wins; + int bidder2_bid_count; + std::vector<auction_worklet::mojom::PreviousWinPtr> bidder2_prev_wins; }; AuctionRunnerTest() - : auction_worklet_service_( + : task_environment_(base::test::TaskEnvironment::TimeSource::MOCK_TIME), + auction_worklet_service_( auction_worklet_service_remote_.BindNewPipeAndPassReceiver()) { mojo::SetDefaultProcessErrorHandler(base::BindRepeating( &AuctionRunnerTest::OnBadMessage, base::Unretained(this))); @@ -597,6 +621,12 @@ // Starts an auction without waiting for it to complete. Useful when using // MockAuctionWorkletService. + // + // `bidders` are added to a new InterestGroupManager before running the + // auction. The times of their previous wins are ignored, as the + // InterestGroupManager automatically attaches the current time, though their + // wins will be added in order, with chronologically increasing times within + // each InterestGroup. void StartAuction( const GURL& seller_decision_logic_url, std::vector<auction_worklet::mojom::BiddingInterestGroupPtr> bidders, @@ -608,6 +638,8 @@ blink::mojom::AuctionAdConfig::New(); auction_config->seller = url::Origin::Create(seller_decision_logic_url); auction_config->decision_logic_url = seller_decision_logic_url; + // This is ignored by AuctionRunner, in favor of its `filtered_buyers` + // parameter. auction_config->interest_group_buyers = blink::mojom::InterestGroupBuyers::NewAllBuyers( blink::mojom::AllBuyers::New()); @@ -619,16 +651,38 @@ per_buyer_signals[kBidder2] = R"({"signalsFor": ")" + kBidder2Name + "\"}"; auction_config->per_buyer_signals = std::move(per_buyer_signals); + interest_group_manager_ = std::make_unique<InterestGroupManager>( + base::FilePath(), true /* in_memory */); + + // Add previous wins and bids to the interest group manager. + for (auto& bidder : bidders) { + for (int i = 0; i < bidder->signals->join_count; i++) { + interest_group_manager_->JoinInterestGroup(bidder->group.Clone()); + } + for (int i = 0; i < bidder->signals->bid_count; i++) { + interest_group_manager_->RecordInterestGroupBid(bidder->group->owner, + bidder->group->name); + } + for (const auto& prev_win : bidder->signals->prev_wins) { + interest_group_manager_->RecordInterestGroupWin( + bidder->group->owner, bidder->group->name, prev_win->ad_json); + // Add some time between interest group wins, so that they'll be added + // to the database in the order they appear. Their times will *not* + // match those in `prev_wins`. + task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(1)); + } + } + auction_run_loop_ = std::make_unique<base::RunLoop>(); - Result result; auction_runner_ = AuctionRunner::CreateAndStart( - this, std::move(auction_config), std::move(bidders), + this, interest_group_manager_.get(), std::move(auction_config), + std::vector<url::Origin>{kBidder1, kBidder2}, std::move(browser_signals), frame_origin_, base::BindOnce(&AuctionRunnerTest::OnAuctionComplete, base::Unretained(this))); } - Result RunAuctionAndWait( + const Result& RunAuctionAndWait( const GURL& seller_decision_logic_url, std::vector<auction_worklet::mojom::BiddingInterestGroupPtr> bidders, const std::string& auction_signals_json, @@ -639,21 +693,60 @@ return result_; } - void OnAuctionComplete(const GURL& ad_url, - const std::string& ad_metadata, - const url::Origin& interest_group_owner, - const std::string& interest_group_name, - const GURL& bidder_report_url, - const GURL& seller_report_url, - const std::vector<std::string>& errors) { + void OnAuctionComplete(AuctionRunner* auction_runner, + absl::optional<GURL> ad_url, + absl::optional<GURL> bidder_report_url, + absl::optional<GURL> seller_report_url, + std::vector<std::string> errors) { + DCHECK(auction_run_loop_); + DCHECK(!auction_complete_); + auction_complete_ = true; - result_.ad_url = ad_url; - result_.ad_metadata = ad_metadata; - result_.interest_group_owner = interest_group_owner; - result_.interest_group_name = interest_group_name; - result_.bidder_report_url = bidder_report_url; - result_.seller_report_url = seller_report_url; - result_.errors = errors; + result_.ad_url = std::move(ad_url); + result_.bidder_report_url = std::move(bidder_report_url); + result_.seller_report_url = std::move(seller_report_url); + result_.errors = std::move(errors); + result_.bidder1_bid_count = -1; + result_.bidder1_prev_wins.clear(); + result_.bidder2_bid_count = -1; + result_.bidder2_prev_wins.clear(); + + // Retrieve bid count and previous wins for kBidder1 (and subsequently + // kBidder2). + interest_group_manager_->GetInterestGroupsForOwner( + kBidder1, base::BindOnce(&AuctionRunnerTest::OnBidder1GroupsRetrieved, + base::Unretained(this))); + } + + void OnBidder1GroupsRetrieved( + std::vector<auction_worklet::mojom::BiddingInterestGroupPtr> + bidding_interest_groups) { + for (auto& bidder : bidding_interest_groups) { + if (bidder->group->owner == kBidder1 && + bidder->group->name == kBidder1Name) { + result_.bidder1_bid_count = bidder->signals->bid_count; + result_.bidder1_prev_wins = std::move(bidder->signals->prev_wins); + SortPrevWins(result_.bidder1_prev_wins); + break; + } + } + interest_group_manager_->GetInterestGroupsForOwner( + kBidder2, base::BindOnce(&AuctionRunnerTest::OnBidder2GroupsRetrieved, + base::Unretained(this))); + } + + void OnBidder2GroupsRetrieved( + std::vector<auction_worklet::mojom::BiddingInterestGroupPtr> + bidding_interest_groups) { + for (auto& bidder : bidding_interest_groups) { + if (bidder->group->owner == kBidder2 && + bidder->group->name == kBidder2Name) { + result_.bidder2_bid_count = bidder->signals->bid_count; + result_.bidder2_prev_wins = std::move(bidder->signals->prev_wins); + SortPrevWins(result_.bidder2_prev_wins); + break; + } + } auction_run_loop_->Quit(); } @@ -674,13 +767,13 @@ ads.push_back(blink::mojom::InterestGroupAd::New(ad_url, absl::nullopt)); } + // Create fake previous wins. The time of these wins is ignored, since the + // InterestGroupManager attaches the current time when logging a win. std::vector<auction_worklet::mojom::PreviousWinPtr> previous_wins; previous_wins.push_back(auction_worklet::mojom::PreviousWin::New( - base::Time::Now() - base::TimeDelta::FromSeconds(2), - R"({"winner": 0})")); + base::Time::Now(), R"({"winner": 0})")); previous_wins.push_back(auction_worklet::mojom::PreviousWin::New( - base::Time::Now() - base::TimeDelta::FromSeconds(1), - R"({"winner": -1})")); + base::Time::Now(), R"({"winner": -1})")); previous_wins.push_back(auction_worklet::mojom::PreviousWin::New( base::Time::Now(), R"({"winner": -2})")); @@ -709,7 +802,7 @@ url::Origin::Create(kSellerUrl))); } - Result RunStandardAuction() { + const Result& RunStandardAuction() { StartStandardAuction(); auction_run_loop_->Run(); return result_; @@ -718,7 +811,7 @@ // Starts the standard auction with the mock worklet service, and waits for // the service to receive the worklet construction calls. void StartStandardAuctionWithMockService() { - use_mock_service_ = true; + UseMockWorkletService(); StartStandardAuction(); mock_worklet_service_->WaitForWorklets(2 /* num_bidders */); } @@ -731,35 +824,35 @@ return &url_loader_factory_; } auction_worklet::mojom::AuctionWorkletService* GetWorkletService() override { - if (use_mock_service_) { - if (!mock_worklet_service_) { - mock_worklet_service_remote_.reset(); - mock_worklet_service_ = std::make_unique<MockAuctionWorkletService>( - mock_worklet_service_remote_.BindNewPipeAndPassReceiver()); - } + if (mock_worklet_service_) { + DCHECK(mock_worklet_service_remote_.is_connected()); return mock_worklet_service_remote_.get(); } return auction_worklet_service_remote_.get(); } + // Enables use of a mock worklet service, destroying any previously used mock + // worklet service. + void UseMockWorkletService() { + mock_worklet_service_remote_.reset(); + mock_worklet_service_ = std::make_unique<MockAuctionWorkletService>( + mock_worklet_service_remote_.BindNewPipeAndPassReceiver()); + } + const url::Origin frame_origin_ = url::Origin::Create(GURL("https://frame.origin.test")); const GURL kSellerUrl{"https://adstuff.publisher1.com/auction.js"}; const GURL kBidder1Url{"https://adplatform.com/offers.js"}; - const url::Origin kBidder1 = - url::Origin::Create(GURL("https://adplatform.com")); + const url::Origin kBidder1 = url::Origin::Create(kBidder1Url); const std::string kBidder1Name{"Ad Platform"}; const GURL kBidder2Url{"https://anotheradthing.com/bids.js"}; - const url::Origin kBidder2 = - url::Origin::Create(GURL("https://anotheradthing.com")); + const url::Origin kBidder2 = url::Origin::Create(kBidder2Url); const std::string kBidder2Name{"Another Ad Thing"}; const GURL kTrustedSignalsUrl{"https://trustedsignaller.org/signals"}; base::test::TaskEnvironment task_environment_; - bool use_mock_service_ = false; - // RunLoop that's quit on auction completion. std::unique_ptr<base::RunLoop> auction_run_loop_; // True if the most recently started auction has completed. @@ -770,17 +863,80 @@ network::TestURLLoaderFactory url_loader_factory_; mojo::Remote<auction_worklet::mojom::AuctionWorkletService> mock_worklet_service_remote_; + // Mock service is used in favor of `auction_worklet_service_`, if non-null. std::unique_ptr<MockAuctionWorkletService> mock_worklet_service_; mojo::Remote<auction_worklet::mojom::AuctionWorkletService> auction_worklet_service_remote_; auction_worklet::AuctionWorkletServiceImpl auction_worklet_service_; + // The InterestGroupManager is recreated and repopulated for each auction. + std::unique_ptr<InterestGroupManager> interest_group_manager_; + std::unique_ptr<AuctionRunner> auction_runner_; // This should be inspected using TakeBadMessage(), which also clears it. std::string bad_message_; }; +// Runs the standard auction, but without adding any interest groups to the +// manager. +TEST_F(AuctionRunnerTest, NoInterestGroups) { + RunAuctionAndWait( + kSellerUrl, + std::vector<auction_worklet::mojom::BiddingInterestGroupPtr>(), + R"({"isAuctionSignals": true})" /* auction_signals_json */, + auction_worklet::mojom::BrowserSignals::New( + url::Origin::Create(GURL("https://publisher1.com")), + url::Origin::Create(kSellerUrl))); + + EXPECT_FALSE(result_.ad_url); + EXPECT_FALSE(result_.seller_report_url); + EXPECT_FALSE(result_.bidder_report_url); + EXPECT_EQ(-1, result_.bidder1_bid_count); + EXPECT_EQ(0u, result_.bidder1_prev_wins.size()); + EXPECT_EQ(-1, result_.bidder2_bid_count); + EXPECT_EQ(0u, result_.bidder2_prev_wins.size()); + EXPECT_THAT(result_.errors, testing::ElementsAre()); +} + +// Runs the standard auction, but with only adding one of the two standard +// interest groups to the manager. +TEST_F(AuctionRunnerTest, OneInterestGroup) { + auction_worklet::AddJavascriptResponse( + &url_loader_factory_, kBidder1Url, + MakeBidScript("1", "https://ad1.com/", kBidder1, kBidder1Name, + true /* has_signals */, "k1", "a")); + auction_worklet::AddJavascriptResponse(&url_loader_factory_, kSellerUrl, + MakeAuctionScript()); + auction_worklet::AddJsonResponse( + &url_loader_factory_, + GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=k1,k2"), + R"({"k1":"a", "k2": "b", "extra": "c"})"); + + std::vector<auction_worklet::mojom::BiddingInterestGroupPtr> bidders; + bidders.push_back(MakeInterestGroup(kBidder1, kBidder1Name, kBidder1Url, + kTrustedSignalsUrl, {"k1", "k2"}, + GURL("https://ad1.com"))); + + RunAuctionAndWait(kSellerUrl, std::move(bidders), + R"({"isAuctionSignals": true})" /* auction_signals_json */, + auction_worklet::mojom::BrowserSignals::New( + url::Origin::Create(GURL("https://publisher1.com")), + url::Origin::Create(kSellerUrl))); + + EXPECT_EQ(GURL("https://ad1.com/"), result_.ad_url); + EXPECT_EQ(GURL("https://reporting.example.com/"), result_.seller_report_url); + EXPECT_EQ(GURL("https://buyer-reporting.example.com/"), + result_.bidder_report_url); + EXPECT_EQ(6, result_.bidder1_bid_count); + ASSERT_EQ(4u, result_.bidder1_prev_wins.size()); + EXPECT_EQ(R"({"render_url":"https://ad1.com/","metadata":{"ads": true}})", + result_.bidder1_prev_wins[3]->ad_json); + EXPECT_EQ(-1, result_.bidder2_bid_count); + EXPECT_EQ(0u, result_.bidder2_prev_wins.size()); + EXPECT_THAT(result_.errors, testing::ElementsAre()); +} + // An auction with two successful bids. TEST_F(AuctionRunnerTest, Basic) { auction_worklet::AddJavascriptResponse( @@ -802,14 +958,17 @@ GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=l1,l2"), R"({"l1":"a", "l2": "b", "extra": "c"})"); - Result res = RunStandardAuction(); - EXPECT_EQ("https://ad2.com/", res.ad_url.spec()); - EXPECT_EQ(R"({"render_url":"https://ad2.com/"})", res.ad_metadata); - EXPECT_EQ("https://anotheradthing.com", res.interest_group_owner.Serialize()); - EXPECT_EQ("Another Ad Thing", res.interest_group_name); - EXPECT_EQ("https://reporting.example.com/", res.seller_report_url.spec()); - EXPECT_EQ("https://buyer-reporting.example.com/", - res.bidder_report_url.spec()); + const Result& res = RunStandardAuction(); + EXPECT_EQ(GURL("https://ad2.com/"), res.ad_url); + EXPECT_EQ(GURL("https://reporting.example.com/"), res.seller_report_url); + EXPECT_EQ(GURL("https://buyer-reporting.example.com/"), + res.bidder_report_url); + EXPECT_EQ(6, res.bidder1_bid_count); + EXPECT_EQ(3u, res.bidder1_prev_wins.size()); + EXPECT_EQ(6, res.bidder2_bid_count); + ASSERT_EQ(4u, res.bidder2_prev_wins.size()); + EXPECT_EQ(R"({"render_url":"https://ad2.com/"})", + res.bidder2_prev_wins[3]->ad_json); EXPECT_THAT(res.errors, testing::ElementsAre()); } @@ -831,15 +990,17 @@ GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=l1,l2"), R"({"l1":"a", "l2": "b", "extra": "c"})"); - Result res = RunStandardAuction(); - EXPECT_EQ("https://ad1.com/", res.ad_url.spec()); + const Result& res = RunStandardAuction(); + EXPECT_EQ(GURL("https://ad1.com/"), res.ad_url); + EXPECT_EQ(GURL("https://reporting.example.com/"), res.seller_report_url); + EXPECT_EQ(GURL("https://buyer-reporting.example.com/"), + res.bidder_report_url); + EXPECT_EQ(6, res.bidder1_bid_count); + ASSERT_EQ(4u, res.bidder1_prev_wins.size()); EXPECT_EQ(R"({"render_url":"https://ad1.com/","metadata":{"ads": true}})", - res.ad_metadata); - EXPECT_EQ("https://adplatform.com", res.interest_group_owner.Serialize()); - EXPECT_EQ("Ad Platform", res.interest_group_name); - EXPECT_EQ("https://reporting.example.com/", res.seller_report_url.spec()); - EXPECT_EQ("https://buyer-reporting.example.com/", - res.bidder_report_url.spec()); + res.bidder1_prev_wins[3]->ad_json); + EXPECT_EQ(6, res.bidder2_bid_count); + EXPECT_EQ(3u, res.bidder2_prev_wins.size()); EXPECT_THAT( res.errors, testing::ElementsAre("Failed to load https://anotheradthing.com/bids.js " @@ -868,15 +1029,17 @@ GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=l1,l2"), R"({"l1":"a", "l2": "b", "extra": "c"})"); - Result res = RunStandardAuction(); - EXPECT_EQ("https://ad1.com/", res.ad_url.spec()); + const Result& res = RunStandardAuction(); + EXPECT_EQ(GURL("https://ad1.com/"), res.ad_url); + EXPECT_EQ(GURL("https://reporting.example.com/"), res.seller_report_url); + EXPECT_EQ(GURL("https://buyer-reporting.example.com/"), + res.bidder_report_url); + EXPECT_EQ(6, res.bidder1_bid_count); + ASSERT_EQ(4u, res.bidder1_prev_wins.size()); EXPECT_EQ(R"({"render_url":"https://ad1.com/","metadata":{"ads": true}})", - res.ad_metadata); - EXPECT_EQ("https://adplatform.com", res.interest_group_owner.Serialize()); - EXPECT_EQ("Ad Platform", res.interest_group_name); - EXPECT_EQ("https://reporting.example.com/", res.seller_report_url.spec()); - EXPECT_EQ("https://buyer-reporting.example.com/", - res.bidder_report_url.spec()); + res.bidder1_prev_wins[3]->ad_json); + EXPECT_EQ(6, res.bidder2_bid_count); + EXPECT_EQ(3u, res.bidder2_prev_wins.size()); EXPECT_THAT(res.errors, testing::ElementsAre("https://anotheradthing.com/bids.js " "`generateBid` is not a function.")); @@ -897,19 +1060,20 @@ GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=l1,l2"), R"({"l1":"a", "l2": "b", "extra":"c"})"); - Result res = RunStandardAuction(); - EXPECT_TRUE(res.ad_url.is_empty()); - EXPECT_TRUE(res.ad_metadata.empty()); - EXPECT_TRUE(res.interest_group_owner.opaque()); - EXPECT_EQ("", res.interest_group_name); - EXPECT_TRUE(res.seller_report_url.is_empty()); - EXPECT_TRUE(res.bidder_report_url.is_empty()); - EXPECT_THAT( - res.errors, - testing::ElementsAre("Failed to load https://adplatform.com/offers.js " - "HTTP status = 404 Not Found.", - "Failed to load https://anotheradthing.com/bids.js " - "HTTP status = 404 Not Found.")); + const Result& res = RunStandardAuction(); + EXPECT_FALSE(res.ad_url); + EXPECT_FALSE(res.seller_report_url); + EXPECT_FALSE(res.bidder_report_url); + EXPECT_EQ(5, res.bidder1_bid_count); + EXPECT_EQ(3u, res.bidder1_prev_wins.size()); + EXPECT_EQ(5, res.bidder2_bid_count); + EXPECT_EQ(3u, res.bidder2_prev_wins.size()); + EXPECT_THAT(res.errors, + testing::UnorderedElementsAre( + "Failed to load https://adplatform.com/offers.js " + "HTTP status = 404 Not Found.", + "Failed to load https://anotheradthing.com/bids.js " + "HTTP status = 404 Not Found.")); } // An auction where none of the bidding scripts has a valid bidding function. @@ -930,16 +1094,17 @@ GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=l1,l2"), R"({"l1":"a", "l2": "b", "extra":"c"})"); - Result res = RunStandardAuction(); - EXPECT_TRUE(res.ad_url.is_empty()); - EXPECT_TRUE(res.ad_metadata.empty()); - EXPECT_TRUE(res.interest_group_owner.opaque()); - EXPECT_EQ("", res.interest_group_name); - EXPECT_TRUE(res.seller_report_url.is_empty()); - EXPECT_TRUE(res.bidder_report_url.is_empty()); + const Result& res = RunStandardAuction(); + EXPECT_FALSE(res.ad_url); + EXPECT_FALSE(res.seller_report_url); + EXPECT_FALSE(res.bidder_report_url); + EXPECT_EQ(5, res.bidder1_bid_count); + EXPECT_EQ(3u, res.bidder1_prev_wins.size()); + EXPECT_EQ(5, res.bidder2_bid_count); + EXPECT_EQ(3u, res.bidder2_prev_wins.size()); EXPECT_THAT( res.errors, - testing::ElementsAre( + testing::UnorderedElementsAre( "https://adplatform.com/offers.js `generateBid` is not a function.", "https://anotheradthing.com/bids.js `generateBid` is not a " "function.")); @@ -969,18 +1134,19 @@ GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=l1,l2"), R"({"l1":"a", "l2": "b", "extra":"c"})"); - Result res = RunStandardAuction(); - EXPECT_TRUE(res.ad_url.is_empty()); - EXPECT_TRUE(res.ad_metadata.empty()); - EXPECT_TRUE(res.interest_group_owner.opaque()); - EXPECT_EQ("", res.interest_group_name); - EXPECT_TRUE(res.seller_report_url.is_empty()); - EXPECT_TRUE(res.bidder_report_url.is_empty()); - EXPECT_THAT(res.errors, - testing::ElementsAre("https://adstuff.publisher1.com/auction.js " - "`scoreAd` is not a function.", - "https://adstuff.publisher1.com/auction.js " - "`scoreAd` is not a function.")); + const Result& res = RunStandardAuction(); + EXPECT_FALSE(res.ad_url); + EXPECT_FALSE(res.seller_report_url); + EXPECT_FALSE(res.bidder_report_url); + EXPECT_EQ(5, res.bidder1_bid_count); + EXPECT_EQ(3u, res.bidder1_prev_wins.size()); + EXPECT_EQ(5, res.bidder2_bid_count); + EXPECT_EQ(3u, res.bidder2_prev_wins.size()); + EXPECT_THAT(res.errors, testing::UnorderedElementsAre( + "https://adstuff.publisher1.com/auction.js " + "`scoreAd` is not a function.", + "https://adstuff.publisher1.com/auction.js " + "`scoreAd` is not a function.")); } // An auction where seller rejects one bid when scoring. @@ -1004,15 +1170,18 @@ GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=l1,l2"), R"({"l1":"a", "l2": "b", "extra": "c"})"); - Result res = RunStandardAuction(); - EXPECT_EQ("https://ad1.com/", res.ad_url.spec()); + const Result& res = RunStandardAuction(); + EXPECT_EQ(GURL("https://ad1.com/"), res.ad_url); + EXPECT_EQ(GURL("https://reporting.example.com/"), res.seller_report_url); + EXPECT_EQ(GURL("https://buyer-reporting.example.com/"), + res.bidder_report_url); + EXPECT_EQ(6, res.bidder1_bid_count); + ASSERT_EQ(4u, res.bidder1_prev_wins.size()); EXPECT_EQ(R"({"render_url":"https://ad1.com/","metadata":{"ads": true}})", - res.ad_metadata); - EXPECT_EQ("https://adplatform.com", res.interest_group_owner.Serialize()); - EXPECT_EQ("Ad Platform", res.interest_group_name); - EXPECT_EQ("https://reporting.example.com/", res.seller_report_url.spec()); - EXPECT_EQ("https://buyer-reporting.example.com/", - res.bidder_report_url.spec()); + res.bidder1_prev_wins[3]->ad_json); + EXPECT_EQ(6, res.bidder2_bid_count); + EXPECT_EQ(3u, res.bidder2_prev_wins.size()); + EXPECT_THAT(res.errors, testing::ElementsAre()); } // An auction where the seller script fails to load. @@ -1020,22 +1189,23 @@ // Tests to make sure that if seller script fails the other fetches are // cancelled, too. url_loader_factory_.AddResponse(kSellerUrl.spec(), "", net::HTTP_NOT_FOUND); - Result res = RunStandardAuction(); - EXPECT_TRUE(res.ad_url.is_empty()); - EXPECT_TRUE(res.ad_metadata.empty()); - EXPECT_TRUE(res.interest_group_owner.opaque()); - EXPECT_EQ("", res.interest_group_name); - EXPECT_TRUE(res.seller_report_url.is_empty()); - EXPECT_TRUE(res.bidder_report_url.is_empty()); + const Result& res = RunStandardAuction(); + EXPECT_FALSE(res.ad_url); + EXPECT_FALSE(res.seller_report_url); + EXPECT_FALSE(res.bidder_report_url); EXPECT_EQ(0, url_loader_factory_.NumPending()); + EXPECT_EQ(5, res.bidder1_bid_count); + EXPECT_EQ(3u, res.bidder1_prev_wins.size()); + EXPECT_EQ(5, res.bidder2_bid_count); + EXPECT_EQ(3u, res.bidder2_prev_wins.size()); EXPECT_THAT(res.errors, testing::ElementsAre( "Failed to load https://adstuff.publisher1.com/auction.js " "HTTP status = 404 Not Found.")); } -// An auction where bidders don't requested trusted bidding signals. +// An auction where bidders don't request trusted bidding signals. TEST_F(AuctionRunnerTest, NoTrustedBiddingSignals) { auction_worklet::AddJavascriptResponse( &url_loader_factory_, kBidder1Url, @@ -1056,20 +1226,23 @@ absl::nullopt, {"l1", "l2"}, GURL("https://ad2.com"))); - Result res = RunAuctionAndWait( + const Result& res = RunAuctionAndWait( kSellerUrl, std::move(bidders), R"({"isAuctionSignals": true})", /* auction_signals_json */ auction_worklet::mojom::BrowserSignals::New( url::Origin::Create(GURL("https://publisher1.com")), url::Origin::Create(kSellerUrl))); - EXPECT_EQ("https://ad2.com/", res.ad_url.spec()); - EXPECT_EQ(R"({"render_url":"https://ad2.com/"})", res.ad_metadata); - EXPECT_EQ("https://anotheradthing.com", res.interest_group_owner.Serialize()); - EXPECT_EQ("Another Ad Thing", res.interest_group_name); - EXPECT_EQ("https://reporting.example.com/", res.seller_report_url.spec()); - EXPECT_EQ("https://buyer-reporting.example.com/", - res.bidder_report_url.spec()); + EXPECT_EQ(GURL("https://ad2.com/"), res.ad_url); + EXPECT_EQ(GURL("https://reporting.example.com/"), res.seller_report_url); + EXPECT_EQ(GURL("https://buyer-reporting.example.com/"), + res.bidder_report_url); + EXPECT_EQ(6, res.bidder1_bid_count); + EXPECT_EQ(3u, res.bidder1_prev_wins.size()); + EXPECT_EQ(6, res.bidder2_bid_count); + ASSERT_EQ(4u, res.bidder2_prev_wins.size()); + EXPECT_EQ(R"({"render_url":"https://ad2.com/"})", + res.bidder2_prev_wins[3]->ad_json); EXPECT_THAT(res.errors, testing::ElementsAre()); } @@ -1092,23 +1265,26 @@ auction_worklet::AddJavascriptResponse(&url_loader_factory_, kSellerUrl, MakeAuctionScript()); - Result res = RunStandardAuction(); - EXPECT_EQ("https://ad2.com/", res.ad_url.spec()); - EXPECT_EQ(R"({"render_url":"https://ad2.com/"})", res.ad_metadata); - EXPECT_EQ("https://anotheradthing.com", res.interest_group_owner.Serialize()); - EXPECT_EQ("Another Ad Thing", res.interest_group_name); - EXPECT_EQ("https://reporting.example.com/", res.seller_report_url.spec()); - EXPECT_EQ("https://buyer-reporting.example.com/", - res.bidder_report_url.spec()); - EXPECT_THAT(res.errors, - testing::ElementsAre("Failed to load " - "https://trustedsignaller.org/" - "signals?hostname=publisher1.com&keys=k1,k2 " - "HTTP status = 404 Not Found.", - "Failed to load " - "https://trustedsignaller.org/" - "signals?hostname=publisher1.com&keys=l1,l2 " - "HTTP status = 404 Not Found.")); + const Result& res = RunStandardAuction(); + EXPECT_EQ(GURL("https://ad2.com/"), res.ad_url); + EXPECT_EQ(GURL("https://reporting.example.com/"), res.seller_report_url); + EXPECT_EQ(GURL("https://buyer-reporting.example.com/"), + res.bidder_report_url); + EXPECT_EQ(6, res.bidder1_bid_count); + EXPECT_EQ(3u, res.bidder1_prev_wins.size()); + EXPECT_EQ(6, res.bidder2_bid_count); + ASSERT_EQ(4u, res.bidder2_prev_wins.size()); + EXPECT_EQ(R"({"render_url":"https://ad2.com/"})", + res.bidder2_prev_wins[3]->ad_json); + EXPECT_THAT(res.errors, testing::UnorderedElementsAre( + "Failed to load " + "https://trustedsignaller.org/" + "signals?hostname=publisher1.com&keys=k1,k2 " + "HTTP status = 404 Not Found.", + "Failed to load " + "https://trustedsignaller.org/" + "signals?hostname=publisher1.com&keys=l1,l2 " + "HTTP status = 404 Not Found.")); } // A successful auction where seller reporting worklet doesn't set a URL. @@ -1132,14 +1308,17 @@ GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=l1,l2"), R"({"l1":"a", "l2": "b", "extra": "c"})"); - Result res = RunStandardAuction(); - EXPECT_EQ("https://ad2.com/", res.ad_url.spec()); - EXPECT_EQ(R"({"render_url":"https://ad2.com/"})", res.ad_metadata); - EXPECT_EQ("https://anotheradthing.com", res.interest_group_owner.Serialize()); - EXPECT_EQ("Another Ad Thing", res.interest_group_name); - EXPECT_TRUE(res.seller_report_url.is_empty()); - EXPECT_EQ("https://buyer-reporting.example.com/", - res.bidder_report_url.spec()); + const Result& res = RunStandardAuction(); + EXPECT_EQ(GURL("https://ad2.com/"), res.ad_url); + EXPECT_FALSE(res.seller_report_url); + EXPECT_EQ(GURL("https://buyer-reporting.example.com/"), + res.bidder_report_url); + EXPECT_EQ(6, res.bidder1_bid_count); + EXPECT_EQ(3u, res.bidder1_prev_wins.size()); + EXPECT_EQ(6, res.bidder2_bid_count); + ASSERT_EQ(4u, res.bidder2_prev_wins.size()); + EXPECT_EQ(R"({"render_url":"https://ad2.com/"})", + res.bidder2_prev_wins[3]->ad_json); EXPECT_THAT(res.errors, testing::ElementsAre()); } @@ -1166,13 +1345,16 @@ GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=l1,l2"), R"({"l1":"a", "l2": "b", "extra": "c"})"); - Result res = RunStandardAuction(); - EXPECT_EQ("https://ad2.com/", res.ad_url.spec()); - EXPECT_EQ(R"({"render_url":"https://ad2.com/"})", res.ad_metadata); - EXPECT_EQ("https://anotheradthing.com", res.interest_group_owner.Serialize()); - EXPECT_EQ("Another Ad Thing", res.interest_group_name); - EXPECT_EQ("https://reporting.example.com/", res.seller_report_url.spec()); - EXPECT_TRUE(res.bidder_report_url.is_empty()); + const Result& res = RunStandardAuction(); + EXPECT_EQ(GURL("https://ad2.com/"), res.ad_url); + EXPECT_EQ(GURL("https://reporting.example.com/"), res.seller_report_url); + EXPECT_FALSE(res.bidder_report_url); + EXPECT_EQ(6, res.bidder1_bid_count); + EXPECT_EQ(3u, res.bidder1_prev_wins.size()); + EXPECT_EQ(6, res.bidder2_bid_count); + ASSERT_EQ(4u, res.bidder2_prev_wins.size()); + EXPECT_EQ(R"({"render_url":"https://ad2.com/"})", + res.bidder2_prev_wins[3]->ad_json); EXPECT_THAT(res.errors, testing::ElementsAre()); } @@ -1199,13 +1381,16 @@ GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=l1,l2"), R"({"l1":"a", "l2": "b", "extra": "c"})"); - Result res = RunStandardAuction(); - EXPECT_EQ("https://ad2.com/", res.ad_url.spec()); - EXPECT_EQ(R"({"render_url":"https://ad2.com/"})", res.ad_metadata); - EXPECT_EQ("https://anotheradthing.com", res.interest_group_owner.Serialize()); - EXPECT_EQ("Another Ad Thing", res.interest_group_name); - EXPECT_TRUE(res.seller_report_url.is_empty()); - EXPECT_TRUE(res.bidder_report_url.is_empty()); + const Result& res = RunStandardAuction(); + EXPECT_EQ(GURL("https://ad2.com/"), res.ad_url); + EXPECT_FALSE(res.seller_report_url); + EXPECT_FALSE(res.bidder_report_url); + EXPECT_EQ(6, res.bidder1_bid_count); + EXPECT_EQ(3u, res.bidder1_prev_wins.size()); + EXPECT_EQ(6, res.bidder2_bid_count); + ASSERT_EQ(4u, res.bidder2_prev_wins.size()); + EXPECT_EQ(R"({"render_url":"https://ad2.com/"})", + res.bidder2_prev_wins[3]->ad_json); EXPECT_THAT(res.errors, testing::ElementsAre()); } @@ -1246,13 +1431,13 @@ auction_run_loop_->Run(); - EXPECT_FALSE(result_.ad_url.is_valid()); - EXPECT_TRUE(result_.ad_metadata.empty()); - EXPECT_TRUE(result_.ad_url.is_empty()); - EXPECT_TRUE(result_.interest_group_owner.opaque()); - EXPECT_EQ("", result_.interest_group_name); - EXPECT_TRUE(result_.seller_report_url.is_empty()); - EXPECT_TRUE(result_.bidder_report_url.is_empty()); + EXPECT_FALSE(result_.ad_url); + EXPECT_FALSE(result_.seller_report_url); + EXPECT_FALSE(result_.bidder_report_url); + EXPECT_EQ(5, result_.bidder1_bid_count); + EXPECT_EQ(3u, result_.bidder1_prev_wins.size()); + EXPECT_EQ(5, result_.bidder2_bid_count); + EXPECT_EQ(3u, result_.bidder2_prev_wins.size()); EXPECT_THAT( result_.errors, testing::UnorderedElementsAre( @@ -1324,11 +1509,14 @@ // Bidder2 won, Bidder1 crashed. auction_run_loop_->Run(); EXPECT_EQ(GURL("https://ad2.com/"), result_.ad_url); - EXPECT_EQ(R"({"render_url":"https://ad2.com/"})", result_.ad_metadata); - EXPECT_EQ(kBidder2, result_.interest_group_owner); - EXPECT_EQ(kBidder2Name, result_.interest_group_name); - EXPECT_TRUE(result_.seller_report_url.is_empty()); - EXPECT_TRUE(result_.bidder_report_url.is_empty()); + EXPECT_FALSE(result_.seller_report_url); + EXPECT_FALSE(result_.bidder_report_url); + EXPECT_EQ(6, result_.bidder1_bid_count); + EXPECT_EQ(3u, result_.bidder1_prev_wins.size()); + EXPECT_EQ(6, result_.bidder2_bid_count); + ASSERT_EQ(4u, result_.bidder2_prev_wins.size()); + EXPECT_EQ(R"({"render_url":"https://ad2.com/"})", + result_.bidder2_prev_wins[3]->ad_json); EXPECT_THAT(result_.errors, testing::ElementsAre(base::StringPrintf( "%s crashed while trying to run generateBid().", @@ -1380,11 +1568,14 @@ // Bidder2 won. EXPECT_EQ(GURL("https://ad2.com/"), result_.ad_url); - EXPECT_EQ(R"({"render_url":"https://ad2.com/"})", result_.ad_metadata); - EXPECT_EQ(kBidder2, result_.interest_group_owner); - EXPECT_EQ(kBidder2Name, result_.interest_group_name); - EXPECT_TRUE(result_.seller_report_url.is_empty()); - EXPECT_TRUE(result_.bidder_report_url.is_empty()); + EXPECT_FALSE(result_.seller_report_url); + EXPECT_FALSE(result_.bidder_report_url); + EXPECT_EQ(6, result_.bidder1_bid_count); + EXPECT_EQ(3u, result_.bidder1_prev_wins.size()); + EXPECT_EQ(6, result_.bidder2_bid_count); + ASSERT_EQ(4u, result_.bidder2_prev_wins.size()); + EXPECT_EQ(R"({"render_url":"https://ad2.com/"})", + result_.bidder2_prev_wins[3]->ad_json); // Since Bidder1 crashed after bidding, don't report anything. EXPECT_THAT(result_.errors, testing::ElementsAre()); } @@ -1427,12 +1618,13 @@ auction_run_loop_->Run(); // No bidder won, Bidder1 crashed. - EXPECT_TRUE(result_.ad_url.is_empty()); - EXPECT_TRUE(result_.ad_metadata.empty()); - EXPECT_TRUE(result_.interest_group_owner.opaque()); - EXPECT_EQ("", result_.interest_group_name); - EXPECT_TRUE(result_.seller_report_url.is_empty()); - EXPECT_TRUE(result_.bidder_report_url.is_empty()); + EXPECT_FALSE(result_.ad_url); + EXPECT_FALSE(result_.seller_report_url); + EXPECT_FALSE(result_.bidder_report_url); + EXPECT_EQ(5, result_.bidder1_bid_count); + EXPECT_EQ(3u, result_.bidder1_prev_wins.size()); + EXPECT_EQ(5, result_.bidder2_bid_count); + EXPECT_EQ(3u, result_.bidder2_prev_wins.size()); EXPECT_THAT(result_.errors, testing::ElementsAre(base::StringPrintf( "%s crashed while idle.", kBidder1Url.spec().c_str()))); @@ -1475,12 +1667,13 @@ auction_run_loop_->Run(); // No bidder won, Bidder1 crashed. - EXPECT_TRUE(result_.ad_url.is_empty()); - EXPECT_TRUE(result_.ad_metadata.empty()); - EXPECT_TRUE(result_.interest_group_owner.opaque()); - EXPECT_EQ("", result_.interest_group_name); - EXPECT_TRUE(result_.seller_report_url.is_empty()); - EXPECT_TRUE(result_.bidder_report_url.is_empty()); + EXPECT_FALSE(result_.ad_url); + EXPECT_FALSE(result_.seller_report_url); + EXPECT_FALSE(result_.bidder_report_url); + EXPECT_EQ(5, result_.bidder1_bid_count); + EXPECT_EQ(3u, result_.bidder1_prev_wins.size()); + EXPECT_EQ(5, result_.bidder2_bid_count); + EXPECT_EQ(3u, result_.bidder2_prev_wins.size()); EXPECT_THAT(result_.errors, testing::ElementsAre(base::StringPrintf( "%s crashed while trying to run reportWin().", kBidder1Url.spec().c_str()))); @@ -1565,12 +1758,13 @@ auction_run_loop_->Run(); // No bidder won, seller crashed. - EXPECT_TRUE(result_.ad_url.is_empty()); - EXPECT_TRUE(result_.ad_metadata.empty()); - EXPECT_TRUE(result_.interest_group_owner.opaque()); - EXPECT_EQ("", result_.interest_group_name); - EXPECT_TRUE(result_.seller_report_url.is_empty()); - EXPECT_TRUE(result_.bidder_report_url.is_empty()); + EXPECT_FALSE(result_.ad_url); + EXPECT_FALSE(result_.seller_report_url); + EXPECT_FALSE(result_.bidder_report_url); + EXPECT_EQ(5, result_.bidder1_bid_count); + EXPECT_EQ(3u, result_.bidder1_prev_wins.size()); + EXPECT_EQ(5, result_.bidder2_bid_count); + EXPECT_EQ(3u, result_.bidder2_prev_wins.size()); EXPECT_THAT(result_.errors, testing::ElementsAre(base::StringPrintf( "%s crashed.", kSellerUrl.spec().c_str()))); } @@ -1675,12 +1869,13 @@ EXPECT_EQ(test_case.expected_error_message, TakeBadMessage()); // No bidder won. - EXPECT_TRUE(result_.ad_url.is_empty()); - EXPECT_TRUE(result_.ad_metadata.empty()); - EXPECT_TRUE(result_.interest_group_owner.opaque()); - EXPECT_EQ("", result_.interest_group_name); - EXPECT_TRUE(result_.seller_report_url.is_empty()); - EXPECT_TRUE(result_.bidder_report_url.is_empty()); + EXPECT_FALSE(result_.ad_url); + EXPECT_FALSE(result_.seller_report_url); + EXPECT_FALSE(result_.bidder_report_url); + EXPECT_EQ(5, result_.bidder1_bid_count); + EXPECT_EQ(3u, result_.bidder1_prev_wins.size()); + EXPECT_EQ(5, result_.bidder2_bid_count); + EXPECT_EQ(3u, result_.bidder2_prev_wins.size()); EXPECT_THAT(result_.errors, testing::ElementsAre()); } } @@ -1719,12 +1914,13 @@ EXPECT_EQ("Invalid seller report URL", TakeBadMessage()); // No bidder won. - EXPECT_TRUE(result_.ad_url.is_empty()); - EXPECT_TRUE(result_.ad_metadata.empty()); - EXPECT_TRUE(result_.interest_group_owner.opaque()); - EXPECT_EQ("", result_.interest_group_name); - EXPECT_TRUE(result_.seller_report_url.is_empty()); - EXPECT_TRUE(result_.bidder_report_url.is_empty()); + EXPECT_FALSE(result_.ad_url); + EXPECT_FALSE(result_.seller_report_url); + EXPECT_FALSE(result_.bidder_report_url); + EXPECT_EQ(5, result_.bidder1_bid_count); + EXPECT_EQ(3u, result_.bidder1_prev_wins.size()); + EXPECT_EQ(5, result_.bidder2_bid_count); + EXPECT_EQ(3u, result_.bidder2_prev_wins.size()); EXPECT_THAT(result_.errors, testing::ElementsAre()); } @@ -1763,12 +1959,13 @@ EXPECT_EQ("Invalid bidder report URL", TakeBadMessage()); // No bidder won. - EXPECT_TRUE(result_.ad_url.is_empty()); - EXPECT_TRUE(result_.ad_metadata.empty()); - EXPECT_TRUE(result_.interest_group_owner.opaque()); - EXPECT_EQ("", result_.interest_group_name); - EXPECT_TRUE(result_.seller_report_url.is_empty()); - EXPECT_TRUE(result_.bidder_report_url.is_empty()); + EXPECT_FALSE(result_.ad_url); + EXPECT_FALSE(result_.seller_report_url); + EXPECT_FALSE(result_.bidder_report_url); + EXPECT_EQ(5, result_.bidder1_bid_count); + EXPECT_EQ(3u, result_.bidder1_prev_wins.size()); + EXPECT_EQ(5, result_.bidder2_bid_count); + EXPECT_EQ(3u, result_.bidder2_prev_wins.size()); EXPECT_THAT(result_.errors, testing::ElementsAre()); }
diff --git a/content/browser/isolated_origin_browsertest.cc b/content/browser/isolated_origin_browsertest.cc index e087d00..f9b7eed 100644 --- a/content/browser/isolated_origin_browsertest.cc +++ b/content/browser/isolated_origin_browsertest.cc
@@ -5282,6 +5282,9 @@ GURL coop_url = https_server()->GetURL( "coop.com", "/set-header?Cross-Origin-Opener-Policy: same-origin"); EXPECT_TRUE(NavigateToURL(shell(), coop_url)); + // Simulate user activation, which normally triggers COOP isolation for + // future BrowsingInstances. + EXPECT_TRUE(ExecJs(shell(), "// no-op")); EXPECT_EQ(web_contents()->GetMainFrame()->cross_origin_opener_policy().value, network::mojom::CrossOriginOpenerPolicyValue::kSameOrigin); SiteInstanceImpl* coop_instance =
diff --git a/content/browser/loader/cors_origin_pattern_setter_unittest.cc b/content/browser/loader/cors_origin_pattern_setter_unittest.cc index 343752c..43ba7bb 100644 --- a/content/browser/loader/cors_origin_pattern_setter_unittest.cc +++ b/content/browser/loader/cors_origin_pattern_setter_unittest.cc
@@ -44,8 +44,7 @@ { content::TestBrowserContext browser_context; - shared_list = content::BrowserContext::GetSharedCorsOriginAccessList( - &browser_context); + shared_list = browser_context.GetSharedCorsOriginAccessList(); ASSERT_TRUE(shared_list); // The list is empty (in absence of calls to CorsOriginPatternSetter::Set). @@ -108,8 +107,7 @@ run_loop.Run(); // Verify that the results got properly stored. - shared_list = content::BrowserContext::GetSharedCorsOriginAccessList( - &browser_context); + shared_list = browser_context.GetSharedCorsOriginAccessList(); ASSERT_TRUE(shared_list); std::vector<network::mojom::CorsOriginAccessPatternsPtr> patterns = shared_list->GetOriginAccessList().CreateCorsOriginAccessPatternsList();
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc index 54d5a879..178a234 100644 --- a/content/browser/loader/navigation_url_loader_impl.cc +++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -1241,11 +1241,10 @@ // Loading and rendering a web page after the user clicks a link. base::TaskPriority file_factory_priority = base::TaskPriority::USER_BLOCKING; non_network_url_loader_factories_.emplace( - url::kFileScheme, - FileURLLoaderFactory::Create( - browser_context_->GetPath(), - BrowserContext::GetSharedCorsOriginAccessList(browser_context_), - file_factory_priority)); + url::kFileScheme, FileURLLoaderFactory::Create( + browser_context_->GetPath(), + browser_context_->GetSharedCorsOriginAccessList(), + file_factory_priority)); #if defined(OS_ANDROID) non_network_url_loader_factories_.emplace(url::kContentScheme,
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc index 77062f0c..7f4dc27 100644 --- a/content/browser/renderer_host/render_frame_host_impl.cc +++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -7068,7 +7068,7 @@ url::kFileScheme, FileURLLoaderFactory::Create( browser_context->GetPath(), - BrowserContext::GetSharedCorsOriginAccessList(browser_context), + browser_context->GetSharedCorsOriginAccessList(), file_factory_priority)); }
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index 617e5d59..1512a77 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -1373,15 +1373,11 @@ } #endif - // If other child processes live on the UI thread then - // DiscardableSharedMemoryManager will have to be used only on UI thread. - if (!base::FeatureList::IsEnabled(features::kProcessHostOnUI)) { - if (auto r = receiver.As<discardable_memory::mojom:: - DiscardableSharedMemoryManager>()) { - discardable_memory::DiscardableSharedMemoryManager::Get()->Bind( - std::move(r)); - return; - } + if (auto r = receiver.As< + discardable_memory::mojom::DiscardableSharedMemoryManager>()) { + discardable_memory::DiscardableSharedMemoryManager::Get()->Bind( + std::move(r)); + return; } if (auto r = receiver.As<ukm::mojom::UkmRecorderInterface>()) { @@ -5067,15 +5063,6 @@ } #endif - if (base::FeatureList::IsEnabled(features::kProcessHostOnUI)) { - if (auto r = receiver.As< - discardable_memory::mojom::DiscardableSharedMemoryManager>()) { - discardable_memory::DiscardableSharedMemoryManager::Get()->Bind( - std::move(r)); - return; - } - } - GetContentClient()->browser()->BindHostReceiverForRenderer( this, std::move(receiver)); }
diff --git a/content/browser/webtransport/web_transport_connector_impl.cc b/content/browser/webtransport/web_transport_connector_impl.cc index 9c6147c..de503b85 100644 --- a/content/browser/webtransport/web_transport_connector_impl.cc +++ b/content/browser/webtransport/web_transport_connector_impl.cc
@@ -4,9 +4,13 @@ #include "content/browser/webtransport/web_transport_connector_impl.h" #include "content/browser/devtools/devtools_instrumentation.h" +#include "content/browser/renderer_host/render_frame_host_impl.h" #include "content/public/browser/browser_thread.h" +#include "content/public/browser/content_browser_client.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/storage_partition.h" +#include "content/public/common/content_client.h" +#include "mojo/public/cpp/bindings/remote.h" #include "mojo/public/cpp/bindings/self_owned_receiver.h" #include "net/quic/quic_transport_client.h" @@ -77,6 +81,28 @@ return; } + GetContentClient()->browser()->WillCreateWebTransport( + frame_.get(), url, + base::BindOnce( + &WebTransportConnectorImpl::OnWillCreateWebTransportCompleted, + weak_factory_.GetWeakPtr(), url, std::move(fingerprints), + std::move(handshake_client))); +} + +void WebTransportConnectorImpl::OnWillCreateWebTransportCompleted( + const GURL& url, + std::vector<network::mojom::WebTransportCertificateFingerprintPtr> + fingerprints, + mojo::PendingRemote<network::mojom::WebTransportHandshakeClient> + handshake_client, + absl::optional<network::mojom::WebTransportErrorPtr> error) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + RenderProcessHost* process = RenderProcessHost::FromID(process_id_); + if (!process) { + return; + } + mojo::PendingRemote<WebTransportHandshakeClient> handshake_client_to_pass; // TODO(yhirano): Stop using MakeSelfOwnedReceiver here, because the // WebTransport implementation in the network service won't notice that @@ -86,6 +112,16 @@ frame_, url, std::move(handshake_client)), handshake_client_to_pass.InitWithNewPipeAndPassReceiver()); + if (error) { + mojo::Remote<WebTransportHandshakeClient> remote( + std::move(handshake_client_to_pass)); + remote->OnHandshakeFailed(net::WebTransportError( + error.value()->net_error, + static_cast<quic::QuicErrorCode>(error.value()->quic_error), + error.value()->details, error.value()->safe_to_report_details)); + return; + } + process->GetStoragePartition()->GetNetworkContext()->CreateWebTransport( url, origin_, network_isolation_key_, std::move(fingerprints), std::move(handshake_client_to_pass));
diff --git a/content/browser/webtransport/web_transport_connector_impl.h b/content/browser/webtransport/web_transport_connector_impl.h index 323ad82..0eef84d 100644 --- a/content/browser/webtransport/web_transport_connector_impl.h +++ b/content/browser/webtransport/web_transport_connector_impl.h
@@ -6,6 +6,7 @@ #define CONTENT_BROWSER_WEBTRANSPORT_WEB_TRANSPORT_CONNECTOR_IMPL_H_ #include "base/memory/weak_ptr.h" +#include "base/optional.h" #include "mojo/public/cpp/bindings/pending_remote.h" #include "net/base/network_isolation_key.h" #include "services/network/public/mojom/network_context.mojom.h" @@ -38,10 +39,20 @@ handshake_client) override; private: + void OnWillCreateWebTransportCompleted( + const GURL& url, + std::vector<network::mojom::WebTransportCertificateFingerprintPtr> + fingerprints, + mojo::PendingRemote<network::mojom::WebTransportHandshakeClient> + handshake_client, + absl::optional<network::mojom::WebTransportErrorPtr> error); + const int process_id_; const base::WeakPtr<RenderFrameHostImpl> frame_; const url::Origin origin_; const net::NetworkIsolationKey network_isolation_key_; + + base::WeakPtrFactory<WebTransportConnectorImpl> weak_factory_{this}; }; } // namespace content
diff --git a/content/browser/worker_host/worker_script_fetch_initiator.cc b/content/browser/worker_host/worker_script_fetch_initiator.cc index 07a2e4e0..dd7fa0c 100644 --- a/content/browser/worker_host/worker_script_fetch_initiator.cc +++ b/content/browser/worker_host/worker_script_fetch_initiator.cc
@@ -230,8 +230,8 @@ non_network_factories.emplace( url::kFileScheme, FileURLLoaderFactory::Create( storage_partition->browser_context()->GetPath(), - BrowserContext::GetSharedCorsOriginAccessList( - storage_partition->browser_context()), + storage_partition->browser_context() + ->GetSharedCorsOriginAccessList(), file_factory_priority)); }
diff --git a/content/common/partition_alloc_support.cc b/content/common/partition_alloc_support.cc index 35f0a640..ed45764 100644 --- a/content/common/partition_alloc_support.cc +++ b/content/common/partition_alloc_support.cc
@@ -55,7 +55,7 @@ #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && PA_ALLOW_PCSCAN DCHECK(base::FeatureList::GetInstance()); if (base::FeatureList::IsEnabled(base::features::kPartitionAllocPCScan)) { - base::allocator::EnablePCScan(); + base::allocator::EnablePCScan(/*dcscan*/ false); return true; } #endif @@ -67,7 +67,13 @@ DCHECK(base::FeatureList::GetInstance()); if (base::FeatureList::IsEnabled( base::features::kPartitionAllocPCScanBrowserOnly)) { - base::allocator::EnablePCScan(); + const bool dcscan_wanted = + base::FeatureList::IsEnabled(base::features::kPartitionAllocDCScan); +#if !defined(PA_STARSCAN_UFFD_WRITE_PROTECTOR_SUPPORTED) + CHECK(!dcscan_wanted) + << "DCScan is currently only supported on Linux based systems"; +#endif + base::allocator::EnablePCScan(dcscan_wanted); return true; } #endif
diff --git a/content/public/browser/browser_context.h b/content/public/browser/browser_context.h index b96752c4..e42b740 100644 --- a/content/public/browser/browser_context.h +++ b/content/public/browser/browser_context.h
@@ -100,11 +100,6 @@ // The currently recommended practice is to make the methods in this section // non-virtual instance methods. // - // TODO(https://crbug.com/1179776): Finish converting the methods in this - // section into non-virtual instance methods. (The old, abandoned practice - // was to make the methods in this section `static` and have them take - // `BrowserContext* self` as the first parameter.) - // // TODO(https://crbug.com/1179776): Consider moving these methods to // BrowserContext::Impl or (in the future) BrowserContextImpl class. @@ -116,7 +111,7 @@ // Returns BrowserContext specific external mount points. It may return // nullptr if the context doesn't have any BrowserContext specific external // mount points. Currently, non-nullptr value is returned only on ChromeOS. - static storage::ExternalMountPoints* GetMountPoints(BrowserContext* self); + storage::ExternalMountPoints* GetMountPoints(); // Returns a BrowsingDataRemover that can schedule data deletion tasks // for this |context|. @@ -207,18 +202,18 @@ blink::mojom::PushSubscriptionPtr old_subscription, base::OnceCallback<void(blink::mojom::PushEventStatus)> callback); - static void NotifyWillBeDestroyed(BrowserContext* self); + void NotifyWillBeDestroyed(); // Ensures that the corresponding ResourceContext is initialized. Normally the // BrowserContext initializs the corresponding getters when its objects are // created, but if the embedder wants to pass the ResourceContext to another // thread before they use BrowserContext, they should call this to make sure // that the ResourceContext is ready. - static void EnsureResourceContextInitialized(BrowserContext* self); + void EnsureResourceContextInitialized(); // Tells the HTML5 objects on this context to persist their session state // across the next restart. - static void SaveSessionState(BrowserContext* self); + void SaveSessionState(); void SetDownloadManagerForTesting( std::unique_ptr<DownloadManager> download_manager); @@ -231,8 +226,7 @@ // network::mojom::NetworkContextParams::cors_origin_access_list) and 2) // consulted by CORS-aware factories (e.g. passed when constructing // FileURLLoaderFactory). - static SharedCorsOriginAccessList* GetSharedCorsOriginAccessList( - BrowserContext* self); + SharedCorsOriginAccessList* GetSharedCorsOriginAccessList(); // Shuts down the storage partitions associated to this browser context. // This must be called before the browser context is actually destroyed
diff --git a/content/public/browser/child_process_security_policy.h b/content/public/browser/child_process_security_policy.h index ab01cf0..eff0b82 100644 --- a/content/public/browser/child_process_security_policy.h +++ b/content/public/browser/child_process_security_policy.h
@@ -325,6 +325,13 @@ // within that particular BrowserContext will be returned (note that this // includes both matching per-profile isolated origins as well as globally // applicable origins which apply to |browser_context| by definition). + // + // Origins returned by this function only include origins that would apply to + // any future BrowsingInstance (browsing context group). Origins that were + // isolated only in specific BrowsingInstances are not included. (In + // particular, this excludes BrowsingInstance-specific isolated origins for + // Origin-Agent-Cluster as well as COOP documents loaded without user + // activation.) virtual std::vector<url::Origin> GetIsolatedOrigins( absl::optional<IsolatedOriginSource> source = absl::nullopt, BrowserContext* browser_context = nullptr) = 0;
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc index 839be65..0a22650 100644 --- a/content/public/browser/content_browser_client.cc +++ b/content/public/browser/content_browser_client.cc
@@ -816,6 +816,13 @@ NOTREACHED(); } +void ContentBrowserClient::WillCreateWebTransport( + RenderFrameHost* frame, + const GURL& url, + WillCreateWebTransportCallback callback) { + std::move(callback).Run(absl::nullopt); +} + bool ContentBrowserClient::WillCreateRestrictedCookieManager( network::mojom::RestrictedCookieManagerRole role, BrowserContext* browser_context,
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h index 42158d28..71d4002 100644 --- a/content/public/browser/content_browser_client.h +++ b/content/public/browser/content_browser_client.h
@@ -49,6 +49,7 @@ #include "services/network/public/mojom/network_context.mojom-forward.h" #include "services/network/public/mojom/restricted_cookie_manager.mojom-forward.h" #include "services/network/public/mojom/url_loader_factory.mojom-forward.h" +#include "services/network/public/mojom/web_transport.mojom-forward.h" #include "services/network/public/mojom/websocket.mojom-forward.h" #include "storage/browser/file_system/file_system_context.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -1477,6 +1478,14 @@ mojo::PendingRemote<network::mojom::WebSocketHandshakeClient> handshake_client); + // Allows the embedder to control if establishing a WebTransport connection is + // allowed. When the connection is blocked, `callback` is called with `error`. + using WillCreateWebTransportCallback = base::OnceCallback<void( + absl::optional<network::mojom::WebTransportErrorPtr> error)>; + virtual void WillCreateWebTransport(RenderFrameHost* frame, + const GURL& url, + WillCreateWebTransportCallback callback); + // Allows the embedder to intercept or replace the mojo objects used for // preference-following access to cookies. This is primarily used for objects // vended to renderer processes for limited, origin-locked (to |origin|),
diff --git a/content/public/browser/cors_origin_pattern_setter.cc b/content/public/browser/cors_origin_pattern_setter.cc index a1ea156..1d2ad94 100644 --- a/content/public/browser/cors_origin_pattern_setter.cc +++ b/content/public/browser/cors_origin_pattern_setter.cc
@@ -60,9 +60,9 @@ // Keep the per-profile access list up to date so that we can use this to // restore NetworkContext settings at anytime, e.g. on restarting the // network service. - content::BrowserContext::GetSharedCorsOriginAccessList(browser_context) - ->SetForOrigin(source_origin, std::move(allow_patterns), - std::move(block_patterns), barrier_closure); + browser_context->GetSharedCorsOriginAccessList()->SetForOrigin( + source_origin, std::move(allow_patterns), std::move(block_patterns), + barrier_closure); } } // namespace content
diff --git a/content/public/test/test_browser_context.cc b/content/public/test/test_browser_context.cc index 44fa38f..d4f572a 100644 --- a/content/public/test/test_browser_context.cc +++ b/content/public/test/test_browser_context.cc
@@ -40,7 +40,7 @@ << "the BrowserTaskEnvironment instance. " << BrowserThread::GetDCheckCurrentlyOnErrorMessage(BrowserThread::UI); - NotifyWillBeDestroyed(this); + NotifyWillBeDestroyed(); ShutdownStoragePartitions(); // Various things that were just torn down above post tasks to other
diff --git a/content/shell/browser/shell_browser_context.cc b/content/shell/browser/shell_browser_context.cc index 815f995..91eb6df 100644 --- a/content/shell/browser/shell_browser_context.cc +++ b/content/shell/browser/shell_browser_context.cc
@@ -59,7 +59,7 @@ } ShellBrowserContext::~ShellBrowserContext() { - NotifyWillBeDestroyed(this); + NotifyWillBeDestroyed(); // The SimpleDependencyManager should always be passed after the // BrowserContextDependencyManager. This is because the KeyedService instances
diff --git a/content/web_test/browser/web_test_browser_context.cc b/content/web_test/browser/web_test_browser_context.cc index eab5c7e..5c278ee4e 100644 --- a/content/web_test/browser/web_test_browser_context.cc +++ b/content/web_test/browser/web_test_browser_context.cc
@@ -45,7 +45,7 @@ } WebTestBrowserContext::~WebTestBrowserContext() { - BrowserContext::NotifyWillBeDestroyed(this); + NotifyWillBeDestroyed(); } DownloadManagerDelegate* WebTestBrowserContext::GetDownloadManagerDelegate() {
diff --git a/device/DIR_METADATA b/device/DIR_METADATA index f4708701..78f0fb6 100644 --- a/device/DIR_METADATA +++ b/device/DIR_METADATA
@@ -1,10 +1,10 @@ # Metadata information for this directory. # # For more information on DIR_METADATA files, see: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md # # For the schema of this file, see Metadata message: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto monorail { component: "Internals>Services>Device"
diff --git a/device/bluetooth/DIR_METADATA b/device/bluetooth/DIR_METADATA index 4879b90..249d388a 100644 --- a/device/bluetooth/DIR_METADATA +++ b/device/bluetooth/DIR_METADATA
@@ -1,10 +1,10 @@ # Metadata information for this directory. # # For more information on DIR_METADATA files, see: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md # # For the schema of this file, see Metadata message: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto monorail { component: "IO>Bluetooth"
diff --git a/device/bluetooth/dbus/DIR_METADATA b/device/bluetooth/dbus/DIR_METADATA index 661058d..ca1c895 100644 --- a/device/bluetooth/dbus/DIR_METADATA +++ b/device/bluetooth/dbus/DIR_METADATA
@@ -1,10 +1,10 @@ # Metadata information for this directory. # # For more information on DIR_METADATA files, see: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md # # For the schema of this file, see Metadata message: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto monorail { component: "OS>Systems>Bluetooth"
diff --git a/device/bluetooth/test/README.md b/device/bluetooth/test/README.md index 7544bb3..fdcd44c3 100644 --- a/device/bluetooth/test/README.md +++ b/device/bluetooth/test/README.md
@@ -84,6 +84,6 @@ Bluetooth controller system tests generating radio signals are run and managed by the Chrome OS team. See: -https://chromium.googlesource.com/chromiumos/third_party/autotest/+/master/server/site_tests/ -https://chromium.googlesource.com/chromiumos/third_party/autotest/+/master/server/cros/bluetooth/ -https://chromium.googlesource.com/chromiumos/third_party/autotest/+/master/client/cros/bluetooth/ +https://chromium.googlesource.com/chromiumos/third_party/autotest/+/main/server/site_tests/ +https://chromium.googlesource.com/chromiumos/third_party/autotest/+/main/server/cros/bluetooth/ +https://chromium.googlesource.com/chromiumos/third_party/autotest/+/main/client/cros/bluetooth/
diff --git a/device/fido/DIR_METADATA b/device/fido/DIR_METADATA index 6152f17..0373478a 100644 --- a/device/fido/DIR_METADATA +++ b/device/fido/DIR_METADATA
@@ -1,10 +1,10 @@ # Metadata information for this directory. # # For more information on DIR_METADATA files, see: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md # # For the schema of this file, see Metadata message: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto monorail { component: "Blink>WebAuthentication"
diff --git a/device/gamepad/DIR_METADATA b/device/gamepad/DIR_METADATA index 60e948d..9ea741b 100644 --- a/device/gamepad/DIR_METADATA +++ b/device/gamepad/DIR_METADATA
@@ -1,10 +1,10 @@ # Metadata information for this directory. # # For more information on DIR_METADATA files, see: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md # # For the schema of this file, see Metadata message: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto monorail { component: "IO>Gamepad"
diff --git a/device/vr/DIR_METADATA b/device/vr/DIR_METADATA index 203eb72a..bbaaf424 100644 --- a/device/vr/DIR_METADATA +++ b/device/vr/DIR_METADATA
@@ -1,10 +1,10 @@ # Metadata information for this directory. # # For more information on DIR_METADATA files, see: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md # # For the schema of this file, see Metadata message: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto monorail { component: "Internals>XR"
diff --git a/device/vr/android/arcore/DIR_METADATA b/device/vr/android/arcore/DIR_METADATA index 27ea7f1..54441bf 100644 --- a/device/vr/android/arcore/DIR_METADATA +++ b/device/vr/android/arcore/DIR_METADATA
@@ -1,10 +1,10 @@ # Metadata information for this directory. # # For more information on DIR_METADATA files, see: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md # # For the schema of this file, see Metadata message: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto monorail { component: "Blink>WebXR>AR"
diff --git a/extensions/browser/api/storage/storage_api.cc b/extensions/browser/api/storage/storage_api.cc index 88a6ca9e..433f0644 100644 --- a/extensions/browser/api/storage/storage_api.cc +++ b/extensions/browser/api/storage/storage_api.cc
@@ -33,18 +33,6 @@ constexpr char kSessionStorageManagerKeyName[] = "StorageAPI SessionStorageManager"; -// Adds all StringValues from a ListValue to a vector of strings. -void AddAllStringValues(const base::ListValue& from, - std::vector<std::string>* to) { - DCHECK(to->empty()); - std::string as_string; - for (const auto& entry : from.GetList()) { - if (entry.GetAsString(&as_string)) { - to->push_back(as_string); - } - } -} - // Returns a vector of any strings within the given list. std::vector<std::string> GetKeysFromList(const base::Value& list) { DCHECK(list.is_list()); @@ -58,15 +46,6 @@ return keys; } -// Gets the keys of a DictionaryValue. -std::vector<std::string> GetKeys(const base::DictionaryValue& dict) { - std::vector<std::string> keys; - for (base::DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) { - keys.push_back(it.key()); - } - return keys; -} - // Returns a vector of keys within the given dict. std::vector<std::string> GetKeysFromDict(const base::Value& dict) { DCHECK(dict.is_dict()); @@ -230,7 +209,7 @@ ValueStore* storage) { TRACE_EVENT1("browser", "StorageStorageAreaGetFunction::RunWithStorage", "extension_id", extension_id()); - base::Value* input = NULL; + base::Value* input = nullptr; if (!args_->Get(0, &input)) return BadMessage(); @@ -238,33 +217,19 @@ case base::Value::Type::NONE: return UseReadResult(storage->Get()); - case base::Value::Type::STRING: { - std::string as_string; - input->GetAsString(&as_string); - return UseReadResult(storage->Get(as_string)); - } + case base::Value::Type::STRING: + return UseReadResult(storage->Get(input->GetString())); - case base::Value::Type::LIST: { - // TODO(crbug.com/1200931): Replace with GetKeysFromList() and delete - // AddAllStringValues(). - std::vector<std::string> as_string_list; - AddAllStringValues(*static_cast<base::ListValue*>(input), - &as_string_list); - return UseReadResult(storage->Get(as_string_list)); - } + case base::Value::Type::LIST: + return UseReadResult(storage->Get(GetKeysFromList(*input))); case base::Value::Type::DICTIONARY: { - // TODO(crbug.com/1200931): Replace with GetKeysFromDict() and delete - // GetKeys(). - base::DictionaryValue* as_dict = - static_cast<base::DictionaryValue*>(input); - ValueStore::ReadResult result = storage->Get(GetKeys(*as_dict)); + ValueStore::ReadResult result = storage->Get(GetKeysFromDict(*input)); if (!result.status().ok()) { return UseReadResult(std::move(result)); } - std::unique_ptr<base::DictionaryValue> with_default_values = - as_dict->CreateDeepCopy(); + static_cast<base::DictionaryValue*>(input)->CreateDeepCopy(); with_default_values->MergeDictionary(&result.settings()); return UseReadResult(ValueStore::ReadResult( std::move(with_default_values), result.PassStatus())); @@ -325,7 +290,7 @@ "StorageStorageAreaGetBytesInUseFunction::RunWithStorage", "extension_id", extension_id()); - base::Value* input = NULL; + base::Value* input = nullptr; if (!args_->Get(0, &input)) return BadMessage(); @@ -336,20 +301,13 @@ bytes_in_use = storage->GetBytesInUse(); break; - case base::Value::Type::STRING: { - std::string as_string; - input->GetAsString(&as_string); - bytes_in_use = storage->GetBytesInUse(as_string); + case base::Value::Type::STRING: + bytes_in_use = storage->GetBytesInUse(input->GetString()); break; - } - case base::Value::Type::LIST: { - std::vector<std::string> as_string_list; - AddAllStringValues(*static_cast<base::ListValue*>(input), - &as_string_list); - bytes_in_use = storage->GetBytesInUse(as_string_list); + case base::Value::Type::LIST: + bytes_in_use = storage->GetBytesInUse(GetKeysFromList(*input)); break; - } default: return BadMessage(); @@ -369,7 +327,7 @@ ValueStore* storage) { TRACE_EVENT1("browser", "StorageStorageAreaSetFunction::RunWithStorage", "extension_id", extension_id()); - base::DictionaryValue* input = NULL; + base::DictionaryValue* input = nullptr; if (!args_->GetDictionary(0, &input)) return BadMessage(); return UseWriteResult(storage->Set(ValueStore::DEFAULTS, *input)); @@ -415,23 +373,16 @@ StorageStorageAreaRemoveFunction::RunWithStorage(ValueStore* storage) { TRACE_EVENT1("browser", "StorageStorageAreaRemoveFunction::RunWithStorage", "extension_id", extension_id()); - base::Value* input = NULL; + base::Value* input = nullptr; if (!args_->Get(0, &input)) return BadMessage(); switch (input->type()) { - case base::Value::Type::STRING: { - std::string as_string; - input->GetAsString(&as_string); - return UseWriteResult(storage->Remove(as_string)); - } + case base::Value::Type::STRING: + return UseWriteResult(storage->Remove(input->GetString())); - case base::Value::Type::LIST: { - std::vector<std::string> as_string_list; - AddAllStringValues(*static_cast<base::ListValue*>(input), - &as_string_list); - return UseWriteResult(storage->Remove(as_string_list)); - } + case base::Value::Type::LIST: + return UseWriteResult(storage->Remove(GetKeysFromList(*input))); default: return BadMessage();
diff --git a/extensions/browser/extension_event_histogram_value.h b/extensions/browser/extension_event_histogram_value.h index 2f5f048..a0fb8f09 100644 --- a/extensions/browser/extension_event_histogram_value.h +++ b/extensions/browser/extension_event_histogram_value.h
@@ -345,9 +345,9 @@ WINDOWS_ON_REMOVED = 324, FILE_SYSTEM_PROVIDER_ON_EXECUTE_ACTION_REQUESTED = 325, FILE_SYSTEM_PROVIDER_ON_GET_ACTIONS_REQUESTED = 326, - LAUNCHER_SEARCH_PROVIDER_ON_QUERY_STARTED = 327, - LAUNCHER_SEARCH_PROVIDER_ON_QUERY_ENDED = 328, - LAUNCHER_SEARCH_PROVIDER_ON_OPEN_RESULT = 329, + DELETED_LAUNCHER_SEARCH_PROVIDER_ON_QUERY_STARTED = 327, + DELETED_LAUNCHER_SEARCH_PROVIDER_ON_QUERY_ENDED = 328, + DELETED_LAUNCHER_SEARCH_PROVIDER_ON_OPEN_RESULT = 329, CHROME_WEB_VIEW_INTERNAL_ON_CLICKED = 330, WEB_VIEW_INTERNAL_CONTEXT_MENUS = 331, CONTEXT_MENUS = 332,
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h index f6d5805..d7e7fb9 100644 --- a/extensions/browser/extension_function_histogram_value.h +++ b/extensions/browser/extension_function_histogram_value.h
@@ -1053,7 +1053,7 @@ DELETED_EASYUNLOCKPRIVATE_HIDEERRORBUBBLE = 992, WEBVIEWINTERNAL_SETZOOMMODE = 993, WEBVIEWINTERNAL_GETZOOMMODE = 994, - LAUNCHERSEARCHPROVIDER_SETSEARCHRESULTS = 995, + DELETED_LAUNCHERSEARCHPROVIDER_SETSEARCHRESULTS = 995, DELETED_DATAREDUCTIONPROXY_CLEARDATASAVINGS = 996, BLUETOOTHPRIVATE_SETDISCOVERYFILTER = 997, FILESYSTEM_GETVOLUMELIST = 998,
diff --git a/extensions/common/mojom/api_permission_id.mojom b/extensions/common/mojom/api_permission_id.mojom index 63e1cad..96e136b1 100644 --- a/extensions/common/mojom/api_permission_id.mojom +++ b/extensions/common/mojom/api_permission_id.mojom
@@ -118,7 +118,7 @@ kInput = 92, kInputMethodPrivate = 93, kDeleted_InterceptAllKeys = 94, - kLauncherSearchProvider = 95, + kDeleted_LauncherSearchProvider = 95, kLocation = 96, kDeleted_LogPrivate = 97, kManagement = 98,
diff --git a/extensions/shell/browser/shell_browser_context.cc b/extensions/shell/browser/shell_browser_context.cc index 665bd9b..f625fd2 100644 --- a/extensions/shell/browser/shell_browser_context.cc +++ b/extensions/shell/browser/shell_browser_context.cc
@@ -21,7 +21,7 @@ storage_policy_(new ShellSpecialStoragePolicy) {} ShellBrowserContext::~ShellBrowserContext() { - content::BrowserContext::NotifyWillBeDestroyed(this); + NotifyWillBeDestroyed(); } content::BrowserPluginGuestManager* ShellBrowserContext::GetGuestManager() {
diff --git a/fuchsia/DIR_METADATA b/fuchsia/DIR_METADATA index de0c11f0..11f5ec9 100644 --- a/fuchsia/DIR_METADATA +++ b/fuchsia/DIR_METADATA
@@ -1,10 +1,10 @@ # Metadata information for this directory. # # For more information on DIR_METADATA files, see: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md # # For the schema of this file, see Metadata message: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto monorail { component: "Fuchsia"
diff --git a/fuchsia/engine/browser/accessibility_bridge_browsertest.cc b/fuchsia/engine/browser/accessibility_bridge_browsertest.cc index 5062b6b..4b840ed 100644 --- a/fuchsia/engine/browser/accessibility_bridge_browsertest.cc +++ b/fuchsia/engine/browser/accessibility_bridge_browsertest.cc
@@ -7,6 +7,7 @@ #include <zircon/types.h> #include "base/strings/stringprintf.h" +#include "base/test/bind.h" #include "content/public/test/browser_test.h" #include "fuchsia/base/mem_buffer_util.h" #include "fuchsia/base/test/frame_test_util.h" @@ -1041,10 +1042,17 @@ ->GetMainFrame() ->AccessibilityPerformAction(action_data); - base::RunLoop run_loop; - semantics_manager_.semantic_tree()->SetNodeUpdatedCallback( - 0u, run_loop.QuitClosure()); - run_loop.Run(); + auto* semantic_tree = semantics_manager_.semantic_tree(); + + semantic_tree->RunUntilCondititionIsTrue( + base::BindLambdaForTesting([semantic_tree]() { + auto* node = semantic_tree->GetNodeWithId(0u); + if (!node) + return false; + + return node->has_states() && node->states().has_has_input_focus() && + node->states().has_input_focus(); + })); ASSERT_TRUE(semantics_manager_.semantic_tree() ->GetNodeWithId(0u) @@ -1063,10 +1071,20 @@ ->GetMainFrame() ->AccessibilityPerformAction(action_data); - base::RunLoop run_loop2; - semantics_manager_.semantic_tree()->SetNodeUpdatedCallback( - new_focus_id, run_loop2.QuitClosure()); - run_loop2.Run(); + semantic_tree->RunUntilCondititionIsTrue( + base::BindLambdaForTesting([semantic_tree, new_focus_id]() { + auto* root = semantic_tree->GetNodeWithId(0u); + auto* node = semantic_tree->GetNodeWithId(new_focus_id); + + if (!node || !root) + return false; + + // Node has the focus, root does not. + return (node->has_states() && node->states().has_has_input_focus() && + node->states().has_input_focus()) && + (root->has_states() && root->states().has_has_input_focus() && + !root->states().has_input_focus()); + })); ASSERT_FALSE(semantics_manager_.semantic_tree() ->GetNodeWithId(0u)
diff --git a/fuchsia/engine/browser/fake_semantic_tree.cc b/fuchsia/engine/browser/fake_semantic_tree.cc index 87c49e0..261af059 100644 --- a/fuchsia/engine/browser/fake_semantic_tree.cc +++ b/fuchsia/engine/browser/fake_semantic_tree.cc
@@ -177,3 +177,19 @@ void FakeSemanticTree::Clear() { nodes_.clear(); } + +void FakeSemanticTree::RunUntilCondititionIsTrue( + base::RepeatingCallback<bool()> condition) { + DCHECK(!on_commit_updates_); + if (condition.Run()) + return; + + base::RunLoop run_loop; + base::AutoReset<base::RepeatingClosure> auto_reset( + &on_commit_updates_, + base::BindLambdaForTesting([&condition, &run_loop]() { + if (condition.Run()) + run_loop.Quit(); + })); + run_loop.Run(); +}
diff --git a/fuchsia/engine/browser/fake_semantic_tree.h b/fuchsia/engine/browser/fake_semantic_tree.h index 8c79858..04ae950 100644 --- a/fuchsia/engine/browser/fake_semantic_tree.h +++ b/fuchsia/engine/browser/fake_semantic_tree.h
@@ -38,6 +38,7 @@ void RunUntilNodeCountAtLeast(size_t count); void RunUntilNodeWithLabelIsInTree(base::StringPiece label); void RunUntilCommitCountIs(size_t count); + void RunUntilCondititionIsTrue(base::RepeatingCallback<bool()> condition); void SetNodeUpdatedCallback(uint32_t node_id, base::OnceClosure node_updated_callback); fuchsia::accessibility::semantics::Node* GetNodeWithId(uint32_t id);
diff --git a/fuchsia/engine/browser/frame_impl.cc b/fuchsia/engine/browser/frame_impl.cc index ca562b9b..bfed581 100644 --- a/fuchsia/engine/browser/frame_impl.cc +++ b/fuchsia/engine/browser/frame_impl.cc
@@ -23,6 +23,7 @@ #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" +#include "content/public/browser/host_zoom_map.h" #include "content/public/browser/media_session.h" #include "content/public/browser/message_port_provider.h" #include "content/public/browser/navigation_entry.h" @@ -30,6 +31,7 @@ #include "content/public/browser/permission_controller_delegate.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" +#include "content/public/browser/render_view_host.h" #include "content/public/browser/render_widget_host.h" #include "content/public/browser/render_widget_host_view.h" #include "content/public/browser/renderer_preferences_util.h" @@ -53,6 +55,7 @@ #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h" #include "third_party/blink/public/common/logging/logging_utils.h" #include "third_party/blink/public/common/messaging/web_message_port.h" +#include "third_party/blink/public/common/page/page_zoom.h" #include "third_party/blink/public/mojom/loader/resource_load_info.mojom.h" #include "ui/aura/window.h" #include "ui/compositor/compositor.h" @@ -581,6 +584,15 @@ std::move(cast_streaming_receiver)); } +void FrameImpl::UpdateRenderViewZoomLevel( + content::RenderViewHost* render_view_host) { + content::HostZoomMap* host_zoom_map = + content::HostZoomMap::GetForWebContents(web_contents_.get()); + host_zoom_map->SetTemporaryZoomLevel( + render_view_host->GetProcess()->GetID(), render_view_host->GetRoutingID(), + blink::PageZoomFactorToZoomLevel(page_scale_)); +} + void FrameImpl::CreateView(fuchsia::ui::views::ViewToken view_token) { scenic::ViewRefPair view_ref_pair = scenic::ViewRefPair::New(); CreateViewWithViewRef(std::move(view_token), @@ -948,6 +960,19 @@ base::Unretained(this))); } +void FrameImpl::SetPageScale(float scale) { + if (scale <= 0.0) { + LOG(ERROR) << "SetPageScale() called with nonpositive scale."; + CloseAndDestroyFrame(ZX_ERR_INVALID_ARGS); + return; + } + + if (scale == page_scale_) + return; + page_scale_ = scale; + UpdateRenderViewZoomLevel(web_contents_->GetRenderViewHost()); +} + void FrameImpl::ForceContentDimensions( std::unique_ptr<fuchsia::ui::gfx::vec2> web_dips) { if (!web_dips) { @@ -959,7 +984,7 @@ gfx::Size web_dips_converted(web_dips->x, web_dips->y); if (web_dips_converted.IsEmpty()) { - LOG(WARNING) << "Rejecting zero-area size for ForceContentDimensions()."; + LOG(ERROR) << "Rejecting zero-area size for ForceContentDimensions()."; CloseAndDestroyFrame(ZX_ERR_INVALID_ARGS); return; } @@ -1146,8 +1171,17 @@ void FrameImpl::RenderFrameCreated(content::RenderFrameHost* frame_host) { // The top-level frame is given a transparent background color. // GetView() is guaranteed to be non-null until |frame_host| teardown. - if (frame_host == web_contents()->GetMainFrame()) + if (frame_host == web_contents()->GetMainFrame()) { frame_host->GetView()->SetBackgroundColor(SK_AlphaTRANSPARENT); + } +} + +void FrameImpl::RenderViewHostChanged(content::RenderViewHost* old_host, + content::RenderViewHost* new_host) { + // UpdateRenderViewZoomLevel() sets temporary zoom level for the current + // RenderView. It needs to be called again whenever main RenderView is + // changed. + UpdateRenderViewZoomLevel(new_host); } void FrameImpl::DidFirstVisuallyNonEmptyPaint() {
diff --git a/fuchsia/engine/browser/frame_impl.h b/fuchsia/engine/browser/frame_impl.h index 5ae4257..73f2d1c 100644 --- a/fuchsia/engine/browser/frame_impl.h +++ b/fuchsia/engine/browser/frame_impl.h
@@ -168,6 +168,9 @@ void MaybeStartCastStreaming(content::NavigationHandle* navigation_handle); + // Updates zoom level for the specified |render_view_host|. + void UpdateRenderViewZoomLevel(content::RenderViewHost* render_view_host); + // fuchsia::web::Frame implementation. void CreateView(fuchsia::ui::views::ViewToken view_token) override; void CreateViewWithViewRef(fuchsia::ui::views::ViewToken view_token, @@ -228,6 +231,7 @@ fidl::InterfaceHandle<fuchsia::web::NavigationPolicyProvider> provider) override; void SetPreferredTheme(fuchsia::settings::ThemeType theme) override; + void SetPageScale(float scale) override; // content::WebContentsDelegate implementation. void CloseContents(content::WebContents* source) override; @@ -270,6 +274,8 @@ void DidFinishLoad(content::RenderFrameHost* render_frame_host, const GURL& validated_url) override; void RenderFrameCreated(content::RenderFrameHost* frame_host) override; + void RenderViewHostChanged(content::RenderViewHost* old_host, + content::RenderViewHost* new_host) override; void DidFirstVisuallyNonEmptyPaint() override; void ResourceLoadComplete( content::RenderFrameHost* render_frame_host, @@ -306,6 +312,9 @@ FramePermissionController permission_controller_; std::unique_ptr<NavigationPolicyHandler> navigation_policy_handler_; + // Current page scale. Updated by calling SetPageScale(). + float page_scale_ = 1.0; + // Session ID to use for fuchsia.media.AudioConsumer. Set with // SetMediaSessionId(). uint64_t media_session_id_ = 0;
diff --git a/fuchsia/engine/browser/frame_impl_browsertest.cc b/fuchsia/engine/browser/frame_impl_browsertest.cc index 8ae66daa..652fba3 100644 --- a/fuchsia/engine/browser/frame_impl_browsertest.cc +++ b/fuchsia/engine/browser/frame_impl_browsertest.cc
@@ -72,6 +72,7 @@ const char kPopupRedirectPath[] = "/popup_child.html"; const char kPopupMultiplePath[] = "/popup_multiple.html"; const char kVisibilityPath[] = "/visibility.html"; +const char kWaitSizePath[] = "/wait-size.html"; const char kPage1Title[] = "title 1"; const char kPage2Title[] = "title 2"; const char kPage3Title[] = "websql not available"; @@ -1329,6 +1330,116 @@ } } +// TODO(crbug.com/1058247): Re-enable this test on Arm64 when femu is available +// for that architecture. This test requires Vulkan and Scenic to properly +// signal the Views visibility. +#if defined(ARCH_CPU_ARM_FAMILY) +#define MAYBE_SetPageScale DISABLED_SetPageScale +#else +#define MAYBE_SetPageScale SetPageScale +#endif +IN_PROC_BROWSER_TEST_F(FrameImplTest, MAYBE_SetPageScale) { + fuchsia::web::FramePtr frame = CreateFrame(); + + auto view_tokens = scenic::ViewTokenPair::New(); + frame->CreateView(std::move(view_tokens.view_token)); + + // Attach the View to a Presenter, the page should be visible. + auto presenter = base::ComponentContextForProcess() + ->svc() + ->Connect<::fuchsia::ui::policy::Presenter>(); + presenter.set_error_handler( + [](zx_status_t) { ADD_FAILURE() << "Presenter disconnected."; }); + presenter->PresentOrReplaceView(std::move(view_tokens.view_holder_token), + nullptr); + + fuchsia::web::NavigationControllerPtr controller; + frame->GetNavigationController(controller.NewRequest()); + + net::test_server::EmbeddedTestServerHandle test_server_handle; + ASSERT_TRUE(test_server_handle = + embedded_test_server()->StartAndReturnHandle()); + GURL url = embedded_test_server()->GetURL(kWaitSizePath); + + EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse( + controller.get(), fuchsia::web::LoadUrlParams(), url.spec())); + navigation_listener_.RunUntilUrlAndTitleEquals(url, "done"); + + absl::optional<base::Value> default_dpr = + cr_fuchsia::ExecuteJavaScript(frame.get(), "window.devicePixelRatio"); + ASSERT_TRUE(default_dpr); + + // Update scale and verify that devicePixelRatio is updated accordingly. + const float kZoomInScale = 1.5; + frame->SetPageScale(kZoomInScale); + + absl::optional<base::Value> scaled_dpr = + cr_fuchsia::ExecuteJavaScript(frame.get(), "window.devicePixelRatio"); + ASSERT_TRUE(scaled_dpr); + + EXPECT_NEAR(scaled_dpr->GetDouble() / default_dpr->GetDouble(), kZoomInScale, + 1e-6); + + // Navigate to the same page on http://localhost. This is a different site, + // so it will be loaded in a new renderer process. Page scale value should be + // preserved. + GURL url2 = embedded_test_server()->GetURL("localhost", kWaitSizePath); + EXPECT_NE(url.host(), url2.host()); + EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse( + controller.get(), fuchsia::web::LoadUrlParams(), url2.spec())); + navigation_listener_.RunUntilUrlAndTitleEquals(url2, "done"); + + absl::optional<base::Value> dpr_after_navigation = + cr_fuchsia::ExecuteJavaScript(frame.get(), "window.devicePixelRatio"); + ASSERT_TRUE(scaled_dpr); + + EXPECT_EQ(dpr_after_navigation, scaled_dpr); + + // Reset the scale to 1.0 (default) and verify that reported DPR is equal to + // the same as when the frame was created. + frame->SetPageScale(1.0); + absl::optional<base::Value> dpr_after_reset = + cr_fuchsia::ExecuteJavaScript(frame.get(), "window.devicePixelRatio"); + ASSERT_TRUE(dpr_after_reset); + + EXPECT_EQ(dpr_after_reset.value(), default_dpr.value()); + + // Zoom out by setting scale to 0.5. + const float kZoomOutScale = 0.5; + frame->SetPageScale(kZoomOutScale); + + absl::optional<base::Value> zoomed_out_dpr = + cr_fuchsia::ExecuteJavaScript(frame.get(), "window.devicePixelRatio"); + ASSERT_TRUE(zoomed_out_dpr); + + EXPECT_NEAR(zoomed_out_dpr->GetDouble() / default_dpr->GetDouble(), + kZoomOutScale, 1e-6); + + // Create another frame. Verify that the scale factor is not applied to the + // new frame. + cr_fuchsia::TestNavigationListener navigation_listener2; + fuchsia::web::FramePtr frame2 = + WebEngineBrowserTest::CreateFrame(&navigation_listener2); + + view_tokens = scenic::ViewTokenPair::New(); + frame2->CreateView(std::move(view_tokens.view_token)); + + presenter->PresentOrReplaceView(std::move(view_tokens.view_holder_token), + nullptr); + + fuchsia::web::NavigationControllerPtr controller2; + frame2->GetNavigationController(controller2.NewRequest()); + EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse( + controller2.get(), fuchsia::web::LoadUrlParams(), url.spec())); + navigation_listener2.RunUntilUrlAndTitleEquals(url, "done"); + + absl::optional<base::Value> frame2_dpr = + cr_fuchsia::ExecuteJavaScript(frame2.get(), "window.devicePixelRatio"); + ASSERT_TRUE(frame2_dpr); + + EXPECT_EQ(frame2_dpr.value(), default_dpr.value()); +} + // Send a MessagePort to the content, then perform bidirectional messaging // over its channel. IN_PROC_BROWSER_TEST_F(FrameImplTest, PostMessageMessagePortDisconnected) {
diff --git a/fuchsia/engine/browser/web_engine_browser_context.cc b/fuchsia/engine/browser/web_engine_browser_context.cc index 47ac7e7e..f9a725e7 100644 --- a/fuchsia/engine/browser/web_engine_browser_context.cc +++ b/fuchsia/engine/browser/web_engine_browser_context.cc
@@ -71,7 +71,7 @@ WebEngineBrowserContext::~WebEngineBrowserContext() { SimpleKeyMap::GetInstance()->Dissociate(this); - NotifyWillBeDestroyed(this); + NotifyWillBeDestroyed(); if (resource_context_) { content::GetIOThreadTaskRunner({})->DeleteSoon(
diff --git a/fuchsia/engine/test/data/wait-size.html b/fuchsia/engine/test/data/wait-size.html new file mode 100644 index 0000000..74c41db --- /dev/null +++ b/fuchsia/engine/test/data/wait-size.html
@@ -0,0 +1,13 @@ +<!DOCTYPE html> +<html> + <script> + // Set title to "done" as soon as the page size is set. + function checkWindowSize() { + if (window.innerWidth > 0 && window.innerHeight > 0) + document.title = "done"; + } + window.onresize = checkWindowSize; + checkWindowSize(); + </script> + <body></body> +</html>
diff --git a/headless/DIR_METADATA b/headless/DIR_METADATA index 477ee6e..5eb4acf 100644 --- a/headless/DIR_METADATA +++ b/headless/DIR_METADATA
@@ -1,10 +1,10 @@ # Metadata information for this directory. # # For more information on DIR_METADATA files, see: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md # # For the schema of this file, see Metadata message: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto monorail { component: "Internals>Headless"
diff --git a/headless/lib/browser/headless_browser_context_impl.cc b/headless/lib/browser/headless_browser_context_impl.cc index 45caa59..e7e650a 100644 --- a/headless/lib/browser/headless_browser_context_impl.cc +++ b/headless/lib/browser/headless_browser_context_impl.cc
@@ -61,7 +61,7 @@ HeadlessBrowserContextImpl::~HeadlessBrowserContextImpl() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); SimpleKeyMap::GetInstance()->Dissociate(this); - NotifyWillBeDestroyed(this); + NotifyWillBeDestroyed(); // Destroy all web contents before shutting down storage partitions. web_contents_map_.clear();
diff --git a/headless/public/headless_browser.h b/headless/public/headless_browser.h index 80441a32..dfd6be4 100644 --- a/headless/public/headless_browser.h +++ b/headless/public/headless_browser.h
@@ -295,7 +295,7 @@ // } // // [1] -// https://chromium.googlesource.com/chromium/src/+/master/docs/linux/zygote.md +// https://chromium.googlesource.com/chromium/src/+/main/docs/linux/zygote.md void RunChildProcessIfNeeded(int argc, const char** argv); #else // In Windows, the headless browser may need to create child processes. This is
diff --git a/ios/chrome/browser/overlays/public/infobar_modal/save_address_profile_infobar_modal_overlay_request_config.h b/ios/chrome/browser/overlays/public/infobar_modal/save_address_profile_infobar_modal_overlay_request_config.h index 01c8960..0da4f1c 100644 --- a/ios/chrome/browser/overlays/public/infobar_modal/save_address_profile_infobar_modal_overlay_request_config.h +++ b/ios/chrome/browser/overlays/public/infobar_modal/save_address_profile_infobar_modal_overlay_request_config.h
@@ -8,6 +8,7 @@ #import <UIKit/UIKit.h> #include "base/containers/flat_map.h" #include "components/autofill/core/browser/data_model/autofill_profile.h" +#include "components/autofill/core/browser/data_model/autofill_profile_comparator.h" #include "ios/chrome/browser/overlays/public/overlay_request_config.h" class InfoBarIOS; @@ -64,9 +65,7 @@ // Computes |profile_diff_| based on the map of // profile difference data fetched from the delegate. void StoreProfileDiff( - const base::flat_map<autofill::ServerFieldType, - std::pair<std::u16string, std::u16string>>& - diff_map); + const std::vector<autofill::ProfileValueDifference>& profile_diff); // The InfoBar causing this modal. InfoBarIOS* infobar_ = nullptr;
diff --git a/ios/chrome/browser/overlays/public/infobar_modal/save_address_profile_infobar_modal_overlay_request_config.mm b/ios/chrome/browser/overlays/public/infobar_modal/save_address_profile_infobar_modal_overlay_request_config.mm index e429186..18aedab0a 100644 --- a/ios/chrome/browser/overlays/public/infobar_modal/save_address_profile_infobar_modal_overlay_request_config.mm +++ b/ios/chrome/browser/overlays/public/infobar_modal/save_address_profile_infobar_modal_overlay_request_config.mm
@@ -52,16 +52,15 @@ } void SaveAddressProfileModalRequestConfig::StoreProfileDiff( - const base::flat_map<autofill::ServerFieldType, - std::pair<std::u16string, std::u16string>>& diff_map) { - for (const auto& row : diff_map) { + const std::vector<autofill::ProfileValueDifference>& profile_diff) { + for (const auto& row : profile_diff) { [profile_diff_ setObject:@[ - base::SysUTF16ToNSString(row.second.first), - base::SysUTF16ToNSString(row.second.second) + base::SysUTF16ToNSString(row.first_value), + base::SysUTF16ToNSString(row.second_value) ] forKey:[NSNumber - numberWithInt:AutofillUITypeFromAutofillType(row.first)]]; + numberWithInt:AutofillUITypeFromAutofillType(row.type)]]; } }
diff --git a/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_promo_signin_coordinator.mm b/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_promo_signin_coordinator.mm index 3844ac1..1488ae55 100644 --- a/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_promo_signin_coordinator.mm +++ b/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_promo_signin_coordinator.mm
@@ -391,6 +391,21 @@ return self.interactionTransition; } +- (void)navigationController:(UINavigationController*)navigationController + didShowViewController:(UIViewController*)viewController + animated:(BOOL)animated { + DCHECK(navigationController == self.navigationController); + DCHECK(navigationController.viewControllers.count > 0); + DCHECK(navigationController.viewControllers[0] == + self.defaultAccountCoordinator.viewController); + if (self.navigationController.viewControllers.count == 1 && + self.accountChooserCoordinator) { + // AccountChooserCoordinator has been removed by "Back" button. + [self.accountChooserCoordinator stop]; + self.accountChooserCoordinator = nil; + } +} + #pragma mark - UIViewControllerTransitioningDelegate - (UIPresentationController*)
diff --git a/ios/chrome/browser/ui/infobars/modals/infobar_save_address_profile_table_view_controller.mm b/ios/chrome/browser/ui/infobars/modals/infobar_save_address_profile_table_view_controller.mm index 95cfc06c..915fed2 100644 --- a/ios/chrome/browser/ui/infobars/modals/infobar_save_address_profile_table_view_controller.mm +++ b/ios/chrome/browser/ui/infobars/modals/infobar_save_address_profile_table_view_controller.mm
@@ -8,6 +8,8 @@ #include "base/metrics/user_metrics.h" #include "base/metrics/user_metrics_action.h" #include "ios/chrome/browser/infobars/infobar_metrics_recorder.h" +#import "ios/chrome/browser/ui/autofill/autofill_ui_type.h" +#import "ios/chrome/browser/ui/autofill/autofill_ui_type_util.h" #import "ios/chrome/browser/ui/infobars/modals/infobar_modal_constants.h" #import "ios/chrome/browser/ui/infobars/modals/infobar_save_address_profile_modal_delegate.h" #import "ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.h" @@ -32,8 +34,6 @@ // Height of the space used by header/footer when none is set. Default is // |estimatedSection{Header|Footer}Height|. const CGFloat kDefaultHeaderFooterHeight = 10; -// Estimated height of the header/footer, used to speed the constraints. -const CGFloat kEstimatedHeaderFooterHeight = 50; } // namespace @@ -98,16 +98,13 @@ - (void)viewDidLoad { [super viewDidLoad]; + self.styler.tableViewBackgroundColor = [UIColor colorNamed:kBackgroundColor]; self.view.backgroundColor = [UIColor colorNamed:kBackgroundColor]; self.styler.cellBackgroundColor = [UIColor colorNamed:kBackgroundColor]; - if (self.isUpdateModal) { - self.tableView.estimatedSectionHeaderHeight = kEstimatedHeaderFooterHeight; - self.tableView.estimatedSectionFooterHeight = kEstimatedHeaderFooterHeight; - } else { - self.tableView.sectionHeaderHeight = 0; - } - [self.tableView - setSeparatorInset:UIEdgeInsetsMake(0, kTableViewHorizontalSpacing, 0, 0)]; + self.tableView.sectionHeaderHeight = 0; + + self.tableView.separatorInset = + UIEdgeInsetsMake(0, kTableViewSeparatorInsetWithIcon, 0, 0); // Configure the NavigationBar. UIBarButtonItem* cancelButton = [[UIBarButtonItem alloc] @@ -182,11 +179,28 @@ addTarget:self action:@selector(saveAddressProfileButtonWasPressed:) forControlEvents:UIControlEventTouchUpInside]; - } else if (itemType == ItemTypeAddress) { + } else if (itemType == ItemTypeAddress || itemType == ItemTypeUpdateOld) { TableViewImageCell* managedcell = base::mac::ObjCCastStrict<TableViewImageCell>(cell); - managedcell.textLabel.numberOfLines = - [[self.address componentsSeparatedByString:@"\n"] count]; + managedcell.textLabel.numberOfLines = 0; + managedcell.imageView.image = [managedcell.imageView.image + imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + [managedcell.imageView setTintColor:[UIColor colorNamed:kGrey400Color]]; + } else if (itemType == ItemTypePhoneNumber || + itemType == ItemTypeEmailAddress) { + TableViewImageCell* managedcell = + base::mac::ObjCCastStrict<TableViewImageCell>(cell); + managedcell.imageView.image = [managedcell.imageView.image + imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + [managedcell.imageView setTintColor:[UIColor colorNamed:kGrey400Color]]; + } else if (itemType == ItemTypeUpdateNew) { + TableViewImageCell* managedcell = + base::mac::ObjCCastStrict<TableViewImageCell>(cell); + managedcell.textLabel.numberOfLines = 0; + managedcell.imageView.image = [managedcell.imageView.image + imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + // Color is blue. + [managedcell.imageView setTintColor:[UIColor colorNamed:kBlueColor]]; } return cell; } @@ -253,8 +267,6 @@ } } - // TODO(crbug.com/1167062): Add image icons for the fields. - // TODO(crbug.com/1167062): Add line separators between sections. TableViewModel* model = self.tableViewModel; [model addSectionWithIdentifier:SectionIdentifierUpdateDescription]; @@ -271,12 +283,10 @@ } for (NSNumber* type in self.profileDataDiff) { if ([self.profileDataDiff[type][0] length] > 0) { - TableViewImageItem* item = - [[TableViewImageItem alloc] initWithType:ItemTypeUpdateNew]; - // TODO(crbug.com/1167062): Use type for determining the icons. - item.title = self.profileDataDiff[type][0]; - item.useCustomSeparator = YES; - [model addItem:item + [model addItem:[self detailItemWithType:ItemTypeUpdateNew + text:self.profileDataDiff[type][0] + iconImageName: + [self iconForAutofillInputTypeNumber:type]] toSectionWithIdentifier:SectionIdentifierUpdateModalNewFields]; } } @@ -290,12 +300,11 @@ forSectionWithIdentifier:SectionIdentifierUpdateModalOldFields]; for (NSNumber* type in self.profileDataDiff) { if ([self.profileDataDiff[type][1] length] > 0) { - TableViewImageItem* item = - [[TableViewImageItem alloc] initWithType:ItemTypeUpdateOld]; - // TODO(crbug.com/1167062): Use type for determining the icons. - item.title = self.profileDataDiff[type][1]; - item.useCustomSeparator = YES; - [model addItem:item + [model addItem:[self + detailItemWithType:ItemTypeUpdateOld + text:self.profileDataDiff[type][1] + iconImageName: + [self iconForAutofillInputTypeNumber:type]] toSectionWithIdentifier:SectionIdentifierUpdateModalOldFields]; } } @@ -311,23 +320,33 @@ TableViewModel* model = self.tableViewModel; [model addSectionWithIdentifier:SectionIdentifierSaveModalFields]; - TableViewImageItem* addressImageItem = - [[TableViewImageItem alloc] initWithType:ItemTypeAddress]; - addressImageItem.title = self.address; - [model addItem:addressImageItem + [model addItem:[self + detailItemWithType:ItemTypeAddress + text:self.address + iconImageName: + [self iconForAutofillUIType: + AutofillUITypeProfileHomeAddressStreet]] toSectionWithIdentifier:SectionIdentifierSaveModalFields]; - TableViewImageItem* emailImageItem = - [[TableViewImageItem alloc] initWithType:ItemTypeEmailAddress]; - emailImageItem.title = self.emailAddress; - [model addItem:emailImageItem - toSectionWithIdentifier:SectionIdentifierSaveModalFields]; - - TableViewImageItem* phoneImageItem = - [[TableViewImageItem alloc] initWithType:ItemTypePhoneNumber]; - phoneImageItem.title = self.phoneNumber; - [model addItem:phoneImageItem - toSectionWithIdentifier:SectionIdentifierSaveModalFields]; + if ([self.emailAddress length]) { + [model addItem:[self detailItemWithType:ItemTypeEmailAddress + text:self.emailAddress + iconImageName: + [self iconForAutofillUIType: + AutofillUITypeProfileEmailAddress]] + toSectionWithIdentifier:SectionIdentifierSaveModalFields]; + } + if ([self.phoneNumber length]) { + [model addItem: + [self + detailItemWithType:ItemTypePhoneNumber + text:self.phoneNumber + iconImageName: + [self + iconForAutofillUIType: + AutofillUITypeProfileHomePhoneWholeNumber]] + toSectionWithIdentifier:SectionIdentifierSaveModalFields]; + } [model addItem:[self saveUpdateButton] toSectionWithIdentifier:SectionIdentifierSaveModalFields]; @@ -364,4 +383,42 @@ return footer; } +- (NSString*)iconForAutofillUIType:(AutofillUIType)type { + switch (type) { + case AutofillUITypeNameFullWithHonorificPrefix: + return @"infobar_profile_icon"; + case AutofillUITypeAddressHomeAddress: + case AutofillUITypeProfileHomeAddressStreet: + return @"infobar_autofill_address_icon"; + case AutofillUITypeProfileEmailAddress: + return @"infobar_email_icon"; + case AutofillUITypeProfileHomePhoneWholeNumber: + return @"infobar_phone_icon"; + default: + NOTREACHED(); + return @""; + } +} + +- (NSString*)iconForAutofillInputTypeNumber:(NSNumber*)val { + return [self iconForAutofillUIType:(AutofillUIType)[val intValue]]; +} + +#pragma mark Item Constructors + +- (TableViewImageItem*)detailItemWithType:(NSInteger)type + text:(NSString*)text + iconImageName:(NSString*)iconImageName { + TableViewImageItem* detailItem = + [[TableViewImageItem alloc] initWithType:type]; + detailItem.title = text; + detailItem.enabled = NO; + detailItem.useCustomSeparator = YES; + if ([iconImageName length]) { + detailItem.image = [UIImage imageNamed:iconImageName]; + } + + return detailItem; +} + @end
diff --git a/ios/chrome/browser/ui/infobars/modals/infobar_save_address_profile_table_view_controller_unittest.mm b/ios/chrome/browser/ui/infobars/modals/infobar_save_address_profile_table_view_controller_unittest.mm index f738a04..38b8da3 100644 --- a/ios/chrome/browser/ui/infobars/modals/infobar_save_address_profile_table_view_controller_unittest.mm +++ b/ios/chrome/browser/ui/infobars/modals/infobar_save_address_profile_table_view_controller_unittest.mm
@@ -38,7 +38,7 @@ kCurrentAddressProfileSavedPrefKey : @(false), kIsUpdateModalPrefKey : @(true), kProfileDataDiffKey : @{ - @[ [NSNumber numberWithInt:AutofillUITypeProfileFullName] ] : + [NSNumber numberWithInt:AutofillUITypeNameFullWithHonorificPrefix] : @[ @"John Doe", @"John H. Doe" ] }, kUpdateModalDescriptionKey : @"For John Doe, 345 Spear Street"
diff --git a/ipc/DIR_METADATA b/ipc/DIR_METADATA index fb07a25..6d266b0 100644 --- a/ipc/DIR_METADATA +++ b/ipc/DIR_METADATA
@@ -1,10 +1,10 @@ # Metadata information for this directory. # # For more information on DIR_METADATA files, see: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md # # For the schema of this file, see Metadata message: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto monorail { component: "Internals>Core"
diff --git a/media/DIR_METADATA b/media/DIR_METADATA index 9f769ce..2dc14a4 100644 --- a/media/DIR_METADATA +++ b/media/DIR_METADATA
@@ -1,10 +1,10 @@ # Metadata information for this directory. # # For more information on DIR_METADATA files, see: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md # # For the schema of this file, see Metadata message: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto monorail { component: "Internals>Media"
diff --git a/media/audio/DIR_METADATA b/media/audio/DIR_METADATA index 99031e0..e80d7931 100644 --- a/media/audio/DIR_METADATA +++ b/media/audio/DIR_METADATA
@@ -1,10 +1,10 @@ # Metadata information for this directory. # # For more information on DIR_METADATA files, see: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md # # For the schema of this file, see Metadata message: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto monorail { component: "Internals>Media>Audio"
diff --git a/media/audio/fuchsia/DIR_METADATA b/media/audio/fuchsia/DIR_METADATA index e88f6232..abc57ac0f 100644 --- a/media/audio/fuchsia/DIR_METADATA +++ b/media/audio/fuchsia/DIR_METADATA
@@ -1,10 +1,10 @@ # Metadata information for this directory. # # For more information on DIR_METADATA files, see: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md # # For the schema of this file, see Metadata message: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto team_email: "cr-fuchsia@chromium.org" os: FUCHSIA \ No newline at end of file
diff --git a/media/capture/content/DIR_METADATA b/media/capture/content/DIR_METADATA index c46eabd..f689e00 100644 --- a/media/capture/content/DIR_METADATA +++ b/media/capture/content/DIR_METADATA
@@ -1,10 +1,10 @@ # Metadata information for this directory. # # For more information on DIR_METADATA files, see: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md # # For the schema of this file, see Metadata message: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto monorail { component: "Internals>Media>SurfaceCapture"
diff --git a/media/capture/video/DIR_METADATA b/media/capture/video/DIR_METADATA index dc21b38..ca45fde 100644 --- a/media/capture/video/DIR_METADATA +++ b/media/capture/video/DIR_METADATA
@@ -1,10 +1,10 @@ # Metadata information for this directory. # # For more information on DIR_METADATA files, see: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md # # For the schema of this file, see Metadata message: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto monorail { component: "Internals>Media>CameraCapture"
diff --git a/media/cast/DIR_METADATA b/media/cast/DIR_METADATA index 9e255559..7c577c4 100644 --- a/media/cast/DIR_METADATA +++ b/media/cast/DIR_METADATA
@@ -1,10 +1,10 @@ # Metadata information for this directory. # # For more information on DIR_METADATA files, see: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md # # For the schema of this file, see Metadata message: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto monorail { component: "Internals>Cast>Streaming"
diff --git a/media/filters/fuchsia/DIR_METADATA b/media/filters/fuchsia/DIR_METADATA index e88f6232..abc57ac0f 100644 --- a/media/filters/fuchsia/DIR_METADATA +++ b/media/filters/fuchsia/DIR_METADATA
@@ -1,10 +1,10 @@ # Metadata information for this directory. # # For more information on DIR_METADATA files, see: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md # # For the schema of this file, see Metadata message: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto team_email: "cr-fuchsia@chromium.org" os: FUCHSIA \ No newline at end of file
diff --git a/media/filters/fuchsia/fuchsia_video_decoder.cc b/media/filters/fuchsia/fuchsia_video_decoder.cc index 44ad52ac..e5397b82 100644 --- a/media/filters/fuchsia/fuchsia_video_decoder.cc +++ b/media/filters/fuchsia/fuchsia_video_decoder.cc
@@ -55,24 +55,28 @@ // Number of output buffers allocated "for camping". This value is passed to // sysmem to ensure that we get one output buffer for the frame currently // displayed on the screen. -const uint32_t kOutputBuffersForCamping = 1; +constexpr uint32_t kOutputBuffersForCamping = 1; // Maximum number of frames we expect to have queued up while playing video. // Higher values require more memory for output buffers. Lower values make it // more likely that renderer will stall because decoded frames are not available // on time. -const uint32_t kMaxUsedOutputBuffers = 5; +constexpr uint32_t kMaxUsedOutputBuffers = 5; // Use 2 buffers for decoder input. Limiting total number of buffers to 2 allows // to minimize required memory without significant effect on performance. -const size_t kNumInputBuffers = 2; +constexpr size_t kNumInputBuffers = 2; // Some codecs do not support splitting video frames across multiple input // buffers, so the buffers need to be large enough to fit all video frames. The -// buffer size is calculated to fit 1080p frame with MinCR=2 (per H264 spec), -// plus 128KiB for SEI/SPS/PPS. (note that the same size is used for all codecs, -// not just H264). -const size_t kInputBufferSize = 1920 * 1080 * 3 / 2 / 2 + 128 * 1024; +// buffer size is calculated to fit 1080p I420 frame with MinCR=2 (per H264 +// spec), plus 128KiB for SEI/SPS/PPS. (note that the same size is used for all +// codecs, not just H264). +constexpr size_t kInputBufferSize = 1920 * 1080 * 3 / 2 / 2 + 128 * 1024; + +// Input buffers are allocate once per decoder, the |buffer_lifetime_ordinal| is +// always the same. +constexpr uint64_t kInputBufferLifetimeOrdinal = 1; // Helper used to hold mailboxes for the output textures. OutputMailbox may // outlive FuchsiaVideoDecoder if is referenced by a VideoFrame. @@ -224,8 +228,6 @@ // Event handlers for |decoder_|. void OnStreamFailed(uint64_t stream_lifetime_ordinal, fuchsia::media::StreamError error); - void OnInputConstraints( - fuchsia::media::StreamBufferConstraints input_constraints); void OnFreeInputPacket(fuchsia::media::PacketHeader free_input_packet); void OnOutputConstraints( fuchsia::media::StreamOutputConstraints output_constraints); @@ -236,6 +238,8 @@ void OnOutputEndOfStream(uint64_t stream_lifetime_ordinal, bool error_detected_before); + void AllocateInputBuffers(); + // Drops all pending input buffers and then calls all pending DecodeCB with // |status|. Returns true if the decoder still exists. bool DropInputQueue(DecodeStatus status); @@ -310,7 +314,6 @@ VmoBufferWriterQueue input_writer_queue_; // Input buffers for |decoder_|. - uint64_t input_buffer_lifetime_ordinal_ = 1; std::unique_ptr<SysmemCollectionClient> input_buffer_collection_; base::flat_map<size_t, InputDecoderPacket> in_flight_input_packets_; @@ -462,8 +465,6 @@ decoder_.events().OnStreamFailed = fit::bind_member(this, &FuchsiaVideoDecoder::OnStreamFailed); - decoder_.events().OnInputConstraints = - fit::bind_member(this, &FuchsiaVideoDecoder::OnInputConstraints); decoder_.events().OnFreeInputPacket = fit::bind_member(this, &FuchsiaVideoDecoder::OnFreeInputPacket); decoder_.events().OnOutputConstraints = @@ -477,6 +478,8 @@ decoder_->EnableOnStreamFailed(); + AllocateInputBuffers(); + current_codec_ = config.codec(); std::move(done_callback).Run(OkStatus()); @@ -581,27 +584,19 @@ OnError(); } -void FuchsiaVideoDecoder::OnInputConstraints( - fuchsia::media::StreamBufferConstraints stream_constraints) { - // Buffer lifetime ordinal is an odd number incremented by 2 for each buffer - // generation as required by StreamProcessor. - input_buffer_lifetime_ordinal_ += 2; - decoder_input_constraints_ = std::move(stream_constraints); - - ReleaseInputBuffers(); +void FuchsiaVideoDecoder::AllocateInputBuffers() { + DCHECK(!input_buffer_collection_); input_buffer_collection_ = sysmem_allocator_.AllocateNewCollection(); - input_buffer_collection_->CreateSharedToken(base::BindOnce( &FuchsiaVideoDecoder::SetInputBufferCollection, base::Unretained(this))); - if (decryptor_) { input_buffer_collection_->CreateSharedToken(base::BindOnce( &FuchsiaSecureStreamDecryptor::SetOutputBufferCollectionToken, base::Unretained(decryptor_.get()))); } - // Create buffer constrains for the input buffer collection. + // Create buffer constraints for the input buffer collection. fuchsia::sysmem::BufferCollectionConstraints buffer_constraints; if (decryptor_) { buffer_constraints.usage.none = fuchsia::sysmem::noneUsage; @@ -630,9 +625,8 @@ void FuchsiaVideoDecoder::SetInputBufferCollection( fuchsia::sysmem::BufferCollectionTokenPtr token) { fuchsia::media::StreamBufferPartialSettings settings; - settings.set_buffer_lifetime_ordinal(input_buffer_lifetime_ordinal_); - settings.set_buffer_constraints_version_ordinal( - decoder_input_constraints_->buffer_constraints_version_ordinal()); + settings.set_buffer_lifetime_ordinal(kInputBufferLifetimeOrdinal); + settings.set_buffer_constraints_version_ordinal(0); settings.set_sysmem_token(std::move(token)); decoder_->SetInputBufferPartialSettings(std::move(settings)); } @@ -658,7 +652,7 @@ StreamProcessorHelper::IoPacket packet) { fuchsia::media::Packet media_packet; media_packet.mutable_header()->set_buffer_lifetime_ordinal( - input_buffer_lifetime_ordinal_); + kInputBufferLifetimeOrdinal); media_packet.mutable_header()->set_packet_index(packet.buffer_index()); media_packet.set_buffer_index(packet.buffer_index()); media_packet.set_timestamp_ish(packet.timestamp().InNanoseconds()); @@ -685,18 +679,12 @@ void FuchsiaVideoDecoder::OnFreeInputPacket( fuchsia::media::PacketHeader free_input_packet) { - if (!free_input_packet.has_buffer_lifetime_ordinal() || - !free_input_packet.has_packet_index()) { + if (!free_input_packet.has_packet_index()) { DLOG(ERROR) << "Received OnFreeInputPacket() with missing required fields."; OnError(); return; } - if (free_input_packet.buffer_lifetime_ordinal() != - input_buffer_lifetime_ordinal_) { - return; - } - auto it = in_flight_input_packets_.find(free_input_packet.packet_index()); if (it == in_flight_input_packets_.end()) { DLOG(ERROR) << "Received OnFreeInputPacket() with invalid packet index.";
diff --git a/media/fuchsia/cdm/fuchsia_stream_decryptor.cc b/media/fuchsia/cdm/fuchsia_stream_decryptor.cc index 586d22ac..82b2754 100644 --- a/media/fuchsia/cdm/fuchsia_stream_decryptor.cc +++ b/media/fuchsia/cdm/fuchsia_stream_decryptor.cc
@@ -100,7 +100,9 @@ size_t min_buffer_size) : processor_(std::move(processor), this), min_buffer_size_(min_buffer_size), - allocator_("CrFuchsiaStreamDecryptorBase") {} + allocator_("CrFuchsiaStreamDecryptorBase") { + AllocateInputBuffers(); +} FuchsiaStreamDecryptorBase::~FuchsiaStreamDecryptorBase() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); @@ -126,14 +128,12 @@ input_writer_queue_.ResetQueue(); } -// StreamProcessorHelper::Client implementation: -void FuchsiaStreamDecryptorBase::AllocateInputBuffers( - const fuchsia::media::StreamBufferConstraints& stream_constraints) { +void FuchsiaStreamDecryptorBase::AllocateInputBuffers() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); input_buffer_collection_ = allocator_.AllocateNewCollection(); input_buffer_collection_->CreateSharedToken( - base::BindOnce(&StreamProcessorHelper::CompleteInputBuffersAllocation, + base::BindOnce(&StreamProcessorHelper::SetInputBufferCollectionToken, base::Unretained(&processor_))); input_buffer_collection_->Initialize( VmoBuffer::GetRecommendedConstraints(kMinBufferCount, min_buffer_size_,
diff --git a/media/fuchsia/cdm/fuchsia_stream_decryptor.h b/media/fuchsia/cdm/fuchsia_stream_decryptor.h index 377c69a..792c5e6 100644 --- a/media/fuchsia/cdm/fuchsia_stream_decryptor.h +++ b/media/fuchsia/cdm/fuchsia_stream_decryptor.h
@@ -28,10 +28,9 @@ protected: // StreamProcessorHelper::Client overrides. - void AllocateInputBuffers( - const fuchsia::media::StreamBufferConstraints& stream_constraints) final; void OnOutputFormat(fuchsia::media::StreamOutputFormat format) final; + void AllocateInputBuffers(); void DecryptInternal(scoped_refptr<DecoderBuffer> encrypted); void ResetStream();
diff --git a/media/fuchsia/common/stream_processor_helper.cc b/media/fuchsia/common/stream_processor_helper.cc index 17b95be..51e9cec 100644 --- a/media/fuchsia/common/stream_processor_helper.cc +++ b/media/fuchsia/common/stream_processor_helper.cc
@@ -9,6 +9,14 @@ namespace media { +namespace { + +// Input buffers are allocate once per decoder, the |buffer_lifetime_ordinal| is +// always the same. +constexpr uint64_t kInputBufferLifetimeOrdinal = 1; + +} // namespace + StreamProcessorHelper::IoPacket::IoPacket(size_t index, size_t offset, size_t size, @@ -68,8 +76,6 @@ processor_.events().OnStreamFailed = fit::bind_member(this, &StreamProcessorHelper::OnStreamFailed); - processor_.events().OnInputConstraints = - fit::bind_member(this, &StreamProcessorHelper::OnInputConstraints); processor_.events().OnFreeInputPacket = fit::bind_member(this, &StreamProcessorHelper::OnFreeInputPacket); processor_.events().OnOutputConstraints = @@ -94,7 +100,7 @@ fuchsia::media::Packet packet; packet.mutable_header()->set_buffer_lifetime_ordinal( - input_buffer_lifetime_ordinal_); + kInputBufferLifetimeOrdinal); packet.mutable_header()->set_packet_index(input.buffer_index()); packet.set_buffer_index(packet.header().packet_index()); packet.set_timestamp_ish(input.timestamp().InNanoseconds()); @@ -161,36 +167,16 @@ OnError(); } -void StreamProcessorHelper::OnInputConstraints( - fuchsia::media::StreamBufferConstraints constraints) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - // Buffer lifetime ordinal is an odd number incremented by 2 for each buffer - // generation as required by StreamProcessor. - input_buffer_lifetime_ordinal_ += 2; - - DCHECK(input_packets_.empty()); - input_buffer_constraints_ = std::move(constraints); - - client_->AllocateInputBuffers(input_buffer_constraints_); -} - void StreamProcessorHelper::OnFreeInputPacket( fuchsia::media::PacketHeader free_input_packet) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - if (!free_input_packet.has_buffer_lifetime_ordinal() || - !free_input_packet.has_packet_index()) { + if (!free_input_packet.has_packet_index()) { DLOG(ERROR) << "Received OnFreeInputPacket() with missing required fields."; OnError(); return; } - if (free_input_packet.buffer_lifetime_ordinal() != - input_buffer_lifetime_ordinal_) { - return; - } - auto it = input_packets_.find(free_input_packet.packet_index()); if (it == input_packets_.end()) { DLOG(ERROR) << "Received OnFreeInputPacket() with invalid packet index."; @@ -323,14 +309,13 @@ client_->OnError(); } -void StreamProcessorHelper::CompleteInputBuffersAllocation( +void StreamProcessorHelper::SetInputBufferCollectionToken( fuchsia::sysmem::BufferCollectionTokenPtr sysmem_token) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(!input_buffer_constraints_.IsEmpty()); + fuchsia::media::StreamBufferPartialSettings settings; - settings.set_buffer_lifetime_ordinal(input_buffer_lifetime_ordinal_); - settings.set_buffer_constraints_version_ordinal( - input_buffer_constraints_.buffer_constraints_version_ordinal()); + settings.set_buffer_lifetime_ordinal(kInputBufferLifetimeOrdinal); + settings.set_buffer_constraints_version_ordinal(0); settings.set_sysmem_token(std::move(sysmem_token)); processor_->SetInputBufferPartialSettings(std::move(settings)); }
diff --git a/media/fuchsia/common/stream_processor_helper.h b/media/fuchsia/common/stream_processor_helper.h index 78f24701..ad16a2d 100644 --- a/media/fuchsia/common/stream_processor_helper.h +++ b/media/fuchsia/common/stream_processor_helper.h
@@ -76,11 +76,8 @@ class Client { public: - // Allocate input/output buffers with the given constraints. Client should - // call ProvideInput/OutputBufferCollectionToken to finish the buffer - // allocation flow. - virtual void AllocateInputBuffers( - const fuchsia::media::StreamBufferConstraints& stream_constraints) = 0; + // Allocate output buffers with the given constraints. Client should call + // ProvideIOutputBufferCollectionToken to finish the buffer allocation flow. virtual void AllocateOutputBuffers( const fuchsia::media::StreamBufferConstraints& stream_constraints) = 0; @@ -118,10 +115,12 @@ // StreamProcessor without calling Reset. void ProcessEos(); - // Provide input/output BufferCollectionToken to finish StreamProcessor buffer - // setup flow. - void CompleteInputBuffersAllocation( + // Sets buffer collection tocken to use for input buffers. + void SetInputBufferCollectionToken( fuchsia::sysmem::BufferCollectionTokenPtr token); + + // Provide output BufferCollectionToken to finish StreamProcessor buffer + // setup flow. Should be called only after AllocateOutputBuffers. void CompleteOutputBuffersAllocation( fuchsia::sysmem::BufferCollectionTokenPtr token); @@ -157,10 +156,6 @@ // stream_lifetime_ordinal_. bool active_stream_ = false; - // Input buffers. - uint64_t input_buffer_lifetime_ordinal_ = 1; - fuchsia::media::StreamBufferConstraints input_buffer_constraints_; - // Map from packet index to corresponding input IoPacket. IoPacket should be // owned by this class until StreamProcessor released the buffer. base::flat_map<size_t, IoPacket> input_packets_;
diff --git a/media/gpu/vaapi/test/av1_decoder.cc b/media/gpu/vaapi/test/av1_decoder.cc index cbe666e..c7e2f7f 100644 --- a/media/gpu/vaapi/test/av1_decoder.cc +++ b/media/gpu/vaapi/test/av1_decoder.cc
@@ -735,7 +735,7 @@ default: // The OBU Parser can only produce bit depths of 8, 10, and 12; we should // not hit any other cases. See - // https://source.chromium.org/chromium/chromium/src/+/master:third_party/libgav1/src/src/obu_parser.cc;l=144-150;drc=7880d0cc1d1976012dbec8a1bb982191ac49b7f4 + // https://source.chromium.org/chromium/chromium/src/+/main:third_party/libgav1/src/src/obu_parser.cc;l=144-150;drc=7880d0cc1d1976012dbec8a1bb982191ac49b7f4 NOTREACHED() << "Invalid color bit depth: " << current_sequence_header_->color_config.bitdepth; }
diff --git a/media/gpu/vaapi/test/vp9_decoder.cc b/media/gpu/vaapi/test/vp9_decoder.cc index 322d65a..7f93201 100644 --- a/media/gpu/vaapi/test/vp9_decoder.cc +++ b/media/gpu/vaapi/test/vp9_decoder.cc
@@ -127,7 +127,7 @@ const VAProfile profile = GetProfile(frame_hdr); // Note: some streams may fail to decode; see - // https://source.chromium.org/chromium/chromium/src/+/master:media/gpu/vp9_decoder.cc;l=249-285;drc=3893688a88eb1b4cf39e346fd8f8c743ad255469 + // https://source.chromium.org/chromium/chromium/src/+/main:media/gpu/vp9_decoder.cc;l=249-285;drc=3893688a88eb1b4cf39e346fd8f8c743ad255469 if (!va_config_ || va_config_->profile() != profile) { va_context_.reset(); va_config_ = std::make_unique<ScopedVAConfig>(va_device_, profile,
diff --git a/media/midi/DIR_METADATA b/media/midi/DIR_METADATA index d6aec82b..b44dd56 100644 --- a/media/midi/DIR_METADATA +++ b/media/midi/DIR_METADATA
@@ -1,10 +1,10 @@ # Metadata information for this directory. # # For more information on DIR_METADATA files, see: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md # # For the schema of this file, see Metadata message: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto monorail { component: "Blink>WebMIDI"
diff --git a/media/muxers/DIR_METADATA b/media/muxers/DIR_METADATA index af1480e..25b8514 100644 --- a/media/muxers/DIR_METADATA +++ b/media/muxers/DIR_METADATA
@@ -1,10 +1,10 @@ # Metadata information for this directory. # # For more information on DIR_METADATA files, see: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md # # For the schema of this file, see Metadata message: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto monorail { component: "Blink>MediaRecording"
diff --git a/media/remoting/DIR_METADATA b/media/remoting/DIR_METADATA index 9e255559..7c577c4 100644 --- a/media/remoting/DIR_METADATA +++ b/media/remoting/DIR_METADATA
@@ -1,10 +1,10 @@ # Metadata information for this directory. # # For more information on DIR_METADATA files, see: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md # # For the schema of this file, see Metadata message: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto monorail { component: "Internals>Cast>Streaming"
diff --git a/media/test/data/README.md b/media/test/data/README.md index f0c090c6..d96170b2 100644 --- a/media/test/data/README.md +++ b/media/test/data/README.md
@@ -1215,4 +1215,4 @@ * opus-trimming-test.webm [libaom test vectors]: https://aomedia.googlesource.com/aom/+/master/test/test_vectors.cc -[libaom LICENSE]: https://source.chromium.org/chromium/chromium/src/+/master:media/test/data/licenses/AOM-LICENSE +[libaom LICENSE]: https://source.chromium.org/chromium/chromium/src/+/main:media/test/data/licenses/AOM-LICENSE
diff --git a/media/webrtc/DIR_METADATA b/media/webrtc/DIR_METADATA index 7ae006c..e28b9ae8 100644 --- a/media/webrtc/DIR_METADATA +++ b/media/webrtc/DIR_METADATA
@@ -1,10 +1,10 @@ # Metadata information for this directory. # # For more information on DIR_METADATA files, see: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md # # For the schema of this file, see Metadata message: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto monorail { component: "Blink>WebRTC>Audio"
diff --git a/printing/backend/cups_helper.cc b/printing/backend/cups_helper.cc index c2c8746..6503ad5 100644 --- a/printing/backend/cups_helper.cc +++ b/printing/backend/cups_helper.cc
@@ -15,7 +15,6 @@ #include "base/files/file_util.h" #include "base/files/scoped_file.h" #include "base/logging.h" -#include "base/macros.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/time/time.h" @@ -598,18 +597,21 @@ return false; } - ppd_file_t* ppd = ppdOpenFd(ppd_fd.get()); + // We release ownership of `ppd_fd` here because ppdOpenFd() assumes ownership + // of it in all but one case (see below). + int unowned_ppd_fd = ppd_fd.release(); + ppd_file_t* ppd = ppdOpenFd(unowned_ppd_fd); if (!ppd) { int line = 0; ppd_status_t ppd_status = ppdLastError(&line); LOG(ERROR) << "Failed to open PDD file: error " << ppd_status << " at line " << line << ", " << ppdErrorString(ppd_status); - if (ppd_status != PPD_FILE_OPEN_ERROR) { - // When the error is not from opening the file then the CUPS library - // internals will have already closed the file descriptor. It is - // important to not close the file a second time (when ScopedFD destructor - // fires), so we release the descriptor prior to that. - ignore_result(ppd_fd.release()); + if (ppd_status == PPD_FILE_OPEN_ERROR) { + // Normally ppdOpenFd assumes ownership of the file descriptor we give it, + // regardless of success or failure. The one exception is when it fails + // with PPD_FILE_OPEN_ERROR. In that case ownership is retained by the + // caller, so we must explicitly close it. + close(unowned_ppd_fd); } return false; } @@ -693,10 +695,6 @@ } ppdClose(ppd); - // The CUPS library internals close the file descriptor upon successfully - // reading it. Explicitly release the `ScopedFD` to prevent a crash caused - // by a bad file descriptor. - ignore_result(ppd_fd.release()); *printer_info = caps; return true;
diff --git a/services/network/network_service.cc b/services/network/network_service.cc index 1fea71a..143c7bd 100644 --- a/services/network/network_service.cc +++ b/services/network/network_service.cc
@@ -623,6 +623,7 @@ auto config = std::make_unique<os_crypt::Config>(); config->store = crypt_config->store; config->product_name = crypt_config->product_name; + config->application_name = crypt_config->application_name; config->main_thread_runner = base::ThreadTaskRunnerHandle::Get(); config->should_use_preference = crypt_config->should_use_preference; config->user_data_path = crypt_config->user_data_path;
diff --git a/services/network/public/mojom/network_service.mojom b/services/network/public/mojom/network_service.mojom index 8752c4b..f7b1e99 100644 --- a/services/network/public/mojom/network_service.mojom +++ b/services/network/public/mojom/network_service.mojom
@@ -99,6 +99,13 @@ // The product name to use for permission prompts. string product_name; + // The application name to store the crypto key against. For Chromium/Chrome + // builds leave this unset and it will default correctly. This config option + // is for embedders to provide their application name in place of "Chromium". + // Only used when the allow_runtime_configurable_key_storage feature is + // enabled + string application_name; + // Controls whether preference on using or ignoring backends is used. bool should_use_preference;
diff --git a/sql/DIR_METADATA b/sql/DIR_METADATA index 3576726..0e61939 100644 --- a/sql/DIR_METADATA +++ b/sql/DIR_METADATA
@@ -1,10 +1,10 @@ # Metadata information for this directory. # # For more information on DIR_METADATA files, see: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md # # For the schema of this file, see Metadata message: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto monorail { component: "Internals>Storage"
diff --git a/testing/buildbot/chromium.perf.json b/testing/buildbot/chromium.perf.json index 2fde9c8..768abbc157 100644 --- a/testing/buildbot/chromium.perf.json +++ b/testing/buildbot/chromium.perf.json
@@ -553,7 +553,8 @@ "trigger_script": { "args": [ "--multiple-dimension-script-verbose", - "True" + "True", + "--use-dynamic-shards" ], "requires_simultaneous_shard_dispatch": true, "script": "//testing/trigger_scripts/perf_device_trigger.py"
diff --git a/testing/buildbot/internal.chromeos.fyi.json b/testing/buildbot/internal.chromeos.fyi.json index 7273358..f53c74e 100644 --- a/testing/buildbot/internal.chromeos.fyi.json +++ b/testing/buildbot/internal.chromeos.fyi.json
@@ -1237,80 +1237,88 @@ "args": [], "cros_board": "coral", "cros_img": "coral-release/R92-13970.0.0", - "name": "mainline_lacros_tast_tests_CORAL_TOT", + "name": "lacros_fyi_tast_tests_CORAL_TOT", "swarming": {}, "tast_expr": "(\"group:mainline\" && \"dep:lacros\")", - "test": "mainline_lacros_tast_tests", + "test": "lacros_fyi_tast_tests", + "test_id_prefix": "ninja://chromeos/lacros:lacros_fyi_tast_tests/", "timeout_sec": 10800 }, { "args": [], "cros_board": "eve", "cros_img": "eve-release/R92-13970.0.0", - "name": "mainline_lacros_tast_tests_EVE_TOT", + "name": "lacros_fyi_tast_tests_EVE_TOT", "swarming": {}, "tast_expr": "(\"group:mainline\" && \"dep:lacros\")", - "test": "mainline_lacros_tast_tests", + "test": "lacros_fyi_tast_tests", + "test_id_prefix": "ninja://chromeos/lacros:lacros_fyi_tast_tests/", "timeout_sec": 10800 }, { "args": [], "cros_board": "kefka", "cros_img": "kefka-release/R92-13970.0.0", - "name": "mainline_lacros_tast_tests_KEFKA_TOT", + "name": "lacros_fyi_tast_tests_KEFKA_TOT", "swarming": {}, "tast_expr": "(\"group:mainline\" && \"dep:lacros\")", - "test": "mainline_lacros_tast_tests", + "test": "lacros_fyi_tast_tests", + "test_id_prefix": "ninja://chromeos/lacros:lacros_fyi_tast_tests/", "timeout_sec": 10800 }, { "args": [], "cros_board": "kip", "cros_img": "kip-release/R92-13970.0.0", - "name": "mainline_lacros_tast_tests_KIP_TOT", + "name": "lacros_fyi_tast_tests_KIP_TOT", "swarming": {}, "tast_expr": "(\"group:mainline\" && \"dep:lacros\")", - "test": "mainline_lacros_tast_tests", + "test": "lacros_fyi_tast_tests", + "test_id_prefix": "ninja://chromeos/lacros:lacros_fyi_tast_tests/", "timeout_sec": 10800 }, { "args": [], "cros_board": "octopus", "cros_img": "octopus-release/R92-13970.0.0", - "name": "mainline_lacros_tast_tests_OCTOPUS_TOT", + "name": "lacros_fyi_tast_tests_OCTOPUS_TOT", "swarming": {}, "tast_expr": "(\"group:mainline\" && \"dep:lacros\")", - "test": "mainline_lacros_tast_tests", + "test": "lacros_fyi_tast_tests", + "test_id_prefix": "ninja://chromeos/lacros:lacros_fyi_tast_tests/", "timeout_sec": 10800 }, { "args": [], "cros_board": "snappy", "cros_img": "snappy-release/R92-13970.0.0", - "name": "mainline_lacros_tast_tests_SNAPPY_TOT", + "name": "lacros_fyi_tast_tests_SNAPPY_TOT", "swarming": {}, "tast_expr": "(\"group:mainline\" && \"dep:lacros\")", - "test": "mainline_lacros_tast_tests", + "test": "lacros_fyi_tast_tests", + "test_id_prefix": "ninja://chromeos/lacros:lacros_fyi_tast_tests/", "timeout_sec": 10800 }, { "args": [], "cros_board": "octopus", "cros_img": "octopus-release/R91-13904.22.0", - "name": "mainline_lacros_tast_tests_OCTOPUS_TOT-1", + "name": "lacros_fyi_tast_tests_OCTOPUS_TOT-1", "swarming": {}, "tast_expr": "(\"group:mainline\" && \"dep:lacros\")", - "test": "mainline_lacros_tast_tests", + "test": "lacros_fyi_tast_tests", + "test_id_prefix": "ninja://chromeos/lacros:lacros_fyi_tast_tests/", "timeout_sec": 10800 }, { "args": [], "cros_board": "octopus", "cros_img": "octopus-release/R90-13816.80.0", - "name": "mainline_lacros_tast_tests_OCTOPUS_TOT-2", + "name": "lacros_fyi_tast_tests_OCTOPUS_TOT-2", "swarming": {}, "tast_expr": "(\"group:mainline\" && \"dep:lacros\")", - "test": "mainline_lacros_tast_tests", + "test": "lacros_fyi_tast_tests", + "test_id_prefix": "ninja://chromeos/lacros:lacros_fyi_tast_tests/", "timeout_sec": 10800 } ]
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl index ea44486..cca7021d 100644 --- a/testing/buildbot/test_suites.pyl +++ b/testing/buildbot/test_suites.pyl
@@ -4218,7 +4218,7 @@ }, 'lacros_skylab_poc': { - 'mainline_lacros_tast_tests': { + 'lacros_fyi_tast_tests': { 'tast_expr': '("group:mainline" && "dep:lacros")', 'timeout_sec': 10800, },
diff --git a/testing/trigger_scripts/perf_device_trigger.py b/testing/trigger_scripts/perf_device_trigger.py index d12a977..9f26a94 100755 --- a/testing/trigger_scripts/perf_device_trigger.py +++ b/testing/trigger_scripts/perf_device_trigger.py
@@ -114,6 +114,9 @@ builder=builder, num_of_shards=num_of_shards ) + for shard_index, bot_index in selected_config: + bot_id = self._bot_configs[bot_index]['id'] + shard_map['extra_infos']['bot #%s' % shard_index] = bot_id return shard_map def append_additional_args(self, args, shard_index):
diff --git a/third_party/blink/public/mojom/link_to_text/link_to_text.mojom b/third_party/blink/public/mojom/link_to_text/link_to_text.mojom index cc29a81f..319b693 100644 --- a/third_party/blink/public/mojom/link_to_text/link_to_text.mojom +++ b/third_party/blink/public/mojom/link_to_text/link_to_text.mojom
@@ -5,6 +5,8 @@ [JavaPackage="org.chromium.blink.mojom"] module blink.mojom; +import "ui/gfx/geometry/mojom/geometry.mojom"; + // TextFragmentReceiver is used for requesting renderer to perform text fragment // operations on the main frame, mainly generating and removing fragments. // Implemented in renderer. @@ -25,4 +27,7 @@ // Request text fragment selectors for existing highlights. GetExistingSelectors() => (array<string> selectors); + + // Request the first text fragment rectangle relative to the viewport + ExtractFirstFragmentRect() => (gfx.mojom.Rect bounds); };
diff --git a/third_party/blink/public/mojom/web_feature/web_feature.mojom b/third_party/blink/public/mojom/web_feature/web_feature.mojom index 22fa14a..76a092c 100644 --- a/third_party/blink/public/mojom/web_feature/web_feature.mojom +++ b/third_party/blink/public/mojom/web_feature/web_feature.mojom
@@ -3230,6 +3230,9 @@ kClientHintsPrefersColorScheme = 3915, kOverscrollBehaviorWillBeFixed = 3916, kControlledWorkerWillBeUncontrolled = 3917, + kARIATouchpassthroughAttribute = 3918, + kARIAVirtualcontentAttribute = 3919, + kAccessibilityTouchPassthroughSet = 3920, // Add new features immediately above this line. Don't change assigned // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/blink/renderer/core/animation/color_property_functions.cc b/third_party/blink/renderer/core/animation/color_property_functions.cc index 0975b09..b1a4d4a4 100644 --- a/third_party/blink/renderer/core/animation/color_property_functions.cc +++ b/third_party/blink/renderer/core/animation/color_property_functions.cc
@@ -18,6 +18,10 @@ const CSSProperty& property, const ComputedStyle& style) { switch (property.PropertyID()) { + case CSSPropertyID::kAccentColor: + if (style.AccentColor().IsAutoColor()) + return nullptr; + return style.AccentColor().ToStyleColor(); case CSSPropertyID::kBackgroundColor: return style.BackgroundColor(); case CSSPropertyID::kBorderLeftColor: @@ -64,6 +68,8 @@ const CSSProperty& property, const ComputedStyle& style) { switch (property.PropertyID()) { + case CSSPropertyID::kAccentColor: + return style.AccentColor(); case CSSPropertyID::kBackgroundColor: return style.InternalVisitedBackgroundColor(); case CSSPropertyID::kBorderLeftColor: @@ -113,6 +119,9 @@ const Color& color) { StyleColor style_color(color); switch (property.PropertyID()) { + case CSSPropertyID::kAccentColor: + style.SetAccentColor(StyleAutoColor(color)); + return; case CSSPropertyID::kBackgroundColor: style.SetBackgroundColor(style_color); return; @@ -166,6 +175,9 @@ const Color& color) { StyleColor style_color(color); switch (property.PropertyID()) { + case CSSPropertyID::kAccentColor: + // The accent-color property is not valid for :visited. + return; case CSSPropertyID::kBackgroundColor: style.SetInternalVisitedBackgroundColor(style_color); return;
diff --git a/third_party/blink/renderer/core/animation/css_interpolation_types_map.cc b/third_party/blink/renderer/core/animation/css_interpolation_types_map.cc index 4caf781..5e248b03 100644 --- a/third_party/blink/renderer/core/animation/css_interpolation_types_map.cc +++ b/third_party/blink/renderer/core/animation/css_interpolation_types_map.cc
@@ -204,6 +204,7 @@ applicable_types->push_back( std::make_unique<CSSNumberInterpolationType>(used_property)); break; + case CSSPropertyID::kAccentColor: case CSSPropertyID::kBackgroundColor: case CSSPropertyID::kBorderBottomColor: case CSSPropertyID::kBorderLeftColor:
diff --git a/third_party/blink/renderer/core/css/css_properties.json5 b/third_party/blink/renderer/core/css/css_properties.json5 index 683d981..44cdfea 100644 --- a/third_party/blink/renderer/core/css/css_properties.json5 +++ b/third_party/blink/renderer/core/css/css_properties.json5
@@ -1093,7 +1093,7 @@ }, { name: "accent-color", - property_methods: ["ParseSingleValue"], + property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"], interpolable: true, inherited: true, field_group: "*", @@ -1108,7 +1108,7 @@ runtime_flag: "CSSAccentColor", default_value: "StyleAutoColor::AutoColor()", style_builder_custom_functions: ["initial", "inherit", "value"], - computable: false, + computable: true, }, { name: "align-content",
diff --git a/third_party/blink/renderer/core/css/cssom/style_value_factory.cc b/third_party/blink/renderer/core/css/cssom/style_value_factory.cc index 4e8f713..db3ae43 100644 --- a/third_party/blink/renderer/core/css/cssom/style_value_factory.cc +++ b/third_party/blink/renderer/core/css/cssom/style_value_factory.cc
@@ -85,8 +85,9 @@ } return nullptr; } + case CSSPropertyID::kAccentColor: case CSSPropertyID::kCaretColor: { - // caret-color also supports 'auto' + // caret-color and accent-color also support 'auto' auto* identifier_value = DynamicTo<CSSIdentifierValue>(value); if (identifier_value && identifier_value->GetValueID() == CSSValueID::kAuto)
diff --git a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc index 7b1d5520..99473f5 100644 --- a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc +++ b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
@@ -4911,6 +4911,19 @@ return css_parsing_utils::ConsumeColor(range, context); } +const CSSValue* AccentColor::CSSValueFromComputedStyleInternal( + const ComputedStyle& style, + const LayoutObject*, + bool allow_visited_style) const { + StyleAutoColor auto_color = style.AccentColor(); + if (auto_color.IsAutoColor()) { + return CSSIdentifierValue::Create(CSSValueID::kAuto); + } + + return ComputedStyleUtils::ValueForStyleAutoColor( + style, style.AccentColor(), CSSValuePhase::kComputedValue); +} + void AccentColor::ApplyInitial(StyleResolverState& state) const { state.Style()->SetAccentColor(StyleAutoColor::AutoColor()); }
diff --git a/third_party/blink/renderer/core/dom/first_letter_pseudo_element_test.cc b/third_party/blink/renderer/core/dom/first_letter_pseudo_element_test.cc index 1d380f4..182eaca 100644 --- a/third_party/blink/renderer/core/dom/first_letter_pseudo_element_test.cc +++ b/third_party/blink/renderer/core/dom/first_letter_pseudo_element_test.cc
@@ -4,6 +4,7 @@ #include "third_party/blink/renderer/core/dom/first_letter_pseudo_element.h" +#include "third_party/blink/renderer/core/dom/text.h" #include "third_party/blink/renderer/core/testing/page_test_base.h" namespace blink { @@ -15,7 +16,38 @@ EXPECT_EQ(2u, FirstLetterPseudoElement::FirstLetterLength(emoji)); } -// http://crbug.com/1161370 +// http://crbug.com/1187834 +TEST_F(FirstLetterPseudoElementTest, AppendDataToSpace) { + InsertStyleElement("div::first-letter { color: red; }"); + SetBodyContent("<div><b id=sample> <!---->xyz</b></div>"); + const auto& sample = *GetElementById("sample"); + const auto& sample_layout_object = *sample.GetLayoutObject(); + auto& first_text = *To<Text>(sample.firstChild()); + + EXPECT_EQ(R"DUMP( +LayoutInline B id="sample" + +--LayoutText #text " " + +--LayoutInline ::first-letter + | +--LayoutTextFragment (anonymous) ("x") + +--LayoutTextFragment #text "xyz" ("yz") +)DUMP", + ToSimpleLayoutTree(sample_layout_object)); + + // Change leading white space " " to " AB". + first_text.appendData("AB"); + UpdateAllLifecyclePhasesForTest(); + + EXPECT_EQ(R"DUMP( +LayoutInline B id="sample" + +--LayoutInline ::first-letter + | +--LayoutTextFragment (anonymous) (" A") + +--LayoutTextFragment #text " AB" ("B") + +--LayoutTextFragment #text "xyz" ("xyz") +)DUMP", + ToSimpleLayoutTree(sample_layout_object)); +} + +// http://crbug.com/1159762 TEST_F(FirstLetterPseudoElementTest, EmptySpanOnly) { InsertStyleElement("p::first-letter { color: red; }"); SetBodyContent("<div><p id=sample><b></b></p>abc</div>");
diff --git a/third_party/blink/renderer/core/dom/text.cc b/third_party/blink/renderer/core/dom/text.cc index 7a56d42..6ff0ca1c 100644 --- a/third_party/blink/renderer/core/dom/text.cc +++ b/third_party/blink/renderer/core/dom/text.cc
@@ -447,6 +447,14 @@ return text_fragment_layout_object.GetFirstLetterPseudoElement() || !text_fragment_layout_object.IsRemainingTextLayoutObject(); } + if (auto* next = text_layout_object->NextSibling()) { + if (IsA<FirstLetterPseudoElement>(next->GetNode())) { + // This |Text| node is not a first-letter part, but it may be changed. + // So, we should rebuild first-letter part and remaining part. + // See FirstLetterPseudoElementTest.AppendDataToSpace + return true; + } + } return false; }
diff --git a/third_party/blink/renderer/core/html/forms/base_button_input_type.cc b/third_party/blink/renderer/core/html/forms/base_button_input_type.cc index cf415b2..fface02 100644 --- a/third_party/blink/renderer/core/html/forms/base_button_input_type.cc +++ b/third_party/blink/renderer/core/html/forms/base_button_input_type.cc
@@ -77,7 +77,7 @@ LayoutObject* BaseButtonInputType::CreateLayoutObject( const ComputedStyle& style, LegacyLayout legacy) const { - return LayoutObjectFactory::CreateButton(GetElement(), legacy); + return LayoutObjectFactory::CreateButton(GetElement(), style, legacy); } InputType::ValueMode BaseButtonInputType::GetValueMode() const {
diff --git a/third_party/blink/renderer/core/html/forms/file_input_type.cc b/third_party/blink/renderer/core/html/forms/file_input_type.cc index 121aa25..3b04500 100644 --- a/third_party/blink/renderer/core/html/forms/file_input_type.cc +++ b/third_party/blink/renderer/core/html/forms/file_input_type.cc
@@ -209,7 +209,8 @@ LayoutObject* FileInputType::CreateLayoutObject(const ComputedStyle& style, LegacyLayout legacy) const { - return LayoutObjectFactory::CreateFileUploadControl(GetElement(), legacy); + return LayoutObjectFactory::CreateFileUploadControl(GetElement(), style, + legacy); } InputType::ValueMode FileInputType::GetValueMode() const {
diff --git a/third_party/blink/renderer/core/html/forms/html_button_element.cc b/third_party/blink/renderer/core/html/forms/html_button_element.cc index 3d178fb..5b52558 100644 --- a/third_party/blink/renderer/core/html/forms/html_button_element.cc +++ b/third_party/blink/renderer/core/html/forms/html_button_element.cc
@@ -57,7 +57,7 @@ display == EDisplay::kInlineLayoutCustom || display == EDisplay::kLayoutCustom) return HTMLFormControlElement::CreateLayoutObject(style, legacy); - return LayoutObjectFactory::CreateButton(*this, legacy); + return LayoutObjectFactory::CreateButton(*this, style, legacy); } const AtomicString& HTMLButtonElement::FormControlType() const {
diff --git a/third_party/blink/renderer/core/html/forms/html_field_set_element.cc b/third_party/blink/renderer/core/html/forms/html_field_set_element.cc index bf9a257..93ab4d0 100644 --- a/third_party/blink/renderer/core/html/forms/html_field_set_element.cc +++ b/third_party/blink/renderer/core/html/forms/html_field_set_element.cc
@@ -121,7 +121,7 @@ LayoutObject* HTMLFieldSetElement::CreateLayoutObject( const ComputedStyle& style, LegacyLayout legacy) { - return LayoutObjectFactory::CreateFieldset(*this, legacy); + return LayoutObjectFactory::CreateFieldset(*this, style, legacy); } LayoutBox* HTMLFieldSetElement::GetLayoutBoxForScrolling() const {
diff --git a/third_party/blink/renderer/core/html/forms/html_select_element.cc b/third_party/blink/renderer/core/html/forms/html_select_element.cc index cbc847f8..88e95ee 100644 --- a/third_party/blink/renderer/core/html/forms/html_select_element.cc +++ b/third_party/blink/renderer/core/html/forms/html_select_element.cc
@@ -406,7 +406,7 @@ const ComputedStyle& style, LegacyLayout legacy_layout) { if (UsesMenuList()) - return LayoutObjectFactory::CreateFlexibleBox(*this, legacy_layout); + return LayoutObjectFactory::CreateFlexibleBox(*this, style, legacy_layout); return LayoutObjectFactory::CreateBlockFlow(*this, style, legacy_layout); }
diff --git a/third_party/blink/renderer/core/html/forms/html_text_area_element.cc b/third_party/blink/renderer/core/html/forms/html_text_area_element.cc index d9e756d..89d0fcc 100644 --- a/third_party/blink/renderer/core/html/forms/html_text_area_element.cc +++ b/third_party/blink/renderer/core/html/forms/html_text_area_element.cc
@@ -263,7 +263,7 @@ LayoutObject* HTMLTextAreaElement::CreateLayoutObject( const ComputedStyle& style, LegacyLayout legacy) { - return LayoutObjectFactory::CreateTextControlMultiLine(*this, legacy); + return LayoutObjectFactory::CreateTextControlMultiLine(*this, style, legacy); } void HTMLTextAreaElement::AppendToFormData(FormData& form_data) {
diff --git a/third_party/blink/renderer/core/html/forms/range_input_type.cc b/third_party/blink/renderer/core/html/forms/range_input_type.cc index f58a5393..f978b04 100644 --- a/third_party/blink/renderer/core/html/forms/range_input_type.cc +++ b/third_party/blink/renderer/core/html/forms/range_input_type.cc
@@ -254,7 +254,7 @@ LegacyLayout legacy) const { // TODO(crbug.com/1131352): input[type=range] should not use // LayoutFlexibleBox. - return LayoutObjectFactory::CreateFlexibleBox(GetElement(), legacy); + return LayoutObjectFactory::CreateFlexibleBox(GetElement(), style, legacy); } Decimal RangeInputType::ParseToNumber(const String& src,
diff --git a/third_party/blink/renderer/core/html/forms/slider_thumb_element.cc b/third_party/blink/renderer/core/html/forms/slider_thumb_element.cc index 872142a..21676c6 100644 --- a/third_party/blink/renderer/core/html/forms/slider_thumb_element.cc +++ b/third_party/blink/renderer/core/html/forms/slider_thumb_element.cc
@@ -327,7 +327,7 @@ LayoutObject* SliderContainerElement::CreateLayoutObject( const ComputedStyle& style, LegacyLayout legacy) { - return LayoutObjectFactory::CreateFlexibleBox(*this, legacy); + return LayoutObjectFactory::CreateFlexibleBox(*this, style, legacy); } void SliderContainerElement::DefaultEventHandler(Event& event) {
diff --git a/third_party/blink/renderer/core/html/forms/slider_track_element.cc b/third_party/blink/renderer/core/html/forms/slider_track_element.cc index 01b6f77..55a7d074 100644 --- a/third_party/blink/renderer/core/html/forms/slider_track_element.cc +++ b/third_party/blink/renderer/core/html/forms/slider_track_element.cc
@@ -13,7 +13,7 @@ LayoutObject* SliderTrackElement::CreateLayoutObject(const ComputedStyle& style, LegacyLayout legacy) { - return LayoutObjectFactory::CreateSliderTrack(*this, legacy); + return LayoutObjectFactory::CreateSliderTrack(*this, style, legacy); } } // namespace blink
diff --git a/third_party/blink/renderer/core/html/forms/text_control_inner_elements.cc b/third_party/blink/renderer/core/html/forms/text_control_inner_elements.cc index a434fb46..17ead81c 100644 --- a/third_party/blink/renderer/core/html/forms/text_control_inner_elements.cc +++ b/third_party/blink/renderer/core/html/forms/text_control_inner_elements.cc
@@ -131,7 +131,8 @@ LayoutObject* TextControlInnerEditorElement::CreateLayoutObject( const ComputedStyle& style, LegacyLayout legacy) { - return LayoutObjectFactory::CreateTextControlInnerEditor(*this, legacy); + return LayoutObjectFactory::CreateTextControlInnerEditor(*this, style, + legacy); } scoped_refptr<ComputedStyle>
diff --git a/third_party/blink/renderer/core/html/forms/text_field_input_type.cc b/third_party/blink/renderer/core/html/forms/text_field_input_type.cc index b55cc1c..bf44e5b 100644 --- a/third_party/blink/renderer/core/html/forms/text_field_input_type.cc +++ b/third_party/blink/renderer/core/html/forms/text_field_input_type.cc
@@ -285,7 +285,8 @@ LayoutObject* TextFieldInputType::CreateLayoutObject( const ComputedStyle& style, LegacyLayout legacy) const { - return LayoutObjectFactory::CreateTextControlSingleLine(GetElement(), legacy); + return LayoutObjectFactory::CreateTextControlSingleLine(GetElement(), style, + legacy); } void TextFieldInputType::CreateShadowSubtree() {
diff --git a/third_party/blink/renderer/core/html/html_element.cc b/third_party/blink/renderer/core/html/html_element.cc index 5696ca6..d1994f67 100644 --- a/third_party/blink/renderer/core/html/html_element.cc +++ b/third_party/blink/renderer/core/html/html_element.cc
@@ -599,6 +599,7 @@ {html_names::kOnwheelAttr, kNoWebFeature, event_type_names::kWheel, nullptr}, + // Begin ARIA attributes. {html_names::kAriaActivedescendantAttr, WebFeature::kARIAActiveDescendantAttribute, kNoEvent, nullptr}, {html_names::kAriaAtomicAttr, WebFeature::kARIAAtomicAttribute, kNoEvent, @@ -691,6 +692,8 @@ kNoEvent, nullptr}, {html_names::kAriaSortAttr, WebFeature::kARIASortAttribute, kNoEvent, nullptr}, + {html_names::kAriaTouchpassthroughAttr, + WebFeature::kARIATouchpassthroughAttribute, kNoEvent, nullptr}, {html_names::kAriaValuemaxAttr, WebFeature::kARIAValueMaxAttribute, kNoEvent, nullptr}, {html_names::kAriaValueminAttr, WebFeature::kARIAValueMinAttribute, @@ -699,6 +702,10 @@ kNoEvent, nullptr}, {html_names::kAriaValuetextAttr, WebFeature::kARIAValueTextAttribute, kNoEvent, nullptr}, + {html_names::kAriaVirtualcontentAttr, + WebFeature::kARIAVirtualcontentAttribute, kNoEvent, nullptr}, + // End ARIA attributes. + {html_names::kAutocapitalizeAttr, WebFeature::kAutocapitalizeAttribute, kNoEvent, nullptr}, };
diff --git a/third_party/blink/renderer/core/html/html_progress_element.cc b/third_party/blink/renderer/core/html/html_progress_element.cc index 7410e1e..e7ba5e9a 100644 --- a/third_party/blink/renderer/core/html/html_progress_element.cc +++ b/third_party/blink/renderer/core/html/html_progress_element.cc
@@ -54,7 +54,7 @@ } UseCounter::Count(GetDocument(), WebFeature::kProgressElementWithProgressBarAppearance); - return LayoutObjectFactory::CreateProgress(this, legacy); + return LayoutObjectFactory::CreateProgress(this, style, legacy); } LayoutProgress* HTMLProgressElement::GetLayoutProgress() const {
diff --git a/third_party/blink/renderer/core/html/html_rt_element.cc b/third_party/blink/renderer/core/html/html_rt_element.cc index 8b3921c7..548e222 100644 --- a/third_party/blink/renderer/core/html/html_rt_element.cc +++ b/third_party/blink/renderer/core/html/html_rt_element.cc
@@ -17,7 +17,7 @@ LayoutObject* HTMLRTElement::CreateLayoutObject(const ComputedStyle& style, LegacyLayout legacy) { if (style.Display() == EDisplay::kBlock) - return LayoutObjectFactory::CreateRubyText(this, legacy); + return LayoutObjectFactory::CreateRubyText(this, style, legacy); return LayoutObject::CreateObject(this, style, legacy); }
diff --git a/third_party/blink/renderer/core/html/html_ruby_element.cc b/third_party/blink/renderer/core/html/html_ruby_element.cc index d0cbef5..96c3ae0 100644 --- a/third_party/blink/renderer/core/html/html_ruby_element.cc +++ b/third_party/blink/renderer/core/html/html_ruby_element.cc
@@ -20,7 +20,7 @@ return new LayoutRubyAsInline(this); if (style.Display() == EDisplay::kBlock) { UseCounter::Count(GetDocument(), WebFeature::kRubyElementWithDisplayBlock); - return LayoutObjectFactory::CreateRubyAsBlock(this, legacy); + return LayoutObjectFactory::CreateRubyAsBlock(this, style, legacy); } return LayoutObject::CreateObject(this, style, legacy); }
diff --git a/third_party/blink/renderer/core/layout/layout_block.cc b/third_party/blink/renderer/core/layout/layout_block.cc index 011d045..bddde61 100644 --- a/third_party/blink/renderer/core/layout/layout_block.cc +++ b/third_party/blink/renderer/core/layout/layout_block.cc
@@ -2270,11 +2270,11 @@ parent->UpdateAnonymousChildStyle(nullptr, *new_style); LayoutBlock* layout_block; if (new_display == EDisplay::kFlex) { - layout_block = - LayoutObjectFactory::CreateFlexibleBox(parent->GetDocument(), legacy); + layout_block = LayoutObjectFactory::CreateFlexibleBox(parent->GetDocument(), + *new_style, legacy); } else if (new_display == EDisplay::kGrid) { - layout_block = - LayoutObjectFactory::CreateGrid(parent->GetDocument(), legacy); + layout_block = LayoutObjectFactory::CreateGrid(parent->GetDocument(), + *new_style, legacy); } else { DCHECK(new_display == EDisplay::kBlock || new_display == EDisplay::kFlowRoot);
diff --git a/third_party/blink/renderer/core/layout/layout_object.cc b/third_party/blink/renderer/core/layout/layout_object.cc index f53e6b9..564d550 100644 --- a/third_party/blink/renderer/core/layout/layout_object.cc +++ b/third_party/blink/renderer/core/layout/layout_object.cc
@@ -288,37 +288,38 @@ return LayoutObjectFactory::CreateBlockFlow(*element, style, legacy); case EDisplay::kTable: case EDisplay::kInlineTable: - return LayoutObjectFactory::CreateTable(*element, legacy); + return LayoutObjectFactory::CreateTable(*element, style, legacy); case EDisplay::kTableRowGroup: case EDisplay::kTableHeaderGroup: case EDisplay::kTableFooterGroup: - return LayoutObjectFactory::CreateTableSection(*element, legacy); + return LayoutObjectFactory::CreateTableSection(*element, style, legacy); case EDisplay::kTableRow: - return LayoutObjectFactory::CreateTableRow(*element, legacy); + return LayoutObjectFactory::CreateTableRow(*element, style, legacy); case EDisplay::kTableColumnGroup: case EDisplay::kTableColumn: - return LayoutObjectFactory::CreateTableColumn(*element, legacy); + return LayoutObjectFactory::CreateTableColumn(*element, style, legacy); case EDisplay::kTableCell: - return LayoutObjectFactory::CreateTableCell(*element, legacy); + return LayoutObjectFactory::CreateTableCell(*element, style, legacy); case EDisplay::kTableCaption: - return LayoutObjectFactory::CreateTableCaption(*element, legacy); + return LayoutObjectFactory::CreateTableCaption(*element, style, legacy); case EDisplay::kWebkitBox: case EDisplay::kWebkitInlineBox: if (style.IsDeprecatedWebkitBoxWithVerticalLineClamp()) { - return LayoutObjectFactory::CreateBlockForLineClamp(*element, legacy); + return LayoutObjectFactory::CreateBlockForLineClamp(*element, style, + legacy); } - return LayoutObjectFactory::CreateFlexibleBox(*element, legacy); + return LayoutObjectFactory::CreateFlexibleBox(*element, style, legacy); case EDisplay::kFlex: case EDisplay::kInlineFlex: UseCounter::Count(element->GetDocument(), WebFeature::kCSSFlexibleBox); - return LayoutObjectFactory::CreateFlexibleBox(*element, legacy); + return LayoutObjectFactory::CreateFlexibleBox(*element, style, legacy); case EDisplay::kGrid: case EDisplay::kInlineGrid: UseCounter::Count(element->GetDocument(), WebFeature::kCSSGridLayout); - return LayoutObjectFactory::CreateGrid(*element, legacy); + return LayoutObjectFactory::CreateGrid(*element, style, legacy); case EDisplay::kMath: case EDisplay::kBlockMath: - return LayoutObjectFactory::CreateMath(*element, legacy); + return LayoutObjectFactory::CreateMath(*element, style, legacy); case EDisplay::kLayoutCustom: case EDisplay::kInlineLayoutCustom: DCHECK(RuntimeEnabledFeatures::LayoutNGEnabled());
diff --git a/third_party/blink/renderer/core/layout/layout_object_factory.cc b/third_party/blink/renderer/core/layout/layout_object_factory.cc index 66dad88b..abc044d 100644 --- a/third_party/blink/renderer/core/layout/layout_object_factory.cc +++ b/third_party/blink/renderer/core/layout/layout_object_factory.cc
@@ -122,18 +122,21 @@ // static LayoutBlock* LayoutObjectFactory::CreateBlockForLineClamp( Node& node, + const ComputedStyle& style, LegacyLayout legacy) { return CreateObject<LayoutBlock, LayoutNGBlockFlow, LayoutDeprecatedFlexibleBox>(node, legacy); } LayoutBlock* LayoutObjectFactory::CreateFlexibleBox(Node& node, + const ComputedStyle& style, LegacyLayout legacy) { return CreateObject<LayoutBlock, LayoutNGFlexibleBox, LayoutFlexibleBox>( node, legacy); } LayoutBlock* LayoutObjectFactory::CreateGrid(Node& node, + const ComputedStyle& style, LegacyLayout legacy) { bool disable_ng_for_type = !RuntimeEnabledFeatures::LayoutNGGridEnabled(); if (disable_ng_for_type) @@ -143,6 +146,7 @@ } LayoutBlock* LayoutObjectFactory::CreateMath(Node& node, + const ComputedStyle& style, LegacyLayout legacy) { DCHECK(IsA<MathMLElement>(node)); DCHECK_NE(legacy, LegacyLayout::kForce); @@ -180,6 +184,7 @@ } LayoutBlock* LayoutObjectFactory::CreateTable(Node& node, + const ComputedStyle& style, LegacyLayout legacy) { bool disable_ng_for_type = !RuntimeEnabledFeatures::LayoutNGTableEnabled(); if (disable_ng_for_type) @@ -190,12 +195,14 @@ LayoutTableCaption* LayoutObjectFactory::CreateTableCaption( Node& node, + const ComputedStyle& style, LegacyLayout legacy) { return CreateObject<LayoutTableCaption, LayoutNGTableCaption>(node, legacy); } LayoutBlockFlow* LayoutObjectFactory::CreateTableCell( Node& node, + const ComputedStyle& style, LegacyLayout legacy) { if (RuntimeEnabledFeatures::LayoutNGTableEnabled()) { return CreateObject<LayoutBlockFlow, LayoutNGTableCell, LayoutTableCell>( @@ -207,6 +214,7 @@ } LayoutBox* LayoutObjectFactory::CreateTableColumn(Node& node, + const ComputedStyle& style, LegacyLayout legacy) { bool disable_ng_for_type = !RuntimeEnabledFeatures::LayoutNGTableEnabled(); if (disable_ng_for_type) @@ -216,6 +224,7 @@ } LayoutBox* LayoutObjectFactory::CreateTableRow(Node& node, + const ComputedStyle& style, LegacyLayout legacy) { bool disable_ng_for_type = !RuntimeEnabledFeatures::LayoutNGTableEnabled(); if (disable_ng_for_type) @@ -225,6 +234,7 @@ } LayoutBox* LayoutObjectFactory::CreateTableSection(Node& node, + const ComputedStyle& style, LegacyLayout legacy) { bool disable_ng_for_type = !RuntimeEnabledFeatures::LayoutNGTableEnabled(); if (disable_ng_for_type) @@ -234,11 +244,13 @@ } LayoutObject* LayoutObjectFactory::CreateButton(Node& node, + const ComputedStyle& style, LegacyLayout legacy) { return CreateObject<LayoutBlock, LayoutNGButton, LayoutButton>(node, legacy); } LayoutBlock* LayoutObjectFactory::CreateFieldset(Node& node, + const ComputedStyle& style, LegacyLayout legacy) { return CreateObject<LayoutBlock, LayoutNGFieldset, LayoutFieldset>(node, legacy); @@ -246,12 +258,14 @@ LayoutBlockFlow* LayoutObjectFactory::CreateFileUploadControl( Node& node, + const ComputedStyle& style, LegacyLayout legacy) { return CreateObject<LayoutBlockFlow, LayoutNGBlockFlow, LayoutFileUploadControl>(node, legacy); } LayoutObject* LayoutObjectFactory::CreateSliderTrack(Node& node, + const ComputedStyle& style, LegacyLayout legacy) { return CreateObject<LayoutBlock, LayoutNGBlockFlow, LayoutSliderTrack>( node, legacy); @@ -259,6 +273,7 @@ LayoutObject* LayoutObjectFactory::CreateTextControlInnerEditor( Node& node, + const ComputedStyle& style, LegacyLayout legacy) { return CreateObject<LayoutBlockFlow, LayoutNGTextControlInnerEditor, LayoutTextControlInnerEditor>(node, legacy); @@ -266,6 +281,7 @@ LayoutObject* LayoutObjectFactory::CreateTextControlMultiLine( Node& node, + const ComputedStyle& style, LegacyLayout legacy) { return CreateObject<LayoutBlockFlow, LayoutNGTextControlMultiLine, LayoutTextControlMultiLine>(node, legacy); @@ -273,6 +289,7 @@ LayoutObject* LayoutObjectFactory::CreateTextControlSingleLine( Node& node, + const ComputedStyle& style, LegacyLayout legacy) { return CreateObject<LayoutBlockFlow, LayoutNGTextControlSingleLine, LayoutTextControlSingleLine>(node, legacy); @@ -320,22 +337,26 @@ } LayoutProgress* LayoutObjectFactory::CreateProgress(Node* node, + const ComputedStyle& style, LegacyLayout legacy) { return CreateObject<LayoutProgress, LayoutNGProgress>(*node, legacy); } LayoutRubyAsBlock* LayoutObjectFactory::CreateRubyAsBlock( Node* node, + const ComputedStyle& style, LegacyLayout legacy) { return CreateObject<LayoutRubyAsBlock, LayoutNGRubyAsBlock>(*node, legacy); } LayoutObject* LayoutObjectFactory::CreateRubyText(Node* node, + const ComputedStyle& style, LegacyLayout legacy) { return CreateObject<LayoutRubyText, LayoutNGRubyText>(*node, legacy); } LayoutObject* LayoutObjectFactory::CreateSVGText(Node& node, + const ComputedStyle& style, LegacyLayout legacy) { const bool disable_ng_for_type = !RuntimeEnabledFeatures::SVGTextNGEnabled(); return CreateObject<LayoutBlockFlow, LayoutNGSVGText, LayoutSVGText>( @@ -363,7 +384,8 @@ ? LegacyLayout::kForce : LegacyLayout::kAuto; - LayoutBlock* new_table = CreateTable(parent.GetDocument(), legacy); + LayoutBlock* new_table = + CreateTable(parent.GetDocument(), *new_style, legacy); new_table->SetDocumentForAnonymous(&parent.GetDocument()); new_table->SetStyle(std::move(new_style)); return new_table; @@ -377,7 +399,8 @@ LegacyLayout legacy = parent.ForceLegacyLayout() ? LegacyLayout::kForce : LegacyLayout::kAuto; - LayoutBox* new_section = CreateTableSection(parent.GetDocument(), legacy); + LayoutBox* new_section = + CreateTableSection(parent.GetDocument(), *new_style, legacy); new_section->SetDocumentForAnonymous(&parent.GetDocument()); new_section->SetStyle(std::move(new_style)); return new_section; @@ -390,7 +413,7 @@ parent.StyleRef(), EDisplay::kTableRow); LegacyLayout legacy = parent.ForceLegacyLayout() ? LegacyLayout::kForce : LegacyLayout::kAuto; - LayoutBox* new_row = CreateTableRow(parent.GetDocument(), legacy); + LayoutBox* new_row = CreateTableRow(parent.GetDocument(), *new_style, legacy); new_row->SetDocumentForAnonymous(&parent.GetDocument()); new_row->SetStyle(std::move(new_style)); return new_row; @@ -403,7 +426,8 @@ parent.StyleRef(), EDisplay::kTableCell); LegacyLayout legacy = parent.ForceLegacyLayout() ? LegacyLayout::kForce : LegacyLayout::kAuto; - LayoutBlockFlow* new_cell = CreateTableCell(parent.GetDocument(), legacy); + LayoutBlockFlow* new_cell = + CreateTableCell(parent.GetDocument(), *new_style, legacy); new_cell->SetDocumentForAnonymous(&parent.GetDocument()); new_cell->SetStyle(std::move(new_style)); return new_cell;
diff --git a/third_party/blink/renderer/core/layout/layout_object_factory.h b/third_party/blink/renderer/core/layout/layout_object_factory.h index 8d06da65..19fb64c 100644 --- a/third_party/blink/renderer/core/layout/layout_object_factory.h +++ b/third_party/blink/renderer/core/layout/layout_object_factory.h
@@ -41,38 +41,50 @@ const ComputedStyle&, LegacyLayout); static LayoutBlock* CreateBlockForLineClamp(Node& node, + const ComputedStyle& style, LegacyLayout legacy); static LayoutBlock* CreateFlexibleBox(Node&, + const ComputedStyle&, LegacyLayout); - static LayoutBlock* CreateGrid(Node&, LegacyLayout); - static LayoutBlock* CreateMath(Node&, LegacyLayout); + static LayoutBlock* CreateGrid(Node&, const ComputedStyle&, LegacyLayout); + static LayoutBlock* CreateMath(Node&, const ComputedStyle&, LegacyLayout); static LayoutObject* CreateListMarker(Node&, const ComputedStyle&, LegacyLayout); - static LayoutBlock* CreateTable(Node&, LegacyLayout); + static LayoutBlock* CreateTable(Node&, const ComputedStyle&, LegacyLayout); static LayoutTableCaption* CreateTableCaption(Node&, + const ComputedStyle&, LegacyLayout); static LayoutBlockFlow* CreateTableCell(Node&, + const ComputedStyle&, LegacyLayout); static LayoutBox* CreateTableColumn(Node&, + const ComputedStyle&, LegacyLayout); - static LayoutBox* CreateTableRow(Node&, LegacyLayout); + static LayoutBox* CreateTableRow(Node&, const ComputedStyle&, LegacyLayout); static LayoutBox* CreateTableSection(Node&, + const ComputedStyle&, LegacyLayout); static LayoutObject* CreateButton(Node& node, + const ComputedStyle& style, LegacyLayout legacy); - static LayoutBlock* CreateFieldset(Node&, LegacyLayout); + static LayoutBlock* CreateFieldset(Node&, const ComputedStyle&, LegacyLayout); static LayoutBlockFlow* CreateFileUploadControl(Node& node, + const ComputedStyle& style, LegacyLayout legacy); static LayoutObject* CreateSliderTrack(Node& node, + const ComputedStyle& style, LegacyLayout legacy); static LayoutObject* CreateTextControlInnerEditor(Node& node, + const ComputedStyle& style, LegacyLayout legacy); static LayoutObject* CreateTextControlMultiLine(Node& node, + const ComputedStyle& style, LegacyLayout legacy); static LayoutObject* CreateTextControlSingleLine(Node& node, + const ComputedStyle& style, LegacyLayout legacy); static LayoutText* CreateText(Node*, scoped_refptr<StringImpl>, LegacyLayout); @@ -85,13 +97,17 @@ int length, LegacyLayout); static LayoutProgress* CreateProgress(Node* node, + const ComputedStyle& style, LegacyLayout legacy); static LayoutRubyAsBlock* CreateRubyAsBlock(Node* node, + const ComputedStyle& style, LegacyLayout legacy); static LayoutObject* CreateRubyText(Node* node, + const ComputedStyle& style, LegacyLayout legacy); static LayoutObject* CreateSVGText(Node& node, + const ComputedStyle& style, LegacyLayout legacy); static LayoutObject* CreateBR(Node*, LegacyLayout);
diff --git a/third_party/blink/renderer/core/layout/layout_table_cell.cc b/third_party/blink/renderer/core/layout/layout_table_cell.cc index 9b4f0fcc..e30bc902 100644 --- a/third_party/blink/renderer/core/layout/layout_table_cell.cc +++ b/third_party/blink/renderer/core/layout/layout_table_cell.cc
@@ -1227,7 +1227,7 @@ scoped_refptr<ComputedStyle> style, LegacyLayout legacy) { LayoutBlockFlow* layout_object = - LayoutObjectFactory::CreateTableCell(*document, legacy); + LayoutObjectFactory::CreateTableCell(*document, *style, legacy); layout_object->SetDocumentForAnonymous(document); layout_object->SetStyle(std::move(style)); return To<LayoutTableCell>(layout_object);
diff --git a/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.cc index f0fd60b..2eaee00 100644 --- a/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.cc
@@ -584,6 +584,9 @@ const Length& specified_length_in_main_axis = is_horizontal_flow_ ? child_style.Width() : child_style.Height(); const Length& flex_basis = child_style.FlexBasis(); + if (is_column_ && flex_basis.IsPercentOrCalc()) + has_column_percent_flex_basis_ = true; + Length length_to_resolve = Length::Auto(); if (flex_basis.IsAuto()) { if (!is_column_ || IsItemMainSizeDefinite(child)) @@ -1059,6 +1062,9 @@ container_builder_.SetIntrinsicBlockSize(intrinsic_block_size); container_builder_.SetFragmentsTotalBlockSize(block_size); + if (has_column_percent_flex_basis_) + container_builder_.SetHasDescendantThatDependsOnPercentageBlockSize(true); + bool success = GiveLinesAndItemsFinalPositionAndSize(); if (!success) return nullptr;
diff --git a/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.h b/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.h index 5667a87..478eef3 100644 --- a/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.h +++ b/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.h
@@ -86,6 +86,7 @@ const bool is_cross_size_definite_; const LogicalSize child_percentage_size_; + bool has_column_percent_flex_basis_ = false; bool ignore_child_scrollbar_changes_ = false; FlexLayoutAlgorithm algorithm_; DevtoolsFlexInfo* layout_info_for_devtools_;
diff --git a/third_party/blink/renderer/core/page/scrolling/element_fragment_anchor.h b/third_party/blink/renderer/core/page/scrolling/element_fragment_anchor.h index 7f19992..3c38470 100644 --- a/third_party/blink/renderer/core/page/scrolling/element_fragment_anchor.h +++ b/third_party/blink/renderer/core/page/scrolling/element_fragment_anchor.h
@@ -58,6 +58,8 @@ void Trace(Visitor*) const override; + bool IsTextFragmentAnchor() override { return false; } + private: FRIEND_TEST_ALL_PREFIXES(ElementFragmentAnchorTest, AnchorRemovedBeforeBeginFrameCrash);
diff --git a/third_party/blink/renderer/core/page/scrolling/fragment_anchor.h b/third_party/blink/renderer/core/page/scrolling/fragment_anchor.h index 0c7e3cc..6681171 100644 --- a/third_party/blink/renderer/core/page/scrolling/fragment_anchor.h +++ b/third_party/blink/renderer/core/page/scrolling/fragment_anchor.h
@@ -57,6 +57,8 @@ virtual bool Dismiss() = 0; virtual void Trace(Visitor*) const {} + + virtual bool IsTextFragmentAnchor() = 0; }; } // namespace blink
diff --git a/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.h b/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.h index d570db10..c520078 100644 --- a/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.h +++ b/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.h
@@ -91,6 +91,8 @@ return text_fragment_finders_; } + bool IsTextFragmentAnchor() override { return true; } + private: // Called when the search is finished. Reports metrics and activates the // element fragment anchor if we didn't find a match.
diff --git a/third_party/blink/renderer/core/page/scrolling/text_fragment_handler.cc b/third_party/blink/renderer/core/page/scrolling/text_fragment_handler.cc index 0eb4687f3..71aad18 100644 --- a/third_party/blink/renderer/core/page/scrolling/text_fragment_handler.cc +++ b/third_party/blink/renderer/core/page/scrolling/text_fragment_handler.cc
@@ -9,6 +9,7 @@ #include "third_party/blink/renderer/core/editing/markers/document_marker.h" #include "third_party/blink/renderer/core/editing/markers/document_marker_controller.h" #include "third_party/blink/renderer/core/editing/position_with_affinity.h" +#include "third_party/blink/renderer/core/editing/visible_units.h" #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.h" @@ -43,17 +44,16 @@ void TextFragmentHandler::GetExistingSelectors( GetExistingSelectorsCallback callback) { Vector<String> text_fragment_selectors; - TextFragmentAnchor* anchor( - static_cast<TextFragmentAnchor*>(GetTextFragmentSelectorGenerator() - ->GetFrame() - ->View() - ->GetFragmentAnchor())); - if (anchor) { - for (auto& finder : anchor->TextFragmentFinders()) { - if (finder->FirstMatch()) { - text_fragment_selectors.push_back(finder->GetSelector().ToString()); - } + TextFragmentAnchor* anchor = GetTextFragmentAnchor(); + if (!anchor) { + std::move(callback).Run(Vector<String>()); + return; + } + + for (auto& finder : anchor->TextFragmentFinders()) { + if (finder->FirstMatch()) { + text_fragment_selectors.push_back(finder->GetSelector().ToString()); } } @@ -90,28 +90,66 @@ ExtractTextFragmentsMatchesCallback callback) { DCHECK( base::FeatureList::IsEnabled(shared_highlighting::kSharedHighlightingV2)); - Vector<String> text_fragment_matches; - TextFragmentAnchor* anchor( - static_cast<TextFragmentAnchor*>(GetTextFragmentSelectorGenerator() - ->GetFrame() - ->View() - ->GetFragmentAnchor())); - if (anchor) { - for (auto& finder : anchor->TextFragmentFinders()) { - EphemeralRangeInFlatTree potential_match = - finder->FirstMatch()->ToEphemeralRange(); - text_fragment_matches.push_back(PlainText(potential_match)); + TextFragmentAnchor* anchor = GetTextFragmentAnchor(); + if (!anchor) { + std::move(callback).Run(Vector<String>()); + return; + } + + for (auto& finder : anchor->TextFragmentFinders()) { + if (finder->FirstMatch()) { + text_fragment_matches.push_back( + PlainText(finder->FirstMatch()->ToEphemeralRange())); } } std::move(callback).Run(text_fragment_matches); } +void TextFragmentHandler::ExtractFirstFragmentRect( + ExtractFirstFragmentRectCallback callback) { + DCHECK( + base::FeatureList::IsEnabled(shared_highlighting::kSharedHighlightingV2)); + IntRect rect_in_viewport; + + TextFragmentAnchor* anchor = GetTextFragmentAnchor(); + if (!anchor || anchor->TextFragmentFinders().size() <= 0) { + std::move(callback).Run(gfx::Rect()); + return; + } + + for (auto& finder : anchor->TextFragmentFinders()) { + if (finder->FirstMatch() == nullptr) { + continue; + } + + PhysicalRect bounding_box( + ComputeTextRect(finder->FirstMatch()->ToEphemeralRange())); + rect_in_viewport = + GetTextFragmentSelectorGenerator()->GetFrame()->View()->FrameToViewport( + EnclosingIntRect(bounding_box)); + break; + } + + std::move(callback).Run(gfx::Rect(rect_in_viewport)); +} + void TextFragmentHandler::Trace(Visitor* visitor) const { visitor->Trace(text_fragment_selector_generator_); visitor->Trace(selector_producer_); } +TextFragmentAnchor* TextFragmentHandler::GetTextFragmentAnchor() { + FragmentAnchor* fragmentAnchor = GetTextFragmentSelectorGenerator() + ->GetFrame() + ->View() + ->GetFragmentAnchor(); + if (!fragmentAnchor || !fragmentAnchor->IsTextFragmentAnchor()) { + return nullptr; + } + return static_cast<TextFragmentAnchor*>(fragmentAnchor); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/page/scrolling/text_fragment_handler.h b/third_party/blink/renderer/core/page/scrolling/text_fragment_handler.h index af6fbabd..82ec06fe 100644 --- a/third_party/blink/renderer/core/page/scrolling/text_fragment_handler.h +++ b/third_party/blink/renderer/core/page/scrolling/text_fragment_handler.h
@@ -6,6 +6,7 @@ #define THIRD_PARTY_BLINK_RENDERER_CORE_PAGE_SCROLLING_TEXT_FRAGMENT_HANDLER_H_ #include "third_party/blink/public/mojom/link_to_text/link_to_text.mojom-blink.h" +#include "third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.h" #include "third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.h" #include "third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h" @@ -44,6 +45,11 @@ void ExtractTextFragmentsMatches( ExtractTextFragmentsMatchesCallback callback) override; + // Request the bounding rectangle, relative to the viewport, of the first + // found match. It will accept an empty rectangle if no matches are found. + void ExtractFirstFragmentRect( + ExtractFirstFragmentRectCallback callback) override; + void Trace(Visitor*) const; TextFragmentSelectorGenerator* GetTextFragmentSelectorGenerator(); @@ -60,6 +66,8 @@ selector_producer_{this, nullptr}; DISALLOW_COPY_AND_ASSIGN(TextFragmentHandler); + + TextFragmentAnchor* GetTextFragmentAnchor(); }; } // namespace blink
diff --git a/third_party/blink/renderer/core/page/scrolling/text_fragment_handler_test.cc b/third_party/blink/renderer/core/page/scrolling/text_fragment_handler_test.cc index 12e0f61..c46686b4 100644 --- a/third_party/blink/renderer/core/page/scrolling/text_fragment_handler_test.cc +++ b/third_party/blink/renderer/core/page/scrolling/text_fragment_handler_test.cc
@@ -10,7 +10,14 @@ #include "components/shared_highlighting/core/common/shared_highlighting_features.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h" +#include "third_party/blink/renderer/bindings/core/v8/string_or_array_buffer_or_array_buffer_view.h" +#include "third_party/blink/renderer/bindings/core/v8/v8_font_face_descriptors.h" +#include "third_party/blink/renderer/bindings/core/v8/v8_mouse_event_init.h" +#include "third_party/blink/renderer/bindings/core/v8/v8_union_arraybuffer_arraybufferview_string.h" +#include "third_party/blink/renderer/core/css/css_font_face.h" +#include "third_party/blink/renderer/core/css/font_face_set_document.h" #include "third_party/blink/renderer/core/editing/markers/document_marker_controller.h" +#include "third_party/blink/renderer/core/editing/visible_units.h" #include "third_party/blink/renderer/core/testing/sim/sim_request.h" #include "third_party/blink/renderer/core/testing/sim/sim_test.h" #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h" @@ -55,6 +62,49 @@ EXPECT_TRUE(callback_called); return target_texts; } + + gfx::Rect ExtractFirstTextFragmentsRect() { + bool callback_called = false; + gfx::Rect text_fragment_rect; + auto lambda = [](bool& callback_called, gfx::Rect& text_fragment_rect, + const gfx::Rect& fetched_text_fragment_rect) { + text_fragment_rect = fetched_text_fragment_rect; + callback_called = true; + }; + auto callback = WTF::Bind(lambda, std::ref(callback_called), + std::ref(text_fragment_rect)); + + GetDocument() + .GetFrame() + ->GetTextFragmentHandler() + ->ExtractFirstFragmentRect(std::move(callback)); + + EXPECT_TRUE(callback_called); + return text_fragment_rect; + } + + void LoadAhem() { + scoped_refptr<SharedBuffer> shared_buffer = + test::ReadFromFile(test::CoreTestDataPath("Ahem.ttf")); +#if defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION) + auto* buffer = + MakeGarbageCollected<V8UnionArrayBufferOrArrayBufferViewOrString>( + DOMArrayBuffer::Create(shared_buffer)); +#else // defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION) + StringOrArrayBufferOrArrayBufferView buffer = + StringOrArrayBufferOrArrayBufferView::FromArrayBuffer( + DOMArrayBuffer::Create(shared_buffer)); +#endif // defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION) + FontFace* ahem = + FontFace::Create(GetDocument().GetExecutionContext(), "Ahem", buffer, + FontFaceDescriptors::Create()); + + ScriptState* script_state = + ToScriptStateForMainWorld(GetDocument().GetFrame()); + DummyExceptionStateForTesting exception_state; + FontFaceSetDocument::From(GetDocument()) + ->addForBinding(script_state, ahem, exception_state); + } }; TEST_F(TextFragmentHandlerTest, RemoveTextFragments) { @@ -258,6 +308,244 @@ EXPECT_EQ("nothing at", target_texts[3]); } +TEST_F(TextFragmentHandlerTest, ExtractFirstTextFragmentRect) { + base::test::ScopedFeatureList feature_list_; + feature_list_.InitAndEnableFeature( + shared_highlighting::kSharedHighlightingV2); + SimRequest request( + "https://example.com/" + "test.html#:~:text=This,page", + "text/html"); + LoadURL( + "https://example.com/" + "test.html#:~:text=This,page"); + request.Complete(R"HTML( + <!DOCTYPE html> + <meta name="viewport" content="width=device-width"> + <style>p { font: 10px/1 Ahem; }</style> + <p id="first">This is a test page</p> + <p id="second">with some more text</p> + )HTML"); + RunAsyncMatchingTasks(); + LoadAhem(); + + Compositor().BeginFrame(); + + EXPECT_EQ(1u, GetDocument().Markers().Markers().size()); + + Node* first_paragraph = GetDocument().getElementById("first")->firstChild(); + const auto& start = Position(first_paragraph, 0); + const auto& end = Position(first_paragraph, 19); + ASSERT_EQ("This is a test page", PlainText(EphemeralRange(start, end))); + IntRect rect(ComputeTextRect(EphemeralRange(start, end))); + gfx::Rect expected_rect = + gfx::Rect(GetDocument().GetFrame()->View()->FrameToViewport(rect)); + // ExtractFirstTextFragmentsRect should return the first matched viewport + // relative location. + ASSERT_EQ(expected_rect.ToString(), "8,10 190x10"); + + gfx::Rect text_fragment_rect = ExtractFirstTextFragmentsRect(); + + EXPECT_EQ(expected_rect.ToString(), text_fragment_rect.ToString()); +} + +TEST_F(TextFragmentHandlerTest, ExtractFirstTextFragmentRectScroll) { + base::test::ScopedFeatureList feature_list_; + feature_list_.InitAndEnableFeature( + shared_highlighting::kSharedHighlightingV2); + // Android settings to correctly extract the rect when the page is loaded + // zoomed in + WebView().GetPage()->GetSettings().SetViewportEnabled(true); + WebView().GetPage()->GetSettings().SetViewportMetaEnabled(true); + WebView().GetPage()->GetSettings().SetShrinksViewportContentToFit(true); + WebView().GetPage()->GetSettings().SetMainFrameResizesAreOrientationChanges( + true); + SimRequest request("https://example.com/test.html#:~:text=test,page", + "text/html"); + LoadURL("https://example.com/test.html#:~:text=test,page"); + request.Complete(R"HTML( + <!DOCTYPE html> + <meta name="viewport" content="initial-scale=4"> + <style> + body { + height: 2200px; + } + p { + position: absolute; + top: 2000px; + font: 10px/1 Ahem; + } + </style> + <p id="first">This is a test page</p> + )HTML"); + RunAsyncMatchingTasks(); + LoadAhem(); + + Compositor().BeginFrame(); + + EXPECT_EQ(1u, GetDocument().Markers().Markers().size()); + + Node* first_paragraph = GetDocument().getElementById("first")->firstChild(); + const auto& start = Position(first_paragraph, 10); + const auto& end = Position(first_paragraph, 19); + ASSERT_EQ("test page", PlainText(EphemeralRange(start, end))); + IntRect rect(ComputeTextRect(EphemeralRange(start, end))); + gfx::Rect expected_rect = + gfx::Rect(GetDocument().GetFrame()->View()->FrameToViewport(rect)); + // ExtractFirstTextFragmentsRect should return the first matched scaled + // viewport relative location since the page is loaded zoomed in 4X + ASSERT_EQ(expected_rect.ToString(), "432,296 360x44"); + + gfx::Rect text_fragment_rect = ExtractFirstTextFragmentsRect(); + + EXPECT_EQ(expected_rect.ToString(), text_fragment_rect.ToString()); +} + +TEST_F(TextFragmentHandlerTest, ExtractFirstTextFragmentRectMultipleHighlight) { + base::test::ScopedFeatureList feature_list_; + feature_list_.InitAndEnableFeature( + shared_highlighting::kSharedHighlightingV2); + SimRequest request( + "https://example.com/" + "test.html#:~:text=test%20page&text=more%20text", + "text/html"); + LoadURL( + "https://example.com/" + "test.html#:~:text=test%20page&text=more%20text"); + request.Complete(R"HTML( + <!DOCTYPE html> + <meta name="viewport" content="width=device-width"> + <style> + p { + font: 10px/1 Ahem; + } + body { + height: 1200px; + } + #second { + position: absolute; + top: 1000px; + } + </style> + <p id="first">This is a test page</p> + <p id="second">With some more text</p> + )HTML"); + RunAsyncMatchingTasks(); + LoadAhem(); + + Compositor().BeginFrame(); + + EXPECT_EQ(2u, GetDocument().Markers().Markers().size()); + + Node* first_paragraph = GetDocument().getElementById("first")->firstChild(); + const auto& start = Position(first_paragraph, 10); + const auto& end = Position(first_paragraph, 19); + ASSERT_EQ("test page", PlainText(EphemeralRange(start, end))); + IntRect rect(ComputeTextRect(EphemeralRange(start, end))); + gfx::Rect expected_rect = + gfx::Rect(GetDocument().GetFrame()->View()->FrameToViewport(rect)); + // ExtractFirstTextFragmentsRect should return the first matched viewport + // relative location. + ASSERT_EQ(expected_rect.ToString(), "108,10 90x10"); + + gfx::Rect text_fragment_rect = ExtractFirstTextFragmentsRect(); + + EXPECT_EQ(expected_rect.ToString(), text_fragment_rect.ToString()); +} + +TEST_F(TextFragmentHandlerTest, + ExtractFirstTextFragmentRectMultipleHighlightWithNoFoundText) { + base::test::ScopedFeatureList feature_list_; + feature_list_.InitAndEnableFeature( + shared_highlighting::kSharedHighlightingV2); + SimRequest request( + "https://example.com/" + "test.html#:~:text=fake&text=test%20page", + "text/html"); + LoadURL( + "https://example.com/" + "test.html#:~:text=fake&text=test%20page"); + request.Complete(R"HTML( + <!DOCTYPE html> + <meta name="viewport" content="width=device-width"> + <style> + p { + font: 10px/1 Ahem; + } + body { + height: 1200px; + } + #second { + position: absolute; + top: 1000px; + } + </style> + <p id="first">This is a test page</p> + )HTML"); + RunAsyncMatchingTasks(); + LoadAhem(); + + Compositor().BeginFrame(); + + EXPECT_EQ(1u, GetDocument().Markers().Markers().size()); + + Node* first_paragraph = GetDocument().getElementById("first")->firstChild(); + const auto& start = Position(first_paragraph, 10); + const auto& end = Position(first_paragraph, 19); + ASSERT_EQ("test page", PlainText(EphemeralRange(start, end))); + IntRect rect(ComputeTextRect(EphemeralRange(start, end))); + gfx::Rect expected_rect = + gfx::Rect(GetDocument().GetFrame()->View()->FrameToViewport(rect)); + // ExtractFirstTextFragmentsRect should return the first matched viewport + // relative location. + ASSERT_EQ(expected_rect.ToString(), "108,10 90x10"); + + gfx::Rect text_fragment_rect = ExtractFirstTextFragmentsRect(); + + EXPECT_EQ(expected_rect.ToString(), text_fragment_rect.ToString()); +} + +TEST_F(TextFragmentHandlerTest, RejectExtractFirstTextFragmentRect) { + base::test::ScopedFeatureList feature_list_; + feature_list_.InitAndEnableFeature( + shared_highlighting::kSharedHighlightingV2); + SimRequest request( + "https://example.com/" + "test.html#:~:text=not%20on%20the%20page", + "text/html"); + LoadURL( + "https://example.com/" + "test.html#:~:text=not%20on%20the%20page"); + request.Complete(R"HTML( + <!DOCTYPE html> + <meta name="viewport" content="width=device-width"> + <style> + p { + font: 10px/1 Ahem; + } + body { + height: 1200px; + } + #second { + position: absolute; + top: 1000px; + } + </style> + <p id="first">This is a test page</p> + <p id="second">With some more text</p> + )HTML"); + RunAsyncMatchingTasks(); + LoadAhem(); + + Compositor().BeginFrame(); + + EXPECT_EQ(0u, GetDocument().Markers().Markers().size()); + + gfx::Rect text_fragment_rect = ExtractFirstTextFragmentsRect(); + + EXPECT_TRUE(text_fragment_rect.IsEmpty()); +} + } // namespace } // namespace blink
diff --git a/third_party/blink/renderer/core/style/computed_style.cc b/third_party/blink/renderer/core/style/computed_style.cc index bbd75a4..52b16de 100644 --- a/third_party/blink/renderer/core/style/computed_style.cc +++ b/third_party/blink/renderer/core/style/computed_style.cc
@@ -2431,7 +2431,7 @@ absl::optional<Color> ComputedStyle::AccentColorResolved() const { const StyleAutoColor& auto_color = AccentColor(); - if (auto_color.IsAutoColor()) + if (auto_color.IsAutoColor() || ShouldForceColor(auto_color)) return absl::nullopt; return auto_color.Resolve(GetCurrentColor(), UsedColorScheme()); }
diff --git a/third_party/blink/renderer/core/style/computed_style.h b/third_party/blink/renderer/core/style/computed_style.h index d69671d..d868f42 100644 --- a/third_party/blink/renderer/core/style/computed_style.h +++ b/third_party/blink/renderer/core/style/computed_style.h
@@ -208,6 +208,7 @@ // Accesses GetColor(). friend class ComputedStyleUtils; // These get visited and unvisited colors separately. + friend class css_longhand::AccentColor; friend class css_longhand::BackgroundColor; friend class css_longhand::BorderBottomColor; friend class css_longhand::BorderLeftColor;
diff --git a/third_party/blink/renderer/core/style/filter_operation.h b/third_party/blink/renderer/core/style/filter_operation.h index 0865cb6..afda061 100644 --- a/third_party/blink/renderer/core/style/filter_operation.h +++ b/third_party/blink/renderer/core/style/filter_operation.h
@@ -349,8 +349,7 @@ class CORE_EXPORT ConvolveMatrixFilterOperation : public FilterOperation { public: - ConvolveMatrixFilterOperation(Filter* filter, - const IntSize& kernel_size, + ConvolveMatrixFilterOperation(const IntSize& kernel_size, float divisor, float bias, const IntPoint& target_offset,
diff --git a/third_party/blink/renderer/core/svg/svg_text_element.cc b/third_party/blink/renderer/core/svg/svg_text_element.cc index 0e9a2d1..e311c65 100644 --- a/third_party/blink/renderer/core/svg/svg_text_element.cc +++ b/third_party/blink/renderer/core/svg/svg_text_element.cc
@@ -29,7 +29,7 @@ LayoutObject* SVGTextElement::CreateLayoutObject(const ComputedStyle& style, LegacyLayout legacy) { - return LayoutObjectFactory::CreateSVGText(*this, legacy); + return LayoutObjectFactory::CreateSVGText(*this, style, legacy); } } // namespace blink
diff --git a/third_party/blink/renderer/core/testing/page_test_base.cc b/third_party/blink/renderer/core/testing/page_test_base.cc index 6565285..97f9ac0 100644 --- a/third_party/blink/renderer/core/testing/page_test_base.cc +++ b/third_party/blink/renderer/core/testing/page_test_base.cc
@@ -22,6 +22,7 @@ #include "third_party/blink/renderer/core/html/html_collection.h" #include "third_party/blink/renderer/core/html/html_element.h" #include "third_party/blink/renderer/core/layout/layout_object.h" +#include "third_party/blink/renderer/core/layout/layout_text_fragment.h" #include "third_party/blink/renderer/core/testing/mock_policy_container_host.h" #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h" #include "third_party/blink/renderer/platform/wtf/shared_buffer.h" @@ -51,6 +52,8 @@ ostream << *node; else ostream << "(anonymous)"; + if (auto* layout_text_fragment = DynamicTo<LayoutTextFragment>(layout_object)) + ostream << " (" << layout_text_fragment->GetText() << ")"; ostream << std::endl; for (auto* child = layout_object.SlowFirstChild(); child; child = child->NextSibling()) {
diff --git a/third_party/blink/renderer/modules/accessibility/ax_sparse_attribute_setter.cc b/third_party/blink/renderer/modules/accessibility/ax_sparse_attribute_setter.cc index 66089e80..af587c98 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_sparse_attribute_setter.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_sparse_attribute_setter.cc
@@ -3,8 +3,10 @@ // found in the LICENSE file. #include "third_party/blink/renderer/modules/accessibility/ax_sparse_attribute_setter.h" +#include "third_party/blink/public/mojom/web_feature/web_feature.mojom-blink.h" #include "third_party/blink/renderer/core/dom/qualified_name.h" #include "third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h" +#include "third_party/blink/renderer/platform/instrumentation/use_counter.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" #include "third_party/blink/renderer/platform/wtf/functional.h" @@ -21,6 +23,18 @@ AXObject* object, ui::AXNodeData* node_data, const AtomicString& value) { + // Don't set kTouchPassthrough unless the feature is enabled in this + // context. + if (attribute == ax::mojom::blink::BoolAttribute::kTouchPassthrough) { + auto* context = object->AXObjectCache().GetDocument().GetExecutionContext(); + if (RuntimeEnabledFeatures::AccessibilityAriaTouchPassthroughEnabled( + context)) { + UseCounter::Count(context, WebFeature::kAccessibilityTouchPassthroughSet); + } else { + return; + } + } + // ARIA booleans are true if not "false" and not specifically undefined. bool is_true = !AccessibleNode::IsUndefinedAttrValue(value) && !EqualIgnoringASCIICase(value, "false");
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_filter_dictionary.idl b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_filter_dictionary.idl index 17d2df35..6421cc3 100644 --- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_filter_dictionary.idl +++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_filter_dictionary.idl
@@ -6,4 +6,5 @@ dictionary CanvasFilterDictionary { object blur; object colorMatrix; + object convolveMatrix; };
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_filter_operation_resolver.cc b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_filter_operation_resolver.cc index 6968aaa..f51498f 100644 --- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_filter_operation_resolver.cc +++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_filter_operation_resolver.cc
@@ -8,24 +8,41 @@ namespace blink { namespace { -double GetDoubleValueOrZero(v8::Local<v8::Object> v8_object, - WTF::String key, - ScriptState* script_state) { +double GetDoubleOr(double default_value, + v8::Local<v8::Object> v8_object, + WTF::String key, + ScriptState* script_state) { v8::Local<v8::Value> v8_value; if (!v8_object ->Get(script_state->GetContext(), V8String(script_state->GetIsolate(), key)) .ToLocal(&v8_value) || !v8_value->IsNumber()) { - return 0; + return default_value; } double result = v8_value.As<v8::Number>()->Value(); if (!std::isfinite(result)) - return 0; + return default_value; return result; } +bool GetBooleanOr(bool default_value, + v8::Local<v8::Object> v8_object, + WTF::String key, + ScriptState* script_state) { + v8::Local<v8::Value> v8_value; + if (!v8_object + ->Get(script_state->GetContext(), + V8String(script_state->GetIsolate(), key)) + .ToLocal(&v8_value) || + !v8_value->IsBoolean()) { + return default_value; + } + + return v8_value.As<v8::Boolean>()->Value(); +} + String GetStringValue(v8::Local<v8::Object> v8_object, WTF::String key, ScriptState* script_state) { @@ -37,14 +54,13 @@ return String(); return ToCoreStringWithUndefinedOrNullCheck(v8_type); } -} // namespace -BlurFilterOperation* ResolveBlur(v8::Local<v8::Object> v8_filter_object, +BlurFilterOperation* ResolveBlur(v8::Local<v8::Object> v8_filter_obj, ScriptState* script_state, ExceptionState& exception_state) { Length std_deviation = Length::Fixed(0); v8::Local<v8::Value> v8_std_deviation; - if (v8_filter_object + if (v8_filter_obj ->Get(script_state->GetContext(), V8String(script_state->GetIsolate(), "stdDeviation")) .ToLocal(&v8_std_deviation)) { @@ -69,12 +85,12 @@ } ColorMatrixFilterOperation* ResolveColorMatrix( - v8::Local<v8::Object> v8_filter_object, + v8::Local<v8::Object> v8_filter_obj, ScriptState* script_state, ExceptionState& exception_state) { v8::Local<v8::Value> v8_value; v8::Local<v8::Array> v8_array; - if (v8_filter_object + if (v8_filter_obj ->Get(script_state->GetContext(), V8String(script_state->GetIsolate(), "values")) .ToLocal(&v8_value)) { @@ -121,6 +137,122 @@ values, FilterOperation::COLOR_MATRIX); } +struct KernelMatrix { + Vector<float> values; + int width = 0; + int height = 0; +}; + +// For resolving feConvolveMatrix type filters +KernelMatrix* GetKernelMatrix(v8::Local<v8::Object> v8_filter_obj, + ScriptState* script_state, + ExceptionState& exception_state) { + v8::Local<v8::Value> v8_value; + v8::Local<v8::Array> v8_kernel_matrix; + if (v8_filter_obj + ->Get(script_state->GetContext(), + V8String(script_state->GetIsolate(), "kernelMatrix")) + .ToLocal(&v8_value)) { + if (!v8_value->IsArray()) { + exception_state.ThrowTypeError( + "Failed to construct convolve matrix filter. 'kernelMatrix' must be " + "an array of arrays representing an n by m matrix."); + return nullptr; + } + v8_kernel_matrix = v8_value.As<v8::Array>(); + } + + KernelMatrix* kernel_matrix = new KernelMatrix(); + kernel_matrix->height = v8_kernel_matrix->Length(); + v8::Local<v8::Array> v8_kernel_matrix_row; + if (!v8_kernel_matrix->Get(script_state->GetContext(), 0) + .ToLocal(&v8_value) || + !v8_value->IsArray()) { + exception_state.ThrowTypeError( + "Failed to construct convolve matrix filter. 'kernelMatrix' must be an " + "array of arrays representing an n by m matrix."); + return nullptr; + } + v8_kernel_matrix_row = v8_value.As<v8::Array>(); + kernel_matrix->width = v8_kernel_matrix_row->Length(); + kernel_matrix->values.ReserveInitialCapacity(kernel_matrix->width * + kernel_matrix->height); + + for (int y = 0; y < kernel_matrix->height; ++y) { + if (!v8_kernel_matrix->Get(script_state->GetContext(), y) + .ToLocal(&v8_value) || + !v8_value->IsArray()) { + exception_state.ThrowTypeError( + "Failed to construct convolve matrix filter. 'kernelMatrix' must be " + "an array of arrays representing an n by m matrix."); + return nullptr; + } + v8_kernel_matrix_row = v8_value.As<v8::Array>(); + if (int(v8_kernel_matrix_row->Length()) != kernel_matrix->width) { + exception_state.ThrowTypeError( + "Failed to construct convolve matrix filter. All rows of the " + "'kernelMatrix' must be the same length."); + return nullptr; + } + + for (int x = 0; x < kernel_matrix->width; ++x) { + if (!v8_kernel_matrix_row->Get(script_state->GetContext(), x) + .ToLocal(&v8_value) || + !v8_value->IsNumber()) { + exception_state.ThrowTypeError( + "Failed to construct convolve matrix filter. All 'kernelMatrix' " + "values must be numbers."); + return nullptr; + } + const float value = v8_value.As<v8::Number>()->Value(); + if (!std::isfinite(value)) { + exception_state.ThrowTypeError( + "Failed to construct convolve matrix filter, 'kernel_matrix' must " + "have finite values."); + return kernel_matrix; + } + kernel_matrix->values.push_back(value); + } + } + + return kernel_matrix; +} + +ConvolveMatrixFilterOperation* ResolveConvolveMatrix( + v8::Local<v8::Object> v8_filter_obj, + ScriptState* script_state, + ExceptionState& exception_state) { + KernelMatrix* kernel_matrix = + GetKernelMatrix(v8_filter_obj, script_state, exception_state); + + if (!kernel_matrix) + return nullptr; + + IntSize kernel_size(kernel_matrix->width, kernel_matrix->height); + double divisor = GetDoubleOr(1, v8_filter_obj, "divisor", script_state); + double bias = GetDoubleOr(0, v8_filter_obj, "bias", script_state); + IntPoint target_offset = + IntPoint(int(GetDoubleOr(kernel_matrix->width / 2, v8_filter_obj, + "targetX", script_state)), + int(GetDoubleOr(kernel_matrix->height / 2, v8_filter_obj, + "targetY", script_state))); + FEConvolveMatrix::EdgeModeType edge_mode = + FEConvolveMatrix::EDGEMODE_DUPLICATE; + String edge_mode_string = + GetStringValue(v8_filter_obj, "edgeMode", script_state); + if (edge_mode_string == "wrap") + edge_mode = FEConvolveMatrix::EDGEMODE_WRAP; + if (edge_mode_string == "none") + edge_mode = FEConvolveMatrix::EDGEMODE_NONE; + bool preserve_alpha = + GetBooleanOr(false, v8_filter_obj, "preserve_alpha", script_state); + + return MakeGarbageCollected<ConvolveMatrixFilterOperation>( + kernel_size, divisor, bias, target_offset, edge_mode, preserve_alpha, + kernel_matrix->values); +} +} // namespace + FilterOperations CanvasFilterOperationResolver::CreateFilterOperations( ScriptState* script_state, HeapVector<Member<CanvasFilterDictionary>> filters, @@ -142,12 +274,12 @@ &v8_object)) { String type = GetStringValue(v8_object, "type", script_state); if (type == "hueRotate") { - double amount = GetDoubleValueOrZero(v8_object, "values", script_state); + double amount = GetDoubleOr(0, v8_object, "values", script_state); operations.Operations().push_back( MakeGarbageCollected<BasicColorMatrixFilterOperation>( amount, FilterOperation::HUE_ROTATE)); } else if (type == "saturate") { - double amount = GetDoubleValueOrZero(v8_object, "values", script_state); + double amount = GetDoubleOr(0, v8_object, "values", script_state); operations.Operations().push_back( MakeGarbageCollected<BasicColorMatrixFilterOperation>( amount, FilterOperation::SATURATE)); @@ -160,6 +292,14 @@ operations.Operations().push_back(color_matrix_operation); } } + if (filter->hasConvolveMatrix() && + filter->convolveMatrix().V8Value()->ToObject(context).ToLocal( + &v8_object)) { + if (auto* convolve_operation = + ResolveConvolveMatrix(v8_object, script_state, exception_state)) { + operations.Operations().push_back(convolve_operation); + } + } } return operations;
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index cf74ce4..2951941 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -116,6 +116,11 @@ status: "stable", }, { + name: "AccessibilityAriaTouchPassthrough", + status: "experimental", + origin_trial_feature_name: "AccessibilityAriaTouchPassthrough", + }, + { name: "AccessibilityAriaVirtualContent", status: "experimental", },
diff --git a/third_party/blink/web_tests/android/ChromeWPTOverrideExpectations b/third_party/blink/web_tests/android/ChromeWPTOverrideExpectations index 782577dd4..12fbcf7 100644 --- a/third_party/blink/web_tests/android/ChromeWPTOverrideExpectations +++ b/third_party/blink/web_tests/android/ChromeWPTOverrideExpectations
@@ -130,14 +130,8 @@ crbug.com/1198573 external/wpt/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-events.sharedworker.html [ Failure ] crbug.com/1198573 external/wpt/html/webappapis/the-windoworworkerglobalscope-mixin/Worker_Self_Origin.html [ Failure ] -# Flaky failure on a DCHECK in DevToolsAgent::ReportChildWorkersCallback -crbug.com/1199769 external/wpt/background-fetch/abort.https.window.html [ Crash Pass ] -crbug.com/1199769 external/wpt/background-fetch/fetch-uploads.https.window.html [ Crash Pass ] -crbug.com/1199769 external/wpt/background-fetch/fetch.https.window.html [ Crash Pass ] -crbug.com/1199769 external/wpt/background-fetch/match.https.window.html [ Crash Pass ] -crbug.com/1199769 external/wpt/background-fetch/mixed-content-and-allowed-schemes.https.window.html [ Crash ] -crbug.com/1199769 external/wpt/background-fetch/port-blocking.https.window.html [ Crash Pass ] -crbug.com/1199769 external/wpt/background-fetch/update-ui.https.window.html [ Crash Pass ] +# Failing background-fetch tests. +crbug.com/882282 external/wpt/background-fetch/fetch.https.window.html [ Failure Pass Timeout ] # crbug.com/178097: navigator.registerProtocolHandler is not available on Android. crbug.com/1198573 external/wpt/html/webappapis/system-state-and-capabilities/the-navigator-object/historical.https.window.html [ Failure ]
diff --git a/third_party/blink/web_tests/android/WebLayerWPTOverrideExpectations b/third_party/blink/web_tests/android/WebLayerWPTOverrideExpectations index 3b57b6c..1a3f28fa 100644 --- a/third_party/blink/web_tests/android/WebLayerWPTOverrideExpectations +++ b/third_party/blink/web_tests/android/WebLayerWPTOverrideExpectations
@@ -68,6 +68,7 @@ crbug.com/1198063 external/wpt/scroll-animations/scroll-timeline-snapshotting.html [ Timeout ] # SharedWorker is not supported on Android (https://crbug.com/154571). +crbug.com/1050754 external/wpt/background-fetch/idlharness.https.any.sharedworker.html [ Failure ] crbug.com/1190392 external/wpt/trusted-types/WorkerGlobalScope-eval.html [ Failure ] crbug.com/1190392 external/wpt/trusted-types/WorkerGlobalScope-importScripts.html [ Failure ] crbug.com/1190392 external/wpt/trusted-types/worker-constructor.https.html [ Failure ] @@ -313,15 +314,8 @@ crbug.com/1198089 external/wpt/webcodecs/videoFrame-texImage.any.html [ Failure Pass ] crbug.com/1198089 external/wpt/webcodecs/videoFrame-texImage.any.worker.html [ Failure Pass ] -# Flaky failure on a DCHECK in DevToolsAgent::ReportChildWorkersCallback. For some reason, this is classified as a Failure here and -# a Crash in Chrome. -crbug.com/1199769 external/wpt/background-fetch/abort.https.window.html [ Failure Pass ] -crbug.com/1199769 external/wpt/background-fetch/fetch-uploads.https.window.html [ Failure Pass ] -crbug.com/1199769 external/wpt/background-fetch/fetch.https.window.html [ Failure Pass Timeout ] -crbug.com/1199769 external/wpt/background-fetch/match.https.window.html [ Failure Pass ] -crbug.com/1199769 external/wpt/background-fetch/mixed-content-and-allowed-schemes.https.window.html [ Failure Pass ] -crbug.com/1199769 external/wpt/background-fetch/port-blocking.https.window.html [ Failure Pass ] -crbug.com/1199769 external/wpt/background-fetch/update-ui.https.window.html [ Failure Pass ] +# Failing background-fetch tests. +crbug.com/882282 external/wpt/background-fetch/fetch.https.window.html [ Failure Pass Timeout ] # Test seems to be flaky on both Chrome and WebLayer. crbug.com/1177918 external/wpt/input-events/input-events-get-target-ranges.html [ Failure Pass ] @@ -344,9 +338,6 @@ crbug.com/1050754 external/wpt/animation-worklet/inactive-timeline.https.html [ Timeout ] crbug.com/1050754 external/wpt/animation-worklet/scroll-timeline-writing-modes.https.html [ Failure ] crbug.com/1050754 external/wpt/animation-worklet/worklet-animation-local-time-null-1.https.html [ Failure Pass ] -crbug.com/1050754 external/wpt/background-fetch/get-ids.https.window.html [ Pass ] -crbug.com/1050754 external/wpt/background-fetch/get.https.window.html [ Pass ] -crbug.com/1050754 external/wpt/background-fetch/idlharness.https.any.sharedworker.html [ Failure ] crbug.com/1050754 external/wpt/bluetooth/adapter/adapter-absent-getAvailability.https.window.html [ Failure ] crbug.com/1050754 external/wpt/bluetooth/adapter/adapter-added-getAvailability.https.window.html [ Failure ] crbug.com/1050754 external/wpt/bluetooth/adapter/adapter-powered-off-getAvailability.https.window.html [ Failure ]
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/flex-basis-011-ref.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/flex-basis-011-ref.html index e1a968b..8c9d248 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-flexbox/flex-basis-011-ref.html +++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/flex-basis-011-ref.html
@@ -1,18 +1,20 @@ <!DOCTYPE html> <link rel="author" title="Sergio Villar Senin" href="mailto:svillar@igalia.com"> +<link href="support/flexbox.css" rel="stylesheet"> <style> -.item { +.flex-item { + flex: 1 0 auto; + height: 100%; border: 1px solid blue; } </style> -<p>Test PASS if there are two boxes with blue borders vertically stretched to fit their contents.</p> -<div style="width: min-content"> - <div> - <div class="item"> +<div class="flexbox"> + <div class="flexbox column"> + <div class="flex-item"> <div>AAA</div> </div> - <div class="item"> + <div class="flex-item"> <div>BBB</div> </div> </div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/flex-basis-011.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/flex-basis-011.html index 78bbd5d8..9edb5dc9 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-flexbox/flex-basis-011.html +++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/flex-basis-011.html
@@ -12,7 +12,6 @@ } </style> -<p>Test PASS if there are two boxes with blue borders vertically stretched to fit their contents.</p> <div class="flexbox"> <div class="flexbox column"> <div class="flex-item">
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/flex-basis-012.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/flex-basis-012.html new file mode 100644 index 0000000..b1addde --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/flex-basis-012.html
@@ -0,0 +1,9 @@ +<!DOCTYPE html> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1199632"> +<link rel="match" href="../reference/ref-filled-green-100px-square.xht"> +<p>Test passes if there is a filled green square and <strong>no red</strong>.</p> +<div style="display: flex; flex-direction: column; width: 100px;"> + <div style="display: flex; flex-direction: column; height: 100px; background: red;"> + <div style="flex-basis: 100%; background: green;"></div> + </div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/accent-color-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/accent-color-expected.txt new file mode 100644 index 0000000..3c4e773 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/accent-color-expected.txt
@@ -0,0 +1,21 @@ +This is a testharness.js-based test. +PASS Can set 'accent-color' to CSS-wide keywords +PASS Can set 'accent-color' to var() references +PASS Can set 'accent-color' to the 'currentcolor' keyword +FAIL Can set 'accent-color' to the 'auto' keyword assert_class_string: expected "[object CSSStyleValue]" but got "[object CSSKeywordValue]" +PASS Setting 'accent-color' to a length throws TypeError +PASS Setting 'accent-color' to a percent throws TypeError +PASS Setting 'accent-color' to a time throws TypeError +PASS Setting 'accent-color' to an angle throws TypeError +PASS Setting 'accent-color' to a flexible length throws TypeError +PASS Setting 'accent-color' to a number throws TypeError +PASS Setting 'accent-color' to a position throws TypeError +PASS Setting 'accent-color' to a URL throws TypeError +PASS Setting 'accent-color' to a transform throws TypeError +PASS 'accent-color' does not supported 'red' +PASS 'accent-color' does not supported '#bbff00' +PASS 'accent-color' does not supported 'rgb(255, 255, 128)' +PASS 'accent-color' does not supported 'hsl(50, 33%, 25%)' +PASS 'accent-color' does not supported 'transparent' +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/accent-color.html b/third_party/blink/web_tests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/accent-color.html new file mode 100644 index 0000000..8cd0b98 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/accent-color.html
@@ -0,0 +1,35 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>'accent-color' property</title> +<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get"> +<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set"> +<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../../resources/testhelper.js"></script> +<script src="resources/testsuite.js"></script> +<body> +<div id="log"></div> +<script> +'use strict'; + +runPropertyTests('accent-color', [ + { + syntax: 'currentcolor', + // computes to a <color>, which is not supported in level 1 + computed: (_, result) => assert_class_string(result, 'CSSStyleValue') + }, + { + syntax: 'auto', + // computes to a <color>, which is not supported in level 1 + computed: (_, result) => assert_class_string(result, 'CSSStyleValue') + } +]); + +// <color>s are not supported in level 1 +runUnsupportedPropertyTests('accent-color', [ + 'red', '#bbff00', 'rgb(255, 255, 128)', 'hsl(50, 33%, 25%)', + 'transparent' +]); + +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/accent-color-computed-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-ui/accent-color-computed-expected.txt index 4908625..54594b62 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-ui/accent-color-computed-expected.txt +++ b/third_party/blink/web_tests/external/wpt/css/css-ui/accent-color-computed-expected.txt
@@ -1,7 +1,10 @@ This is a testharness.js-based test. -FAIL Property accent-color value 'initial' assert_equals: expected "auto" but got "" -FAIL Property accent-color value 'inherit' assert_equals: expected "rgb(255, 0, 0)" but got "" -FAIL Property accent-color value 'red' assert_equals: expected "rgb(255, 0, 0)" but got "" -FAIL Property accent-color value 'blue' assert_equals: expected "rgb(0, 0, 255)" but got "" +PASS Property accent-color value 'initial' +PASS Property accent-color value 'inherit' +PASS Property accent-color value 'red' +PASS Property accent-color value 'blue' +PASS Property accent-color value 'auto' +FAIL Property accent-color value 'currentcolor' assert_equals: expected "currentcolor" but got "rgb(0, 0, 0)" +PASS Property accent-color value '#fff' Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/accent-color-computed.html b/third_party/blink/web_tests/external/wpt/css/css-ui/accent-color-computed.html index 896e4bb..10e08010 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-ui/accent-color-computed.html +++ b/third_party/blink/web_tests/external/wpt/css/css-ui/accent-color-computed.html
@@ -9,9 +9,16 @@ <div id="outer"> <div id="target"></div> </div> +<div id=noAccentColor></div> <script> test_computed_value('accent-color', 'initial', 'auto'); test_computed_value('accent-color', 'inherit', 'rgb(255, 0, 0)'); test_computed_value('accent-color', 'red', 'rgb(255, 0, 0)'); test_computed_value('accent-color', 'blue', 'rgb(0, 0, 255)'); +test_computed_value('accent-color', 'auto', 'auto'); +test_computed_value('accent-color', 'currentcolor', 'currentcolor'); +test_computed_value('accent-color', '#fff', 'rgb(255, 255, 255)'); + +// When accent-color isn't specified, it should return 'auto' +assert_equals(getComputedStyle(noAccentColor).accentColor, 'auto'); </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/accent-color-visited-ref.html b/third_party/blink/web_tests/external/wpt/css/css-ui/accent-color-visited-ref.html new file mode 100644 index 0000000..3954a319 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-ui/accent-color-visited-ref.html
@@ -0,0 +1,4 @@ +<!DOCTYPE html> +<a href=""> + <input type=checkbox> +</a>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/accent-color-visited.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-ui/accent-color-visited.tentative.html new file mode 100644 index 0000000..5aee0f1 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-ui/accent-color-visited.tentative.html
@@ -0,0 +1,15 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<link rel="author" title="Joey Arhar" href="mailto:jarhar@chromium.org"> +<link rel="match" href="accent-color-visited-ref.html"> + +<!-- :visited shouldn't apply to accent-color. --> + +<style> +:visited { + accent-color: red; +} +</style> +<a href=""> + <input type=checkbox> +</a>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/animation/accent-color-interpolation.html b/third_party/blink/web_tests/external/wpt/css/css-ui/animation/accent-color-interpolation.html new file mode 100644 index 0000000..20d87c4 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-ui/animation/accent-color-interpolation.html
@@ -0,0 +1,106 @@ +<!DOCTYPE html> +<meta charset="UTF-8"> +<title>accent-color interpolation</title> +<link rel="author" title="Joey Arhar" href="mailto:jarhar@chromium.org"> +<link rel="help" href="https://drafts.csswg.org/css-ui-4/#widget-accent"> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/interpolation-testcommon.js"></script> + +<style> +.parent { + accent-color: blue; +} +.target { + display: inline-block; + font-size: 60pt; + accent-color: yellow; +} +.expected { + margin-right: 15px; +} +</style> + +<body contenteditable> + <template id="target-template">T</template> +</body> + +<script> +test_interpolation({ + property: 'accent-color', + from: neutralKeyframe, + to: 'green', +}, [ + {at: -0.3, expect: 'rgb(255, 255, 0)'}, + {at: 0, expect: 'rgb(255, 255, 0)'}, + {at: 0.3, expect: 'rgb(179, 217, 0)'}, + {at: 0.6, expect: 'rgb(102, 179, 0)'}, + {at: 1, expect: 'rgb(0, 128, 0)'}, + {at: 1.5, expect: 'rgb(0, 65, 0)'}, +]); + +test_no_interpolation({ + property: 'accent-color', + from: 'initial', + to: 'green', +}); + +test_no_interpolation({ + property: 'accent-color', + from: 'auto', + to: 'green', +}); + +test_interpolation({ + property: 'accent-color', + from: 'currentColor', + to: 'green', +}, [ + {at: -0.3, expect: 'rgb(0, 0, 0)'}, + {at: 0, expect: 'rgb(0, 0, 0)'}, + {at: 0.3, expect: 'rgb(0, 38, 0)'}, + {at: 0.6, expect: 'rgb(0, 77, 0)'}, + {at: 1, expect: 'rgb(0, 128, 0)'}, + {at: 1.5, expect: 'rgb(0, 192, 0)'}, +]); + +test_interpolation({ + property: 'accent-color', + from: 'inherit', + to: 'green', +}, [ + {at: -0.3, expect: 'rgb(0, 0, 255)'}, + {at: 0, expect: 'rgb(0, 0, 255)'}, + {at: 0.3, expect: 'rgb(0, 38, 179)'}, + {at: 0.6, expect: 'rgb(0, 77, 102)'}, + {at: 1, expect: 'rgb(0, 128, 0)'}, + {at: 1.5, expect: 'rgb(0, 192, 0)'}, +]); + +test_interpolation({ + property: 'accent-color', + from: 'unset', + to: 'green', +}, [ + {at: -0.3, expect: 'rgb(0, 0, 255)'}, + {at: 0, expect: 'rgb(0, 0, 255)'}, + {at: 0.3, expect: 'rgb(0, 38, 179)'}, + {at: 0.6, expect: 'rgb(0, 77, 102)'}, + {at: 1, expect: 'rgb(0, 128, 0)'}, + {at: 1.5, expect: 'rgb(0, 192, 0)'}, +]); + +test_interpolation({ + property: 'accent-color', + from: 'black', + to: 'orange', +}, [ + {at: -0.3, expect: 'rgb(0, 0, 0)'}, + {at: 0, expect: 'rgb(0, 0, 0)'}, + {at: 0.3, expect: 'rgb(77, 50, 0)'}, + {at: 0.6, expect: 'rgb(153, 99, 0)'}, + {at: 1, expect: 'rgb(255, 165, 0)'}, + {at: 1.5, expect: 'rgb(255, 248, 0)'}, +]); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom/cssstyledeclaration-custom-properties-expected.txt b/third_party/blink/web_tests/external/wpt/css/cssom/cssstyledeclaration-custom-properties-expected.txt index 7287e4f..fdc0f0c6 100644 --- a/third_party/blink/web_tests/external/wpt/css/cssom/cssstyledeclaration-custom-properties-expected.txt +++ b/third_party/blink/web_tests/external/wpt/css/cssom/cssstyledeclaration-custom-properties-expected.txt
@@ -1,4 +1,4 @@ This is a testharness.js-based test. -FAIL Custom properties are included in computed style assert_equals: Should show up in .length expected 342 but got 341 +FAIL Custom properties are included in computed style assert_equals: Should show up in .length expected 343 but got 342 Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom/getComputedStyle-detached-subtree-expected.txt b/third_party/blink/web_tests/external/wpt/css/cssom/getComputedStyle-detached-subtree-expected.txt index 97d84ff..e1c2ab5 100644 --- a/third_party/blink/web_tests/external/wpt/css/cssom/getComputedStyle-detached-subtree-expected.txt +++ b/third_party/blink/web_tests/external/wpt/css/cssom/getComputedStyle-detached-subtree-expected.txt
@@ -1,9 +1,9 @@ This is a testharness.js-based test. PASS getComputedStyle returns no style for detached element -FAIL getComputedStyle returns no style for element in non-rendered iframe (display: none) assert_equals: expected 0 but got 341 -FAIL getComputedStyle returns no style for element in non-rendered iframe (display: none) from iframe's window assert_equals: expected 0 but got 341 -FAIL getComputedStyle returns no style for element outside the flat tree assert_equals: expected 0 but got 341 -FAIL getComputedStyle returns no style for descendant outside the flat tree assert_equals: expected 0 but got 341 +FAIL getComputedStyle returns no style for element in non-rendered iframe (display: none) assert_equals: expected 0 but got 342 +FAIL getComputedStyle returns no style for element in non-rendered iframe (display: none) from iframe's window assert_equals: expected 0 but got 342 +FAIL getComputedStyle returns no style for element outside the flat tree assert_equals: expected 0 but got 342 +FAIL getComputedStyle returns no style for descendant outside the flat tree assert_equals: expected 0 but got 342 PASS getComputedStyle returns no style for shadow tree outside of flattened tree Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/element/filters/2d.filter.canvasFilterObject.convolveMatrix.exceptions.html b/third_party/blink/web_tests/external/wpt/html/canvas/element/filters/2d.filter.canvasFilterObject.convolveMatrix.exceptions.html new file mode 100644 index 0000000..dd7b57c --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/canvas/element/filters/2d.filter.canvasFilterObject.convolveMatrix.exceptions.html
@@ -0,0 +1,35 @@ +<!DOCTYPE html> +<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. --> +<title>Canvas test: 2d.filter.canvasFilterObject.convolveMatrix.exceptions</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/html/canvas/resources/canvas-tests.js"></script> +<link rel="stylesheet" href="/html/canvas/resources/canvas-tests.css"> +<body class="show_output"> + +<h1>2d.filter.canvasFilterObject.convolveMatrix.exceptions</h1> +<p class="desc">Test exceptions on CanvasFilter() convolveMatrix</p> + + +<p class="output">Actual output:</p> +<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas> + +<ul id="d"></ul> +<script> +var t = async_test("Test exceptions on CanvasFilter() convolveMatrix"); +_addTest(function(canvas, ctx) { + +assert_throws_js(TypeError, function() { new CanvasFilter({convolveMatrix: {}}); }); +assert_throws_js(TypeError, function() { new CanvasFilter({convolveMatrix: null}); }); +assert_throws_js(TypeError, function() { new CanvasFilter({convolveMatrix: {divisor: 2}}); }); +assert_throws_js(TypeError, function() { new CanvasFilter({convolveMatrix: {kernelMatrix: null}}); }); +assert_throws_js(TypeError, function() { new CanvasFilter({convolveMatrix: {kernelMatrix: 1}}); }); +assert_throws_js(TypeError, function() { new CanvasFilter({convolveMatrix: {kernelMatrix: [[1, 0], [0]]}}); }); +assert_throws_js(TypeError, function() { new CanvasFilter({convolveMatrix: {kernelMatrix: [[1, "a"], [0]]}}); }); +assert_throws_js(TypeError, function() { new CanvasFilter({convolveMatrix: {kernelMatrix: [[1, 0], 0]}}); }); +assert_throws_js(TypeError, function() { new CanvasFilter({convolveMatrix: {kernelMatrix: [[1, 0], [0, Infinity]]}}); }); + + +}); +</script> +
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/filters/canvas-filter-object-convolve-matrix-expected.html b/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/filters/canvas-filter-object-convolve-matrix-expected.html new file mode 100644 index 0000000..f8dba9bb --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/filters/canvas-filter-object-convolve-matrix-expected.html
@@ -0,0 +1,38 @@ +<body> + <canvas id="canvas"></canvas> + <svg width="0" height="0"> + <filter id="emboss"> + <feConvolveMatrix + kernelMatrix="3 0 0 + 0 0 0 + 0 0 -3"/> + </filter> + </svg> +</body> +<script type="text/javascript"> + +const canvas = document.getElementById("canvas"); +const ctx = canvas.getContext("2d"); + +function draw() { + ctx.fillRect(20, 20, 100, 100); + + ctx.beginPath(); + ctx.arc(150, 70, 50, 0, 2*Math.PI); + ctx.fill(); + + ctx.beginPath(); + ctx.moveTo(220, 20); + ctx.lineTo(170, 120); + ctx.lineTo(270, 120); + ctx.lineTo(220, 20); + ctx.fill(); +} + +ctx.fillStyle = "rgba(0,255,0,0.5)"; +draw(); +ctx.fillStyle = "rgba(255,0,255,0.5)"; +ctx.filter = "url('#emboss')"; +draw(); + +</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/filters/canvas-filter-object-convolve-matrix.html b/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/filters/canvas-filter-object-convolve-matrix.html new file mode 100644 index 0000000..c565107 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/filters/canvas-filter-object-convolve-matrix.html
@@ -0,0 +1,38 @@ +<head> + <link rel="match" href="canvas-filter-object-convolve-matrix-expected.html"> +</head> +<body> + <canvas id="canvas"></canvas> +</body> +<script> + const canvas = document.getElementById("canvas"); + const ctx = canvas.getContext("2d"); + + const convolveFilter = new CanvasFilter({convolveMatrix: { + kernelMatrix: [ + [3, 0, 0], + [0, 0, 0], + [0, 0, -3], + ], + }}); + + function draw() { + ctx.fillRect(20, 20, 100, 100); + + ctx.beginPath(); + ctx.arc(150, 70, 50, 0, 2*Math.PI); + ctx.fill(); + + ctx.beginPath(); + ctx.moveTo(220, 20); + ctx.lineTo(170, 120); + ctx.lineTo(270, 120); + ctx.lineTo(220, 20); + ctx.fill(); + } + ctx.fillStyle = "rgba(0,255,0,0.5)"; + draw(); + ctx.fillStyle = "rgba(255,0,255,0.5)"; + ctx.filter = convolveFilter; + draw(); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.colorMatrix.html b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.colorMatrix.html index ed4fe91..e11013e2 100644 --- a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.colorMatrix.html +++ b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.colorMatrix.html
@@ -64,5 +64,6 @@ _assertPixelApprox(offscreenCanvas, 10,30, 0,255,0,255, "10,30", "0,255,0,255", 2); _assertPixelApprox(offscreenCanvas, 60,30, 0,255,0,255, "60,30", "0,255,0,255", 2); t.done(); + }); </script>
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.colorMatrix.worker.js b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.colorMatrix.worker.js index a2f73e09..3b4959d 100644 --- a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.colorMatrix.worker.js +++ b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.colorMatrix.worker.js
@@ -60,5 +60,6 @@ _assertPixelApprox(offscreenCanvas, 10,30, 0,255,0,255, "10,30", "0,255,0,255", 2); _assertPixelApprox(offscreenCanvas, 60,30, 0,255,0,255, "60,30", "0,255,0,255", 2); t.done(); + }); done();
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.convolveMatrix.exceptions.html b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.convolveMatrix.exceptions.html new file mode 100644 index 0000000..e8838ff --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.convolveMatrix.exceptions.html
@@ -0,0 +1,35 @@ +<!DOCTYPE html> +<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. --> +<title>OffscreenCanvas test: 2d.filter.canvasFilterObject.convolveMatrix.exceptions</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/html/canvas/resources/canvas-tests.js"></script> + +<h1>2d.filter.canvasFilterObject.convolveMatrix.exceptions</h1> +<p class="desc">Test exceptions on CanvasFilter() convolveMatrix</p> + + +<script> +var t = async_test("Test exceptions on CanvasFilter() convolveMatrix"); +var t_pass = t.done.bind(t); +var t_fail = t.step_func(function(reason) { + throw reason; +}); +t.step(function() { + +var offscreenCanvas = new OffscreenCanvas(100, 50); +var ctx = offscreenCanvas.getContext('2d'); + +assert_throws_js(TypeError, function() { new CanvasFilter({convolveMatrix: {}}); }); +assert_throws_js(TypeError, function() { new CanvasFilter({convolveMatrix: null}); }); +assert_throws_js(TypeError, function() { new CanvasFilter({convolveMatrix: {divisor: 2}}); }); +assert_throws_js(TypeError, function() { new CanvasFilter({convolveMatrix: {kernelMatrix: null}}); }); +assert_throws_js(TypeError, function() { new CanvasFilter({convolveMatrix: {kernelMatrix: 1}}); }); +assert_throws_js(TypeError, function() { new CanvasFilter({convolveMatrix: {kernelMatrix: [[1, 0], [0]]}}); }); +assert_throws_js(TypeError, function() { new CanvasFilter({convolveMatrix: {kernelMatrix: [[1, "a"], [0]]}}); }); +assert_throws_js(TypeError, function() { new CanvasFilter({convolveMatrix: {kernelMatrix: [[1, 0], 0]}}); }); +assert_throws_js(TypeError, function() { new CanvasFilter({convolveMatrix: {kernelMatrix: [[1, 0], [0, Infinity]]}}); }); +t.done(); + +}); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.convolveMatrix.exceptions.worker.js b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.convolveMatrix.exceptions.worker.js new file mode 100644 index 0000000..de249c5 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/filters/2d.filter.canvasFilterObject.convolveMatrix.exceptions.worker.js
@@ -0,0 +1,31 @@ +// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. +// OffscreenCanvas test in a worker:2d.filter.canvasFilterObject.convolveMatrix.exceptions +// Description:Test exceptions on CanvasFilter() convolveMatrix +// Note: + +importScripts("/resources/testharness.js"); +importScripts("/html/canvas/resources/canvas-tests.js"); + +var t = async_test("Test exceptions on CanvasFilter() convolveMatrix"); +var t_pass = t.done.bind(t); +var t_fail = t.step_func(function(reason) { + throw reason; +}); +t.step(function() { + +var offscreenCanvas = new OffscreenCanvas(100, 50); +var ctx = offscreenCanvas.getContext('2d'); + +assert_throws_js(TypeError, function() { new CanvasFilter({convolveMatrix: {}}); }); +assert_throws_js(TypeError, function() { new CanvasFilter({convolveMatrix: null}); }); +assert_throws_js(TypeError, function() { new CanvasFilter({convolveMatrix: {divisor: 2}}); }); +assert_throws_js(TypeError, function() { new CanvasFilter({convolveMatrix: {kernelMatrix: null}}); }); +assert_throws_js(TypeError, function() { new CanvasFilter({convolveMatrix: {kernelMatrix: 1}}); }); +assert_throws_js(TypeError, function() { new CanvasFilter({convolveMatrix: {kernelMatrix: [[1, 0], [0]]}}); }); +assert_throws_js(TypeError, function() { new CanvasFilter({convolveMatrix: {kernelMatrix: [[1, "a"], [0]]}}); }); +assert_throws_js(TypeError, function() { new CanvasFilter({convolveMatrix: {kernelMatrix: [[1, 0], 0]}}); }); +assert_throws_js(TypeError, function() { new CanvasFilter({convolveMatrix: {kernelMatrix: [[1, 0], [0, Infinity]]}}); }); +t.done(); + +}); +done();
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml/element/filters.yaml b/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml/element/filters.yaml index c4dabab..11026f4 100644 --- a/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml/element/filters.yaml +++ b/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml/element/filters.yaml
@@ -108,4 +108,18 @@ @assert pixel 60,10 ==~ 0,255,0,255; @assert pixel 10,30 ==~ 0,255,0,255; @assert pixel 60,30 ==~ 0,255,0,255; - expected: green \ No newline at end of file + expected: green + +- name: 2d.filter.canvasFilterObject.convolveMatrix.exceptions + desc: Test exceptions on CanvasFilter() convolveMatrix + code: | + @assert throws TypeError new CanvasFilter({convolveMatrix: {}}); + @assert throws TypeError new CanvasFilter({convolveMatrix: null}); + @assert throws TypeError new CanvasFilter({convolveMatrix: {divisor: 2}}); + @assert throws TypeError new CanvasFilter({convolveMatrix: {kernelMatrix: null}}); + @assert throws TypeError new CanvasFilter({convolveMatrix: {kernelMatrix: 1}}); + @assert throws TypeError new CanvasFilter({convolveMatrix: {kernelMatrix: [[1, 0], [0]]}}); + @assert throws TypeError new CanvasFilter({convolveMatrix: {kernelMatrix: [[1, "a"], [0]]}}); + @assert throws TypeError new CanvasFilter({convolveMatrix: {kernelMatrix: [[1, 0], 0]}}); + @assert throws TypeError new CanvasFilter({convolveMatrix: {kernelMatrix: [[1, 0], [0, Infinity]]}}); +
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml/offscreen/filters.yaml b/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml/offscreen/filters.yaml index dd11080..1bcd5bb0 100644 --- a/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml/offscreen/filters.yaml +++ b/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml/offscreen/filters.yaml
@@ -76,4 +76,18 @@ @assert pixel 60,10 ==~ 0,255,0,255; @assert pixel 10,30 ==~ 0,255,0,255; @assert pixel 60,30 ==~ 0,255,0,255; - t.done(); \ No newline at end of file + t.done(); + +- name: 2d.filter.canvasFilterObject.convolveMatrix.exceptions + desc: Test exceptions on CanvasFilter() convolveMatrix + code: | + @assert throws TypeError new CanvasFilter({convolveMatrix: {}}); + @assert throws TypeError new CanvasFilter({convolveMatrix: null}); + @assert throws TypeError new CanvasFilter({convolveMatrix: {divisor: 2}}); + @assert throws TypeError new CanvasFilter({convolveMatrix: {kernelMatrix: null}}); + @assert throws TypeError new CanvasFilter({convolveMatrix: {kernelMatrix: 1}}); + @assert throws TypeError new CanvasFilter({convolveMatrix: {kernelMatrix: [[1, 0], [0]]}}); + @assert throws TypeError new CanvasFilter({convolveMatrix: {kernelMatrix: [[1, "a"], [0]]}}); + @assert throws TypeError new CanvasFilter({convolveMatrix: {kernelMatrix: [[1, 0], 0]}}); + @assert throws TypeError new CanvasFilter({convolveMatrix: {kernelMatrix: [[1, 0], [0, Infinity]]}}); + t.done();
diff --git a/third_party/blink/web_tests/fast/css/getComputedStyle/computed-style-listing-expected.txt b/third_party/blink/web_tests/fast/css/getComputedStyle/computed-style-listing-expected.txt index f78c331..f8f5f87 100644 --- a/third_party/blink/web_tests/fast/css/getComputedStyle/computed-style-listing-expected.txt +++ b/third_party/blink/web_tests/fast/css/getComputedStyle/computed-style-listing-expected.txt
@@ -50,6 +50,7 @@ -webkit-user-drag: auto -webkit-user-modify: read-only -webkit-writing-mode: horizontal-tb +accent-color: auto align-content: normal align-items: normal align-self: auto
diff --git a/third_party/blink/web_tests/fast/css/getComputedStyle/computed-style-without-renderer-listing-expected.txt b/third_party/blink/web_tests/fast/css/getComputedStyle/computed-style-without-renderer-listing-expected.txt index cd8e69e..ee3b24f 100644 --- a/third_party/blink/web_tests/fast/css/getComputedStyle/computed-style-without-renderer-listing-expected.txt +++ b/third_party/blink/web_tests/fast/css/getComputedStyle/computed-style-without-renderer-listing-expected.txt
@@ -50,6 +50,7 @@ -webkit-user-drag: auto -webkit-user-modify: read-only -webkit-writing-mode: horizontal-tb +accent-color: auto align-content: normal align-items: normal align-self: auto
diff --git a/third_party/blink/web_tests/svg/css/getComputedStyle-listing-expected.txt b/third_party/blink/web_tests/svg/css/getComputedStyle-listing-expected.txt index cb25ba9..418e082 100644 --- a/third_party/blink/web_tests/svg/css/getComputedStyle-listing-expected.txt +++ b/third_party/blink/web_tests/svg/css/getComputedStyle-listing-expected.txt
@@ -50,6 +50,7 @@ -webkit-user-drag: auto -webkit-user-modify: read-only -webkit-writing-mode: horizontal-tb +accent-color: auto align-content: normal align-items: normal align-self: auto
diff --git a/third_party/crashpad/README.chromium b/third_party/crashpad/README.chromium index 2608fe3..cf4fd68 100644 --- a/third_party/crashpad/README.chromium +++ b/third_party/crashpad/README.chromium
@@ -42,3 +42,5 @@ - MemoryMap.SelfLargeMapFile, SelfBasic, SelfLargeFiles are disabled when BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) are defined. crbug.com/1163794 (crashpad/util/BUILD.gn, crashpad/util/linux/memory_map_test.cc) + - CloseMultipleNowOrOnExec has been updated to invoke the new + base::subtle::ResetFDOwnership() API
diff --git a/third_party/crashpad/crashpad/util/posix/close_multiple.cc b/third_party/crashpad/crashpad/util/posix/close_multiple.cc index 0c07832..a26ff94b 100644 --- a/third_party/crashpad/crashpad/util/posix/close_multiple.cc +++ b/third_party/crashpad/crashpad/util/posix/close_multiple.cc
@@ -109,6 +109,12 @@ } // namespace void CloseMultipleNowOrOnExec(int fd, int preserve_fd) { +#if defined(OS_LINUX) || defined(OS_CHROMEOS) + // See comments on the ResetFDOwnership() declaration in + // base/files/scoped_file.h regarding why this is called here. + base::subtle::ResetFDOwnership(); +#endif + if (CloseMultipleNowOrOnExecUsingFDDir(fd, preserve_fd)) { return; }
diff --git a/tools/android/checkstyle/checkstyle.py b/tools/android/checkstyle/checkstyle.py index 21cf13b..987ba0b 100644 --- a/tools/android/checkstyle/checkstyle.py +++ b/tools/android/checkstyle/checkstyle.py
@@ -52,7 +52,7 @@ 'com.puppycrawl.tools.checkstyle.Main', '-c', style_file, '-f', 'xml'] + java_files, stdout=subprocess.PIPE) - stdout, _ = check.communicate() + stdout = check.communicate()[0].decode('utf-8') result_errors = [] result_warnings = []
diff --git a/tools/licenses.py b/tools/licenses.py index aaa520b..7c2e504 100755 --- a/tools/licenses.py +++ b/tools/licenses.py
@@ -438,7 +438,7 @@ raise LicenseError("missing README.chromium or licenses.py " "SPECIAL_CASES entry in %s\n" % path) - for line in open(readme_path): + for line in codecs.open(readme_path, encoding='utf-8'): line = line.strip() if not line: break @@ -500,7 +500,7 @@ third_party_dirs.""" additional_paths_file = os.path.join(root, dirname, ADDITIONAL_PATHS_FILENAME) if os.path.exists(additional_paths_file): - with open(additional_paths_file) as paths_file: + with codecs.open(additional_paths_file, encoding='utf-8') as paths_file: extra_paths = json.load(paths_file) third_party_dirs.update([os.path.join(dirname, p) for p in extra_paths]) @@ -673,7 +673,8 @@ env = { 'name': metadata['Name'], 'url': metadata['URL'], - 'license': open(metadata['License File']).read(), + 'license': codecs.open(metadata['License File'], + encoding='utf-8').read(), } return { 'name': metadata['Name'], @@ -701,7 +702,7 @@ 'about_ui', 'resources', 'about_credits_entry.tmpl') - entry_template = open(entry_template_file).read() + entry_template = codecs.open(entry_template_file, encoding='utf-8').read() entries = [] # Start from Chromium's LICENSE file chromium_license_metadata = { @@ -744,7 +745,7 @@ entry['content'] = entry['content'].replace('{{id}}', str(entry_id)) entries_contents = '\n'.join([entry['content'] for entry in entries]) - file_template = open(file_template_file).read() + file_template = codecs.open(file_template_file, encoding='utf-8').read() template_contents = "<!-- Generated by licenses.py; do not edit. -->" template_contents += EvaluateTemplate( file_template, {'entries': entries_contents}, escape=False) @@ -752,13 +753,13 @@ if output_file: changed = True try: - old_output = open(output_file, 'r').read() + old_output = codecs.open(output_file, 'r', encoding='utf-8').read() if old_output == template_contents: changed = False except: pass if changed: - with open(output_file, 'w') as output: + with codecs.open(output_file, 'w', encoding='utf-8') as output: output.write(template_contents) else: print(template_contents)
diff --git a/tools/mb/mb.py b/tools/mb/mb.py index 9467283..e5bd2a3 100755 --- a/tools/mb/mb.py +++ b/tools/mb/mb.py
@@ -111,12 +111,15 @@ self.args.expectations_dir = os.path.join( os.path.dirname(self.args.config_file), 'mb_config_expectations') + banned_from_rts_map = json.loads( + self.ReadFile( + self.PathJoin(self.chromium_src_dir, 'tools', 'mb', + 'rts_banned_suites.json'))) + self.banned_from_rts.update(banned_from_rts_map.get('*', set())) + if getattr(self.args, 'builder', None): - banned_from_rts_map = json.loads( - self.ReadFile( - self.PathJoin(self.chromium_src_dir, 'tools', 'mb', - 'rts_banned_suites.json'))) - self.banned_from_rts = banned_from_rts_map.get(self.args.builder, set()) + self.banned_from_rts.update( + banned_from_rts_map.get(self.args.builder, set())) def Main(self, args): self.ParseArgs(args)
diff --git a/tools/mb/rts_banned_suites.json b/tools/mb/rts_banned_suites.json index e8eb8a63..5317924 100644 --- a/tools/mb/rts_banned_suites.json +++ b/tools/mb/rts_banned_suites.json
@@ -1,66 +1,17 @@ { - "linux-rel-rts": [ + + "*": [ "xr_browser_tests", - "hardware_accelerated_feature_tests", + "telemetry_gpu_integration_test", + "metrics_python_tests", + "mojo_python_unittests", + "blink_python_tests", + "grit_python_unittests", "telemetry_perf_unittests", - "pixel_skia_gold_passthrough_test", - "gl_renderer_screenshot_sync_tests", - "mojo_python_unittests", - "blink_python_tests", - "info_collection_tests", - "telemetry_gpu_unittests", - "depth_capture_tests", - "metrics_python_tests", - "grit_python_unittests", - "webgl_conformance_tests", - "gpu_process_launch_tests", - "maps_pixel_passthrough_test", - "trace_test", - "context_lost_passthrough_tests", - "screenshot_sync_passthrough_tests" - ], - "win10_chromium_x64_rel_ng_rts": [ - "trace_test", - "webgl_conformance_d3d11_passthrough_tests", - "xr_browser_tests", - "info_collection_tests", - "maps_pixel_passthrough_test", - "pixel_skia_gold_passthrough_test", - "metrics_python_tests", - "screenshot_sync_passthrough_tests", - "blink_python_tests", - "gpu_process_launch_tests", - "mojo_python_unittests", - "depth_capture_tests", - "grit_python_unittests", - "hardware_accelerated_feature_tests", - "telemetry_gpu_unittests", - "telemetry_desktop_minidump_unittests", - "context_lost_passthrough_tests" + "maps_tests", + "telemetry_gpu_unittests" ], "fuchsia_x64_rts": [ - "maps_tests", - "hardware_accelerated_feature_tests", - "webgl_conformance_tests", - "trace_test", - "blink_web_tests", - "gpu_process_launch_tests", - "context_lost_validating_tests" - ], - "mac-rel-rts": [ - "trace_test", - "maps_pixel_validating_test", - "screenshot_sync_validating_tests", - "hardware_accelerated_feature_tests", - "webgl_conformance_tests", - "pixel_skia_gold_validating_test", - "info_collection_tests", - "context_lost_validating_tests", - "depth_capture_tests", - "gpu_process_launch_tests" - ], - "chromeos-amd64-generic-rel-rts": [ - "telemetry_perf_unittests", - "webgl_conformance_tests" + "blink_web_tests" ] }
diff --git a/tools/media_engagement_preload/PRESUBMIT.py b/tools/media_engagement_preload/PRESUBMIT.py index df19c77f..97e25f9 100644 --- a/tools/media_engagement_preload/PRESUBMIT.py +++ b/tools/media_engagement_preload/PRESUBMIT.py
@@ -5,6 +5,10 @@ """Chromium presubmit script for src/tools/media_engagement_preload.""" +# This line is 'magic' in that git-cl looks for it to decide whether to +# use Python3 instead of Python2 when running the code in this file. +USE_PYTHON3 = True + def _RunMakeDafsaTests(input_api, output_api): """Runs unittest for make_dafsa if any related file has been modified.""" @@ -12,16 +16,14 @@ 'tools/media_engagement_preload/make_dafsa_unittest.py') if not any(f in input_api.LocalPaths() for f in files): return [] - test_path = input_api.os_path.join(input_api.PresubmitLocalPath(), - 'make_dafsa_unittest.py') - cmd_name = 'make_dafsa_unittest' - cmd = [input_api.python_executable, test_path] - test_cmd = input_api.Command( - name=cmd_name, - cmd=cmd, - kwargs={}, - message=output_api.PresubmitPromptWarning) - return input_api.RunTests([test_cmd]) + + return input_api.RunTests( + input_api.canned_checks.RunUnitTestsInDirectory( + input_api, + output_api, + input_api.PresubmitLocalPath(), + files_to_check=['.*test\.py$'], + run_on_python2=False)) def CheckChangeOnUpload(input_api, output_api):
diff --git a/tools/media_engagement_preload/make_dafsa.py b/tools/media_engagement_preload/make_dafsa.py index 72cbf7d..db78c67 100755 --- a/tools/media_engagement_preload/make_dafsa.py +++ b/tools/media_engagement_preload/make_dafsa.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # 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. @@ -9,7 +9,7 @@ import json import sys import os -import urlparse +import urllib.parse SOURCE_ROOT = os.path.join(os.path.dirname( os.path.abspath(__file__)), os.pardir, os.pardir) @@ -440,7 +440,7 @@ def to_proto(data): """Generates protobuf from a list of encoded bytes.""" message = media_engagement_preload_pb2.PreloadedData() - message.dafsa = array.array('B', data).tostring() + message.dafsa = array.array('B', data).tobytes() return message.SerializeToString() @@ -458,7 +458,7 @@ netlocs = {} for entry in json.loads(infile): # Parse the origin and reject any with an invalid protocol. - parsed = urlparse.urlparse(entry) + parsed = urllib.parse.urlparse(entry) if parsed.scheme != 'http' and parsed.scheme != 'https': raise InputError('Invalid protocol: %s' % entry) @@ -471,7 +471,7 @@ # Join the numerical values to the netlocs. output = [] - for location, value in netlocs.iteritems(): + for location, value in netlocs.items(): output.append(location + str(value)) return output except ValueError:
diff --git a/tools/media_engagement_preload/make_dafsa_unittest.py b/tools/media_engagement_preload/make_dafsa_unittest.py index cdf7965..3575af58 100755 --- a/tools/media_engagement_preload/make_dafsa_unittest.py +++ b/tools/media_engagement_preload/make_dafsa_unittest.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # 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. @@ -6,6 +6,7 @@ import sys import unittest + import make_dafsa @@ -678,14 +679,14 @@ def testExample1(self): """Tests Example 1 from make_dafsa.py.""" infile = '["https://www.example.com:8081", "http://www.example.org"]' - outfile = "\n\x1c\x81www.example\xae\x02\x89com:8081\x80org\x81" + outfile = b'\n\x1c\x81www.example\xae\x02\x84org\x81com:8081\x80' self.assertEqual(make_dafsa.words_to_proto(make_dafsa.parse_json(infile)), outfile) def testExample2(self): """Tests Example 2 from make_dafsa.py.""" infile = '["https://www.example.org", "http://www.google.com"]' - outfile = "\n\x1e\x81www\xae\x02\x8bgoogle.com\x81example.org\x80" + outfile = b'\n\x1e\x81www\xae\x02\x8bgoogle.com\x81example.org\x80' self.assertEqual(make_dafsa.words_to_proto(make_dafsa.parse_json(infile)), outfile)
diff --git a/tools/media_engagement_preload/media_engagement_preload_pb2.py b/tools/media_engagement_preload/media_engagement_preload_pb2.py index 0cde5091..bdb9bdc 100644 --- a/tools/media_engagement_preload/media_engagement_preload_pb2.py +++ b/tools/media_engagement_preload/media_engagement_preload_pb2.py
@@ -1,23 +1,26 @@ -# 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. - +# -*- coding: utf-8 -*- # Generated by the protocol buffer compiler. DO NOT EDIT! # source: media_engagement_preload.proto from google.protobuf import descriptor as _descriptor from google.protobuf import message as _message from google.protobuf import reflection as _reflection -from google.protobuf import descriptor_pb2 +from google.protobuf import symbol_database as _symbol_database # @@protoc_insertion_point(imports) +_sym_db = _symbol_database.Default() + DESCRIPTOR = _descriptor.FileDescriptor( name='media_engagement_preload.proto', package='chrome_browser_media', - serialized_pb='\n\x1emedia_engagement_preload.proto\x12\x14\x63hrome_browser_media\"\x1e\n\rPreloadedData\x12\r\n\x05\x64\x61\x66sa\x18\x01 \x01(\x0c\x42\x02H\x03') + syntax='proto2', + serialized_options=b'H\003', + create_key=_descriptor._internal_create_key, + serialized_pb=b'\n\x1emedia_engagement_preload.proto\x12\x14\x63hrome_browser_media\"\x1e\n\rPreloadedData\x12\r\n\x05\x64\x61\x66sa\x18\x01 \x01(\x0c\x42\x02H\x03' +) @@ -28,36 +31,41 @@ filename=None, file=DESCRIPTOR, containing_type=None, + create_key=_descriptor._internal_create_key, fields=[ _descriptor.FieldDescriptor( name='dafsa', full_name='chrome_browser_media.PreloadedData.dafsa', index=0, number=1, type=12, cpp_type=9, label=1, - has_default_value=False, default_value="", + has_default_value=False, default_value=b"", message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, + syntax='proto2', extension_ranges=[], + oneofs=[ + ], serialized_start=56, serialized_end=86, ) DESCRIPTOR.message_types_by_name['PreloadedData'] = _PRELOADEDDATA +_sym_db.RegisterFileDescriptor(DESCRIPTOR) -class PreloadedData(_message.Message): - __metaclass__ = _reflection.GeneratedProtocolMessageType - DESCRIPTOR = _PRELOADEDDATA - +PreloadedData = _reflection.GeneratedProtocolMessageType('PreloadedData', (_message.Message,), { + 'DESCRIPTOR' : _PRELOADEDDATA, + '__module__' : 'media_engagement_preload_pb2' # @@protoc_insertion_point(class_scope:chrome_browser_media.PreloadedData) + }) +_sym_db.RegisterMessage(PreloadedData) -DESCRIPTOR.has_options = True -DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), 'H\003') +DESCRIPTOR._options = None # @@protoc_insertion_point(module_scope)
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index cb9cf0d3..67d9ea7 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -25596,9 +25596,9 @@ <int value="324" label="WINDOWS_ON_REMOVED"/> <int value="325" label="FILE_SYSTEM_PROVIDER_ON_EXECUTE_ACTION_REQUESTED"/> <int value="326" label="FILE_SYSTEM_PROVIDER_ON_GET_ACTIONS_REQUESTED"/> - <int value="327" label="LAUNCHER_SEARCH_PROVIDER_ON_QUERY_STARTED"/> - <int value="328" label="LAUNCHER_SEARCH_PROVIDER_ON_QUERY_ENDED"/> - <int value="329" label="LAUNCHER_SEARCH_PROVIDER_ON_OPEN_RESULT"/> + <int value="327" label="DELETED_LAUNCHER_SEARCH_PROVIDER_ON_QUERY_STARTED"/> + <int value="328" label="DELETED_LAUNCHER_SEARCH_PROVIDER_ON_QUERY_ENDED"/> + <int value="329" label="DELETED_LAUNCHER_SEARCH_PROVIDER_ON_OPEN_RESULT"/> <int value="330" label="CHROME_WEB_VIEW_INTERNAL_ON_CLICKED"/> <int value="331" label="WEB_VIEW_INTERNAL_CONTEXT_MENUS"/> <int value="332" label="CONTEXT_MENUS"/> @@ -26809,7 +26809,7 @@ <int value="992" label="DELETED_EASYUNLOCKPRIVATE_HIDEERRORBUBBLE"/> <int value="993" label="WEBVIEWINTERNAL_SETZOOMMODE"/> <int value="994" label="WEBVIEWINTERNAL_GETZOOMMODE"/> - <int value="995" label="LAUNCHERSEARCHPROVIDER_SETSEARCHRESULTS"/> + <int value="995" label="DELETED_LAUNCHERSEARCHPROVIDER_SETSEARCHRESULTS"/> <int value="996" label="DELETED_DATAREDUCTIONPROXY_CLEARDATASAVINGS"/> <int value="997" label="BLUETOOTHPRIVATE_SETDISCOVERYFILTER"/> <int value="998" label="FILESYSTEM_GETVOLUMELIST"/> @@ -27881,7 +27881,7 @@ <int value="92" label="kInput"/> <int value="93" label="kInputMethodPrivate"/> <int value="94" label="kDeleted_InterceptAllKeys"/> - <int value="95" label="kLauncherSearchProvider"/> + <int value="95" label="kDeleted_LauncherSearchProvider"/> <int value="96" label="kLocation"/> <int value="97" label="kDeleted_LogPrivate"/> <int value="98" label="kManagement"/> @@ -32552,6 +32552,9 @@ <int value="3915" label="ClientHintsPrefersColorScheme"/> <int value="3916" label="OverscrollBehaviorWillBeFixed"/> <int value="3917" label="ControlledWorkerWillBeUncontrolled"/> + <int value="3918" label="ARIATouchpassthroughAttribute"/> + <int value="3919" label="ARIAVirtualcontentAttribute"/> + <int value="3920" label="AccessibilityTouchPassthroughSet"/> </enum> <enum name="FeaturePolicyAllowlistType"> @@ -38953,6 +38956,7 @@ <int value="4" label="kScreenRecording"/> <int value="5" label="kArcDownload"/> <int value="6" label="kPrintedPdf"/> + <int value="7" label="kDiagnosticsLog"/> </enum> <enum name="HoldingSpacePodAction"> @@ -70084,6 +70088,7 @@ <int value="7" label="MODEL_INVALID_VERSION_NUMBER"/> <int value="8" label="BAD_HASH_IDS"/> <int value="9" label="MODEL_NEVER_FETCHED"/> + <int value="10" label="FAILED_MAP_VISUAL_TFLITE_MODEL"/> </enum> <enum name="SBClientPhishingScorerCreationStatus">
diff --git a/tools/metrics/histograms/histograms_xml/apps/histograms.xml b/tools/metrics/histograms/histograms_xml/apps/histograms.xml index e77a764..a6b9cda 100644 --- a/tools/metrics/histograms/histograms_xml/apps/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/apps/histograms.xml
@@ -1442,6 +1442,16 @@ </summary> </histogram> +<histogram name="Apps.ArcGhostWindowLaunch" enum="Boolean" + expires_after="2021-11-01"> + <owner>nancylingwang@chromium.org</owner> + <owner>sstan@chromium.org</owner> + <summary> + Records whether the ARC ghost window is launched when the ARC app are + restored during the system startup phase. + </summary> +</histogram> + <histogram name="Apps.Bounced" enum="BooleanBounced" expires_after="2020-12-14"> <owner>ajlinker@chromium.org</owner> <owner>dominickn@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/holding_space/histograms.xml b/tools/metrics/histograms/histograms_xml/holding_space/histograms.xml index 76cf35c4..7b13f77 100644 --- a/tools/metrics/histograms/histograms_xml/holding_space/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/holding_space/histograms.xml
@@ -35,6 +35,8 @@ <variants name="HoldingSpaceItemType"> <variant name="All" summary="Includes all item types."/> <variant name="ArcDownload" summary="Items backed by an ARC download file."/> + <variant name="DiagnosticsLog" + summary="Items backed by a diagnostics log file."/> <variant name="Download" summary="Items backed by a download file."/> <variant name="NearbyShare" summary="Items backed by a nearby shared file."/> <variant name="PinnedFile" summary="Items pinned explicitly by the user."/>
diff --git a/tools/metrics/histograms/histograms_xml/local/histograms.xml b/tools/metrics/histograms/histograms_xml/local/histograms.xml index cf229e11..854f5c4 100644 --- a/tools/metrics/histograms/histograms_xml/local/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/local/histograms.xml
@@ -268,6 +268,8 @@ <summary> The renderer side cache hit rate metrics for new HTML5 LocalStorage DB opened. + + Warning: this histogram was expired from M78 to M92; data may be missing. </summary> </histogram>
diff --git a/tools/perf/core/perf_data_generator.py b/tools/perf/core/perf_data_generator.py index 8f47c31..42c297c 100755 --- a/tools/perf/core/perf_data_generator.py +++ b/tools/perf/core/perf_data_generator.py
@@ -101,7 +101,9 @@ ] # This is an opt-in list for builders which uses dynamic sharding. -DYNAMIC_SHARDING_TESTERS = ['android-pixel2-perf-fyi', 'linux-perf-calibration'] +DYNAMIC_SHARDING_TESTERS = [ + 'android-pixel2-perf', 'android-pixel2-perf-fyi', 'linux-perf-calibration' +] CALIBRATION_BUILDERS = { 'linux-perf-calibration': {
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json index 5d51f57..378573350 100644 --- a/tools/perf/core/perfetto_binary_roller/binary_deps.json +++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -6,11 +6,11 @@ }, "mac": { "hash": "d60c6038003ec1b551e16068d49f4d55ee20656f", - "remote_path": "perfetto_binaries/trace_processor_shell/mac/7d6375fd3e2f91b5880195a9c02de2334a3fa0d4/trace_processor_shell" + "remote_path": "perfetto_binaries/trace_processor_shell/mac/565fc165d0f867c9de129ead9b1766f42d2a1205/trace_processor_shell" }, "linux": { "hash": "dd23313e9aabc34dcaed1743f3bb1938be1c63b2", - "remote_path": "perfetto_binaries/trace_processor_shell/linux/9a1689eeaa281b21c5bcedcad5d54ddaeeb7889c/trace_processor_shell" + "remote_path": "perfetto_binaries/trace_processor_shell/linux/565fc165d0f867c9de129ead9b1766f42d2a1205/trace_processor_shell" } }, "power_profile.sql": {
diff --git a/tools/perf/cross_device_test_config.py b/tools/perf/cross_device_test_config.py index 49bf646..e0cb88e 100644 --- a/tools/perf/cross_device_test_config.py +++ b/tools/perf/cross_device_test_config.py
@@ -32,12 +32,8 @@ 'system_health.memory_mobile': 3, }, 'android-pixel2-perf': { - 'system_health.common_mobile': { - # timeToFirstContentfulPaint - 'browse:media:googleplaystore:2019': 10, - 'load:social:pinterest:2019': 10, - 'browse:media:facebook_photos:2019': 10 - } + 'system_health.common_mobile': 3, + 'system_health.memory_mobile': 3, }, 'android-go-perf': { 'system_health.common_mobile': {
diff --git a/ui/base/clipboard/clipboard_android.cc b/ui/base/clipboard/clipboard_android.cc index f8391c2..62e6ef7 100644 --- a/ui/base/clipboard/clipboard_android.cc +++ b/ui/base/clipboard/clipboard_android.cc
@@ -480,13 +480,13 @@ types->push_back(base::UTF8ToUTF16(kMimeTypeText)); if (IsFormatAvailable(ClipboardFormatType::GetHtmlType(), buffer, data_dst)) types->push_back(base::UTF8ToUTF16(kMimeTypeHTML)); + if (IsFormatAvailable(ClipboardFormatType::GetBitmapType(), buffer, data_dst)) + types->push_back(base::UTF8ToUTF16(kMimeTypePNG)); // these formats aren't supported by the ClipboardMap currently, but might // be one day? if (IsFormatAvailable(ClipboardFormatType::GetRtfType(), buffer, data_dst)) types->push_back(base::UTF8ToUTF16(kMimeTypeRTF)); - if (IsFormatAvailable(ClipboardFormatType::GetBitmapType(), buffer, data_dst)) - types->push_back(base::UTF8ToUTF16(kMimeTypePNG)); } // |data_dst| is not used. It's only passed to be consistent with other
diff --git a/ui/file_manager/BUILD.gn b/ui/file_manager/BUILD.gn index a842f79..469ef97a 100644 --- a/ui/file_manager/BUILD.gn +++ b/ui/file_manager/BUILD.gn
@@ -193,7 +193,6 @@ "file_manager/background/js/file_operation_util.m.js", "file_manager/background/js/import_history.m.js", "file_manager/background/js/launcher.m.js", - "file_manager/background/js/launcher_search.m.js", "file_manager/background/js/media_import_handler.m.js", "file_manager/background/js/media_scanner.m.js", "file_manager/background/js/metadata_proxy.m.js",
diff --git a/ui/file_manager/file_manager/background/js/BUILD.gn b/ui/file_manager/file_manager/background/js/BUILD.gn index 4598a53..c6ef5950 100644 --- a/ui/file_manager/file_manager/background/js/BUILD.gn +++ b/ui/file_manager/file_manager/background/js/BUILD.gn
@@ -54,7 +54,6 @@ ":file_operation_util", ":import_history", ":launcher", - ":launcher_search", ":media_import_handler", ":media_scanner", ":metadata_proxy", @@ -87,7 +86,6 @@ ":file_operation_util.m", ":import_history.m", ":launcher.m", - ":launcher_search.m", ":media_import_handler.m", ":media_scanner.m", ":metadata_proxy.m", @@ -163,7 +161,6 @@ "//ui/file_manager/file_manager/externs/background_window.js", "//ui/file_manager/file_manager/externs/css_rule.js", "//ui/file_manager/file_manager/externs/drive_dialog_controller.js", - "//ui/file_manager/file_manager/externs/launcher_search_provider.js", "//ui/file_manager/file_manager/externs/platform.js", "//ui/file_manager/file_manager/externs/progress_center_panel.js", "//ui/file_manager/file_manager/externs/background/task_queue.js", @@ -216,7 +213,6 @@ ":file_operation_manager", ":import_history", ":launcher", - ":launcher_search", ":media_import_handler", ":mount_metrics", ":progress_center", @@ -243,7 +239,6 @@ ":file_operation_util.m", ":import_history.m", ":launcher.m", - ":launcher_search.m", ":media_import_handler.m", ":media_scanner.m", ":mount_metrics.m", @@ -763,30 +758,6 @@ extra_deps = [ ":modulize" ] } -js_library("launcher_search") { - deps = [ - ":launcher", - ":volume_manager_factory", - "//ui/file_manager/file_manager/common/js:file_type", - "//ui/file_manager/file_manager/common/js:util", - ] -} - -js_library("launcher_search.m") { - sources = [ "$root_gen_dir/ui/file_manager/file_manager/background/js/launcher_search.m.js" ] - deps = [ - ":launcher.m", - ":volume_manager_factory.m", - "//ui/file_manager/file_manager/common/js:file_type.m", - "//ui/file_manager/file_manager/common/js:util.m", - ] - - externs_list = - [ "//ui/file_manager/file_manager/externs/launcher_search_provider.js" ] - - extra_deps = [ ":modulize" ] -} - js_library("media_import_handler") { deps = [ ":drive_sync_handler", @@ -1366,7 +1337,6 @@ "progress_center.js", "device_handler.js", "launcher.js", - "launcher_search.js", "background.js", ]
diff --git a/ui/file_manager/file_manager/background/js/background.js b/ui/file_manager/file_manager/background/js/background.js index ddbd283..caee064 100644 --- a/ui/file_manager/file_manager/background/js/background.js +++ b/ui/file_manager/file_manager/background/js/background.js
@@ -22,7 +22,6 @@ // #import {FileOperationManagerImpl} from './file_operation_manager.m.js'; // #import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js'; // #import {volumeManagerFactory} from './volume_manager_factory.m.js'; -// #import {LauncherSearch} from './launcher_search.m.js'; // #import {MountMetrics} from './mount_metrics.m.js'; // #import {CrostiniImpl} from './crostini.m.js'; // #import {mediaImport} from './media_import_handler.m.js'; @@ -126,12 +125,6 @@ */ this.stringData = null; - /** - * Provides drive search to app launcher. - * @private {!LauncherSearch} - */ - this.launcherSearch_ = new LauncherSearch(); - if (!window.isSWA) { // Initialize listener for importer.handlePhotosAppMessage messages to // the files app back-end. FIXME: Files SWA needs to support photos
diff --git a/ui/file_manager/file_manager/background/js/background_scripts.js b/ui/file_manager/file_manager/background/js/background_scripts.js index 0888738b..68ced1039 100644 --- a/ui/file_manager/file_manager/background/js/background_scripts.js +++ b/ui/file_manager/file_manager/background/js/background_scripts.js
@@ -22,7 +22,6 @@ // <include src="file_operation_util.js"> // <include src="import_history.js"> // <include src="launcher.js"> -// <include src="launcher_search.js"> // <include src="task_queue.js"> // <include src="media_import_handler.js"> // <include src="media_scanner.js">
diff --git a/ui/file_manager/file_manager/background/js/launcher_search.js b/ui/file_manager/file_manager/background/js/launcher_search.js deleted file mode 100644 index a87059c4..0000000 --- a/ui/file_manager/file_manager/background/js/launcher_search.js +++ /dev/null
@@ -1,350 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// #import {FileType} from '../../common/js/file_type.m.js'; -// #import {launcher, LaunchType} from './launcher.m.js'; -// #import {util} from '../../common/js/util.m.js'; -// #import {volumeManagerFactory} from './volume_manager_factory.m.js'; - -/** - * Provides drive search results to chrome launcher. - */ -/* #export */ class LauncherSearch { - constructor() { - // Launcher search provider is restricted to dev channel at now. - if (!chrome.launcherSearchProvider) { - return; - } - - /** - * Active query id. This value is set null when there is no active query. - * @private {?number} - */ - this.queryId_ = null; - - /** - * True if this feature is enabled. - * @private {boolean} - */ - this.enabled_ = false; - - /** - * @private {function(number, string, number)} - */ - this.onQueryStartedBound_ = this.onQueryStarted_.bind(this); - - /** - * @private {function(number)} - */ - this.onQueryEndedBound_ = this.onQueryEnded_.bind(this); - - /** - * @private {function(string)} - */ - this.onOpenResultBound_ = this.onOpenResult_.bind(this); - - // This feature is disabled when drive is disabled. - chrome.fileManagerPrivate.onPreferencesChanged.addListener( - this.onPreferencesChanged_.bind(this)); - this.onPreferencesChanged_(); - } - - /** - * Handles onPreferencesChanged event. - */ - onPreferencesChanged_() { - chrome.fileManagerPrivate.getPreferences(preferences => { - this.initializeEventListeners_( - preferences.driveEnabled, preferences.searchSuggestEnabled); - }); - } - - /** - * Initialize event listeners of chrome.launcherSearchProvider. - * - * When drive and search suggest are enabled, listen events of - * chrome.launcherSearchProvider and provide search resutls. When one of them - * is disabled, remove these event listeners and stop providing search - * results. - * - * @param {boolean} isDriveEnabled True if drive is enabled. - * @param {boolean} isSearchSuggestEnabled True if search suggest is enabled. - */ - initializeEventListeners_(isDriveEnabled, isSearchSuggestEnabled) { - const launcherSearchEnabled = isDriveEnabled && isSearchSuggestEnabled; - - // If this.enabled_ === launcherSearchEnabled, we don't need to change - // anything here. - if (this.enabled_ === launcherSearchEnabled) { - return; - } - - // Remove event listeners if it's already enabled. - if (this.enabled_) { - chrome.launcherSearchProvider.onQueryStarted.removeListener( - this.onQueryStartedBound_); - chrome.launcherSearchProvider.onQueryEnded.removeListener( - this.onQueryEndedBound_); - chrome.launcherSearchProvider.onOpenResult.removeListener( - this.onOpenResultBound_); - } - - // Set queryId_ to null to prevent that on-going search returns search - // results. - this.queryId_ = null; - - // Add event listeners when launcher search of Drive is enabled. - if (launcherSearchEnabled) { - this.enabled_ = true; - chrome.launcherSearchProvider.onQueryStarted.addListener( - this.onQueryStartedBound_); - chrome.launcherSearchProvider.onQueryEnded.addListener( - this.onQueryEndedBound_); - chrome.launcherSearchProvider.onOpenResult.addListener( - this.onOpenResultBound_); - } else { - this.enabled_ = false; - } - } - - /** - * Handles onQueryStarted event. - * @param {number} queryId - * @param {string} query - * @param {number} limit - */ - onQueryStarted_(queryId, query, limit) { - this.queryId_ = queryId; - - const startTime = Date.now(); - // Request an instance of volume manager to ensure that all volumes are - // initialized. When user searches while background page of the Files app is - // not running, it happens that this method is executed before all volumes - // are initialized. In this method, - // chrome.fileManagerPrivate.searchDriveMetadata resolves url internally, - // and it fails if filesystem of the url is not initialized. - volumeManagerFactory.getInstance() - .then(() => { - return Promise.all([ - this.queryDriveEntries_(queryId, query, limit, startTime), - this.queryLocalEntries_(query, limit, startTime), - ]); - }) - .then((results) => { - const entries = results[0].concat(results[1]); - if (queryId !== this.queryId_ || entries.length === 0) { - return; - } - - const resultEntries = this.chooseEntries_(entries, query, limit); - const searchResults = resultEntries.map(this.createSearchResult_); - chrome.launcherSearchProvider.setSearchResults( - queryId, searchResults); - }); - } - - /** - * Handles onQueryEnded event. - * @param {number} queryId - */ - onQueryEnded_(queryId) { - this.queryId_ = null; - } - - /** - * Handles onOpenResult event. - * @param {string} itemId - */ - onOpenResult_(itemId) { - // Request an instance of volume manager to ensure that all volumes are - // initialized. webkitResolveLocalFileSystemURL in util.urlToEntry fails if - // filesystem of the url is not initialized. - volumeManagerFactory.getInstance().then(() => { - util.urlToEntry(itemId).then(entry => { - if (entry.isDirectory) { - // If it's directory, open the directory with file manager. - launcher.launchFileManager( - {currentDirectoryURL: entry.toURL()}, undefined, /* App ID */ - LaunchType.FOCUS_SAME_OR_CREATE); - } else { - // getFileTasks does not support fake entries. - if (util.isFakeEntry(entry)) { - return; - } - // If the file is not directory, try to execute default task. - chrome.fileManagerPrivate.getFileTasks([entry], tasks => { - // Select default task. - let defaultTask = null; - for (let i = 0; i < tasks.length; i++) { - const task = tasks[i]; - if (task.isDefault) { - defaultTask = task; - break; - } - } - - // If we haven't picked a default task yet, then just pick the first - // one which is not generic file handler as default task. - // TODO(yawano) Share task execution logic with file_tasks.js. - if (!defaultTask) { - for (let i = 0; i < tasks.length; i++) { - const task = tasks[i]; - if (!task.isGenericFileHandler) { - defaultTask = task; - break; - } - } - } - - if (defaultTask) { - // Execute default task. - chrome.fileManagerPrivate.executeTask( - defaultTask.taskId, [entry], result => { - if (chrome.runtime.lastError) { - console.warn( - 'Unable to execute task: ' + - chrome.runtime.lastError.message); - } - if (result === 'opened' || result === 'message_sent') { - return; - } - this.openFileManagerWithSelectionURL_(entry.toURL()); - }); - } else { - // If there is no default task for the url, open a file manager - // with selecting it. - // TODO(yawano): Add fallback to view-in-browser as file_tasks.js - // do - this.openFileManagerWithSelectionURL_(entry.toURL()); - } - }); - } - }); - }); - } - - /** - * Opens file manager with selecting a specified url. - * @param {string} selectionURL A url to be selected. - * @private - */ - openFileManagerWithSelectionURL_(selectionURL) { - launcher.launchFileManager( - {selectionURL: selectionURL}, undefined, /* App ID */ - LaunchType.FOCUS_SAME_OR_CREATE); - } - - /** - * Queries entries which match the given query in Google Drive. - * @param {number} queryId - * @param {string} query - * @param {number} limit - * @param {number} startTime - * @return {!Promise<!Array<!Entry>>} - * @private - */ - queryDriveEntries_(queryId, query, limit, startTime) { - const param = { - query: query, - types: chrome.fileManagerPrivate.SearchType.ALL, - maxResults: limit - }; - return new Promise((resolve, reject) => { - chrome.fileManagerPrivate.searchDriveMetadata(param, results => { - chrome.fileManagerPrivate.getDriveConnectionState(connectionState => { - if (connectionState.type !== - chrome.fileManagerPrivate.DriveConnectionStateType.ONLINE) { - results = results.filter( - result => result.entry.isDirectory || - result.availableOffline !== false); - } - chrome.metricsPrivate.recordTime( - 'FileBrowser.LauncherSearch.Drive', Date.now() - startTime); - resolve(results.map(result => result.entry)); - }); - }); - }); - } - - /** - * Queries entries which match the given query in Downloads. - * @param {string} query - * @param {number} startTime - * @return {!Promise<!Array<!Entry>>} - * @private - */ - queryLocalEntries_(query, limit, startTime) { - if (!query) { - return Promise.resolve([]); - } - return new Promise((resolve, reject) => { - chrome.fileManagerPrivate.searchFiles( - { - query: query, - types: chrome.fileManagerPrivate.SearchType.ALL, - maxResults: limit - }, - results => { - chrome.metricsPrivate.recordTime( - 'FileBrowser.LauncherSearch.Local', Date.now() - startTime); - resolve(results); - }); - }); - } - - /** - * Chooses entries to show among the given entries. - * @param {!Array<!Entry>} entries - * @param {string} query - * @param {number} limit - * @return {!Array<!Entry>} - * @private - */ - chooseEntries_(entries, query, limit) { - query = query.toLowerCase(); - const scoreEntry = (entry) => { - // Prefer entry which has the query string as a prefix. - if (entry.name.toLowerCase().indexOf(query) === 0) { - return 1; - } - return 0; - }; - const sortedEntries = entries.sort((a, b) => { - return scoreEntry(b) - scoreEntry(a); - }); - return sortedEntries.slice(0, limit); - } - - /** - * Creates a search result from entry to pass to launcherSearchProvider API. - * @param {!Entry} entry - * @return {!Object} - * @private - */ - createSearchResult_(entry) { - // TODO(yawano): Use filetype_folder_shared.png for a shared - // folder. - let icon = FileType.getIcon(entry); - - if (icon === 'UNKNOWN') { - icon = 'generic'; - } - - // Hide extensions for hosted files. - const title = FileType.isHosted(entry) ? - entry.name.substr( - 0, entry.name.length - FileType.getExtension(entry).length) : - entry.name; - - return { - itemId: entry.toURL(), - title: title, - iconType: icon, - // Relevance is set as 2 for all results as a temporary - // implementation. 2 is the middle value. - // TODO(yawano): Implement practical relevance calculation. - relevance: 2 - }; - } -}
diff --git a/ui/file_manager/file_manager/background/js/runtime_loaded_test_util.js b/ui/file_manager/file_manager/background/js/runtime_loaded_test_util.js index 7e76d6b..5ea65a80 100644 --- a/ui/file_manager/file_manager/background/js/runtime_loaded_test_util.js +++ b/ui/file_manager/file_manager/background/js/runtime_loaded_test_util.js
@@ -992,22 +992,6 @@ }; /** - * Opens the file URL. It emulates the interaction that Launcher search does - * from a search result, it triggers the background page's event listener that - * listens to evens from launcher_search_provider API. - * - * @param {string} fileURL File URL to open by Files app background dialog. - * @suppress {accessControls|missingProperties} Closure disallow calling private - * launcherSearch_, but here we just want to emulate the behaviour, so we don't - * need to make this attribute public. Also the interface - * "FileBrowserBackground" doesn't define the attributes "launcherSearch_" so we - * need to suppress missingProperties. - */ -test.util.sync.launcherSearchOpenResult = fileURL => { - window.background.launcherSearch_.onOpenResult_(fileURL); -}; - -/** * Gets file entries just under the volume. * * @param {VolumeManagerCommon.VolumeType} volumeType Volume type.
diff --git a/ui/file_manager/file_manager/externs/launcher_search_provider.js b/ui/file_manager/file_manager/externs/launcher_search_provider.js deleted file mode 100644 index 6bb7f45..0000000 --- a/ui/file_manager/file_manager/externs/launcher_search_provider.js +++ /dev/null
@@ -1,32 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/** - * Namespace for chrome.launcherSearchProvider API. Since this API is under - * development and idl change may happen, we put extern file under - * ui/file_manager as temporary. - */ -chrome.launcherSearchProvider = {}; - -/** - * @param {number} queryId - * @param {Array<{itemId:string, title:string, iconUrl:?string, - * relevance:number}>} results - */ -chrome.launcherSearchProvider.setSearchResults = function(queryId, results) {}; - -/** - * @type {!ChromeEvent} - */ -chrome.launcherSearchProvider.onQueryStarted; - -/** - * @type {!ChromeEvent} - */ -chrome.launcherSearchProvider.onQueryEnded; - -/** - * @type {!ChromeEvent} - */ -chrome.launcherSearchProvider.onOpenResult;
diff --git a/ui/file_manager/file_manager/foreground/js/ui/multi_menu.js b/ui/file_manager/file_manager/foreground/js/ui/multi_menu.js index 52c1023..102f72f 100644 --- a/ui/file_manager/file_manager/foreground/js/ui/multi_menu.js +++ b/ui/file_manager/file_manager/foreground/js/ui/multi_menu.js
@@ -58,7 +58,7 @@ */ this.menuEndGap_ = 0; // padding on cr.menu + 2px. - /** @private {?EventTracker} */ + /** @private {?cr.EventTracker} */ this.showingEvents_ = null; /** TODO(adanilo) Annotate these for closure checking. */ @@ -99,7 +99,7 @@ decorate() { // Event tracker for the sub-menu specific listeners. - this.showingEvents_ = new EventTracker(); + this.showingEvents_ = new cr.EventTracker(); this.currentMenu = this; this.menuEndGap_ = 18; // padding on cr.menu + 2px }
diff --git a/ui/file_manager/file_manager/foreground/js/ui/multi_menu_button.js b/ui/file_manager/file_manager/foreground/js/ui/multi_menu_button.js index 50966e9..80289169 100644 --- a/ui/file_manager/file_manager/foreground/js/ui/multi_menu_button.js +++ b/ui/file_manager/file_manager/foreground/js/ui/multi_menu_button.js
@@ -38,7 +38,7 @@ */ this.menuEndGap_ = 0; // padding on cr.menu + 2px - /** @private {?EventTracker} */ + /** @private {?cr.EventTracker} */ this.showingEvents_ = null; /** @private {?cr.ui.Menu} */ @@ -115,7 +115,7 @@ // An event tracker for events we only connect to while the menu is // displayed. - this.showingEvents_ = new EventTracker(); + this.showingEvents_ = new cr.EventTracker(); } /**
diff --git a/ui/file_manager/file_manager/manifest.json b/ui/file_manager/file_manager/manifest.json index ce44f3d..70a377ac 100644 --- a/ui/file_manager/file_manager/manifest.json +++ b/ui/file_manager/file_manager/manifest.json
@@ -35,7 +35,6 @@ "https://docs.google.com/", "https://drive.google.com/", "https://www.google-analytics.com/", - "launcherSearchProvider", "metricsPrivate", "notifications", "power",
diff --git a/ui/file_manager/integration_tests/file_manager/BUILD.gn b/ui/file_manager/integration_tests/file_manager/BUILD.gn index a69fa55..958ac37 100644 --- a/ui/file_manager/integration_tests/file_manager/BUILD.gn +++ b/ui/file_manager/integration_tests/file_manager/BUILD.gn
@@ -28,7 +28,6 @@ ":grid_view", ":install_linux_package_dialog", ":keyboard_operations", - ":launcher_search", ":metadata", ":metrics", ":my_files", @@ -157,11 +156,6 @@ deps = [] } -js_library("launcher_search") { - testonly = true - deps = [] -} - js_library("metadata") { testonly = true deps = []
diff --git a/ui/file_manager/integration_tests/file_manager/launcher_search.js b/ui/file_manager/integration_tests/file_manager/launcher_search.js deleted file mode 100644 index ea9e5f8..0000000 --- a/ui/file_manager/integration_tests/file_manager/launcher_search.js +++ /dev/null
@@ -1,101 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -/** - * @fileoverview Tests for interface we expose to Launcher app's search feature. - */ - -'use strict'; - -(() => { - /** - * Tests opening an image using the Launcher app's search feature. - */ - testcase.launcherOpenSearchResult = async () => { - const imageName = ENTRIES.desktop.nameText; - - await sendTestMessage({ - name: 'expectFileTask', - fileNames: [ENTRIES.desktop.targetPath], - openType: 'launch' - }); - - // Create an image file in Drive. - await addEntries(['drive'], [ENTRIES.desktop]); - - // Get the image file URL. - const fileURLs = await remoteCall.callRemoteTestUtil( - 'getFilesUnderVolume', null, ['drive', [imageName]]); - - // Request Files app to open the image URL. - // This emulates the Launcher interaction with Files app. - chrome.test.assertEq(1, fileURLs.length); - await remoteCall.callRemoteTestUtil( - 'launcherSearchOpenResult', null, [fileURLs[0]]); - - // Files app opens the MediaApp for images, so wait for it. - await waitForMediaApp(); - }; - - const hostedDocument = Object.assign( - {}, ENTRIES.testDocument, - {nameText: 'testDocument.txt.gdoc', targetPath: 'testDocument.txt'}); - const photos = Object.assign( - {}, ENTRIES.photos, {nameText: 'photos.txt', targetPath: 'photos.txt'}); - - /** - * Tests Local and Drive files show up in search results. - */ - testcase.launcherSearch = async () => { - // Create a file in Downloads, and a pinned and unpinned file in Drive. - await Promise.all([ - addEntries(['local'], [ENTRIES.tallText, photos]), - addEntries( - ['drive'], [ENTRIES.hello, ENTRIES.pinned, hostedDocument, photos]), - ]); - const appId = await openNewWindow(null, null); - chrome.test.assertTrue(!!appId, 'failed to open new window'); - - const result = JSON.parse(await sendTestMessage({ - name: 'runLauncherSearch', - query: '.Txt', - })); - chrome.test.assertEq( - [ - ENTRIES.hello.targetPath, - photos.targetPath, - photos.targetPath, - ENTRIES.pinned.targetPath, - ENTRIES.tallText.targetPath, - hostedDocument.targetPath, - ], - result); - }; - - /** - * Tests Local and Drive files show up in search results. - */ - testcase.launcherSearchOffline = async () => { - // Create a file in Downloads, and a pinned and unpinned file in Drive. - await Promise.all([ - addEntries(['local'], [ENTRIES.tallText, photos]), - addEntries( - ['drive'], [ENTRIES.hello, ENTRIES.pinned, hostedDocument, photos]), - ]); - const appId = await openNewWindow(null, null); - chrome.test.assertTrue(!!appId, 'failed to open new window'); - - const result = JSON.parse(await sendTestMessage({ - name: 'runLauncherSearch', - query: '.txt', - })); - chrome.test.assertEq( - [ - photos.targetPath, - photos.targetPath, - ENTRIES.pinned.targetPath, - ENTRIES.tallText.targetPath, - ], - result); - }; -})();
diff --git a/ui/file_manager/integration_tests/file_manager_test_manifest.json b/ui/file_manager/integration_tests/file_manager_test_manifest.json index 194b7bb..d373a73 100644 --- a/ui/file_manager/integration_tests/file_manager_test_manifest.json +++ b/ui/file_manager/integration_tests/file_manager_test_manifest.json
@@ -34,7 +34,6 @@ "file_manager/install_linux_package_dialog.js", "file_manager/keyboard_operations.js", "file_manager/launch_files_app_swa.js", - "file_manager/launcher_search.js", "file_manager/metadata.js", "file_manager/metrics.js", "file_manager/my_files.js",
diff --git a/ui/views/controls/message_box_view.cc b/ui/views/controls/message_box_view.cc index d94b81c0..bfd76ace 100644 --- a/ui/views/controls/message_box_view.cc +++ b/ui/views/controls/message_box_view.cc
@@ -109,11 +109,11 @@ } else { add_label(message, true, gfx::ALIGN_LEFT); } - auto scroll_view = std::make_unique<ScrollView>(); - scroll_view->ClipHeightTo(0, provider->GetDistanceMetric( - DISTANCE_DIALOG_SCROLLABLE_AREA_MAX_HEIGHT)); - scroll_view->SetContents(std::move(message_contents)); - scroll_view_ = AddChildView(std::move(scroll_view)); + scroll_view_ = AddChildView(std::make_unique<ScrollView>()); + scroll_view_->ClipHeightTo( + 0, + provider->GetDistanceMetric(DISTANCE_DIALOG_SCROLLABLE_AREA_MAX_HEIGHT)); + scroll_view_->SetContents(std::move(message_contents)); // Don't enable text selection if multiple labels are used, since text // selection can't span multiple labels. if (message_labels_.size() == 1u)
diff --git a/ui/views/controls/scroll_view.cc b/ui/views/controls/scroll_view.cc index 8e7479a..df0bde7 100644 --- a/ui/views/controls/scroll_view.cc +++ b/ui/views/controls/scroll_view.cc
@@ -159,13 +159,6 @@ scroll_view_->ScrollContentsRegionToBeVisible(scroll_rect); } - // TODO(https://crbug.com/947053): this override should not be necessary, but - // there are some assumptions that this calls Layout(). - void ChildPreferredSizeChanged(View* child) override { - if (parent()) - parent()->Layout(); - } - void ViewHierarchyChanged( const ViewHierarchyChangedDetails& details) override { if (details.is_add && GetIsContentsViewport() && Contains(details.parent)) @@ -417,6 +410,9 @@ } void ScrollView::ClipHeightTo(int min_height, int max_height) { + if (min_height != min_height_ || max_height != max_height_) + PreferredSizeChanged(); + min_height_ = min_height; max_height_ = max_height; } @@ -467,12 +463,11 @@ } gfx::Size ScrollView::CalculatePreferredSize() const { - if (!is_bounded()) - return View::CalculatePreferredSize(); - - gfx::Size size = contents_->GetPreferredSize(); - size.SetToMax(gfx::Size(size.width(), min_height_)); - size.SetToMin(gfx::Size(size.width(), max_height_)); + gfx::Size size = contents_ ? contents_->GetPreferredSize() : gfx::Size(); + if (is_bounded()) { + size.SetToMax(gfx::Size(size.width(), min_height_)); + size.SetToMin(gfx::Size(size.width(), max_height_)); + } gfx::Insets insets = GetInsets(); size.Enlarge(insets.width(), insets.height()); return size; @@ -484,7 +479,8 @@ gfx::Insets insets = GetInsets(); width = std::max(0, width - insets.width()); - int height = contents_->GetHeightForWidth(width) + insets.height(); + int height = contents_ ? contents_->GetHeightForWidth(width) + insets.height() + : insets.height(); return base::ClampToRange(height, min_height_, max_height_); } @@ -900,10 +896,7 @@ *member = parent->AddChildViewAt(std::move(new_view), 0); else *member = nullptr; - // TODO(https://crbug.com/947053): this should call InvalidateLayout(), but - // there are some assumptions that it call Layout(). These assumptions should - // be updated. - Layout(); + InvalidateLayout(); } void ScrollView::ScrollContentsRegionToBeVisible(const gfx::Rect& rect) {
diff --git a/ui/views/controls/scroll_view_unittest.cc b/ui/views/controls/scroll_view_unittest.cc index 54cf561..6823b96 100644 --- a/ui/views/controls/scroll_view_unittest.cc +++ b/ui/views/controls/scroll_view_unittest.cc
@@ -634,12 +634,14 @@ } // Assertions around adding a header. -TEST_F(ScrollViewTest, Header) { - auto* header = scroll_view_->SetHeader(std::make_unique<CustomView>()); +TEST_F(WidgetScrollViewTest, Header) { + auto contents_ptr = std::make_unique<View>(); + auto* contents = contents_ptr.get(); + ScrollView* scroll_view = AddScrollViewWithContents(std::move(contents_ptr)); + auto* header = scroll_view->SetHeader(std::make_unique<CustomView>()); View* header_parent = header->parent(); - View* contents = InstallContents(); - scroll_view_->Layout(); + widget()->LayoutRootViewIfNecessary(); // |header|s preferred size is empty, which should result in all space going // to contents. EXPECT_EQ("0,0 100x0", header->parent()->bounds().ToString()); @@ -657,8 +659,8 @@ // Get the header a height of 20. header->SetPreferredSize(gfx::Size(10, 20)); - EXPECT_TRUE(ViewTestApi(scroll_view_.get()).needs_layout()); - scroll_view_->Layout(); + EXPECT_TRUE(ViewTestApi(scroll_view).needs_layout()); + widget()->LayoutRootViewIfNecessary(); EXPECT_EQ("0,0 100x20", header->parent()->bounds().ToString()); EXPECT_EQ("0,20 100x80", contents->parent()->bounds().ToString()); if (contents->layer()) { @@ -668,9 +670,10 @@ EXPECT_EQ("0,0 0x0", contents->bounds().ToString()); // Remove the header. - scroll_view_->SetHeader(nullptr); + scroll_view->SetHeader(nullptr); // SetHeader(nullptr) deletes header. header = nullptr; + widget()->LayoutRootViewIfNecessary(); EXPECT_EQ("0,0 100x0", header_parent->bounds().ToString()); EXPECT_EQ("0,0 100x100", contents->parent()->bounds().ToString()); } @@ -1093,6 +1096,25 @@ EXPECT_EQ(gfx::Size(kWidth, kMaxHeight), scroll_view_->size()); } +// Verifies ClipHeightTo() updates the ScrollView's preferred size. +TEST_F(ScrollViewTest, ClipHeightToUpdatesPreferredSize) { + auto contents_view = std::make_unique<View>(); + contents_view->SetPreferredSize({100, 100}); + scroll_view_->SetContents(std::move(contents_view)); + EXPECT_FALSE(scroll_view_->is_bounded()); + + constexpr int kMinHeight1 = 20; + constexpr int kMaxHeight1 = 80; + scroll_view_->ClipHeightTo(kMinHeight1, kMaxHeight1); + EXPECT_TRUE(scroll_view_->is_bounded()); + EXPECT_EQ(scroll_view_->GetPreferredSize().height(), kMaxHeight1); + + constexpr int kMinHeight2 = 200; + constexpr int kMaxHeight2 = 300; + scroll_view_->ClipHeightTo(kMinHeight2, kMaxHeight2); + EXPECT_EQ(scroll_view_->GetPreferredSize().height(), kMinHeight2); +} + TEST_F(ScrollViewTest, CornerViewVisibility) { View* contents = InstallContents(); View* corner_view = ScrollViewTestApi(scroll_view_.get()).corner_view(); @@ -2270,6 +2292,21 @@ EXPECT_EQ(gfx::ScrollOffset(10, 0), test_api.CurrentOffset()); } +TEST_F(WidgetScrollViewTest, UnboundedScrollViewUsesContentPreferredSize) { + auto contents = std::make_unique<View>(); + constexpr gfx::Size kContentsPreferredSize(500, 500); + contents->SetPreferredSize(kContentsPreferredSize); + ScrollView* scroll_view = + AddScrollViewWithContents(std::move(contents), true); + EXPECT_EQ(kContentsPreferredSize, scroll_view->GetPreferredSize()); + + constexpr gfx::Insets kInsets(20); + scroll_view->SetBorder(CreateEmptyBorder(kInsets)); + gfx::Size preferred_size_with_insets(kContentsPreferredSize); + preferred_size_with_insets.Enlarge(kInsets.width(), kInsets.height()); + EXPECT_EQ(preferred_size_with_insets, scroll_view->GetPreferredSize()); +} + INSTANTIATE_TEST_SUITE_P(All, WidgetScrollViewTestRTLAndLayers, ::testing::Values(UiConfig::kLtr,
diff --git a/ui/views/examples/examples_with_content_main.cc b/ui/views/examples/examples_with_content_main.cc index b8dd433..7fca765e 100644 --- a/ui/views/examples/examples_with_content_main.cc +++ b/ui/views/examples/examples_with_content_main.cc
@@ -48,7 +48,7 @@ // dlsym search path, which breaks (usually valid) assumptions made in // sandbox::InitLibcUrandomOverrides(). See http://crbug.com/374712. if (!browser_context) { - content::BrowserContext::SaveSessionState(nullptr); + browser_context->SaveSessionState(); NOTREACHED(); } }
diff --git a/ui/views/examples/native_theme_example.cc b/ui/views/examples/native_theme_example.cc index bf0d7a86c..28eb339 100644 --- a/ui/views/examples/native_theme_example.cc +++ b/ui/views/examples/native_theme_example.cc
@@ -39,11 +39,13 @@ void InsertColorRow(GridLayout* layout, base::StringPiece16 label_string, ui::NativeTheme::ColorId color_id) { - auto label_view = std::make_unique<Label>(std::u16string(label_string)); + layout->StartRow(GridLayout::kFixedSize, 0); + auto* label_view = + layout->AddView(std::make_unique<Label>(std::u16string(label_string))); label_view->SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT); label_view->SetSelectable(true); - auto color_view = std::make_unique<Label>(); + auto* color_view = layout->AddView(std::make_unique<Label>()); color_view->SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT); auto background_color = color_view->GetNativeTheme()->GetSystemColor(color_id); @@ -57,16 +59,12 @@ color_view->SetBackgroundColor(background_color); color_view->SetBackground(CreateSolidBackground(background_color)); color_view->SetSelectable(true); - - layout->StartRow(GridLayout::kFixedSize, 0); - layout->AddView(std::move(label_view)); - layout->AddView(std::move(color_view)); } // Returns a view of two columns where the first contains the identifier names // of ui::NativeTheme::ColorId and the second contains the color. -std::unique_ptr<View> CreateAllColorsView() { - auto container = std::make_unique<View>(); +void CreateAllColorsView(ScrollView* scroll_view) { + auto* container = scroll_view->SetContents(std::make_unique<View>()); auto* layout = container->SetLayoutManager(std::make_unique<GridLayout>()); auto* column_set = layout->AddColumnSet(0); column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1.0, @@ -163,9 +161,22 @@ InsertColorRow(layout, COLOR_LABEL_ARGS(kColorId_DefaultIconColor)); // Expands the view to allow for scrolling. container->SizeToPreferredSize(); - return container; } +class AllColorsScrollView : public ScrollView { + public: + AllColorsScrollView() { + constexpr int kMaxHeight = 300; + ClipHeightTo(0, kMaxHeight); + } + + protected: + void OnThemeChanged() override { + ScrollView::OnThemeChanged(); + CreateAllColorsView(this); + } +}; + } // namespace NativeThemeExample::NativeThemeExample() @@ -175,9 +186,7 @@ void NativeThemeExample::CreateExampleView(View* container) { container->SetLayoutManager(std::make_unique<FillLayout>()); - auto scroll_view = std::make_unique<ScrollView>(); - scroll_view->SetContents(CreateAllColorsView()); - container->AddChildView(std::move(scroll_view)); + container->AddChildView(std::make_unique<AllColorsScrollView>()); } } // namespace examples
diff --git a/ui/webui/resources/cr_components/chromeos/cellular_setup/BUILD.gn b/ui/webui/resources/cr_components/chromeos/cellular_setup/BUILD.gn index ea45ec53..677200e0 100644 --- a/ui/webui/resources/cr_components/chromeos/cellular_setup/BUILD.gn +++ b/ui/webui/resources/cr_components/chromeos/cellular_setup/BUILD.gn
@@ -141,6 +141,7 @@ deps = [ ":base_page.m", ":cellular_setup_delegate.m", + "//ui/webui/resources/cr_elements/cr_lottie:cr_lottie.m", "//ui/webui/resources/js:assert.m", ] extra_deps = [ ":setup_loading_page_module" ]
diff --git a/ui/webui/resources/cr_components/chromeos/cellular_setup/button_bar.html b/ui/webui/resources/cr_components/chromeos/cellular_setup/button_bar.html index 65323d3..72beca8d 100644 --- a/ui/webui/resources/cr_components/chromeos/cellular_setup/button_bar.html +++ b/ui/webui/resources/cr_components/chromeos/cellular_setup/button_bar.html
@@ -18,6 +18,10 @@ padding: 10px 0; } + #forward:focus { + box-shadow: 0 0 0 2px var(--focus-shadow-color); + } + #flex { flex: 1; }
diff --git a/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_flow_ui.html b/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_flow_ui.html index 916383a9..db0c29c3 100644 --- a/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_flow_ui.html +++ b/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_flow_ui.html
@@ -30,9 +30,7 @@ <iron-pages attr-for-selected="id" selected="[[selectedESimPageName_]]"> <setup-loading-page id="profileLoadingPage" - delegate="[[delegate]]" - loading-message="[[i18n('eSimProfileDetectMessage')]]" - state="[[getLoadingPageState_(hasHadActiveCellularNetwork_)]]"> + loading-message="[[getLoadingMessage_(hasHadActiveCellularNetwork_)]]"> </setup-loading-page> <profile-discovery-list-page id="profileDiscoveryPage" pending-profiles="[[pendingProfiles_]]"
diff --git a/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_flow_ui.js b/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_flow_ui.js index ee35f8f..891470f 100644 --- a/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_flow_ui.js +++ b/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_flow_ui.js
@@ -671,14 +671,11 @@ this.state_ === ESimUiState.PROFILE_SELECTION_INSTALLING; }, - /** - * @param {boolean} hasActiveCellularNetwork - * @private - */ - getLoadingPageState_(hasActiveCellularNetwork) { - return hasActiveCellularNetwork ? - LoadingPageState.CELLULAR_DISCONNECT_WARNING : - LoadingPageState.LOADING; + /** @private */ + getLoadingMessage_() { + return this.hasHadActiveCellularNetwork_ ? + this.i18n('eSimProfileDetectDuringActiveCellularConnectionMessage') : + this.i18n('eSimProfileDetectMessage'); }, /**
diff --git a/ui/webui/resources/cr_components/chromeos/cellular_setup/psim_flow_ui.html b/ui/webui/resources/cr_components/chromeos/cellular_setup/psim_flow_ui.html index 0571520..2a1e88c 100644 --- a/ui/webui/resources/cr_components/chromeos/cellular_setup/psim_flow_ui.html +++ b/ui/webui/resources/cr_components/chromeos/cellular_setup/psim_flow_ui.html
@@ -27,8 +27,9 @@ selected="[[selectedPSimPageName_]]" selected-item="{{selectedPage_}}"> <setup-loading-page id="simDetectPage" - delegate="[[delegate]]" state="[[getLoadingPageState_(state_)]]" - loading-message="[[i18n('establishNetworkConnectionMessage')]]"> + loading-title="[[getLoadingTitle_(state_)]]" + loading-message="[[getLoadingMessage_(state_)]]" + is-sim-detect-error="[[isSimDetectError_(state_)]]"> </setup-loading-page> <provisioning-page id="provisioningPage" delegate="[[delegate]]" show-error="{{showError_}}"
diff --git a/ui/webui/resources/cr_components/chromeos/cellular_setup/psim_flow_ui.js b/ui/webui/resources/cr_components/chromeos/cellular_setup/psim_flow_ui.js index ff00949..860748a7 100644 --- a/ui/webui/resources/cr_components/chromeos/cellular_setup/psim_flow_ui.js +++ b/ui/webui/resources/cr_components/chromeos/cellular_setup/psim_flow_ui.js
@@ -576,17 +576,28 @@ PSimUIState.ACTIVATION_FAILURE; }, - /** - * @return {LoadingPageState} - * @private - */ - getLoadingPageState_() { + /** @return {string} */ + getLoadingMessage_() { if (this.state_ === PSimUIState.TIMEOUT_START_ACTIVATION) { - return LoadingPageState.SIM_DETECT_ERROR; + return this.i18n('simDetectPageErrorMessage'); } else if (this.state_ === PSimUIState.FINAL_TIMEOUT_START_ACTIVATION) { - return LoadingPageState.FINAL_SIM_DETECT_ERROR; + return this.i18n('simDetectPageFinalErrorMessage'); } - return LoadingPageState.LOADING; + return this.i18n('establishNetworkConnectionMessage'); + }, + + /** @return {boolean} */ + isSimDetectError_() { + return this.state_ === PSimUIState.TIMEOUT_START_ACTIVATION || + this.state_ === PSimUIState.FINAL_TIMEOUT_START_ACTIVATION; + }, + + /** @return {string} */ + getLoadingTitle_() { + if (this.delegate.shouldShowPageTitle() && this.isSimDetectError_()) { + return this.i18n('simDetectPageErrorTitle'); + } + return ''; }, });
diff --git a/ui/webui/resources/cr_components/chromeos/cellular_setup/setup_loading_page.html b/ui/webui/resources/cr_components/chromeos/cellular_setup/setup_loading_page.html index 43968642..407731f 100644 --- a/ui/webui/resources/cr_components/chromeos/cellular_setup/setup_loading_page.html +++ b/ui/webui/resources/cr_components/chromeos/cellular_setup/setup_loading_page.html
@@ -6,15 +6,17 @@ <link rel="import" href="../../../cr_elements/hidden_style_css.html"> <link rel="import" href="chrome://resources/html/assert.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner-lite.html"> +<link rel="import" href="chrome://resources/cr_elements/cr_lottie/cr_lottie.html"> <dom-module id="setup-loading-page"> <template> <style include="iron-flex cr-hidden-style"> - paper-spinner-lite { - height: 32px; - margin-bottom: 8px; - width: 32px; + #animationContainer { + display: flex; + height: 216px; + justify-content: center; + margin-bottom: 30px; + margin-top: 24px; } #simDetectError { @@ -26,20 +28,20 @@ width: 100%; } - #networkConnectionMessage { - text-align: center; + #pageBody { + height: 222px; } </style> - <base-page title="[[getTitle_(state)]]" - message="[[getMessage_(state)]]" - message-icon="[[getMessageIcon_(state)]]"> - <div slot="page-body" class="layout vertical center-center"> - <paper-spinner-lite active hidden$="[[shouldShowSimDetectError_(state)]]"> - </paper-spinner-lite> - <div id="networkConnectionMessage" hidden$="[[shouldShowSimDetectError_(state)]]" aria-live="polite"> - [[loadingMessage]] + <base-page title="[[loadingTitle]]" message="[[loadingMessage]]"> + <div slot="page-body" id="pageBody" class="layout vertical center-center"> + <template is="dom-if" if="[[!isSimDetectError]]" restamp> + <div id="animationContainer"> + <cr-lottie id="spinner" animation-url="spinner.json" autoplay> + </cr-lottie> + </div> + </template> + <div id="simDetectError" hidden$="[[!isSimDetectError]]"> </div> - <div id="simDetectError" hidden$="[[!shouldShowSimDetectError_(state)]]"></div> </div> </base-page> </template>
diff --git a/ui/webui/resources/cr_components/chromeos/cellular_setup/setup_loading_page.js b/ui/webui/resources/cr_components/chromeos/cellular_setup/setup_loading_page.js index 060d033..c2c7772 100644 --- a/ui/webui/resources/cr_components/chromeos/cellular_setup/setup_loading_page.js +++ b/ui/webui/resources/cr_components/chromeos/cellular_setup/setup_loading_page.js
@@ -2,19 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -/** @enum {number} */ -/* #export */ const LoadingPageState = { - LOADING: 1, - SIM_DETECT_ERROR: 2, - FINAL_SIM_DETECT_ERROR: 3, - CELLULAR_DISCONNECT_WARNING: 4, -}; - /** - * Loading subpage in Cellular Setup flow. This element contains image - * asset and description to indicate that a SIM detection or eSIM profiles - * loading is in progress. It can show a 'detecting sim' error or a 'cellular - * disconnection' warning depending on its state. + * Loading subpage in Cellular Setup flow that shows an in progress operation or + * an error. This element contains error image asset and loading animation. */ Polymer({ is: 'setup-loading-page', @@ -22,15 +12,6 @@ behaviors: [I18nBehavior], properties: { - /** @type {!cellular_setup.CellularSetupDelegate} */ - delegate: Object, - - /** @type {!LoadingPageState} */ - state: { - type: Object, - value: LoadingPageState.LOADING, - }, - /** * Message displayed with spinner when in LOADING state. */ @@ -38,61 +19,22 @@ type: String, value: '', }, - }, - /** - * @param {LoadingPageState} state - * @return {?string} - * @private - */ - getTitle_(state) { - if (this.delegate.shouldShowPageTitle() && - state === LoadingPageState.SIM_DETECT_ERROR) { - return this.i18n('simDetectPageErrorTitle'); - } - return null; - }, + /** + * Title for page if needed. + * @type {?string} + */ + loadingTitle: { + type: Object, + value: '', + }, - /** - * @param {LoadingPageState} state - * @return {string} - * @private - */ - getMessage_(state) { - switch (state) { - case LoadingPageState.SIM_DETECT_ERROR: - return this.i18n('simDetectPageErrorMessage'); - case LoadingPageState.FINAL_SIM_DETECT_ERROR: - return this.i18n('simDetectPageFinalErrorMessage'); - case LoadingPageState.CELLULAR_DISCONNECT_WARNING: - return this.i18n('eSimConnectionWarning'); - case LoadingPageState.LOADING: - return ''; - default: - assertNotReached(); - } - }, - - /** - * @param {LoadingPageState} state - * @return {string} - * @private - */ - getMessageIcon_(state) { - if (state === LoadingPageState.CELLULAR_DISCONNECT_WARNING) { - return 'info'; - } - - return ''; - }, - - /** - * @param {LoadingPageState} state - * @return {boolean} - * @private - */ - shouldShowSimDetectError_(state) { - return state === LoadingPageState.SIM_DETECT_ERROR || - state === LoadingPageState.FINAL_SIM_DETECT_ERROR; + /** + * Displays a sim detect error graphic if true. + */ + isSimDetectError: { + type: Boolean, + value: false, + }, }, });
diff --git a/ui/webui/resources/cr_components/chromeos/network/network_list_item.html b/ui/webui/resources/cr_components/chromeos/network/network_list_item.html index 42499fd4f..7de1bdec 100644 --- a/ui/webui/resources/cr_components/chromeos/network/network_list_item.html +++ b/ui/webui/resources/cr_components/chromeos/network/network_list_item.html
@@ -163,7 +163,9 @@ </cr-policy-indicator> </template> <!-- This can only be shown if isUpdatedCellularUiEnabled_ is enabled. --> - <template is="dom-if" if="[[isPSimPendingActivationNetwork_]]" restamp> + <template is="dom-if" + if="[[shouldShowActivateButton_(isPSimPendingActivationNetwork_, + showButtons)]]" restamp> <cr-button id="activateButton" aria-label$="[[getActivateBtnA11yLabel_(item)]]" on-click="onActivateButtonClick_" @@ -177,12 +179,12 @@ <paper-spinner-lite id="activatingPSimSpinner" active> </paper-spinner-lite> [[i18n('networkListItemActivating')]] - <div class="separator"></div> + <div class="separator" hidden$="[[!showButtons]]"></div> </template> <template is="dom-if" if="[[isSubpageButtonVisible_(networkState, showButtons, disabled_, networkState.typeState.cellular.simLocked, - isPSimPendingActivationNetwork_)]]" restamp> + isPSimPendingActivationNetwork_, isPSimActivatingNetwork_)]]" restamp> <div> <cr-icon-button class="subpage-arrow" id="subpageButton" @@ -195,7 +197,7 @@ </div> </template> <template is="dom-if" if="[[shouldShowUnlockButton_(networkState, - networkState.typeState.cellular.simLocked)]]" restamp> + networkState.typeState.cellular.simLocked, showButtons)]]" restamp> <cr-button id="unlockButton" aria-label$="[[getUnlockBtnA11yLabel_(item)]]" on-click="onUnlockButtonClick_" @@ -209,7 +211,8 @@ device-state="[[deviceState]]"> </sim-lock-dialogs> </template> - <template is="dom-if" if="[[isESimPendingProfile_]]" restamp> + <template is="dom-if" if="[[shouldShowInstallButton_( + isESimPendingProfile_, showButtons)]]" restamp> <cr-button id="installButton" aria-label$="[[getInstallBtnA11yLabel_(item)]]" on-click="onInstallButtonClick_"
diff --git a/ui/webui/resources/cr_components/chromeos/network/network_list_item.js b/ui/webui/resources/cr_components/chromeos/network/network_list_item.js index 20eaf25b..325b883 100644 --- a/ui/webui/resources/cr_components/chromeos/network/network_list_item.js +++ b/ui/webui/resources/cr_components/chromeos/network/network_list_item.js
@@ -618,11 +618,13 @@ * @private */ isSubpageButtonVisible_(networkState, showButtons, disabled_) { + if (!this.showButtons) { + return false; + } if (this.isPSimPendingActivationNetwork_ || this.isPSimActivatingNetwork_) { return true; } - return !!networkState && showButtons && !disabled_ && - !this.shouldShowUnlockButton_(); + return !!networkState && !disabled_ && !this.shouldShowUnlockButton_(); }, /** @@ -673,15 +675,17 @@ this.networkState, this.showButtons, this.disabled_) && this.$$('#subpageButton') === this.shadowRoot.activeElement) { this.fireShowDetails_(event); - } else if (this.isESimPendingProfile_) { + } else if (this.shouldShowInstallButton_()) { this.onInstallButtonClick_(event); } else if (this.shouldShowUnlockButton_()) { this.onUnlockButtonClick_(); } else if (this.item && this.item.hasOwnProperty('customItemName')) { this.fire('custom-item-selected', this.item); + } else if (this.shouldShowActivateButton_()) { + this.fireShowDetails_(event); } else if ( - this.isPSimPendingActivationNetwork_ || - this.isPSimUnavailableNetwork_ || this.isPSimActivatingNetwork_) { + this.showButtons && + (this.isPSimUnavailableNetwork_ || this.isPSimActivatingNetwork_)) { this.fireShowDetails_(event); } else { this.fire('selected', this.item); @@ -819,6 +823,17 @@ }, /** + * @return {boolean} + * @private + */ + shouldShowActivateButton_() { + if (!this.showButtons) { + return false; + } + return this.isPSimPendingActivationNetwork_; + }, + + /** * @return {string} * @private */ @@ -902,6 +917,9 @@ * @private */ shouldShowUnlockButton_() { + if (!this.showButtons) { + return false; + } if (!this.networkState || !this.networkState.typeState.cellular || !this.isUpdatedCellularUiEnabled_) { return false; @@ -918,6 +936,17 @@ }, /** + * @return {boolean} + * @private + */ + shouldShowInstallButton_() { + if (!this.showButtons) { + return false; + } + return this.isESimPendingProfile_; + }, + + /** * @return {string} * @private */
diff --git a/ui/webui/resources/cr_components/chromeos/os_cr_components.gni b/ui/webui/resources/cr_components/chromeos/os_cr_components.gni index 6e0f162..09b92ec 100644 --- a/ui/webui/resources/cr_components/chromeos/os_cr_components.gni +++ b/ui/webui/resources/cr_components/chromeos/os_cr_components.gni
@@ -49,7 +49,6 @@ "ui/webui/resources/cr_components/chromeos/cellular_setup/mojo_interface_provider.html|setCellularSetupRemoteForTesting,getCellularSetupRemote,setESimManagerRemoteForTesting,getESimManagerRemote,observeESimManager", "ui/webui/resources/cr_components/chromeos/cellular_setup/esim_manager_utils.html|getPendingESimProfiles,getNonPendingESimProfiles,getNumESimProfiles,getEuicc,getESimProfile,getESimProfileProperties", "ui/webui/resources/cr_components/chromeos/cellular_setup/esim_manager_listener_behavior.html|ESimManagerListenerBehavior", - "ui/webui/resources/cr_components/chromeos/cellular_setup/setup_loading_page.html|LoadingPageState", "ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_browser_proxy.html|BrowserProxy,BrowserProxyImpl", "ui/webui/resources/cr_components/chromeos/multidevice_setup/mojo_api.html|MojoInterfaceProvider,MojoInterfaceProviderImpl", "ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_delegate.html|MultiDeviceSetupDelegate",
diff --git a/ui/webui/resources/cr_elements/cr_radio_group/cr_radio_group.js b/ui/webui/resources/cr_elements/cr_radio_group/cr_radio_group.js index 115f054..5b5bdfe3 100644 --- a/ui/webui/resources/cr_elements/cr_radio_group/cr_radio_group.js +++ b/ui/webui/resources/cr_elements/cr_radio_group/cr_radio_group.js
@@ -58,7 +58,7 @@ /** @private {Array<!CrRadioButtonElement>} */ buttons_: null, - /** @private {EventTracker} */ + /** @private {cr.EventTracker} */ buttonEventTracker_: null, /** @private {Map<string, number>} */ @@ -84,7 +84,7 @@ ['PageDown', 1], ['PageUp', -1], ]); - this.buttonEventTracker_ = new EventTracker(); + this.buttonEventTracker_ = new cr.EventTracker(); this.populateBound_ = () => this.populate_(); // Needed for when the radio buttons change when using dom-repeat or
diff --git a/ui/webui/resources/cr_elements/cr_slider/cr_slider.js b/ui/webui/resources/cr_elements/cr_slider/cr_slider.js index 9ce4c4a..064e8456 100644 --- a/ui/webui/resources/cr_elements/cr_slider/cr_slider.js +++ b/ui/webui/resources/cr_elements/cr_slider/cr_slider.js
@@ -187,7 +187,7 @@ /** @private {Map<string, number>} */ deltaKeyMap_: null, - /** @private {EventTracker} */ + /** @private {cr.EventTracker} */ draggingEventTracker_: null, /** @override */ @@ -201,7 +201,7 @@ ['ArrowLeft', this.isRtl_ ? 1 : -1], ['ArrowRight', this.isRtl_ ? -1 : 1], ]); - this.draggingEventTracker_ = new EventTracker(); + this.draggingEventTracker_ = new cr.EventTracker(); }, /**
diff --git a/ui/webui/resources/js/BUILD.gn b/ui/webui/resources/js/BUILD.gn index e1e8a220..a049d0e 100644 --- a/ui/webui/resources/js/BUILD.gn +++ b/ui/webui/resources/js/BUILD.gn
@@ -173,6 +173,7 @@ } js_library("event_tracker") { + deps = [ ":cr" ] } js_library("icon") {
diff --git a/ui/webui/resources/js/cr/ui/context_menu_handler.js b/ui/webui/resources/js/cr/ui/context_menu_handler.js index 801d4bdd..3a6f1fd 100644 --- a/ui/webui/resources/js/cr/ui/context_menu_handler.js +++ b/ui/webui/resources/js/cr/ui/context_menu_handler.js
@@ -26,8 +26,8 @@ class ContextMenuHandler extends cr.EventTarget { constructor() { super(); - /** @private {!EventTracker} */ - this.showingEvents_ = new EventTracker(); + /** @private {!cr.EventTracker} */ + this.showingEvents_ = new cr.EventTracker(); /** * The menu that we are currently showing.
diff --git a/ui/webui/resources/js/cr/ui/focus_row.js b/ui/webui/resources/js/cr/ui/focus_row.js index c297608..1a22300f 100644 --- a/ui/webui/resources/js/cr/ui/focus_row.js +++ b/ui/webui/resources/js/cr/ui/focus_row.js
@@ -40,8 +40,8 @@ /** @type {cr.ui.FocusRowDelegate|undefined} */ this.delegate = delegate; - /** @protected {!EventTracker} */ - this.eventTracker = new EventTracker; + /** @protected {!cr.EventTracker} */ + this.eventTracker = new cr.EventTracker; } /**
diff --git a/ui/webui/resources/js/cr/ui/menu_button.js b/ui/webui/resources/js/cr/ui/menu_button.js index 0cfd92b6..00ec20a 100644 --- a/ui/webui/resources/js/cr/ui/menu_button.js +++ b/ui/webui/resources/js/cr/ui/menu_button.js
@@ -63,7 +63,7 @@ // An event tracker for events we only connect to while the menu is // displayed. - this.showingEvents_ = new EventTracker(); + this.showingEvents_ = new cr.EventTracker(); this.anchorType = cr.ui.AnchorType.BELOW; this.invertLeftRight = false;
diff --git a/ui/webui/resources/js/event_tracker.js b/ui/webui/resources/js/event_tracker.js index fd0634b..58bf1df 100644 --- a/ui/webui/resources/js/event_tracker.js +++ b/ui/webui/resources/js/event_tracker.js
@@ -11,84 +11,86 @@ * calling Function.bind. */ -// eslint-disable-next-line no-var -/* #export */ var EventTracker = class { - /** - * Create an EventTracker to track a set of events. - * EventTracker instances are typically tied 1:1 with other objects or - * DOM elements whose listeners should be removed when the object is disposed - * or the corresponding elements are removed from the DOM. - */ - constructor() { +cr.define('cr', function() { + /* #export */ class EventTracker { /** - * @type {Array<EventTrackerEntry>} - * @private + * Create an EventTracker to track a set of events. + * EventTracker instances are typically tied 1:1 with other objects or + * DOM elements whose listeners should be removed when the object is + * disposed or the corresponding elements are removed from the DOM. */ - this.listeners_ = []; + constructor() { + /** + * @type {Array<EventTrackerEntry>} + * @private + */ + this.listeners_ = []; + } + + /** + * Add an event listener - replacement for EventTarget.addEventListener. + * @param {!EventTarget} target The DOM target to add a listener to. + * @param {string} eventType The type of event to subscribe to. + * @param {EventListener|Function} listener The listener to add. + * @param {boolean=} opt_capture Whether to invoke during the capture phase. + */ + add(target, eventType, listener, opt_capture) { + const capture = !!opt_capture; + const h = { + target: target, + eventType: eventType, + listener: listener, + capture: capture, + }; + this.listeners_.push(h); + target.addEventListener(eventType, listener, capture); + } + + /** + * Remove any specified event listeners added with this EventTracker. + * @param {!EventTarget} target The DOM target to remove a listener from. + * @param {?string} eventType The type of event to remove. + */ + remove(target, eventType) { + this.listeners_ = this.listeners_.filter(listener => { + if (listener.target === target && + (!eventType || (listener.eventType === eventType))) { + EventTracker.removeEventListener(listener); + return false; + } + return true; + }); + } + + /** Remove all event listeners added with this EventTracker. */ + removeAll() { + this.listeners_.forEach( + listener => EventTracker.removeEventListener(listener)); + this.listeners_ = []; + } + + /** + * Remove a single event listener given it's tracking entry. It's up to the + * caller to ensure the entry is removed from listeners_. + * @param {EventTrackerEntry} entry The entry describing the listener to + * remove. + */ + static removeEventListener(entry) { + entry.target.removeEventListener( + entry.eventType, entry.listener, entry.capture); + } } /** - * Add an event listener - replacement for EventTarget.addEventListener. - * @param {!EventTarget} target The DOM target to add a listener to. - * @param {string} eventType The type of event to subscribe to. - * @param {EventListener|Function} listener The listener to add. - * @param {boolean=} opt_capture Whether to invoke during the capture phase. + * The type of the internal tracking entry. + * @typedef {{target: !EventTarget, + * eventType: string, + * listener: (EventListener|Function), + * capture: boolean}} */ - add(target, eventType, listener, opt_capture) { - const capture = !!opt_capture; - const h = { - target: target, - eventType: eventType, - listener: listener, - capture: capture, - }; - this.listeners_.push(h); - target.addEventListener(eventType, listener, capture); - } + let EventTrackerEntry; - /** - * Remove any specified event listeners added with this EventTracker. - * @param {!EventTarget} target The DOM target to remove a listener from. - * @param {?string} eventType The type of event to remove. - */ - remove(target, eventType) { - this.listeners_ = this.listeners_.filter(listener => { - if (listener.target === target && - (!eventType || (listener.eventType === eventType))) { - EventTracker.removeEventListener(listener); - return false; - } - return true; - }); - } - - /** Remove all event listeners added with this EventTracker. */ - removeAll() { - this.listeners_.forEach( - listener => EventTracker.removeEventListener(listener)); - this.listeners_ = []; - } - - /** - * Remove a single event listener given it's tracking entry. It's up to the - * caller to ensure the entry is removed from listeners_. - * @param {EventTrackerEntry} entry The entry describing the listener to - * remove. - */ - static removeEventListener(entry) { - entry.target.removeEventListener( - entry.eventType, entry.listener, entry.capture); - } -}; - -/** - * The type of the internal tracking entry. - * @typedef {{target: !EventTarget, - * eventType: string, - * listener: (EventListener|Function), - * capture: boolean}} - */ -// eslint-disable-next-line no-var -var EventTrackerEntry; - -/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.'); + // #cr_define_end + console.warn('crbug/1173575, non-JS module files deprecated.'); + return {EventTracker}; +});
diff --git a/ui/webui/resources/tools/js_modulizer.gni b/ui/webui/resources/tools/js_modulizer.gni index 452ed5ce..d4ca2084b 100644 --- a/ui/webui/resources/tools/js_modulizer.gni +++ b/ui/webui/resources/tools/js_modulizer.gni
@@ -3,10 +3,10 @@ # found in the LICENSE file. common_namespace_rewrites = [ - "cr_slider.SliderTick|SliderTick", "cr.addSingletonGetter|addSingletonGetter", "cr.addWebUIListener|addWebUIListener", "cr.dispatchSimpleEvent|dispatchSimpleEvent", + "cr.EventTracker|EventTracker", "cr.icon.getFavicon|getFavicon", "cr.icon.getImage|getImage", "cr.isAndroid|isAndroid", @@ -19,6 +19,7 @@ "cr.png.convertImageSequenceToPng|convertImageSequenceToPng", "cr.removeWebUIListener|removeWebUIListener", "cr.sendWithPromise|sendWithPromise", + "cr_slider.SliderTick|SliderTick", "cr.toastManager.getToastManager|getToastManager", "cr.ui.FocusOutlineManager|FocusOutlineManager", "cr.ui.FocusRowBehavior|FocusRowBehavior",
diff --git a/weblayer/browser/browser_context_impl.cc b/weblayer/browser/browser_context_impl.cc index 431ae2b..4a933a9 100644 --- a/weblayer/browser/browser_context_impl.cc +++ b/weblayer/browser/browser_context_impl.cc
@@ -124,7 +124,7 @@ } BrowserContextImpl::~BrowserContextImpl() { - NotifyWillBeDestroyed(this); + NotifyWillBeDestroyed(); BrowserContextDependencyManager::GetInstance()->DestroyBrowserContextServices( this);