diff --git a/AUTHORS b/AUTHORS index cd603bd0..7c0c78e 100644 --- a/AUTHORS +++ b/AUTHORS
@@ -511,6 +511,7 @@ Kristof Kosztyo <kkosztyo.u-szeged@partner.samsung.com> Krzysztof Czech <k.czech@samsung.com> Krzysztof Wolanski <k.wolanski@samsung.com> +Kui Tan <tk1061178@gmail.com> Kunal Thakar <kunalt@gmail.com> Kushal Pisavadia <kushi.p@gmail.com> Kwangho Shin <k_h.shin@samsung.com>
diff --git a/DEPS b/DEPS index d5554f62..46ccfb0 100644 --- a/DEPS +++ b/DEPS
@@ -129,11 +129,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': '59b733715141b732ce3fb73b8870851f616c3163', + 'skia_revision': 'acb4829c1be4bd6be53ea750effd94c07da95632', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': 'c3553b10c8f8d018da015b448e6f2e72168741b4', + 'v8_revision': '804cfc5fb2ab8c49facc7a5f486c1555c2cbad63', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling swarming_client # and whatever else without interference from each other. @@ -145,11 +145,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. - 'swiftshader_revision': '555c33311d83b09b09045c837a7feace4966f906', + 'swiftshader_revision': '52a67b6495ce4973c4e17830107f09c35f7abbcc', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. - 'pdfium_revision': 'bc36bade1e160e34415fa445ba456e56ab69336b', + 'pdfium_revision': '21d000094adeb6be3b97f3758523c6117f334e82', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling openmax_dl # and whatever else without interference from each other. @@ -805,7 +805,7 @@ # Build tools for Chrome OS. Note: This depends on third_party/pyelftools. 'src/third_party/chromite': { - 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'a46c6ae7a64f28c2871f1fd042866e4583548549', + 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '507bf397d15ce43076ded2298db4a23bdecc2b1d', 'condition': 'checkout_linux', }, @@ -1343,7 +1343,7 @@ Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '688fbfe33779392aa210d67d4aa12cb012f112c2', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '3295c01df233c0106c3358414ade2b61e3cd36fc', + Var('webrtc_git') + '/src.git' + '@' + '708eccc1bd2d0163e35df9605649e6cadd68f589', 'src/third_party/xdg-utils': { 'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d', @@ -1384,7 +1384,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@d6512b3755d97e324dae3da952032ec8d77670f2', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@2523c15caf5fee59aa11611e62ec46c83019562a', 'condition': 'checkout_src_internal', },
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index 50eb18a..7b2d605 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -1527,6 +1527,7 @@ # TODO(stevenjb): Investigate whether this is OK. https://crbug.com/644336. "//chromeos/audio", "//chromeos/dbus", + "//chromeos/dbus/biod", "//components/discardable_memory/public/interfaces", "//components/services/font:lib", "//components/services/font/public/interfaces",
diff --git a/ash/DEPS b/ash/DEPS index 029e03c..92dd1c8 100644 --- a/ash/DEPS +++ b/ash/DEPS
@@ -59,6 +59,7 @@ "+chromeos/audio", "+chromeos/components/multidevice/logging/logging.h", "+chromeos/constants", + "+chromeos/dbus/biod/biod_client.h", "+chromeos/dbus/dbus_thread_manager.h", "+chromeos/dbus/fake_power_manager_client.h", "+chromeos/dbus/hammerd",
diff --git a/ash/app_menu/notification_menu_view.cc b/ash/app_menu/notification_menu_view.cc index 1cfe140..f3c8e44 100644 --- a/ash/app_menu/notification_menu_view.cc +++ b/ash/app_menu/notification_menu_view.cc
@@ -132,20 +132,22 @@ const auto i = NotificationIterForId(notification_id); if (i == notification_item_views_.end()) return; + const bool removed_displayed_notification = + i->get() == GetDisplayedNotificationItemView(); - // Erase the notification from |notification_item_views_| and - // |overflow_view_|. notification_item_views_.erase(i); - if (overflow_view_) - overflow_view_->RemoveIcon(notification_id); header_view_->UpdateCounter(notification_item_views_.size()); - // Display the next notification. - auto* item = GetDisplayedNotificationItemView(); - if (item) { - AddChildView(item); - if (overflow_view_) - overflow_view_->RemoveIcon(item->notification_id()); + if (removed_displayed_notification) { + // Display the next notification. + auto* item = GetDisplayedNotificationItemView(); + if (item) { + AddChildView(item); + if (overflow_view_) + overflow_view_->RemoveIcon(item->notification_id()); + } + } else if (overflow_view_) { + overflow_view_->RemoveIcon(notification_id); } if (overflow_view_ && overflow_view_->is_empty()) {
diff --git a/ash/shell/content/client/shell_browser_main_parts.cc b/ash/shell/content/client/shell_browser_main_parts.cc index 548a75a..f55bdb3 100644 --- a/ash/shell/content/client/shell_browser_main_parts.cc +++ b/ash/shell/content/client/shell_browser_main_parts.cc
@@ -32,7 +32,9 @@ #include "base/threading/thread_restrictions.h" #include "base/time/time.h" #include "chromeos/audio/cras_audio_handler.h" +#include "chromeos/dbus/biod/biod_client.h" #include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/dbus/power/power_manager_client.h" #include "chromeos/dbus/power/power_policy_controller.h" #include "components/exo/file_helper.h" #include "content/public/browser/browser_task_traits.h" @@ -72,6 +74,8 @@ void ShellBrowserMainParts::PostMainMessageLoopStart() { chromeos::DBusThreadManager::Initialize(chromeos::DBusThreadManager::kShared); + chromeos::PowerManagerClient::InitializeFake(); + chromeos::BiodClient::InitializeFake(); // WindowTreeClient needs to do some shutdown while the IO thread is alive. if (mus_client_)
diff --git a/base/files/file_util.cc b/base/files/file_util.cc index c6481c5..e6e84a2 100644 --- a/base/files/file_util.cc +++ b/base/files/file_util.cc
@@ -241,7 +241,11 @@ // On Windows, FILE_FLAG_BACKUP_SEMANTICS is needed to open a directory. if (DirectoryExists(path)) flags |= File::FLAG_BACKUP_SEMANTICS; -#endif // OS_WIN +#elif defined(OS_FUCHSIA) + // On Fuchsia, we need O_RDONLY for directories, or O_WRONLY for files. + // TODO(https://crbug.com/947802): Find a cleaner workaround for this. + flags |= (DirectoryExists(path) ? File::FLAG_READ : File::FLAG_WRITE); +#endif File file(path, flags); if (!file.IsValid())
diff --git a/base/fuchsia/service_directory_test_base.cc b/base/fuchsia/service_directory_test_base.cc index c476c6d..7067d94 100644 --- a/base/fuchsia/service_directory_test_base.cc +++ b/base/fuchsia/service_directory_test_base.cc
@@ -24,8 +24,9 @@ // Create the ServiceDirectoryClient, connected to the "public" sub-directory. fidl::InterfaceHandle<::fuchsia::io::Directory> public_directory; - CHECK_EQ(fdio_open_at(directory.channel().get(), "public", 0, - public_directory.NewRequest().TakeChannel().release()), + CHECK_EQ(fdio_service_connect_at( + directory.channel().get(), "/public/.", + public_directory.NewRequest().TakeChannel().release()), ZX_OK); public_service_directory_client_ = std::make_unique<ServiceDirectoryClient>(std::move(public_directory));
diff --git a/build/android/pylib/symbols/symbol_utils_unittest.py b/build/android/pylib/symbols/symbol_utils_unittest.py index e0c1405..82a7e313 100644 --- a/build/android/pylib/symbols/symbol_utils_unittest.py +++ b/build/android/pylib/symbols/symbol_utils_unittest.py
@@ -34,7 +34,6 @@ (0x0155d000, 0x015ab98c, 0x0004e98c, 'libbase_i18n.cr.so'), (0x015ac000, 0x015dff4c, 0x00033f4c, 'libbindings.cr.so'), (0x015e0000, 0x015f5a54, 0x00015a54, 'libbindings_base.cr.so'), - (0x015f6000, 0x0160d770, 0x00017770, 'libblink_android_mojo_bindings_shared.cr.so'), (0x0160e000, 0x01731960, 0x00123960, 'libblink_common.cr.so'), (0x01732000, 0x0174ce54, 0x0001ae54, 'libblink_controller.cr.so'), (0x0174d000, 0x0318c528, 0x01a3f528, 'libblink_core.cr.so'),
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1 index c51a474..947d51c 100644 --- a/build/fuchsia/linux.sdk.sha1 +++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@ -8917613372240707536 \ No newline at end of file +8917444505235389856 \ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1 index 4e755571..b1f8579 100644 --- a/build/fuchsia/mac.sdk.sha1 +++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@ -8917620309259302576 \ No newline at end of file +8917450276044616784 \ No newline at end of file
diff --git a/build/toolchain/gcc_toolchain.gni b/build/toolchain/gcc_toolchain.gni index ccd512f..80e2a36 100644 --- a/build/toolchain/gcc_toolchain.gni +++ b/build/toolchain/gcc_toolchain.gni
@@ -319,6 +319,7 @@ tool("cc") { depfile = "{{output}}.d" + precompiled_header_type = "gcc" command = "$cc -MMD -MF $depfile ${rebuild_string}{{defines}} {{include_dirs}} {{cflags}} {{cflags_c}}${extra_cppflags}${extra_cflags} -c {{source}} -o {{output}}" depsformat = "gcc" description = "CC {{output}}" @@ -329,6 +330,7 @@ tool("cxx") { depfile = "{{output}}.d" + precompiled_header_type = "gcc" command = "$cxx -MMD -MF $depfile ${rebuild_string}{{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}}${extra_cppflags}${extra_cxxflags} -c {{source}} -o {{output}}" depsformat = "gcc" description = "CXX {{output}}"
diff --git a/chrome/VERSION b/chrome/VERSION index c0b240c..d4f1fe7b 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=75 MINOR=0 -BUILD=3752 +BUILD=3753 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index 43f4909..b968a96 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -347,7 +347,6 @@ "//third_party/android_media:android_media_java", "//third_party/android_sdk:android_gcm_java", "//third_party/android_swipe_refresh:android_swipe_refresh_java", - "//third_party/blink/public:android_mojo_bindings_java", "//third_party/blink/public:blink_headers_java", "//third_party/blink/public/mojom:android_mojo_bindings_java", "//third_party/blink/public/mojom:mojom_platform_java", @@ -635,7 +634,6 @@ "//third_party/android_deps:com_android_support_mediarouter_v7_java", "//third_party/android_deps:com_android_support_recyclerview_v7_java", "//third_party/android_deps:com_android_support_support_annotations_java", - "//third_party/blink/public:android_mojo_bindings_java", "//third_party/blink/public:blink_headers_java", "//third_party/blink/public/mojom:android_mojo_bindings_java", "//third_party/cacheinvalidation:cacheinvalidation_javalib", @@ -782,7 +780,6 @@ "//third_party/android_sdk:android_test_runner_java", "//third_party/android_support_test_runner:rules_java", "//third_party/android_support_test_runner:runner_java", - "//third_party/blink/public:android_mojo_bindings_java", "//third_party/blink/public:blink_headers_java", "//third_party/blink/public/mojom:android_mojo_bindings_java", "//third_party/blink/public/mojom:mojom_mhtml_load_result_java",
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni index abd7c24f..4d276b2f 100644 --- a/chrome/android/chrome_java_sources.gni +++ b/chrome/android/chrome_java_sources.gni
@@ -1380,6 +1380,7 @@ "java/src/org/chromium/chrome/browser/rappor/RapporServiceBridge.java", "java/src/org/chromium/chrome/browser/rlz/RevenueStats.java", "java/src/org/chromium/chrome/browser/rlz/RlzPingHandler.java", + "java/src/org/chromium/chrome/browser/search_engines/SearchEngineChoiceNotification.java", "java/src/org/chromium/chrome/browser/search_engines/TemplateUrl.java", "java/src/org/chromium/chrome/browser/search_engines/TemplateUrlService.java", "java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java",
diff --git a/chrome/android/chrome_junit_test_java_sources.gni b/chrome/android/chrome_junit_test_java_sources.gni index 2875d4b..17f6f75 100644 --- a/chrome/android/chrome_junit_test_java_sources.gni +++ b/chrome/android/chrome_junit_test_java_sources.gni
@@ -156,6 +156,7 @@ "junit/src/org/chromium/chrome/browser/preferences/password/SingleThreadBarrierClosureTest.java", "junit/src/org/chromium/chrome/browser/preferences/password/TimedCallbackDelayerTest.java", "junit/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferencesManagerTest.java", + "junit/src/org/chromium/chrome/browser/search_engines/SearchEngineChoiceNotificationTest.java", "junit/src/org/chromium/chrome/browser/send_tab_to_self/SendTabToSelfAndroidBridgeTest.java", "junit/src/org/chromium/chrome/browser/send_tab_to_self/SendTabToSelfShareActivityTest.java", "junit/src/org/chromium/chrome/browser/signin/SigninManagerTest.java",
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java index db66043..6046950 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
@@ -164,6 +164,8 @@ public static final String ANDROID_PAY_INTEGRATION_V1 = "AndroidPayIntegrationV1"; public static final String ANDROID_PAY_INTEGRATION_V2 = "AndroidPayIntegrationV2"; public static final String ANDROID_PAYMENT_APPS = "AndroidPaymentApps"; + public static final String ANDROID_SEARCH_ENGINE_CHOICE_NOTIFICATION = + "AndroidSearchEngineChoiceNotification"; public static final String ANDROID_SITE_SETTINGS_UI_REFRESH = "AndroidSiteSettingsUIRefresh"; public static final String APP_NOTIFICATION_STATUS_MESSAGING = "AppNotificationStatusMessaging"; public static final String AUTOFILL_ASSISTANT = "AutofillAssistant";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java index 72874d2..35542b15 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -117,6 +117,7 @@ import org.chromium.chrome.browser.preferences.ChromePreferenceManager; import org.chromium.chrome.browser.preferences.PrefServiceBridge; import org.chromium.chrome.browser.profiles.Profile; +import org.chromium.chrome.browser.search_engines.SearchEngineChoiceNotification; import org.chromium.chrome.browser.signin.SigninPromoUtil; import org.chromium.chrome.browser.snackbar.undo.UndoBarController; import org.chromium.chrome.browser.suggestions.SuggestionsEventReporterBridge; @@ -793,6 +794,9 @@ } } + // This call is not guarded by a feature flag. + SearchEngineChoiceNotification.handleSearchEngineChoice(this, getSnackbarManager()); + if (!isWarmOnResume()) { SuggestionsMetrics.recordArticlesListVisible(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java b/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java index 99992e9..e07f06d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java
@@ -46,6 +46,7 @@ import org.chromium.content_public.browser.BrowserStartupController; import org.chromium.content_public.browser.DeviceUtils; import org.chromium.content_public.browser.SpeechRecognition; +import org.chromium.content_public.browser.UiThreadTaskTraits; import org.chromium.net.NetworkChangeNotifier; import org.chromium.policy.CombinedPolicyProvider; import org.chromium.ui.resources.ResourceExtractor; @@ -258,6 +259,7 @@ // Check to see if we need to extract any new resources from the APK. This could // be on first run when we need to extract all the .pak files we need, or after // the user has switched locale, in which case we want new locale resources. + ResourceExtractor.get().setResultTraits(UiThreadTaskTraits.BOOTSTRAP); ResourceExtractor.get().startExtractingResources(LocaleUtils.toLanguage( ChromeLocalizationUtils.getUiLocaleStringForCompressedPak()));
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/SearchEngineAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/SearchEngineAdapter.java index 6856afb..b3ea22b5 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/SearchEngineAdapter.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/SearchEngineAdapter.java
@@ -129,6 +129,7 @@ TemplateUrlService.getInstance().unregisterLoadListener(this); mHasLoadObserver = false; } + TemplateUrlService.getInstance().removeObserver(this); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferences.java index abdba9d..28551675fa 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferences.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferences.java
@@ -27,6 +27,7 @@ import org.chromium.base.VisibleForTesting; import org.chromium.base.metrics.RecordHistogram; import org.chromium.chrome.R; +import org.chromium.chrome.browser.locale.LocaleManager; import org.chromium.chrome.browser.preferences.ChromeBaseCheckBoxPreference; import org.chromium.chrome.browser.preferences.ChromeBasePreference; import org.chromium.chrome.browser.preferences.ChromeSwitchPreference; @@ -34,6 +35,7 @@ import org.chromium.chrome.browser.preferences.PreferencesLauncher; import org.chromium.chrome.browser.preferences.SearchUtils; import org.chromium.chrome.browser.preferences.TextMessagePreference; +import org.chromium.components.signin.ChromeSigninController; import org.chromium.ui.text.SpanApplier; import java.util.Locale; @@ -448,6 +450,12 @@ } private void displayManageAccountLink() { + // See http://crbug/946332 + if (LocaleManager.getInstance().isSpecialUser() + && !ChromeSigninController.get().isSignedIn()) { + // Don't add the Manage Account link if this is a special user and not signed in. + return; + } if (mSearchQuery != null && !mNoPasswords) { return; // Don't add the Manage Account link if there is a search going on. }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/search_engines/SearchEngineChoiceNotification.java b/chrome/android/java/src/org/chromium/chrome/browser/search_engines/SearchEngineChoiceNotification.java new file mode 100644 index 0000000..ed359bef --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/search_engines/SearchEngineChoiceNotification.java
@@ -0,0 +1,239 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.search_engines; + +import android.content.Context; +import android.support.annotation.IntDef; +import android.support.annotation.Nullable; + +import org.chromium.base.ContextUtils; +import org.chromium.base.metrics.RecordHistogram; +import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeFeatureList; +import org.chromium.chrome.browser.ChromeVersionInfo; +import org.chromium.chrome.browser.omaha.VersionNumber; +import org.chromium.chrome.browser.preferences.PreferencesLauncher; +import org.chromium.chrome.browser.preferences.SearchEnginePreference; +import org.chromium.chrome.browser.snackbar.Snackbar; +import org.chromium.chrome.browser.snackbar.SnackbarManager; +import org.chromium.chrome.browser.snackbar.SnackbarManager.SnackbarController; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.concurrent.TimeUnit; + +/** + * Class that prompts the user to change their search engine at the browser startup. + * User is only meant to be propmpted once, hence the fact of prompting is saved to preferences. + */ +public final class SearchEngineChoiceNotification { + /** Key used to store the date of when search engine choice was requested. */ + static final String PREF_SEARCH_ENGINE_CHOICE_REQUESTED_TIMESTAMP = + "search_engine_choice_requested_timestamp"; + + /** Key used to store the version of Chrome in which the choice was presented. */ + static final String PREF_SEARCH_ENGINE_CHOICE_PRESENTED_VERSION = + "search_engine_choice_presented_version"; + + /** Key used to store the default Search Engine Type before choice is presented. */ + static final String PREF_SEARCH_ENGINE_CHOICE_DEFAULT_TYPE_BEFORE = + "search_engine_choice_default_type_before"; + + /** Variations parameter name for notification snackbar duration (in seconds). */ + private static final String PARAM_NOTIFICATION_SNACKBAR_DURATION_SECONDS = + "notification-snackbar-duration-seconds"; + + /** Default value for notification snackbar duration (in seconds). */ + private static final int PARAM_NOTIFICATION_SNACKBAR_DURATION_SECONDS_DEFAULT = 10; + + /** Variations parameter name for invalidating version number. */ + private static final String PARAM_NOTIFICATION_INVALIDATING_VERSION_NUMBER = + "notification-invalidating-version-number"; + + // AndroidSearchEngineChoiceEvents defined in tools/metrics/histograms/enums.xml. + // These values are persisted to logs. Entries should not be renumbered and numeric values + // should never be reused. + @IntDef({Events.SNACKBAR_SHOWN, Events.PROMPT_FOLLOWED, Events.SEARCH_ENGINE_CHANGED}) + @Retention(RetentionPolicy.SOURCE) + @interface Events { + int SNACKBAR_SHOWN = 0; + int PROMPT_FOLLOWED = 1; + int SEARCH_ENGINE_CHANGED = 2; + int MAX = 3; + } + + /** + * Snackbar controller for search engine choice notification. It takes the user to the settings + * page responsible for search engine choice, when button is clicked. + */ + public static class NotificationSnackbarController implements SnackbarController { + private Context mContext; + + private NotificationSnackbarController(Context context) { + mContext = context; + } + + @Override + public void onAction(Object actionData) { + PreferencesLauncher.launchSettingsPage(mContext, SearchEnginePreference.class); + recordEvent(Events.PROMPT_FOLLOWED); + recordSearchEngineTypeBeforeChoicePresented(); + } + } + + private SearchEngineChoiceNotification() {} + + /** + * When called for the first time, it will save a preference that search engine choice was + * requested. + */ + public static void receiveSearchEngineChoiceRequest() { + if (wasSearchEngineChoiceRequested()) return; + + updateSearchEngineChoiceRequested(); + } + + /** + * Shows a search engine change notification, in form of a Snackbar. When run for the first time + * after showing a prompt, it reports metrics about Search Engine change. + * + * @param context Context in which to show the Snackbar. + * @param snackbarManager Snackbar manager which will shown and manage the Snackbar. + */ + public static void handleSearchEngineChoice(Context context, SnackbarManager snackbarManager) { + boolean searchEngineChoiceRequested = wasSearchEngineChoiceRequested(); + boolean searchEngineChoicePresented = wasSearchEngineChoicePresented(); + + if (searchEngineChoiceRequested && !searchEngineChoicePresented) { + snackbarManager.showSnackbar(buildSnackbarNotification(context)); + updateSearchEngineChoicePresented(); + recordEvent(Events.SNACKBAR_SHOWN); + } else if (isSearchEnginePossiblyDifferent()) { + @SearchEngineType + int previousSearchEngineType = getPreviousSearchEngineType(); + @SearchEngineType + int currentSearchEngineType = getDefaultSearchEngineType(); + if (previousSearchEngineType != currentSearchEngineType) { + recordEvent(Events.SEARCH_ENGINE_CHANGED); + RecordHistogram.recordEnumeratedHistogram( + "Android.SearchEngineChoice.ChosenSearchEngine", currentSearchEngineType, + SearchEngineType.SEARCH_ENGINE_MAX); + } + removePreviousSearchEngineType(); + } + } + + private static void recordEvent(@Events int event) { + RecordHistogram.recordEnumeratedHistogram( + "Android.SearchEngineChoice.Events", event, Events.MAX); + } + + private static Snackbar buildSnackbarNotification(Context context) { + int durationSeconds = ChromeFeatureList.getFieldTrialParamByFeatureAsInt( + ChromeFeatureList.ANDROID_SEARCH_ENGINE_CHOICE_NOTIFICATION, + PARAM_NOTIFICATION_SNACKBAR_DURATION_SECONDS, + PARAM_NOTIFICATION_SNACKBAR_DURATION_SECONDS_DEFAULT); + + return Snackbar + .make(context.getString(R.string.search_engine_choice_prompt), + new NotificationSnackbarController(context), Snackbar.TYPE_NOTIFICATION, + Snackbar.UMA_SEARCH_ENGINE_CHOICE_NOTIFICATION) + .setAction(context.getString(R.string.preferences), null) + .setDuration((int) TimeUnit.SECONDS.toMillis(durationSeconds)) + .setSingleLine(false) + .setTheme(Snackbar.Theme.GOOGLE); + } + + private static void updateSearchEngineChoiceRequested() { + long now = System.currentTimeMillis(); + ContextUtils.getAppSharedPreferences() + .edit() + .putLong(PREF_SEARCH_ENGINE_CHOICE_REQUESTED_TIMESTAMP, now) + .apply(); + } + + private static boolean wasSearchEngineChoiceRequested() { + return ContextUtils.getAppSharedPreferences().contains( + PREF_SEARCH_ENGINE_CHOICE_REQUESTED_TIMESTAMP); + } + + private static void updateSearchEngineChoicePresented() { + String productVersion = ChromeVersionInfo.getProductVersion(); + ContextUtils.getAppSharedPreferences() + .edit() + .putString(PREF_SEARCH_ENGINE_CHOICE_PRESENTED_VERSION, productVersion) + .apply(); + } + + private static boolean wasSearchEngineChoicePresented() { + VersionNumber lastPresentedVersionNumber = getLastPresentedVersionNumber(); + if (lastPresentedVersionNumber == null) return false; + + VersionNumber lowestAcceptedVersionNumber = getLowestAcceptedVersionNumber(); + if (lowestAcceptedVersionNumber == null) return true; + + return !lastPresentedVersionNumber.isSmallerThan(lowestAcceptedVersionNumber); + } + + @Nullable + private static VersionNumber getLastPresentedVersionNumber() { + return VersionNumber.fromString(ContextUtils.getAppSharedPreferences().getString( + PREF_SEARCH_ENGINE_CHOICE_PRESENTED_VERSION, null)); + } + + @Nullable + private static VersionNumber getLowestAcceptedVersionNumber() { + return VersionNumber.fromString(ChromeFeatureList.getFieldTrialParamByFeature( + ChromeFeatureList.ANDROID_SEARCH_ENGINE_CHOICE_NOTIFICATION, + PARAM_NOTIFICATION_INVALIDATING_VERSION_NUMBER)); + } + + @SearchEngineType + private static int getDefaultSearchEngineType() { + TemplateUrlService templateUrlService = TemplateUrlService.getInstance(); + TemplateUrl currentSearchEngine = templateUrlService.getDefaultSearchEngineTemplateUrl(); + if (currentSearchEngine == null) return SearchEngineType.SEARCH_ENGINE_UNKNOWN; + return templateUrlService.getSearchEngineTypeFromTemplateUrl( + currentSearchEngine.getKeyword()); + } + + private static void recordSearchEngineTypeBeforeChoicePresented() { + @SearchEngineType + int currentSearchEngineType = getDefaultSearchEngineType(); + RecordHistogram.recordEnumeratedHistogram( + "Android.SearchEngineChoice.SearchEngineBeforeChoicePrompt", + currentSearchEngineType, SearchEngineType.SEARCH_ENGINE_MAX); + ContextUtils.getAppSharedPreferences() + .edit() + .putInt(PREF_SEARCH_ENGINE_CHOICE_DEFAULT_TYPE_BEFORE, currentSearchEngineType) + .apply(); + } + + private static boolean isSearchEnginePossiblyDifferent() { + return ContextUtils.getAppSharedPreferences().contains( + PREF_SEARCH_ENGINE_CHOICE_DEFAULT_TYPE_BEFORE); + } + + @SearchEngineType + private static int getPreviousSearchEngineType() { + return ContextUtils.getAppSharedPreferences().getInt( + PREF_SEARCH_ENGINE_CHOICE_DEFAULT_TYPE_BEFORE, + SearchEngineType.SEARCH_ENGINE_UNKNOWN); + } + + private static void removePreviousSearchEngineType() { + ContextUtils.getAppSharedPreferences() + .edit() + .remove(PREF_SEARCH_ENGINE_CHOICE_DEFAULT_TYPE_BEFORE) + .apply(); + } + + private static int getNotificationSnackbarDuration() { + return ChromeFeatureList.getFieldTrialParamByFeatureAsInt( + ChromeFeatureList.ANDROID_SEARCH_ENGINE_CHOICE_NOTIFICATION, + PARAM_NOTIFICATION_SNACKBAR_DURATION_SECONDS, + PARAM_NOTIFICATION_SNACKBAR_DURATION_SECONDS_DEFAULT); + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/search_engines/TemplateUrlService.java b/chrome/android/java/src/org/chromium/chrome/browser/search_engines/TemplateUrlService.java index 3aa6620a..55c72cd 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/search_engines/TemplateUrlService.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/search_engines/TemplateUrlService.java
@@ -332,6 +332,11 @@ return nativeUpdateLastVisitedForTesting(mNativeTemplateUrlServiceAndroid, keyword); } + @VisibleForTesting + static void setInstanceForTesting(TemplateUrlService service) { + sService = service; + } + private native long nativeInit(); private native void nativeLoad(long nativeTemplateUrlServiceAndroid); private native boolean nativeIsLoaded(long nativeTemplateUrlServiceAndroid);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/snackbar/Snackbar.java b/chrome/android/java/src/org/chromium/chrome/browser/snackbar/Snackbar.java index 344a402..9ea8a47 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/snackbar/Snackbar.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/snackbar/Snackbar.java
@@ -82,6 +82,7 @@ public static final int UMA_TWA_PRIVACY_DISCLOSURE = 28; public static final int UMA_AUTOFILL_ASSISTANT_STOP_UNDO = 29; public static final int UMA_TAB_CLOSE_MULTIPLE_UNDO = 30; + public static final int UMA_SEARCH_ENGINE_CHOICE_NOTIFICATION = 31; private SnackbarController mController; private CharSequence mText;
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd index 07d7746..35723b3 100644 --- a/chrome/android/java/strings/android_chrome_strings.grd +++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -452,6 +452,10 @@ You can change this later in Settings </message> + <message name="IDS_SEARCH_ENGINE_CHOICE_PROMPT" desc="Prompt asking users whether they want to change the search engine"> + You can choose your search engine + </message> + <!-- Autofill and Payments preferences --> <message name="IDS_AUTOFILL_KEYBOARD_ACCESSORY_CONTENT_DESCRIPTION" desc="The text announced by the screen reader when the autofill suggestions are shown."> Passwords available
diff --git a/chrome/android/java/strings/android_chrome_strings_grd/IDS_SEARCH_ENGINE_CHOICE_PROMPT.png.sha1 b/chrome/android/java/strings/android_chrome_strings_grd/IDS_SEARCH_ENGINE_CHOICE_PROMPT.png.sha1 new file mode 100644 index 0000000..ff70abc --- /dev/null +++ b/chrome/android/java/strings/android_chrome_strings_grd/IDS_SEARCH_ENGINE_CHOICE_PROMPT.png.sha1
@@ -0,0 +1 @@ +13f3afa89a013f58ba2ce9a13c4da6b09e2cca1e \ No newline at end of file
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataPreferencesTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataPreferencesTest.java index 71e7711..a7fe6ca 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataPreferencesTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataPreferencesTest.java
@@ -70,10 +70,7 @@ * Integration tests for ClearBrowsingDataPreferences. */ @RunWith(ChromeJUnit4ClassRunner.class) -// Disable notifications for the default search engine so that it doesn't interfere with important -// sites tests. -@CommandLineFlags. -Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, "disable-features=GrantNotificationsToDSE"}) +@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) @RetryOnFailure public class ClearBrowsingDataPreferencesTest { @Rule
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/search_engines/SearchEngineChoiceNotificationTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/search_engines/SearchEngineChoiceNotificationTest.java new file mode 100644 index 0000000..33efdaf --- /dev/null +++ b/chrome/android/junit/src/org/chromium/chrome/browser/search_engines/SearchEngineChoiceNotificationTest.java
@@ -0,0 +1,291 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.search_engines; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.isNull; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.content.Intent; +import android.support.test.filters.SmallTest; + +import org.junit.Before; +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.mockito.Spy; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +import org.chromium.base.ContextUtils; +import org.chromium.base.metrics.test.ShadowRecordHistogram; +import org.chromium.base.test.BaseRobolectricTestRunner; +import org.chromium.chrome.browser.ChromeFeatureList; +import org.chromium.chrome.browser.ChromeVersionInfo; +import org.chromium.chrome.browser.snackbar.Snackbar; +import org.chromium.chrome.browser.snackbar.SnackbarManager; +import org.chromium.chrome.test.support.DisableHistogramsRule; + +import java.util.HashMap; + +/** + * Unit tests for {@link SearchEngineChoiceNotification}. + */ +@RunWith(BaseRobolectricTestRunner.class) +@Config(manifest = Config.NONE, shadows = {ShadowRecordHistogram.class}) +public final class SearchEngineChoiceNotificationTest { + private static final String TEST_INITIAL_ENGINE = "google.com"; + private static final String TEST_ALTERNATIVE_ENGINE = "duckduckgo.com"; + + @Rule + public DisableHistogramsRule mDisableHistogramsRule = new DisableHistogramsRule(); + @Spy + private Context mContext = RuntimeEnvironment.application.getApplicationContext(); + @Mock + private SnackbarManager mSnackbarManager; + @Mock + private TemplateUrlService mTemplateUrlService; + @Mock + private TemplateUrl mInitialSearchEngine; + @Mock + private TemplateUrl mAlternativeSearchEngine; + @Captor + private ArgumentCaptor<Snackbar> mSnackbarArgument; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + ContextUtils.initApplicationContextForTests(mContext); + ContextUtils.getAppSharedPreferences().edit().clear().apply(); + + ChromeFeatureList.setTestFeatures(new HashMap<String, Boolean>()); + ShadowRecordHistogram.reset(); + + // Sets up appropriate responses from Template URL service. + TemplateUrlService.setInstanceForTesting(mTemplateUrlService); + doReturn(TEST_ALTERNATIVE_ENGINE).when(mAlternativeSearchEngine).getKeyword(); + doReturn(SearchEngineType.SEARCH_ENGINE_DUCKDUCKGO) + .when(mTemplateUrlService) + .getSearchEngineTypeFromTemplateUrl(TEST_ALTERNATIVE_ENGINE); + doReturn(TEST_INITIAL_ENGINE).when(mInitialSearchEngine).getKeyword(); + doReturn(SearchEngineType.SEARCH_ENGINE_GOOGLE) + .when(mTemplateUrlService) + .getSearchEngineTypeFromTemplateUrl(TEST_INITIAL_ENGINE); + doReturn(mInitialSearchEngine) + .when(mTemplateUrlService) + .getDefaultSearchEngineTemplateUrl(); + } + + @Test + @SmallTest + public void receiveSearchEngineChoiceRequest() { + assertFalse(ContextUtils.getAppSharedPreferences().contains( + SearchEngineChoiceNotification.PREF_SEARCH_ENGINE_CHOICE_REQUESTED_TIMESTAMP)); + SearchEngineChoiceNotification.receiveSearchEngineChoiceRequest(); + assertTrue(ContextUtils.getAppSharedPreferences().contains( + SearchEngineChoiceNotification.PREF_SEARCH_ENGINE_CHOICE_REQUESTED_TIMESTAMP)); + + long firstTimestamp = ContextUtils.getAppSharedPreferences().getLong( + SearchEngineChoiceNotification.PREF_SEARCH_ENGINE_CHOICE_REQUESTED_TIMESTAMP, 0); + SearchEngineChoiceNotification.receiveSearchEngineChoiceRequest(); + long secondTimestamp = ContextUtils.getAppSharedPreferences().getLong( + SearchEngineChoiceNotification.PREF_SEARCH_ENGINE_CHOICE_REQUESTED_TIMESTAMP, 0); + + assertEquals(firstTimestamp, secondTimestamp); + } + + @Test + @SmallTest + public void handleSearchEngineChoice_ignoredWhenNotRequested() { + assertFalse(ContextUtils.getAppSharedPreferences().contains( + SearchEngineChoiceNotification.PREF_SEARCH_ENGINE_CHOICE_PRESENTED_VERSION)); + + SearchEngineChoiceNotification.handleSearchEngineChoice(mContext, null); + + assertFalse("When not requested, the call should have been ignored.", + ContextUtils.getAppSharedPreferences().contains( + SearchEngineChoiceNotification + .PREF_SEARCH_ENGINE_CHOICE_PRESENTED_VERSION)); + + assertEquals(0, + ShadowRecordHistogram.getHistogramValueCountForTesting( + "Android.SearchEngineChoice.Events", + SearchEngineChoiceNotification.Events.SNACKBAR_SHOWN)); + } + + @Test + @SmallTest + public void handleSearchEngineChoice_performedFirstTime() { + SearchEngineChoiceNotification.receiveSearchEngineChoiceRequest(); + SearchEngineChoiceNotification.handleSearchEngineChoice(mContext, mSnackbarManager); + // TODO(fgorski): Snackbar content is scoped to its package, therefore cannot be verified + // here at this time. See whether that can be fixed. + verify(mSnackbarManager, times(1)).showSnackbar(any(Snackbar.class)); + + assertEquals("We are expecting exactly one snackbar shown event.", 1, + ShadowRecordHistogram.getHistogramValueCountForTesting( + "Android.SearchEngineChoice.Events", + SearchEngineChoiceNotification.Events.SNACKBAR_SHOWN)); + + assertTrue("Version of the app should be persisted upon prompting.", + ContextUtils.getAppSharedPreferences().contains( + SearchEngineChoiceNotification + .PREF_SEARCH_ENGINE_CHOICE_PRESENTED_VERSION)); + + assertEquals("Presented version should be set to the current product version.", + ChromeVersionInfo.getProductVersion(), + ContextUtils.getAppSharedPreferences().getString( + SearchEngineChoiceNotification.PREF_SEARCH_ENGINE_CHOICE_PRESENTED_VERSION, + null)); + } + + @Test + @SmallTest + public void handleSearchEngineChoice_ignoredOnSubsequentCalls() { + SearchEngineChoiceNotification.receiveSearchEngineChoiceRequest(); + SearchEngineChoiceNotification.handleSearchEngineChoice(mContext, mSnackbarManager); + verify(mSnackbarManager, times(1)).showSnackbar(any(Snackbar.class)); + + SearchEngineChoiceNotification.handleSearchEngineChoice(mContext, mSnackbarManager); + assertFalse("Second call removes the preference for search engine choice before.", + ContextUtils.getAppSharedPreferences().contains( + SearchEngineChoiceNotification + .PREF_SEARCH_ENGINE_CHOICE_DEFAULT_TYPE_BEFORE)); + + SearchEngineChoiceNotification.handleSearchEngineChoice(mContext, mSnackbarManager); + + // No increase in execution counter means it was not called again. + verify(mSnackbarManager, times(1)).showSnackbar(any(Snackbar.class)); + assertEquals(1, + ShadowRecordHistogram.getHistogramValueCountForTesting( + "Android.SearchEngineChoice.Events", + SearchEngineChoiceNotification.Events.SNACKBAR_SHOWN)); + } + + @Test + @SmallTest + public void snackbarClicked() { + SearchEngineChoiceNotification.receiveSearchEngineChoiceRequest(); + SearchEngineChoiceNotification.handleSearchEngineChoice(mContext, mSnackbarManager); + verify(mSnackbarManager, times(1)).showSnackbar(mSnackbarArgument.capture()); + + mSnackbarArgument.getValue().getController().onAction(null); + assertEquals(1, + ShadowRecordHistogram.getHistogramValueCountForTesting( + "Android.SearchEngineChoice.Events", + SearchEngineChoiceNotification.Events.PROMPT_FOLLOWED)); + verify(mContext, times(1)).startActivity(any(Intent.class), isNull()); + } + + @Test + @SmallTest + public void reportSearchEngineChanged_whenNoChange() { + SearchEngineChoiceNotification.receiveSearchEngineChoiceRequest(); + SearchEngineChoiceNotification.handleSearchEngineChoice(mContext, mSnackbarManager); + verify(mSnackbarManager, times(1)).showSnackbar(mSnackbarArgument.capture()); + mSnackbarArgument.getValue().getController().onAction(null); + + // Simulates no change. + SearchEngineChoiceNotification.handleSearchEngineChoice(mContext, mSnackbarManager); + + assertFalse( + "First handleSearchEngineChoice call after prompt removes SE choice before pref.", + ContextUtils.getAppSharedPreferences().contains( + SearchEngineChoiceNotification + .PREF_SEARCH_ENGINE_CHOICE_DEFAULT_TYPE_BEFORE)); + + assertEquals(0, + ShadowRecordHistogram.getHistogramValueCountForTesting( + "Android.SearchEngineChoice.Events", + SearchEngineChoiceNotification.Events.SEARCH_ENGINE_CHANGED)); + assertEquals(0, + ShadowRecordHistogram.getHistogramValueCountForTesting( + "Android.SearchEngineChoice.ChosenSearchEngine", + SearchEngineType.SEARCH_ENGINE_DUCKDUCKGO)); + } + + @Test + @SmallTest + public void reportSearchEngineChanged_whenNoChangeOnFirstVisitToSettings() { + SearchEngineChoiceNotification.receiveSearchEngineChoiceRequest(); + SearchEngineChoiceNotification.handleSearchEngineChoice(mContext, mSnackbarManager); + verify(mSnackbarManager, times(1)).showSnackbar(mSnackbarArgument.capture()); + mSnackbarArgument.getValue().getController().onAction(null); + + // Simulates a change between the initialization, but reporting happens only the first time. + SearchEngineChoiceNotification.handleSearchEngineChoice(mContext, mSnackbarManager); + assertFalse( + "First handleSearchEngineChoice call after prompt removes SE choice before pref.", + ContextUtils.getAppSharedPreferences().contains( + SearchEngineChoiceNotification + .PREF_SEARCH_ENGINE_CHOICE_DEFAULT_TYPE_BEFORE)); + + doReturn(mAlternativeSearchEngine) + .when(mTemplateUrlService) + .getDefaultSearchEngineTemplateUrl(); + SearchEngineChoiceNotification.handleSearchEngineChoice(mContext, mSnackbarManager); + + assertEquals(0, + ShadowRecordHistogram.getHistogramValueCountForTesting( + "Android.SearchEngineChoice.Events", + SearchEngineChoiceNotification.Events.SEARCH_ENGINE_CHANGED)); + assertEquals(0, + ShadowRecordHistogram.getHistogramValueCountForTesting( + "Android.SearchEngineChoice.ChosenSearchEngine", + SearchEngineType.SEARCH_ENGINE_DUCKDUCKGO)); + } + + @Test + @SmallTest + public void reportSearchEngineChanged_onlyFirstTime() { + SearchEngineChoiceNotification.receiveSearchEngineChoiceRequest(); + SearchEngineChoiceNotification.handleSearchEngineChoice(mContext, mSnackbarManager); + verify(mSnackbarManager, times(1)).showSnackbar(mSnackbarArgument.capture()); + mSnackbarArgument.getValue().getController().onAction(null); + + // Simulates a change of search engine on the first visit to settings. + doReturn(mAlternativeSearchEngine) + .when(mTemplateUrlService) + .getDefaultSearchEngineTemplateUrl(); + SearchEngineChoiceNotification.handleSearchEngineChoice(mContext, mSnackbarManager); + + assertEquals("Event is recorded when search engine was changed.", 1, + ShadowRecordHistogram.getHistogramValueCountForTesting( + "Android.SearchEngineChoice.Events", + SearchEngineChoiceNotification.Events.SEARCH_ENGINE_CHANGED)); + assertEquals("Newly chosen search engine type should be recoreded.", 1, + ShadowRecordHistogram.getHistogramValueCountForTesting( + "Android.SearchEngineChoice.ChosenSearchEngine", + SearchEngineType.SEARCH_ENGINE_DUCKDUCKGO)); + + assertFalse( + "First handleSearchEngineChoice call after prompt removes SE choice before pref.", + ContextUtils.getAppSharedPreferences().contains( + SearchEngineChoiceNotification + .PREF_SEARCH_ENGINE_CHOICE_DEFAULT_TYPE_BEFORE)); + + SearchEngineChoiceNotification.handleSearchEngineChoice(mContext, mSnackbarManager); + + assertEquals("Event should only be recorded once, therefore count should be still 1.", 1, + ShadowRecordHistogram.getHistogramValueCountForTesting( + "Android.SearchEngineChoice.Events", + SearchEngineChoiceNotification.Events.SEARCH_ENGINE_CHANGED)); + assertEquals("New Search Engine shoudl only be reported once, therefore count should be 1", + 1, + ShadowRecordHistogram.getHistogramValueCountForTesting( + "Android.SearchEngineChoice.ChosenSearchEngine", + SearchEngineType.SEARCH_ENGINE_DUCKDUCKGO)); + } +}
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt index 4c6f29c..39c5b8d 100644 --- a/chrome/android/profiles/newest.txt +++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@ -chromeos-chrome-amd64-75.0.3750.0_rc-r1-merged.afdo.bz2 \ No newline at end of file +chromeos-chrome-amd64-75.0.3752.0_rc-r1-merged.afdo.bz2 \ No newline at end of file
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS index 16e2dea..75e297a 100644 --- a/chrome/browser/DEPS +++ b/chrome/browser/DEPS
@@ -195,7 +195,6 @@ # Allow mojo generated files in WebKit. These files use STL types and # don't use WTF types. "+third_party/blink/public/platform/modules/budget_service/budget_service.mojom.h", - "+third_party/blink/public/platform/modules/installation/installation.mojom.h", "+third_party/blink/public/platform/modules/presentation/presentation.mojom.h", # The following restrictions are for ChromeOS and in particular mus/mash where
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 97f6413..9a3961d 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -108,6 +108,7 @@ #include "content/public/common/content_switches.h" #include "content/public/common/feature_h264_with_openh264_ffmpeg.h" #include "device/base/features.h" +#include "device/fido/features.h" #include "device/vr/buildflags/buildflags.h" #include "extensions/buildflags/buildflags.h" #include "gpu/config/gpu_finch_features.h" @@ -3088,6 +3089,13 @@ kOsDesktop, FEATURE_VALUE_TYPE(features::kWebAuthCable)}, #endif // !defined(OS_ANDROID) +#if !defined(OS_ANDROID) + {"enable-web-authentication-pin-support", + flag_descriptions::kEnableWebAuthenticationPINSupportName, + flag_descriptions::kEnableWebAuthenticationPINSupportDescription, + kOsDesktop, FEATURE_VALUE_TYPE(device::kWebAuthPINSupport)}, +#endif // !defined(OS_ANDROID) + #if defined(OS_ANDROID) {"enable-sole-integration", flag_descriptions::kSoleIntegrationName, flag_descriptions::kSoleIntegrationDescription, kOsAndroid,
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc index 3a943b8..68952c3 100644 --- a/chrome/browser/android/chrome_feature_list.cc +++ b/chrome/browser/android/chrome_feature_list.cc
@@ -94,6 +94,7 @@ &kAndroidPayIntegrationV1, &kAndroidPayIntegrationV2, &kAndroidPaymentApps, + &kAndroidSearchEngineChoiceNotification, &kAndroidSiteSettingsUIRefresh, &kBackgroundTaskSchedulerForBackgroundSync, &kCastDeviceFilter, @@ -244,6 +245,10 @@ // TODO(rouslan): Remove this. const base::Feature kAndroidPaymentApps{"AndroidPaymentApps", base::FEATURE_ENABLED_BY_DEFAULT}; + +const base::Feature kAndroidSearchEngineChoiceNotification{ + "AndroidSearchEngineChoiceNotification", base::FEATURE_ENABLED_BY_DEFAULT}; + const base::Feature kAndroidSiteSettingsUIRefresh{ "AndroidSiteSettingsUIRefresh", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/chrome/browser/android/chrome_feature_list.h b/chrome/browser/android/chrome_feature_list.h index 879d274..234540f 100644 --- a/chrome/browser/android/chrome_feature_list.h +++ b/chrome/browser/android/chrome_feature_list.h
@@ -20,6 +20,7 @@ extern const base::Feature kAndroidPayIntegrationV1; extern const base::Feature kAndroidPayIntegrationV2; extern const base::Feature kAndroidPaymentApps; +extern const base::Feature kAndroidSearchEngineChoiceNotification; extern const base::Feature kAndroidSiteSettingsUIRefresh; extern const base::Feature kAndroidWebContentsDarkMode; extern const base::Feature kBackgroundTaskComponentUpdate;
diff --git a/chrome/browser/android/webapps/add_to_homescreen_manager.cc b/chrome/browser/android/webapps/add_to_homescreen_manager.cc index 615a5c6..afdc489 100644 --- a/chrome/browser/android/webapps/add_to_homescreen_manager.cc +++ b/chrome/browser/android/webapps/add_to_homescreen_manager.cc
@@ -22,7 +22,7 @@ #include "jni/AddToHomescreenManager_jni.h" #include "mojo/public/cpp/bindings/interface_request.h" #include "services/service_manager/public/cpp/interface_provider.h" -#include "third_party/blink/public/platform/modules/installation/installation.mojom.h" +#include "third_party/blink/public/mojom/installation/installation.mojom.h" #include "ui/gfx/android/java_bitmap.h" using base::android::JavaParamRef;
diff --git a/chrome/browser/banners/app_banner_manager.cc b/chrome/browser/banners/app_banner_manager.cc index 9b9ef20..d45a738 100644 --- a/chrome/browser/banners/app_banner_manager.cc +++ b/chrome/browser/banners/app_banner_manager.cc
@@ -30,7 +30,7 @@ #include "content/public/browser/web_contents.h" #include "mojo/public/cpp/bindings/interface_request.h" #include "services/service_manager/public/cpp/interface_provider.h" -#include "third_party/blink/public/platform/modules/installation/installation.mojom.h" +#include "third_party/blink/public/mojom/installation/installation.mojom.h" #include "third_party/skia/include/core/SkBitmap.h" #if defined(OS_ANDROID)
diff --git a/chrome/browser/chrome_browser_main_win.cc b/chrome/browser/chrome_browser_main_win.cc index 8a118cc8..588f8f58 100644 --- a/chrome/browser/chrome_browser_main_win.cc +++ b/chrome/browser/chrome_browser_main_win.cc
@@ -413,9 +413,7 @@ FROM_HERE, base::BindOnce(&InitializeModuleDatabase, third_party_blocking_policy_enabled)); - *module_watcher = - ModuleWatcher::Create(base::BindRepeating(&OnModuleEvent), - /* report_background_loaded_modules = */ true); + *module_watcher = ModuleWatcher::Create(base::BindRepeating(&OnModuleEvent)); } void ShowCloseBrowserFirstMessageBox() {
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index f922aba..27e4ef5 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -1286,8 +1286,6 @@ "login/screens/network_screen_view.h", "login/screens/recommend_apps/recommend_apps_fetcher.cc", "login/screens/recommend_apps/recommend_apps_fetcher.h", - "login/screens/recommend_apps/recommend_apps_fetcher_impl.cc", - "login/screens/recommend_apps/recommend_apps_fetcher_impl.h", "login/screens/recommend_apps_screen.cc", "login/screens/recommend_apps_screen.h", "login/screens/recommend_apps_screen_view.h",
diff --git a/chrome/browser/chromeos/authpolicy/auth_policy_credentials_manager.cc b/chrome/browser/chromeos/authpolicy/auth_policy_credentials_manager.cc index 066d453..361a87f 100644 --- a/chrome/browser/chromeos/authpolicy/auth_policy_credentials_manager.cc +++ b/chrome/browser/chromeos/authpolicy/auth_policy_credentials_manager.cc
@@ -116,11 +116,6 @@ StopObserveNetwork(); } -KerberosFilesHandler* -AuthPolicyCredentialsManager::GetKerberosFilesHandlerForTesting() { - return &kerberos_files_handler_; -} - void AuthPolicyCredentialsManager::GetUserStatus() { DCHECK(!is_get_status_in_progress_); is_get_status_in_progress_ = true;
diff --git a/chrome/browser/chromeos/authpolicy/auth_policy_credentials_manager.h b/chrome/browser/chromeos/authpolicy/auth_policy_credentials_manager.h index 389f7f99..a4e98a49f 100644 --- a/chrome/browser/chromeos/authpolicy/auth_policy_credentials_manager.h +++ b/chrome/browser/chromeos/authpolicy/auth_policy_credentials_manager.h
@@ -53,8 +53,6 @@ const chromeos::NetworkState* network) override; void OnShuttingDown() override; - KerberosFilesHandler* GetKerberosFilesHandlerForTesting(); - private: friend class AuthPolicyCredentialsManagerTest; // Calls AuthPolicyClient::GetUserStatus method. @@ -130,7 +128,6 @@ friend struct base::DefaultSingletonTraits< AuthPolicyCredentialsManagerFactory>; friend class AuthPolicyCredentialsManagerTest; - friend class ExistingUserControllerActiveDirectoryTest; AuthPolicyCredentialsManagerFactory(); ~AuthPolicyCredentialsManagerFactory() override;
diff --git a/chrome/browser/chromeos/authpolicy/kerberos_files_handler.cc b/chrome/browser/chromeos/authpolicy/kerberos_files_handler.cc index d847d9b..939febf6 100644 --- a/chrome/browser/chromeos/authpolicy/kerberos_files_handler.cc +++ b/chrome/browser/chromeos/authpolicy/kerberos_files_handler.cc
@@ -41,17 +41,7 @@ // Writes |blob| into file <UserPath>/kerberos/|file_name|. First writes into // temporary file and then replaces existing one. -void WriteFile(const base::FilePath& path, base::Optional<std::string> blob) { - if (!blob.has_value()) - return; - if (!base::ImportantFileWriter::WriteFileAtomically(path, blob.value())) - LOG(ERROR) << "Failed to write file " << path.value(); -} - -// Writes |krb5cc| to <DIR_HOME>/kerberos/krb5cc and |krb5config| to -// <DIR_HOME>/kerberos/krb5.conf if set. Creates directories if necessary. -void WriteFiles(base::Optional<std::string> krb5cc, - base::Optional<std::string> krb5config) { +void WriteFile(const std::string& file_name, const std::string& blob) { base::FilePath dir; base::PathService::Get(base::DIR_HOME, &dir); dir = dir.Append(kKrb5Directory); @@ -61,22 +51,19 @@ << "' directory: " << base::File::ErrorToString(error); return; } - - WriteFile(dir.Append(kKrb5CCFile), std::move(krb5cc)); - WriteFile(dir.Append(kKrb5ConfFile), std::move(krb5config)); + base::FilePath dest_file = dir.Append(file_name); + if (!base::ImportantFileWriter::WriteFileAtomically(dest_file, blob)) { + LOG(ERROR) << "Failed to write file " << dest_file.value(); + } } -// If |config| has a value, puts canonicalization settings first depending on -// user policy. Whatever setting comes first wins, so even if krb5.conf sets -// rdns or dns_canonicalize_hostname below, it would get overridden. -base::Optional<std::string> MaybeAdjustConfig( - base::Optional<std::string> config, - bool is_dns_cname_enabled) { - if (!config.has_value()) - return base::nullopt; +// Put canonicalization settings first depending on user policy. Whatever +// setting comes first wins, so even if krb5.conf sets rdns or +// dns_canonicalize_hostname below, it would get overridden. +std::string AdjustConfig(const std::string& config, bool is_dns_cname_enabled) { std::string adjusted_config = base::StringPrintf( kKrb5CnameSettings, is_dns_cname_enabled ? "true" : "false"); - adjusted_config.append(config.value()); + adjusted_config.append(config); return adjusted_config; } @@ -125,20 +112,23 @@ void KerberosFilesHandler::SetFiles(base::Optional<std::string> krb5cc, base::Optional<std::string> krb5conf) { - krb5conf = - MaybeAdjustConfig(krb5conf, !negotiate_disable_cname_lookup_.GetValue()); - base::PostTaskWithTraitsAndReply( - FROM_HERE, - {base::MayBlock(), base::TaskPriority::BEST_EFFORT, - base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}, - base::BindOnce(&WriteFiles, std::move(krb5cc), std::move(krb5conf)), - base::BindOnce(&KerberosFilesHandler::OnFilesChanged, - weak_factory_.GetWeakPtr())); -} - -void KerberosFilesHandler::SetFilesChangedForTesting( - base::OnceClosure callback) { - files_changed_for_testing_ = std::move(callback); + if (krb5cc.has_value()) { + base::PostTaskWithTraits( + FROM_HERE, + {base::MayBlock(), base::TaskPriority::BEST_EFFORT, + base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}, + base::BindOnce(&WriteFile, kKrb5CCFile, krb5cc.value())); + } + if (krb5conf.has_value()) { + base::PostTaskWithTraits( + FROM_HERE, + {base::MayBlock(), base::TaskPriority::BEST_EFFORT, + base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}, + base::BindOnce( + &WriteFile, kKrb5ConfFile, + AdjustConfig(krb5conf.value(), + !negotiate_disable_cname_lookup_.GetValue()))); + } } void KerberosFilesHandler::OnDisabledAuthNegotiateCnameLookupChanged() { @@ -146,9 +136,4 @@ get_kerberos_files_.Run(); } -void KerberosFilesHandler::OnFilesChanged() { - if (files_changed_for_testing_) - std::move(files_changed_for_testing_).Run(); -} - } // namespace chromeos
diff --git a/chrome/browser/chromeos/authpolicy/kerberos_files_handler.h b/chrome/browser/chromeos/authpolicy/kerberos_files_handler.h index df223e2d..2f93805 100644 --- a/chrome/browser/chromeos/authpolicy/kerberos_files_handler.h +++ b/chrome/browser/chromeos/authpolicy/kerberos_files_handler.h
@@ -30,24 +30,15 @@ void SetFiles(base::Optional<std::string> krb5cc, base::Optional<std::string> krb5conf); - // Sets a callback for when disk IO task posted by SetFiles has finished. - void SetFilesChangedForTesting(base::OnceClosure callback); - private: // Called whenever prefs::kDisableAuthNegotiateCnameLookup is changed. void OnDisabledAuthNegotiateCnameLookupChanged(); - // Forwards to |files_changed_for_testing_| if set. - void OnFilesChanged(); - PrefMember<bool> negotiate_disable_cname_lookup_; // Triggers a fetch of Kerberos files. Called when the watched pref changes. base::RepeatingClosure get_kerberos_files_; - // Called when disk IO queued by SetFiles has finished. - base::OnceClosure files_changed_for_testing_; - base::WeakPtrFactory<KerberosFilesHandler> weak_factory_{this}; DISALLOW_COPY_AND_ASSIGN(KerberosFilesHandler); };
diff --git a/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc b/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc index 7d3b97c..81d363c2 100644 --- a/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc +++ b/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc
@@ -5,14 +5,15 @@ #include <string> #include <vector> +#include "base/barrier_closure.h" #include "base/bind.h" #include "base/bind_helpers.h" #include "base/callback.h" #include "base/command_line.h" +#include "base/files/file_path_watcher.h" #include "base/location.h" #include "base/macros.h" #include "base/memory/ref_counted.h" -#include "base/path_service.h" #include "base/run_loop.h" #include "base/strings/stringprintf.h" #include "base/threading/thread_restrictions.h" @@ -35,8 +36,6 @@ #include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h" #include "chrome/browser/chromeos/settings/cros_settings.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_manager.h" -#include "chrome/browser/ui/browser.h" #include "chrome/grit/generated_resources.h" #include "chrome/test/base/testing_browser_process.h" #include "chromeos/constants/chromeos_switches.h" @@ -70,13 +69,13 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" -using ::testing::_; using ::testing::AnyNumber; using ::testing::Invoke; using ::testing::InvokeWithoutArgs; using ::testing::Return; using ::testing::ReturnNull; using ::testing::WithArg; +using ::testing::_; namespace em = enterprise_management; @@ -91,6 +90,7 @@ const char kSupervisedUserID[] = "supervised_user@locally-managed.localhost"; const char kPassword[] = "test_password"; const char kActiveDirectoryRealm[] = "active.directory.realm"; +const char kKrb5CCFilePrefix[] = "FILE:"; const char kPublicSessionUserEmail[] = "public_session_user@localhost"; const int kAutoLoginNoDelay = 0; @@ -116,18 +116,78 @@ } } -base::FilePath GetKerberosConfigPath() { - base::FilePath path; - EXPECT_TRUE(base::PathService::Get(base::DIR_HOME, &path)); - return path.Append("kerberos").Append("krb5.conf"); +std::string GetKerberosConfigFileName() { + std::unique_ptr<base::Environment> env(base::Environment::Create()); + std::string config_file; + EXPECT_TRUE(env->GetVar("KRB5_CONFIG", &config_file)); + return config_file; } -base::FilePath GetKerberosCredentialsCachePath() { - base::FilePath path; - EXPECT_TRUE(base::PathService::Get(base::DIR_HOME, &path)); - return path.Append("kerberos").Append("krb5cc"); +std::string GetKerberosCredentialsCacheFileName() { + std::unique_ptr<base::Environment> env(base::Environment::Create()); + std::string creds_file; + EXPECT_TRUE(env->GetVar("KRB5CCNAME", &creds_file)); + EXPECT_EQ(kKrb5CCFilePrefix, creds_file.substr(0, strlen(kKrb5CCFilePrefix))); + return creds_file.substr(strlen(kKrb5CCFilePrefix)); } +// Helper class to wait when both Kerberos credentials cache and config file +// changed. +class KerberosFilesChangeWaiter { + public: + // If |files_must_exist| is true and a file already exists the class does not + // wait when it changes. + explicit KerberosFilesChangeWaiter(bool files_must_exist) { + barrier_closure_ = base::BarrierClosure(2, loop_.QuitClosure()); + + watch_callback_ = base::BindRepeating( + [](const base::RepeatingClosure& barrier_closure, + const base::FilePath& path, bool error) -> void { + EXPECT_FALSE(error); + barrier_closure.Run(); + }, + barrier_closure_); + + config_watcher_ = std::make_unique<base::FilePathWatcher>(); + MaybeStartWatch(&config_watcher_, + base::FilePath(GetKerberosConfigFileName()), + files_must_exist); + + creds_watcher_ = std::make_unique<base::FilePathWatcher>(); + MaybeStartWatch(&creds_watcher_, + base::FilePath(GetKerberosCredentialsCacheFileName()), + files_must_exist); + } + + // Should be called once. + void Wait() { + base::ScopedAllowBlockingForTesting allow_io; + loop_.Run(); + config_watcher_.reset(); + creds_watcher_.reset(); + } + + private: + void MaybeStartWatch(std::unique_ptr<base::FilePathWatcher>* watcher, + const base::FilePath& path, + bool files_must_exist) { + base::ScopedAllowBlockingForTesting allow_io; + (*watcher)->Watch(path, false /* recursive */, watch_callback_); + if (!files_must_exist && base::PathExists(path)) { + watch_callback_.Run(path, false /* error */); + watcher->reset(); + } + } + base::RunLoop loop_; + base::RepeatingClosure barrier_closure_; + + base::RepeatingCallback<void(const base::FilePath& path, bool error)> + watch_callback_; + + std::unique_ptr<base::FilePathWatcher> config_watcher_; + std::unique_ptr<base::FilePathWatcher> creds_watcher_; +}; + } // namespace class ExistingUserControllerTest : public policy::DevicePolicyCrosBrowserTest { @@ -810,7 +870,8 @@ existing_user_controller()->CompleteLogin(user_context); profile_prepared_observer.Wait(); - WaitForKerberosFilesChanged(); + KerberosFilesChangeWaiter files_change_waiter(false /* files_must_exist */); + files_change_waiter.Wait(); CheckKerberosFiles(true /* enable_dns_cname_lookup */); } @@ -848,19 +909,20 @@ void CheckKerberosFiles(bool enable_dns_cname_lookup) { base::ScopedAllowBlockingForTesting allow_io; std::string file_contents; - EXPECT_TRUE( - base::ReadFileToString(GetKerberosConfigPath(), &file_contents)); + EXPECT_TRUE(base::ReadFileToString( + base::FilePath(GetKerberosConfigFileName()), &file_contents)); EXPECT_EQ(GetExpectedKerberosConfig(enable_dns_cname_lookup), file_contents); - EXPECT_TRUE(base::ReadFileToString(GetKerberosCredentialsCachePath(), - &file_contents)); + EXPECT_TRUE(base::ReadFileToString( + base::FilePath(GetKerberosCredentialsCacheFileName()), &file_contents)); EXPECT_EQ(file_contents, FakeAuthPolicyClient::Get()->user_kerberos_creds()); } // Applies policy and waits until both config and credentials files changed. void ApplyPolicyAndWaitFilesChanged(bool enable_dns_cname_lookup) { + KerberosFilesChangeWaiter files_change_waiter(true /* files_must_exist */); policy::PolicyMap policies; policies.Set(policy::key::kDisableAuthNegotiateCnameLookup, policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER, @@ -868,26 +930,7 @@ std::make_unique<base::Value>(!enable_dns_cname_lookup), nullptr); UpdateProviderPolicy(policies); - WaitForKerberosFilesChanged(); - } - - // Waits until the Kerberos files change on disk. - void WaitForKerberosFilesChanged() { - auto* auth_policy_credentials_manager = - static_cast<AuthPolicyCredentialsManager*>( - AuthPolicyCredentialsManagerFactory::GetInstance() - ->GetServiceForBrowserContext( - ProfileManager::GetLastUsedProfile(), false /* create */)); - EXPECT_TRUE(auth_policy_credentials_manager); - - base::RunLoop run_loop; - auth_policy_credentials_manager->GetKerberosFilesHandlerForTesting() - ->SetFilesChangedForTesting(base::BindOnce( - [](base::OnceClosure quit_closure) { - std::move(quit_closure).Run(); - }, - run_loop.QuitClosure())); - run_loop.Run(); + files_change_waiter.Wait(); } private: @@ -929,8 +972,9 @@ // Tests if DisabledAuthNegotiateCnameLookup changes trigger updating user // Kerberos files. +// Disabled due to flakiness, see https://crbug.com/865206. IN_PROC_BROWSER_TEST_F(ExistingUserControllerActiveDirectoryTest, - PolicyChangeTriggersFileUpdate) { + DISABLED_PolicyChangeTriggersFileUpdate) { LoginAdOnline(); ApplyPolicyAndWaitFilesChanged(false /* enable_dns_cname_lookup */); @@ -942,12 +986,15 @@ // Tests if user Kerberos files changed D-Bus signal triggers updating user // Kerberos files. -IN_PROC_BROWSER_TEST_F(ExistingUserControllerActiveDirectoryTest, - UserKerberosFilesChangedSignalTriggersFileUpdate) { +// Disabled due to flakiness, see https://crbug.com/865206. +IN_PROC_BROWSER_TEST_F( + ExistingUserControllerActiveDirectoryTest, + DISABLED_UserKerberosFilesChangedSignalTriggersFileUpdate) { LoginAdOnline(); + KerberosFilesChangeWaiter files_change_waiter(true /* files_must_exist */); FakeAuthPolicyClient::Get()->SetUserKerberosFiles("new_kerberos_creds", "new_kerberos_config"); - WaitForKerberosFilesChanged(); + files_change_waiter.Wait(); CheckKerberosFiles(true /* enable_dns_cname_lookup */); } @@ -968,7 +1015,8 @@ content::NotificationService::AllSources()); existing_user_controller()->Login(user_context, SigninSpecifics()); profile_prepared_observer.Wait(); - WaitForKerberosFilesChanged(); + KerberosFilesChangeWaiter files_change_waiter(false /* files_must_exist */); + files_change_waiter.Wait(); CheckKerberosFiles(true /* enable_dns_cname_lookup */); }
diff --git a/chrome/browser/chromeos/login/screens/recommend_apps/recommend_apps_fetcher.cc b/chrome/browser/chromeos/login/screens/recommend_apps/recommend_apps_fetcher.cc index 08ca541..3d5c804c 100644 --- a/chrome/browser/chromeos/login/screens/recommend_apps/recommend_apps_fetcher.cc +++ b/chrome/browser/chromeos/login/screens/recommend_apps/recommend_apps_fetcher.cc
@@ -1,37 +1,633 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. -// + #include "chrome/browser/chromeos/login/screens/recommend_apps/recommend_apps_fetcher.h" -#include "base/callback.h" -#include "chrome/browser/chromeos/login/screens/recommend_apps/recommend_apps_fetcher_impl.h" +#include "ash/public/interfaces/constants.mojom.h" +#include "ash/public/interfaces/cros_display_config.mojom.h" +#include "base/base64url.h" +#include "base/bind.h" +#include "base/json/json_reader.h" +#include "base/metrics/histogram_functions.h" +#include "base/metrics/histogram_macros.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_piece.h" +#include "base/strings/string_split.h" +#include "base/task/post_task.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/profiles/profile_manager.h" +#include "content/public/browser/gpu_data_manager.h" +#include "content/public/browser/storage_partition.h" +#include "content/public/common/service_manager_connection.h" +#include "extensions/common/api/system_display.h" +#include "gpu/config/gpu_info.h" +#include "net/base/load_flags.h" +#include "net/http/http_status_code.h" +#include "services/network/public/cpp/simple_url_loader.h" +#include "services/service_manager/public/cpp/connector.h" +#include "third_party/zlib/google/compression_utils.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" +#include "ui/events/devices/input_device.h" +#include "ui/events/devices/input_device_manager.h" +#include "ui/gfx/extension_set.h" +#include "ui/gl/gl_version_info.h" namespace chromeos { namespace { -// The factory callback that will be used to create RecommendAppsFetcher -// instances other than default RecommendAppsFetcherImpl. -// It can be set by SetFactoryCallbackForTesting(). -RecommendAppsFetcher::FactoryCallback* g_factory_callback = nullptr; +constexpr const char kGetAppListUrl[] = + "https://android.clients.google.com/fdfe/chrome/getfastreinstallappslist"; + +constexpr int kResponseErrorNotEnoughApps = 5; + +constexpr int kResponseErrorNotFirstTimeChromebookUser = 6; + +constexpr base::TimeDelta kDownloadTimeOut = base::TimeDelta::FromMinutes(1); + +constexpr const int64_t kMaxDownloadBytes = 1024 * 1024; // 1Mb + +constexpr const int kMaxAppCount = 21; + +enum RecommendAppsResponseParseResult { + // These values are persisted to logs. Entries should not be renumbered and + // numeric values should never be reused. + RECOMMEND_APPS_RESPONSE_PARSE_RESULT_NO_ERROR = 0, + RECOMMEND_APPS_RESPONSE_PARSE_RESULT_INVALID_JSON = 1, + RECOMMEND_APPS_RESPONSE_PARSE_RESULT_NO_APP = 2, + RECOMMEND_APPS_RESPONSE_PARSE_RESULT_OWNS_CHROMEBOOK_ALREADY = 3, + RECOMMEND_APPS_RESPONSE_PARSE_RESULT_UNKNOWN_ERROR_CODE = 4, + RECOMMEND_APPS_RESPONSE_PARSE_RESULT_INVALID_ERROR_CODE = 5, + + kMaxValue = RECOMMEND_APPS_RESPONSE_PARSE_RESULT_INVALID_ERROR_CODE +}; + +bool HasTouchScreen() { + return !ui::InputDeviceManager::GetInstance() + ->GetTouchscreenDevices() + .empty(); +} + +bool HasStylusInput() { + // Check to see if the hardware reports it is stylus capable. + for (const ui::TouchscreenDevice& device : + ui::InputDeviceManager::GetInstance()->GetTouchscreenDevices()) { + if (device.has_stylus && + device.type == ui::InputDeviceType::INPUT_DEVICE_INTERNAL) { + return true; + } + } + + return false; +} + +bool HasKeyboard() { + return !ui::InputDeviceManager::GetInstance()->GetKeyboardDevices().empty(); +} + +bool HasHardKeyboard() { + for (const ui::InputDevice& device : + ui::InputDeviceManager::GetInstance()->GetKeyboardDevices()) { + if (!device.phys.empty()) + return true; + } + + return false; +} + +gfx::Size GetScreenSize() { + return display::Screen::GetScreen()->GetPrimaryDisplay().GetSizeInPixel(); +} + +// TODO(rsgingerrs): This function is copied from Play. We need to find a way to +// keep this synced with the Play side if there are any changes there. Another +// approach is to let the server do the calculation since we have provided the +// screen width, height and dpi. +int CalculateStableScreenLayout(const int screen_width, + const int screen_height, + const float dpi) { + const int density_default = 160; + const float px_to_dp = density_default / static_cast<float>(dpi); + const int short_size_dp = static_cast<int>(screen_width * px_to_dp); + const int long_size_dp = static_cast<int>(screen_height * px_to_dp); + + int screen_layout_size; + bool screen_layout_long; + + const int screenlayout_size_small = 0x01; + const int screenlayout_size_normal = 0x02; + const int screenlayout_size_large = 0x03; + const int screenlayout_size_xlarge = 0x04; + const int screenlayout_long_no = 0x10; + + // These semi-magic numbers define our compatibility modes for + // applications with different screens. These are guarantees to + // app developers about the space they can expect for a particular + // configuration. DO NOT CHANGE! + if (long_size_dp < 470) { + // This is shorter than an HVGA normal density screen (which + // is 480 pixels on its long side). + screen_layout_size = screenlayout_size_small; + screen_layout_long = false; + } else { + // What size is this screen? + if (long_size_dp >= 960 && short_size_dp >= 720) { + // 1.5xVGA or larger screens at medium density are the point + // at which we consider it to be an extra large screen. + screen_layout_size = screenlayout_size_xlarge; + } else if (long_size_dp >= 640 && short_size_dp >= 480) { + // VGA or larger screens at medium density are the point + // at which we consider it to be a large screen. + screen_layout_size = screenlayout_size_large; + } else { + screen_layout_size = screenlayout_size_normal; + } + + // Is this a long screen? Anything wider than WVGA (5:3) is considering to + // be long. + screen_layout_long = ((long_size_dp * 3) / 5) >= (short_size_dp - 1); + } + + int screen_layout = screen_layout_size; + if (!screen_layout_long) { + screen_layout |= screenlayout_long_no; + } + + return screen_layout; +} + +device_configuration::DeviceConfigurationProto_ScreenLayout +GetScreenLayoutSizeId(const int screen_layout_size_value) { + const int screenlayout_size_small = 0x01; + const int screenlayout_size_normal = 0x02; + const int screenlayout_size_large = 0x03; + const int screenlayout_size_xlarge = 0x04; + const int screenlayout_size_mask = 0x0f; + int size_bits = screen_layout_size_value & screenlayout_size_mask; + + switch (size_bits) { + case screenlayout_size_small: + return device_configuration::DeviceConfigurationProto_ScreenLayout:: + DeviceConfigurationProto_ScreenLayout_SMALL; + case screenlayout_size_normal: + return device_configuration::DeviceConfigurationProto_ScreenLayout:: + DeviceConfigurationProto_ScreenLayout_NORMAL; + case screenlayout_size_large: + return device_configuration::DeviceConfigurationProto_ScreenLayout:: + DeviceConfigurationProto_ScreenLayout_LARGE; + case screenlayout_size_xlarge: + return device_configuration::DeviceConfigurationProto_ScreenLayout:: + DeviceConfigurationProto_ScreenLayout_EXTRA_LARGE; + default: + return device_configuration::DeviceConfigurationProto_ScreenLayout:: + DeviceConfigurationProto_ScreenLayout_UNDEFINED_SCREEN_LAYOUT; + } +} + +const gpu::GPUInfo GetGPUInfo() { + return content::GpuDataManager::GetInstance()->GetGPUInfo(); +} + +// This function converts the major and minor versions to the proto accepted +// value. For example, if the version is 3.2, the return value is 0x00030002. +unsigned GetGLVersionInfo() { + const gpu::GPUInfo gpu_info = GetGPUInfo(); + gfx::ExtensionSet extensionSet(gfx::MakeExtensionSet(gpu_info.gl_extensions)); + gl::GLVersionInfo glVersionInfo(gpu_info.gl_version.c_str(), + gpu_info.gl_renderer.c_str(), extensionSet); + + unsigned major_version = glVersionInfo.major_version; + unsigned minor_version = glVersionInfo.minor_version; + unsigned version = 0x0000ffff; + version &= minor_version; + version |= (major_version << 16) & 0xffff0000; + + return version; +} + +gfx::ExtensionSet GetGLExtensions() { + const gpu::GPUInfo gpu_info = GetGPUInfo(); + gfx::ExtensionSet extensionSet(gfx::MakeExtensionSet(gpu_info.gl_extensions)); + + return extensionSet; +} + +const std::string& GetAndroidSdkVersion(const arc::ArcFeatures& arc_features) { + return arc_features.build_props.at("ro.build.version.sdk"); +} + +std::vector<std::string> GetCpuAbiList(const arc::ArcFeatures& arc_features) { + const std::string& abi_list_str = + arc_features.build_props.at("ro.product.cpu.abilist"); + return base::SplitString(abi_list_str, ",", base::TRIM_WHITESPACE, + base::SPLIT_WANT_ALL); +} + +std::string CompressAndEncodeProtoMessageOnBlockingThread( + device_configuration::DeviceConfigurationProto device_config) { + std::string encoded_device_configuration_proto; + + std::string serialized_proto; + device_config.SerializeToString(&serialized_proto); + std::string compressed_proto; + compression::GzipCompress(serialized_proto, &compressed_proto); + base::Base64UrlEncode(compressed_proto, + base::Base64UrlEncodePolicy::OMIT_PADDING, + &encoded_device_configuration_proto); + + return encoded_device_configuration_proto; +} + +void RecordUmaResponseAppCount(int app_count) { + UMA_HISTOGRAM_CUSTOM_COUNTS("OOBE.RecommendApps.Fetcher.AppCount", app_count, + 0, kMaxAppCount, kMaxAppCount + 1); +} + +void RecordUmaDownloadTime(base::TimeDelta download_time) { + UMA_HISTOGRAM_TIMES("OOBE.RecommendApps.Fetcher.DownloadTime", download_time); +} + +void RecordUmaResponseCode(int code) { + base::UmaHistogramSparse("OOBE.RecommendApps.Fetcher.ResponseCode", code); +} + +void RecordUmaResponseParseResult(RecommendAppsResponseParseResult result) { + UMA_HISTOGRAM_ENUMERATION("OOBE.RecommendApps.Fetcher.ResponseParseResult", + result); +} + +void RecordUmaResponseSize(unsigned long responseSize) { + UMA_HISTOGRAM_COUNTS_1M( + "OOBE.RecommendApps.Fetcher.ResponseSize", + static_cast<base::HistogramBase::Sample>(responseSize)); +} } // namespace -// static -std::unique_ptr<RecommendAppsFetcher> RecommendAppsFetcher::Create( - RecommendAppsScreenView* view) { - if (g_factory_callback) - return g_factory_callback->Run(view); - return std::make_unique<RecommendAppsFetcherImpl>(view); +RecommendAppsFetcher::RecommendAppsFetcher(RecommendAppsScreenView* view) + : view_(view), weak_ptr_factory_(this) { + service_manager::Connector* connector = + content::ServiceManagerConnection::GetForProcess()->GetConnector(); + DCHECK(connector); + connector->BindInterface(ash::mojom::kServiceName, &cros_display_config_); + + PopulateDeviceConfig(); + StartAshRequest(); + arc::ArcFeaturesParser::GetArcFeatures( + base::BindOnce(&RecommendAppsFetcher::OnArcFeaturesRead, + weak_ptr_factory_.GetWeakPtr())); } -// static -void RecommendAppsFetcher::SetFactoryCallbackForTesting( - FactoryCallback* callback) { - DCHECK(!g_factory_callback || !callback); +RecommendAppsFetcher::~RecommendAppsFetcher() = default; - g_factory_callback = callback; +void RecommendAppsFetcher::PopulateDeviceConfig() { + if (!HasTouchScreen()) { + device_config_.set_touch_screen( + device_configuration::DeviceConfigurationProto_TouchScreen:: + DeviceConfigurationProto_TouchScreen_NOTOUCH); + } else if (!HasStylusInput()) { + device_config_.set_touch_screen( + device_configuration::DeviceConfigurationProto_TouchScreen:: + DeviceConfigurationProto_TouchScreen_FINGER); + } else { + device_config_.set_touch_screen( + device_configuration::DeviceConfigurationProto_TouchScreen:: + DeviceConfigurationProto_TouchScreen_STYLUS); + } + + if (!HasKeyboard()) { + device_config_.set_keyboard( + device_configuration::DeviceConfigurationProto_Keyboard:: + DeviceConfigurationProto_Keyboard_NOKEYS); + } else { + // TODO(rsgingerrs): Currently there is no straightforward way to determine + // whether it is a full keyboard or not. We assume it is safe to set it as + // QWERTY keyboard for this feature. + device_config_.set_keyboard( + device_configuration::DeviceConfigurationProto_Keyboard:: + DeviceConfigurationProto_Keyboard_QWERTY); + } + device_config_.set_has_hard_keyboard(HasHardKeyboard()); + + // TODO(rsgingerrs): There is no straightforward way to get this info. We + // assume it is safe to set it as no navigation. + device_config_.set_navigation( + device_configuration::DeviceConfigurationProto_Navigation:: + DeviceConfigurationProto_Navigation_NONAV); + device_config_.set_has_five_way_navigation(false); + + device_config_.set_gl_es_version(GetGLVersionInfo()); + + for (const base::StringPiece& gl_extension : GetGLExtensions()) { + if (!gl_extension.empty()) + device_config_.add_gl_extension(gl_extension.as_string()); + } +} + +void RecommendAppsFetcher::StartAshRequest() { + cros_display_config_->GetDisplayUnitInfoList( + false /* single_unified */, + base::BindOnce(&RecommendAppsFetcher::OnAshResponse, + weak_ptr_factory_.GetWeakPtr())); +} + +void RecommendAppsFetcher::MaybeStartCompressAndEncodeProtoMessage() { + if (!ash_ready_ || !arc_features_ready_ || has_started_proto_processing_) + return; + + base::PostTaskWithTraitsAndReplyWithResult( + FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT}, + base::BindOnce(&CompressAndEncodeProtoMessageOnBlockingThread, + std::move(device_config_)), + base::BindOnce(&RecommendAppsFetcher::OnProtoMessageCompressedAndEncoded, + weak_ptr_factory_.GetWeakPtr())); + has_started_proto_processing_ = true; +} + +void RecommendAppsFetcher::OnProtoMessageCompressedAndEncoded( + std::string encoded_device_configuration_proto) { + proto_compressed_and_encoded_ = true; + encoded_device_configuration_proto_ = encoded_device_configuration_proto; + StartDownload(); +} + +void RecommendAppsFetcher::OnAshResponse( + std::vector<ash::mojom::DisplayUnitInfoPtr> all_displays_info) { + ash_ready_ = true; + + int screen_density = 0; + for (const ash::mojom::DisplayUnitInfoPtr& display_info : all_displays_info) { + if (base::NumberToString(display::Display::InternalDisplayId()) == + display_info->id) { + screen_density = display_info->dpi_x + display_info->dpi_y; + break; + } + } + device_config_.set_screen_density(screen_density); + + const int screen_width = GetScreenSize().width(); + const int screen_height = GetScreenSize().height(); + device_config_.set_screen_width(screen_width); + device_config_.set_screen_height(screen_height); + + const int screen_layout = + CalculateStableScreenLayout(screen_width, screen_height, screen_density); + device_config_.set_screen_layout(GetScreenLayoutSizeId(screen_layout)); + + MaybeStartCompressAndEncodeProtoMessage(); +} + +void RecommendAppsFetcher::OnArcFeaturesRead( + base::Optional<arc::ArcFeatures> read_result) { + arc_features_ready_ = true; + + if (read_result != base::nullopt) { + for (const auto& feature : read_result.value().feature_map) { + device_config_.add_system_available_feature(feature.first); + } + + for (const auto& abi : GetCpuAbiList(read_result.value())) { + device_config_.add_native_platform(abi); + } + + play_store_version_ = read_result.value().play_store_version; + + android_sdk_version_ = GetAndroidSdkVersion(read_result.value()); + } + + MaybeStartCompressAndEncodeProtoMessage(); +} + +void RecommendAppsFetcher::StartDownload() { + if (!proto_compressed_and_encoded_) + return; + + net::NetworkTrafficAnnotationTag traffic_annotation = + net::DefineNetworkTrafficAnnotation("play_recommended_apps_download", R"( + semantics { + sender: "ChromeOS Recommended Apps Screen" + description: + "Chrome OS downloads the recommended app list from Google Play API." + trigger: + "When user has accepted the ARC Terms of Service." + data: + "URL of the Google Play API." + destination: GOOGLE_OWNED_SERVICE + } + policy { + cookies_allowed: YES + cookie_store: "user" + setting: + "NA" + policy_exception_justification: + "Not implemented, considered not necessary." + })"); + + Profile* profile = ProfileManager::GetActiveUserProfile(); + + auto resource_request = std::make_unique<network::ResourceRequest>(); + resource_request->url = GURL(kGetAppListUrl); + resource_request->method = "GET"; + resource_request->load_flags = + net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE; + + resource_request->headers.SetHeader("X-DFE-Device-Config", + encoded_device_configuration_proto_); + resource_request->headers.SetHeader("X-DFE-Sdk-Version", + android_sdk_version_); + resource_request->headers.SetHeader("X-DFE-Chromesky-Client-Version", + play_store_version_); + + network::mojom::URLLoaderFactory* loader_factory = + content::BrowserContext::GetDefaultStoragePartition(profile) + ->GetURLLoaderFactoryForBrowserProcess() + .get(); + + start_time_ = base::TimeTicks::Now(); + app_list_loader_ = network::SimpleURLLoader::Create( + std::move(resource_request), traffic_annotation); + // Retry up to three times if network changes are detected during the + // download. + app_list_loader_->SetRetryOptions( + 3, network::SimpleURLLoader::RETRY_ON_NETWORK_CHANGE); + app_list_loader_->DownloadToString( + loader_factory, + base::BindOnce(&RecommendAppsFetcher::OnDownloaded, + base::Unretained(this)), + kMaxDownloadBytes); + + // Abort the download attempt if it takes longer than one minute. + download_timer_.Start(FROM_HERE, kDownloadTimeOut, this, + &RecommendAppsFetcher::OnDownloadTimeout); +} + +void RecommendAppsFetcher::OnDownloadTimeout() { + // Destroy the fetcher, which will abort the download attempt. + app_list_loader_.reset(); + + RecordUmaDownloadTime(base::TimeTicks::Now() - start_time_); + + // Show an error message to the user. + if (view_) + view_->OnLoadError(); +} + +void RecommendAppsFetcher::OnDownloaded( + std::unique_ptr<std::string> response_body) { + download_timer_.Stop(); + + RecordUmaDownloadTime(base::TimeTicks::Now() - start_time_); + + std::unique_ptr<network::SimpleURLLoader> loader(std::move(app_list_loader_)); + if (!view_) + return; + + int response_code = 0; + if (!loader->ResponseInfo() || !loader->ResponseInfo()->headers) { + view_->OnLoadError(); + return; + } + response_code = loader->ResponseInfo()->headers->response_code(); + RecordUmaResponseCode(response_code); + + // If the recommended app list could not be downloaded, show an error message + // to the user. + if (!response_body || response_body->empty()) { + view_->OnLoadError(); + return; + } + + // If the recommended app list were downloaded successfully, show them to + // the user. + // + // The response starts with a prefix ")]}'". This needs to be removed before + // further parsing. + RecordUmaResponseSize(response_body->size()); + constexpr base::StringPiece json_xss_prevention_prefix(")]}'"); + base::StringPiece response_body_json(*response_body); + if (response_body_json.starts_with(json_xss_prevention_prefix)) + response_body_json.remove_prefix(json_xss_prevention_prefix.length()); + base::Optional<base::Value> output = ParseResponse(response_body_json); + if (!output.has_value()) { + RecordUmaResponseAppCount(0); + view_->OnParseResponseError(); + return; + } + + view_->OnLoadSuccess(std::move(output.value())); +} + +void RecommendAppsFetcher::Retry() { + StartDownload(); +} + +base::Optional<base::Value> RecommendAppsFetcher::ParseResponse( + base::StringPiece response) { + base::Value output(base::Value::Type::LIST); + + int error_code; + std::string error_msg; + std::unique_ptr<base::Value> json_value = + base::JSONReader::ReadAndReturnErrorDeprecated( + response, base::JSON_PARSE_RFC, &error_code, &error_msg); + + if (!json_value || (!json_value->is_list() && !json_value->is_dict())) { + LOG(ERROR) << "Error parsing response JSON: " << error_msg; + RecordUmaResponseParseResult( + RECOMMEND_APPS_RESPONSE_PARSE_RESULT_INVALID_JSON); + return base::nullopt; + } + + // If the response is a dictionary, it is an error message in the + // following format: + // {"Error code":"error code","Error message":"Error message"} + if (json_value->is_dict()) { + const base::Value* response_error_code_value = + json_value->FindKeyOfType("Error code", base::Value::Type::STRING); + + if (!response_error_code_value) { + LOG(ERROR) << "Unable to find error code: response=" + << response.substr(0, 128); + RecordUmaResponseParseResult( + RECOMMEND_APPS_RESPONSE_PARSE_RESULT_INVALID_JSON); + return base::nullopt; + } + + base::StringPiece response_error_code_str = + response_error_code_value->GetString(); + int response_error_code = 0; + if (!base::StringToInt(response_error_code_str, &response_error_code)) { + LOG(WARNING) << "Unable to parse error code: " << response_error_code_str; + RecordUmaResponseParseResult( + RECOMMEND_APPS_RESPONSE_PARSE_RESULT_INVALID_ERROR_CODE); + return base::nullopt; + } + + if (response_error_code == kResponseErrorNotFirstTimeChromebookUser) { + RecordUmaResponseParseResult( + RECOMMEND_APPS_RESPONSE_PARSE_RESULT_OWNS_CHROMEBOOK_ALREADY); + } else if (response_error_code == kResponseErrorNotEnoughApps) { + RecordUmaResponseParseResult(RECOMMEND_APPS_RESPONSE_PARSE_RESULT_NO_APP); + } else { + LOG(WARNING) << "Unknown error code: " << response_error_code_str; + RecordUmaResponseParseResult( + RECOMMEND_APPS_RESPONSE_PARSE_RESULT_UNKNOWN_ERROR_CODE); + } + + return base::nullopt; + } + + // Otherwise, the response should return a list of apps. + const base::Value::ListStorage& app_list = json_value->GetList(); + if (app_list.empty()) { + DVLOG(1) << "No app in the response."; + RecordUmaResponseParseResult(RECOMMEND_APPS_RESPONSE_PARSE_RESULT_NO_APP); + return base::nullopt; + } + + for (auto& item : app_list) { + base::Value output_map(base::Value::Type::DICTIONARY); + + if (!item.is_dict()) { + DVLOG(1) << "Cannot parse item."; + continue; + } + + // Retrieve the app title. + const base::Value* title = + item.FindPathOfType({"title_", "name_"}, base::Value::Type::STRING); + if (title) + output_map.SetKey("name", base::Value(title->GetString())); + + // Retrieve the package name. + const base::Value* package_name = + item.FindPathOfType({"id_", "id_"}, base::Value::Type::STRING); + if (package_name) + output_map.SetKey("package_name", base::Value(package_name->GetString())); + + // Retrieve the icon URL for the app. + // + // The name "privateDoNotAccessOrElseSafeUrlWrappedValue_" here is because + // it is a direct serialization from the proto message. The value has been + // sanitized so it is regarded as a safe URL. In general, if the response is + // a protobuf, we should not directly access this field but use the wrapper + // method getSafeUrlString() to read it. In our case, we don't have the + // option other than access it directly. + const base::Value* icon_url = item.FindPathOfType( + {"icon_", "url_", "privateDoNotAccessOrElseSafeUrlWrappedValue_"}, + base::Value::Type::STRING); + if (icon_url) + output_map.SetKey("icon", base::Value(icon_url->GetString())); + + output.GetList().push_back(std::move(output_map)); + } + + RecordUmaResponseParseResult(RECOMMEND_APPS_RESPONSE_PARSE_RESULT_NO_ERROR); + RecordUmaResponseAppCount(static_cast<int>(output.GetList().size())); + + return output; } } // namespace chromeos
diff --git a/chrome/browser/chromeos/login/screens/recommend_apps/recommend_apps_fetcher.h b/chrome/browser/chromeos/login/screens/recommend_apps/recommend_apps_fetcher.h index f6be97a..357c7a5 100644 --- a/chrome/browser/chromeos/login/screens/recommend_apps/recommend_apps_fetcher.h +++ b/chrome/browser/chromeos/login/screens/recommend_apps/recommend_apps_fetcher.h
@@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. @@ -6,27 +6,132 @@ #define CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_RECOMMEND_APPS_RECOMMEND_APPS_FETCHER_H_ #include <memory> +#include <string> +#include <vector> -#include "base/callback_forward.h" +#include "ash/public/interfaces/cros_display_config.mojom.h" +#include "base/callback.h" +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "base/timer/timer.h" +#include "chrome/browser/chromeos/login/screens/recommend_apps/device_configuration.pb.h" +#include "chrome/browser/chromeos/login/screens/recommend_apps_screen_view.h" +#include "components/arc/arc_features_parser.h" +#include "extensions/browser/api/system_display/display_info_provider.h" + +namespace network { +class SimpleURLLoader; +} namespace chromeos { -class RecommendAppsScreenView; - +// This class handles the network request for the Recommend Apps screen. It is +// supposed to run on the UI thread. The request requires the following headers: +// 1. X-Device-Config +// 2. X-Sdk-Version +// Play requires Android device config information to filter apps. +// device_configuration.proto is used to encode all the info. The following +// fields will be retrieved and sent: +// 1. touch_screen +// 2. keyboard +// 3. navigation +// 4. screen_layout +// 5. has_hard_keyboard +// 6. has_five_way_navigation +// 7. screen_density +// 8. screen_width +// 9. screen_height +// 10. gl_es_version +// 11. system_available_feature +// 12. native_platform +// 13. gl_extension class RecommendAppsFetcher { public: - static std::unique_ptr<RecommendAppsFetcher> Create( - RecommendAppsScreenView* view); + explicit RecommendAppsFetcher(RecommendAppsScreenView* view); + ~RecommendAppsFetcher(); - using FactoryCallback = - base::RepeatingCallback<std::unique_ptr<RecommendAppsFetcher>( - RecommendAppsScreenView* view)>; - static void SetFactoryCallbackForTesting(FactoryCallback* callback); + // Provide a retry method to download the app list again. + void Retry(); - virtual ~RecommendAppsFetcher() = default; + private: + // Populate the required device config info. + void PopulateDeviceConfig(); - virtual void Start() = 0; - virtual void Retry() = 0; + // Start the connection to ash. Send the request to get display unit info + // list. + void StartAshRequest(); + + // Start to compress and encode the proto message if we finish ash request + // and ARC feature is read. + void MaybeStartCompressAndEncodeProtoMessage(); + + // Callback function called when display unit info list is retrieved from ash. + // It will populate the device config info related to the screen density. + void OnAshResponse( + std::vector<ash::mojom::DisplayUnitInfoPtr> all_displays_info); + + // Callback function called when ARC features are read by the parser. + // It will populate the device config info related to ARC features. + void OnArcFeaturesRead(base::Optional<arc::ArcFeatures> read_result); + + // Callback function called when the proto message has been compressed and + // encoded. + void OnProtoMessageCompressedAndEncoded( + std::string encoded_device_configuration_proto); + + // Start downloading the recommended app list. + void StartDownload(); + + // Abort the attempt to download the recommended app list if it takes too + // long. + void OnDownloadTimeout(); + + // Callback function called when SimpleURLLoader completes. + void OnDownloaded(std::unique_ptr<std::string> response_body); + + // If the response is not a valid JSON, return base::nullopt. + // If the response contains no app, return base::nullopt; + // Value output, in true, is a list containing: + // 1. name: the title of the app. + // 2. package_name + // 3. Possibly an Icon URL. + // Parses an input string that looks somewhat like this: + // [{"title_" : {"name_" : {title of app"}}, + // "id_" : {"id_" : {com.package.name"}}, + // "icon_": {"url_": {"privateDoNotAccessOrElseSafeUrlWrappedValue_": + // "http://icon_url.com/url"}}}, + // {"title_" : "title of second app", + // "packageName_": "second package name.", + // }] + base::Optional<base::Value> ParseResponse(base::StringPiece response); + + device_configuration::DeviceConfigurationProto device_config_; + + std::string android_sdk_version_; + + std::string play_store_version_; + + std::string encoded_device_configuration_proto_; + + bool ash_ready_ = false; + bool arc_features_ready_ = false; + bool has_started_proto_processing_ = false; + bool proto_compressed_and_encoded_ = false; + + RecommendAppsScreenView* view_; + + std::unique_ptr<network::SimpleURLLoader> app_list_loader_; + + // Timer that enforces a custom (shorter) timeout on the attempt to download + // the recommended app list. + base::OneShotTimer download_timer_; + + base::TimeTicks start_time_; + + ash::mojom::CrosDisplayConfigControllerPtr cros_display_config_; + base::WeakPtrFactory<RecommendAppsFetcher> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(RecommendAppsFetcher); }; } // namespace chromeos
diff --git a/chrome/browser/chromeos/login/screens/recommend_apps/recommend_apps_fetcher_impl.cc b/chrome/browser/chromeos/login/screens/recommend_apps/recommend_apps_fetcher_impl.cc deleted file mode 100644 index 3c4cdf9..0000000 --- a/chrome/browser/chromeos/login/screens/recommend_apps/recommend_apps_fetcher_impl.cc +++ /dev/null
@@ -1,637 +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. - -#include "chrome/browser/chromeos/login/screens/recommend_apps/recommend_apps_fetcher_impl.h" - -#include "ash/public/interfaces/constants.mojom.h" -#include "ash/public/interfaces/cros_display_config.mojom.h" -#include "base/base64url.h" -#include "base/bind.h" -#include "base/json/json_reader.h" -#include "base/metrics/histogram_functions.h" -#include "base/metrics/histogram_macros.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_piece.h" -#include "base/strings/string_split.h" -#include "base/task/post_task.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_manager.h" -#include "content/public/browser/gpu_data_manager.h" -#include "content/public/browser/storage_partition.h" -#include "content/public/common/service_manager_connection.h" -#include "extensions/common/api/system_display.h" -#include "gpu/config/gpu_info.h" -#include "net/base/load_flags.h" -#include "net/http/http_status_code.h" -#include "services/network/public/cpp/simple_url_loader.h" -#include "services/service_manager/public/cpp/connector.h" -#include "third_party/zlib/google/compression_utils.h" -#include "ui/display/display.h" -#include "ui/display/screen.h" -#include "ui/events/devices/input_device.h" -#include "ui/events/devices/input_device_manager.h" -#include "ui/gfx/extension_set.h" -#include "ui/gl/gl_version_info.h" - -namespace chromeos { - -namespace { - -constexpr const char kGetAppListUrl[] = - "https://android.clients.google.com/fdfe/chrome/getfastreinstallappslist"; - -constexpr int kResponseErrorNotEnoughApps = 5; - -constexpr int kResponseErrorNotFirstTimeChromebookUser = 6; - -constexpr base::TimeDelta kDownloadTimeOut = base::TimeDelta::FromMinutes(1); - -constexpr const int64_t kMaxDownloadBytes = 1024 * 1024; // 1Mb - -constexpr const int kMaxAppCount = 21; - -enum RecommendAppsResponseParseResult { - // These values are persisted to logs. Entries should not be renumbered and - // numeric values should never be reused. - RECOMMEND_APPS_RESPONSE_PARSE_RESULT_NO_ERROR = 0, - RECOMMEND_APPS_RESPONSE_PARSE_RESULT_INVALID_JSON = 1, - RECOMMEND_APPS_RESPONSE_PARSE_RESULT_NO_APP = 2, - RECOMMEND_APPS_RESPONSE_PARSE_RESULT_OWNS_CHROMEBOOK_ALREADY = 3, - RECOMMEND_APPS_RESPONSE_PARSE_RESULT_UNKNOWN_ERROR_CODE = 4, - RECOMMEND_APPS_RESPONSE_PARSE_RESULT_INVALID_ERROR_CODE = 5, - - kMaxValue = RECOMMEND_APPS_RESPONSE_PARSE_RESULT_INVALID_ERROR_CODE -}; - -bool HasTouchScreen() { - return !ui::InputDeviceManager::GetInstance() - ->GetTouchscreenDevices() - .empty(); -} - -bool HasStylusInput() { - // Check to see if the hardware reports it is stylus capable. - for (const ui::TouchscreenDevice& device : - ui::InputDeviceManager::GetInstance()->GetTouchscreenDevices()) { - if (device.has_stylus && - device.type == ui::InputDeviceType::INPUT_DEVICE_INTERNAL) { - return true; - } - } - - return false; -} - -bool HasKeyboard() { - return !ui::InputDeviceManager::GetInstance()->GetKeyboardDevices().empty(); -} - -bool HasHardKeyboard() { - for (const ui::InputDevice& device : - ui::InputDeviceManager::GetInstance()->GetKeyboardDevices()) { - if (!device.phys.empty()) - return true; - } - - return false; -} - -gfx::Size GetScreenSize() { - return display::Screen::GetScreen()->GetPrimaryDisplay().GetSizeInPixel(); -} - -// TODO(rsgingerrs): This function is copied from Play. We need to find a way to -// keep this synced with the Play side if there are any changes there. Another -// approach is to let the server do the calculation since we have provided the -// screen width, height and dpi. -int CalculateStableScreenLayout(const int screen_width, - const int screen_height, - const float dpi) { - const int density_default = 160; - const float px_to_dp = density_default / static_cast<float>(dpi); - const int short_size_dp = static_cast<int>(screen_width * px_to_dp); - const int long_size_dp = static_cast<int>(screen_height * px_to_dp); - - int screen_layout_size; - bool screen_layout_long; - - const int screenlayout_size_small = 0x01; - const int screenlayout_size_normal = 0x02; - const int screenlayout_size_large = 0x03; - const int screenlayout_size_xlarge = 0x04; - const int screenlayout_long_no = 0x10; - - // These semi-magic numbers define our compatibility modes for - // applications with different screens. These are guarantees to - // app developers about the space they can expect for a particular - // configuration. DO NOT CHANGE! - if (long_size_dp < 470) { - // This is shorter than an HVGA normal density screen (which - // is 480 pixels on its long side). - screen_layout_size = screenlayout_size_small; - screen_layout_long = false; - } else { - // What size is this screen? - if (long_size_dp >= 960 && short_size_dp >= 720) { - // 1.5xVGA or larger screens at medium density are the point - // at which we consider it to be an extra large screen. - screen_layout_size = screenlayout_size_xlarge; - } else if (long_size_dp >= 640 && short_size_dp >= 480) { - // VGA or larger screens at medium density are the point - // at which we consider it to be a large screen. - screen_layout_size = screenlayout_size_large; - } else { - screen_layout_size = screenlayout_size_normal; - } - - // Is this a long screen? Anything wider than WVGA (5:3) is considering to - // be long. - screen_layout_long = ((long_size_dp * 3) / 5) >= (short_size_dp - 1); - } - - int screen_layout = screen_layout_size; - if (!screen_layout_long) { - screen_layout |= screenlayout_long_no; - } - - return screen_layout; -} - -device_configuration::DeviceConfigurationProto_ScreenLayout -GetScreenLayoutSizeId(const int screen_layout_size_value) { - const int screenlayout_size_small = 0x01; - const int screenlayout_size_normal = 0x02; - const int screenlayout_size_large = 0x03; - const int screenlayout_size_xlarge = 0x04; - const int screenlayout_size_mask = 0x0f; - int size_bits = screen_layout_size_value & screenlayout_size_mask; - - switch (size_bits) { - case screenlayout_size_small: - return device_configuration::DeviceConfigurationProto_ScreenLayout:: - DeviceConfigurationProto_ScreenLayout_SMALL; - case screenlayout_size_normal: - return device_configuration::DeviceConfigurationProto_ScreenLayout:: - DeviceConfigurationProto_ScreenLayout_NORMAL; - case screenlayout_size_large: - return device_configuration::DeviceConfigurationProto_ScreenLayout:: - DeviceConfigurationProto_ScreenLayout_LARGE; - case screenlayout_size_xlarge: - return device_configuration::DeviceConfigurationProto_ScreenLayout:: - DeviceConfigurationProto_ScreenLayout_EXTRA_LARGE; - default: - return device_configuration::DeviceConfigurationProto_ScreenLayout:: - DeviceConfigurationProto_ScreenLayout_UNDEFINED_SCREEN_LAYOUT; - } -} - -const gpu::GPUInfo GetGPUInfo() { - return content::GpuDataManager::GetInstance()->GetGPUInfo(); -} - -// This function converts the major and minor versions to the proto accepted -// value. For example, if the version is 3.2, the return value is 0x00030002. -unsigned GetGLVersionInfo() { - const gpu::GPUInfo gpu_info = GetGPUInfo(); - gfx::ExtensionSet extensionSet(gfx::MakeExtensionSet(gpu_info.gl_extensions)); - gl::GLVersionInfo glVersionInfo(gpu_info.gl_version.c_str(), - gpu_info.gl_renderer.c_str(), extensionSet); - - unsigned major_version = glVersionInfo.major_version; - unsigned minor_version = glVersionInfo.minor_version; - unsigned version = 0x0000ffff; - version &= minor_version; - version |= (major_version << 16) & 0xffff0000; - - return version; -} - -gfx::ExtensionSet GetGLExtensions() { - const gpu::GPUInfo gpu_info = GetGPUInfo(); - gfx::ExtensionSet extensionSet(gfx::MakeExtensionSet(gpu_info.gl_extensions)); - - return extensionSet; -} - -const std::string& GetAndroidSdkVersion(const arc::ArcFeatures& arc_features) { - return arc_features.build_props.at("ro.build.version.sdk"); -} - -std::vector<std::string> GetCpuAbiList(const arc::ArcFeatures& arc_features) { - const std::string& abi_list_str = - arc_features.build_props.at("ro.product.cpu.abilist"); - return base::SplitString(abi_list_str, ",", base::TRIM_WHITESPACE, - base::SPLIT_WANT_ALL); -} - -std::string CompressAndEncodeProtoMessageOnBlockingThread( - device_configuration::DeviceConfigurationProto device_config) { - std::string encoded_device_configuration_proto; - - std::string serialized_proto; - device_config.SerializeToString(&serialized_proto); - std::string compressed_proto; - compression::GzipCompress(serialized_proto, &compressed_proto); - base::Base64UrlEncode(compressed_proto, - base::Base64UrlEncodePolicy::OMIT_PADDING, - &encoded_device_configuration_proto); - - return encoded_device_configuration_proto; -} - -void RecordUmaResponseAppCount(int app_count) { - UMA_HISTOGRAM_CUSTOM_COUNTS("OOBE.RecommendApps.Fetcher.AppCount", app_count, - 0, kMaxAppCount, kMaxAppCount + 1); -} - -void RecordUmaDownloadTime(base::TimeDelta download_time) { - UMA_HISTOGRAM_TIMES("OOBE.RecommendApps.Fetcher.DownloadTime", download_time); -} - -void RecordUmaResponseCode(int code) { - base::UmaHistogramSparse("OOBE.RecommendApps.Fetcher.ResponseCode", code); -} - -void RecordUmaResponseParseResult(RecommendAppsResponseParseResult result) { - UMA_HISTOGRAM_ENUMERATION("OOBE.RecommendApps.Fetcher.ResponseParseResult", - result); -} - -void RecordUmaResponseSize(unsigned long responseSize) { - UMA_HISTOGRAM_COUNTS_1M( - "OOBE.RecommendApps.Fetcher.ResponseSize", - static_cast<base::HistogramBase::Sample>(responseSize)); -} - -} // namespace - -RecommendAppsFetcherImpl::RecommendAppsFetcherImpl( - RecommendAppsScreenView* view) - : view_(view), weak_ptr_factory_(this) { - service_manager::Connector* connector = - content::ServiceManagerConnection::GetForProcess()->GetConnector(); - DCHECK(connector); - connector->BindInterface(ash::mojom::kServiceName, &cros_display_config_); -} - -RecommendAppsFetcherImpl::~RecommendAppsFetcherImpl() = default; - -void RecommendAppsFetcherImpl::PopulateDeviceConfig() { - if (!HasTouchScreen()) { - device_config_.set_touch_screen( - device_configuration::DeviceConfigurationProto_TouchScreen:: - DeviceConfigurationProto_TouchScreen_NOTOUCH); - } else if (!HasStylusInput()) { - device_config_.set_touch_screen( - device_configuration::DeviceConfigurationProto_TouchScreen:: - DeviceConfigurationProto_TouchScreen_FINGER); - } else { - device_config_.set_touch_screen( - device_configuration::DeviceConfigurationProto_TouchScreen:: - DeviceConfigurationProto_TouchScreen_STYLUS); - } - - if (!HasKeyboard()) { - device_config_.set_keyboard( - device_configuration::DeviceConfigurationProto_Keyboard:: - DeviceConfigurationProto_Keyboard_NOKEYS); - } else { - // TODO(rsgingerrs): Currently there is no straightforward way to determine - // whether it is a full keyboard or not. We assume it is safe to set it as - // QWERTY keyboard for this feature. - device_config_.set_keyboard( - device_configuration::DeviceConfigurationProto_Keyboard:: - DeviceConfigurationProto_Keyboard_QWERTY); - } - device_config_.set_has_hard_keyboard(HasHardKeyboard()); - - // TODO(rsgingerrs): There is no straightforward way to get this info. We - // assume it is safe to set it as no navigation. - device_config_.set_navigation( - device_configuration::DeviceConfigurationProto_Navigation:: - DeviceConfigurationProto_Navigation_NONAV); - device_config_.set_has_five_way_navigation(false); - - device_config_.set_gl_es_version(GetGLVersionInfo()); - - for (const base::StringPiece& gl_extension : GetGLExtensions()) { - if (!gl_extension.empty()) - device_config_.add_gl_extension(gl_extension.as_string()); - } -} - -void RecommendAppsFetcherImpl::StartAshRequest() { - cros_display_config_->GetDisplayUnitInfoList( - false /* single_unified */, - base::BindOnce(&RecommendAppsFetcherImpl::OnAshResponse, - weak_ptr_factory_.GetWeakPtr())); -} - -void RecommendAppsFetcherImpl::MaybeStartCompressAndEncodeProtoMessage() { - if (!ash_ready_ || !arc_features_ready_ || has_started_proto_processing_) - return; - - base::PostTaskWithTraitsAndReplyWithResult( - FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT}, - base::BindOnce(&CompressAndEncodeProtoMessageOnBlockingThread, - std::move(device_config_)), - base::BindOnce( - &RecommendAppsFetcherImpl::OnProtoMessageCompressedAndEncoded, - weak_ptr_factory_.GetWeakPtr())); - has_started_proto_processing_ = true; -} - -void RecommendAppsFetcherImpl::OnProtoMessageCompressedAndEncoded( - std::string encoded_device_configuration_proto) { - proto_compressed_and_encoded_ = true; - encoded_device_configuration_proto_ = encoded_device_configuration_proto; - StartDownload(); -} - -void RecommendAppsFetcherImpl::OnAshResponse( - std::vector<ash::mojom::DisplayUnitInfoPtr> all_displays_info) { - ash_ready_ = true; - - int screen_density = 0; - for (const ash::mojom::DisplayUnitInfoPtr& display_info : all_displays_info) { - if (base::NumberToString(display::Display::InternalDisplayId()) == - display_info->id) { - screen_density = display_info->dpi_x + display_info->dpi_y; - break; - } - } - device_config_.set_screen_density(screen_density); - - const int screen_width = GetScreenSize().width(); - const int screen_height = GetScreenSize().height(); - device_config_.set_screen_width(screen_width); - device_config_.set_screen_height(screen_height); - - const int screen_layout = - CalculateStableScreenLayout(screen_width, screen_height, screen_density); - device_config_.set_screen_layout(GetScreenLayoutSizeId(screen_layout)); - - MaybeStartCompressAndEncodeProtoMessage(); -} - -void RecommendAppsFetcherImpl::OnArcFeaturesRead( - base::Optional<arc::ArcFeatures> read_result) { - arc_features_ready_ = true; - - if (read_result != base::nullopt) { - for (const auto& feature : read_result.value().feature_map) { - device_config_.add_system_available_feature(feature.first); - } - - for (const auto& abi : GetCpuAbiList(read_result.value())) { - device_config_.add_native_platform(abi); - } - - play_store_version_ = read_result.value().play_store_version; - - android_sdk_version_ = GetAndroidSdkVersion(read_result.value()); - } - - MaybeStartCompressAndEncodeProtoMessage(); -} - -void RecommendAppsFetcherImpl::StartDownload() { - if (!proto_compressed_and_encoded_) - return; - - net::NetworkTrafficAnnotationTag traffic_annotation = - net::DefineNetworkTrafficAnnotation("play_recommended_apps_download", R"( - semantics { - sender: "ChromeOS Recommended Apps Screen" - description: - "Chrome OS downloads the recommended app list from Google Play API." - trigger: - "When user has accepted the ARC Terms of Service." - data: - "URL of the Google Play API." - destination: GOOGLE_OWNED_SERVICE - } - policy { - cookies_allowed: YES - cookie_store: "user" - setting: - "NA" - policy_exception_justification: - "Not implemented, considered not necessary." - })"); - - Profile* profile = ProfileManager::GetActiveUserProfile(); - - auto resource_request = std::make_unique<network::ResourceRequest>(); - resource_request->url = GURL(kGetAppListUrl); - resource_request->method = "GET"; - resource_request->load_flags = - net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE; - - resource_request->headers.SetHeader("X-DFE-Device-Config", - encoded_device_configuration_proto_); - resource_request->headers.SetHeader("X-DFE-Sdk-Version", - android_sdk_version_); - resource_request->headers.SetHeader("X-DFE-Chromesky-Client-Version", - play_store_version_); - - network::mojom::URLLoaderFactory* loader_factory = - content::BrowserContext::GetDefaultStoragePartition(profile) - ->GetURLLoaderFactoryForBrowserProcess() - .get(); - - start_time_ = base::TimeTicks::Now(); - app_list_loader_ = network::SimpleURLLoader::Create( - std::move(resource_request), traffic_annotation); - // Retry up to three times if network changes are detected during the - // download. - app_list_loader_->SetRetryOptions( - 3, network::SimpleURLLoader::RETRY_ON_NETWORK_CHANGE); - app_list_loader_->DownloadToString( - loader_factory, - base::BindOnce(&RecommendAppsFetcherImpl::OnDownloaded, - base::Unretained(this)), - kMaxDownloadBytes); - - // Abort the download attempt if it takes longer than one minute. - download_timer_.Start(FROM_HERE, kDownloadTimeOut, this, - &RecommendAppsFetcherImpl::OnDownloadTimeout); -} - -void RecommendAppsFetcherImpl::OnDownloadTimeout() { - // Destroy the fetcher, which will abort the download attempt. - app_list_loader_.reset(); - - RecordUmaDownloadTime(base::TimeTicks::Now() - start_time_); - - // Show an error message to the user. - if (view_) - view_->OnLoadError(); -} - -void RecommendAppsFetcherImpl::OnDownloaded( - std::unique_ptr<std::string> response_body) { - download_timer_.Stop(); - - RecordUmaDownloadTime(base::TimeTicks::Now() - start_time_); - - std::unique_ptr<network::SimpleURLLoader> loader(std::move(app_list_loader_)); - if (!view_) - return; - - int response_code = 0; - if (!loader->ResponseInfo() || !loader->ResponseInfo()->headers) { - view_->OnLoadError(); - return; - } - response_code = loader->ResponseInfo()->headers->response_code(); - RecordUmaResponseCode(response_code); - - // If the recommended app list could not be downloaded, show an error message - // to the user. - if (!response_body || response_body->empty()) { - view_->OnLoadError(); - return; - } - - // If the recommended app list were downloaded successfully, show them to - // the user. - // - // The response starts with a prefix ")]}'". This needs to be removed before - // further parsing. - RecordUmaResponseSize(response_body->size()); - constexpr base::StringPiece json_xss_prevention_prefix(")]}'"); - base::StringPiece response_body_json(*response_body); - if (response_body_json.starts_with(json_xss_prevention_prefix)) - response_body_json.remove_prefix(json_xss_prevention_prefix.length()); - base::Optional<base::Value> output = ParseResponse(response_body_json); - if (!output.has_value()) { - RecordUmaResponseAppCount(0); - view_->OnParseResponseError(); - return; - } - - view_->OnLoadSuccess(std::move(output.value())); -} - -void RecommendAppsFetcherImpl::Start() { - PopulateDeviceConfig(); - StartAshRequest(); - arc::ArcFeaturesParser::GetArcFeatures( - base::BindOnce(&RecommendAppsFetcherImpl::OnArcFeaturesRead, - weak_ptr_factory_.GetWeakPtr())); -} - -void RecommendAppsFetcherImpl::Retry() { - StartDownload(); -} - -base::Optional<base::Value> RecommendAppsFetcherImpl::ParseResponse( - base::StringPiece response) { - base::Value output(base::Value::Type::LIST); - - int error_code; - std::string error_msg; - std::unique_ptr<base::Value> json_value = - base::JSONReader::ReadAndReturnErrorDeprecated( - response, base::JSON_PARSE_RFC, &error_code, &error_msg); - - if (!json_value || (!json_value->is_list() && !json_value->is_dict())) { - LOG(ERROR) << "Error parsing response JSON: " << error_msg; - RecordUmaResponseParseResult( - RECOMMEND_APPS_RESPONSE_PARSE_RESULT_INVALID_JSON); - return base::nullopt; - } - - // If the response is a dictionary, it is an error message in the - // following format: - // {"Error code":"error code","Error message":"Error message"} - if (json_value->is_dict()) { - const base::Value* response_error_code_value = - json_value->FindKeyOfType("Error code", base::Value::Type::STRING); - - if (!response_error_code_value) { - LOG(ERROR) << "Unable to find error code: response=" - << response.substr(0, 128); - RecordUmaResponseParseResult( - RECOMMEND_APPS_RESPONSE_PARSE_RESULT_INVALID_JSON); - return base::nullopt; - } - - base::StringPiece response_error_code_str = - response_error_code_value->GetString(); - int response_error_code = 0; - if (!base::StringToInt(response_error_code_str, &response_error_code)) { - LOG(WARNING) << "Unable to parse error code: " << response_error_code_str; - RecordUmaResponseParseResult( - RECOMMEND_APPS_RESPONSE_PARSE_RESULT_INVALID_ERROR_CODE); - return base::nullopt; - } - - if (response_error_code == kResponseErrorNotFirstTimeChromebookUser) { - RecordUmaResponseParseResult( - RECOMMEND_APPS_RESPONSE_PARSE_RESULT_OWNS_CHROMEBOOK_ALREADY); - } else if (response_error_code == kResponseErrorNotEnoughApps) { - RecordUmaResponseParseResult(RECOMMEND_APPS_RESPONSE_PARSE_RESULT_NO_APP); - } else { - LOG(WARNING) << "Unknown error code: " << response_error_code_str; - RecordUmaResponseParseResult( - RECOMMEND_APPS_RESPONSE_PARSE_RESULT_UNKNOWN_ERROR_CODE); - } - - return base::nullopt; - } - - // Otherwise, the response should return a list of apps. - const base::Value::ListStorage& app_list = json_value->GetList(); - if (app_list.empty()) { - DVLOG(1) << "No app in the response."; - RecordUmaResponseParseResult(RECOMMEND_APPS_RESPONSE_PARSE_RESULT_NO_APP); - return base::nullopt; - } - - for (auto& item : app_list) { - base::Value output_map(base::Value::Type::DICTIONARY); - - if (!item.is_dict()) { - DVLOG(1) << "Cannot parse item."; - continue; - } - - // Retrieve the app title. - const base::Value* title = - item.FindPathOfType({"title_", "name_"}, base::Value::Type::STRING); - if (title) - output_map.SetKey("name", base::Value(title->GetString())); - - // Retrieve the package name. - const base::Value* package_name = - item.FindPathOfType({"id_", "id_"}, base::Value::Type::STRING); - if (package_name) - output_map.SetKey("package_name", base::Value(package_name->GetString())); - - // Retrieve the icon URL for the app. - // - // The name "privateDoNotAccessOrElseSafeUrlWrappedValue_" here is because - // it is a direct serialization from the proto message. The value has been - // sanitized so it is regarded as a safe URL. In general, if the response is - // a protobuf, we should not directly access this field but use the wrapper - // method getSafeUrlString() to read it. In our case, we don't have the - // option other than access it directly. - const base::Value* icon_url = item.FindPathOfType( - {"icon_", "url_", "privateDoNotAccessOrElseSafeUrlWrappedValue_"}, - base::Value::Type::STRING); - if (icon_url) - output_map.SetKey("icon", base::Value(icon_url->GetString())); - - output.GetList().push_back(std::move(output_map)); - } - - RecordUmaResponseParseResult(RECOMMEND_APPS_RESPONSE_PARSE_RESULT_NO_ERROR); - RecordUmaResponseAppCount(static_cast<int>(output.GetList().size())); - - return output; -} - -} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/screens/recommend_apps/recommend_apps_fetcher_impl.h b/chrome/browser/chromeos/login/screens/recommend_apps/recommend_apps_fetcher_impl.h deleted file mode 100644 index 7c51c1f..0000000 --- a/chrome/browser/chromeos/login/screens/recommend_apps/recommend_apps_fetcher_impl.h +++ /dev/null
@@ -1,142 +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. - -#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_RECOMMEND_APPS_RECOMMEND_APPS_FETCHER_IMPL_H_ -#define CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_RECOMMEND_APPS_RECOMMEND_APPS_FETCHER_IMPL_H_ - -#include <memory> -#include <string> -#include <vector> - -#include "ash/public/interfaces/cros_display_config.mojom.h" -#include "base/callback.h" -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "base/timer/timer.h" -#include "chrome/browser/chromeos/login/screens/recommend_apps/device_configuration.pb.h" -#include "chrome/browser/chromeos/login/screens/recommend_apps/recommend_apps_fetcher.h" -#include "chrome/browser/chromeos/login/screens/recommend_apps_screen_view.h" -#include "components/arc/arc_features_parser.h" -#include "extensions/browser/api/system_display/display_info_provider.h" - -namespace network { -class SimpleURLLoader; -} - -namespace chromeos { - -// This class handles the network request for the Recommend Apps screen. It is -// supposed to run on the UI thread. The request requires the following headers: -// 1. X-Device-Config -// 2. X-Sdk-Version -// Play requires Android device config information to filter apps. -// device_configuration.proto is used to encode all the info. The following -// fields will be retrieved and sent: -// 1. touch_screen -// 2. keyboard -// 3. navigation -// 4. screen_layout -// 5. has_hard_keyboard -// 6. has_five_way_navigation -// 7. screen_density -// 8. screen_width -// 9. screen_height -// 10. gl_es_version -// 11. system_available_feature -// 12. native_platform -// 13. gl_extension -class RecommendAppsFetcherImpl : public RecommendAppsFetcher { - public: - explicit RecommendAppsFetcherImpl(RecommendAppsScreenView* view); - ~RecommendAppsFetcherImpl() override; - - // Provide a retry method to download the app list again. - // RecommendAppsFetcher: - void Start() override; - void Retry() override; - - private: - // Populate the required device config info. - void PopulateDeviceConfig(); - - // Start the connection to ash. Send the request to get display unit info - // list. - void StartAshRequest(); - - // Start to compress and encode the proto message if we finish ash request - // and ARC feature is read. - void MaybeStartCompressAndEncodeProtoMessage(); - - // Callback function called when display unit info list is retrieved from ash. - // It will populate the device config info related to the screen density. - void OnAshResponse( - std::vector<ash::mojom::DisplayUnitInfoPtr> all_displays_info); - - // Callback function called when ARC features are read by the parser. - // It will populate the device config info related to ARC features. - void OnArcFeaturesRead(base::Optional<arc::ArcFeatures> read_result); - - // Callback function called when the proto message has been compressed and - // encoded. - void OnProtoMessageCompressedAndEncoded( - std::string encoded_device_configuration_proto); - - // Start downloading the recommended app list. - void StartDownload(); - - // Abort the attempt to download the recommended app list if it takes too - // long. - void OnDownloadTimeout(); - - // Callback function called when SimpleURLLoader completes. - void OnDownloaded(std::unique_ptr<std::string> response_body); - - // If the response is not a valid JSON, return base::nullopt. - // If the response contains no app, return base::nullopt; - // Value output, in true, is a list containing: - // 1. name: the title of the app. - // 2. package_name - // 3. Possibly an Icon URL. - // Parses an input string that looks somewhat like this: - // [{"title_" : {"name_" : {title of app"}}, - // "id_" : {"id_" : {com.package.name"}}, - // "icon_": {"url_": {"privateDoNotAccessOrElseSafeUrlWrappedValue_": - // "http://icon_url.com/url"}}}, - // {"title_" : "title of second app", - // "packageName_": "second package name.", - // }] - base::Optional<base::Value> ParseResponse(base::StringPiece response); - - device_configuration::DeviceConfigurationProto device_config_; - - std::string android_sdk_version_; - - std::string play_store_version_; - - std::string encoded_device_configuration_proto_; - - bool ash_ready_ = false; - bool arc_features_ready_ = false; - bool has_started_proto_processing_ = false; - bool proto_compressed_and_encoded_ = false; - - RecommendAppsScreenView* view_; - - std::unique_ptr<network::SimpleURLLoader> app_list_loader_; - - // Timer that enforces a custom (shorter) timeout on the attempt to download - // the recommended app list. - base::OneShotTimer download_timer_; - - base::TimeTicks start_time_; - - ash::mojom::CrosDisplayConfigControllerPtr cros_display_config_; - base::WeakPtrFactory<RecommendAppsFetcherImpl> weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(RecommendAppsFetcherImpl); -}; - -} // namespace chromeos - -#endif // CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_RECOMMEND_APPS_RECOMMEND_APPS_FETCHER_IMPL_H_
diff --git a/chrome/browser/chromeos/login/screens/recommend_apps_screen.cc b/chrome/browser/chromeos/login/screens/recommend_apps_screen.cc index cc71080..026bad3 100644 --- a/chrome/browser/chromeos/login/screens/recommend_apps_screen.cc +++ b/chrome/browser/chromeos/login/screens/recommend_apps_screen.cc
@@ -4,8 +4,6 @@ #include "chrome/browser/chromeos/login/screens/recommend_apps_screen.h" -#include "chrome/browser/chromeos/login/screens/recommend_apps/recommend_apps_fetcher.h" - namespace chromeos { RecommendAppsScreen::RecommendAppsScreen( @@ -30,8 +28,7 @@ void RecommendAppsScreen::Show() { view_->Show(); - recommend_apps_fetcher_ = RecommendAppsFetcher::Create(view_); - recommend_apps_fetcher_->Start(); + recommend_apps_fetcher_ = std::make_unique<RecommendAppsFetcher>(view_); } void RecommendAppsScreen::Hide() {
diff --git a/chrome/browser/chromeos/login/screens/recommend_apps_screen.h b/chrome/browser/chromeos/login/screens/recommend_apps_screen.h index 252ac1dc3..9d7af0b 100644 --- a/chrome/browser/chromeos/login/screens/recommend_apps_screen.h +++ b/chrome/browser/chromeos/login/screens/recommend_apps_screen.h
@@ -11,12 +11,11 @@ #include "base/callback.h" #include "base/macros.h" #include "chrome/browser/chromeos/login/screens/base_screen.h" +#include "chrome/browser/chromeos/login/screens/recommend_apps/recommend_apps_fetcher.h" #include "chrome/browser/chromeos/login/screens/recommend_apps_screen_view.h" namespace chromeos { -class RecommendAppsFetcher; - // This is Recommend Apps screen that is displayed as a part of user first // sign-in flow. class RecommendAppsScreen : public BaseScreen,
diff --git a/chrome/browser/chromeos/login/screens/recommend_apps_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/recommend_apps_screen_browsertest.cc deleted file mode 100644 index a84684a..0000000 --- a/chrome/browser/chromeos/login/screens/recommend_apps_screen_browsertest.cc +++ /dev/null
@@ -1,703 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/chromeos/login/screens/recommend_apps_screen.h" - -#include <memory> -#include <vector> - -#include "base/bind.h" -#include "base/run_loop.h" -#include "base/strings/string_piece.h" -#include "base/strings/stringprintf.h" -#include "base/values.h" -#include "chrome/browser/chromeos/login/login_wizard.h" -#include "chrome/browser/chromeos/login/mixin_based_in_process_browser_test.h" -#include "chrome/browser/chromeos/login/oobe_screen.h" -#include "chrome/browser/chromeos/login/screens/recommend_apps/recommend_apps_fetcher.h" -#include "chrome/browser/chromeos/login/test/js_checker.h" -#include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h" -#include "chrome/browser/chromeos/login/ui/login_display_host.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_manager.h" -#include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h" -#include "components/arc/arc_prefs.h" -#include "components/prefs/pref_service.h" -#include "content/public/test/browser_test_utils.h" - -namespace chromeos { - -namespace { - -chromeos::OobeUI* GetOobeUI() { - auto* host = chromeos::LoginDisplayHost::default_host(); - return host ? host->GetOobeUI() : nullptr; -} - -struct FakeAppInfo { - public: - FakeAppInfo(const std::string& id, - const std::string& package_name, - const std::string& name) - : id(id), package_name(package_name), name(name) {} - ~FakeAppInfo() = default; - - base::Value ToValue() const { - base::Value result(base::Value::Type::DICTIONARY); - result.SetKey("id", base::Value(id)); - result.SetKey("package_name", base::Value(package_name)); - result.SetKey("name", base::Value(name)); - return result; - } - - const std::string id; - const std::string package_name; - const std::string name; -}; - -class FakeRecommendAppsFetcher : public RecommendAppsFetcher { - public: - explicit FakeRecommendAppsFetcher(RecommendAppsScreenView* view) - : view_(view) {} - ~FakeRecommendAppsFetcher() override = default; - - bool started() const { return started_; } - int retries() const { return retries_; } - - void SimulateSuccess(const std::vector<FakeAppInfo>& apps) { - EXPECT_TRUE(started_); - base::Value app_list(base::Value::Type::LIST); - for (const auto& app : apps) { - app_list.GetList().emplace_back(app.ToValue()); - } - view_->OnLoadSuccess(app_list); - } - - void SimulateParseError() { - EXPECT_TRUE(started_); - view_->OnParseResponseError(); - } - - void SimulateLoadError() { - EXPECT_TRUE(started_); - view_->OnLoadError(); - } - - // RecommendAppsFetcher: - void Start() override { - EXPECT_FALSE(started_); - started_ = true; - } - void Retry() override { - EXPECT_TRUE(started_); - ++retries_; - } - - private: - RecommendAppsScreenView* const view_; - bool started_ = false; - int retries_ = 0; -}; -} // namespace - -class RecommendAppsScreenTest : public InProcessBrowserTest { - public: - RecommendAppsScreenTest() = default; - ~RecommendAppsScreenTest() override = default; - - void SetUpOnMainThread() override { - ShowLoginWizard(OobeScreen::SCREEN_TEST_NO_WINDOW); - - fetcher_factory_callback_ = base::BindRepeating( - &RecommendAppsScreenTest::CreateRecommendAppsFetcher, - base::Unretained(this)); - RecommendAppsFetcher::SetFactoryCallbackForTesting( - &fetcher_factory_callback_); - - recommend_apps_screen_ = std::make_unique<RecommendAppsScreen>( - GetOobeUI()->GetRecommendAppsScreenView(), - base::BindRepeating(&RecommendAppsScreenTest::HandleScreenExit, - base::Unretained(this))); - - InProcessBrowserTest::SetUpOnMainThread(); - } - void TearDownOnMainThread() override { - RecommendAppsFetcher::SetFactoryCallbackForTesting(nullptr); - fetcher_factory_callback_.Reset(); - recommend_apps_fetcher_ = nullptr; - - InProcessBrowserTest::TearDownOnMainThread(); - } - - void WaitForScreenExit() { - if (screen_result_.has_value()) - return; - base::RunLoop run_loop; - screen_exit_callback_ = run_loop.QuitClosure(); - run_loop.Run(); - } - - bool WaitForAppListSize(const std::string& webview_path, int app_count) { - std::string count_apps_script = - "Array.from(document.getElementById('recommend-apps-container')" - " .querySelectorAll('.item'))" - " .map(i => i.getAttribute('data-packagename'));"; - - std::string script = base::StringPrintf( - "(function() {" - " var getAppCount = function() {" - " %s.executeScript({code: \"%s\"}, r => {" - " if (!r || !r[0] || r[0].length !== %d) {" - " setTimeout(getAppCount, 50);" - " return;" - " }" - " console.error('send DONE');" - " window.domAutomationController.send(true);" - " });" - " };" - " getAppCount();" - "})();", - webview_path.c_str(), count_apps_script.c_str(), app_count); - - // Wait for some apps to be shown - bool result; - return content::ExecuteScriptAndExtractBool( - LoginDisplayHost::default_host()->GetOobeWebContents(), script, - &result) && - result; - } - - // Simulates click on the apps in the webview's app list. - // The apps are expected to be passed in as a JavaScript array string. - // For example ['app_package_name1', 'app_package_name_2'] - bool ToggleAppsSelection(const std::string& webview_path, - const std::string& package_names) { - std::string toggle_apps_script = base::StringPrintf( - "Array.from(document.getElementById('recommend-apps-container')" - " .querySelectorAll('.item'))" - " .filter(i => %s.includes(i.getAttribute('data-packagename')))" - " .forEach(i => i.querySelector('.image-picker').click());", - package_names.c_str()); - - std::string script = base::StringPrintf( - "(function() {" - " %s.executeScript({code: \"%s\"}," - " r => window.domAutomationController.send(true));" - "})();", - webview_path.c_str(), toggle_apps_script.c_str()); - - bool result; - return content::ExecuteScriptAndExtractBool( - LoginDisplayHost::default_host()->GetOobeWebContents(), script, - &result) && - result; - } - - std::unique_ptr<RecommendAppsScreen> recommend_apps_screen_; - base::Optional<RecommendAppsScreen::Result> screen_result_; - FakeRecommendAppsFetcher* recommend_apps_fetcher_ = nullptr; - - private: - void HandleScreenExit(RecommendAppsScreen::Result result) { - ASSERT_FALSE(screen_result_.has_value()); - screen_result_ = result; - if (screen_exit_callback_) - std::move(screen_exit_callback_).Run(); - } - - std::unique_ptr<RecommendAppsFetcher> CreateRecommendAppsFetcher( - RecommendAppsScreenView* view) { - EXPECT_EQ(view, GetOobeUI()->GetRecommendAppsScreenView()); - EXPECT_FALSE(recommend_apps_fetcher_); - - auto fetcher = std::make_unique<FakeRecommendAppsFetcher>(view); - recommend_apps_fetcher_ = fetcher.get(); - return fetcher; - } - - // The callback passed to - // RecommendAppsFetcher::SetFactoryCallbackForTesting(). Bound to - // CreateRecommendAppsFetcher(). - RecommendAppsFetcher::FactoryCallback fetcher_factory_callback_; - - base::OnceClosure screen_exit_callback_; -}; - -IN_PROC_BROWSER_TEST_F(RecommendAppsScreenTest, BasicSelection) { - recommend_apps_screen_->Show(); - - OobeScreenWaiter screen_waiter(OobeScreen::SCREEN_RECOMMEND_APPS); - screen_waiter.set_assert_next_screen(); - screen_waiter.Wait(); - - // Wait for loading screen. - test::OobeJS().CreateVisibilityWaiter(true, {"recommend-apps-loading"}); - test::OobeJS().ExpectHidden("recommend-apps-screen"); - - std::vector<FakeAppInfo> test_apps = { - FakeAppInfo("test_app_1", "test.app.foo.app1", "Test app 1"), - FakeAppInfo("test_app_2", "test.app.foo.app2", "Test app 2"), - FakeAppInfo("test_app_3", "test.app.foo.app3", "Test app 3")}; - recommend_apps_fetcher_->SimulateSuccess(test_apps); - - test::OobeJS().CreateVisibilityWaiter(true, {"recommend-apps-screen"}); - test::OobeJS().ExpectHidden("recommend-apps-loading"); - - const std::string webview_path = - test::GetOobeElementPath({"recommend-apps-screen", "app-list-view"}); - const std::initializer_list<base::StringPiece> install_button = { - "recommend-apps-screen", "recommend-apps-install-button"}; - const std::initializer_list<base::StringPiece> skip_button = { - "recommend-apps-screen", "recommend-apps-skip-button"}; - const std::initializer_list<base::StringPiece> retry_button = { - "recommend-apps-screen", "recommend-apps-retry-button"}; - - test::OobeJS().ExpectDisabledPath(install_button); - - test::OobeJS() - .CreateDisplayedWaiter(true, {"recommend-apps-screen", "app-list-view"}) - ->Wait(); - ASSERT_TRUE(WaitForAppListSize(webview_path, test_apps.size())); - - test::OobeJS().ExpectPathDisplayed(true, install_button); - test::OobeJS().ExpectDisabledPath(install_button); - test::OobeJS().ExpectPathDisplayed(true, skip_button); - test::OobeJS().ExpectEnabledPath(skip_button); - test::OobeJS().ExpectPathDisplayed(false, retry_button); - - ASSERT_TRUE(ToggleAppsSelection( - webview_path, "['test.app.foo.app1', 'test.app.foo.app2']")); - - test::OobeJS().CreateEnabledWaiter(true, install_button)->Wait(); - test::OobeJS().ExpectEnabledPath(skip_button); - test::OobeJS().ExpectPathDisplayed(false, retry_button); - - test::OobeJS().TapOnPath(install_button); - - WaitForScreenExit(); - EXPECT_EQ(RecommendAppsScreen::Result::SELECTED, screen_result_.value()); - - EXPECT_EQ(0, recommend_apps_fetcher_->retries()); - - const base::Value* fast_reinstall_packages = - ProfileManager::GetActiveUserProfile()->GetPrefs()->Get( - arc::prefs::kArcFastAppReinstallPackages); - ASSERT_TRUE(fast_reinstall_packages); - - base::Value expected_pref_value(base::Value::Type::LIST); - expected_pref_value.GetList().emplace_back("test.app.foo.app1"); - expected_pref_value.GetList().emplace_back("test.app.foo.app2"); - EXPECT_EQ(expected_pref_value, *fast_reinstall_packages); -} - -IN_PROC_BROWSER_TEST_F(RecommendAppsScreenTest, SelectionChange) { - recommend_apps_screen_->Show(); - - OobeScreenWaiter screen_waiter(OobeScreen::SCREEN_RECOMMEND_APPS); - screen_waiter.set_assert_next_screen(); - screen_waiter.Wait(); - - // Wait for loading screen. - test::OobeJS().CreateVisibilityWaiter(true, {"recommend-apps-loading"}); - test::OobeJS().ExpectHidden("recommend-apps-screen"); - - std::vector<FakeAppInfo> test_apps = { - FakeAppInfo("test_app_1", "test.app.foo.app1", "Test app 1"), - FakeAppInfo("test_app_2", "test.app.foo.app2", "Test app 2"), - FakeAppInfo("test_app_3", "test.app.foo.app3", "Test app 3")}; - recommend_apps_fetcher_->SimulateSuccess(test_apps); - - test::OobeJS().CreateVisibilityWaiter(true, {"recommend-apps-screen"}); - test::OobeJS().ExpectHidden("recommend-apps-loading"); - - const std::string webview_path = - test::GetOobeElementPath({"recommend-apps-screen", "app-list-view"}); - const std::initializer_list<base::StringPiece> install_button = { - "recommend-apps-screen", "recommend-apps-install-button"}; - const std::initializer_list<base::StringPiece> skip_button = { - "recommend-apps-screen", "recommend-apps-skip-button"}; - const std::initializer_list<base::StringPiece> retry_button = { - "recommend-apps-screen", "recommend-apps-retry-button"}; - - test::OobeJS().ExpectDisabledPath(install_button); - - test::OobeJS() - .CreateDisplayedWaiter(true, {"recommend-apps-screen", "app-list-view"}) - ->Wait(); - ASSERT_TRUE(WaitForAppListSize(webview_path, test_apps.size())); - - test::OobeJS().ExpectPathDisplayed(true, install_button); - test::OobeJS().ExpectDisabledPath(install_button); - test::OobeJS().ExpectPathDisplayed(true, skip_button); - test::OobeJS().ExpectEnabledPath(skip_button); - test::OobeJS().ExpectPathDisplayed(false, retry_button); - - ASSERT_TRUE(ToggleAppsSelection( - webview_path, "['test.app.foo.app1', 'test.app.foo.app2']")); - - test::OobeJS().CreateEnabledWaiter(true, install_button)->Wait(); - test::OobeJS().ExpectEnabledPath(skip_button); - test::OobeJS().ExpectPathDisplayed(false, retry_button); - - ASSERT_TRUE(ToggleAppsSelection(webview_path, "['test.app.foo.app1']")); - - test::OobeJS().TapOnPath(install_button); - - WaitForScreenExit(); - EXPECT_EQ(RecommendAppsScreen::Result::SELECTED, screen_result_.value()); - - EXPECT_EQ(0, recommend_apps_fetcher_->retries()); - - const base::Value* fast_reinstall_packages = - ProfileManager::GetActiveUserProfile()->GetPrefs()->Get( - arc::prefs::kArcFastAppReinstallPackages); - ASSERT_TRUE(fast_reinstall_packages); - - base::Value expected_pref_value(base::Value::Type::LIST); - expected_pref_value.GetList().emplace_back("test.app.foo.app2"); - EXPECT_EQ(expected_pref_value, *fast_reinstall_packages); -} - -IN_PROC_BROWSER_TEST_F(RecommendAppsScreenTest, SkipWithSelectedApps) { - recommend_apps_screen_->Show(); - - OobeScreenWaiter screen_waiter(OobeScreen::SCREEN_RECOMMEND_APPS); - screen_waiter.set_assert_next_screen(); - screen_waiter.Wait(); - - // Wait for loading screen. - test::OobeJS().CreateVisibilityWaiter(true, {"recommend-apps-loading"}); - test::OobeJS().ExpectHidden("recommend-apps-screen"); - - std::vector<FakeAppInfo> test_apps = { - FakeAppInfo("test_app_1", "test.app.foo.app1", "Test app 1"), - FakeAppInfo("test_app_2", "test.app.foo.app2", "Test app 2"), - FakeAppInfo("test_app_3", "test.app.foo.app3", "Test app 3")}; - recommend_apps_fetcher_->SimulateSuccess(test_apps); - - test::OobeJS().CreateVisibilityWaiter(true, {"recommend-apps-screen"}); - test::OobeJS().ExpectHidden("recommend-apps-loading"); - - const std::string webview_path = - test::GetOobeElementPath({"recommend-apps-screen", "app-list-view"}); - const std::initializer_list<base::StringPiece> install_button = { - "recommend-apps-screen", "recommend-apps-install-button"}; - const std::initializer_list<base::StringPiece> skip_button = { - "recommend-apps-screen", "recommend-apps-skip-button"}; - const std::initializer_list<base::StringPiece> retry_button = { - "recommend-apps-screen", "recommend-apps-retry-button"}; - - test::OobeJS().ExpectDisabledPath(install_button); - - test::OobeJS() - .CreateDisplayedWaiter(true, {"recommend-apps-screen", "app-list-view"}) - ->Wait(); - ASSERT_TRUE(WaitForAppListSize(webview_path, test_apps.size())); - - test::OobeJS().ExpectPathDisplayed(true, install_button); - test::OobeJS().ExpectDisabledPath(install_button); - test::OobeJS().ExpectPathDisplayed(true, skip_button); - test::OobeJS().ExpectEnabledPath(skip_button); - test::OobeJS().ExpectPathDisplayed(false, retry_button); - - ASSERT_TRUE(ToggleAppsSelection(webview_path, "['test.app.foo.app2']")); - - test::OobeJS().CreateEnabledWaiter(true, install_button)->Wait(); - test::OobeJS().ExpectEnabledPath(skip_button); - test::OobeJS().ExpectPathDisplayed(false, retry_button); - - test::OobeJS().TapOnPath(skip_button); - - WaitForScreenExit(); - EXPECT_EQ(RecommendAppsScreen::Result::SKIPPED, screen_result_.value()); - - EXPECT_EQ(0, recommend_apps_fetcher_->retries()); - - const base::Value* fast_reinstall_packages = - ProfileManager::GetActiveUserProfile()->GetPrefs()->Get( - arc::prefs::kArcFastAppReinstallPackages); - ASSERT_TRUE(fast_reinstall_packages); - EXPECT_EQ(base::Value(base::Value::Type::LIST), *fast_reinstall_packages); -} - -IN_PROC_BROWSER_TEST_F(RecommendAppsScreenTest, SkipWithNoAppsSelected) { - recommend_apps_screen_->Show(); - - OobeScreenWaiter screen_waiter(OobeScreen::SCREEN_RECOMMEND_APPS); - screen_waiter.set_assert_next_screen(); - screen_waiter.Wait(); - - // Wait for loading screen. - test::OobeJS().CreateVisibilityWaiter(true, {"recommend-apps-loading"}); - test::OobeJS().ExpectHidden("recommend-apps-screen"); - - std::vector<FakeAppInfo> test_apps = { - FakeAppInfo("test_app_1", "test.app.foo.app1", "Test app 1"), - FakeAppInfo("test_app_2", "test.app.foo.app2", "Test app 2"), - FakeAppInfo("test_app_3", "test.app.foo.app3", "Test app 3")}; - recommend_apps_fetcher_->SimulateSuccess(test_apps); - - test::OobeJS().CreateVisibilityWaiter(true, {"recommend-apps-screen"}); - test::OobeJS().ExpectHidden("recommend-apps-loading"); - - const std::string webview_path = - test::GetOobeElementPath({"recommend-apps-screen", "app-list-view"}); - const std::initializer_list<base::StringPiece> install_button = { - "recommend-apps-screen", "recommend-apps-install-button"}; - const std::initializer_list<base::StringPiece> skip_button = { - "recommend-apps-screen", "recommend-apps-skip-button"}; - const std::initializer_list<base::StringPiece> retry_button = { - "recommend-apps-screen", "recommend-apps-retry-button"}; - - test::OobeJS().ExpectDisabledPath(install_button); - - test::OobeJS() - .CreateDisplayedWaiter(true, {"recommend-apps-screen", "app-list-view"}) - ->Wait(); - ASSERT_TRUE(WaitForAppListSize(webview_path, test_apps.size())); - - test::OobeJS().ExpectPathDisplayed(true, install_button); - test::OobeJS().ExpectDisabledPath(install_button); - test::OobeJS().ExpectPathDisplayed(true, skip_button); - test::OobeJS().ExpectEnabledPath(skip_button); - test::OobeJS().ExpectPathDisplayed(false, retry_button); - - ASSERT_TRUE(ToggleAppsSelection(webview_path, "['test.app.foo.app2']")); - - test::OobeJS().CreateEnabledWaiter(true, install_button)->Wait(); - test::OobeJS().ExpectEnabledPath(skip_button); - test::OobeJS().ExpectPathDisplayed(false, retry_button); - - ASSERT_TRUE(ToggleAppsSelection(webview_path, "['test.app.foo.app2']")); - - test::OobeJS().CreateEnabledWaiter(false, install_button)->Wait(); - test::OobeJS().ExpectEnabledPath(skip_button); - test::OobeJS().ExpectPathDisplayed(false, retry_button); - - test::OobeJS().TapOnPath(skip_button); - - WaitForScreenExit(); - EXPECT_EQ(RecommendAppsScreen::Result::SKIPPED, screen_result_.value()); - - EXPECT_EQ(0, recommend_apps_fetcher_->retries()); - - const base::Value* fast_reinstall_packages = - ProfileManager::GetActiveUserProfile()->GetPrefs()->Get( - arc::prefs::kArcFastAppReinstallPackages); - ASSERT_TRUE(fast_reinstall_packages); - EXPECT_EQ(base::Value(base::Value::Type::LIST), *fast_reinstall_packages); -} - -IN_PROC_BROWSER_TEST_F(RecommendAppsScreenTest, InstallWithNoAppsSelected) { - recommend_apps_screen_->Show(); - - OobeScreenWaiter screen_waiter(OobeScreen::SCREEN_RECOMMEND_APPS); - screen_waiter.set_assert_next_screen(); - screen_waiter.Wait(); - - // Wait for loading screen. - test::OobeJS().CreateVisibilityWaiter(true, {"recommend-apps-loading"}); - test::OobeJS().ExpectHidden("recommend-apps-screen"); - - std::vector<FakeAppInfo> test_apps = { - FakeAppInfo("test_app_1", "test.app.foo.app1", "Test app 1")}; - recommend_apps_fetcher_->SimulateSuccess(test_apps); - - test::OobeJS().CreateVisibilityWaiter(true, {"recommend-apps-screen"}); - test::OobeJS().ExpectHidden("recommend-apps-loading"); - - const std::string webview_path = - test::GetOobeElementPath({"recommend-apps-screen", "app-list-view"}); - test::OobeJS() - .CreateDisplayedWaiter(true, {"recommend-apps-screen", "app-list-view"}) - ->Wait(); - ASSERT_TRUE(WaitForAppListSize(webview_path, test_apps.size())); - - // The install button is expected to be disabled at this point. Send empty app - // list directly to test handler behavior when install is triggered with no - // apps selected. - test::OobeJS().Evaluate("chrome.send('recommendAppsInstall', []);"); - - WaitForScreenExit(); - EXPECT_EQ(RecommendAppsScreen::Result::SKIPPED, screen_result_.value()); - - EXPECT_EQ(0, recommend_apps_fetcher_->retries()); - - const base::Value* fast_reinstall_packages = - ProfileManager::GetActiveUserProfile()->GetPrefs()->Get( - arc::prefs::kArcFastAppReinstallPackages); - ASSERT_TRUE(fast_reinstall_packages); - EXPECT_EQ(base::Value(base::Value::Type::LIST), *fast_reinstall_packages); -} - -IN_PROC_BROWSER_TEST_F(RecommendAppsScreenTest, NoRecommendedApps) { - recommend_apps_screen_->Show(); - - OobeScreenWaiter screen_waiter(OobeScreen::SCREEN_RECOMMEND_APPS); - screen_waiter.set_assert_next_screen(); - screen_waiter.Wait(); - - // Wait for loading screen. - test::OobeJS().CreateVisibilityWaiter(true, {"recommend-apps-loading"}); - test::OobeJS().ExpectHidden("recommend-apps-screen"); - - recommend_apps_fetcher_->SimulateSuccess(std::vector<FakeAppInfo>()); - - test::OobeJS().CreateVisibilityWaiter(true, {"recommend-apps-screen"}); - test::OobeJS().ExpectHidden("recommend-apps-loading"); - - const std::initializer_list<base::StringPiece> install_button = { - "recommend-apps-screen", "recommend-apps-install-button"}; - const std::initializer_list<base::StringPiece> skip_button = { - "recommend-apps-screen", "recommend-apps-skip-button"}; - const std::initializer_list<base::StringPiece> retry_button = { - "recommend-apps-screen", "recommend-apps-retry-button"}; - - test::OobeJS().CreateDisplayedWaiter(true, skip_button)->Wait(); - test::OobeJS().ExpectEnabledPath(skip_button); - test::OobeJS().ExpectPathDisplayed(false, install_button); - test::OobeJS().ExpectPathDisplayed(false, retry_button); - test::OobeJS().ExpectPathDisplayed(false, retry_button); - - test::OobeJS().TapOnPath(skip_button); - - WaitForScreenExit(); - EXPECT_EQ(RecommendAppsScreen::Result::SKIPPED, screen_result_.value()); - - EXPECT_EQ(0, recommend_apps_fetcher_->retries()); - - const base::Value* fast_reinstall_packages = - ProfileManager::GetActiveUserProfile()->GetPrefs()->Get( - arc::prefs::kArcFastAppReinstallPackages); - ASSERT_TRUE(fast_reinstall_packages); - EXPECT_EQ(base::Value(base::Value::Type::LIST), *fast_reinstall_packages); -} - -IN_PROC_BROWSER_TEST_F(RecommendAppsScreenTest, ParseError) { - recommend_apps_screen_->Show(); - - OobeScreenWaiter screen_waiter(OobeScreen::SCREEN_RECOMMEND_APPS); - screen_waiter.set_assert_next_screen(); - screen_waiter.Wait(); - - // Wait for loading screen. - test::OobeJS().CreateVisibilityWaiter(true, {"recommend-apps-loading"}); - test::OobeJS().ExpectHidden("recommend-apps-screen"); - - recommend_apps_fetcher_->SimulateParseError(); - - ASSERT_TRUE(screen_result_.has_value()); - EXPECT_EQ(RecommendAppsScreen::Result::SKIPPED, screen_result_.value()); - EXPECT_EQ(0, recommend_apps_fetcher_->retries()); -} - -IN_PROC_BROWSER_TEST_F(RecommendAppsScreenTest, SkipOnLoadError) { - recommend_apps_screen_->Show(); - - OobeScreenWaiter screen_waiter(OobeScreen::SCREEN_RECOMMEND_APPS); - screen_waiter.set_assert_next_screen(); - screen_waiter.Wait(); - - // Wait for loading screen. - test::OobeJS().CreateVisibilityWaiter(true, {"recommend-apps-loading"}); - test::OobeJS().ExpectHidden("recommend-apps-screen"); - - recommend_apps_fetcher_->SimulateLoadError(); - - test::OobeJS().CreateVisibilityWaiter(true, {"recommend-apps-screen"}); - test::OobeJS().ExpectHidden("recommend-apps-loading"); - - const std::initializer_list<base::StringPiece> install_button = { - "recommend-apps-screen", "recommend-apps-install-button"}; - const std::initializer_list<base::StringPiece> skip_button = { - "recommend-apps-screen", "recommend-apps-skip-button"}; - const std::initializer_list<base::StringPiece> retry_button = { - "recommend-apps-screen", "recommend-apps-retry-button"}; - - test::OobeJS().CreateDisplayedWaiter(true, skip_button)->Wait(); - test::OobeJS().ExpectEnabledPath(skip_button); - test::OobeJS().CreateDisplayedWaiter(true, retry_button)->Wait(); - test::OobeJS().ExpectEnabledPath(retry_button); - test::OobeJS().ExpectPathDisplayed(false, install_button); - - test::OobeJS().TapOnPath(skip_button); - - WaitForScreenExit(); - EXPECT_EQ(RecommendAppsScreen::Result::SKIPPED, screen_result_.value()); - EXPECT_EQ(0, recommend_apps_fetcher_->retries()); - - const base::Value* fast_reinstall_packages = - ProfileManager::GetActiveUserProfile()->GetPrefs()->Get( - arc::prefs::kArcFastAppReinstallPackages); - ASSERT_TRUE(fast_reinstall_packages); - EXPECT_EQ(base::Value(base::Value::Type::LIST), *fast_reinstall_packages); -} - -IN_PROC_BROWSER_TEST_F(RecommendAppsScreenTest, RetryOnLoadError) { - recommend_apps_screen_->Show(); - - OobeScreenWaiter screen_waiter(OobeScreen::SCREEN_RECOMMEND_APPS); - screen_waiter.set_assert_next_screen(); - screen_waiter.Wait(); - - // Wait for loading screen. - test::OobeJS().CreateVisibilityWaiter(true, {"recommend-apps-loading"}); - test::OobeJS().ExpectHidden("recommend-apps-screen"); - - recommend_apps_fetcher_->SimulateLoadError(); - - test::OobeJS().CreateVisibilityWaiter(true, {"recommend-apps-screen"}); - test::OobeJS().ExpectHidden("recommend-apps-loading"); - - const std::initializer_list<base::StringPiece> install_button = { - "recommend-apps-screen", "recommend-apps-install-button"}; - const std::initializer_list<base::StringPiece> skip_button = { - "recommend-apps-screen", "recommend-apps-skip-button"}; - const std::initializer_list<base::StringPiece> retry_button = { - "recommend-apps-screen", "recommend-apps-retry-button"}; - - test::OobeJS().CreateDisplayedWaiter(true, skip_button)->Wait(); - test::OobeJS().ExpectEnabledPath(skip_button); - test::OobeJS().CreateDisplayedWaiter(true, retry_button)->Wait(); - test::OobeJS().ExpectEnabledPath(retry_button); - test::OobeJS().ExpectPathDisplayed(false, install_button); - - test::OobeJS().TapOnPath(retry_button); - - EXPECT_EQ(1, recommend_apps_fetcher_->retries()); - - test::OobeJS().CreateVisibilityWaiter(false, {"recommend-apps-screen"}); - test::OobeJS().ExpectVisible("recommend-apps-loading"); - - std::vector<FakeAppInfo> test_apps = { - FakeAppInfo("test_app_1", "test.app.foo.app1", "Test app 1")}; - recommend_apps_fetcher_->SimulateSuccess(test_apps); - - test::OobeJS().CreateVisibilityWaiter(true, {"recommend-apps-screen"}); - test::OobeJS().ExpectHidden("recommend-apps-loading"); - - const std::string webview_path = - test::GetOobeElementPath({"recommend-apps-screen", "app-list-view"}); - test::OobeJS() - .CreateDisplayedWaiter(true, {"recommend-apps-screen", "app-list-view"}) - ->Wait(); - ASSERT_TRUE(WaitForAppListSize(webview_path, test_apps.size())); - - test::OobeJS().ExpectPathDisplayed(true, install_button); - test::OobeJS().ExpectDisabledPath(install_button); - test::OobeJS().ExpectPathDisplayed(true, skip_button); - test::OobeJS().ExpectEnabledPath(skip_button); - test::OobeJS().ExpectPathDisplayed(false, retry_button); - - EXPECT_FALSE(screen_result_.has_value()); - EXPECT_EQ(1, recommend_apps_fetcher_->retries()); - - const base::Value* fast_reinstall_packages = - ProfileManager::GetActiveUserProfile()->GetPrefs()->Get( - arc::prefs::kArcFastAppReinstallPackages); - ASSERT_TRUE(fast_reinstall_packages); - EXPECT_EQ(base::Value(base::Value::Type::LIST), *fast_reinstall_packages); -} - -} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/test/js_checker.cc b/chrome/browser/chromeos/login/test/js_checker.cc index 8382afa..58f2379c 100644 --- a/chrome/browser/chromeos/login/test/js_checker.cc +++ b/chrome/browser/chromeos/login/test/js_checker.cc
@@ -136,28 +136,6 @@ return CreateWaiter(js_condition); } -std::unique_ptr<TestConditionWaiter> JSChecker::CreateDisplayedWaiter( - bool displayed, - std::initializer_list<base::StringPiece> element_ids) { - const std::string element_path = GetOobeElementPath(element_ids); - std::string js_condition = element_path + ".offsetWidth > 0 && " + - element_path + ".offsetHeight > 0"; - if (!displayed) { - js_condition = "!(" + js_condition + ")"; - } - return CreateWaiter(js_condition); -} - -std::unique_ptr<TestConditionWaiter> JSChecker::CreateEnabledWaiter( - bool enabled, - std::initializer_list<base::StringPiece> element_ids) { - std::string js_condition = GetOobeElementPath(element_ids) + ".disabled"; - if (enabled) { - js_condition = "!(" + js_condition + ")"; - } - return CreateWaiter(js_condition); -} - void JSChecker::GetBoolImpl(const std::string& expression, bool* result) { CHECK(web_contents_); ASSERT_TRUE(content::ExecuteScriptAndExtractBool( @@ -202,28 +180,6 @@ ExpectHiddenPath({element_id}); } -void JSChecker::ExpectPathDisplayed( - bool displayed, - std::initializer_list<base::StringPiece> element_ids) { - const std::string element_path = GetOobeElementPath(element_ids); - std::string js_condition = element_path + ".offsetWidth > 0 && " + - element_path + ".offsetHeight > 0"; - if (!displayed) { - js_condition = "!(" + js_condition + ")"; - } - ExpectTrue(js_condition); -} - -void JSChecker::ExpectDisabledPath( - std::initializer_list<base::StringPiece> element_ids) { - ExpectTrue(GetOobeElementPath(element_ids) + ".disabled"); -} - -void JSChecker::ExpectEnabledPath( - std::initializer_list<base::StringPiece> element_ids) { - ExpectFalse(GetOobeElementPath(element_ids) + ".disabled"); -} - void JSChecker::ExpectHasClass( const std::string& css_class, std::initializer_list<base::StringPiece> element_ids) {
diff --git a/chrome/browser/chromeos/login/test/js_checker.h b/chrome/browser/chromeos/login/test/js_checker.h index 0db84970..6a289db 100644 --- a/chrome/browser/chromeos/login/test/js_checker.h +++ b/chrome/browser/chromeos/login/test/js_checker.h
@@ -65,42 +65,14 @@ bool visibility, std::initializer_list<base::StringPiece> element_ids); - // Waiter that waits until specified element is (not) displayed with non-zero - // size. - std::unique_ptr<TestConditionWaiter> CreateDisplayedWaiter( - bool displayed, - std::initializer_list<base::StringPiece> element_ids); - - // Waiter that waits until an element is enabled or disabled. - std::unique_ptr<TestConditionWaiter> CreateEnabledWaiter( - bool enabled, - std::initializer_list<base::StringPiece> element_ids); - // Expects that indicated UI element is not hidden. - // NOTE: This only checks hidden property - it might not work for elements - // hidden by "display: none" style. void ExpectVisiblePath(std::initializer_list<base::StringPiece> element_ids); void ExpectVisible(const std::string& element_id); // Expects that indicated UI element is hidden. - // NOTE: This only checks hidden property - it might not work for elements - // hidden by "display: none" style. void ExpectHiddenPath(std::initializer_list<base::StringPiece> element_ids); void ExpectHidden(const std::string& element_id); - // Expects that the element is displayed on screen - i.e. that it has non-null - // size. Unlike ExpectHidden and ExpectVisible methods, this will correctly - // elements with "display: none" style, but might not work for polymer module - // roots. - void ExpectPathDisplayed(bool displayed, - std::initializer_list<base::StringPiece> element_id); - - // Expects that the indicated UI element is disabled. - void ExpectDisabledPath(std::initializer_list<base::StringPiece> element_ids); - - // Expects that the indicated UI element is not disabled. - void ExpectEnabledPath(std::initializer_list<base::StringPiece> element_ids); - // Expects that indicated UI element has particular class. void ExpectHasClass(const std::string& css_class, std::initializer_list<base::StringPiece> element_ids);
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/adapter.cc b/chrome/browser/chromeos/power/auto_screen_brightness/adapter.cc index 69ef8c0..ca9cf9f 100644 --- a/chrome/browser/chromeos/power/auto_screen_brightness/adapter.cc +++ b/chrome/browser/chromeos/power/auto_screen_brightness/adapter.cc
@@ -56,38 +56,21 @@ ModelConfigLoader* model_config_loader, MetricsReporter* metrics_reporter, chromeos::PowerManagerClient* power_manager_client) - : profile_(profile), - als_reader_observer_(this), - brightness_monitor_observer_(this), - modeller_observer_(this), - model_config_loader_observer_(this), - power_manager_client_observer_(this), - metrics_reporter_(metrics_reporter), - power_manager_client_(power_manager_client), - tick_clock_(base::DefaultTickClock::GetInstance()), - weak_ptr_factory_(this) { - DCHECK(profile); - DCHECK(als_reader); - DCHECK(brightness_monitor); - DCHECK(modeller); - DCHECK(model_config_loader); - DCHECK(power_manager_client); - - als_reader_observer_.Add(als_reader); - brightness_monitor_observer_.Add(brightness_monitor); - modeller_observer_.Add(modeller); - model_config_loader_observer_.Add(model_config_loader); - power_manager_client_observer_.Add(power_manager_client); - - power_manager_client_->WaitForServiceToBeAvailable( - base::BindOnce(&Adapter::OnPowerManagerServiceAvailable, - weak_ptr_factory_.GetWeakPtr())); -} + : Adapter(profile, + als_reader, + brightness_monitor, + modeller, + model_config_loader, + metrics_reporter, + power_manager_client, + base::DefaultTickClock::GetInstance()) {} Adapter::~Adapter() = default; void Adapter::OnAmbientLightUpdated(int lux) { // Ambient light data is only used when adapter is initialized to success. + // |ambient_light_values_| may not be available to use when adapter is being + // initialized. if (adapter_status_ != Status::kSuccess) return; @@ -104,6 +87,7 @@ DCHECK(!als_init_status_); als_init_status_ = status; + als_init_time_ = tick_clock_->NowTicks(); UpdateStatus(); } @@ -116,14 +100,26 @@ void Adapter::OnUserBrightnessChanged(double old_brightness_percent, double new_brightness_percent) { + const base::TimeTicks now = tick_clock_->NowTicks(); // We skip this notification if adapter hasn't been initialised because its // |params_| may change. We need to log even if adapter is initialized to // disabled. if (adapter_status_ == Status::kInitializing) return; - // TODO(jiameng): record current average als and update thresholds. - current_brightness_ = new_brightness_percent; + // |latest_brightness_change_time_|, |current_brightness_|, + // |log_average_ambient_lux_| and thresholds are only needed if adapter is + // |kSuccess|. + if (adapter_status_ == Status::kSuccess) { + DCHECK(ambient_light_values_); + const base::Optional<AlsAvgStdDev> als_avg_stddev = + ambient_light_values_->AverageAmbientWithStdDev(now); + + OnBrightnessChanged(now, new_brightness_percent, + als_avg_stddev ? base::Optional<double>( + ConvertToLog(als_avg_stddev->avg)) + : base::nullopt); + } if (!metrics_reporter_) return; @@ -161,9 +157,10 @@ } void Adapter::OnUserBrightnessChangeRequested() { - // We skip this notification if adapter hasn't been initialised because its - // |params_| may change. - if (adapter_status_ == Status::kInitializing) + // We skip this notification if adapter hasn't been initialised (because its + // |params_| may change), or, if adapter is disabled (because adapter won't + // change brightness anyway). + if (adapter_status_ != Status::kSuccess) return; if (params_.user_adjustment_effect != UserAdjustmentEffect::kContinueAuto) { @@ -210,19 +207,16 @@ } void Adapter::SuspendDone(const base::TimeDelta& /* sleep_duration */) { - // We skip this notification if adapter hasn't been initialised because its - // |params_| may change. - if (adapter_status_ == Status::kInitializing) + // We skip this notification if adapter hasn't been initialised (because its + // |params_| may change), or, if adapter is disabled (because adapter won't + // change brightness anyway). + if (adapter_status_ != Status::kSuccess) return; if (params_.user_adjustment_effect == UserAdjustmentEffect::kPauseAuto) adapter_disabled_by_user_adjustment_ = false; } -void Adapter::SetTickClockForTesting(const base::TickClock* test_tick_clock) { - tick_clock_ = test_tick_clock; -} - Adapter::Status Adapter::GetStatusForTesting() const { return adapter_status_; } @@ -255,6 +249,60 @@ return *darkening_threshold_; } +base::Optional<double> Adapter::GetCurrentLogAvgAlsForTesting() const { + return log_average_ambient_lux_; +} + +std::unique_ptr<Adapter> Adapter::CreateForTesting( + Profile* profile, + AlsReader* als_reader, + BrightnessMonitor* brightness_monitor, + Modeller* modeller, + ModelConfigLoader* model_config_loader, + MetricsReporter* metrics_reporter, + chromeos::PowerManagerClient* power_manager_client, + const base::TickClock* tick_clock) { + return base::WrapUnique(new Adapter( + profile, als_reader, brightness_monitor, modeller, model_config_loader, + metrics_reporter, power_manager_client, tick_clock)); +} + +Adapter::Adapter(Profile* profile, + AlsReader* als_reader, + BrightnessMonitor* brightness_monitor, + Modeller* modeller, + ModelConfigLoader* model_config_loader, + MetricsReporter* metrics_reporter, + chromeos::PowerManagerClient* power_manager_client, + const base::TickClock* tick_clock) + : profile_(profile), + als_reader_observer_(this), + brightness_monitor_observer_(this), + modeller_observer_(this), + model_config_loader_observer_(this), + power_manager_client_observer_(this), + metrics_reporter_(metrics_reporter), + power_manager_client_(power_manager_client), + tick_clock_(tick_clock), + weak_ptr_factory_(this) { + DCHECK(profile); + DCHECK(als_reader); + DCHECK(brightness_monitor); + DCHECK(modeller); + DCHECK(model_config_loader); + DCHECK(power_manager_client); + + als_reader_observer_.Add(als_reader); + brightness_monitor_observer_.Add(brightness_monitor); + modeller_observer_.Add(modeller); + model_config_loader_observer_.Add(model_config_loader); + power_manager_client_observer_.Add(power_manager_client); + + power_manager_client_->WaitForServiceToBeAvailable( + base::BindOnce(&Adapter::OnPowerManagerServiceAvailable, + weak_ptr_factory_.GetWeakPtr())); +} + void Adapter::InitParams(const ModelConfig& model_config) { if (!base::FeatureList::IsEnabled(features::kAutoScreenBrightness) && model_config.metrics_key != "atlas") { @@ -274,6 +322,10 @@ features::kAutoScreenBrightness, "darkening_log_lux_threshold", params_.darkening_log_lux_threshold); + params_.stabilization_threshold = GetFieldTrialParamByFeatureAsDouble( + features::kAutoScreenBrightness, "stabilization_threshold", + params_.stabilization_threshold); + const int model_curve = base::GetFieldTrialParamByFeatureAsInt( features::kAutoScreenBrightness, "model_curve", 2); if (model_curve < 0 || model_curve > 2) { @@ -284,7 +336,10 @@ params_.model_curve = static_cast<ModelCurve>(model_curve); const int auto_brightness_als_horizon_seconds = - model_config.auto_brightness_als_horizon_seconds; + GetFieldTrialParamByFeatureAsInt( + features::kAutoScreenBrightness, + "auto_brightness_als_horizon_seconds", + model_config.auto_brightness_als_horizon_seconds); if (auto_brightness_als_horizon_seconds <= 0) { adapter_status_ = Status::kDisabled; @@ -371,10 +426,12 @@ } base::Optional<Adapter::BrightnessChangeCause> Adapter::CanAdjustBrightness( - double current_log_average_ambient) const { + double current_log_average_ambient, + double stddev) const { if (adapter_status_ != Status::kSuccess || - adapter_disabled_by_user_adjustment_) + adapter_disabled_by_user_adjustment_) { return base::nullopt; + } // Do not change brightness if it's set by the policy, but do not completely // disable the model as the policy could change. @@ -385,18 +442,29 @@ return base::nullopt; } - if (latest_brightness_change_time_.is_null()) { - // Brightness hasn't been changed before. + if (!log_average_ambient_lux_) { + // Either + // 1. brightness hasn't been changed, or, + // 2. brightness was changed by the user but there wasn't any ALS data. This + // case should be rare. + // In either case, we change brightness as soon as we have brightness. return BrightnessChangeCause::kInitialAlsReceived; } // The following thresholds should have been set last time when brightness was // changed. - if (current_log_average_ambient > *brightening_threshold_) { + DCHECK(brightening_threshold_); + DCHECK(darkening_threshold_); + + if (current_log_average_ambient > *brightening_threshold_ && + stddev <= params_.brightening_log_lux_threshold * + params_.stabilization_threshold) { return BrightnessChangeCause::kBrightneningThresholdExceeded; } - if (current_log_average_ambient < *darkening_threshold_) { + if (current_log_average_ambient < *darkening_threshold_ && + stddev <= params_.darkening_log_lux_threshold * + params_.stabilization_threshold) { return BrightnessChangeCause::kDarkeningThresholdExceeded; } @@ -406,6 +474,18 @@ void Adapter::MaybeAdjustBrightness(base::TimeTicks now) { DCHECK_EQ(adapter_status_, Status::kSuccess); DCHECK(ambient_light_values_); + DCHECK(!als_init_time_.is_null()); + // Wait until we've had enough ALS data to calc avg. + if (now - als_init_time_ < params_.auto_brightness_als_horizon) + return; + + // Check if we've waited long enough from previous brightness change (either + // by user or by model). + if (!latest_brightness_change_time_.is_null() && + now - latest_brightness_change_time_ < + params_.auto_brightness_als_horizon) + return; + const base::Optional<AlsAvgStdDev> als_avg_stddev = ambient_light_values_->AverageAmbientWithStdDev(now); if (!als_avg_stddev) @@ -414,7 +494,7 @@ const double log_average_ambient_lux = ConvertToLog(als_avg_stddev->avg); const base::Optional<BrightnessChangeCause> brightness_change_cause = - CanAdjustBrightness(log_average_ambient_lux); + CanAdjustBrightness(log_average_ambient_lux, als_avg_stddev->stddev); if (!brightness_change_cause.has_value()) return; @@ -435,35 +515,22 @@ power_manager_client_->SetScreenBrightness(request); const base::TimeTicks brightness_change_time = tick_clock_->NowTicks(); - if (!latest_brightness_change_time_.is_null()) { + if (!latest_model_brightness_change_time_.is_null()) { UMA_HISTOGRAM_LONG_TIMES( "AutoScreenBrightness.BrightnessChange.ElapsedTime", - brightness_change_time - latest_brightness_change_time_); + brightness_change_time - latest_model_brightness_change_time_); } - latest_brightness_change_time_ = brightness_change_time; + latest_model_brightness_change_time_ = brightness_change_time; const BrightnessChangeCause cause = *brightness_change_cause; UMA_HISTOGRAM_ENUMERATION("AutoScreenBrightness.BrightnessChange.Cause", cause); WriteLogMessages(log_average_ambient_lux, *brightness, cause); + model_brightness_change_counter_++; - current_brightness_ = *brightness; - brightness_change_counter_++; - - log_average_ambient_lux_ = log_average_ambient_lux; - - UpdateBrightnessChangeThresholds(); -} - -void Adapter::UpdateBrightnessChangeThresholds() { - DCHECK_NE(adapter_status_, Status::kInitializing); - DCHECK(log_average_ambient_lux_); - - brightening_threshold_ = - *log_average_ambient_lux_ + params_.brightening_log_lux_threshold; - darkening_threshold_ = - *log_average_ambient_lux_ - params_.darkening_log_lux_threshold; + OnBrightnessChanged(brightness_change_time, *brightness, + log_average_ambient_lux); } base::Optional<double> Adapter::GetBrightnessBasedOnAmbientLogLux( @@ -484,6 +551,31 @@ } } +void Adapter::OnBrightnessChanged(base::TimeTicks now, + double new_brightness_percent, + base::Optional<double> new_log_als) { + DCHECK_NE(adapter_status_, Status::kInitializing); + + current_brightness_ = new_brightness_percent; + latest_brightness_change_time_ = now; + + UMA_HISTOGRAM_BOOLEAN("AutoScreenBrightness.MissingAlsWhenBrightnessChanged", + !new_log_als); + + if (!new_log_als) + return; + + // Update |log_average_ambient_lux_| with the new reference value. Brightness + // will be changed by the model if next log-avg ALS value goes outside of the + // range + // [|darkening_threshold_|, |brightening_threshold_|]. + // Thresholds in |params_| are absolute values to be added/subtracted from + // the reference values. Log-avg can be negative. + log_average_ambient_lux_ = new_log_als; + brightening_threshold_ = *new_log_als + params_.brightening_log_lux_threshold; + darkening_threshold_ = *new_log_als - params_.darkening_log_lux_threshold; +} + void Adapter::WriteLogMessages(double new_log_als, double new_brightness, BrightnessChangeCause cause) const { @@ -498,7 +590,8 @@ ? base::StringPrintf("%.4f", current_brightness_.value()) + "%->" : ""; - VLOG(1) << "Screen brightness change #" << brightness_change_counter_ << ": " + VLOG(1) << "Screen brightness change #" << model_brightness_change_counter_ + << ": " << "brightness=" << old_brightness << base::StringPrintf("%.4f", new_brightness) << "%" << " cause=" << BrightnessChangeCauseToString(cause)
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/adapter.h b/chrome/browser/chromeos/power/auto_screen_brightness/adapter.h index 4a75d2f..87591ba 100644 --- a/chrome/browser/chromeos/power/auto_screen_brightness/adapter.h +++ b/chrome/browser/chromeos/power/auto_screen_brightness/adapter.h
@@ -68,14 +68,23 @@ }; // The values in Params can be overridden by experiment flags. + // TODO(jiameng): move them to cros config json file once experiments are + // complete. struct Params { Params(); - // The log of average ambient value has to go up (resp. down) by - // |brightening_log_lux_threshold| (resp. |darkening_log_lux_threshold|) - // from the current value before brightness could be changed. - double brightening_log_lux_threshold = 1.0; - double darkening_log_lux_threshold = 1.0; + // Brightness is only changed if + // 1. the log of average ambient value has gone up (resp. down) by + // |brightening_log_lux_threshold| (resp. |darkening_log_lux_threshold|) + // from the reference value. The reference value is the average ALS when + // brightness was changed last time (by user or model). + // and + // 2. the std-dev of ALS within the averaging period is less than + // |stabilization_threshold| multiplied by the brightening/darkening + // thresholds to show the ALS has stabilized. + double brightening_log_lux_threshold = 0.6; + double darkening_log_lux_threshold = 0.6; + double stabilization_threshold = 0.15; ModelCurve model_curve = ModelCurve::kLatest; @@ -83,7 +92,7 @@ // |auto_brightness_als_horizon|. This is only used for brightness update, // which can be different from the horizon used in model training. base::TimeDelta auto_brightness_als_horizon = - base::TimeDelta::FromSeconds(5); + base::TimeDelta::FromSeconds(4); UserAdjustmentEffect user_adjustment_effect = UserAdjustmentEffect::kDisableAuto; @@ -144,8 +153,6 @@ // chromeos::PowerManagerClient::Observer overrides: void SuspendDone(const base::TimeDelta& sleep_duration) override; - void SetTickClockForTesting(const base::TickClock* test_tick_clock); - Status GetStatusForTesting() const; // Only returns true if Adapter status is success and it's not disabled by @@ -160,10 +167,32 @@ double GetBrighteningThresholdForTesting() const; double GetDarkeningThresholdForTesting() const; + // Returns |log_average_ambient_lux_|. + base::Optional<double> GetCurrentLogAvgAlsForTesting() const; + + static std::unique_ptr<Adapter> CreateForTesting( + Profile* profile, + AlsReader* als_reader, + BrightnessMonitor* brightness_monitor, + Modeller* modeller, + ModelConfigLoader* model_config_loader, + MetricsReporter* metrics_reporter, + chromeos::PowerManagerClient* power_manager_client, + const base::TickClock* tick_clock); + private: + Adapter(Profile* profile, + AlsReader* als_reader, + BrightnessMonitor* brightness_monitor, + Modeller* modeller, + ModelConfigLoader* model_config_loader, + MetricsReporter* metrics_reporter, + chromeos::PowerManagerClient* power_manager_client, + const base::TickClock* tick_clock); + // Called by |OnModelConfigLoaded|. It will initialize all params used by - // the modeller from |model_config| and also other experiment flags. If any - // param is invalid, it will disable the adapter. + // the modeller from |model_config| and also other experiment flags. If + // any param is invalid, it will disable the adapter. void InitParams(const ModelConfig& model_config); // Called when powerd becomes available. @@ -177,22 +206,22 @@ // Returns a BrightnessChangeCause if the adapter can change the brightness. // This is generally the case when the brightness hasn't been manually // set, we've received enough initial ambient light readings, and - // the ambient light has changed beyond thresholds. + // the ambient light has changed beyond thresholds and has stabilized. // Returns nullopt if it shouldn't change the brightness. base::Optional<BrightnessChangeCause> CanAdjustBrightness( - double current_average_ambient) const; + double current_log_average_ambient, + double stddev) const; // Called when ambient light changes. It only changes screen brightness if // |CanAdjustBrightness| returns true and a required curve is set up: // if the required curve is personal but no personal curve is available, then // brightness won't be changed. - // It will call |UpdateBrightnessChangeThresholds| if brightness is actually - // changed. + // It will call |OnBrightnessChanged| if brightness is actually changed. + // |now| should be the timestamp when ALS reading comes in, i.e. when + // |OnAmbientLightUpdated| is called. |OnAmbientLightUpdated| is the event + // that triggers the call of |MaybeAdjustBrightness|. void MaybeAdjustBrightness(base::TimeTicks now); - // This is only called when brightness is changed. - void UpdateBrightnessChangeThresholds(); - // Calculates brightness from given |ambient_log_lux| based on either // |global_curve_| or |personal_curve_| (as specified by the experiment // params). Returns nullopt if a personal curve should be used but it's not @@ -200,6 +229,17 @@ base::Optional<double> GetBrightnessBasedOnAmbientLogLux( double ambient_log_lux) const; + // Called when brightness is changed by the model or user. This function + // updates |latest_brightness_change_time_|, |current_brightness_|. If + // |new_log_als| is not nullopt, it will also update + // |log_average_ambient_lux_| and thresholds. |new_log_als| should be + // available when this function is called, but may be nullopt when a user + // changes brightness before any ALS reading comes in. We log an error if this + // happens. + void OnBrightnessChanged(base::TimeTicks now, + double new_brightness_percent, + base::Optional<double> new_log_als); + // Called by |MaybeAdjustBrightness| when brightness should be changed. void WriteLogMessages(double new_log_als, double new_brightness, @@ -229,10 +269,15 @@ // This will be replaced by a mock tick clock during tests. const base::TickClock* tick_clock_; + // TODO(jiameng): refactor internal states and flags. + // This buffer will be used to store the recent ambient light values. std::unique_ptr<AmbientLightSampleBuffer> ambient_light_values_; base::Optional<AlsReader::AlsInitStatus> als_init_status_; + // Time when AlsReader is initialized. + base::TimeTicks als_init_time_; + base::Optional<bool> brightness_monitor_success_; // |model_config_exists_| will remain nullopt until |OnModelConfigLoaded| is @@ -249,32 +294,34 @@ // This is set to true whenever a user makes a manual adjustment, and if // |params_.user_adjustment_effect| is not |kContinueAuto|. It will be // reset to false if |params_.user_adjustment_effect| is |kPauseAuto|. + // It won't be set/reset if adapter is disabled because it won't be necessary + // to check |adapter_disabled_by_user_adjustment_|. bool adapter_disabled_by_user_adjustment_ = false; // The thresholds are calculated from the |log_average_ambient_lux_|. - // They are only updated when brightness should occur (because the log of - // average ambient value changed sufficiently). + // They are only updated when brightness is changed (either by user or model). base::Optional<double> brightening_threshold_; base::Optional<double> darkening_threshold_; base::Optional<MonotoneCubicSpline> global_curve_; base::Optional<MonotoneCubicSpline> personal_curve_; - // Average ambient value is only calculated when |CanAdjustBrightness| - // returns true. This is the log of average over all values in - // |ambient_light_values_|. The adapter will notify powerd to change - // brightness. New thresholds will be calculated from it. + // |log_average_ambient_lux_| is only recorded when screen brightness is + // changed by either model or user. New thresholds will be calculated from it. base::Optional<double> log_average_ambient_lux_; - // Last time brightness change occurred. + // Last time brightness change occurred, either by user or model. base::TimeTicks latest_brightness_change_time_; + // Last time brightness was changed by the model. + base::TimeTicks latest_model_brightness_change_time_; + // Current recorded brightness. It can be either the user requested brightness // or the model requested brightness. base::Optional<double> current_brightness_; // Used to record number of model-triggered brightness changes. - int brightness_change_counter_ = 1; + int model_brightness_change_counter_ = 1; base::WeakPtrFactory<Adapter> weak_ptr_factory_;
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/adapter_unittest.cc b/chrome/browser/chromeos/power/auto_screen_brightness/adapter_unittest.cc index febce768a..5334b5f 100644 --- a/chrome/browser/chromeos/power/auto_screen_brightness/adapter_unittest.cc +++ b/chrome/browser/chromeos/power/auto_screen_brightness/adapter_unittest.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/chromeos/power/auto_screen_brightness/adapter.h" #include <map> +#include <numeric> #include <vector> #include "ash/public/cpp/ash_pref_names.h" @@ -40,25 +41,15 @@ namespace { -// Checks |result.avg| and |result.stddev| are the same as that -// calculated from the |expected_data|. -void CheckAverageAndStdDev(const AlsAvgStdDev& result, - const std::vector<double>& expected_data) { +// Checks |actual_log_avg| is equal to the log avg calculated from +// |expected_data|. +void CheckLogAvg(const std::vector<double>& expected_data, + double actual_log_avg) { const size_t count = expected_data.size(); CHECK_NE(count, 0u); - double expected_avg = 0; - double expected_stddev = 0; - - for (const auto& i : expected_data) { - expected_avg += i; - expected_stddev += i * i; - } - - expected_avg = expected_avg / count; - expected_stddev = - std::sqrt(expected_stddev / count - expected_avg * expected_avg); - EXPECT_DOUBLE_EQ(result.avg, expected_avg); - EXPECT_DOUBLE_EQ(result.stddev, expected_stddev); + const double expected_log_avg = ConvertToLog( + std::accumulate(expected_data.begin(), expected_data.end(), 0.0) / count); + EXPECT_DOUBLE_EQ(actual_log_avg, expected_log_avg); } // Testing modeller. @@ -166,8 +157,13 @@ chromeos::PowerManagerClient::Shutdown(); } + // Creates Adapter only, but its input may or may not be ready. void SetUpAdapter(const std::map<std::string, std::string>& params, bool brightness_set_by_policy = false) { + // Simulate the real clock that will not produce TimeTicks equal to 0. + // This is because the Adapter will treat 0 TimeTicks are uninitialized + // values. + thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(1)); sync_preferences::PrefServiceMockFactory factory; factory.set_user_prefs(base::WrapRefCounted(new TestingPrefStore())); scoped_refptr<user_prefs::PrefRegistrySyncable> registry( @@ -207,13 +203,15 @@ features::kAutoScreenBrightness, params); } - adapter_ = std::make_unique<Adapter>( + adapter_ = Adapter::CreateForTesting( profile_.get(), &fake_als_reader_, &fake_brightness_monitor_, &fake_modeller_, &fake_model_config_loader_, - nullptr /* metrics_reporter */, chromeos::PowerManagerClient::Get()); - adapter_->SetTickClockForTesting(thread_bundle_.GetMockTickClock()); + nullptr /* metrics_reporter */, chromeos::PowerManagerClient::Get(), + thread_bundle_.GetMockTickClock()); + thread_bundle_.RunUntilIdle(); } + // Sets up all required input for Adapter and then creates Adapter. void Init(AlsReader::AlsInitStatus als_reader_status, BrightnessMonitor::Status brightness_monitor_status, const base::Optional<MonotoneCubicSpline>& global_curve, @@ -229,7 +227,6 @@ } SetUpAdapter(params, brightness_set_by_policy); - thread_bundle_.RunUntilIdle(); } void ReportSuspendDone() { @@ -253,6 +250,29 @@ return model_config; } + void ReportAls(int als_value) { + fake_als_reader_.ReportAmbientLightUpdate(als_value); + thread_bundle_.RunUntilIdle(); + } + + void ReportUserBrightnessChangeRequest(double old_brightness_percent, + double new_brightness_percent) { + fake_brightness_monitor_.ReportUserBrightnessChanged( + old_brightness_percent, new_brightness_percent); + fake_brightness_monitor_.ReportUserBrightnessChangeRequested(); + thread_bundle_.RunUntilIdle(); + } + + // Forwards time first and then reports Als. + void ForwardTimeAndReportAls(const std::vector<int>& als_values) { + for (const int als_value : als_values) { + // Forward 1 second to simulate the real AlsReader that samples data at + // 1hz. + thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(1)); + ReportAls(als_value); + } + } + protected: content::TestBrowserThreadBundle thread_bundle_; @@ -271,10 +291,16 @@ base::HistogramTester histogram_tester_; + // |brightening_log_lux_threshold| and |darkening_log_lux_threshold| are set + // to very small values so a slight change in ALS would trigger brightness + // update. |stabilization_threshold| is set to a very high value so that we + // don't have to check ALS has stablized. const std::map<std::string, std::string> default_params_ = { - {"brightening_log_lux_threshold", "0.1"}, - {"darkening_log_lux_threshold", "0.2"}, + {"brightening_log_lux_threshold", "0.00001"}, + {"darkening_log_lux_threshold", "0.00001"}, + {"stabilization_threshold", "100000000"}, {"model_curve", "2"}, + {"auto_brightness_als_horizon_seconds", "5"}, {"user_adjustment_effect", "0"}, }; @@ -456,6 +482,44 @@ EXPECT_FALSE(adapter_->GetPersonalCurveForTesting()); } +// First ALS comes in 1 second after AlsReader is initialized. Hence after +// |auto_brightness_als_horizon_seconds|, brightness is changed. +TEST_F(AdapterTest, FirstAlsAfterAlsReaderInitTime) { + Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess, + global_curve_, personal_curve_, GetTestModelConfig(), default_params_); + + EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess); + + // |auto_brightness_als_horizon_seconds| is 5. + ForwardTimeAndReportAls({1, 2, 3, 4}); + EXPECT_EQ(test_observer_.num_changes(), 0); + + ForwardTimeAndReportAls({100}); + EXPECT_EQ(test_observer_.num_changes(), 1); + CheckLogAvg({1, 2, 3, 4, 100}, + adapter_->GetCurrentLogAvgAlsForTesting().value()); +} + +// First ALS comes in at the same time when AlsReader is initialized. Hence +// after |auto_brightness_als_horizon_seconds| + 1 readings, brightness is +// changed. +TEST_F(AdapterTest, FirstAlsAtAlsReaderInitTime) { + Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess, + global_curve_, personal_curve_, GetTestModelConfig(), default_params_); + + EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess); + + // First ALS when AlsReader is initialized. + ReportAls(10); + ForwardTimeAndReportAls({1, 2, 3, 4}); + EXPECT_EQ(test_observer_.num_changes(), 0); + + ForwardTimeAndReportAls({100}); + EXPECT_EQ(test_observer_.num_changes(), 1); + CheckLogAvg({1, 2, 3, 4, 100}, + adapter_->GetCurrentLogAvgAlsForTesting().value()); +} + TEST_F(AdapterTest, SequenceOfBrightnessUpdatesWithDefaultParams) { Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess, global_curve_, personal_curve_, GetTestModelConfig(), default_params_); @@ -466,113 +530,227 @@ EXPECT_TRUE(adapter_->GetPersonalCurveForTesting()); EXPECT_EQ(*adapter_->GetPersonalCurveForTesting(), *personal_curve_); - thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(1)); + ForwardTimeAndReportAls({1, 2, 3, 4}); + EXPECT_EQ(test_observer_.num_changes(), 0); - // Brightness is changed after the 1st ALS reading comes in. - fake_als_reader_.ReportAmbientLightUpdate(10); - thread_bundle_.RunUntilIdle(); + // Brightness is changed for the first time after the 5th reading. + ForwardTimeAndReportAls({5}); EXPECT_EQ(test_observer_.num_changes(), 1); - CheckAverageAndStdDev( - adapter_->GetAverageAmbientWithStdDevForTesting(thread_bundle_.NowTicks()) - .value(), - {10}); + CheckLogAvg({1, 2, 3, 4, 5}, + adapter_->GetCurrentLogAvgAlsForTesting().value()); - EXPECT_DOUBLE_EQ(adapter_->GetBrighteningThresholdForTesting(), - ConvertToLog(10.0) + 0.1); - EXPECT_DOUBLE_EQ(adapter_->GetDarkeningThresholdForTesting(), - ConvertToLog(10.0) - 0.2); + // Several other ALS readings come in, but need to wait for + // |params.auto_brightness_als_horizon_seconds| to pass before having any + // effect + ForwardTimeAndReportAls({20}); + EXPECT_EQ(test_observer_.num_changes(), 1); + CheckLogAvg({1, 2, 3, 4, 5}, + adapter_->GetCurrentLogAvgAlsForTesting().value()); - thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(1)); - fake_als_reader_.ReportAmbientLightUpdate(20); - thread_bundle_.RunUntilIdle(); + ForwardTimeAndReportAls({30}); + EXPECT_EQ(test_observer_.num_changes(), 1); + CheckLogAvg({1, 2, 3, 4, 5}, + adapter_->GetCurrentLogAvgAlsForTesting().value()); + + ForwardTimeAndReportAls({40}); + EXPECT_EQ(test_observer_.num_changes(), 1); + CheckLogAvg({1, 2, 3, 4, 5}, + adapter_->GetCurrentLogAvgAlsForTesting().value()); + + ForwardTimeAndReportAls({50}); + EXPECT_EQ(test_observer_.num_changes(), 1); + CheckLogAvg({1, 2, 3, 4, 5}, + adapter_->GetCurrentLogAvgAlsForTesting().value()); + + // The next ALS reading triggers brightness change. + ForwardTimeAndReportAls({60}); EXPECT_EQ(test_observer_.num_changes(), 2); - CheckAverageAndStdDev( - adapter_->GetAverageAmbientWithStdDevForTesting(thread_bundle_.NowTicks()) - .value(), - {10, 20}); - - EXPECT_DOUBLE_EQ(adapter_->GetBrighteningThresholdForTesting(), - ConvertToLog(15.0) + 0.1); - EXPECT_DOUBLE_EQ(adapter_->GetDarkeningThresholdForTesting(), - ConvertToLog(15.0) - 0.2); + CheckLogAvg({20, 30, 40, 50, 60}, + adapter_->GetCurrentLogAvgAlsForTesting().value()); // |params.auto_brightness_als_horizon_seconds| has elapsed since we've made // the change, but there's no new ALS value, hence no brightness change is // triggered. thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(10)); EXPECT_EQ(test_observer_.num_changes(), 2); + CheckLogAvg({20, 30, 40, 50, 60}, + adapter_->GetCurrentLogAvgAlsForTesting().value()); + EXPECT_EQ(adapter_->GetAverageAmbientWithStdDevForTesting( thread_bundle_.NowTicks()), base::nullopt); // A new ALS value triggers a brightness change. - thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(1)); - fake_als_reader_.ReportAmbientLightUpdate(40); - thread_bundle_.RunUntilIdle(); + ForwardTimeAndReportAls({100}); EXPECT_EQ(test_observer_.num_changes(), 3); - CheckAverageAndStdDev( - adapter_->GetAverageAmbientWithStdDevForTesting(thread_bundle_.NowTicks()) - .value(), - {40}); - - EXPECT_DOUBLE_EQ(adapter_->GetBrighteningThresholdForTesting(), - ConvertToLog(40.0) + 0.1); - EXPECT_DOUBLE_EQ(adapter_->GetDarkeningThresholdForTesting(), - ConvertToLog(40.0) - 0.2); - - // Adapter will not be applied after a user manual adjustment. - fake_brightness_monitor_.ReportUserBrightnessChangeRequested(); - thread_bundle_.RunUntilIdle(); - EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess); - EXPECT_FALSE(adapter_->IsAppliedForTesting()); - - // SuspendDone does not re-enable Adapter as default for effect is - // |kDisableAuto|. - ReportSuspendDone(); - EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess); - EXPECT_FALSE(adapter_->IsAppliedForTesting()); - - thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(1)); - fake_als_reader_.ReportAmbientLightUpdate(100); - thread_bundle_.RunUntilIdle(); - EXPECT_EQ(test_observer_.num_changes(), 3); - - // Another user manual adjustment came in. - fake_brightness_monitor_.ReportUserBrightnessChangeRequested(); - thread_bundle_.RunUntilIdle(); - EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess); - EXPECT_FALSE(adapter_->IsAppliedForTesting()); + CheckLogAvg({100}, adapter_->GetCurrentLogAvgAlsForTesting().value()); } -TEST_F(AdapterTest, UserBrightnessRequestBeforeAnyModelUpdate) { +// A user brightness change comes in when ALS readings exist. This also disables +// the adapter because |user_adjustment_effect| is 0 (disabled). +TEST_F(AdapterTest, UserBrightnessChangeAlsReadingExists) { Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess, global_curve_, personal_curve_, GetTestModelConfig(), default_params_); EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess); - EXPECT_TRUE(adapter_->GetGlobalCurveForTesting()); - EXPECT_EQ(*adapter_->GetGlobalCurveForTesting(), *global_curve_); - EXPECT_TRUE(adapter_->GetPersonalCurveForTesting()); - EXPECT_EQ(*adapter_->GetPersonalCurveForTesting(), *personal_curve_); - thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(1)); + ForwardTimeAndReportAls({1, 2, 3, 4}); + EXPECT_EQ(test_observer_.num_changes(), 0); // Adapter will not be applied after a user manual adjustment. - fake_brightness_monitor_.ReportUserBrightnessChangeRequested(); - thread_bundle_.RunUntilIdle(); - EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess); - EXPECT_FALSE(adapter_->IsAppliedForTesting()); + ReportUserBrightnessChangeRequest(20.0, 30.0); - // Another user manual adjustment came in. - fake_brightness_monitor_.ReportUserBrightnessChangeRequested(); - thread_bundle_.RunUntilIdle(); + histogram_tester_.ExpectUniqueSample( + "AutoScreenBrightness.MissingAlsWhenBrightnessChanged", false, 1); EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess); EXPECT_FALSE(adapter_->IsAppliedForTesting()); + CheckLogAvg({1, 2, 3, 4}, adapter_->GetCurrentLogAvgAlsForTesting().value()); + + // An als reading comes in but will not change the brightness. + ForwardTimeAndReportAls({100}); + EXPECT_EQ(test_observer_.num_changes(), 0); + CheckLogAvg({1, 2, 3, 4}, adapter_->GetCurrentLogAvgAlsForTesting().value()); + + // Another user manual adjustment comes in. + thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(1)); + ReportUserBrightnessChangeRequest(30.0, 40.0); + + EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess); + EXPECT_FALSE(adapter_->IsAppliedForTesting()); + histogram_tester_.ExpectUniqueSample( + "AutoScreenBrightness.MissingAlsWhenBrightnessChanged", false, 2); + CheckLogAvg({2, 3, 4, 100}, + adapter_->GetCurrentLogAvgAlsForTesting().value()); } -TEST_F(AdapterTest, BrightnessLuxThresholds) { +// Same as |UserBrightnessChangeAlsReadingExists| except that user adjustment +// effect is Continue. +TEST_F(AdapterTest, UserBrightnessChangeAlsReadingExistsContinue) { std::map<std::string, std::string> params = default_params_; - params["brightening_log_lux_threshold"] = "1"; - params["darkening_log_lux_threshold"] = "0.2"; + // UserAdjustmentEffect::kContinueAuto = 2. + params["user_adjustment_effect"] = "2"; + Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess, + global_curve_, personal_curve_, GetTestModelConfig(), params); + + EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess); + + ForwardTimeAndReportAls({2, 4, 6, 8}); + EXPECT_EQ(test_observer_.num_changes(), 0); + + // User brightness change comes in. + ReportUserBrightnessChangeRequest(20.0, 30.0); + histogram_tester_.ExpectUniqueSample( + "AutoScreenBrightness.MissingAlsWhenBrightnessChanged", false, 1); + EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess); + EXPECT_TRUE(adapter_->IsAppliedForTesting()); + EXPECT_EQ(test_observer_.num_changes(), 0); + CheckLogAvg({2, 4, 6, 8}, adapter_->GetCurrentLogAvgAlsForTesting().value()); + + // Four ALS readings come in, but not enough time has passed since user + // brightness change. + ForwardTimeAndReportAls({4, 6, 8, 2}); + EXPECT_EQ(test_observer_.num_changes(), 0); + CheckLogAvg({2, 4, 6, 8}, adapter_->GetCurrentLogAvgAlsForTesting().value()); + + // Another ALS reading is in, but avg is the same as reference ALS (when user + // changed brightness). Hence no change to brightness. + ForwardTimeAndReportAls({5}); + EXPECT_EQ(test_observer_.num_changes(), 0); + CheckLogAvg({2, 4, 6, 8}, adapter_->GetCurrentLogAvgAlsForTesting().value()); + + // Another user manual adjustment comes in. + thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(1)); + ReportUserBrightnessChangeRequest(30.0, 40.0); + + EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess); + EXPECT_TRUE(adapter_->IsAppliedForTesting()); + histogram_tester_.ExpectUniqueSample( + "AutoScreenBrightness.MissingAlsWhenBrightnessChanged", false, 2); + CheckLogAvg({6, 8, 2, 5}, adapter_->GetCurrentLogAvgAlsForTesting().value()); +} + +// Same as |UserBrightnessChangeAlsReadingExists| except that the 1st user +// brightness change comes when there is no ALS reading. +TEST_F(AdapterTest, UserBrightnessChangeAlsReadingAbsent) { + Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess, + global_curve_, personal_curve_, GetTestModelConfig(), default_params_); + + EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess); + + // Adapter will not be applied after a user manual adjustment. + ReportUserBrightnessChangeRequest(20.0, 30.0); + + histogram_tester_.ExpectUniqueSample( + "AutoScreenBrightness.MissingAlsWhenBrightnessChanged", true, 1); + EXPECT_EQ(adapter_->GetCurrentLogAvgAlsForTesting(), base::nullopt); + EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess); + EXPECT_FALSE(adapter_->IsAppliedForTesting()); + EXPECT_FALSE(adapter_->GetCurrentLogAvgAlsForTesting()); + + // ALS readings come in but will not change the brightness. + ForwardTimeAndReportAls({100, 101, 102, 103, 104}); + EXPECT_EQ(test_observer_.num_changes(), 0); + EXPECT_FALSE(adapter_->GetCurrentLogAvgAlsForTesting()); + + // Another user manual adjustment comes in. + thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(1)); + ReportUserBrightnessChangeRequest(30.0, 40.0); + histogram_tester_.ExpectBucketCount( + "AutoScreenBrightness.MissingAlsWhenBrightnessChanged", true, 1); + histogram_tester_.ExpectBucketCount( + "AutoScreenBrightness.MissingAlsWhenBrightnessChanged", false, 1); + EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess); + EXPECT_FALSE(adapter_->IsAppliedForTesting()); + CheckLogAvg({101, 102, 103, 104}, + adapter_->GetCurrentLogAvgAlsForTesting().value()); +} + +// Same as |UserBrightnessChangeAlsReadingAbsent| except that user adjustment +// effect is Continue. +TEST_F(AdapterTest, UserBrightnessChangeAlsReadingAbsentContinue) { + std::map<std::string, std::string> params = default_params_; + // UserAdjustmentEffect::kContinueAuto = 2. + params["user_adjustment_effect"] = "2"; + Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess, + global_curve_, personal_curve_, GetTestModelConfig(), params); + + EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess); + + ReportUserBrightnessChangeRequest(20.0, 30.0); + + histogram_tester_.ExpectUniqueSample( + "AutoScreenBrightness.MissingAlsWhenBrightnessChanged", true, 1); + EXPECT_EQ(adapter_->GetCurrentLogAvgAlsForTesting(), base::nullopt); + EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess); + EXPECT_TRUE(adapter_->IsAppliedForTesting()); + EXPECT_FALSE(adapter_->GetCurrentLogAvgAlsForTesting()); + + // ALS readings come in, and will trigger a brightness change. + ForwardTimeAndReportAls({100}); + EXPECT_EQ(test_observer_.num_changes(), 0); + ForwardTimeAndReportAls({101, 102, 103, 104}); + EXPECT_EQ(test_observer_.num_changes(), 1); + CheckLogAvg({100, 101, 102, 103, 104}, + adapter_->GetCurrentLogAvgAlsForTesting().value()); + + // Another user manual adjustment comes in. + thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(1)); + ReportUserBrightnessChangeRequest(30.0, 40.0); + histogram_tester_.ExpectBucketCount( + "AutoScreenBrightness.MissingAlsWhenBrightnessChanged", true, 1); + histogram_tester_.ExpectBucketCount( + "AutoScreenBrightness.MissingAlsWhenBrightnessChanged", false, 2); + EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess); + EXPECT_TRUE(adapter_->IsAppliedForTesting()); + CheckLogAvg({101, 102, 103, 104}, + adapter_->GetCurrentLogAvgAlsForTesting().value()); +} + +// Set |brightening_log_lux_threshold| to a very high value to effectively make +// brightening impossible. +TEST_F(AdapterTest, BrighteningThreshold) { + std::map<std::string, std::string> params = default_params_; + params["brightening_log_lux_threshold"] = "100"; Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess, global_curve_, personal_curve_, GetTestModelConfig(), params); @@ -582,90 +760,130 @@ EXPECT_TRUE(adapter_->GetPersonalCurveForTesting()); EXPECT_EQ(*adapter_->GetPersonalCurveForTesting(), *personal_curve_); - thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(1)); - - // Brightness is changed after the 1st ALS value, and the thresholds are - // changed. - fake_als_reader_.ReportAmbientLightUpdate(20); - thread_bundle_.RunUntilIdle(); + ForwardTimeAndReportAls({1, 2, 3, 4}); + EXPECT_EQ(test_observer_.num_changes(), 0); + ForwardTimeAndReportAls({5}); EXPECT_EQ(test_observer_.num_changes(), 1); - CheckAverageAndStdDev( - adapter_->GetAverageAmbientWithStdDevForTesting(thread_bundle_.NowTicks()) - .value(), - {20}); - - double expected_log_avg = ConvertToLog(20); - double expected_brightening_threshold = expected_log_avg + 1; - double expected_darkening_threshold = expected_log_avg - 0.2; + CheckLogAvg({1, 2, 3, 4, 5}, + adapter_->GetCurrentLogAvgAlsForTesting().value()); EXPECT_DOUBLE_EQ(adapter_->GetBrighteningThresholdForTesting(), - expected_brightening_threshold); + adapter_->GetCurrentLogAvgAlsForTesting().value() + 100); EXPECT_DOUBLE_EQ(adapter_->GetDarkeningThresholdForTesting(), - expected_darkening_threshold); + adapter_->GetCurrentLogAvgAlsForTesting().value() - 0.00001); - // A 2nd ALS comes in, but average ambient is within the thresholds, hence - // brightness isn't changed and thresholds aren't updated. - thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(1)); - fake_als_reader_.ReportAmbientLightUpdate(21); - thread_bundle_.RunUntilIdle(); - EXPECT_EQ(1, test_observer_.num_changes()); - CheckAverageAndStdDev( - adapter_->GetAverageAmbientWithStdDevForTesting(thread_bundle_.NowTicks()) - .value(), - {20, 21}); - - EXPECT_DOUBLE_EQ(adapter_->GetBrighteningThresholdForTesting(), - expected_brightening_threshold); - EXPECT_DOUBLE_EQ(adapter_->GetDarkeningThresholdForTesting(), - expected_darkening_threshold); - - // // A 3rd ALS comes in, but still not enough to trigger brightness change. - thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(1)); - fake_als_reader_.ReportAmbientLightUpdate(15); - thread_bundle_.RunUntilIdle(); + ForwardTimeAndReportAls({4, 4, 4, 4, 4}); EXPECT_EQ(test_observer_.num_changes(), 1); - CheckAverageAndStdDev( - adapter_->GetAverageAmbientWithStdDevForTesting(thread_bundle_.NowTicks()) - .value(), - {20, 21, 15}); - + CheckLogAvg({1, 2, 3, 4, 5}, + adapter_->GetCurrentLogAvgAlsForTesting().value()); EXPECT_DOUBLE_EQ(adapter_->GetBrighteningThresholdForTesting(), - expected_brightening_threshold); + adapter_->GetCurrentLogAvgAlsForTesting().value() + 100); EXPECT_DOUBLE_EQ(adapter_->GetDarkeningThresholdForTesting(), - expected_darkening_threshold); + adapter_->GetCurrentLogAvgAlsForTesting().value() - 0.00001); - // A 4th ALS makes average value below the darkening threshold, hence - // brightness is changed. Thresholds are also changed. - thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(1)); - fake_als_reader_.ReportAmbientLightUpdate(5); - thread_bundle_.RunUntilIdle(); + // Darkening is still possible. + ForwardTimeAndReportAls({1}); + EXPECT_EQ(test_observer_.num_changes(), 1); + CheckLogAvg({1, 2, 3, 4, 5}, + adapter_->GetCurrentLogAvgAlsForTesting().value()); + EXPECT_DOUBLE_EQ(adapter_->GetBrighteningThresholdForTesting(), + adapter_->GetCurrentLogAvgAlsForTesting().value() + 100); + EXPECT_DOUBLE_EQ(adapter_->GetDarkeningThresholdForTesting(), + adapter_->GetCurrentLogAvgAlsForTesting().value() - 0.00001); + + ForwardTimeAndReportAls({1}); EXPECT_EQ(test_observer_.num_changes(), 2); - expected_log_avg = ConvertToLog((20 + 21 + 15 + 5) / 4.0); - CheckAverageAndStdDev( - adapter_->GetAverageAmbientWithStdDevForTesting(thread_bundle_.NowTicks()) - .value(), - {20, 21, 15, 5}); - + CheckLogAvg({4, 4, 4, 1, 1}, + adapter_->GetCurrentLogAvgAlsForTesting().value()); EXPECT_DOUBLE_EQ(adapter_->GetBrighteningThresholdForTesting(), - expected_log_avg + 1); + adapter_->GetCurrentLogAvgAlsForTesting().value() + 100); EXPECT_DOUBLE_EQ(adapter_->GetDarkeningThresholdForTesting(), - expected_log_avg - 0.2); + adapter_->GetCurrentLogAvgAlsForTesting().value() - 0.00001); +} - thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(1)); - fake_als_reader_.ReportAmbientLightUpdate(8); - thread_bundle_.RunUntilIdle(); - CheckAverageAndStdDev( - adapter_->GetAverageAmbientWithStdDevForTesting(thread_bundle_.NowTicks()) - .value(), - {20, 21, 15, 5, 8}); +// Set |darkening_log_lux_threshold| to a very high value to effectively make +// darkening impossible. +TEST_F(AdapterTest, DarkeningThreshold) { + std::map<std::string, std::string> params = default_params_; + params["darkening_log_lux_threshold"] = "100"; + Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess, + global_curve_, personal_curve_, GetTestModelConfig(), params); - thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(1)); - fake_als_reader_.ReportAmbientLightUpdate(9); - thread_bundle_.RunUntilIdle(); + ForwardTimeAndReportAls({10, 20, 30, 40}); + EXPECT_EQ(test_observer_.num_changes(), 0); + ForwardTimeAndReportAls({50}); + EXPECT_EQ(test_observer_.num_changes(), 1); + CheckLogAvg({10, 20, 30, 40, 50}, + adapter_->GetCurrentLogAvgAlsForTesting().value()); + EXPECT_DOUBLE_EQ(adapter_->GetBrighteningThresholdForTesting(), + adapter_->GetCurrentLogAvgAlsForTesting().value() + 0.00001); + EXPECT_DOUBLE_EQ(adapter_->GetDarkeningThresholdForTesting(), + adapter_->GetCurrentLogAvgAlsForTesting().value() - 100); - CheckAverageAndStdDev( - adapter_->GetAverageAmbientWithStdDevForTesting(thread_bundle_.NowTicks()) - .value(), - {21, 15, 5, 8, 9}); + ForwardTimeAndReportAls({29, 29, 29, 29, 29}); + EXPECT_EQ(test_observer_.num_changes(), 1); + CheckLogAvg({10, 20, 30, 40, 50}, + adapter_->GetCurrentLogAvgAlsForTesting().value()); + EXPECT_DOUBLE_EQ(adapter_->GetBrighteningThresholdForTesting(), + adapter_->GetCurrentLogAvgAlsForTesting().value() + 0.00001); + EXPECT_DOUBLE_EQ(adapter_->GetDarkeningThresholdForTesting(), + adapter_->GetCurrentLogAvgAlsForTesting().value() - 100); + + ForwardTimeAndReportAls({40}); + CheckLogAvg({29, 29, 29, 29, 40}, + adapter_->GetCurrentLogAvgAlsForTesting().value()); + EXPECT_DOUBLE_EQ(adapter_->GetBrighteningThresholdForTesting(), + adapter_->GetCurrentLogAvgAlsForTesting().value() + 0.00001); + EXPECT_DOUBLE_EQ(adapter_->GetDarkeningThresholdForTesting(), + adapter_->GetCurrentLogAvgAlsForTesting().value() - 100); +} + +// Set |stabilization_threshold| to a very low value so that the average really +// should have little fluctuations before we change brightness. +TEST_F(AdapterTest, StablizationThreshold) { + std::map<std::string, std::string> params = default_params_; + params["stabilization_threshold"] = "0.00001"; + Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess, + global_curve_, personal_curve_, GetTestModelConfig(), params); + + ForwardTimeAndReportAls({10, 20, 30, 40, 50}); + EXPECT_EQ(test_observer_.num_changes(), 1); + CheckLogAvg({10, 20, 30, 40, 50}, + adapter_->GetCurrentLogAvgAlsForTesting().value()); + + // A slight fluctuation means brightness is not changed. + ForwardTimeAndReportAls({29, 29, 29, 29, 28}); + EXPECT_EQ(test_observer_.num_changes(), 1); + CheckLogAvg({10, 20, 30, 40, 50}, + adapter_->GetCurrentLogAvgAlsForTesting().value()); + + ForwardTimeAndReportAls({28, 28, 28, 28}); + EXPECT_EQ(test_observer_.num_changes(), 2); + CheckLogAvg({28, 28, 28, 28, 28}, + adapter_->GetCurrentLogAvgAlsForTesting().value()); +} + +// Shorten |auto_brightness_als_horizon| to 1 second. Averaging period is +// shorter and |stabilization_threshold| is ineffective in regularizing +// stabilization. +TEST_F(AdapterTest, AlsHorizon) { + std::map<std::string, std::string> params = default_params_; + params["auto_brightness_als_horizon_seconds"] = "1"; + // Small |stabilization_threshold|. + params["stabilization_threshold"] = "0.00001"; + Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess, + global_curve_, personal_curve_, GetTestModelConfig(), params); + + ForwardTimeAndReportAls({10}); + EXPECT_EQ(test_observer_.num_changes(), 1); + CheckLogAvg({10}, adapter_->GetCurrentLogAvgAlsForTesting().value()); + + ForwardTimeAndReportAls({100}); + EXPECT_EQ(test_observer_.num_changes(), 2); + CheckLogAvg({100}, adapter_->GetCurrentLogAvgAlsForTesting().value()); + + ForwardTimeAndReportAls({2}); + EXPECT_EQ(test_observer_.num_changes(), 3); + CheckLogAvg({2}, adapter_->GetCurrentLogAvgAlsForTesting().value()); } TEST_F(AdapterTest, UsePersonalCurve) { @@ -679,33 +897,32 @@ EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess); - // ALS comes in but no brightness change is triggered because there is no - // personal curve. - thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(1)); - fake_als_reader_.ReportAmbientLightUpdate(10); - thread_bundle_.RunUntilIdle(); + // Sufficient ALS data has come in but no brightness change is triggered + // because there is no personal curve. + ForwardTimeAndReportAls({1, 2, 3, 4, 5, 6, 7, 8}); EXPECT_EQ(test_observer_.num_changes(), 0); + EXPECT_EQ(adapter_->GetCurrentLogAvgAlsForTesting(), base::nullopt); - // Personal curve is received. + // Personal curve is received, it does not lead to any immediate brightness + // change. thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(1)); fake_modeller_.ReportModelTrained(*personal_curve_); EXPECT_EQ(test_observer_.num_changes(), 0); - fake_als_reader_.ReportAmbientLightUpdate(20); - thread_bundle_.RunUntilIdle(); + EXPECT_EQ(adapter_->GetCurrentLogAvgAlsForTesting(), base::nullopt); + + // Another ALS comes in, which triggers a brightness change. + ReportAls(20); EXPECT_EQ(test_observer_.num_changes(), 1); EXPECT_EQ(test_observer_.GetCause(), power_manager::BacklightBrightnessChange_Cause_MODEL); - const double expected_log_avg = ConvertToLog((10 + 20) / 2.0); - CheckAverageAndStdDev( - adapter_->GetAverageAmbientWithStdDevForTesting(thread_bundle_.NowTicks()) - .value(), - {10, 20}); + CheckLogAvg({5, 6, 7, 8, 20}, + adapter_->GetCurrentLogAvgAlsForTesting().value()); - const double expected_brightness_percent = - personal_curve_->Interpolate(expected_log_avg); + // Brightness is changed according to the personal curve. EXPECT_DOUBLE_EQ(test_observer_.GetBrightnessPercent(), - expected_brightness_percent); + personal_curve_->Interpolate( + adapter_->GetCurrentLogAvgAlsForTesting().value())); } TEST_F(AdapterTest, UseGlobalCurve) { @@ -717,39 +934,28 @@ EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess); - thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(1)); - fake_als_reader_.ReportAmbientLightUpdate(10); - thread_bundle_.RunUntilIdle(); + ForwardTimeAndReportAls({1, 2, 3, 4, 5}); EXPECT_EQ(test_observer_.num_changes(), 1); - const double expected_log_avg1 = ConvertToLog(10); - CheckAverageAndStdDev( - adapter_->GetAverageAmbientWithStdDevForTesting(thread_bundle_.NowTicks()) - .value(), - {10}); + CheckLogAvg({1, 2, 3, 4, 5}, + adapter_->GetCurrentLogAvgAlsForTesting().value()); - const double expected_brightness_percent1 = - global_curve_->Interpolate(expected_log_avg1); + // Brightness is changed according to the global curve. EXPECT_DOUBLE_EQ(test_observer_.GetBrightnessPercent(), - expected_brightness_percent1); + global_curve_->Interpolate( + adapter_->GetCurrentLogAvgAlsForTesting().value())); // A new personal curve is received but adapter still uses the global curve. thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(20)); fake_modeller_.ReportModelTrained(*personal_curve_); - fake_als_reader_.ReportAmbientLightUpdate(20); - thread_bundle_.RunUntilIdle(); + ReportAls(20); EXPECT_EQ(test_observer_.num_changes(), 2); EXPECT_EQ(test_observer_.GetCause(), power_manager::BacklightBrightnessChange_Cause_MODEL); - const double expected_log_avg2 = ConvertToLog(20); - CheckAverageAndStdDev( - adapter_->GetAverageAmbientWithStdDevForTesting(thread_bundle_.NowTicks()) - .value(), - {20}); - const double expected_brightness_percent2 = - global_curve_->Interpolate(expected_log_avg2); + // Brightness is changed according to the global curve. EXPECT_DOUBLE_EQ(test_observer_.GetBrightnessPercent(), - expected_brightness_percent2); + global_curve_->Interpolate( + adapter_->GetCurrentLogAvgAlsForTesting().value())); } TEST_F(AdapterTest, BrightnessSetByPolicy) { @@ -759,10 +965,9 @@ EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess); - thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(1)); - fake_als_reader_.ReportAmbientLightUpdate(10); - thread_bundle_.RunUntilIdle(); + ForwardTimeAndReportAls({1, 2, 3, 4, 5, 6, 7, 8}); EXPECT_EQ(test_observer_.num_changes(), 0); + EXPECT_EQ(adapter_->GetCurrentLogAvgAlsForTesting(), base::nullopt); } TEST_F(AdapterTest, FeatureDisabled) { @@ -773,17 +978,16 @@ global_curve_, personal_curve_, GetTestModelConfig(), empty_params); EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kDisabled); + // Global and personal curves are received, but they won't be used to change // brightness. EXPECT_TRUE(adapter_->GetGlobalCurveForTesting()); EXPECT_TRUE(adapter_->GetPersonalCurveForTesting()); - thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(1)); - - // Brightness not changed after the 1st ALS reading comes in. - fake_als_reader_.ReportAmbientLightUpdate(10); - thread_bundle_.RunUntilIdle(); + // No brightness is changed. + ForwardTimeAndReportAls({1, 2, 3, 4, 5, 6, 7, 8}); EXPECT_EQ(test_observer_.num_changes(), 0); + EXPECT_EQ(adapter_->GetCurrentLogAvgAlsForTesting(), base::nullopt); } TEST_F(AdapterTest, FeatureEnabledForAtlas) { @@ -799,11 +1003,10 @@ EXPECT_TRUE(adapter_->GetGlobalCurveForTesting()); EXPECT_TRUE(adapter_->GetPersonalCurveForTesting()); - thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(1)); - - fake_als_reader_.ReportAmbientLightUpdate(10); - thread_bundle_.RunUntilIdle(); + ForwardTimeAndReportAls({1, 2, 3, 4, 5}); EXPECT_EQ(test_observer_.num_changes(), 1); + CheckLogAvg({1, 2, 3, 4, 5}, + adapter_->GetCurrentLogAvgAlsForTesting().value()); } TEST_F(AdapterTest, ValidParameters) { @@ -825,8 +1028,47 @@ static_cast<int>(ParameterError::kAdapterError), 1); } +TEST_F(AdapterTest, UserAdjustmentEffectDisable) { + // |default_params_| sets the effect to disable. + Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess, + global_curve_, personal_curve_, GetTestModelConfig(), default_params_); + + EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess); + EXPECT_TRUE(adapter_->GetGlobalCurveForTesting()); + EXPECT_EQ(*adapter_->GetGlobalCurveForTesting(), *global_curve_); + EXPECT_TRUE(adapter_->GetPersonalCurveForTesting()); + EXPECT_EQ(*adapter_->GetPersonalCurveForTesting(), *personal_curve_); + + // Brightness is changed for the 1st time. + ForwardTimeAndReportAls({1, 2, 3, 4, 5}); + EXPECT_EQ(test_observer_.num_changes(), 1); + CheckLogAvg({1, 2, 3, 4, 5}, + adapter_->GetCurrentLogAvgAlsForTesting().value()); + + // Adapter will not be applied after a user manual adjustment. + ReportUserBrightnessChangeRequest(20.0, 30.0); + EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess); + EXPECT_FALSE(adapter_->IsAppliedForTesting()); + + ForwardTimeAndReportAls({6, 7, 8, 9, 10, 11}); + EXPECT_EQ(test_observer_.num_changes(), 1); + CheckLogAvg({1, 2, 3, 4, 5}, + adapter_->GetCurrentLogAvgAlsForTesting().value()); + + // SuspendDone is received, which does not enable Adapter. + ReportSuspendDone(); + EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess); + EXPECT_FALSE(adapter_->IsAppliedForTesting()); + + ForwardTimeAndReportAls({11, 12, 13, 14, 15, 16}); + EXPECT_EQ(test_observer_.num_changes(), 1); + CheckLogAvg({1, 2, 3, 4, 5}, + adapter_->GetCurrentLogAvgAlsForTesting().value()); +} + TEST_F(AdapterTest, UserAdjustmentEffectPause) { std::map<std::string, std::string> params = default_params_; + // UserAdjustmentEffect::kPauseAuto = 1. params["user_adjustment_effect"] = "1"; Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess, @@ -838,44 +1080,67 @@ EXPECT_TRUE(adapter_->GetPersonalCurveForTesting()); EXPECT_EQ(*adapter_->GetPersonalCurveForTesting(), *personal_curve_); - thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(1)); - - // Brightness is changed after the 1st ALS reading comes in. - fake_als_reader_.ReportAmbientLightUpdate(10); - thread_bundle_.RunUntilIdle(); + // Brightness is changed for the 1st time. + ForwardTimeAndReportAls({1, 2, 3, 4, 5}); EXPECT_EQ(test_observer_.num_changes(), 1); + CheckLogAvg({1, 2, 3, 4, 5}, + adapter_->GetCurrentLogAvgAlsForTesting().value()); - // Adapter will not be applied after a user manual adjustment. - fake_brightness_monitor_.ReportUserBrightnessChangeRequested(); - thread_bundle_.RunUntilIdle(); + // User manually changes brightness so that adapter will not be applied. + ReportUserBrightnessChangeRequest(20.0, 30.0); EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess); EXPECT_FALSE(adapter_->IsAppliedForTesting()); - // SuspendDone is received, which reenables Adapter. + // New ALS data will not trigger brightness update. + ForwardTimeAndReportAls({101, 102, 103, 104, 105, 106, 107, 108}); + EXPECT_EQ(test_observer_.num_changes(), 1); + CheckLogAvg({1, 2, 3, 4, 5}, + adapter_->GetCurrentLogAvgAlsForTesting().value()); + + // // SuspendDone is received, which reenables adapter. ReportSuspendDone(); EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess); EXPECT_TRUE(adapter_->IsAppliedForTesting()); - thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(1)); - fake_als_reader_.ReportAmbientLightUpdate(30); - thread_bundle_.RunUntilIdle(); + // Another ALS results in a brightness change. + ForwardTimeAndReportAls({109}); EXPECT_EQ(test_observer_.num_changes(), 2); + CheckLogAvg({105, 106, 107, 108, 109}, + adapter_->GetCurrentLogAvgAlsForTesting().value()); - // Another user manual adjustment that stops Adapter from being applied. - fake_brightness_monitor_.ReportUserBrightnessChangeRequested(); - thread_bundle_.RunUntilIdle(); + // Another user brightness change. + ReportUserBrightnessChangeRequest(40.0, 50.0); + CheckLogAvg({105, 106, 107, 108, 109}, + adapter_->GetCurrentLogAvgAlsForTesting().value()); EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess); EXPECT_FALSE(adapter_->IsAppliedForTesting()); - // Brightness is not changed after another ALS reading comes in. - thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(1)); - fake_als_reader_.ReportAmbientLightUpdate(60); - thread_bundle_.RunUntilIdle(); + // New ALS data will not trigger brightness update. + ForwardTimeAndReportAls({200}); EXPECT_EQ(test_observer_.num_changes(), 2); + CheckLogAvg({105, 106, 107, 108, 109}, + adapter_->GetCurrentLogAvgAlsForTesting().value()); + + // SuspendDone is received, which reenables adapter. + ReportSuspendDone(); + EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess); + EXPECT_TRUE(adapter_->IsAppliedForTesting()); + + // Als readings come in but not sufficient time since user changed brightness. + ForwardTimeAndReportAls({201, 202, 203}); + EXPECT_EQ(test_observer_.num_changes(), 2); + CheckLogAvg({105, 106, 107, 108, 109}, + adapter_->GetCurrentLogAvgAlsForTesting().value()); + + ForwardTimeAndReportAls({204}); + EXPECT_EQ(test_observer_.num_changes(), 3); + CheckLogAvg({200, 201, 202, 203, 204}, + adapter_->GetCurrentLogAvgAlsForTesting().value()); } TEST_F(AdapterTest, UserAdjustmentEffectContinue) { std::map<std::string, std::string> params = default_params_; + // UserAdjustmentEffect::kContinueAuto = 2. params["user_adjustment_effect"] = "2"; Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess, @@ -887,33 +1152,37 @@ EXPECT_TRUE(adapter_->GetPersonalCurveForTesting()); EXPECT_EQ(*adapter_->GetPersonalCurveForTesting(), *personal_curve_); - thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(1)); - - // Brightness is changed after the 1st ALS reading comes in. - fake_als_reader_.ReportAmbientLightUpdate(10); - thread_bundle_.RunUntilIdle(); + // Brightness is changed for the 1st time. + ForwardTimeAndReportAls({1, 2, 3, 4, 5}); EXPECT_EQ(test_observer_.num_changes(), 1); + CheckLogAvg({1, 2, 3, 4, 5}, + adapter_->GetCurrentLogAvgAlsForTesting().value()); - // User manual adjustment doesn't disable Adapter. - fake_brightness_monitor_.ReportUserBrightnessChangeRequested(); - thread_bundle_.RunUntilIdle(); + ForwardTimeAndReportAls({10}); + // User manual adjustment doesn't disable adapter. + ReportUserBrightnessChangeRequest(40.0, 50.0); + CheckLogAvg({2, 3, 4, 5, 10}, + adapter_->GetCurrentLogAvgAlsForTesting().value()); + EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess); EXPECT_TRUE(adapter_->IsAppliedForTesting()); - // Brightness is changed again after another ALS reading comes in. - thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(1)); - fake_als_reader_.ReportAmbientLightUpdate(30); - thread_bundle_.RunUntilIdle(); + ForwardTimeAndReportAls({100, 101, 102, 103}); + CheckLogAvg({2, 3, 4, 5, 10}, + adapter_->GetCurrentLogAvgAlsForTesting().value()); + + ForwardTimeAndReportAls({104}); EXPECT_EQ(test_observer_.num_changes(), 2); + CheckLogAvg({100, 101, 102, 103, 104}, + adapter_->GetCurrentLogAvgAlsForTesting().value()); } // Default user adjustment effect for atlas is Continue. TEST_F(AdapterTest, UserAdjustmentEffectContinueDefaultForAtlas) { - const std::map<std::string, std::string> params = { - {"brightening_log_lux_threshold", "0.1"}, - {"darkening_log_lux_threshold", "0.2"}, - {"model_curve", "2"}, - }; + std::map<std::string, std::string> params = default_params_; + // User adjustment effect for Atlas is only Continue when it's not explicitly + // set by the finch params. + params.erase("user_adjustment_effect"); Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess, global_curve_, personal_curve_, GetTestModelConfig("atlas"), params); @@ -924,24 +1193,29 @@ EXPECT_TRUE(adapter_->GetPersonalCurveForTesting()); EXPECT_EQ(*adapter_->GetPersonalCurveForTesting(), *personal_curve_); - thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(1)); - - // Brightness is changed after the 1st ALS reading comes in. - fake_als_reader_.ReportAmbientLightUpdate(10); - thread_bundle_.RunUntilIdle(); + // Brightness is changed for the 1st time. + ForwardTimeAndReportAls({1, 2, 3, 4, 5}); EXPECT_EQ(test_observer_.num_changes(), 1); + CheckLogAvg({1, 2, 3, 4, 5}, + adapter_->GetCurrentLogAvgAlsForTesting().value()); - // User manual adjustment doesn't disable Adapter. - fake_brightness_monitor_.ReportUserBrightnessChangeRequested(); - thread_bundle_.RunUntilIdle(); + ForwardTimeAndReportAls({10}); + // User manual adjustment doesn't disable adapter. + ReportUserBrightnessChangeRequest(40.0, 50.0); + CheckLogAvg({2, 3, 4, 5, 10}, + adapter_->GetCurrentLogAvgAlsForTesting().value()); + EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess); EXPECT_TRUE(adapter_->IsAppliedForTesting()); - // Brightness is changed again after another ALS reading comes in. - thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(1)); - fake_als_reader_.ReportAmbientLightUpdate(30); - thread_bundle_.RunUntilIdle(); + ForwardTimeAndReportAls({100, 101, 102, 103}); + CheckLogAvg({2, 3, 4, 5, 10}, + adapter_->GetCurrentLogAvgAlsForTesting().value()); + + ForwardTimeAndReportAls({104}); EXPECT_EQ(test_observer_.num_changes(), 2); + CheckLogAvg({100, 101, 102, 103, 104}, + adapter_->GetCurrentLogAvgAlsForTesting().value()); } } // namespace auto_screen_brightness
diff --git a/chrome/browser/data_reduction_proxy/data_reduction_proxy_browsertest.cc b/chrome/browser/data_reduction_proxy/data_reduction_proxy_browsertest.cc index cca5246..260f582 100644 --- a/chrome/browser/data_reduction_proxy/data_reduction_proxy_browsertest.cc +++ b/chrome/browser/data_reduction_proxy/data_reduction_proxy_browsertest.cc
@@ -776,6 +776,30 @@ BYPASS_EVENT_TYPE_MALFORMED_407, 1); } +IN_PROC_BROWSER_TEST_F(DataReductionProxyFallbackBrowsertest, + ProxyBypassedForCurrentRequestOn502Error) { + base::HistogramTester histogram_tester; + net::EmbeddedTestServer test_server; + test_server.RegisterRequestHandler( + base::BindRepeating(&BasicResponse, kDummyBody)); + ASSERT_TRUE(test_server.Start()); + + SetStatusCode(net::HTTP_BAD_GATEWAY); + + ui_test_utils::NavigateToURL(browser(), + GetURLWithMockHost(test_server, "/echo")); + EXPECT_THAT(GetBody(), kDummyBody); + histogram_tester.ExpectUniqueSample( + "DataReductionProxy.BlockTypePrimary", + BYPASS_EVENT_TYPE_STATUS_502_HTTP_BAD_GATEWAY, 1); + + // Proxy should no longer be blocked, and use first proxy. + SetStatusCode(net::HTTP_OK); + ui_test_utils::NavigateToURL(browser(), + GetURLWithMockHost(test_server, "/echo")); + EXPECT_EQ(GetBody(), kPrimaryResponse); +} + // Tests that if using data reduction proxy results in redirect loop, then // the proxy is bypassed, and the request is fetched directly. IN_PROC_BROWSER_TEST_F(DataReductionProxyFallbackBrowsertest, RedirectCycle) {
diff --git a/chrome/browser/engagement/important_sites_util.cc b/chrome/browser/engagement/important_sites_util.cc index 366314d2..900f794 100644 --- a/chrome/browser/engagement/important_sites_util.cc +++ b/chrome/browser/engagement/important_sites_util.cc
@@ -15,6 +15,7 @@ #include "base/stl_util.h" #include "base/time/time.h" #include "base/values.h" +#include "build/build_config.h" #include "chrome/browser/banners/app_banner_settings_helper.h" #include "chrome/browser/bookmarks/bookmark_model_factory.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" @@ -32,8 +33,13 @@ #include "net/base/registry_controlled_domains/registry_controlled_domain.h" #include "third_party/blink/public/mojom/site_engagement/site_engagement.mojom.h" #include "url/gurl.h" +#include "url/origin.h" #include "url/url_util.h" +#if defined(OS_ANDROID) +#include "chrome/browser/android/search_permissions/search_permissions_service.h" +#endif + namespace { using bookmarks::BookmarkModel; using bookmarks::UrlAndTitle; @@ -274,14 +280,28 @@ HostContentSettingsMapFactory::GetForProfile(profile)->GetSettingsForOneType( content_type, content_settings::ResourceIdentifier(), &content_settings_list); + // Extract a set of urls, using the primary pattern. We don't handle // wildcard patterns. std::set<GURL> content_origins; for (const ContentSettingPatternSource& site : content_settings_list) { if (site.GetContentSetting() != CONTENT_SETTING_ALLOW) continue; - MaybePopulateImportantInfoForReason(GURL(site.primary_pattern.ToString()), - &content_origins, reason, output); + GURL url(site.primary_pattern.ToString()); + +#if defined(OS_ANDROID) + SearchPermissionsService* search_permissions_service = + SearchPermissionsService::Factory::GetInstance()->GetForBrowserContext( + profile); + // If the permission is controlled by the Default Search Engine then don't + // consider it important. The DSE gets these permissions by default. + if (search_permissions_service->IsPermissionControlledByDSE( + content_type, url::Origin::Create(url))) { + continue; + } +#endif + + MaybePopulateImportantInfoForReason(url, &content_origins, reason, output); } }
diff --git a/chrome/browser/extensions/bookmark_app_extension_util.cc b/chrome/browser/extensions/bookmark_app_extension_util.cc index 5675c05..5131b1d9 100644 --- a/chrome/browser/extensions/bookmark_app_extension_util.cc +++ b/chrome/browser/extensions/bookmark_app_extension_util.cc
@@ -30,6 +30,20 @@ namespace extensions { +namespace { + +#if !defined(OS_CHROMEOS) +bool CanOsAddDesktopShortcuts() { +#if defined(OS_LINUX) || defined(OS_WIN) + return true; +#else + return false; +#endif +} +#endif // !defined(OS_CHROMEOS) + +} // namespace + bool CanBookmarkAppCreateOsShortcuts() { #if defined(OS_CHROMEOS) return false; @@ -41,19 +55,18 @@ void BookmarkAppCreateOsShortcuts( Profile* profile, const Extension* extension, + bool add_to_desktop, base::OnceCallback<void(bool created_shortcuts)> callback) { DCHECK(CanBookmarkAppCreateOsShortcuts()); #if !defined(OS_CHROMEOS) web_app::ShortcutLocations creation_locations; -#if defined(OS_LINUX) || defined(OS_WIN) - creation_locations.on_desktop = true; -#else - creation_locations.on_desktop = false; -#endif creation_locations.applications_menu_location = web_app::APP_MENU_LOCATION_SUBDIR_CHROMEAPPS; creation_locations.in_quick_launch_bar = false; + if (CanOsAddDesktopShortcuts()) + creation_locations.on_desktop = add_to_desktop; + Profile* current_profile = profile->GetOriginalProfile(); web_app::CreateShortcuts(web_app::SHORTCUT_CREATION_BY_USER, creation_locations, current_profile, extension,
diff --git a/chrome/browser/extensions/bookmark_app_extension_util.h b/chrome/browser/extensions/bookmark_app_extension_util.h index fcde5da8..56ce30b 100644 --- a/chrome/browser/extensions/bookmark_app_extension_util.h +++ b/chrome/browser/extensions/bookmark_app_extension_util.h
@@ -21,6 +21,7 @@ void BookmarkAppCreateOsShortcuts( Profile* profile, const Extension* extension, + bool add_to_desktop, base::OnceCallback<void(bool created_shortcuts)> callback); bool CanBookmarkAppBePinnedToShelf();
diff --git a/chrome/browser/extensions/bookmark_app_helper.cc b/chrome/browser/extensions/bookmark_app_helper.cc index 8266f29..2521a96a 100644 --- a/chrome/browser/extensions/bookmark_app_helper.cc +++ b/chrome/browser/extensions/bookmark_app_helper.cc
@@ -463,9 +463,11 @@ web_app::RecordAppBanner(contents_, web_app_info_.app_url); - if (create_shortcuts_ && CanBookmarkAppCreateOsShortcuts()) { + // TODO(ortuno): Make adding a shortcut to the applications menu independent + // from adding a shortcut to desktop. + if (add_to_applications_menu_ && CanBookmarkAppCreateOsShortcuts()) { BookmarkAppCreateOsShortcuts( - profile_, extension, + profile_, extension, add_to_desktop_, base::BindOnce(&BookmarkAppHelper::OnShortcutCreationCompleted, weak_factory_.GetWeakPtr(), extension->id())); } else { @@ -486,7 +488,7 @@ return; } - if (create_shortcuts_ && CanBookmarkAppBePinnedToShelf()) + if (add_to_quick_launch_bar_ && CanBookmarkAppBePinnedToShelf()) BookmarkAppPinToShelf(extension); // If there is a browser, it means that the app is being installed in the
diff --git a/chrome/browser/extensions/bookmark_app_helper.h b/chrome/browser/extensions/bookmark_app_helper.h index 2805806..84abe2c5 100644 --- a/chrome/browser/extensions/bookmark_app_helper.h +++ b/chrome/browser/extensions/bookmark_app_helper.h
@@ -98,10 +98,25 @@ bool is_no_network_install() { return is_no_network_install_; } - // If called, desktop shortcuts will not be created. - void set_skip_shortcut_creation() { create_shortcuts_ = false; } + void set_skip_adding_to_applications_menu() { + add_to_applications_menu_ = false; + } - bool create_shortcuts() const { return create_shortcuts_; } + bool add_to_applications_menu() { return add_to_applications_menu_; } + + // If called, desktop shortcuts will not be created. Has no effect on + // platforms other than Linux and Windows. + void set_skip_adding_to_desktop() { add_to_desktop_ = false; } + + bool add_to_desktop() const { return add_to_desktop_; } + + // If called, the app will not be pinned to the shelf. Has no effect on + // platforms other than Chrome OS. + void set_skip_adding_to_quick_launch_bar() { + add_to_quick_launch_bar_ = false; + } + + bool add_to_quick_launch_bar() { return add_to_quick_launch_bar_; } // If called, the installability check won't test for a service worker. void set_bypass_service_worker_check() { @@ -198,7 +213,11 @@ // installation and we should not try to fetch a manifest. bool is_no_network_install_ = false; - bool create_shortcuts_ = true; + bool add_to_applications_menu_ = true; + + bool add_to_desktop_ = true; + + bool add_to_quick_launch_bar_ = true; bool bypass_service_worker_check_ = false;
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index f73303f1..1fcdaa8 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -1867,6 +1867,11 @@ "expiry_milestone": -1 }, { + "name": "enable-web-authentication-pin-support", + "owners": [ "webauthn-team@google.com" ], + "expiry_milestone": 77 + }, + { "name": "enable-webassembly", "owners": [ "titzer", "wasm-team@google.com" ], "expiry_milestone": 72
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index dc23d11..518c3ae 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -979,6 +979,12 @@ "Enable the cloud-assisted pairingless BLE protocol for use with " "the Web Authentication API."; +const char kEnableWebAuthenticationPINSupportName[] = + "Web Authentication PIN support"; +const char kEnableWebAuthenticationPINSupportDescription[] = + "Enable the use of PINs with the Web Authentication API and compatible " + "security keys."; + const char kEnableIncognitoWindowCounterName[] = "Incognito Window Counter"; const char kEnableIncognitoWindowCounterDescription[] = "Shows the count of Incognito windows next to the Incognito icon on the "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 487b1f5..a7be4ca09 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -589,6 +589,9 @@ extern const char kEnableWebAuthenticationCableSupportName[]; extern const char kEnableWebAuthenticationCableSupportDescription[]; +extern const char kEnableWebAuthenticationPINSupportName[]; +extern const char kEnableWebAuthenticationPINSupportDescription[]; + extern const char kEnableWebUsbName[]; extern const char kEnableWebUsbDescription[];
diff --git a/chrome/browser/resources/chromeos/login/screen_recommend_apps.js b/chrome/browser/resources/chromeos/login/screen_recommend_apps.js index 50cd1ed..9e1f9a2 100644 --- a/chrome/browser/resources/chromeos/login/screen_recommend_apps.js +++ b/chrome/browser/resources/chromeos/login/screen_recommend_apps.js
@@ -92,12 +92,6 @@ // Hide the loading throbber and show the recommend app list. this.setThrobberVisible(false); - // Disable install button until the webview reports that some apps are - // selected. - $('recommend-apps-screen') - .getElement('recommend-apps-install-button') - .disabled = true; - const appListView = this.getElement_('app-list-view'); const subtitle = this.getElement_('subtitle'); subtitle.innerText = loadTimeData.getStringF( @@ -188,4 +182,4 @@ $('recommend-apps-screen').hidden = visible; }, }; -}); +}); \ No newline at end of file
diff --git a/chrome/browser/ui/page_info/OWNERS b/chrome/browser/ui/page_info/OWNERS index 1df299f..d0ebc2a7 100644 --- a/chrome/browser/ui/page_info/OWNERS +++ b/chrome/browser/ui/page_info/OWNERS
@@ -1,10 +1,10 @@ # Please use for OWNERS code reviews benwells@chromium.org +engedy@chromium.org estark@chromium.org felt@chromium.org meacer@chromium.org patricialor@chromium.org -raymes@chromium.org # COMPONENT: UI>Browser>Bubbles>PageInfo # TEAM: security-enamel@chromium.org
diff --git a/chrome/browser/ui/views/page_info/OWNERS b/chrome/browser/ui/views/page_info/OWNERS index 39f0eac..72c5daf 100644 --- a/chrome/browser/ui/views/page_info/OWNERS +++ b/chrome/browser/ui/views/page_info/OWNERS
@@ -1,9 +1,4 @@ -benwells@chromium.org -estark@chromium.org -felt@chromium.org -meacer@chromium.org -patricialor@chromium.org -raymes@chromium.org +file://chrome/browser/ui/page_info/OWNERS # COMPONENT: UI>Browser>Bubbles>PageInfo # TEAM: security-enamel@chromium.org
diff --git a/chrome/browser/ui/web_applications/bookmark_app_browsertest.cc b/chrome/browser/ui/web_applications/bookmark_app_browsertest.cc index e821af2b..76399f9 100644 --- a/chrome/browser/ui/web_applications/bookmark_app_browsertest.cc +++ b/chrome/browser/ui/web_applications/bookmark_app_browsertest.cc
@@ -45,7 +45,9 @@ web_app::LaunchContainer::kWindow, web_app::InstallSource::kInternal); // Avoid creating real shortcuts in tests. - install_options.create_shortcuts = false; + install_options.add_to_applications_menu = false; + install_options.add_to_desktop = false; + install_options.add_to_quick_launch_bar = false; return install_options; }
diff --git a/chrome/browser/vr/model/capturing_state_model.h b/chrome/browser/vr/model/capturing_state_model.h index 367c960..6e5f0d25 100644 --- a/chrome/browser/vr/model/capturing_state_model.h +++ b/chrome/browser/vr/model/capturing_state_model.h
@@ -5,6 +5,8 @@ #ifndef CHROME_BROWSER_VR_MODEL_CAPTURING_STATE_MODEL_H_ #define CHROME_BROWSER_VR_MODEL_CAPTURING_STATE_MODEL_H_ +#include <string> + #include "chrome/browser/vr/vr_base_export.h" namespace vr { @@ -15,6 +17,24 @@ bool screen_capture_enabled = false; bool location_access_enabled = false; bool bluetooth_connected = false; + + bool operator==(const CapturingStateModel& rhs) const { + return audio_capture_enabled == rhs.audio_capture_enabled && + video_capture_enabled == rhs.video_capture_enabled && + screen_capture_enabled == rhs.screen_capture_enabled && + location_access_enabled == rhs.location_access_enabled && + bluetooth_connected == rhs.bluetooth_connected; + } + + bool operator!=(const CapturingStateModel& rhs) const { + return !(*this == rhs); + } + + bool IsAnyCapturingEnabled() const { + return audio_capture_enabled || video_capture_enabled || + screen_capture_enabled || location_access_enabled || + bluetooth_connected; + } }; typedef bool CapturingStateModel::*CapturingStateModelMemberPtr;
diff --git a/chrome/browser/vr/ui_host/vr_ui_host_impl.cc b/chrome/browser/vr/ui_host/vr_ui_host_impl.cc index 73ed60b..0febaa4 100644 --- a/chrome/browser/vr/ui_host/vr_ui_host_impl.cc +++ b/chrome/browser/vr/ui_host/vr_ui_host_impl.cc
@@ -7,18 +7,21 @@ #include <memory> #include "base/task/post_task.h" +#include "chrome/browser/content_settings/tab_specific_content_settings.h" +#include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h" +#include "chrome/browser/media/webrtc/media_stream_capture_indicator.h" +#include "chrome/browser/permissions/permission_manager.h" +#include "chrome/browser/permissions/permission_result.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ssl/security_state_tab_helper.h" #include "chrome/browser/vr/metrics/session_metrics_helper.h" #include "chrome/browser/vr/service/browser_xr_runtime.h" #include "chrome/browser/vr/service/xr_runtime_manager.h" #include "chrome/browser/vr/vr_tab_helper.h" #include "chrome/browser/vr/win/vr_browser_renderer_thread_win.h" -#include "components/strings/grit/components_strings.h" -#include "content/public/browser/navigation_controller.h" #include "content/public/browser/navigation_entry.h" -#include "content/public/browser/render_process_host.h" -#include "content/public/browser/render_view_host.h" +#include "content/public/common/service_manager_connection.h" +#include "services/device/public/mojom/constants.mojom.h" +#include "services/service_manager/public/cpp/connector.h" #include "ui/base/l10n/l10n_util.h" namespace vr { @@ -26,11 +29,18 @@ namespace { static constexpr base::TimeDelta kPermissionPromptTimeout = base::TimeDelta::FromSeconds(5); + +static constexpr base::TimeDelta kPollCapturingStateInterval = + base::TimeDelta::FromSecondsD(0.2); + +const CapturingStateModel g_default_capturing_state; } // namespace VRUiHostImpl::VRUiHostImpl(device::mojom::XRDeviceId device_id, device::mojom::XRCompositorHostPtr compositor) - : compositor_(std::move(compositor)), weak_ptr_factory_(this) { + : compositor_(std::move(compositor)), + main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()), + weak_ptr_factory_(this) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DVLOG(1) << __func__; @@ -39,6 +49,10 @@ if (runtime) { runtime->AddObserver(this); } + + auto* connector = + content::ServiceManagerConnection::GetForProcess()->GetConnector(); + connector->BindInterface(device::mojom::kServiceName, &geolocation_config_); } VRUiHostImpl::~VRUiHostImpl() { @@ -109,8 +123,11 @@ web_contents_ = contents; if (contents) { StartUiRendering(); + InitCapturingStates(); ui_rendering_thread_->SetWebXrPresenting(true); + PollCapturingState(); + PermissionRequestManager::CreateForWebContents(contents); permission_request_manager_ = PermissionRequestManager::FromWebContents(contents); @@ -129,6 +146,8 @@ DVLOG(1) << __func__ << ": No PermissionRequestManager"; } } else { + poll_capturing_state_task_.Cancel(); + if (ui_rendering_thread_) ui_rendering_thread_->SetWebXrPresenting(false); StopUiRendering(); @@ -159,6 +178,7 @@ void VRUiHostImpl::StopUiRendering() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DVLOG(1) << __func__; + ui_rendering_thread_ = nullptr; } @@ -185,30 +205,130 @@ SetLocationInfoOnUi(); + if (indicators_visible_) { + indicators_visible_ = false; + ui_rendering_thread_->SetIndicatorsVisible(false); + } + ui_rendering_thread_->SetVisibleExternalPromptNotification( ExternalPromptNotificationType::kPromptGenericPermission); - is_prompt_showing_in_headset_ = true; - current_prompt_sequence_num_++; - base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, - base::BindOnce(&VRUiHostImpl::RemoveHeadsetNotificationPrompt, - weak_ptr_factory_.GetWeakPtr(), - current_prompt_sequence_num_), + is_external_prompt_showing_in_headset_ = true; + external_prompt_timeout_task_.Reset( + base::BindRepeating(&VRUiHostImpl::RemoveHeadsetNotificationPrompt, + weak_ptr_factory_.GetWeakPtr())); + main_thread_task_runner_->PostDelayedTask( + FROM_HERE, external_prompt_timeout_task_.callback(), kPermissionPromptTimeout); } void VRUiHostImpl::OnBubbleRemoved() { - RemoveHeadsetNotificationPrompt(current_prompt_sequence_num_); + external_prompt_timeout_task_.Cancel(); + RemoveHeadsetNotificationPrompt(); } -void VRUiHostImpl::RemoveHeadsetNotificationPrompt(int prompt_sequence_num) { - if (!is_prompt_showing_in_headset_) +void VRUiHostImpl::RemoveHeadsetNotificationPrompt() { + if (!is_external_prompt_showing_in_headset_) return; - if (prompt_sequence_num != current_prompt_sequence_num_) - return; - is_prompt_showing_in_headset_ = false; + is_external_prompt_showing_in_headset_ = false; ui_rendering_thread_->SetVisibleExternalPromptNotification( ExternalPromptNotificationType::kPromptNone); + indicators_shown_start_time_ = base::Time::Now(); } + +void VRUiHostImpl::InitCapturingStates() { + active_capturing_ = g_default_capturing_state; + potential_capturing_ = g_default_capturing_state; + + DCHECK(web_contents_); + PermissionManager* permission_manager = PermissionManager::Get( + Profile::FromBrowserContext(web_contents_->GetBrowserContext())); + const GURL& origin = web_contents_->GetLastCommittedURL(); + content::RenderFrameHost* rfh = web_contents_->GetMainFrame(); + potential_capturing_.audio_capture_enabled = + permission_manager + ->GetPermissionStatusForFrame( + ContentSettingsType::CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, rfh, + origin) + .content_setting == CONTENT_SETTING_ALLOW; + potential_capturing_.video_capture_enabled = + permission_manager + ->GetPermissionStatusForFrame( + ContentSettingsType::CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, + rfh, origin) + .content_setting == CONTENT_SETTING_ALLOW; + potential_capturing_.location_access_enabled = + permission_manager + ->GetPermissionStatusForFrame( + ContentSettingsType::CONTENT_SETTINGS_TYPE_GEOLOCATION, rfh, + origin) + .content_setting == CONTENT_SETTING_ALLOW; + + indicators_shown_start_time_ = base::Time::Now(); + indicators_visible_ = false; +} + +void VRUiHostImpl::PollCapturingState() { + poll_capturing_state_task_.Reset(base::BindRepeating( + &VRUiHostImpl::PollCapturingState, base::Unretained(this))); + main_thread_task_runner_->PostDelayedTask( + FROM_HERE, poll_capturing_state_task_.callback(), + kPollCapturingStateInterval); + + // Microphone, Camera, location. + CapturingStateModel active_capturing = active_capturing_; + TabSpecificContentSettings* settings = + TabSpecificContentSettings::FromWebContents(web_contents_); + if (settings) { + const ContentSettingsUsagesState& usages_state = + settings->geolocation_usages_state(); + if (!usages_state.state_map().empty()) { + unsigned int state_flags = 0; + usages_state.GetDetailedInfo(nullptr, &state_flags); + active_capturing.location_access_enabled = !!( + state_flags & ContentSettingsUsagesState::TABSTATE_HAS_ANY_ALLOWED); + } + active_capturing.audio_capture_enabled = + (settings->GetMicrophoneCameraState() & + TabSpecificContentSettings::MICROPHONE_ACCESSED) && + !(settings->GetMicrophoneCameraState() & + TabSpecificContentSettings::MICROPHONE_BLOCKED); + active_capturing.video_capture_enabled = + (settings->GetMicrophoneCameraState() & + TabSpecificContentSettings::CAMERA_ACCESSED) & + !(settings->GetMicrophoneCameraState() & + TabSpecificContentSettings::CAMERA_BLOCKED); + } + + // Screen capture, bluetooth. + scoped_refptr<MediaStreamCaptureIndicator> indicator = + MediaCaptureDevicesDispatcher::GetInstance() + ->GetMediaStreamCaptureIndicator(); + active_capturing.screen_capture_enabled = + indicator->IsBeingMirrored(web_contents_); + active_capturing.bluetooth_connected = + web_contents_->IsConnectedToBluetoothDevice(); + + if (active_capturing_ != active_capturing) { + indicators_shown_start_time_ = base::Time::Now(); + } + + active_capturing_ = active_capturing; + ui_rendering_thread_->SetCapturingState( + active_capturing_, g_default_capturing_state, potential_capturing_); + + if (indicators_shown_start_time_ + kPermissionPromptTimeout > + base::Time::Now()) { + if (!indicators_visible_ && !is_external_prompt_showing_in_headset_) { + indicators_visible_ = true; + ui_rendering_thread_->SetIndicatorsVisible(true); + } + } else { + if (indicators_visible_) { + indicators_visible_ = false; + ui_rendering_thread_->SetIndicatorsVisible(false); + } + } +} + } // namespace vr
diff --git a/chrome/browser/vr/ui_host/vr_ui_host_impl.h b/chrome/browser/vr/ui_host/vr_ui_host_impl.h index 03f3bd8..07d12bb 100644 --- a/chrome/browser/vr/ui_host/vr_ui_host_impl.h +++ b/chrome/browser/vr/ui_host/vr_ui_host_impl.h
@@ -5,13 +5,17 @@ #ifndef CHROME_BROWSER_VR_UI_HOST_VR_UI_HOST_IMPL_H_ #define CHROME_BROWSER_VR_UI_HOST_VR_UI_HOST_IMPL_H_ +#include "base/callback.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" +#include "base/single_thread_task_runner.h" #include "base/threading/thread_checker.h" #include "chrome/browser/permissions/permission_request_manager.h" +#include "chrome/browser/vr/model/capturing_state_model.h" #include "chrome/browser/vr/service/browser_xr_runtime.h" #include "chrome/browser/vr/service/vr_ui_host.h" #include "content/public/browser/web_contents.h" +#include "services/device/public/mojom/geolocation_config.mojom.h" namespace vr { @@ -46,17 +50,28 @@ void OnBubbleAdded() override; void OnBubbleRemoved() override; - void RemoveHeadsetNotificationPrompt(int prompt_sequence_num); + void RemoveHeadsetNotificationPrompt(); void SetLocationInfoOnUi(); + void InitCapturingStates(); + void PollCapturingState(); + device::mojom::XRCompositorHostPtr compositor_; std::unique_ptr<VRBrowserRendererThreadWin> ui_rendering_thread_; device::mojom::VRDisplayInfoPtr info_; content::WebContents* web_contents_ = nullptr; PermissionRequestManager* permission_request_manager_ = nullptr; + scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_; - bool is_prompt_showing_in_headset_ = false; - int current_prompt_sequence_num_ = 0; + base::CancelableClosure external_prompt_timeout_task_; + bool is_external_prompt_showing_in_headset_ = false; + + CapturingStateModel active_capturing_; + CapturingStateModel potential_capturing_; + device::mojom::GeolocationConfigPtr geolocation_config_; + base::CancelableClosure poll_capturing_state_task_; + base::Time indicators_shown_start_time_; + bool indicators_visible_ = false; THREAD_CHECKER(thread_checker_);
diff --git a/chrome/browser/vr/ui_scene_creator.cc b/chrome/browser/vr/ui_scene_creator.cc index 984ddb62..58329c02c 100644 --- a/chrome/browser/vr/ui_scene_creator.cc +++ b/chrome/browser/vr/ui_scene_creator.cc
@@ -685,8 +685,9 @@ std::unique_ptr<UiElement> CreateWebVrIndicator(Model* model, UiBrowserInterface* browser, - IndicatorSpec spec) { - auto container = Create<Rect>(spec.webvr_name, kPhaseOverlayForeground); + IndicatorSpec spec, + DrawPhase phase) { + auto container = Create<Rect>(spec.webvr_name, phase); VR_BIND_COLOR(model, container.get(), &ColorScheme::webvr_permission_background, &Rect::SetColor); container->set_corner_radius(kWebVrPermissionCornerRadius); @@ -699,7 +700,7 @@ auto layout = Create<LinearLayout>(kNone, kPhaseNone, LinearLayout::kRight); layout->set_margin(kWebVrPermissionMargin); - auto icon_element = Create<VectorIcon>(kNone, kPhaseOverlayForeground, 128); + auto icon_element = Create<VectorIcon>(kNone, phase, 128); VR_BIND_COLOR(model, icon_element.get(), &ColorScheme::webvr_permission_foreground, &VectorIcon::SetColor); @@ -717,12 +718,12 @@ std::unique_ptr<UiElement> description_element; if (spec.is_url) { auto url_text = Create<UrlText>( - kNone, kPhaseOverlayForeground, kWebVrPermissionFontHeight, + kNone, phase, kWebVrPermissionFontHeight, base::BindRepeating(&UiBrowserInterface::OnUnsupportedMode, base::Unretained(browser), UiUnsupportedMode::kUnhandledCodePoint) - ); + ); url_text->SetFieldWidth(kWebVrPermissionTextWidth); url_text->AddBinding(VR_BIND_FUNC(GURL, Model, model, model->location_bar_state.gurl, UrlText, @@ -736,8 +737,7 @@ description_element = std::move(url_text); } else { - auto text_element = Create<Text>(kNone, kPhaseOverlayForeground, - kWebVrPermissionFontHeight); + auto text_element = Create<Text>(kNone, phase, kWebVrPermissionFontHeight); text_element->SetLayoutMode(kMultiLineFixedWidth); text_element->SetAlignment(kTextAlignmentLeft); text_element->SetColor(SK_ColorWHITE); @@ -758,12 +758,11 @@ return container; } -std::unique_ptr<UiElement> CreateHostedUi( - Model* model, - UiBrowserInterface* browser, - UiElementName name, - UiElementName element_name, - float distance) { +std::unique_ptr<UiElement> CreateHostedUi(Model* model, + UiBrowserInterface* browser, + UiElementName name, + UiElementName element_name, + float distance) { auto hosted_ui = Create<PlatformUiElement>(element_name, kPhaseForeground); hosted_ui->SetSize(kContentWidth * kHostedUiWidthRatio, kContentHeight * kHostedUiHeightRatio); @@ -942,6 +941,178 @@ return parent; } +#if defined(OS_WIN) +void BindIndicatorTranscienceForWin( + TransientElement* e, + Model* model, + UiScene* scene, + const base::Optional< + std::tuple<bool, CapturingStateModel, CapturingStateModel>>& last_value, + const std::tuple<bool, CapturingStateModel, CapturingStateModel>& value) { + const bool in_web_vr_presentation = model->web_vr_enabled() && + model->web_vr.IsImmersiveWebXrVisible() && + model->web_vr.has_received_permissions; + + const CapturingStateModel active_capture = std::get<1>(value); + const CapturingStateModel potential_capture = std::get<2>(value); + const CapturingStateModel last_active_capture = + last_value ? std::get<1>(last_value.value()) : CapturingStateModel(); + const CapturingStateModel last_potential_capture = + last_value ? std::get<2>(last_value.value()) : CapturingStateModel(); + + // Update the visibility state of the indicators based on the capturing state + // diff. potential_capture represents the permissions granted to the site + // before the presentation. active_capture members are set when a relevant + // device starts to get used. + // When the session starts, indicators display which permissions are granted + // upfront (struct potential_capture). Then, when a device gets accessed, + // an indicator notifies the user about its usage. + // The below logic tries to capture this logic. + bool initial_toasts = !active_capture.IsAnyCapturingEnabled(); + if (active_capture != last_active_capture || + potential_capture != last_potential_capture) { + auto specs = GetIndicatorSpecs(); + for (const auto& spec : specs) { + bool allowed = potential_capture.*spec.signal; + bool triggered = + !(last_active_capture.*spec.signal) && (active_capture.*spec.signal); + bool show_ui = initial_toasts ? allowed : triggered; + SetVisibleInLayout(scene->GetUiElementByName(spec.webvr_name), show_ui); + } + } + + if (!in_web_vr_presentation) { + e->SetVisibleImmediately(false); + return; + } + + e->SetVisible(true); + e->RefreshVisible(); + SetVisibleInLayout(scene->GetUiElementByName(kWebVrExclusiveScreenToast), + !model->browsing_disabled); + + e->RemoveKeyframeModels(TRANSFORM); + + e->SetTranslate(0, kWebVrPermissionOffsetStart, 0); + + // Build up a keyframe model for the initial transition. + std::unique_ptr<cc::KeyframedTransformAnimationCurve> curve( + cc::KeyframedTransformAnimationCurve::Create()); + + cc::TransformOperations value_1; + value_1.AppendTranslate(0, kWebVrPermissionOffsetStart, 0); + curve->AddKeyframe(cc::TransformKeyframe::Create( + base::TimeDelta(), value_1, + cc::CubicBezierTimingFunction::CreatePreset( + cc::CubicBezierTimingFunction::EaseType::EASE))); + + cc::TransformOperations value_2; + value_2.AppendTranslate(0, kWebVrPermissionOffsetOvershoot, 0); + curve->AddKeyframe(cc::TransformKeyframe::Create( + base::TimeDelta::FromMilliseconds(kWebVrPermissionOffsetMs), value_2, + cc::CubicBezierTimingFunction::CreatePreset( + cc::CubicBezierTimingFunction::EaseType::EASE))); + + cc::TransformOperations value_3; + value_3.AppendTranslate(0, kWebVrPermissionOffsetFinal, 0); + curve->AddKeyframe(cc::TransformKeyframe::Create( + base::TimeDelta::FromMilliseconds(kWebVrPermissionAnimationDurationMs), + value_3, + cc::CubicBezierTimingFunction::CreatePreset( + cc::CubicBezierTimingFunction::EaseType::EASE))); + + e->AddKeyframeModel(cc::KeyframeModel::Create( + std::move(curve), Animation::GetNextKeyframeModelId(), + Animation::GetNextGroupId(), TRANSFORM)); +} + +#else + +void BindIndicatorTranscience( + TransientElement* e, + Model* model, + UiScene* scene, + const base::Optional<std::tuple<bool, bool, bool>>& last_value, + const std::tuple<bool, bool, bool>& value) { + const bool in_web_vr_presentation = std::get<0>(value); + const bool in_long_press = std::get<1>(value); + const bool showing_hosted_ui = std::get<2>(value); + const bool was_in_long_press = last_value && std::get<1>(last_value.value()); + const bool was_showing_hosted_ui = + last_value && std::get<2>(last_value.value()); + + if (!in_web_vr_presentation) { + e->SetVisibleImmediately(false); + return; + } + + // The reason we need the previous state is to disguish the + // situation where the app button has been released after a long + // press, and the situation when we want to initially show the + // indicators. + if (was_in_long_press && !in_long_press) + return; + + // Similarly, we need to know when we've finished presenting hosted + // ui because we should not show indicators then. + if (was_showing_hosted_ui && !showing_hosted_ui) + return; + + e->SetVisible(true); + e->RefreshVisible(); + SetVisibleInLayout(scene->GetUiElementByName(kWebVrExclusiveScreenToast), + !model->browsing_disabled && !in_long_press); + + auto specs = GetIndicatorSpecs(); + for (const auto& spec : specs) { + SetVisibleInLayout(scene->GetUiElementByName(spec.webvr_name), + model->active_capturing.*spec.signal || + model->potential_capturing.*spec.signal || + model->background_capturing.*spec.signal); + } + + e->RemoveKeyframeModels(TRANSFORM); + if (in_long_press) { + // We do not do a translation animation for long press. + e->SetTranslate(0, 0, 0); + return; + } + + e->SetTranslate(0, kWebVrPermissionOffsetStart, 0); + + // Build up a keyframe model for the initial transition. + std::unique_ptr<cc::KeyframedTransformAnimationCurve> curve( + cc::KeyframedTransformAnimationCurve::Create()); + + cc::TransformOperations value_1; + value_1.AppendTranslate(0, kWebVrPermissionOffsetStart, 0); + curve->AddKeyframe(cc::TransformKeyframe::Create( + base::TimeDelta(), value_1, + cc::CubicBezierTimingFunction::CreatePreset( + cc::CubicBezierTimingFunction::EaseType::EASE))); + + cc::TransformOperations value_2; + value_2.AppendTranslate(0, kWebVrPermissionOffsetOvershoot, 0); + curve->AddKeyframe(cc::TransformKeyframe::Create( + base::TimeDelta::FromMilliseconds(kWebVrPermissionOffsetMs), value_2, + cc::CubicBezierTimingFunction::CreatePreset( + cc::CubicBezierTimingFunction::EaseType::EASE))); + + cc::TransformOperations value_3; + value_3.AppendTranslate(0, kWebVrPermissionOffsetFinal, 0); + curve->AddKeyframe(cc::TransformKeyframe::Create( + base::TimeDelta::FromMilliseconds(kWebVrPermissionAnimationDurationMs), + value_3, + cc::CubicBezierTimingFunction::CreatePreset( + cc::CubicBezierTimingFunction::EaseType::EASE))); + + e->AddKeyframeModel(cc::KeyframeModel::Create( + std::move(curve), Animation::GetNextKeyframeModelId(), + Animation::GetNextGroupId(), TRANSFORM)); +} + +#endif + } // namespace UiSceneCreator::UiSceneCreator(UiBrowserInterface* browser, @@ -1845,8 +2016,7 @@ float, Model, model_, model->reposition_window_enabled() ? kRepositionContentOpacity : 1.0f, UiElement, content_toggle.get(), SetOpacity)); - scene_->AddParentUiElement(k2dBrowsingForeground, - std::move(content_toggle)); + scene_->AddParentUiElement(k2dBrowsingForeground, std::move(content_toggle)); auto hit_plane = Create<InvisibleHitTarget>(kContentRepositionHitPlane, kPhaseForeground); @@ -2311,7 +2481,8 @@ }; std::vector<MenuItem> menu_items = { { - kOverflowMenuNewIncognitoTabItem, new_incognito_tab_res_id, + kOverflowMenuNewIncognitoTabItem, + new_incognito_tab_res_id, base::BindRepeating( [](UiBrowserInterface* browser) { browser->OpenNewTab(true); }), base::BindRepeating([](Model* m) { return !m->incognito; }), @@ -2803,6 +2974,8 @@ indicators->SetTranslate(0, 0, kWebVrPermissionDepth); indicators->set_margin(kWebVrPermissionOuterMargin); + DrawPhase phase = kPhaseOverlayForeground; + IndicatorSpec app_button_spec = {kNone, kWebVrExclusiveScreenToast, GetVrIcon(kVrRemoveCircleOutlineIcon), @@ -2811,15 +2984,34 @@ 0, nullptr, false}; - indicators->AddChild(CreateWebVrIndicator(model_, browser_, app_button_spec)); + indicators->AddChild( + CreateWebVrIndicator(model_, browser_, app_button_spec, phase)); auto specs = GetIndicatorSpecs(); for (const auto& spec : specs) { - indicators->AddChild(CreateWebVrIndicator(model_, browser_, spec)); + indicators->AddChild(CreateWebVrIndicator(model_, browser_, spec, phase)); } auto parent = CreateTransientParent(kWebVrIndicatorTransience, kToastTimeoutSeconds, true); +#if defined(OS_WIN) + parent->AddBinding( + std::make_unique< + Binding<std::tuple<bool, CapturingStateModel, CapturingStateModel>>>( + VR_BIND_LAMBDA( + [](Model* model) { + return std::tuple<bool, CapturingStateModel, + CapturingStateModel>( + model->web_vr_enabled() && + model->web_vr.IsImmersiveWebXrVisible() && + model->web_vr.has_received_permissions, + model->active_capturing, model->potential_capturing); + }, + base::Unretained(model_)), + VR_BIND_LAMBDA(BindIndicatorTranscienceForWin, + base::Unretained(parent.get()), + base::Unretained(model_), base::Unretained(scene_)))); +#else parent->AddBinding(std::make_unique<Binding<std::tuple<bool, bool, bool>>>( VR_BIND_LAMBDA( [](Model* model) { @@ -2831,93 +3023,9 @@ model->web_vr.showing_hosted_ui); }, base::Unretained(model_)), - VR_BIND_LAMBDA( - [](TransientElement* e, Model* model, UiScene* scene, - const base::Optional<std::tuple<bool, bool, bool>>& last_value, - const std::tuple<bool, bool, bool>& value) { - const bool in_web_vr_presentation = std::get<0>(value); - const bool in_long_press = std::get<1>(value); - const bool showing_hosted_ui = std::get<2>(value); - const bool was_in_long_press = - last_value && std::get<1>(last_value.value()); - const bool was_showing_hosted_ui = - last_value && std::get<2>(last_value.value()); - - if (!in_web_vr_presentation) { - e->SetVisibleImmediately(false); - return; - } - - // The reason we need the previous state is to disguish the - // situation where the app button has been released after a long - // press, and the situation when we want to initially show the - // indicators. - if (was_in_long_press && !in_long_press) - return; - - // Similarly, we need to know when we've finished presenting hosted - // ui because we should not show indicators then. - if (was_showing_hosted_ui && !showing_hosted_ui) - return; - - e->SetVisible(true); - e->RefreshVisible(); - SetVisibleInLayout( - scene->GetUiElementByName(kWebVrExclusiveScreenToast), - !model->browsing_disabled && !in_long_press); - - auto specs = GetIndicatorSpecs(); - for (const auto& spec : specs) { - SetVisibleInLayout( - scene->GetUiElementByName(spec.webvr_name), - model->active_capturing.*spec.signal || - model->potential_capturing.*spec.signal || - model->background_capturing.*spec.signal); - } - - e->RemoveKeyframeModels(TRANSFORM); - if (in_long_press) { - // We do not do a translation animation for long press. - e->SetTranslate(0, 0, 0); - return; - } - - e->SetTranslate(0, kWebVrPermissionOffsetStart, 0); - - // Build up a keyframe model for the initial transition. - std::unique_ptr<cc::KeyframedTransformAnimationCurve> curve( - cc::KeyframedTransformAnimationCurve::Create()); - - cc::TransformOperations value_1; - value_1.AppendTranslate(0, kWebVrPermissionOffsetStart, 0); - curve->AddKeyframe(cc::TransformKeyframe::Create( - base::TimeDelta(), value_1, - cc::CubicBezierTimingFunction::CreatePreset( - cc::CubicBezierTimingFunction::EaseType::EASE))); - - cc::TransformOperations value_2; - value_2.AppendTranslate(0, kWebVrPermissionOffsetOvershoot, 0); - curve->AddKeyframe(cc::TransformKeyframe::Create( - base::TimeDelta::FromMilliseconds(kWebVrPermissionOffsetMs), - value_2, - cc::CubicBezierTimingFunction::CreatePreset( - cc::CubicBezierTimingFunction::EaseType::EASE))); - - cc::TransformOperations value_3; - value_3.AppendTranslate(0, kWebVrPermissionOffsetFinal, 0); - curve->AddKeyframe(cc::TransformKeyframe::Create( - base::TimeDelta::FromMilliseconds( - kWebVrPermissionAnimationDurationMs), - value_3, - cc::CubicBezierTimingFunction::CreatePreset( - cc::CubicBezierTimingFunction::EaseType::EASE))); - - e->AddKeyframeModel(cc::KeyframeModel::Create( - std::move(curve), Animation::GetNextKeyframeModelId(), - Animation::GetNextGroupId(), TRANSFORM)); - }, - base::Unretained(parent.get()), base::Unretained(model_), - base::Unretained(scene_)))); + VR_BIND_LAMBDA(BindIndicatorTranscience, base::Unretained(parent.get()), + base::Unretained(model_), base::Unretained(scene_)))); +#endif auto scaler = std::make_unique<ScaledDepthAdjuster>(kWebVrToastDistance); scaler->AddChild(std::move(indicators));
diff --git a/chrome/browser/vr/ui_unittest.cc b/chrome/browser/vr/ui_unittest.cc index e494271..070be975 100644 --- a/chrome/browser/vr/ui_unittest.cc +++ b/chrome/browser/vr/ui_unittest.cc
@@ -1307,6 +1307,7 @@ // Ensures that permissions do not appear after showing hosted UI. TEST_F(UiTest, DoNotShowIndicatorsAfterHostedUi) { +#if !defined(OS_WIN) CreateScene(kInWebVr); auto browser_ui = ui_->GetBrowserUiWeakPtr(); browser_ui->SetWebVrMode(true); @@ -1323,12 +1324,14 @@ model_->web_vr.showing_hosted_ui = false; OnBeginFrame(); EXPECT_FALSE(IsVisible(kWebVrExclusiveScreenToast)); +#endif } // Ensures that permissions appear on long press, and that when the menu button // is released that we do not show the exclusive screen toast. Distinguishing // these cases requires knowledge of the previous state. TEST_F(UiTest, LongPressMenuButtonInWebVrMode) { +#if !defined(OS_WIN) CreateScene(kInWebVr); auto browser_ui = ui_->GetBrowserUiWeakPtr(); browser_ui->SetWebVrMode(true); @@ -1360,6 +1363,7 @@ std::make_unique<InputEvent>(InputEvent::kMenuButtonLongPressEnd)); ui_->HandleMenuButtonEvents(&events); EXPECT_FALSE(model_->menu_button_long_pressed); +#endif } TEST_F(UiTest, MenuItems) {
diff --git a/chrome/browser/vr/win/graphics_delegate_win.cc b/chrome/browser/vr/win/graphics_delegate_win.cc index e156569..2a6627e 100644 --- a/chrome/browser/vr/win/graphics_delegate_win.cc +++ b/chrome/browser/vr/win/graphics_delegate_win.cc
@@ -304,7 +304,7 @@ } void GraphicsDelegateWin::PrepareBufferForBrowserUi() { - gl_->ClearColor(0, 1, 0, 1); + gl_->ClearColor(0, 0, 0, 0); gl_->Clear(GL_COLOR_BUFFER_BIT); DCHECK(prepared_drawing_buffer_ == DrawingBufferMode::kNone);
diff --git a/chrome/browser/vr/win/scheduler_delegate_win.cc b/chrome/browser/vr/win/scheduler_delegate_win.cc index 271224d..3d171cc8 100644 --- a/chrome/browser/vr/win/scheduler_delegate_win.cc +++ b/chrome/browser/vr/win/scheduler_delegate_win.cc
@@ -13,13 +13,14 @@ void SchedulerDelegateWin::OnPose(base::OnceCallback<void()> on_frame_ended, gfx::Transform head_pose, + bool draw_overlay, bool draw_ui) { on_frame_ended_ = std::move(on_frame_ended); base::TimeTicks now = base::TimeTicks::Now(); - if (draw_ui) - browser_renderer_->DrawBrowserFrame(now); - else + if (draw_overlay) browser_renderer_->DrawWebXrFrame(now, head_pose); + else if (draw_ui) + browser_renderer_->DrawBrowserFrame(now); } void SchedulerDelegateWin::OnPause() {
diff --git a/chrome/browser/vr/win/scheduler_delegate_win.h b/chrome/browser/vr/win/scheduler_delegate_win.h index 1c0c120..f2e0945 100644 --- a/chrome/browser/vr/win/scheduler_delegate_win.h +++ b/chrome/browser/vr/win/scheduler_delegate_win.h
@@ -17,6 +17,7 @@ // Tell browser when poses available, when we rendered, etc. void OnPose(base::OnceCallback<void()> on_frame_ended, gfx::Transform head_pose, + bool draw_overlay, bool draw_ui); private:
diff --git a/chrome/browser/vr/win/vr_browser_renderer_thread_win.cc b/chrome/browser/vr/win/vr_browser_renderer_thread_win.cc index 16d329e..1501421e 100644 --- a/chrome/browser/vr/win/vr_browser_renderer_thread_win.cc +++ b/chrome/browser/vr/win/vr_browser_renderer_thread_win.cc
@@ -57,6 +57,8 @@ started_ = false; graphics_ = nullptr; scheduler_ = nullptr; + ui_ = nullptr; + scheduler_ui_ = nullptr; } void VRBrowserRendererThreadWin::SetVRDisplayInfo( @@ -115,6 +117,13 @@ OnSpinnerVisibilityChanged(false); } +int VRBrowserRendererThreadWin::GetNextRequestId() { + current_request_id_++; + if (current_request_id_ >= 0x10000) + current_request_id_ = 0; + return current_request_id_; +} + void VRBrowserRendererThreadWin::OnWebXrTimeoutImminent() { OnSpinnerVisibilityChanged(true); scheduler_ui_->OnWebXrTimeoutImminent(); @@ -135,16 +144,48 @@ ui_->SetVisibleExternalPromptNotification(prompt); - overlay_->SetOverlayAndWebXRVisibility(draw_state_.ShouldDrawUI(), - draw_state_.ShouldDrawWebXR()); + if (overlay_) + overlay_->SetOverlayAndWebXRVisibility(draw_state_.ShouldDrawUI(), + draw_state_.ShouldDrawWebXR()); if (draw_state_.ShouldDrawUI()) { - overlay_->RequestNextOverlayPose(base::BindOnce( - &VRBrowserRendererThreadWin::OnPose, base::Unretained(this))); + if (overlay_) // False only while testing + overlay_->RequestNextOverlayPose( + base::BindOnce(&VRBrowserRendererThreadWin::OnPose, + base::Unretained(this), GetNextRequestId())); } else { StopOverlay(); } } +void VRBrowserRendererThreadWin::SetIndicatorsVisible(bool visible) { + if (!draw_state_.SetIndicatorsVisible(visible)) + return; + + if (draw_state_.ShouldDrawUI()) + StartOverlay(); + + if (overlay_) + overlay_->SetOverlayAndWebXRVisibility(draw_state_.ShouldDrawUI(), + draw_state_.ShouldDrawWebXR()); + if (draw_state_.ShouldDrawUI()) { + if (overlay_) // False only while testing + overlay_->RequestNextOverlayPose( + base::BindOnce(&VRBrowserRendererThreadWin::OnPose, + base::Unretained(this), GetNextRequestId())); + } else { + StopOverlay(); + } +} + +void VRBrowserRendererThreadWin::SetCapturingState( + const CapturingStateModel& active_capturing, + const CapturingStateModel& background_capturing, + const CapturingStateModel& potential_capturing) { + if (ui_) + ui_->SetCapturingState(active_capturing, background_capturing, + potential_capturing); +} + VRBrowserRendererThreadWin* VRBrowserRendererThreadWin::GetInstanceForTesting() { return instance_for_testing_; @@ -263,22 +304,24 @@ } void VRBrowserRendererThreadWin::OnSpinnerVisibilityChanged(bool visible) { - if (draw_state_.SetSpinnerVisible(visible)) { - if (draw_state_.ShouldDrawUI()) { - StartOverlay(); - } + if (!draw_state_.SetSpinnerVisible(visible)) + return; + if (draw_state_.ShouldDrawUI()) { + StartOverlay(); + } - if (overlay_) { - overlay_->SetOverlayAndWebXRVisibility(draw_state_.ShouldDrawUI(), - draw_state_.ShouldDrawWebXR()); - } + if (overlay_) { + overlay_->SetOverlayAndWebXRVisibility(draw_state_.ShouldDrawUI(), + draw_state_.ShouldDrawWebXR()); + } - if (draw_state_.ShouldDrawUI()) { - overlay_->RequestNextOverlayPose(base::BindOnce( - &VRBrowserRendererThreadWin::OnPose, base::Unretained(this))); - } else { - StopOverlay(); - } + if (draw_state_.ShouldDrawUI()) { + if (overlay_) // False only while testing. + overlay_->RequestNextOverlayPose( + base::BindOnce(&VRBrowserRendererThreadWin::OnPose, + base::Unretained(this), GetNextRequestId())); + } else { + StopOverlay(); } } @@ -288,12 +331,16 @@ StopWebXrTimeout(); } -void VRBrowserRendererThreadWin::OnPose(device::mojom::XRFrameDataPtr data) { +void VRBrowserRendererThreadWin::OnPose(int request_id, + device::mojom::XRFrameDataPtr data) { + if (request_id != current_request_id_) { + // Old request. Do nothing. + return; + } if (!draw_state_.ShouldDrawUI()) { // We shouldn't be showing UI. overlay_->SetOverlayAndWebXRVisibility(draw_state_.ShouldDrawUI(), draw_state_.ShouldDrawWebXR()); - if (graphics_) graphics_->ResetMemoryBuffer(); return; @@ -330,7 +377,8 @@ // calling the callback if we are destroyed. scheduler_->OnPose(base::BindOnce(&VRBrowserRendererThreadWin::SubmitFrame, base::Unretained(this), std::move(data)), - head_from_world, draw_state_.ShouldDrawUI()); + head_from_world, draw_state_.ShouldDrawWebXR(), + draw_state_.ShouldDrawUI()); } void VRBrowserRendererThreadWin::SubmitFrame( @@ -345,24 +393,28 @@ } void VRBrowserRendererThreadWin::SubmitResult(bool success) { - if (!success) { + if (!success && graphics_) { graphics_->ResetMemoryBuffer(); } + if (scheduler_ui_ && success) + scheduler_ui_->OnWebXrFrameAvailable(); if (draw_state_.ShouldDrawUI() && started_) { - overlay_->RequestNextOverlayPose(base::BindOnce( - &VRBrowserRendererThreadWin::OnPose, base::Unretained(this))); + overlay_->RequestNextOverlayPose( + base::BindOnce(&VRBrowserRendererThreadWin::OnPose, + base::Unretained(this), GetNextRequestId())); } } // VRBrowserRendererThreadWin::DrawContentType functions. bool VRBrowserRendererThreadWin::DrawState::ShouldDrawUI() { return prompt_ != ExternalPromptNotificationType::kPromptNone || - spinner_visible_; + spinner_visible_ || indicators_visible_; } bool VRBrowserRendererThreadWin::DrawState::ShouldDrawWebXR() { - return prompt_ == ExternalPromptNotificationType::kPromptNone && - !spinner_visible_; + return (prompt_ == ExternalPromptNotificationType::kPromptNone && + !spinner_visible_) || + indicators_visible_; } bool VRBrowserRendererThreadWin::DrawState::SetPrompt( @@ -380,4 +432,11 @@ return old_ui != ShouldDrawUI() || old_webxr != ShouldDrawWebXR(); } +bool VRBrowserRendererThreadWin::DrawState::SetIndicatorsVisible(bool visible) { + bool old_ui = ShouldDrawUI(); + bool old_webxr = ShouldDrawWebXR(); + indicators_visible_ = visible; + return old_ui != ShouldDrawUI() || old_webxr != ShouldDrawWebXR(); +} + } // namespace vr
diff --git a/chrome/browser/vr/win/vr_browser_renderer_thread_win.h b/chrome/browser/vr/win/vr_browser_renderer_thread_win.h index 8204a03..a8675ee 100644 --- a/chrome/browser/vr/win/vr_browser_renderer_thread_win.h +++ b/chrome/browser/vr/win/vr_browser_renderer_thread_win.h
@@ -9,6 +9,7 @@ #include "base/threading/thread.h" #include "chrome/browser/vr/browser_renderer.h" +#include "chrome/browser/vr/model/capturing_state_model.h" #include "chrome/browser/vr/model/web_vr_model.h" #include "chrome/browser/vr/service/browser_xr_runtime.h" #include "chrome/browser/vr/vr_export.h" @@ -37,6 +38,10 @@ // The below function(s) affect(s) whether UI is drawn or not. void SetVisibleExternalPromptNotification( ExternalPromptNotificationType prompt); + void SetIndicatorsVisible(bool visible); + void SetCapturingState(const CapturingStateModel& active_capturing, + const CapturingStateModel& background_capturing, + const CapturingStateModel& potential_capturing); static VRBrowserRendererThreadWin* GetInstanceForTesting(); BrowserRenderer* GetBrowserRendererForTesting(); @@ -48,6 +53,7 @@ // State changing methods. bool SetPrompt(ExternalPromptNotificationType prompt); bool SetSpinnerVisible(bool visible); + bool SetIndicatorsVisible(bool visible); // State querying methods. bool ShouldDrawUI(); @@ -58,9 +64,10 @@ ExternalPromptNotificationType::kPromptNone; bool spinner_visible_ = false; + bool indicators_visible_ = false; }; - void OnPose(device::mojom::XRFrameDataPtr data); + void OnPose(int request_id, device::mojom::XRFrameDataPtr data); void SubmitResult(bool success); void SubmitFrame(device::mojom::XRFrameDataPtr data); void StartOverlay(); @@ -71,6 +78,7 @@ void OnWebXrTimedOut(); void StartWebXrTimeout(); void StopWebXrTimeout(); + int GetNextRequestId(); // We need to do some initialization of GraphicsDelegateWin before // browser_renderer_, so we first store it in a unique_ptr, then transition @@ -94,6 +102,7 @@ DrawState draw_state_; bool started_ = false; bool webxr_presenting_ = false; + int current_request_id_ = 0; device::mojom::ImmersiveOverlayPtr overlay_; device::mojom::VRDisplayInfoPtr display_info_;
diff --git a/chrome/browser/web_applications/bookmark_apps/bookmark_app_install_manager.cc b/chrome/browser/web_applications/bookmark_apps/bookmark_app_install_manager.cc index f0eb05d..c51d98c 100644 --- a/chrome/browser/web_applications/bookmark_apps/bookmark_app_install_manager.cc +++ b/chrome/browser/web_applications/bookmark_apps/bookmark_app_install_manager.cc
@@ -195,8 +195,14 @@ break; } - if (!options.create_shortcuts) - helper->set_skip_shortcut_creation(); + if (!options.add_to_applications_menu) + helper->set_skip_adding_to_applications_menu(); + + if (!options.add_to_desktop) + helper->set_skip_adding_to_desktop(); + + if (!options.add_to_quick_launch_bar) + helper->set_skip_adding_to_quick_launch_bar(); if (options.bypass_service_worker_check) helper->set_bypass_service_worker_check();
diff --git a/chrome/browser/web_applications/bookmark_apps/bookmark_app_install_manager_unittest.cc b/chrome/browser/web_applications/bookmark_apps/bookmark_app_install_manager_unittest.cc index 7f27258..3643787 100644 --- a/chrome/browser/web_applications/bookmark_apps/bookmark_app_install_manager_unittest.cc +++ b/chrome/browser/web_applications/bookmark_apps/bookmark_app_install_manager_unittest.cc
@@ -11,11 +11,14 @@ #include "base/files/file_path.h" #include "base/run_loop.h" #include "base/test/bind_test_util.h" +#include "chrome/browser/extensions/bookmark_app_helper.h" #include "chrome/browser/extensions/test_extension_system.h" #include "chrome/browser/installable/installable_manager.h" #include "chrome/browser/installable/installable_metrics.h" #include "chrome/browser/ssl/security_state_tab_helper.h" +#include "chrome/browser/web_applications/components/install_options.h" #include "chrome/browser/web_applications/components/web_app_constants.h" +#include "chrome/browser/web_applications/test/test_data_retriever.h" #include "chrome/common/web_application_info.h" #include "chrome/test/base/chrome_render_view_host_test_harness.h" #include "chrome/test/base/testing_profile.h" @@ -115,10 +118,195 @@ run_loop.Quit(); })); - // Destroy InstallManager. + // Destroy InstallManager: Call Reset as if Profile gets destroyed. install_manager_->Reset(); run_loop.Run(); + // Delete InstallManager object. + install_manager_.reset(); + EXPECT_TRUE(callback_called); +} + +TEST_F(BookmarkAppInstallManagerTest, WithOptions_WebContentsDestroyed) { + const GURL app_url("https://example.com/path"); + NavigateAndCommit(app_url); + + web_app::InstallOptions install_options( + app_url, web_app::LaunchContainer::kWindow, + web_app::InstallSource::kExternalPolicy); + + base::RunLoop run_loop; + bool callback_called = false; + + install_manager_->InstallWebAppWithOptions( + web_contents(), install_options, + base::BindLambdaForTesting([&](const web_app::AppId& installed_app_id, + web_app::InstallResultCode code) { + EXPECT_EQ(web_app::InstallResultCode::kWebContentsDestroyed, code); + EXPECT_EQ(web_app::AppId(), installed_app_id); + callback_called = true; + run_loop.Quit(); + })); + EXPECT_FALSE(callback_called); + + // Destroy WebContents. + DeleteContents(); + EXPECT_EQ(nullptr, web_contents()); + + run_loop.Run(); + + EXPECT_TRUE(callback_called); +} + +TEST_F(BookmarkAppInstallManagerTest, + WithOptions_WebContentsDestroyedAfterDataRetrieval) { + const GURL app_url("https://example.com/path"); + NavigateAndCommit(app_url); + + web_app::InstallOptions install_options( + app_url, web_app::LaunchContainer::kWindow, + web_app::InstallSource::kExternalPolicy); + + base::RunLoop retrieval_run_loop; + bool data_retrieval_passed = false; + + install_manager_->SetDataRetrieverFactoryForTesting( + base::BindLambdaForTesting([&]() { + WebApplicationInfo info; + info.app_url = app_url; + auto data_retriever = std::make_unique<web_app::TestDataRetriever>( + std::make_unique<WebApplicationInfo>(std::move(info))); + + return std::unique_ptr<web_app::WebAppDataRetriever>( + std::move(data_retriever)); + })); + + install_manager_->SetBookmarkAppHelperFactoryForTesting( + base::BindLambdaForTesting([&](Profile* profile, + const WebApplicationInfo& web_app_info, + content::WebContents* web_contents, + WebappInstallSource install_source) { + data_retrieval_passed = true; + retrieval_run_loop.Quit(); + return std::make_unique<BookmarkAppHelper>( + profile, web_app_info, web_contents, install_source); + })); + + base::RunLoop install_run_loop; + bool callback_called = false; + + install_manager_->InstallWebAppWithOptions( + web_contents(), install_options, + base::BindLambdaForTesting([&](const web_app::AppId& installed_app_id, + web_app::InstallResultCode code) { + EXPECT_EQ(web_app::InstallResultCode::kWebContentsDestroyed, code); + EXPECT_EQ(web_app::AppId(), installed_app_id); + callback_called = true; + install_run_loop.Quit(); + })); + EXPECT_FALSE(callback_called); + + retrieval_run_loop.Run(); + EXPECT_TRUE(data_retrieval_passed); + EXPECT_FALSE(callback_called); + + // Destroy WebContents. + DeleteContents(); + EXPECT_EQ(nullptr, web_contents()); + + install_run_loop.Run(); + EXPECT_TRUE(callback_called); +} + +TEST_F(BookmarkAppInstallManagerTest, WithOptions_InstallManagerDestroyed) { + const GURL app_url("https://example.com/path"); + NavigateAndCommit(app_url); + + web_app::InstallOptions install_options( + app_url, web_app::LaunchContainer::kWindow, + web_app::InstallSource::kExternalPolicy); + + base::RunLoop run_loop; + bool callback_called = false; + + install_manager_->InstallWebAppWithOptions( + web_contents(), install_options, + base::BindLambdaForTesting([&](const web_app::AppId& installed_app_id, + web_app::InstallResultCode code) { + EXPECT_EQ(web_app::InstallResultCode::kInstallManagerDestroyed, code); + EXPECT_EQ(web_app::AppId(), installed_app_id); + callback_called = true; + run_loop.Quit(); + })); + EXPECT_FALSE(callback_called); + + // Destroy InstallManager: Call Reset as if Profile gets destroyed. + install_manager_->Reset(); + run_loop.Run(); + + // Delete InstallManager object. + install_manager_.reset(); + + EXPECT_TRUE(callback_called); +} + +TEST_F(BookmarkAppInstallManagerTest, + WithOptions_InstallManagerDestroyedAfterDataRetrieval) { + const GURL app_url("https://example.com/path"); + NavigateAndCommit(app_url); + + web_app::InstallOptions install_options( + app_url, web_app::LaunchContainer::kWindow, + web_app::InstallSource::kExternalPolicy); + + base::RunLoop retrieval_run_loop; + bool data_retrieval_passed = false; + + install_manager_->SetDataRetrieverFactoryForTesting( + base::BindLambdaForTesting([&]() { + WebApplicationInfo info; + info.app_url = app_url; + auto data_retriever = std::make_unique<web_app::TestDataRetriever>( + std::make_unique<WebApplicationInfo>(std::move(info))); + + return std::unique_ptr<web_app::WebAppDataRetriever>( + std::move(data_retriever)); + })); + + install_manager_->SetBookmarkAppHelperFactoryForTesting( + base::BindLambdaForTesting([&](Profile* profile, + const WebApplicationInfo& web_app_info, + content::WebContents* web_contents, + WebappInstallSource install_source) { + data_retrieval_passed = true; + retrieval_run_loop.Quit(); + return std::make_unique<BookmarkAppHelper>( + profile, web_app_info, web_contents, install_source); + })); + + base::RunLoop install_run_loop; + bool callback_called = false; + + install_manager_->InstallWebAppWithOptions( + web_contents(), install_options, + base::BindLambdaForTesting([&](const web_app::AppId& installed_app_id, + web_app::InstallResultCode code) { + EXPECT_EQ(web_app::InstallResultCode::kInstallManagerDestroyed, code); + EXPECT_EQ(web_app::AppId(), installed_app_id); + callback_called = true; + install_run_loop.Quit(); + })); + EXPECT_FALSE(callback_called); + + retrieval_run_loop.Run(); + EXPECT_TRUE(data_retrieval_passed); + EXPECT_FALSE(callback_called); + + // Destroy InstallManager: Call Reset as if Profile gets destroyed. + install_manager_->Reset(); + install_run_loop.Run(); + + // Delete InstallManager object. install_manager_.reset(); EXPECT_TRUE(callback_called); }
diff --git a/chrome/browser/web_applications/bookmark_apps/external_web_apps_unittest.cc b/chrome/browser/web_applications/bookmark_apps/external_web_apps_unittest.cc index 07ef8765..04889c4f 100644 --- a/chrome/browser/web_applications/bookmark_apps/external_web_apps_unittest.cc +++ b/chrome/browser/web_applications/bookmark_apps/external_web_apps_unittest.cc
@@ -188,7 +188,9 @@ GURL("https://www.chromestatus.com/features"), web_app::LaunchContainer::kTab, web_app::InstallSource::kExternalDefault); - install_options.create_shortcuts = true; + install_options.add_to_applications_menu = true; + install_options.add_to_desktop = true; + install_options.add_to_quick_launch_bar = true; install_options.require_manifest = true; test_install_options_list.push_back(std::move(install_options)); } @@ -197,7 +199,9 @@ GURL("https://events.google.com/io2016/?utm_source=web_app_manifest"), web_app::LaunchContainer::kWindow, web_app::InstallSource::kExternalDefault); - install_options.create_shortcuts = false; + install_options.add_to_applications_menu = false; + install_options.add_to_desktop = false; + install_options.add_to_quick_launch_bar = false; install_options.require_manifest = true; test_install_options_list.push_back(std::move(install_options)); }
diff --git a/chrome/browser/web_applications/bookmark_apps/policy/web_app_policy_manager_unittest.cc b/chrome/browser/web_applications/bookmark_apps/policy/web_app_policy_manager_unittest.cc index 0ede645..92a894f2 100644 --- a/chrome/browser/web_applications/bookmark_apps/policy/web_app_policy_manager_unittest.cc +++ b/chrome/browser/web_applications/bookmark_apps/policy/web_app_policy_manager_unittest.cc
@@ -50,7 +50,9 @@ InstallOptions GetWindowedInstallOptions() { InstallOptions options(GURL(kWindowedUrl), LaunchContainer::kWindow, InstallSource::kExternalPolicy); - options.create_shortcuts = false; + options.add_to_applications_menu = false; + options.add_to_desktop = false; + options.add_to_quick_launch_bar = false; return options; } @@ -65,7 +67,9 @@ InstallOptions GetTabbedInstallOptions() { InstallOptions options(GURL(kTabbedUrl), LaunchContainer::kTab, InstallSource::kExternalPolicy); - options.create_shortcuts = false; + options.add_to_applications_menu = false; + options.add_to_desktop = false; + options.add_to_quick_launch_bar = false; return options; } @@ -78,7 +82,9 @@ InstallOptions GetNoContainerInstallOptions() { InstallOptions options(GURL(kNoContainerUrl), LaunchContainer::kTab, InstallSource::kExternalPolicy); - options.create_shortcuts = false; + options.add_to_applications_menu = false; + options.add_to_desktop = false; + options.add_to_quick_launch_bar = false; return options; } @@ -91,7 +97,9 @@ InstallOptions GetCreateDesktopShorcutDefaultInstallOptions() { InstallOptions options(GURL(kNoContainerUrl), LaunchContainer::kTab, InstallSource::kExternalPolicy); - options.create_shortcuts = false; + options.add_to_applications_menu = false; + options.add_to_desktop = false; + options.add_to_quick_launch_bar = false; return options; } @@ -105,7 +113,9 @@ InstallOptions GetCreateDesktopShorcutFalseInstallOptions() { InstallOptions options(GURL(kNoContainerUrl), LaunchContainer::kTab, InstallSource::kExternalPolicy); - options.create_shortcuts = false; + options.add_to_applications_menu = false; + options.add_to_desktop = false; + options.add_to_quick_launch_bar = false; return options; } @@ -119,7 +129,9 @@ InstallOptions GetCreateDesktopShorcutTrueInstallOptions() { InstallOptions options(GURL(kNoContainerUrl), LaunchContainer::kTab, InstallSource::kExternalPolicy); - options.create_shortcuts = true; + options.add_to_applications_menu = true; + options.add_to_desktop = true; + options.add_to_quick_launch_bar = false; return options; }
diff --git a/chrome/browser/web_applications/bookmark_apps/system_web_app_manager_unittest.cc b/chrome/browser/web_applications/bookmark_apps/system_web_app_manager_unittest.cc index 6b715d2..1a875f6 100644 --- a/chrome/browser/web_applications/bookmark_apps/system_web_app_manager_unittest.cc +++ b/chrome/browser/web_applications/bookmark_apps/system_web_app_manager_unittest.cc
@@ -41,7 +41,9 @@ InstallOptions GetWindowedInstallOptions() { InstallOptions options(GURL(kAppUrl1), LaunchContainer::kWindow, InstallSource::kSystemInstalled); - options.create_shortcuts = false; + options.add_to_applications_menu = false; + options.add_to_desktop = false; + options.add_to_quick_launch_bar = false; options.bypass_service_worker_check = true; options.always_update = true; return options;
diff --git a/chrome/browser/web_applications/components/install_options.cc b/chrome/browser/web_applications/components/install_options.cc index 611db56..9f6aab82 100644 --- a/chrome/browser/web_applications/components/install_options.cc +++ b/chrome/browser/web_applications/components/install_options.cc
@@ -26,11 +26,14 @@ default; bool InstallOptions::operator==(const InstallOptions& other) const { - return std::tie(url, launch_container, install_source, create_shortcuts, - override_previous_user_uninstall, bypass_service_worker_check, - require_manifest, always_update) == + return std::tie(url, launch_container, install_source, + add_to_applications_menu, add_to_desktop, + add_to_quick_launch_bar, override_previous_user_uninstall, + bypass_service_worker_check, require_manifest, + always_update) == std::tie(other.url, other.launch_container, other.install_source, - other.create_shortcuts, + other.add_to_applications_menu, other.add_to_desktop, + other.add_to_quick_launch_bar, other.override_previous_user_uninstall, other.bypass_service_worker_check, other.require_manifest, other.always_update); @@ -42,7 +45,11 @@ << static_cast<int32_t>(install_options.launch_container) << "\n install_source: " << static_cast<int32_t>(install_options.install_source) - << "\n create_shortcuts: " << install_options.create_shortcuts + << "\n add_to_applications_menu: " + << install_options.add_to_applications_menu + << "\n add_to_desktop: " << install_options.add_to_desktop + << "\n add_to_quick_launch_bar: " + << install_options.add_to_quick_launch_bar << "\n override_previous_user_uninstall: " << install_options.override_previous_user_uninstall << "\n bypass_service_worker_check: "
diff --git a/chrome/browser/web_applications/components/install_options.h b/chrome/browser/web_applications/components/install_options.h index bf368132..bcb3a5a 100644 --- a/chrome/browser/web_applications/components/install_options.h +++ b/chrome/browser/web_applications/components/install_options.h
@@ -29,7 +29,23 @@ LaunchContainer launch_container; InstallSource install_source; - bool create_shortcuts = true; + // If true, a shortcut is added to the Applications folder on macOS, and Start + // Menu on Linux and Windows. On Chrome OS, all installed apps show up in the + // app list, so there is no need to do anything there. If false, we skip + // adding a shortcut to desktop as well, regardless of the value of + // |add_to_desktop|. + // TODO(ortuno): Make adding a shortcut to the applications menu independent + // from adding a shortcut to desktop. + bool add_to_applications_menu = true; + + // If true, a shortcut is added to the desktop on Linux and Windows. Has no + // effect on macOS and Chrome OS. + bool add_to_desktop = true; + + // If true, a shortcut is added to the "quick launch bar" of the OS: the Shelf + // for Chrome OS, the Dock for macOS, and the Quick Launch Bar or Taskbar on + // Windows. Currently this only works on Chrome OS. + bool add_to_quick_launch_bar = true; // Whether the app should be reinstalled even if the user has previously // uninstalled it.
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer.cc b/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer.cc index a2fc2a72..83bdb2d 100644 --- a/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer.cc +++ b/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer.cc
@@ -104,7 +104,8 @@ const web_app::AppId& app_id, CreateOsShortcutsCallback callback) { const Extension* app = GetExtensionById(profile_, app_id); - BookmarkAppCreateOsShortcuts(profile_, app, std::move(callback)); + BookmarkAppCreateOsShortcuts(profile_, app, true /* add_to_desktop */, + std::move(callback)); } bool BookmarkAppInstallFinalizer::CanPinAppToShelf() const {
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_installation_task_unittest.cc b/chrome/browser/web_applications/extensions/bookmark_app_installation_task_unittest.cc index d7e59943..edfa360 100644 --- a/chrome/browser/web_applications/extensions/bookmark_app_installation_task_unittest.cc +++ b/chrome/browser/web_applications/extensions/bookmark_app_installation_task_unittest.cc
@@ -183,7 +183,9 @@ EXPECT_EQ(result.app_id.value(), id.value()); - EXPECT_TRUE(test_helper().create_shortcuts()); + EXPECT_TRUE(test_helper().add_to_quick_launch_bar()); + EXPECT_TRUE(test_helper().add_to_desktop()); + EXPECT_TRUE(test_helper().add_to_quick_launch_bar()); EXPECT_FALSE(test_helper().forced_launch_type().has_value()); EXPECT_TRUE(test_helper().is_default_app()); EXPECT_FALSE(test_helper().is_policy_installed_app()); @@ -236,11 +238,11 @@ } TEST_F(BookmarkAppInstallationTaskTest, - WebAppOrShortcutFromContents_NoShortcuts) { + WebAppOrShortcutFromContents_NoDesktopShortcut) { web_app::InstallOptions install_options(app_url(), web_app::LaunchContainer::kWindow, web_app::InstallSource::kInternal); - install_options.create_shortcuts = false; + install_options.add_to_desktop = false; auto task = std::make_unique<BookmarkAppInstallationTask>( profile(), std::move(install_options)); @@ -252,7 +254,71 @@ result.code); EXPECT_TRUE(result.app_id.has_value()); - EXPECT_FALSE(test_helper().create_shortcuts()); + EXPECT_TRUE(test_helper().add_to_applications_menu()); + EXPECT_TRUE(test_helper().add_to_quick_launch_bar()); + EXPECT_FALSE(test_helper().add_to_desktop()); + + callback_called = true; + })); + content::RunAllTasksUntilIdle(); + + test_helper().CompleteInstallation(); + EXPECT_TRUE(callback_called); +} + +TEST_F(BookmarkAppInstallationTaskTest, + WebAppOrShortcutFromContents_NoQuickLaunchBarShortcut) { + web_app::InstallOptions install_options(app_url(), + web_app::LaunchContainer::kWindow, + web_app::InstallSource::kInternal); + install_options.add_to_quick_launch_bar = false; + auto task = std::make_unique<BookmarkAppInstallationTask>( + profile(), std::move(install_options)); + + bool callback_called = false; + task->Install(web_contents(), + base::BindLambdaForTesting( + [&](BookmarkAppInstallationTask::Result result) { + EXPECT_EQ(web_app::InstallResultCode::kSuccess, + result.code); + EXPECT_TRUE(result.app_id.has_value()); + + EXPECT_TRUE(test_helper().add_to_applications_menu()); + EXPECT_FALSE(test_helper().add_to_quick_launch_bar()); + EXPECT_TRUE(test_helper().add_to_desktop()); + + callback_called = true; + })); + + content::RunAllTasksUntilIdle(); + + test_helper().CompleteInstallation(); + EXPECT_TRUE(callback_called); +} + +TEST_F( + BookmarkAppInstallationTaskTest, + WebAppOrShortcutFromContents_NoDesktopShortcutAndNoQuickLaunchBarShortcut) { + web_app::InstallOptions install_options(app_url(), + web_app::LaunchContainer::kWindow, + web_app::InstallSource::kInternal); + install_options.add_to_desktop = false; + install_options.add_to_quick_launch_bar = false; + auto task = std::make_unique<BookmarkAppInstallationTask>( + profile(), std::move(install_options)); + + bool callback_called = false; + task->Install(web_contents(), + base::BindLambdaForTesting( + [&](BookmarkAppInstallationTask::Result result) { + EXPECT_EQ(web_app::InstallResultCode::kSuccess, + result.code); + EXPECT_TRUE(result.app_id.has_value()); + + EXPECT_TRUE(test_helper().add_to_applications_menu()); + EXPECT_FALSE(test_helper().add_to_quick_launch_bar()); + EXPECT_FALSE(test_helper().add_to_desktop()); + callback_called = true; }));
diff --git a/chrome/browser/web_applications/extensions/pending_bookmark_app_manager_browsertest.cc b/chrome/browser/web_applications/extensions/pending_bookmark_app_manager_browsertest.cc index 34f43ab..16cfb86 100644 --- a/chrome/browser/web_applications/extensions/pending_bookmark_app_manager_browsertest.cc +++ b/chrome/browser/web_applications/extensions/pending_bookmark_app_manager_browsertest.cc
@@ -32,7 +32,10 @@ web_app::LaunchContainer::kWindow, web_app::InstallSource::kInternal); // Avoid creating real shortcuts in tests. - install_options.create_shortcuts = false; + install_options.add_to_applications_menu = false; + install_options.add_to_desktop = false; + install_options.add_to_quick_launch_bar = false; + return install_options; }
diff --git a/chrome/browser/web_applications/external_web_apps.cc b/chrome/browser/web_applications/external_web_apps.cc index 5d4b7a5..f4d07de 100644 --- a/chrome/browser/web_applications/external_web_apps.cc +++ b/chrome/browser/web_applications/external_web_apps.cc
@@ -174,7 +174,9 @@ web_app::InstallOptions install_options( std::move(app_url), launch_container, web_app::InstallSource::kExternalDefault); - install_options.create_shortcuts = create_shortcuts; + install_options.add_to_applications_menu = create_shortcuts; + install_options.add_to_desktop = create_shortcuts; + install_options.add_to_quick_launch_bar = create_shortcuts; install_options.require_manifest = true; install_options_list.push_back(std::move(install_options));
diff --git a/chrome/browser/web_applications/policy/web_app_policy_manager.cc b/chrome/browser/web_applications/policy/web_app_policy_manager.cc index 79cbdb5..914f9b2 100644 --- a/chrome/browser/web_applications/policy/web_app_policy_manager.cc +++ b/chrome/browser/web_applications/policy/web_app_policy_manager.cc
@@ -92,11 +92,12 @@ if (create_desktop_shortcut) create_shortcut = create_desktop_shortcut->GetBool(); - // This currently pins the app to the shelf on Chrome OS, which we don't - // want to do because there is a separate policy for that. - // TODO(ortuno): Introduce an option to specifically create desktop - // shortcuts and not pin the app to the shelf. - install_options.create_shortcuts = create_shortcut; + install_options.add_to_applications_menu = create_shortcut; + install_options.add_to_desktop = create_shortcut; + + // It's not yet clear how pinning to shelf will work for policy installed + // Web Apps, but for now never pin them. See crbug.com/880125. + install_options.add_to_quick_launch_bar = false; install_options_list.push_back(std::move(install_options)); }
diff --git a/chrome/browser/web_applications/system_web_app_manager.cc b/chrome/browser/web_applications/system_web_app_manager.cc index d0d4dee..7b5a4fa0 100644 --- a/chrome/browser/web_applications/system_web_app_manager.cc +++ b/chrome/browser/web_applications/system_web_app_manager.cc
@@ -37,7 +37,9 @@ web_app::InstallOptions install_options(url, LaunchContainer::kWindow, InstallSource::kSystemInstalled); - install_options.create_shortcuts = false; + install_options.add_to_applications_menu = false; + install_options.add_to_desktop = false; + install_options.add_to_quick_launch_bar = false; install_options.bypass_service_worker_check = true; install_options.always_update = true; return install_options;
diff --git a/chrome/common/conflicts/module_watcher_win.cc b/chrome/common/conflicts/module_watcher_win.cc index 77048fb3..bdcfb79 100644 --- a/chrome/common/conflicts/module_watcher_win.cc +++ b/chrome/common/conflicts/module_watcher_win.cc
@@ -12,18 +12,15 @@ #include <utility> #include "base/bind.h" -#include "base/debug/dump_without_crashing.h" #include "base/lazy_instance.h" #include "base/location.h" #include "base/memory/ptr_util.h" -#include "base/rand_util.h" #include "base/sequenced_task_runner.h" #include "base/strings/string_piece.h" #include "base/strings/utf_string_conversions.h" #include "base/synchronization/lock.h" #include "base/task/post_task.h" #include "base/task/task_traits.h" -#include "base/threading/platform_thread.h" #include "base/threading/sequenced_task_runner_handle.h" #include "base/win/scoped_handle.h" @@ -114,11 +111,6 @@ constexpr char kLdrRegisterDllNotification[] = "LdrRegisterDllNotification"; constexpr char kLdrUnregisterDllNotification[] = "LdrUnregisterDllNotification"; -// It is currently estimated that around 10 DLLs are loaded in a background -// sequence in Chrome. This number was chosen so that on average 1% of launches -// will cause a process dump. -constexpr int kMaxBackgroundLoadedDllCount = 1000; - // Helper function for converting a UNICODE_STRING to a FilePath. base::FilePath ToFilePath(const UNICODE_STRING* str) { return base::FilePath( @@ -139,15 +131,13 @@ // static std::unique_ptr<ModuleWatcher> ModuleWatcher::Create( - OnModuleEventCallback callback, - bool report_background_loaded_modules) { + OnModuleEventCallback callback) { { base::AutoLock lock(g_module_watcher_lock.Get()); // If a ModuleWatcher already exists then bail out. if (g_module_watcher_instance) return nullptr; - g_module_watcher_instance = - new ModuleWatcher(report_background_loaded_modules); + g_module_watcher_instance = new ModuleWatcher(); } // Initialization mustn't occur while holding |g_module_watcher_lock|. @@ -156,8 +146,6 @@ } ModuleWatcher::~ModuleWatcher() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - // Done before acquiring |g_module_watcher_lock|. UnregisterDllNotificationCallback(); @@ -168,17 +156,10 @@ g_module_watcher_instance = nullptr; } -ModuleWatcher::ModuleWatcher(bool report_background_loaded_modules) - : report_background_loaded_modules_(report_background_loaded_modules), - background_loaded_dll_count_(0), - num_background_loaded_dll_report_( - base::RandInt(0, kMaxBackgroundLoadedDllCount)), - weak_ptr_factory_(this) {} +ModuleWatcher::ModuleWatcher() : weak_ptr_factory_(this) {} // Initializes the ModuleWatcher instance. void ModuleWatcher::Initialize(OnModuleEventCallback callback) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - callback_ = std::move(callback); RegisterDllNotificationCallback(); @@ -245,18 +226,13 @@ } } -void ModuleWatcher::DumpOnBackgroundLoadedModule() { - if (!report_background_loaded_modules_ || - base::PlatformThread::GetCurrentThreadPriority() != - base::ThreadPriority::BACKGROUND) { - return; - } - - if (background_loaded_dll_count_++ == num_background_loaded_dll_report_) { - // DLL loaded on a thread with background priority. This can cause jank on - // the UI thread if it tries to acquire the loader lock. - base::debug::DumpWithoutCrashing(); - } +// static +ModuleWatcher::OnModuleEventCallback ModuleWatcher::GetCallbackForContext( + void* context) { + base::AutoLock lock(g_module_watcher_lock.Get()); + if (context != g_module_watcher_instance) + return OnModuleEventCallback(); + return g_module_watcher_instance->callback_; } // static @@ -264,16 +240,7 @@ unsigned long notification_reason, const LDR_DLL_NOTIFICATION_DATA* notification_data, void* context) { - OnModuleEventCallback callback; - { - base::AutoLock lock(g_module_watcher_lock.Get()); - if (context == g_module_watcher_instance) { - callback = g_module_watcher_instance->callback_; - - g_module_watcher_instance->DumpOnBackgroundLoadedModule(); - } - } - + auto callback = GetCallbackForContext(context); if (!callback) return; @@ -295,7 +262,5 @@ } void ModuleWatcher::RunCallback(const ModuleEvent& event) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - callback_.Run(event); }
diff --git a/chrome/common/conflicts/module_watcher_win.h b/chrome/common/conflicts/module_watcher_win.h index fe681833..a4af43b 100644 --- a/chrome/common/conflicts/module_watcher_win.h +++ b/chrome/common/conflicts/module_watcher_win.h
@@ -11,7 +11,6 @@ #include "base/files/file_path.h" #include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" -#include "base/sequence_checker.h" class ModuleWatcherTest; @@ -90,9 +89,7 @@ // // Only a single instance of a watcher may exist at any moment. This will // return nullptr when trying to create a second watcher. - static std::unique_ptr<ModuleWatcher> Create( - OnModuleEventCallback callback, - bool report_background_loaded_modules); + static std::unique_ptr<ModuleWatcher> Create(OnModuleEventCallback callback); // This can be called on any thread. After destruction the |callback| // provided to the constructor will no longer be invoked with module events. @@ -103,7 +100,7 @@ friend class ModuleWatcherTest; // Private to enforce Singleton semantics. See Create above. - explicit ModuleWatcher(bool report_background_loaded_modules); + ModuleWatcher(); // Initializes the ModuleWatcher instance. void Initialize(OnModuleEventCallback callback); @@ -122,9 +119,9 @@ scoped_refptr<base::SequencedTaskRunner> task_runner, OnModuleEventCallback callback); - // Dumps the process if executed in a background sequence and - // |report_background_loaded_modules_| is true. - void DumpOnBackgroundLoadedModule(); + // Helper function for retrieving the callback associated with a given + // LdrNotification context. + static OnModuleEventCallback GetCallbackForContext(void* context); // The loader notification callback. This is actually // void CALLBACK LoaderNotificationCallback( @@ -144,17 +141,6 @@ // Used by the DllNotification mechanism. void* dll_notification_cookie_ = nullptr; - // Indicates if modules loaded in a background sequence should be reported. - const bool report_background_loaded_modules_; - - // The count of DLL that were loaded in a background sequence. - int background_loaded_dll_count_; - - // The number of background loaded DLL that will cause a process dump. - const int num_background_loaded_dll_report_; - - SEQUENCE_CHECKER(sequence_checker_); - base::WeakPtrFactory<ModuleWatcher> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(ModuleWatcher);
diff --git a/chrome/common/conflicts/module_watcher_win_unittest.cc b/chrome/common/conflicts/module_watcher_win_unittest.cc index 98073e2..9efcb783 100644 --- a/chrome/common/conflicts/module_watcher_win_unittest.cc +++ b/chrome/common/conflicts/module_watcher_win_unittest.cc
@@ -59,8 +59,7 @@ std::unique_ptr<ModuleWatcher> Create() { return ModuleWatcher::Create( - base::Bind(&ModuleWatcherTest::OnModuleEvent, base::Unretained(this)), - /* report_background_loaded_modules = */ false); + base::Bind(&ModuleWatcherTest::OnModuleEvent, base::Unretained(this))); } base::test::ScopedTaskEnvironment scoped_task_environment_;
diff --git a/chrome/common/conflicts/remote_module_watcher_win.cc b/chrome/common/conflicts/remote_module_watcher_win.cc index ca22d93..50cb691 100644 --- a/chrome/common/conflicts/remote_module_watcher_win.cc +++ b/chrome/common/conflicts/remote_module_watcher_win.cc
@@ -63,12 +63,10 @@ connector->BindInterface(content::mojom::kBrowserServiceName, &module_event_sink_); - module_watcher_ = ModuleWatcher::Create( - base::BindRepeating( - &OnModuleEvent, task_runner_, - base::BindRepeating(&RemoteModuleWatcher::HandleModuleEvent, - weak_ptr_factory_.GetWeakPtr())), - /* report_background_loaded_modules = */ false); + module_watcher_ = ModuleWatcher::Create(base::BindRepeating( + &OnModuleEvent, task_runner_, + base::BindRepeating(&RemoteModuleWatcher::HandleModuleEvent, + weak_ptr_factory_.GetWeakPtr()))); } void RemoteModuleWatcher::HandleModuleEvent(
diff --git a/chrome/credential_provider/gaiacp/gaia_resources.grd b/chrome/credential_provider/gaiacp/gaia_resources.grd index e365506..55ec8341 100644 --- a/chrome/credential_provider/gaiacp/gaia_resources.grd +++ b/chrome/credential_provider/gaiacp/gaia_resources.grd
@@ -88,11 +88,14 @@ <message name="IDS_AUTH_FID_DESCRIPTION" desc=""> Sign in using your work account. </message> + <message name="IDS_REAUTH_FID_DESCRIPTION" desc=""> + Your session has expired. Sign in using your work account. + </message> <message name="IDS_AUTH_FID_PROVIDER_LABEL" desc=""> - Add person + Add work account </message> <message name="IDS_EXISTING_AUTH_FID_PROVIDER_LABEL" desc=""> - Sign in using your work account. + Sign in using your work account </message> <message name="IDS_USER_ACCOUNT_COMMENT" desc=""> User created from a work account
diff --git a/chrome/credential_provider/gaiacp/gaia_resources_grd/IDS_AUTH_FID_PROVIDER_LABEL.png.sha1 b/chrome/credential_provider/gaiacp/gaia_resources_grd/IDS_AUTH_FID_PROVIDER_LABEL.png.sha1 index b0b9fc5..be20487 100644 --- a/chrome/credential_provider/gaiacp/gaia_resources_grd/IDS_AUTH_FID_PROVIDER_LABEL.png.sha1 +++ b/chrome/credential_provider/gaiacp/gaia_resources_grd/IDS_AUTH_FID_PROVIDER_LABEL.png.sha1
@@ -1 +1 @@ -19a49972aaaec7dd9126cff9eb619384ca97a9bb \ No newline at end of file +5882568cc1329600b141a486c6a69f0cd7385945 \ No newline at end of file
diff --git a/chrome/credential_provider/gaiacp/gaia_resources_grd/IDS_EXISTING_AUTH_FID_PROVIDER_LABEL.png.sha1 b/chrome/credential_provider/gaiacp/gaia_resources_grd/IDS_EXISTING_AUTH_FID_PROVIDER_LABEL.png.sha1 index e0fd529..9e9df61f 100644 --- a/chrome/credential_provider/gaiacp/gaia_resources_grd/IDS_EXISTING_AUTH_FID_PROVIDER_LABEL.png.sha1 +++ b/chrome/credential_provider/gaiacp/gaia_resources_grd/IDS_EXISTING_AUTH_FID_PROVIDER_LABEL.png.sha1
@@ -1 +1 @@ -0290a1c7d0e931d0cc66411b35ccafdddb2a028e \ No newline at end of file +2918e662e203c8dd44e70bd311f5677500c0ccf2 \ No newline at end of file
diff --git a/chrome/credential_provider/gaiacp/gaia_resources_grd/IDS_REAUTH_FID_DESCRIPTION.png.sha1 b/chrome/credential_provider/gaiacp/gaia_resources_grd/IDS_REAUTH_FID_DESCRIPTION.png.sha1 new file mode 100644 index 0000000..32dd291 --- /dev/null +++ b/chrome/credential_provider/gaiacp/gaia_resources_grd/IDS_REAUTH_FID_DESCRIPTION.png.sha1
@@ -0,0 +1 @@ +e04970e79ced97e4e2e96ff0db4bbc0ae86bb34b \ No newline at end of file
diff --git a/chrome/credential_provider/gaiacp/reauth_credential_base.cc b/chrome/credential_provider/gaiacp/reauth_credential_base.cc index dcbb34d..6c1ee262 100644 --- a/chrome/credential_provider/gaiacp/reauth_credential_base.cc +++ b/chrome/credential_provider/gaiacp/reauth_credential_base.cc
@@ -69,6 +69,9 @@ base::string16 label( GetStringResource(IDS_EXISTING_AUTH_FID_PROVIDER_LABEL_BASE)); return ::SHStrDupW(label.c_str(), value); + } else if (field_id == FID_DESCRIPTION) { + base::string16 label(GetStringResource(IDS_REAUTH_FID_DESCRIPTION_BASE)); + return ::SHStrDupW(label.c_str(), value); } return CGaiaCredentialBase::GetStringValueImpl(field_id, value);
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 15a67a3..2c707c5 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -1871,7 +1871,6 @@ "../browser/chromeos/login/screens/mock_wrong_hwid_screen.cc", "../browser/chromeos/login/screens/mock_wrong_hwid_screen.h", "../browser/chromeos/login/screens/network_screen_browsertest.cc", - "../browser/chromeos/login/screens/recommend_apps_screen_browsertest.cc", "../browser/chromeos/login/screens/update_screen_browsertest.cc", "../browser/chromeos/login/screens/user_selection_screen_browsertest.cc", "../browser/chromeos/login/screenshot_testing/SkDiffPixelsMetric.h",
diff --git a/chrome/test/base/v8_unit_test.cc b/chrome/test/base/v8_unit_test.cc index 18626ac4..cae4e69 100644 --- a/chrome/test/base/v8_unit_test.cc +++ b/chrome/test/base/v8_unit_test.cc
@@ -38,12 +38,41 @@ // testDone results. bool g_test_result_ok = false; +// Location of src root. +base::FilePath g_src_root; + // Location of test data (currently test/data/webui). base::FilePath g_test_data_directory; // Location of generated test data (<(PROGRAM_DIR)/test_data). base::FilePath g_gen_test_data_directory; +// Finds the file that is indicated by |library_path|, updates |library_path| +// to be an absolute path to that file, and returns true. +// If no file is found, returns false. +bool FindLibraryFile(base::FilePath* library_path) { + if (library_path->IsAbsolute()) { + // Absolute file. Only one place to look. + return base::PathExists(*library_path); + } + + // Look for relative file. + base::FilePath possible_path = g_src_root.Append(*library_path); + if (!base::PathExists(possible_path)) { + possible_path = g_gen_test_data_directory.Append(*library_path); + if (!base::PathExists(possible_path)) { + possible_path = g_test_data_directory.Append(*library_path); + if (!base::PathExists(possible_path)) { + return false; // Couldn't find relative file anywhere. + } + } + } + + *library_path = base::MakeAbsoluteFilePath(possible_path); + return true; +} + + } // namespace V8UnitTest::V8UnitTest() : handle_scope_(blink::MainThreadIsolate()) { @@ -64,14 +93,14 @@ ++user_libraries_iterator) { std::string library_content; base::FilePath library_file(*user_libraries_iterator); - if (!user_libraries_iterator->IsAbsolute()) { - base::FilePath gen_file = g_gen_test_data_directory.Append(library_file); - library_file = base::PathExists(gen_file) ? - gen_file : g_test_data_directory.Append(*user_libraries_iterator); + + if (!FindLibraryFile(&library_file)) { + ADD_FAILURE() << "Couldn't find " << library_file.value(); + return false; } - library_file = base::MakeAbsoluteFilePath(library_file); + if (!base::ReadFileToString(library_file, &library_content)) { - ADD_FAILURE() << library_file.value(); + ADD_FAILURE() << "Error reading " << library_file.value(); return false; } ExecuteScriptInContext(library_content, library_file.MaybeAsASCII()); @@ -156,21 +185,20 @@ ASSERT_TRUE(base::PathService::Get(chrome::DIR_GEN_TEST_DATA, &g_gen_test_data_directory)); - base::FilePath src_root; - ASSERT_TRUE(base::PathService::Get(base::DIR_SOURCE_ROOT, &src_root)); + ASSERT_TRUE(base::PathService::Get(base::DIR_SOURCE_ROOT, &g_src_root)); - AddLibrary(src_root.AppendASCII("chrome") - .AppendASCII("third_party") - .AppendASCII("mock4js") - .AppendASCII("mock4js.js")); + AddLibrary(g_src_root.AppendASCII("chrome") + .AppendASCII("third_party") + .AppendASCII("mock4js") + .AppendASCII("mock4js.js")); - AddLibrary(src_root.AppendASCII("third_party") - .AppendASCII("chaijs") - .AppendASCII("chai.js")); + AddLibrary(g_src_root.AppendASCII("third_party") + .AppendASCII("chaijs") + .AppendASCII("chai.js")); - AddLibrary(src_root.AppendASCII("third_party") - .AppendASCII("accessibility-audit") - .AppendASCII("axs_testing.js")); + AddLibrary(g_src_root.AppendASCII("third_party") + .AppendASCII("accessibility-audit") + .AppendASCII("axs_testing.js")); AddLibrary(g_test_data_directory.AppendASCII("test_api.js")); }
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol_unittest.cc index cd6eade..0000693 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol_unittest.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol_unittest.cc
@@ -643,382 +643,227 @@ int expected_duration; DataReductionProxyBypassType expected_bypass_type; } tests[] = { - // Valid data reduction proxy response with no bypass message. - { "GET", - "HTTP/1.1 200 OK\r\n" - "Server: proxy\r\n" - "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", - false, - false, - 0u, - true, - -1, - BYPASS_EVENT_TYPE_MAX, - }, - // Response error does not result in bypass. - { "GET", - "Not an HTTP response", - false, - true, - 0u, - true, - -1, - BYPASS_EVENT_TYPE_MAX, - }, - // Valid data reduction proxy response with chained via header, - // no bypass message. - { "GET", - "HTTP/1.1 200 OK\r\n" - "Server: proxy\r\n" - "Via: 1.1 Chrome-Compression-Proxy, 1.0 some-other-proxy\r\n\r\n", - false, - false, - 0u, - true, - -1, - BYPASS_EVENT_TYPE_MAX - }, - // Valid data reduction proxy response with a bypass message. - { "GET", - "HTTP/1.1 200 OK\r\n" - "Server: proxy\r\n" - "Chrome-Proxy: bypass=0\r\n" - "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", - true, - false, - 1u, - true, - 0, - BYPASS_EVENT_TYPE_MEDIUM - }, - // Valid data reduction proxy response with a bypass message. - { "GET", - "HTTP/1.1 200 OK\r\n" - "Server: proxy\r\n" - "Chrome-Proxy: bypass=1\r\n" - "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", - true, - false, - 1u, - true, - 1, - BYPASS_EVENT_TYPE_SHORT - }, - // Same as above with the OPTIONS method, which is idempotent. - { "OPTIONS", - "HTTP/1.1 200 OK\r\n" - "Server: proxy\r\n" - "Chrome-Proxy: bypass=0\r\n" - "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", - true, - false, - 1u, - true, - 0, - BYPASS_EVENT_TYPE_MEDIUM - }, - // Same as above with the HEAD method, which is idempotent. - { "HEAD", - "HTTP/1.1 200 OK\r\n" - "Server: proxy\r\n" - "Chrome-Proxy: bypass=0\r\n" - "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", - true, - false, - 1u, - false, - 0, - BYPASS_EVENT_TYPE_MEDIUM - }, - // Same as above with the PUT method, which is idempotent. - { "PUT", - "HTTP/1.1 200 OK\r\n" - "Server: proxy\r\n" - "Chrome-Proxy: bypass=0\r\n" - "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", - true, - false, - 1u, - true, - 0, - BYPASS_EVENT_TYPE_MEDIUM - }, - // Same as above with the DELETE method, which is idempotent. - { "DELETE", - "HTTP/1.1 200 OK\r\n" - "Server: proxy\r\n" - "Chrome-Proxy: bypass=0\r\n" - "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", - true, - false, - 1u, - true, - 0, - BYPASS_EVENT_TYPE_MEDIUM - }, - // Same as above with the TRACE method, which is idempotent. - { "TRACE", - "HTTP/1.1 200 OK\r\n" - "Server: proxy\r\n" - "Chrome-Proxy: bypass=0\r\n" - "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", - true, - false, - 1u, - true, - 0, - BYPASS_EVENT_TYPE_MEDIUM - }, - // 500 responses should be bypassed. - { "GET", - "HTTP/1.1 500 Internal Server Error\r\n" - "Server: proxy\r\n" - "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", - true, - false, - 1u, - true, - 0, - BYPASS_EVENT_TYPE_STATUS_500_HTTP_INTERNAL_SERVER_ERROR - }, - // 502 responses should be bypassed. - { "GET", - "HTTP/1.1 502 Internal Server Error\r\n" - "Server: proxy\r\n" - "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", - true, - false, - 1u, - true, - 0, - BYPASS_EVENT_TYPE_STATUS_502_HTTP_BAD_GATEWAY - }, - // 503 responses should be bypassed. - { "GET", - "HTTP/1.1 503 Internal Server Error\r\n" - "Server: proxy\r\n" - "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", - true, - false, - 1u, - true, - 0, - BYPASS_EVENT_TYPE_STATUS_503_HTTP_SERVICE_UNAVAILABLE - }, - // Invalid data reduction proxy 4xx response. Missing Via header. - { "GET", - "HTTP/1.1 404 Not Found\r\n" - "Server: proxy\r\n\r\n", - true, - false, - 0u, - true, - 0, - BYPASS_EVENT_TYPE_MISSING_VIA_HEADER_4XX - }, - // Invalid data reduction proxy response. Missing Via header. - { "GET", - "HTTP/1.1 200 OK\r\n" - "Server: proxy\r\n\r\n", - true, - false, - 1u, - true, - 0, - BYPASS_EVENT_TYPE_MISSING_VIA_HEADER_OTHER - }, - // Invalid data reduction proxy response. Wrong Via header. - { "GET", - "HTTP/1.1 200 OK\r\n" - "Server: proxy\r\n" - "Via: 1.0 some-other-proxy\r\n\r\n", - true, - false, - 1u, - true, - 0, - BYPASS_EVENT_TYPE_MISSING_VIA_HEADER_OTHER - }, - // Valid data reduction proxy response. 304 missing Via header. - { "GET", - "HTTP/1.1 304 Not Modified\r\n" - "Server: proxy\r\n\r\n", - false, - false, - 0u, - false, - 0, - BYPASS_EVENT_TYPE_MAX - }, - // Valid data reduction proxy response with a bypass message. It will - // not be retried because the request is non-idempotent. - { "POST", - "HTTP/1.1 200 OK\r\n" - "Server: proxy\r\n" - "Chrome-Proxy: bypass=0\r\n" - "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", - false, - false, - 1u, - true, - 0, - BYPASS_EVENT_TYPE_MEDIUM - }, - // Valid data reduction proxy response with block message. Both proxies - // should be on the retry list when it completes. - { "GET", - "HTTP/1.1 200 OK\r\n" - "Server: proxy\r\n" - "Chrome-Proxy: block=1\r\n" - "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", - true, - false, - 2u, - true, - 1, - BYPASS_EVENT_TYPE_SHORT - }, - // Valid data reduction proxy response with a block-once message. It will be - // retried, and there will be no proxies on the retry list since block-once - // only affects the current request. - { "GET", - "HTTP/1.1 200 OK\r\n" - "Server: proxy\r\n" - "Chrome-Proxy: block-once\r\n" - "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", - true, - false, - 0u, - true, - 0, - BYPASS_EVENT_TYPE_CURRENT - }, - // Same as above with the OPTIONS method, which is idempotent. - { "OPTIONS", - "HTTP/1.1 200 OK\r\n" - "Server: proxy\r\n" - "Chrome-Proxy: block-once\r\n" - "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", - true, - false, - 0u, - true, - 0, - BYPASS_EVENT_TYPE_CURRENT - }, - // Same as above with the HEAD method, which is idempotent. - { "HEAD", - "HTTP/1.1 200 OK\r\n" - "Server: proxy\r\n" - "Chrome-Proxy: block-once\r\n" - "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", - true, - false, - 0u, - false, - 0, - BYPASS_EVENT_TYPE_CURRENT - }, - // Same as above with the PUT method, which is idempotent. - { "PUT", - "HTTP/1.1 200 OK\r\n" - "Server: proxy\r\n" - "Chrome-Proxy: block-once\r\n" - "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", - true, - false, - 0u, - true, - 0, - BYPASS_EVENT_TYPE_CURRENT - }, - // Same as above with the DELETE method, which is idempotent. - { "DELETE", - "HTTP/1.1 200 OK\r\n" - "Server: proxy\r\n" - "Chrome-Proxy: block-once\r\n" - "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", - true, - false, - 0u, - true, - 0, - BYPASS_EVENT_TYPE_CURRENT - }, - // Same as above with the TRACE method, which is idempotent. - { "TRACE", - "HTTP/1.1 200 OK\r\n" - "Server: proxy\r\n" - "Chrome-Proxy: block-once\r\n" - "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", - true, - false, - 0u, - true, - 0, - BYPASS_EVENT_TYPE_CURRENT - }, - // Valid Data Reduction Proxy response with a block-once message. It will - // be retried because block-once indicates that request did not reach the - // origin and client should retry. Only current request is retried direct, - // so there should be no proxies on the retry list. - { "POST", - "HTTP/1.1 200 OK\r\n" - "Server: proxy\r\n" - "Chrome-Proxy: block-once\r\n" - "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", - true, - false, - 0u, - true, - 0, - BYPASS_EVENT_TYPE_CURRENT - }, - // Valid Data Reduction Proxy response with a bypass message. It will - // not be retried because the request is non-idempotent. Both proxies - // should be on the retry list for 1 second. - { "POST", - "HTTP/1.1 200 OK\r\n" - "Server: proxy\r\n" - "Chrome-Proxy: block=1\r\n" - "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", - false, - false, - 2u, - true, - 1, - BYPASS_EVENT_TYPE_SHORT - }, - // Valid data reduction proxy response with block and block-once messages. - // The block message will override the block-once message, so both proxies - // should be on the retry list when it completes. - { "GET", - "HTTP/1.1 200 OK\r\n" - "Server: proxy\r\n" - "Chrome-Proxy: block=1, block-once\r\n" - "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", - true, - false, - 2u, - true, - 1, - BYPASS_EVENT_TYPE_SHORT - }, - // Valid data reduction proxy response with bypass and block-once messages. - // The bypass message will override the block-once message, so one proxy - // should be on the retry list when it completes. - { "GET", - "HTTP/1.1 200 OK\r\n" - "Server: proxy\r\n" - "Chrome-Proxy: bypass=1, block-once\r\n" - "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", - true, - false, - 1u, - true, - 1, - BYPASS_EVENT_TYPE_SHORT - }, + // Valid data reduction proxy response with no bypass message. + { + "GET", + "HTTP/1.1 200 OK\r\n" + "Server: proxy\r\n" + "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", + false, + false, + 0u, + true, + -1, + BYPASS_EVENT_TYPE_MAX, + }, + // Response error does not result in bypass. + { + "GET", + "Not an HTTP response", + false, + true, + 0u, + true, + -1, + BYPASS_EVENT_TYPE_MAX, + }, + // Valid data reduction proxy response with chained via header, + // no bypass message. + {"GET", + "HTTP/1.1 200 OK\r\n" + "Server: proxy\r\n" + "Via: 1.1 Chrome-Compression-Proxy, 1.0 some-other-proxy\r\n\r\n", + false, false, 0u, true, -1, BYPASS_EVENT_TYPE_MAX}, + // Valid data reduction proxy response with a bypass message. + {"GET", + "HTTP/1.1 200 OK\r\n" + "Server: proxy\r\n" + "Chrome-Proxy: bypass=0\r\n" + "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", + true, false, 1u, true, 0, BYPASS_EVENT_TYPE_MEDIUM}, + // Valid data reduction proxy response with a bypass message. + {"GET", + "HTTP/1.1 200 OK\r\n" + "Server: proxy\r\n" + "Chrome-Proxy: bypass=1\r\n" + "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", + true, false, 1u, true, 1, BYPASS_EVENT_TYPE_SHORT}, + // Same as above with the OPTIONS method, which is idempotent. + {"OPTIONS", + "HTTP/1.1 200 OK\r\n" + "Server: proxy\r\n" + "Chrome-Proxy: bypass=0\r\n" + "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", + true, false, 1u, true, 0, BYPASS_EVENT_TYPE_MEDIUM}, + // Same as above with the HEAD method, which is idempotent. + {"HEAD", + "HTTP/1.1 200 OK\r\n" + "Server: proxy\r\n" + "Chrome-Proxy: bypass=0\r\n" + "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", + true, false, 1u, false, 0, BYPASS_EVENT_TYPE_MEDIUM}, + // Same as above with the PUT method, which is idempotent. + {"PUT", + "HTTP/1.1 200 OK\r\n" + "Server: proxy\r\n" + "Chrome-Proxy: bypass=0\r\n" + "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", + true, false, 1u, true, 0, BYPASS_EVENT_TYPE_MEDIUM}, + // Same as above with the DELETE method, which is idempotent. + {"DELETE", + "HTTP/1.1 200 OK\r\n" + "Server: proxy\r\n" + "Chrome-Proxy: bypass=0\r\n" + "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", + true, false, 1u, true, 0, BYPASS_EVENT_TYPE_MEDIUM}, + // Same as above with the TRACE method, which is idempotent. + {"TRACE", + "HTTP/1.1 200 OK\r\n" + "Server: proxy\r\n" + "Chrome-Proxy: bypass=0\r\n" + "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", + true, false, 1u, true, 0, BYPASS_EVENT_TYPE_MEDIUM}, + // 500 responses should be bypassed. + {"GET", + "HTTP/1.1 500 Internal Server Error\r\n" + "Server: proxy\r\n" + "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", + true, false, 1u, true, 0, + BYPASS_EVENT_TYPE_STATUS_500_HTTP_INTERNAL_SERVER_ERROR}, + // 502 responses should be bypassed. + {"GET", + "HTTP/1.1 502 Internal Server Error\r\n" + "Server: proxy\r\n" + "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", + true, false, 0u, true, 0, BYPASS_EVENT_TYPE_STATUS_502_HTTP_BAD_GATEWAY}, + // 503 responses should be bypassed. + {"GET", + "HTTP/1.1 503 Internal Server Error\r\n" + "Server: proxy\r\n" + "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", + true, false, 1u, true, 0, + BYPASS_EVENT_TYPE_STATUS_503_HTTP_SERVICE_UNAVAILABLE}, + // Invalid data reduction proxy 4xx response. Missing Via header. + {"GET", + "HTTP/1.1 404 Not Found\r\n" + "Server: proxy\r\n\r\n", + true, false, 0u, true, 0, BYPASS_EVENT_TYPE_MISSING_VIA_HEADER_4XX}, + // Invalid data reduction proxy response. Missing Via header. + {"GET", + "HTTP/1.1 200 OK\r\n" + "Server: proxy\r\n\r\n", + true, false, 1u, true, 0, BYPASS_EVENT_TYPE_MISSING_VIA_HEADER_OTHER}, + // Invalid data reduction proxy response. Wrong Via header. + {"GET", + "HTTP/1.1 200 OK\r\n" + "Server: proxy\r\n" + "Via: 1.0 some-other-proxy\r\n\r\n", + true, false, 1u, true, 0, BYPASS_EVENT_TYPE_MISSING_VIA_HEADER_OTHER}, + // Valid data reduction proxy response. 304 missing Via header. + {"GET", + "HTTP/1.1 304 Not Modified\r\n" + "Server: proxy\r\n\r\n", + false, false, 0u, false, 0, BYPASS_EVENT_TYPE_MAX}, + // Valid data reduction proxy response with a bypass message. It will + // not be retried because the request is non-idempotent. + {"POST", + "HTTP/1.1 200 OK\r\n" + "Server: proxy\r\n" + "Chrome-Proxy: bypass=0\r\n" + "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", + false, false, 1u, true, 0, BYPASS_EVENT_TYPE_MEDIUM}, + // Valid data reduction proxy response with block message. Both proxies + // should be on the retry list when it completes. + {"GET", + "HTTP/1.1 200 OK\r\n" + "Server: proxy\r\n" + "Chrome-Proxy: block=1\r\n" + "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", + true, false, 2u, true, 1, BYPASS_EVENT_TYPE_SHORT}, + // Valid data reduction proxy response with a block-once message. It will + // be + // retried, and there will be no proxies on the retry list since + // block-once + // only affects the current request. + {"GET", + "HTTP/1.1 200 OK\r\n" + "Server: proxy\r\n" + "Chrome-Proxy: block-once\r\n" + "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", + true, false, 0u, true, 0, BYPASS_EVENT_TYPE_CURRENT}, + // Same as above with the OPTIONS method, which is idempotent. + {"OPTIONS", + "HTTP/1.1 200 OK\r\n" + "Server: proxy\r\n" + "Chrome-Proxy: block-once\r\n" + "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", + true, false, 0u, true, 0, BYPASS_EVENT_TYPE_CURRENT}, + // Same as above with the HEAD method, which is idempotent. + {"HEAD", + "HTTP/1.1 200 OK\r\n" + "Server: proxy\r\n" + "Chrome-Proxy: block-once\r\n" + "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", + true, false, 0u, false, 0, BYPASS_EVENT_TYPE_CURRENT}, + // Same as above with the PUT method, which is idempotent. + {"PUT", + "HTTP/1.1 200 OK\r\n" + "Server: proxy\r\n" + "Chrome-Proxy: block-once\r\n" + "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", + true, false, 0u, true, 0, BYPASS_EVENT_TYPE_CURRENT}, + // Same as above with the DELETE method, which is idempotent. + {"DELETE", + "HTTP/1.1 200 OK\r\n" + "Server: proxy\r\n" + "Chrome-Proxy: block-once\r\n" + "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", + true, false, 0u, true, 0, BYPASS_EVENT_TYPE_CURRENT}, + // Same as above with the TRACE method, which is idempotent. + {"TRACE", + "HTTP/1.1 200 OK\r\n" + "Server: proxy\r\n" + "Chrome-Proxy: block-once\r\n" + "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", + true, false, 0u, true, 0, BYPASS_EVENT_TYPE_CURRENT}, + // Valid Data Reduction Proxy response with a block-once message. It will + // be retried because block-once indicates that request did not reach the + // origin and client should retry. Only current request is retried direct, + // so there should be no proxies on the retry list. + {"POST", + "HTTP/1.1 200 OK\r\n" + "Server: proxy\r\n" + "Chrome-Proxy: block-once\r\n" + "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", + true, false, 0u, true, 0, BYPASS_EVENT_TYPE_CURRENT}, + // Valid Data Reduction Proxy response with a bypass message. It will + // not be retried because the request is non-idempotent. Both proxies + // should be on the retry list for 1 second. + {"POST", + "HTTP/1.1 200 OK\r\n" + "Server: proxy\r\n" + "Chrome-Proxy: block=1\r\n" + "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", + false, false, 2u, true, 1, BYPASS_EVENT_TYPE_SHORT}, + // Valid data reduction proxy response with block and block-once messages. + // The block message will override the block-once message, so both proxies + // should be on the retry list when it completes. + {"GET", + "HTTP/1.1 200 OK\r\n" + "Server: proxy\r\n" + "Chrome-Proxy: block=1, block-once\r\n" + "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", + true, false, 2u, true, 1, BYPASS_EVENT_TYPE_SHORT}, + // Valid data reduction proxy response with bypass and block-once + // messages. + // The bypass message will override the block-once message, so one proxy + // should be on the retry list when it completes. + {"GET", + "HTTP/1.1 200 OK\r\n" + "Server: proxy\r\n" + "Chrome-Proxy: bypass=1, block-once\r\n" + "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", + true, false, 1u, true, 1, BYPASS_EVENT_TYPE_SHORT}, }; test_context_->config()->test_params()->UseNonSecureProxiesForHttp(); std::string primary = test_context_->config() @@ -1172,14 +1017,14 @@ {"HTTP/1.1 502 Bad Gateway\r\n" "Server: proxy\r\n" "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", - true, true, BYPASS_EVENT_TYPE_STATUS_502_HTTP_BAD_GATEWAY}, + true, false, BYPASS_EVENT_TYPE_STATUS_502_HTTP_BAD_GATEWAY}, {"HTTP/1.1 200 OK\r\n" "Server: proxy\r\n" "Chrome-Proxy: block=0\r\n\r\n", false, false, BYPASS_EVENT_TYPE_MAX}, {"HTTP/1.1 502 Bad Gateway\r\n" "Server: proxy\r\n\r\n", - false, false, BYPASS_EVENT_TYPE_MAX}, + true, false, BYPASS_EVENT_TYPE_MAX}, }; for (const auto& test : test_cases) {
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats_unittest.cc index bdb54b35..4f929ba 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats_unittest.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats_unittest.cc
@@ -473,6 +473,22 @@ histogram_tester, "DataReductionProxy.BypassedBytes.ProxyOverridden"); } +TEST_F(DataReductionProxyBypassStatsEndToEndTest, NoChromeProxy502AreBypassed) { + InitializeContext(); + base::HistogramTester histogram_tester; + CreateAndExecuteRequest(GURL("http://foo.com"), net::LOAD_NORMAL, net::OK, + "HTTP/1.1 502 Bad Gateway\r\n" + "Via: 1.1 Chrome-Compression-Proxy\r\n" + "Chrome-Proxy: block-once\r\n\r\n", + kErrorBody.c_str(), "HTTP/1.1 200 OK\r\n\r\n", + kBody.c_str()); + + histogram_tester.ExpectUniqueSample( + "DataReductionProxy.BypassedBytes.Current", kBody.size(), 1); + ExpectOtherBypassedBytesHistogramsEmpty( + histogram_tester, "DataReductionProxy.BypassedBytes.Current"); +} + TEST_F(DataReductionProxyBypassStatsEndToEndTest, BypassedBytesCurrent) { InitializeContext(); struct TestCase { @@ -610,9 +626,6 @@ { "DataReductionProxy.BypassedBytes.Status500HttpInternalServerError", "HTTP/1.1 500 Internal Server Error\r\n\r\n", }, - { "DataReductionProxy.BypassedBytes.Status502HttpBadGateway", - "HTTP/1.1 502 Bad Gateway\r\n\r\n", - }, { "DataReductionProxy.BypassedBytes.Status503HttpServiceUnavailable", "HTTP/1.1 503 Service Unavailable\r\n\r\n", },
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc index 1834dee..3c234c3 100644 --- a/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc +++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc
@@ -46,5 +46,10 @@ "DataReductionProxyEnabledWithNetworkService", base::FEATURE_DISABLED_BY_DEFAULT}; +// Enables block-once action when 502 is received with no Chrome-Proxy header. +const base::Feature kDataReductionProxyBlockOnceOnBadGatewayResponse{ + "DataReductionProxyBlockOnceOnBadGatewayResponse", + base::FEATURE_ENABLED_BY_DEFAULT}; + } // namespace features } // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_features.h b/components/data_reduction_proxy/core/common/data_reduction_proxy_features.h index 3347846..65802a2 100644 --- a/components/data_reduction_proxy/core/common/data_reduction_proxy_features.h +++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_features.h
@@ -17,6 +17,7 @@ extern const base::Feature kDataSaverSiteBreakdownUsingPageLoadMetrics; extern const base::Feature kDataReductionProxyEnabledWithNetworkService; extern const base::Feature kDataSaverUseOnDeviceSafeBrowsing; +extern const base::Feature kDataReductionProxyBlockOnceOnBadGatewayResponse; } // namespace features } // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc index 2764f52..305286e 100644 --- a/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc +++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc
@@ -418,8 +418,16 @@ // Fall back if a 500, 502 or 503 is returned. if (headers.response_code() == net::HTTP_INTERNAL_SERVER_ERROR) return BYPASS_EVENT_TYPE_STATUS_500_HTTP_INTERNAL_SERVER_ERROR; - if (headers.response_code() == net::HTTP_BAD_GATEWAY) + if (headers.response_code() == net::HTTP_BAD_GATEWAY) { + if (base::FeatureList::IsEnabled( + features::kDataReductionProxyBlockOnceOnBadGatewayResponse)) { + data_reduction_proxy_info->bypass_all = true; + data_reduction_proxy_info->mark_proxies_as_bad = false; + data_reduction_proxy_info->bypass_duration = base::TimeDelta(); + data_reduction_proxy_info->bypass_action = BYPASS_ACTION_TYPE_BLOCK_ONCE; + } return BYPASS_EVENT_TYPE_STATUS_502_HTTP_BAD_GATEWAY; + } if (headers.response_code() == net::HTTP_SERVICE_UNAVAILABLE) return BYPASS_EVENT_TYPE_STATUS_503_HTTP_SERVICE_UNAVAILABLE; // TODO(kundaji): Bypass if Proxy-Authenticate header value cannot be
diff --git a/components/sync_sessions/favicon_cache.cc b/components/sync_sessions/favicon_cache.cc index 2fed6405..ca58d61f 100644 --- a/components/sync_sessions/favicon_cache.cc +++ b/components/sync_sessions/favicon_cache.cc
@@ -226,7 +226,6 @@ history::HistoryService* history_service, int max_sync_favicon_limit) : favicon_service_(favicon_service), - history_service_(history_service), max_sync_favicon_limit_(max_sync_favicon_limit), history_service_observer_(this), weak_ptr_factory_(this) { @@ -237,16 +236,6 @@ FaviconCache::~FaviconCache() {} -void FaviconCache::WaitUntilReadyToSync(base::OnceClosure done) { - if (history_service_->backend_loaded()) { - std::move(done).Run(); - } else { - // Wait until HistoryService's backend loads, reported via - // OnHistoryServiceLoaded(). - wait_until_ready_to_sync_cb_ = std::move(done); - } -} - syncer::SyncMergeResult FaviconCache::MergeDataAndStartSyncing( syncer::ModelType type, const syncer::SyncDataList& initial_sync_data, @@ -1027,10 +1016,4 @@ } } -void FaviconCache::OnHistoryServiceLoaded( - history::HistoryService* history_service) { - if (wait_until_ready_to_sync_cb_) - std::move(wait_until_ready_to_sync_cb_).Run(); -} - } // namespace sync_sessions
diff --git a/components/sync_sessions/favicon_cache.h b/components/sync_sessions/favicon_cache.h index 03aca1b0..08946fb 100644 --- a/components/sync_sessions/favicon_cache.h +++ b/components/sync_sessions/favicon_cache.h
@@ -66,7 +66,6 @@ ~FaviconCache() override; // SyncableService implementation. - void WaitUntilReadyToSync(base::OnceClosure done) override; syncer::SyncMergeResult MergeDataAndStartSyncing( syncer::ModelType type, const syncer::SyncDataList& initial_sync_data, @@ -199,11 +198,8 @@ // history::HistoryServiceObserver: void OnURLsDeleted(history::HistoryService* history_service, const history::DeletionInfo& deletion_info) override; - void OnHistoryServiceLoaded( - history::HistoryService* history_service) override; - favicon::FaviconService* const favicon_service_; - history::HistoryService* const history_service_; + favicon::FaviconService* favicon_service_; // Task tracker for loading favicons. base::CancelableTaskTracker cancelable_task_tracker_; @@ -230,8 +226,6 @@ // Maximum number of favicons to sync. 0 means no limit. const size_t max_sync_favicon_limit_; - base::OnceClosure wait_until_ready_to_sync_cb_; - ScopedObserver<history::HistoryService, history::HistoryServiceObserver> history_service_observer_;
diff --git a/components/ui_devtools/ui_element.cc b/components/ui_devtools/ui_element.cc index a760ee02..20a3489 100644 --- a/components/ui_devtools/ui_element.cc +++ b/components/ui_devtools/ui_element.cc
@@ -76,19 +76,23 @@ children_.erase(iter); } -void UIElement::ReorderChild(UIElement* child, int new_index) { - auto iter = std::find(children_.begin(), children_.end(), child); - DCHECK(iter != children_.end()); +void UIElement::ReorderChild(UIElement* child, int index) { + auto i = std::find(children_.begin(), children_.end(), child); + DCHECK(i != children_.end()); + DCHECK_GE(index, 0); + DCHECK_LT(static_cast<size_t>(index), children_.size()); - // Don't re-order if the new position is the same as the old position. - if (std::distance(children_.begin(), iter) == new_index) + // If |child| is already at the desired position, there's nothing to do. + const auto pos = std::next(children_.begin(), index); + if (i == pos) return; - children_.erase(iter); - // Move child to new position |new_index| in vector |children_|. - new_index = std::min(static_cast<int>(children_.size()) - 1, new_index); - iter = children_.begin() + new_index; - children_.insert(iter, child); + // Rotate |child| to be at the desired position. + if (pos < i) + std::rotate(pos, i, std::next(i)); + else + std::rotate(i, std::next(i), std::next(pos)); + delegate()->OnUIElementReordered(child->parent(), child); }
diff --git a/components/ui_devtools/ui_element.h b/components/ui_devtools/ui_element.h index fb3737d5..217e406 100644 --- a/components/ui_devtools/ui_element.h +++ b/components/ui_devtools/ui_element.h
@@ -65,8 +65,8 @@ // OnUIElementRemoved(), which destroys the DOM node for |child|. void RemoveChild(UIElement* child, bool notify_delegate = true); - // Move |child| to position new_index in |children_|. - void ReorderChild(UIElement* child, int new_index); + // Moves |child| to position |index| in |children_|. + void ReorderChild(UIElement* child, int index); template <class T> int FindUIElementIdForBackendElement(T* element) const;
diff --git a/components/viz/common/frame_sinks/begin_frame_source.cc b/components/viz/common/frame_sinks/begin_frame_source.cc index 65b081cb..769cd717 100644 --- a/components/viz/common/frame_sinks/begin_frame_source.cc +++ b/components/viz/common/frame_sinks/begin_frame_source.cc
@@ -41,8 +41,29 @@ observer->OnBeginFrame(args); } +// Checks |args| for continuity with our last args. It is possible that the +// source in which |args| originate changes, or that our hookup to this source +// changes, so we have to check for continuity. See also +// https://crbug.com/690127 for what may happen without this check. +bool CheckBeginFrameContinuity(BeginFrameObserver* observer, + const BeginFrameArgs& args) { + const BeginFrameArgs& last_args = observer->LastUsedBeginFrameArgs(); + if (!last_args.IsValid() || (args.frame_time > last_args.frame_time)) { + DCHECK((args.source_id != last_args.source_id) || + (args.sequence_number > last_args.sequence_number)) + << "current " << args.AsValue()->ToString() << ", last " + << last_args.AsValue()->ToString(); + return true; + } + return false; +} } // namespace +// BeginFrameObserver ----------------------------------------------------- +bool BeginFrameObserver::IsRoot() const { + return false; +} + // BeginFrameObserverBase ------------------------------------------------- BeginFrameObserverBase::BeginFrameObserverBase() = default; @@ -385,18 +406,24 @@ last_begin_frame_args_ = args; base::flat_set<BeginFrameObserver*> observers(observers_); + + // Process non-root observers. + // TODO(ericrk): Remove root/non-root handling once a better workaround + // exists. https://crbug.com/947717 for (auto* obs : observers) { - // It is possible that the source in which |args| originate changes, or that - // our hookup to this source changes, so we have to check for continuity. - // See also https://crbug.com/690127 for what may happen without this check. - const BeginFrameArgs& last_args = obs->LastUsedBeginFrameArgs(); - if (!last_args.IsValid() || (args.frame_time > last_args.frame_time)) { - DCHECK((args.source_id != last_args.source_id) || - (args.sequence_number > last_args.sequence_number)) - << "current " << args.AsValue()->ToString() << ", last " - << last_args.AsValue()->ToString(); - FilterAndIssueBeginFrame(obs, args); - } + if (obs->IsRoot()) + continue; + if (!CheckBeginFrameContinuity(obs, args)) + continue; + FilterAndIssueBeginFrame(obs, args); + } + // Process root observers. + for (auto* obs : observers) { + if (!obs->IsRoot()) + continue; + if (!CheckBeginFrameContinuity(obs, args)) + continue; + FilterAndIssueBeginFrame(obs, args); } } @@ -404,17 +431,9 @@ BeginFrameObserver* obs) { if (!last_begin_frame_args_.IsValid()) return BeginFrameArgs(); - - const BeginFrameArgs& last_args = obs->LastUsedBeginFrameArgs(); - if (last_args.IsValid() && - last_begin_frame_args_.frame_time <= last_args.frame_time) { + if (!CheckBeginFrameContinuity(obs, last_begin_frame_args_)) return BeginFrameArgs(); - } - DCHECK((last_begin_frame_args_.source_id != last_args.source_id) || - (last_begin_frame_args_.sequence_number > last_args.sequence_number)) - << "current " << last_begin_frame_args_.AsValue()->ToString() << ", last " - << last_args.AsValue()->ToString(); BeginFrameArgs missed_args = last_begin_frame_args_; missed_args.type = BeginFrameArgs::MISSED; return missed_args;
diff --git a/components/viz/common/frame_sinks/begin_frame_source.h b/components/viz/common/frame_sinks/begin_frame_source.h index ec70441..a718369 100644 --- a/components/viz/common/frame_sinks/begin_frame_source.h +++ b/components/viz/common/frame_sinks/begin_frame_source.h
@@ -62,6 +62,13 @@ // Whether the observer also wants to receive animate_only BeginFrames. virtual bool WantsAnimateOnlyBeginFrames() const = 0; + + // Indicates whether this observer is the root frame sink. This helps in + // a workaround for input jank, allowing us to deliver BeginFrames to the + // root last, avoiding a race. + // TODO(ericrk): Remove this once we have a longer-term fix. + // https://crbug.com/947717 + virtual bool IsRoot() const; }; // Simple base class which implements a BeginFrameObserver which checks the
diff --git a/components/viz/common/frame_sinks/begin_frame_source_unittest.cc b/components/viz/common/frame_sinks/begin_frame_source_unittest.cc index 6d5633a..65fc6fd 100644 --- a/components/viz/common/frame_sinks/begin_frame_source_unittest.cc +++ b/components/viz/common/frame_sinks/begin_frame_source_unittest.cc
@@ -618,5 +618,52 @@ source_->AddObserver(obs_.get()); } +// Tests that an observer which returns true from IsRoot is notified after +// observers which return false. +TEST_F(ExternalBeginFrameSourceTest, RootsNotifiedLast) { + using ::testing::InSequence; + + NiceMock<MockBeginFrameObserver> obs1, obs2; + source_->AddObserver(&obs1); + source_->AddObserver(&obs2); + + { + BeginFrameArgs args = CreateBeginFrameArgsForTesting( + BEGINFRAME_FROM_HERE, 0, 1, 10000, 10100, 100); + // Set obs1 to root, obs2 to child. + EXPECT_CALL(obs1, IsRoot()).WillRepeatedly(::testing::Return(true)); + EXPECT_CALL(obs2, IsRoot()).WillRepeatedly(::testing::Return(false)); + { + // Ensure that OnBeginFrame delivers the calls in the right order. + InSequence s; + EXPECT_CALL(obs2, OnBeginFrame(args)) + .WillOnce(::testing::SaveArg<0>(&(obs2.last_begin_frame_args))); + EXPECT_CALL(obs1, OnBeginFrame(args)) + .WillOnce(::testing::SaveArg<0>(&(obs1.last_begin_frame_args))); + source_->OnBeginFrame(args); + } + } + + { + BeginFrameArgs args = CreateBeginFrameArgsForTesting( + BEGINFRAME_FROM_HERE, 0, 2, 10001, 10101, 100); + // Set obs2 to root, obs1 to child. + EXPECT_CALL(obs1, IsRoot()).WillRepeatedly(::testing::Return(false)); + EXPECT_CALL(obs2, IsRoot()).WillRepeatedly(::testing::Return(true)); + { + // Ensure that OnBeginFrame delivers the calls in the right order. + InSequence s; + EXPECT_CALL(obs1, OnBeginFrame(args)) + .WillOnce(::testing::SaveArg<0>(&(obs1.last_begin_frame_args))); + EXPECT_CALL(obs2, OnBeginFrame(args)) + .WillOnce(::testing::SaveArg<0>(&(obs2.last_begin_frame_args))); + source_->OnBeginFrame(args); + } + } + + source_->RemoveObserver(&obs1); + source_->RemoveObserver(&obs2); +} + } // namespace } // namespace viz
diff --git a/components/viz/common/quads/shared_quad_state.h b/components/viz/common/quads/shared_quad_state.h index c9043f50..c339d46c 100644 --- a/components/viz/common/quads/shared_quad_state.h +++ b/components/viz/common/quads/shared_quad_state.h
@@ -7,6 +7,7 @@ #include <memory> +#include "base/optional.h" #include "components/viz/common/viz_common_export.h" #include "third_party/skia/include/core/SkBlendMode.h" #include "ui/gfx/geometry/rect.h" @@ -76,6 +77,11 @@ // merge quads for a surface into their target render pass. It is a // performance optimization by avoiding render passes as much as possible. bool is_fast_rounded_corner = false; + // This is for underlay optimization and used only in the SurfaceAggregator + // and the OverlayProcessor. This damage rect contains union of damage from + // occluding surfaces and is only for quads that are the only quad in + // their surface. SetAll() doesn't update this data. + base::Optional<gfx::Rect> occluding_damage_rect; }; } // namespace viz
diff --git a/components/viz/service/display/dc_layer_overlay.cc b/components/viz/service/display/dc_layer_overlay.cc index 9fe6799b..429590b 100644 --- a/components/viz/service/display/dc_layer_overlay.cc +++ b/components/viz/service/display/dc_layer_overlay.cc
@@ -330,8 +330,8 @@ gfx::ToEnclosingRect(ClippedQuadRectangle(solid_quad)); // Propagate punch through rect as damage up the stack of render passes. // TODO(sunnyps): We should avoid this extra damage if we knew that the - // video (in child render surface) was the only thing damaging this render - // surface. + // video (in child render surface) was the only thing damaging this + // render surface. damage_rect->Union(clipped_quad_rect); // Add transformed info to list in case this renderpass is included in @@ -438,8 +438,7 @@ } else { ProcessForUnderlay(display_rect, render_pass, quad_rectangle_in_target_space, occlusion_bounding_box, - it, is_root, has_occluding_surface_damage, damage_rect, - &this_frame_underlay_rect, + it, is_root, damage_rect, &this_frame_underlay_rect, &this_frame_underlay_occlusion, &dc_layer); } @@ -510,7 +509,6 @@ const gfx::RectF& occlusion_bounding_box, const QuadList::Iterator& it, bool is_root, - bool has_occluding_surface_damage, gfx::Rect* damage_rect, gfx::Rect* this_frame_underlay_rect, gfx::Rect* this_frame_underlay_occlusion, @@ -564,12 +562,12 @@ if (is_root && current_frame_processed_overlay_count_ == 0 && is_axis_aligned && is_opaque && !underlay_rect_changed && - !display_rect_changed) { + !display_rect_changed && + shared_quad_state->occluding_damage_rect.has_value()) { // If this underlay rect is the same as for last frame, subtract its area // from the damage of the main surface, as the cleared area was already // cleared last frame. Add back the damage from the occluded area for this - // and last frame, as that may have changed. - gfx::Rect occluding_damage_rect = *damage_rect; + // frame. damage_rect->Subtract(quad_rectangle); // If none of the quads on top give any damage, we can skip compositing @@ -578,19 +576,9 @@ // compositor will be empty. If the incoming damage rect is bigger than the // video quad, we don't have an oppertunity for power optimization even if // no damage on top. The output damage rect will not be empty in this case. - if (has_occluding_surface_damage) { - gfx::Rect occlusion = gfx::ToEnclosingRect(occlusion_bounding_box); - occlusion.Union(previous_frame_underlay_occlusion_); - - occluding_damage_rect.Intersect(quad_rectangle); - occluding_damage_rect.Intersect(occlusion); - - damage_rect->Union(occluding_damage_rect); - } + damage_rect->Union(shared_quad_state->occluding_damage_rect.value()); } else { // Entire replacement quad must be redrawn. - // TODO(sunnyps): We should avoid this extra damage if we knew that the - // video was the only thing damaging this render surface. damage_rect->Union(quad_rectangle); }
diff --git a/components/viz/service/display/dc_layer_overlay.h b/components/viz/service/display/dc_layer_overlay.h index 0fe4e8d..919f112 100644 --- a/components/viz/service/display/dc_layer_overlay.h +++ b/components/viz/service/display/dc_layer_overlay.h
@@ -108,7 +108,6 @@ const gfx::RectF& occlusion_bounding_box, const QuadList::Iterator& it, bool is_root, - bool has_occluding_surface_damage, gfx::Rect* damage_rect, gfx::Rect* this_frame_underlay_rect, gfx::Rect* this_frame_underlay_occlusion,
diff --git a/components/viz/service/display/display.cc b/components/viz/service/display/display.cc index 02fe84d..9d50f66c 100644 --- a/components/viz/service/display/display.cc +++ b/components/viz/service/display/display.cc
@@ -340,10 +340,15 @@ // TODO(jbauman): Outputting an incomplete quad list doesn't work when using // overlays. - bool output_partial_list = renderer_->use_partial_swap() && - !output_surface_->GetOverlayCandidateValidator(); + OverlayCandidateValidator* overlay_validator = + output_surface_->GetOverlayCandidateValidator(); + bool output_partial_list = + renderer_->use_partial_swap() && !overlay_validator; + bool needs_surface_occluding_damage_rect = + overlay_validator && overlay_validator->AllowDCLayerOverlays(); aggregator_.reset(new SurfaceAggregator( - surface_manager_, resource_provider_.get(), output_partial_list)); + surface_manager_, resource_provider_.get(), output_partial_list, + needs_surface_occluding_damage_rect)); aggregator_->set_output_is_secure(output_is_secure_); aggregator_->SetOutputColorSpace(blending_color_space_, device_color_space_); }
diff --git a/components/viz/service/display/overlay_unittest.cc b/components/viz/service/display/overlay_unittest.cc index 17fcaf2..c54847f 100644 --- a/components/viz/service/display/overlay_unittest.cc +++ b/components/viz/service/display/overlay_unittest.cc
@@ -2485,6 +2485,8 @@ feature_list.InitAndEnableFeature(features::kDirectCompositionUnderlays); { std::unique_ptr<RenderPass> pass = CreateRenderPass(); + SharedQuadState* first_shared_state = pass->shared_quad_state_list.back(); + first_shared_state->occluding_damage_rect = gfx::Rect(1, 1, 10, 10); CreateOpaqueQuadAt(resource_provider_.get(), pass->shared_quad_state_list.back(), pass.get(), gfx::Rect(0, 3, 100, 100), SK_ColorWHITE); @@ -2492,6 +2494,9 @@ resource_provider_.get(), child_resource_provider_.get(), child_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); + SharedQuadState* second_shared_state = + pass->CreateAndAppendSharedQuadState(); + second_shared_state->occluding_damage_rect = gfx::Rect(1, 1, 10, 10); auto* second_video_quad = CreateFullscreenCandidateYUVVideoQuad( resource_provider_.get(), child_resource_provider_.get(), child_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); @@ -2522,6 +2527,8 @@ } { std::unique_ptr<RenderPass> pass = CreateRenderPass(); + SharedQuadState* first_shared_state = pass->shared_quad_state_list.back(); + first_shared_state->occluding_damage_rect = gfx::Rect(1, 1, 10, 10); CreateOpaqueQuadAt(resource_provider_.get(), pass->shared_quad_state_list.back(), pass.get(), gfx::Rect(3, 3, 100, 100), SK_ColorWHITE); @@ -2529,6 +2536,9 @@ resource_provider_.get(), child_resource_provider_.get(), child_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); + SharedQuadState* second_shared_state = + pass->CreateAndAppendSharedQuadState(); + second_shared_state->occluding_damage_rect = gfx::Rect(1, 1, 10, 10); auto* second_video_quad = CreateFullscreenCandidateYUVVideoQuad( resource_provider_.get(), child_resource_provider_.get(), child_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); @@ -2570,6 +2580,8 @@ feature_list.InitAndEnableFeature(features::kDirectCompositionUnderlays); { std::unique_ptr<RenderPass> pass = CreateRenderPass(); + SharedQuadState* shared_quad_state = pass->shared_quad_state_list.back(); + shared_quad_state->occluding_damage_rect = gfx::Rect(210, 210, 20, 20); // Occluding quad fully contained in video rect. CreateOpaqueQuadAt(resource_provider_.get(), pass->shared_quad_state_list.back(), pass.get(), @@ -2606,6 +2618,8 @@ } { std::unique_ptr<RenderPass> pass = CreateRenderPass(); + SharedQuadState* shared_quad_state = pass->shared_quad_state_list.back(); + shared_quad_state->occluding_damage_rect = gfx::Rect(210, 210, 20, 20); // Occluding quad fully contained in video rect. CreateOpaqueQuadAt(resource_provider_.get(), pass->shared_quad_state_list.back(), pass.get(), @@ -3005,9 +3019,9 @@ // The quad on top does not give damage on the third frame if (i == 2) - shared_state_on_top->has_surface_damage = false; + shared_state->occluding_damage_rect = gfx::Rect(); else - shared_state_on_top->has_surface_damage = true; + shared_state->occluding_damage_rect = kOverlayBottomRightRect; overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
diff --git a/components/viz/service/display/surface_aggregator.cc b/components/viz/service/display/surface_aggregator.cc index 32821fdd..0237d951 100644 --- a/components/viz/service/display/surface_aggregator.cc +++ b/components/viz/service/display/surface_aggregator.cc
@@ -78,11 +78,13 @@ SurfaceAggregator::SurfaceAggregator(SurfaceManager* manager, DisplayResourceProvider* provider, - bool aggregate_only_damaged) + bool aggregate_only_damaged, + bool needs_surface_occluding_damage_rect) : manager_(manager), provider_(provider), next_render_pass_id_(1), aggregate_only_damaged_(aggregate_only_damaged), + needs_surface_occluding_damage_rect_(needs_surface_occluding_damage_rect), weak_factory_(this) { DCHECK(manager_); } @@ -185,6 +187,102 @@ return full_rect; } +gfx::Rect SurfaceAggregator::CalculateOccludingSurfaceDamageRect( + const DrawQuad* quad, + const gfx::Transform& parent_quad_to_root_target_transform) { + if (damage_rects_union_of_surfaces_on_top_.IsEmpty()) + return gfx::Rect(); + + // Transform the quad to the parent root target space + // Note: this quad is on the child root render pass. + gfx::Transform transform(parent_quad_to_root_target_transform, + quad->shared_quad_state->quad_to_target_transform); + gfx::Rect surface_in_root_target_space = + cc::MathUtil::MapEnclosingClippedRect(transform, quad->visible_rect); + + // damage_rects_union_of_surfaces_on_top_ is already in the parent root target + // space. + gfx::Rect occluding_damage_rect = damage_rects_union_of_surfaces_on_top_; + occluding_damage_rect.Intersect(surface_in_root_target_space); + + return occluding_damage_rect; +} + +// In CopyPasses(), surfaces are processed from top to bottom. Therefore, all +// surfaces on top has been added to damage_rects_union_of_surfaces_on_top_ +// before this. +void SurfaceAggregator::UnionSurfaceDamageRectsOnTop( + const gfx::Rect& surface_rect, + const gfx::Transform& quad_to_root_target_transform, + const RenderPass* render_pass) { + DCHECK(!surface_rect.IsEmpty()); + + gfx::Rect damage_rect_in_root_target_space = + cc::MathUtil::MapEnclosingClippedRect(quad_to_root_target_transform, + surface_rect); + damage_rects_union_of_surfaces_on_top_.Union( + damage_rect_in_root_target_space); +} + +// This is for underlay video power optimization. +// The purpose of this function is to calculate the occluding damage rect if +// there are elements on top of underlay. This damage rect is later saved in +// shared_quad_state->occluding_damage_rect and used by the overlay +// processor for damage rect optimization. This function is called once +// for each surface. It adds the damage rects of all surfaces to +// damage_rects_union_of_surfaces_on_top_. The occluding damage rect +// is then calculated based on this rect. +bool SurfaceAggregator::ProcessSurfaceOccludingDamage( + const Surface* surface, + const RenderPassList& render_pass_list, + const gfx::Transform& parent_target_transform, + const RenderPass* dest_pass, + gfx::Rect* occluding_damage_rect) { + if (!needs_surface_occluding_damage_rect_) + return false; + + bool occluding_damage_rect_valid = false; + RenderPass* last_render_pass = render_pass_list.back().get(); + gfx::Transform quad_to_root_target_transform = gfx::Transform( + dest_pass->transform_to_root_target, parent_target_transform); + + // This occluding damage detection only works when there is only one quad + // in the current surface. + if (render_pass_list.size() == 1 && last_render_pass->quad_list.size() == 1) { + auto* quad = last_render_pass->quad_list.back(); + *occluding_damage_rect = CalculateOccludingSurfaceDamageRect( + quad, quad_to_root_target_transform); + occluding_damage_rect_valid = true; + } + + gfx::Rect surface_damage_rect; + if (RenderPassNeedsFullDamage(dest_pass)) { + surface_damage_rect = last_render_pass->output_rect; + } else { + surface_damage_rect = DamageRectForSurface(surface, *last_render_pass, + last_render_pass->output_rect); + } + + // Add the current surface to the damage rect union if there is any damage. + // This should be done AFTER checking the occluding damage because the surface + // on top should not include its own surface. + if (!surface_damage_rect.IsEmpty()) { + UnionSurfaceDamageRectsOnTop( + surface_damage_rect, quad_to_root_target_transform, last_render_pass); + } + return occluding_damage_rect_valid; +} + +bool SurfaceAggregator::RenderPassNeedsFullDamage( + const RenderPass* pass) const { + if (copy_request_passes_.count(pass->id) || pass->cache_render_pass || + moved_pixel_passes_.count(pass->id)) { + return true; + } else { + return false; + } +} + // static void SurfaceAggregator::UnrefResources( base::WeakPtr<SurfaceClient> surface_client, @@ -330,6 +428,11 @@ copy_requests.empty() && combined_transform.Preserves2dAxisAlignment() && CanMergeRoundedCorner(rounded_corner_info, *render_pass_list.back()); + gfx::Rect occluding_damage_rect; + bool occluding_damage_rect_valid = ProcessSurfaceOccludingDamage( + surface, render_pass_list, combined_transform, dest_pass, + &occluding_damage_rect); + const RenderPassList& referenced_passes = render_pass_list; // TODO(fsamuel): Move this to a separate helper function. size_t passes_to_copy = @@ -367,16 +470,15 @@ surface->GetActiveFrame().device_scale_factor(), child_to_parent_map, gfx::Transform(), ClipData(), copy_pass.get(), surface_id, has_surface_damage, - RoundedCornerInfo()); + RoundedCornerInfo(), occluding_damage_rect, + occluding_damage_rect_valid); // If the render pass has copy requests, or should be cached, or has // moving-pixel filters, or in a moving-pixel surface, we should damage the // whole output rect so that we always drawn the full content. Otherwise, we // might have incompleted copy request, or cached patially drawn render // pass. - if (!copy_request_passes_.count(remapped_pass_id) && - !copy_pass->cache_render_pass && - !moved_pixel_passes_.count(remapped_pass_id)) { + if (!RenderPassNeedsFullDamage(copy_pass.get())) { gfx::Transform inverse_transform(gfx::Transform::kSkipInitialization); if (copy_pass->transform_to_root_target.GetInverse(&inverse_transform)) { gfx::Rect damage_rect_in_render_pass_space = @@ -422,7 +524,8 @@ surface->GetActiveFrame().device_scale_factor(), child_to_parent_map, surface_transform, quads_clip, dest_pass, surface_id, has_surface_damage, - rounded_corner_info); + rounded_corner_info, occluding_damage_rect, + occluding_damage_rect_valid); } else { auto* shared_quad_state = CopyAndScaleSharedQuadState( source_sqs, scaled_quad_to_target_transform, target_transform, @@ -432,7 +535,8 @@ gfx::ScaleToEnclosingRect(source_sqs->visible_quad_layer_rect, layer_to_content_scale_x, layer_to_content_scale_y), - clip_rect, dest_pass, has_surface_damage, rounded_corner_info); + clip_rect, dest_pass, has_surface_damage, rounded_corner_info, + occluding_damage_rect, occluding_damage_rect_valid); gfx::Rect scaled_rect(gfx::ScaleToEnclosingRect( source_rect, layer_to_content_scale_x, layer_to_content_scale_y)); @@ -466,11 +570,22 @@ SkColor background_color = surface_quad->default_background_color; auto* shared_quad_state = CopySharedQuadState( surface_quad->shared_quad_state, target_transform, clip_rect, dest_pass, - /*has_surface_damage*/ true, rounded_corner_info); + /*has_surface_damage*/ true, rounded_corner_info, + /*occluding_damage_rect*/ gfx::Rect(), + /*occluding_damage_rect_valid*/ false); + auto* solid_color_quad = dest_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); solid_color_quad->SetNew(shared_quad_state, surface_quad->rect, surface_quad->visible_rect, background_color, false); + + if (needs_surface_occluding_damage_rect_) { + gfx::Transform transform( + target_transform, + surface_quad->shared_quad_state->quad_to_target_transform); + transform.ConcatTransform(dest_pass->transform_to_root_target); + UnionSurfaceDamageRectsOnTop(surface_quad->rect, transform, dest_pass); + } } void SurfaceAggregator::EmitGutterQuadsIfNecessary( @@ -499,7 +614,9 @@ primary_shared_quad_state, primary_shared_quad_state->quad_to_target_transform, target_transform, right_gutter_rect, right_gutter_rect, clip_rect, dest_pass, - /*has_surface_damage*/ true, rounded_corner_info); + /*has_surface_damage*/ true, rounded_corner_info, + /*occluding_damage_rect*/ gfx::Rect(), + /*occluding_damage_rect_valid*/ false); auto* right_gutter = dest_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); @@ -516,7 +633,9 @@ primary_shared_quad_state, primary_shared_quad_state->quad_to_target_transform, target_transform, bottom_gutter_rect, bottom_gutter_rect, clip_rect, dest_pass, - /*has_surface_damage*/ true, rounded_corner_info); + /*has_surface_damage*/ true, rounded_corner_info, + /*occluding_damage_rect*/ gfx::Rect(), + /*occluding_damage_rect_valid*/ false); auto* bottom_gutter = dest_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); @@ -572,11 +691,14 @@ const ClipData& clip_rect, RenderPass* dest_render_pass, bool has_surface_damage, - const RoundedCornerInfo& rounded_corner_info) { + const RoundedCornerInfo& rounded_corner_info, + const gfx::Rect& occluding_damage_rect, + bool occluding_damage_rect_valid) { return CopyAndScaleSharedQuadState( source_sqs, source_sqs->quad_to_target_transform, target_transform, source_sqs->quad_layer_rect, source_sqs->visible_quad_layer_rect, - clip_rect, dest_render_pass, has_surface_damage, rounded_corner_info); + clip_rect, dest_render_pass, has_surface_damage, rounded_corner_info, + occluding_damage_rect, occluding_damage_rect_valid); } SharedQuadState* SurfaceAggregator::CopyAndScaleSharedQuadState( @@ -588,7 +710,9 @@ const ClipData& clip_rect, RenderPass* dest_render_pass, bool has_surface_damage, - const RoundedCornerInfo& rounded_corner_info) { + const RoundedCornerInfo& rounded_corner_info, + const gfx::Rect& occluding_damage_rect, + bool occluding_damage_rect_valid) { auto* shared_quad_state = dest_render_pass->CreateAndAppendSharedQuadState(); ClipData new_clip_rect = CalculateClipRect( clip_rect, ClipData(source_sqs->is_clipped, source_sqs->clip_rect), @@ -612,6 +736,9 @@ shared_quad_state->has_surface_damage = has_surface_damage; shared_quad_state->is_fast_rounded_corner = rounded_corner_info.is_fast_rounded_corner; + if (occluding_damage_rect_valid) { + shared_quad_state->occluding_damage_rect = occluding_damage_rect; + } return shared_quad_state; } @@ -626,7 +753,9 @@ RenderPass* dest_pass, const SurfaceId& surface_id, bool has_surface_damage, - const RoundedCornerInfo& parent_rounded_corner_info) { + const RoundedCornerInfo& parent_rounded_corner_info, + const gfx::Rect& occluding_damage_rect, + bool occluding_damage_rect_valid) { const SharedQuadState* last_copied_source_shared_quad_state = nullptr; // If the current frame has copy requests or cached render passes, then // aggregate the entire thing, as otherwise parts of the copy requests may be @@ -688,7 +817,9 @@ } const SharedQuadState* dest_shared_quad_state = CopySharedQuadState( quad->shared_quad_state, target_transform, clip_rect, dest_pass, - has_surface_damage, new_rounded_corner_info); + has_surface_damage, new_rounded_corner_info, occluding_damage_rect, + occluding_damage_rect_valid); + last_copied_source_shared_quad_state = quad->shared_quad_state; if (ignore_undamaged) { damage_rect_in_quad_space_valid = CalculateQuadSpaceDamageRect( @@ -771,6 +902,12 @@ const auto& child_to_parent_map = provider_ ? provider_->GetChildToParentMap(ChildIdForSurface(surface)) : empty_map; + + gfx::Rect occluding_damage_rect; + bool occluding_damage_rect_valid = ProcessSurfaceOccludingDamage( + surface, source_pass_list, gfx::Transform(), + source_pass_list.back().get(), &occluding_damage_rect); + for (size_t i = 0; i < source_pass_list.size(); ++i) { const auto& source = *source_pass_list[i]; @@ -795,16 +932,15 @@ frame.device_scale_factor(), child_to_parent_map, gfx::Transform(), ClipData(), copy_pass.get(), surface->surface_id(), has_surface_damage, - RoundedCornerInfo()); + RoundedCornerInfo(), occluding_damage_rect, + occluding_damage_rect_valid); // If the render pass has copy requests, or should be cached, or has // moving-pixel filters, or in a moving-pixel surface, we should damage the // whole output rect so that we always drawn the full content. Otherwise, we // might have incompleted copy request, or cached patially drawn render // pass. - if (!copy_request_passes_.count(remapped_pass_id) && - !copy_pass->cache_render_pass && - !moved_pixel_passes_.count(remapped_pass_id)) { + if (!RenderPassNeedsFullDamage(copy_pass.get())) { gfx::Transform inverse_transform(gfx::Transform::kSkipInitialization); if (copy_pass->transform_to_root_target.GetInverse(&inverse_transform)) { gfx::Rect damage_rect_in_render_pass_space = @@ -1221,6 +1357,7 @@ valid_surfaces_.clear(); has_cached_render_passes_ = false; damage_ranges_.clear(); + damage_rects_union_of_surfaces_on_top_ = gfx::Rect(); DCHECK(referenced_surfaces_.empty()); PrewalkResult prewalk_result; root_damage_rect_ =
diff --git a/components/viz/service/display/surface_aggregator.h b/components/viz/service/display/surface_aggregator.h index 6ff8f31f..ffacddf 100644 --- a/components/viz/service/display/surface_aggregator.h +++ b/components/viz/service/display/surface_aggregator.h
@@ -36,7 +36,8 @@ SurfaceAggregator(SurfaceManager* manager, DisplayResourceProvider* provider, - bool aggregate_only_damaged); + bool aggregate_only_damaged, + bool needs_surface_occluding_damage_rect); ~SurfaceAggregator(); CompositorFrame Aggregate(const SurfaceId& surface_id, @@ -151,7 +152,9 @@ const ClipData& clip_rect, RenderPass* dest_render_pass, bool has_surface_damage, - const RoundedCornerInfo& rounded_corner_info); + const RoundedCornerInfo& rounded_corner_info, + const gfx::Rect& occluding_damage_rect, + bool occluding_damage_rect_valid); SharedQuadState* CopyAndScaleSharedQuadState( const SharedQuadState* source_sqs, @@ -162,7 +165,9 @@ const ClipData& clip_rect, RenderPass* dest_render_pass, bool has_surface_damage, - const RoundedCornerInfo& rounded_corner_info); + const RoundedCornerInfo& rounded_corner_info, + const gfx::Rect& occluding_damage_rect, + bool occluding_damage_rect_valid); void CopyQuadsToPass( const QuadList& source_quad_list, @@ -174,7 +179,10 @@ RenderPass* dest_pass, const SurfaceId& surface_id, bool has_surface_damage, - const RoundedCornerInfo& rounded_corner_info); + const RoundedCornerInfo& rounded_corner_info, + const gfx::Rect& occluding_damage_rect, + bool occluding_damage_rect_valid); + gfx::Rect PrewalkTree(Surface* surface, bool in_moved_pixel_surface, int parent_pass, @@ -202,6 +210,18 @@ gfx::Rect DamageRectForSurface(const Surface* surface, const RenderPass& source, const gfx::Rect& full_rect) const; + gfx::Rect CalculateOccludingSurfaceDamageRect( + const DrawQuad* quad, + const gfx::Transform& parent_quad_to_root_target_transform); + void UnionSurfaceDamageRectsOnTop(const gfx::Rect& surface_rect, + const gfx::Transform& target_transform, + const RenderPass* pass); + bool ProcessSurfaceOccludingDamage(const Surface* surface, + const RenderPassList& render_pass_list, + const gfx::Transform& target_transform, + const RenderPass* dest_pass, + gfx::Rect* occluding_damage_rect); + bool RenderPassNeedsFullDamage(const RenderPass* pass) const; static void UnrefResources(base::WeakPtr<SurfaceClient> surface_client, const std::vector<ReturnedResource>& resources); @@ -275,6 +295,13 @@ // The root damage rect of the currently-aggregating frame. gfx::Rect root_damage_rect_; + // Occluding damage rect will be calculated for qualified candidates + const bool needs_surface_occluding_damage_rect_; + + // This is the union of the damage rects of all surface on top + // of the current surface. + gfx::Rect damage_rects_union_of_surfaces_on_top_; + // True if the frame that's currently being aggregated has copy requests. // This is valid during Aggregate after PrewalkTree is called. bool has_copy_requests_;
diff --git a/components/viz/service/display/surface_aggregator_perftest.cc b/components/viz/service/display/surface_aggregator_perftest.cc index 64768baf..a6ea493 100644 --- a/components/viz/service/display/surface_aggregator_perftest.cc +++ b/components/viz/service/display/surface_aggregator_perftest.cc
@@ -53,7 +53,8 @@ child_tokens[i] = base::UnguessableToken::Create(); } aggregator_ = std::make_unique<SurfaceAggregator>( - manager_.surface_manager(), resource_provider_.get(), optimize_damage); + manager_.surface_manager(), resource_provider_.get(), optimize_damage, + true); for (int i = 0; i < num_surfaces; i++) { LocalSurfaceId local_surface_id(i + 1, child_tokens[i]); @@ -168,6 +169,22 @@ RunTest(20, 100, 1.f, false, true, "many_surfaces_opaque"); } +TEST_F(SurfaceAggregatorPerfTest, ManySurfacesOpaque_100) { + RunTest(100, 1, 1.f, true, false, "(100 Surfaces, 1 quad each)"); +} + +TEST_F(SurfaceAggregatorPerfTest, ManySurfacesOpaque_300) { + RunTest(300, 1, 1.f, true, false, "(300 Surfaces, 1 quad each)"); +} + +TEST_F(SurfaceAggregatorPerfTest, ManySurfacesManyQuadsOpaque_100) { + RunTest(100, 100, 1.f, true, false, "(100 Surfaces, 100 quads each)"); +} + +TEST_F(SurfaceAggregatorPerfTest, ManySurfacesManyQuadsOpaque_300) { + RunTest(300, 100, 1.f, true, false, "(300 Surfaces, 100 quads each)"); +} + TEST_F(SurfaceAggregatorPerfTest, ManySurfacesTransparent) { RunTest(20, 100, .5f, false, true, "many_surfaces_transparent"); }
diff --git a/components/viz/service/display/surface_aggregator_pixeltest.cc b/components/viz/service/display/surface_aggregator_pixeltest.cc index 3b8ea88..e53d0a2 100644 --- a/components/viz/service/display/surface_aggregator_pixeltest.cc +++ b/components/viz/service/display/surface_aggregator_pixeltest.cc
@@ -113,7 +113,7 @@ std::move(root_frame)); SurfaceAggregator aggregator(this->manager_.surface_manager(), - this->resource_provider_.get(), true); + this->resource_provider_.get(), true, false); CompositorFrame aggregated_frame = aggregator.Aggregate(root_surface_id, this->GetNextDisplayTime()); @@ -195,7 +195,7 @@ } SurfaceAggregator aggregator(this->manager_.surface_manager(), - this->resource_provider_.get(), true); + this->resource_provider_.get(), true, false); CompositorFrame aggregated_frame = aggregator.Aggregate(root_surface_id, this->GetNextDisplayTime()); @@ -337,7 +337,7 @@ } SurfaceAggregator aggregator(this->manager_.surface_manager(), - this->resource_provider_.get(), true); + this->resource_provider_.get(), true, false); CompositorFrame aggregated_frame = aggregator.Aggregate(root_surface_id, this->GetNextDisplayTime());
diff --git a/components/viz/service/display/surface_aggregator_unittest.cc b/components/viz/service/display/surface_aggregator_unittest.cc index a9c8b51..599a005a 100644 --- a/components/viz/service/display/surface_aggregator_unittest.cc +++ b/components/viz/service/display/surface_aggregator_unittest.cc
@@ -26,6 +26,7 @@ #include "components/viz/common/quads/solid_color_draw_quad.h" #include "components/viz/common/quads/surface_draw_quad.h" #include "components/viz/common/quads/texture_draw_quad.h" +#include "components/viz/common/quads/yuv_video_draw_quad.h" #include "components/viz/common/surfaces/parent_local_surface_id_allocator.h" #include "components/viz/service/display/display_resource_provider.h" #include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" @@ -119,7 +120,10 @@ kArbitraryRootFrameSinkId, kRootIsRoot, kNeedsSyncPoints)), - aggregator_(manager_.surface_manager(), nullptr, use_damage_rect) { + aggregator_(manager_.surface_manager(), + nullptr, + use_damage_rect, + true) { manager_.surface_manager()->AddObserver(&observer_); } @@ -139,6 +143,13 @@ return quad; } + static Quad YUVVideoQuad(const gfx::Rect& rect) { + Quad quad; + quad.material = DrawQuad::YUV_VIDEO_CONTENT; + quad.rect = rect; + return quad; + } + // If |fallback_surface_id| is a valid surface Id then this will generate // two SurfaceDrawQuads. static Quad SurfaceQuad(const SurfaceRange& surface_range, @@ -237,6 +248,9 @@ case DrawQuad::RENDER_PASS: AddRenderPassQuad(pass, desc.render_pass_id); break; + case DrawQuad::YUV_VIDEO_CONTENT: + AddYUVVideoQuad(pass, desc.rect); + break; default: NOTREACHED(); } @@ -348,6 +362,18 @@ gfx::RectF(), false, 1.0f); } + static void AddYUVVideoQuad(RenderPass* pass, const gfx::Rect& output_rect) { + auto* shared_state = pass->CreateAndAppendSharedQuadState(); + shared_state->SetAll(gfx::Transform(), output_rect, output_rect, + gfx::RRectF(), output_rect, false, false, 1, + SkBlendMode::kSrcOver, 0); + auto* quad = pass->CreateAndAppendDrawQuad<YUVVideoDrawQuad>(); + quad->SetNew(shared_state, output_rect, output_rect, false, + gfx::RectF(output_rect), gfx::RectF(), output_rect.size(), + gfx::Size(), 0, 0, 0, 0, gfx::ColorSpace::CreateREC709(), 0, + 1.0, 8); + } + protected: ServerSharedBitmapManager shared_bitmap_manager_; FrameSinkManagerImpl manager_; @@ -858,16 +884,14 @@ }; TEST_F(SurfaceAggregatorValidSurfaceTest, UndrawnSurfaces) { - TestVizClient child( - this, &manager_, kArbitraryFrameSinkId1, - gfx::Rect(10, 10)); + TestVizClient child(this, &manager_, kArbitraryFrameSinkId1, + gfx::Rect(10, 10)); child.SubmitCompositorFrame(SK_ColorBLUE); // Parent first submits a CompositorFrame that renfereces |child|, but does // not provide a DrawQuad that embeds it. - TestVizClient parent( - this, &manager_, kArbitraryFrameSinkId2, - gfx::Rect(15, 15)); + TestVizClient parent(this, &manager_, kArbitraryFrameSinkId2, + gfx::Rect(15, 15)); parent.SetEmbeddedClient(&child, false); parent.SubmitCompositorFrame(SK_ColorGREEN); @@ -913,17 +937,15 @@ } TEST_F(SurfaceAggregatorValidSurfaceTest, UndrawnSurfacesWithCopyRequests) { - TestVizClient child( - this, &manager_, kArbitraryFrameSinkId1, - gfx::Rect(10, 10)); + TestVizClient child(this, &manager_, kArbitraryFrameSinkId1, + gfx::Rect(10, 10)); child.SubmitCompositorFrame(SK_ColorBLUE); child.RequestCopyOfOutput(); // Parent first submits a CompositorFrame that renfereces |child|, but does // not provide a DrawQuad that embeds it. - TestVizClient parent( - this, &manager_, kArbitraryFrameSinkId2, - gfx::Rect(15, 15)); + TestVizClient parent(this, &manager_, kArbitraryFrameSinkId2, + gfx::Rect(15, 15)); parent.SetEmbeddedClient(&child, false); parent.SubmitCompositorFrame(SK_ColorGREEN); @@ -958,24 +980,21 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, SurfacesWithMultipleEmbeddersBothVisibleAndInvisible) { - TestVizClient child( - this, &manager_, kArbitraryFrameSinkId1, - gfx::Rect(10, 10)); + TestVizClient child(this, &manager_, kArbitraryFrameSinkId1, + gfx::Rect(10, 10)); child.SubmitCompositorFrame(SK_ColorBLUE); // First parent submits a CompositorFrame that renfereces |child|, but does // not provide a DrawQuad that embeds it. - TestVizClient first_parent( - this, &manager_, kArbitraryFrameSinkId2, - gfx::Rect(15, 15)); + TestVizClient first_parent(this, &manager_, kArbitraryFrameSinkId2, + gfx::Rect(15, 15)); first_parent.SetEmbeddedClient(&child, false); first_parent.SubmitCompositorFrame(SK_ColorGREEN); // Second parent submits a CompositorFrame referencing |child|, and also // includes a draw-quad for it. - TestVizClient second_parent( - this, &manager_, kArbitraryMiddleFrameSinkId, - gfx::Rect(25, 25)); + TestVizClient second_parent(this, &manager_, kArbitraryMiddleFrameSinkId, + gfx::Rect(25, 25)); second_parent.SetEmbeddedClient(&child, true); second_parent.SubmitCompositorFrame(SK_ColorYELLOW); @@ -3875,7 +3894,7 @@ DisplayResourceProvider::kSoftware, nullptr, &shared_bitmap_manager_); aggregator_ = std::make_unique<SurfaceAggregator>( - manager_.surface_manager(), resource_provider_.get(), false); + manager_.surface_manager(), resource_provider_.get(), false, false); aggregator_->set_output_is_secure(true); } @@ -4842,6 +4861,169 @@ } } +// Tests the overlay occluding damage rect +TEST_F(SurfaceAggregatorValidSurfaceTest, OverlayOccludingDamageRect) { + // Video quad + std::vector<Quad> child_surface_quads = { + Quad::YUVVideoQuad(gfx::Rect(0, 0, 100, 100))}; + + std::vector<Pass> child_surface_passes = { + Pass(child_surface_quads, /*size*/ gfx::Size(100, 100), + /*damage_rect*/ gfx::Rect(0, 0, 100, 100))}; + + CompositorFrame child_surface_frame = MakeEmptyCompositorFrame(); + AddPasses(&child_surface_frame.render_pass_list, child_surface_passes, + &child_surface_frame.metadata.referenced_surfaces); + + ParentLocalSurfaceIdAllocator allocator; + allocator.GenerateId(); + LocalSurfaceId child_local_surface_id = + allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id(); + SurfaceId child_surface_id(child_sink_->frame_sink_id(), + child_local_surface_id); + child_sink_->SubmitCompositorFrame(child_local_surface_id, + std::move(child_surface_frame)); + + // Original video quad (0, 0, 100, 100) x this video_transform matrix == + // (10, 0, 80, 80) + gfx::Transform video_transform(0.8f, 0, 0, 0.8f, 10.0f, 0); + + // root surface quads + std::vector<Quad> root_surface_quads = { + Quad::SolidColorQuad(SK_ColorRED, gfx::Rect(60, 0, 40, 40)), + Quad::SurfaceQuad(SurfaceRange(base::nullopt, child_surface_id), + SK_ColorWHITE, + /*primary_surface_rect*/ gfx::Rect(0, 0, 100, 100), + /*opacity*/ 1.f, video_transform, + /*stretch_content_to_fill_bounds=*/false, + /*ignores_input_event=*/false)}; + + std::vector<Pass> root_passes = { + Pass(root_surface_quads, + /*size*/ gfx::Size(200, 200), + /*damage_rect*/ gfx::Rect(60, 0, 40, 40))}; + + CompositorFrame root_frame = MakeEmptyCompositorFrame(); + AddPasses(&root_frame.render_pass_list, root_passes, + &root_frame.metadata.referenced_surfaces); + + SurfaceId root_surface_id(root_sink_->frame_sink_id(), + root_local_surface_id_); + root_sink_->SubmitCompositorFrame(root_local_surface_id_, + std::move(root_frame)); + + CompositorFrame aggregated_frame = + aggregator_.Aggregate(root_surface_id, GetNextDisplayTimeAndIncrement()); + + // Frame # 0 - Full occluding damage rect + // The damage rect of the very first frame is always the full rect + auto* output_root_pass = aggregated_frame.render_pass_list.back().get(); + EXPECT_EQ(gfx::Rect(0, 0, 200, 200), output_root_pass->damage_rect); + + const SharedQuadState* video_sqs = + output_root_pass->quad_list.back()->shared_quad_state; + // Occluding damage of the first frame = the whole surface rect on top + // intersects the video quad. + // (0, 0, 200, 200) intersect with video quad (10, 0, 80, 80) == (10, 0, 80, + // 80). + EXPECT_EQ(gfx::Rect(10, 0, 80, 80), video_sqs->occluding_damage_rect.value()); + + // Frame #1 - Has occluding damage + { + CompositorFrame child_surface_frame = MakeEmptyCompositorFrame(); + AddPasses(&child_surface_frame.render_pass_list, child_surface_passes, + &child_surface_frame.metadata.referenced_surfaces); + child_sink_->SubmitCompositorFrame(child_local_surface_id, + std::move(child_surface_frame)); + + CompositorFrame root_frame = MakeEmptyCompositorFrame(); + AddPasses(&root_frame.render_pass_list, root_passes, + &root_frame.metadata.referenced_surfaces); + + root_sink_->SubmitCompositorFrame(root_local_surface_id_, + std::move(root_frame)); + + CompositorFrame aggregated_frame = aggregator_.Aggregate( + root_surface_id, GetNextDisplayTimeAndIncrement()); + + auto* output_root_pass = aggregated_frame.render_pass_list.back().get(); + // The video quad (10, 0, 80, 80) unions the solid quad on top (60, 0, 40, + // 40) + EXPECT_EQ(gfx::Rect(10, 0, 90, 80), output_root_pass->damage_rect); + + const SharedQuadState* video_sqs = + output_root_pass->quad_list.back()->shared_quad_state; + // The solid quad on top (60, 0, 40, 40) intersects the video quad (10, 0, + // 80, 80) + EXPECT_EQ(gfx::Rect(60, 0, 30, 40), + video_sqs->occluding_damage_rect.value()); + } + // Frame #2 - No occluding damage, the quad on top doesn't change + { + CompositorFrame child_surface_frame = MakeEmptyCompositorFrame(); + AddPasses(&child_surface_frame.render_pass_list, child_surface_passes, + &child_surface_frame.metadata.referenced_surfaces); + child_sink_->SubmitCompositorFrame(child_local_surface_id, + std::move(child_surface_frame)); + + // No change in root frame + CompositorFrame aggregated_frame = aggregator_.Aggregate( + root_surface_id, GetNextDisplayTimeAndIncrement()); + + auto* output_root_pass = aggregated_frame.render_pass_list.back().get(); + // Only the video quad (10, 0, 80, 80) is damaged + EXPECT_EQ(gfx::Rect(10, 0, 80, 80), output_root_pass->damage_rect); + + const SharedQuadState* video_sqs = + output_root_pass->quad_list.back()->shared_quad_state; + // No occluding damage + EXPECT_EQ(gfx::Rect(), video_sqs->occluding_damage_rect.value()); + } + // Frame #3 - The only quad on top is removed + { + CompositorFrame child_surface_frame = MakeEmptyCompositorFrame(); + AddPasses(&child_surface_frame.render_pass_list, child_surface_passes, + &child_surface_frame.metadata.referenced_surfaces); + child_sink_->SubmitCompositorFrame(child_local_surface_id, + std::move(child_surface_frame)); + + // root surface quads, the solid quad (60, 0, 40, 40) is removed + std::vector<Quad> root_surface_quads = {Quad::SurfaceQuad( + SurfaceRange(base::nullopt, child_surface_id), SK_ColorWHITE, + /*primary_surface_rect*/ gfx::Rect(0, 0, 100, 100), + /*opacity*/ 1.f, video_transform, + /*stretch_content_to_fill_bounds=*/false, + /*ignores_input_event=*/false)}; + + std::vector<Pass> root_passes = { + Pass(root_surface_quads, + /*size*/ gfx::Size(200, 200), + /*damage_rect*/ gfx::Rect(60, 0, 40, 40))}; + + CompositorFrame root_frame = MakeEmptyCompositorFrame(); + AddPasses(&root_frame.render_pass_list, root_passes, + &root_frame.metadata.referenced_surfaces); + + root_sink_->SubmitCompositorFrame(root_local_surface_id_, + std::move(root_frame)); + + CompositorFrame aggregated_frame = aggregator_.Aggregate( + root_surface_id, GetNextDisplayTimeAndIncrement()); + + auto* output_root_pass = aggregated_frame.render_pass_list.back().get(); + // The video quad (10, 0, 80, 80) unions the expose damage from removing + // the solid quad on top (60, 0, 40, 40) + EXPECT_EQ(gfx::Rect(10, 0, 90, 80), output_root_pass->damage_rect); + + const SharedQuadState* video_sqs = + output_root_pass->quad_list.back()->shared_quad_state; + // The expose damage (60, 0, 40, 40) intersects the video quad (10, 0, + // 80, 80) + EXPECT_EQ(gfx::Rect(60, 0, 30, 40), + video_sqs->occluding_damage_rect.value()); + } +} + // Tests that quads outside the damage rect are not ignored for cached render // pass. TEST_F(SurfaceAggregatorPartialSwapTest, NotIgnoreOutsideForCachedRenderPass) {
diff --git a/components/viz/service/frame_sinks/compositor_frame_sink_support.cc b/components/viz/service/frame_sinks/compositor_frame_sink_support.cc index 80872fb..4a729685a 100644 --- a/components/viz/service/frame_sinks/compositor_frame_sink_support.cc +++ b/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
@@ -287,6 +287,10 @@ return wants_animate_only_begin_frames_; } +bool CompositorFrameSinkSupport::IsRoot() const { + return is_root_; +} + void CompositorFrameSinkSupport::DidNotProduceFrame(const BeginFrameAck& ack) { TRACE_EVENT2("viz", "CompositorFrameSinkSupport::DidNotProduceFrame", "ack.source_id", ack.source_id, "ack.sequence_number",
diff --git a/components/viz/service/frame_sinks/compositor_frame_sink_support.h b/components/viz/service/frame_sinks/compositor_frame_sink_support.h index e3a85a8a..521cb34 100644 --- a/components/viz/service/frame_sinks/compositor_frame_sink_support.h +++ b/components/viz/service/frame_sinks/compositor_frame_sink_support.h
@@ -215,6 +215,7 @@ const BeginFrameArgs& LastUsedBeginFrameArgs() const override; void OnBeginFrameSourcePausedChanged(bool paused) override; bool WantsAnimateOnlyBeginFrames() const override; + bool IsRoot() const override; void UpdateNeedsBeginFramesInternal(); Surface* CreateSurface(const SurfaceInfo& surface_info,
diff --git a/components/viz/service/frame_sinks/video_detector_unittest.cc b/components/viz/service/frame_sinks/video_detector_unittest.cc index 484cac1..dd5b361 100644 --- a/components/viz/service/frame_sinks/video_detector_unittest.cc +++ b/components/viz/service/frame_sinks/video_detector_unittest.cc
@@ -79,6 +79,7 @@ : frame_sink_manager_(&shared_bitmap_manager_), surface_aggregator_(frame_sink_manager_.surface_manager(), nullptr, + false, false) {} ~VideoDetectorTest() override {}
diff --git a/components/viz/test/begin_frame_source_test.h b/components/viz/test/begin_frame_source_test.h index 086f1c53..1ad005a 100644 --- a/components/viz/test/begin_frame_source_test.h +++ b/components/viz/test/begin_frame_source_test.h
@@ -84,6 +84,7 @@ MOCK_CONST_METHOD0(LastUsedBeginFrameArgs, const BeginFrameArgs&()); MOCK_METHOD1(OnBeginFrameSourcePausedChanged, void(bool)); MOCK_CONST_METHOD0(WantsAnimateOnlyBeginFrames, bool()); + MOCK_CONST_METHOD0(IsRoot, bool()); virtual void AsValueInto(base::trace_event::TracedValue* dict) const;
diff --git a/content/browser/DEPS b/content/browser/DEPS index 94dcee5..2293035 100644 --- a/content/browser/DEPS +++ b/content/browser/DEPS
@@ -103,7 +103,6 @@ "+third_party/blink/public/platform/web_touch_event.h", "+third_party/blink/public/platform/web_text_input_type.h", "+third_party/blink/public/platform/mac/web_scrollbar_theme.h", - "+third_party/blink/public/platform/modules/font_unique_name_lookup/font_unique_name_lookup.mojom.h", "+third_party/blink/public/platform/modules/indexeddb/web_idb_database_exception.h", "+third_party/blink/public/platform/modules/notifications/web_notification_constants.h", "+third_party/blink/public/platform/modules/service_worker/web_service_worker_error.h", @@ -128,7 +127,6 @@ # don't use WTF types. "+third_party/blink/public/platform/modules/bluetooth/web_bluetooth.mojom.h", "+third_party/blink/public/platform/modules/cookie_store/cookie_store.mojom.h", - "+third_party/blink/public/platform/modules/mediasession/media_session.mojom.h", "+third_party/blink/public/platform/modules/mediastream/media_devices.mojom.h", "+third_party/blink/public/platform/modules/websockets/websocket.mojom.h",
diff --git a/content/browser/font_unique_name_lookup/font_unique_name_lookup_service.h b/content/browser/font_unique_name_lookup/font_unique_name_lookup_service.h index 01aac22..f60ca495 100644 --- a/content/browser/font_unique_name_lookup/font_unique_name_lookup_service.h +++ b/content/browser/font_unique_name_lookup/font_unique_name_lookup_service.h
@@ -8,7 +8,7 @@ #include "base/files/file_path.h" #include "base/macros.h" #include "mojo/public/cpp/bindings/interface_request.h" -#include "third_party/blink/public/platform/modules/font_unique_name_lookup/font_unique_name_lookup.mojom.h" +#include "third_party/blink/public/mojom/font_unique_name_lookup/font_unique_name_lookup.mojom.h" namespace content {
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc index 277edfd2..1f4476e2 100644 --- a/content/browser/frame_host/navigation_request.cc +++ b/content/browser/frame_host/navigation_request.cc
@@ -210,7 +210,7 @@ // Blink and //content. if (IsSecMetadataEnabled() && IsOriginSecure(url)) { std::string site_value = "cross-site"; - std::string user_value = has_user_gesture ? "?T" : "?F"; + std::string user_value = has_user_gesture ? "?T" : std::string(); // Navigations that aren't triggerable from the web (e.g. typing in the // address bar, or clicking a bookmark) are labeled as 'none'. Webby @@ -255,7 +255,8 @@ headers->SetHeaderIfMissing("Sec-Fetch-Dest", destination.c_str()); headers->SetHeaderIfMissing("Sec-Fetch-Mode", mode.c_str()); headers->SetHeaderIfMissing("Sec-Fetch-Site", site_value.c_str()); - headers->SetHeaderIfMissing("Sec-Fetch-User", user_value.c_str()); + if (!user_value.empty()) + headers->SetHeaderIfMissing("Sec-Fetch-User", user_value.c_str()); } // Ask whether we should request a policy.
diff --git a/content/browser/media/session/media_metadata_sanitizer.h b/content/browser/media/session/media_metadata_sanitizer.h index 0b21ced5..5f1b7b6 100644 --- a/content/browser/media/session/media_metadata_sanitizer.h +++ b/content/browser/media/session/media_metadata_sanitizer.h
@@ -5,7 +5,7 @@ #ifndef CONTENT_BROWSER_MEDIA_SESSION_MEDIA_METADATA_SANITIZER_H_ #define CONTENT_BROWSER_MEDIA_SESSION_MEDIA_METADATA_SANITIZER_H_ -#include "third_party/blink/public/platform/modules/mediasession/media_session.mojom.h" +#include "third_party/blink/public/mojom/mediasession/media_session.mojom.h" namespace content {
diff --git a/content/browser/media/session/media_session_impl.cc b/content/browser/media/session/media_session_impl.cc index 3f8cff547..bd2c598 100644 --- a/content/browser/media/session/media_session_impl.cc +++ b/content/browser/media/session/media_session_impl.cc
@@ -26,7 +26,7 @@ #include "media/base/media_content_type.h" #include "services/media_session/public/cpp/media_image_manager.h" #include "services/media_session/public/mojom/audio_focus.mojom.h" -#include "third_party/blink/public/platform/modules/mediasession/media_session.mojom.h" +#include "third_party/blink/public/mojom/mediasession/media_session.mojom.h" #if defined(OS_ANDROID) #include "content/browser/media/session/media_session_android.h"
diff --git a/content/browser/media/session/media_session_impl_service_routing_unittest.cc b/content/browser/media/session/media_session_impl_service_routing_unittest.cc index fcccdf2..9d366798 100644 --- a/content/browser/media/session/media_session_impl_service_routing_unittest.cc +++ b/content/browser/media/session/media_session_impl_service_routing_unittest.cc
@@ -19,7 +19,7 @@ #include "services/media_session/public/cpp/media_metadata.h" #include "services/media_session/public/cpp/test/mock_media_session.h" #include "services/media_session/public/mojom/constants.mojom.h" -#include "third_party/blink/public/platform/modules/mediasession/media_session.mojom.h" +#include "third_party/blink/public/mojom/mediasession/media_session.mojom.h" using ::testing::_; using ::testing::AnyNumber;
diff --git a/content/browser/media/session/media_session_service_impl.h b/content/browser/media/session/media_session_service_impl.h index 06a0d36..22eb0e1 100644 --- a/content/browser/media/session/media_session_service_impl.h +++ b/content/browser/media/session/media_session_service_impl.h
@@ -5,8 +5,9 @@ #ifndef CONTENT_BROWSER_MEDIA_SESSION_MEDIA_SESSION_SERVICE_IMPL_H_ #define CONTENT_BROWSER_MEDIA_SESSION_MEDIA_SESSION_SERVICE_IMPL_H_ +#include "content/common/content_export.h" #include "mojo/public/cpp/bindings/binding.h" -#include "third_party/blink/public/platform/modules/mediasession/media_session.mojom.h" +#include "third_party/blink/public/mojom/mediasession/media_session.mojom.h" namespace content {
diff --git a/content/browser/media/session/mock_media_session_service_impl.h b/content/browser/media/session/mock_media_session_service_impl.h index 8253287..d10b936 100644 --- a/content/browser/media/session/mock_media_session_service_impl.h +++ b/content/browser/media/session/mock_media_session_service_impl.h
@@ -7,7 +7,7 @@ #include "content/browser/media/session/media_session_service_impl.h" #include "testing/gmock/include/gmock/gmock.h" -#include "third_party/blink/public/platform/modules/mediasession/media_session.mojom.h" +#include "third_party/blink/public/mojom/mediasession/media_session.mojom.h" namespace content {
diff --git a/content/browser/webauth/authenticator_impl_unittest.cc b/content/browser/webauth/authenticator_impl_unittest.cc index f7e9fac3..0c78440 100644 --- a/content/browser/webauth/authenticator_impl_unittest.cc +++ b/content/browser/webauth/authenticator_impl_unittest.cc
@@ -520,29 +520,6 @@ EXPECT_EQ(AuthenticatorStatus::NOT_ALLOWED_ERROR, callback_receiver.status()); } -// Test that service returns NOT_ALLOWED_ERROR if user verification is REQUIRED -// for get(). -TEST_F(AuthenticatorImplTest, GetAssertionUserVerification) { - SimulateNavigation(GURL(kTestOrigin1)); - device::test::ScopedVirtualFidoDevice scoped_virtual_device; - auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>( - base::Time::Now(), base::TimeTicks::Now()); - auto authenticator = ConstructAuthenticatorWithTimer(task_runner); - - PublicKeyCredentialRequestOptionsPtr options = - GetTestPublicKeyCredentialRequestOptions(); - options->user_verification = - blink::mojom::UserVerificationRequirement::REQUIRED; - TestGetAssertionCallback callback_receiver; - authenticator->GetAssertion(std::move(options), callback_receiver.callback()); - - // Trigger timer. - base::RunLoop().RunUntilIdle(); - task_runner->FastForwardBy(base::TimeDelta::FromMinutes(1)); - callback_receiver.WaitForCallback(); - EXPECT_EQ(AuthenticatorStatus::NOT_ALLOWED_ERROR, callback_receiver.status()); -} - // Test that MakeCredential request times out with NOT_ALLOWED_ERROR if user // verification is required for U2F devices. TEST_F(AuthenticatorImplTest, MakeCredentialUserVerification) { @@ -3102,21 +3079,22 @@ SCOPED_TRACE(UVToString(uv)); auto options = get_credential_options(uv); - // UV cannot be satisfied without fingerprints. - const bool should_timeout = + // Without a fingerprint enrolled we assume that a UV=required request + // cannot be satisfied by an authenticator that cannot do UV. It is + // possible for a credential to be created without UV and then later + // asserted with UV=required, but that would be bizarre behaviour from + // an RP and we currently don't worry about it. + const bool should_be_unrecognized = !fingerprints_enrolled && uv == blink::mojom::UserVerificationRequirement::REQUIRED; - if (should_timeout) { - options->adjusted_timeout = base::TimeDelta::FromMilliseconds(100); - } TestGetAssertionCallback callback_receiver; authenticator->GetAssertion(std::move(options), callback_receiver.callback()); callback_receiver.WaitForCallback(); - if (should_timeout) { - EXPECT_EQ(AuthenticatorStatus::NOT_ALLOWED_ERROR, + if (should_be_unrecognized) { + EXPECT_EQ(AuthenticatorStatus::CREDENTIAL_NOT_RECOGNIZED, callback_receiver.status()); } else { EXPECT_EQ(AuthenticatorStatus::SUCCESS, callback_receiver.status());
diff --git a/content/browser/webauth/webauth_browsertest.cc b/content/browser/webauth/webauth_browsertest.cc index 8011dc8..ac765d0 100644 --- a/content/browser/webauth/webauth_browsertest.cc +++ b/content/browser/webauth/webauth_browsertest.cc
@@ -88,6 +88,10 @@ constexpr char kRelyingPartyRpIconUrlSecurityErrorMessage[] = "webauth: SecurityError: 'rp.icon' should be a secure URL"; +constexpr char kInvalidStateError[] = + "webauth: InvalidStateError: The user attempted to use an authenticator " + "that recognized none of the provided credentials."; + // Templates to be used with base::ReplaceStringPlaceholders. Can be // modified to include up to 9 replacements. The default values for // any additional replacements added should also be added to the @@ -815,7 +819,10 @@ } // Tests that when navigator.credentials.get() is called with user verification -// required, we get a NotSupportedError. +// required, we get an InvalidStateError because the virtual device isn't +// configured with UV and GetAssertionRequestHandler will return +// |kUserConsentButCredentialNotRecognized| when such an authenticator is +// touched in that case. IN_PROC_BROWSER_TEST_F(WebAuthJavascriptClientBrowserTest, GetPublicKeyCredentialUserVerification) { for (const auto protocol : kAllProtocols) { @@ -828,7 +835,7 @@ ASSERT_TRUE(content::ExecuteScriptAndExtractString( shell()->web_contents()->GetMainFrame(), BuildGetCallWithParameters(parameters), &result)); - ASSERT_EQ(kTimeoutErrorMessage, result); + ASSERT_EQ(kInvalidStateError, result); } }
diff --git a/content/browser/worker_host/worker_script_fetch_initiator.cc b/content/browser/worker_host/worker_script_fetch_initiator.cc index 81453c2..b5dc343 100644 --- a/content/browser/worker_host/worker_script_fetch_initiator.cc +++ b/content/browser/worker_host/worker_script_fetch_initiator.cc
@@ -232,7 +232,7 @@ site_value.c_str()); resource_request->headers.SetHeaderIfMissing("Sec-Fetch-Mode", "same-origin"); - resource_request->headers.SetHeaderIfMissing("Sec-Fetch-User", "?F"); + // We don't set `Sec-Fetch-User` for subresource requests. } }
diff --git a/content/common/DEPS b/content/common/DEPS index 2407b45c..b820802c 100644 --- a/content/common/DEPS +++ b/content/common/DEPS
@@ -52,7 +52,6 @@ "+third_party/blink/public/platform/modules/bluetooth/web_bluetooth.mojom.h", "+third_party/blink/public/platform/modules/device_orientation/WebDeviceMotionData.h", "+third_party/blink/public/platform/modules/device_orientation/WebDeviceOrientationData.h", - "+third_party/blink/public/platform/modules/mediasession/media_session.mojom.h", "+third_party/blink/public/platform/modules/mediastream/media_devices.mojom.h", "+third_party/blink/public/platform/modules/push_messaging/web_push_error.h", "+third_party/blink/public/platform/modules/remoteplayback/web_remote_playback_availability.h",
diff --git a/content/public/android/java/src/org/chromium/content/browser/BrowserStartupControllerImpl.java b/content/public/android/java/src/org/chromium/content/browser/BrowserStartupControllerImpl.java index 1ec506c..650f5a7 100644 --- a/content/public/android/java/src/org/chromium/content/browser/BrowserStartupControllerImpl.java +++ b/content/public/android/java/src/org/chromium/content/browser/BrowserStartupControllerImpl.java
@@ -426,6 +426,7 @@ } }; + ResourceExtractor.get().setResultTraits(UiThreadTaskTraits.BOOTSTRAP); if (completionCallback == null) { // If no continuation callback is specified, then force the resource extraction // to complete. @@ -450,6 +451,7 @@ @Override public void initChromiumBrowserProcessForTests() { ResourceExtractor resourceExtractor = ResourceExtractor.get(); + resourceExtractor.setResultTraits(UiThreadTaskTraits.BOOTSTRAP); resourceExtractor.startExtractingResources("en"); resourceExtractor.waitForCompletion(); nativeSetCommandLineFlags(false);
diff --git a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/NativeLibraryTestRule.java b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/NativeLibraryTestRule.java index 4252934..50434b7 100644 --- a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/NativeLibraryTestRule.java +++ b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/NativeLibraryTestRule.java
@@ -15,6 +15,7 @@ import org.chromium.base.library_loader.LibraryProcessType; import org.chromium.base.library_loader.ProcessInitException; import org.chromium.content_public.browser.BrowserStartupController; +import org.chromium.content_public.browser.UiThreadTaskTraits; import org.chromium.ui.resources.ResourceExtractor; /** @@ -56,6 +57,7 @@ try { // Extract compressed resource paks. ResourceExtractor resourceExtractor = ResourceExtractor.get(); + resourceExtractor.setResultTraits(UiThreadTaskTraits.BOOTSTRAP); resourceExtractor.startExtractingResources("en"); resourceExtractor.waitForCompletion();
diff --git a/content/renderer/media/stream/media_stream_center.cc b/content/renderer/media/stream/media_stream_center.cc index 18bd3994..8622723b 100644 --- a/content/renderer/media/stream/media_stream_center.cc +++ b/content/renderer/media/stream/media_stream_center.cc
@@ -180,7 +180,8 @@ blink::WebAudioSourceProvider* MediaStreamCenter::CreateWebAudioSourceFromMediaStreamTrack( - const blink::WebMediaStreamTrack& track) { + const blink::WebMediaStreamTrack& track, + int context_sample_rate) { DVLOG(1) << "MediaStreamCenter::createWebAudioSourceFromMediaStreamTrack"; blink::WebPlatformMediaStreamTrack* media_stream_track = track.GetPlatformTrack(); @@ -195,7 +196,7 @@ // TODO(tommi): Rename WebRtcLocalAudioSourceProvider to // WebAudioMediaStreamSink since it's not specific to any particular source. // https://crbug.com/577874 - return new WebRtcLocalAudioSourceProvider(track); + return new WebRtcLocalAudioSourceProvider(track, context_sample_rate); } void MediaStreamCenter::DidStopMediaStreamSource(
diff --git a/content/renderer/media/stream/media_stream_center.h b/content/renderer/media/stream/media_stream_center.h index 55fbd4f5..c83a5cd 100644 --- a/content/renderer/media/stream/media_stream_center.h +++ b/content/renderer/media/stream/media_stream_center.h
@@ -40,7 +40,8 @@ const blink::WebMediaStreamTrack& track) override; blink::WebAudioSourceProvider* CreateWebAudioSourceFromMediaStreamTrack( - const blink::WebMediaStreamTrack& track) override; + const blink::WebMediaStreamTrack& track, + int context_sample_rate) override; void DidStopMediaStreamSource( const blink::WebMediaStreamSource& web_source) override;
diff --git a/content/renderer/media/webrtc/transmission_encoding_info_handler.cc b/content/renderer/media/webrtc/transmission_encoding_info_handler.cc index de47e79..76c29a8 100644 --- a/content/renderer/media/webrtc/transmission_encoding_info_handler.cc +++ b/content/renderer/media/webrtc/transmission_encoding_info_handler.cc
@@ -144,8 +144,7 @@ void TransmissionEncodingInfoHandler::EncodingInfo( const blink::WebMediaConfiguration& configuration, - std::unique_ptr<blink::WebMediaCapabilitiesEncodingInfoCallbacks> callbacks) - const { + OnMediaCapabilitiesEncodingInfoCallback callback) const { DCHECK(configuration.video_configuration || configuration.audio_configuration); @@ -153,7 +152,7 @@ if (!configuration.video_configuration && !configuration.audio_configuration) { DVLOG(2) << "Neither video nor audio configuration specified."; - callbacks->OnSuccess(std::move(info)); + std::move(callback).Run(std::move(info)); return; } @@ -191,7 +190,7 @@ DVLOG(2) << "Audio MIME type:" << mime_type << " capabilities:" << ToString(*info); } - callbacks->OnSuccess(std::move(info)); + std::move(callback).Run(std::move(info)); } } // namespace content
diff --git a/content/renderer/media/webrtc/transmission_encoding_info_handler.h b/content/renderer/media/webrtc/transmission_encoding_info_handler.h index f56a9cde..b5aca6a 100644 --- a/content/renderer/media/webrtc/transmission_encoding_info_handler.h +++ b/content/renderer/media/webrtc/transmission_encoding_info_handler.h
@@ -36,10 +36,8 @@ ~TransmissionEncodingInfoHandler() override; // blink::WebTransmissionEncodingInfoHandler implementation. - void EncodingInfo( - const blink::WebMediaConfiguration& configuration, - std::unique_ptr<blink::WebMediaCapabilitiesEncodingInfoCallbacks> cb) - const override; + void EncodingInfo(const blink::WebMediaConfiguration& configuration, + OnMediaCapabilitiesEncodingInfoCallback cb) const override; private: // Extracts supported video/audio codec name from |mime_type|. Returns "" if
diff --git a/content/renderer/media/webrtc/transmission_encoding_info_handler_unittest.cc b/content/renderer/media/webrtc/transmission_encoding_info_handler_unittest.cc index ed9910b..2e30db0 100644 --- a/content/renderer/media/webrtc/transmission_encoding_info_handler_unittest.cc +++ b/content/renderer/media/webrtc/transmission_encoding_info_handler_unittest.cc
@@ -7,6 +7,7 @@ #include <utility> #include <vector> +#include "base/bind.h" #include "media/base/video_codecs.h" #include "media/video/video_encode_accelerator.h" #include "testing/gtest/include/gtest/gtest.h" @@ -93,22 +94,20 @@ // OnSuccess() received argument. So it moves OnSuccess()'s received argument, // WebMediaCapabilitiesInfo instance, to EncodingInfoObserver instance for // inspection. -class WebMediaCapabilitiesEncodingInfoCallbacksForTest - : public blink::WebMediaCapabilitiesEncodingInfoCallbacks { +class WebMediaCapabilitiesEncodingInfoCallbacksForTest { public: WebMediaCapabilitiesEncodingInfoCallbacksForTest( EncodingInfoObserver* observer) : observer_(observer) { DCHECK(observer_); } - ~WebMediaCapabilitiesEncodingInfoCallbacksForTest() override = default; + virtual ~WebMediaCapabilitiesEncodingInfoCallbacksForTest() = default; - void OnSuccess( - std::unique_ptr<blink::WebMediaCapabilitiesInfo> info) override { + void OnSuccess(std::unique_ptr<blink::WebMediaCapabilitiesInfo> info) { observer_->OnSuccess(std::move(info)); } - void OnError() override { observer_->OnError(); } + void OnError() { observer_->OnError(); } private: EncodingInfoObserver* observer_; @@ -165,7 +164,11 @@ auto callbacks = std::make_unique<WebMediaCapabilitiesEncodingInfoCallbacksForTest>( &observer); - handler.EncodingInfo(configuration, std::move(callbacks)); + handler.EncodingInfo( + configuration, + base::BindOnce( + &WebMediaCapabilitiesEncodingInfoCallbacksForTest::OnSuccess, + base::Unretained(callbacks.get()))); EXPECT_TRUE(observer.IsCalled()); EXPECT_TRUE(observer.is_success());
diff --git a/content/renderer/media/webrtc_local_audio_source_provider.cc b/content/renderer/media/webrtc_local_audio_source_provider.cc index 078585f3..21412ec 100644 --- a/content/renderer/media/webrtc_local_audio_source_provider.cc +++ b/content/renderer/media/webrtc_local_audio_source_provider.cc
@@ -28,10 +28,9 @@ const size_t WebRtcLocalAudioSourceProvider::kWebAudioRenderBufferSize = 128; WebRtcLocalAudioSourceProvider::WebRtcLocalAudioSourceProvider( - const blink::WebMediaStreamTrack& track) - : is_enabled_(false), - track_(track), - track_stopped_(false) { + const blink::WebMediaStreamTrack& track, + int context_sample_rate) + : is_enabled_(false), track_(track), track_stopped_(false) { // Get the native audio output hardware sample-rate for the sink. // We need to check if there is a valid frame since the unittests // do not have one and they will inject their own |sink_params_| for testing. @@ -39,13 +38,8 @@ blink::WebLocalFrame::FrameForCurrentContext(); RenderFrame* const render_frame = RenderFrame::FromWebFrame(web_frame); if (render_frame) { - int sample_rate = - AudioDeviceFactory::GetOutputDeviceInfo(render_frame->GetRoutingID(), - media::AudioSinkParameters()) - .output_params() - .sample_rate(); sink_params_.Reset(media::AudioParameters::AUDIO_PCM_LOW_LATENCY, - media::CHANNEL_LAYOUT_STEREO, sample_rate, + media::CHANNEL_LAYOUT_STEREO, context_sample_rate, kWebAudioRenderBufferSize); } // Connect the source provider to the track as a sink.
diff --git a/content/renderer/media/webrtc_local_audio_source_provider.h b/content/renderer/media/webrtc_local_audio_source_provider.h index 83624c2..930c02f 100644 --- a/content/renderer/media/webrtc_local_audio_source_provider.h +++ b/content/renderer/media/webrtc_local_audio_source_provider.h
@@ -57,7 +57,8 @@ static const size_t kWebAudioRenderBufferSize; explicit WebRtcLocalAudioSourceProvider( - const blink::WebMediaStreamTrack& track); + const blink::WebMediaStreamTrack& track, + int context_sample_rate); ~WebRtcLocalAudioSourceProvider() override; // blink::WebMediaStreamAudioSink implementation.
diff --git a/content/renderer/media/webrtc_local_audio_source_provider_unittest.cc b/content/renderer/media/webrtc_local_audio_source_provider_unittest.cc index e611d93..e833984 100644 --- a/content/renderer/media/webrtc_local_audio_source_provider_unittest.cc +++ b/content/renderer/media/webrtc_local_audio_source_provider_unittest.cc
@@ -21,9 +21,10 @@ void SetUp() override { source_params_.Reset(media::AudioParameters::AUDIO_PCM_LOW_LATENCY, media::CHANNEL_LAYOUT_MONO, 48000, 480); + const int context_sample_rate = 44100; sink_params_.Reset( media::AudioParameters::AUDIO_PCM_LOW_LATENCY, - media::CHANNEL_LAYOUT_STEREO, 44100, + media::CHANNEL_LAYOUT_STEREO, context_sample_rate, WebRtcLocalAudioSourceProvider::kWebAudioRenderBufferSize); sink_bus_ = media::AudioBus::Create(sink_params_); blink::WebMediaStreamSource audio_source; @@ -35,7 +36,8 @@ audio_source); blink_track_.SetPlatformTrack( std::make_unique<blink::MediaStreamAudioTrack>(true)); - source_provider_.reset(new WebRtcLocalAudioSourceProvider(blink_track_)); + source_provider_.reset( + new WebRtcLocalAudioSourceProvider(blink_track_, context_sample_rate)); source_provider_->SetSinkParamsForTesting(sink_params_); source_provider_->OnSetFormat(source_params_); }
diff --git a/content/renderer/media_recorder/media_recorder_handler.cc b/content/renderer/media_recorder/media_recorder_handler.cc index 00b3f1d3..7d5c614 100644 --- a/content/renderer/media_recorder/media_recorder_handler.cc +++ b/content/renderer/media_recorder/media_recorder_handler.cc
@@ -22,6 +22,7 @@ #include "media/base/video_codecs.h" #include "media/base/video_frame.h" #include "media/muxers/webm_muxer.h" +#include "third_party/blink/public/platform/modules/media_capabilities/web_media_capabilities_info.h" #include "third_party/blink/public/platform/modules/media_capabilities/web_media_configuration.h" #include "third_party/blink/public/platform/modules/mediastream/media_stream_audio_track.h" #include "third_party/blink/public/platform/modules/mediastream/web_platform_media_stream_track.h" @@ -36,8 +37,6 @@ namespace content { -using blink::WebMediaCapabilitiesEncodingInfoCallbacks; - namespace { // Encoding smoothness depends on a number of parameters, namely: frame rate, @@ -348,8 +347,7 @@ void MediaRecorderHandler::EncodingInfo( const blink::WebMediaConfiguration& configuration, - std::unique_ptr<blink::WebMediaCapabilitiesEncodingInfoCallbacks> - callbacks) { + OnMediaCapabilitiesEncodingInfoCallback callback) { DCHECK(main_render_thread_checker_.CalledOnValidThread()); DCHECK(configuration.video_configuration || configuration.audio_configuration); @@ -398,7 +396,7 @@ << " is" << (info->supported ? " supported" : " NOT supported") << " and" << (info->smooth ? " smooth" : " NOT smooth"); - callbacks->OnSuccess(std::move(info)); + std::move(callback).Run(std::move(info)); } blink::WebString MediaRecorderHandler::ActualMimeType() {
diff --git a/content/renderer/media_recorder/media_recorder_handler.h b/content/renderer/media_recorder/media_recorder_handler.h index 29377153..f34a4c8 100644 --- a/content/renderer/media_recorder/media_recorder_handler.h +++ b/content/renderer/media_recorder/media_recorder_handler.h
@@ -64,10 +64,8 @@ void Stop() override; void Pause() override; void Resume() override; - void EncodingInfo( - const blink::WebMediaConfiguration& configuration, - std::unique_ptr<blink::WebMediaCapabilitiesEncodingInfoCallbacks> cb) - override; + void EncodingInfo(const blink::WebMediaConfiguration& configuration, + OnMediaCapabilitiesEncodingInfoCallback cb) override; blink::WebString ActualMimeType() override; private:
diff --git a/device/fido/features.cc b/device/fido/features.cc index 16ed5cc..48dfe89f 100644 --- a/device/fido/features.cc +++ b/device/fido/features.cc
@@ -19,8 +19,8 @@ extern const base::Feature kWebAuthProxyCryptotoken{ "WebAuthenticationProxyCryptotoken", base::FEATURE_ENABLED_BY_DEFAULT}; -extern const base::Feature kWebAuthPINSupport{ - "WebAuthenticationPINSupport", base::FEATURE_DISABLED_BY_DEFAULT}; +extern const base::Feature kWebAuthPINSupport{"WebAuthenticationPINSupport", + base::FEATURE_ENABLED_BY_DEFAULT}; extern const base::Feature kWebAuthResidentKeys{ "WebAuthenticationResidentKeys", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/device/fido/fido_test_data.h b/device/fido/fido_test_data.h index 3419817..8a82db7 100644 --- a/device/fido/fido_test_data.h +++ b/device/fido/fido_test_data.h
@@ -87,6 +87,29 @@ 0x00, 0x00, }; +// kU2fBogusRegisterCommandApdu is the U2F register command generated by +// |ConstructBogusU2fRegistrationCommand|. +constexpr uint8_t kU2fBogusRegisterCommandApdu[] = { + // clang-format off + // CLA, INS, P1, P2 APDU instructions + 0x00, 0x01, 0x03, 0x00, + // Data length in 3 bytes in big endian order. + 0x00, 0x00, 0x40, + // Challenge parameter -- see kClientDataHash + 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, + // Application parameter + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + // Max response length + 0x00, 0x00, + // clang-format on +}; + // Sample U2F sign request parameters used in example 7 of the CTAP spec. // https://fidoalliance.org/specs/fido-v2.0-rd-20170927/fido-client-to-authenticator-protocol-v2.0-rd-20170927.html#using-the-ctap2-authenticatormakecredential-command-with-ctap1-u2f-authenticators constexpr uint8_t kU2fSignKeyHandle[] = {
diff --git a/device/fido/get_assertion_handler_unittest.cc b/device/fido/get_assertion_handler_unittest.cc index ed42af0..e30688d 100644 --- a/device/fido/get_assertion_handler_unittest.cc +++ b/device/fido/get_assertion_handler_unittest.cc
@@ -23,8 +23,10 @@ #include "device/fido/fido_transport_protocol.h" #include "device/fido/get_assertion_request_handler.h" #include "device/fido/hid/fake_hid_impl_for_testing.h" +#include "device/fido/make_credential_task.h" #include "device/fido/mock_fido_device.h" #include "device/fido/test_callback_receiver.h" +#include "device/fido/u2f_command_constructor.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -236,11 +238,15 @@ auto device = MockFidoDevice::MakeCtapWithGetInfoExpectation( test_data::kTestGetInfoResponseWithoutUvSupport); + device->ExpectRequestAndRespondWith( + MakeCredentialTask::GetTouchRequest(device.get()).EncodeAsCBOR(), + test_data::kTestMakeCredentialResponse); discovery()->AddDevice(std::move(device)); scoped_task_environment_.FastForwardUntilNoTasksRemain(); - EXPECT_FALSE(get_assertion_callback().was_called()); + EXPECT_EQ(FidoReturnCode::kUserConsentButCredentialNotRecognized, + get_assertion_callback().status()); } TEST_F(FidoGetAssertionHandlerTest, @@ -256,10 +262,14 @@ discovery()->WaitForCallToStartAndSimulateSuccess(); auto device = MockFidoDevice::MakeU2fWithGetInfoExpectation(); + device->ExpectRequestAndRespondWith( + ConstructBogusU2fRegistrationCommand(), + test_data::kApduEncodedNoErrorRegisterResponse); discovery()->AddDevice(std::move(device)); scoped_task_environment_.FastForwardUntilNoTasksRemain(); - EXPECT_FALSE(get_assertion_callback().was_called()); + EXPECT_EQ(FidoReturnCode::kUserConsentButCredentialNotRecognized, + get_assertion_callback().status()); } TEST_F(FidoGetAssertionHandlerTest, IncorrectRpIdHash) {
diff --git a/device/fido/make_credential_handler_unittest.cc b/device/fido/make_credential_handler_unittest.cc index dee7783..c5c9afca 100644 --- a/device/fido/make_credential_handler_unittest.cc +++ b/device/fido/make_credential_handler_unittest.cc
@@ -22,6 +22,7 @@ #include "device/fido/fido_test_data.h" #include "device/fido/fido_transport_protocol.h" #include "device/fido/make_credential_request_handler.h" +#include "device/fido/make_credential_task.h" #include "device/fido/mock_fido_device.h" #include "device/fido/test_callback_receiver.h" #include "device/fido/virtual_ctap2_device.h" @@ -189,46 +190,58 @@ auto request_handler = CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria( AuthenticatorSelectionCriteria( - AuthenticatorAttachment::kAny, false /* require_resident_key */, + AuthenticatorAttachment::kAny, /*require_resident_key=*/false, UserVerificationRequirement::kRequired)); discovery()->WaitForCallToStartAndSimulateSuccess(); auto device = MockFidoDevice::MakeU2fWithGetInfoExpectation(); + device->ExpectRequestAndRespondWith( + test_data::kU2fBogusRegisterCommandApdu, + test_data::kApduEncodedNoErrorRegisterResponse); discovery()->AddDevice(std::move(device)); scoped_task_environment_.FastForwardUntilNoTasksRemain(); - EXPECT_FALSE(callback().was_called()); + EXPECT_EQ(FidoReturnCode::kAuthenticatorMissingUserVerification, + callback().status()); } TEST_F(FidoMakeCredentialHandlerTest, U2fRegisterWithResidentKeyRequirement) { auto request_handler = CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria( AuthenticatorSelectionCriteria( - AuthenticatorAttachment::kAny, true /* require_resident_key */, + AuthenticatorAttachment::kAny, /*require_resident_key=*/true, UserVerificationRequirement::kPreferred)); discovery()->WaitForCallToStartAndSimulateSuccess(); auto device = MockFidoDevice::MakeU2fWithGetInfoExpectation(); + device->ExpectRequestAndRespondWith( + test_data::kU2fBogusRegisterCommandApdu, + test_data::kApduEncodedNoErrorRegisterResponse); discovery()->AddDevice(std::move(device)); scoped_task_environment_.FastForwardUntilNoTasksRemain(); - EXPECT_FALSE(callback().was_called()); + EXPECT_EQ(FidoReturnCode::kAuthenticatorMissingResidentKeys, + callback().status()); } TEST_F(FidoMakeCredentialHandlerTest, UserVerificationRequirementNotMet) { auto request_handler = CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria( AuthenticatorSelectionCriteria( - AuthenticatorAttachment::kAny, false /* require_resident_key */, + AuthenticatorAttachment::kAny, /*require_resident_key=*/false, UserVerificationRequirement::kRequired)); discovery()->WaitForCallToStartAndSimulateSuccess(); auto device = MockFidoDevice::MakeCtapWithGetInfoExpectation( test_data::kTestGetInfoResponseWithoutUvSupport); + device->ExpectRequestAndRespondWith( + MakeCredentialTask::GetTouchRequest(device.get()).EncodeAsCBOR(), + test_data::kTestMakeCredentialResponse); discovery()->AddDevice(std::move(device)); scoped_task_environment_.FastForwardUntilNoTasksRemain(); - EXPECT_FALSE(callback().was_called()); + EXPECT_EQ(FidoReturnCode::kAuthenticatorMissingUserVerification, + callback().status()); } // TODO(crbug.com/873710): Platform authenticators are temporarily disabled if @@ -242,7 +255,7 @@ auto request_handler = CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria( AuthenticatorSelectionCriteria( - AuthenticatorAttachment::kAny, false /* require_resident_key */, + AuthenticatorAttachment::kAny, /*require_resident_key=*/false, UserVerificationRequirement::kPreferred)); // MakeCredentialHandler will not dispatch the kAny request to the platform @@ -265,7 +278,7 @@ CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria( AuthenticatorSelectionCriteria( AuthenticatorAttachment::kCrossPlatform, - false /* require_resident_key */, + /*require_resident_key=*/false, UserVerificationRequirement::kPreferred)); // kCloudAssistedBluetoothLowEnergy not yet supported for MakeCredential. @@ -290,7 +303,7 @@ CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria( AuthenticatorSelectionCriteria( AuthenticatorAttachment::kPlatform, - false /* require_resident_key */, + /*require_resident_key=*/false, UserVerificationRequirement::kRequired)); ExpectAllowedTransportsForRequestAre(request_handler.get(), @@ -301,16 +314,21 @@ auto request_handler = CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria( AuthenticatorSelectionCriteria( - AuthenticatorAttachment::kAny, true /* require_resident_key */, + AuthenticatorAttachment::kAny, /*require_resident_key=*/true, UserVerificationRequirement::kPreferred)); discovery()->WaitForCallToStartAndSimulateSuccess(); auto device = MockFidoDevice::MakeCtapWithGetInfoExpectation( test_data::kTestGetInfoResponseWithoutResidentKeySupport); + device->ExpectRequestAndRespondWith( + MakeCredentialTask::GetTouchRequest(device.get()).EncodeAsCBOR(), + test_data::kTestMakeCredentialResponse); + discovery()->AddDevice(std::move(device)); scoped_task_environment_.FastForwardUntilNoTasksRemain(); - EXPECT_FALSE(callback().was_called()); + EXPECT_EQ(FidoReturnCode::kAuthenticatorMissingResidentKeys, + callback().status()); } TEST_F(FidoMakeCredentialHandlerTest, @@ -320,7 +338,7 @@ CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria( AuthenticatorSelectionCriteria( AuthenticatorAttachment::kCrossPlatform, - true /* require_resident_key */, + /*require_resident_key=*/true, UserVerificationRequirement::kRequired)); discovery()->WaitForCallToStartAndSimulateSuccess(); @@ -359,7 +377,7 @@ CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria( AuthenticatorSelectionCriteria( AuthenticatorAttachment::kPlatform, - true /* require_resident_key */, + /*require_resident_key=*/true, UserVerificationRequirement::kRequired)); callback().WaitForCallback(); @@ -378,7 +396,7 @@ CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria( AuthenticatorSelectionCriteria( AuthenticatorAttachment::kCrossPlatform, - false /* require_resident_key */, + /*require_resident_key=*/false, UserVerificationRequirement::kPreferred)); discovery()->WaitForCallToStartAndSimulateSuccess(); @@ -408,7 +426,7 @@ CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria( AuthenticatorSelectionCriteria( AuthenticatorAttachment::kPlatform, - true /* require_resident_key */, + /*require_resident_key=*/true, UserVerificationRequirement::kRequired)); scoped_task_environment_.FastForwardUntilNoTasksRemain(); @@ -427,7 +445,7 @@ CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria( AuthenticatorSelectionCriteria( AuthenticatorAttachment::kCrossPlatform, - false /* require_resident_key */, + /*require_resident_key=*/false, UserVerificationRequirement::kPreferred)); ExpectAllowedTransportsForRequestAre(request_handler.get(), kBleAndNfc); @@ -437,7 +455,7 @@ auto request_handler = CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria( AuthenticatorSelectionCriteria( - AuthenticatorAttachment::kAny, false /* require_resident_key */, + AuthenticatorAttachment::kAny, /*require_resident_key=*/false, UserVerificationRequirement::kPreferred)); discovery()->WaitForCallToStartAndSimulateSuccess(); @@ -466,7 +484,7 @@ auto request_handler = CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria( AuthenticatorSelectionCriteria( - AuthenticatorAttachment::kAny, true /* require_resident_key */, + AuthenticatorAttachment::kAny, /*require_resident_key=*/true, UserVerificationRequirement::kPreferred)); discovery()->WaitForCallToStartAndSimulateSuccess(); @@ -485,14 +503,15 @@ auto request_handler = CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria( AuthenticatorSelectionCriteria( - AuthenticatorAttachment::kAny, true /* require_resident_key */, + AuthenticatorAttachment::kAny, /*require_resident_key=*/true, UserVerificationRequirement::kPreferred)); discovery()->WaitForCallToStartAndSimulateSuccess(); discovery()->AddDevice(std::move(device)); scoped_task_environment_.FastForwardUntilNoTasksRemain(); - EXPECT_FALSE(callback().was_called()); + EXPECT_EQ(FidoReturnCode::kAuthenticatorMissingResidentKeys, + callback().status()); } // If a device with transport type kInternal returns a @@ -512,7 +531,7 @@ CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria( AuthenticatorSelectionCriteria( AuthenticatorAttachment::kPlatform, - false /* require_resident_key */, + /*require_resident_key=*/false, UserVerificationRequirement::kPreferred)); scoped_task_environment_.FastForwardUntilNoTasksRemain(); @@ -532,7 +551,7 @@ auto request_handler = CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria( AuthenticatorSelectionCriteria( - AuthenticatorAttachment::kAny, false /* require_resident_key */, + AuthenticatorAttachment::kAny, /*require_resident_key=*/false, UserVerificationRequirement::kPreferred)); discovery()->WaitForCallToStartAndSimulateSuccess();
diff --git a/device/fido/mock_fido_device.cc b/device/fido/mock_fido_device.cc index 27030a5..02282bf 100644 --- a/device/fido/mock_fido_device.cc +++ b/device/fido/mock_fido_device.cc
@@ -52,11 +52,14 @@ // static std::unique_ptr<MockFidoDevice> MockFidoDevice::MakeCtapWithGetInfoExpectation( base::Optional<base::span<const uint8_t>> get_info_response) { - auto device = std::make_unique<MockFidoDevice>(); - device->StubGetId(); if (!get_info_response) { get_info_response = test_data::kTestAuthenticatorGetInfoResponse; } + + auto get_info = ReadCTAPGetInfoResponse(*get_info_response); + CHECK(get_info); + auto device = MockFidoDevice::MakeCtap(std::move(*get_info)); + device->StubGetId(); device->ExpectCtap2CommandAndRespondWith( CtapRequestCommand::kAuthenticatorGetInfo, std::move(get_info_response)); return device;
diff --git a/device/vr/windows/compositor_base.cc b/device/vr/windows/compositor_base.cc index 1a714ab0..d4e0807 100644 --- a/device/vr/windows/compositor_base.cc +++ b/device/vr/windows/compositor_base.cc
@@ -64,10 +64,6 @@ // frame, we allow the renderer to receive poses. std::move(delayed_get_frame_data_callback_).Run(); } - - if (delayed_overlay_get_frame_data_callback_ && overlay_visible_) { - std::move(delayed_overlay_get_frame_data_callback_).Run(); - } } void XRCompositorCommon::SubmitFrameMissing(int16_t frame_index, @@ -250,7 +246,6 @@ // Kill outstanding overlays: overlay_visible_ = false; - delayed_overlay_get_frame_data_callback_.Reset(); overlay_binding_.Close(); texture_helper_.SetSourceAndOverlayVisible(false, false); @@ -402,16 +397,6 @@ DCHECK(overlay_visible_); TRACE_EVENT_INSTANT0("xr", "RequestOverlayPose", TRACE_EVENT_SCOPE_THREAD); - // If we've already given out a pose for the current frame delay giving out a - // pose until the next frame we are visible. - if (pending_frame_ && pending_frame_->overlay_has_pose_) { - DCHECK(!delayed_overlay_get_frame_data_callback_); - delayed_overlay_get_frame_data_callback_ = - base::BindOnce(&XRCompositorCommon::RequestNextOverlayPose, - base::Unretained(this), std::move(callback)); - return; - } - // Ensure we have a pending frame. StartPendingFrame(); pending_frame_->overlay_has_pose_ = true;
diff --git a/device/vr/windows/compositor_base.h b/device/vr/windows/compositor_base.h index 49fa920..e19a071b 100644 --- a/device/vr/windows/compositor_base.h +++ b/device/vr/windows/compositor_base.h
@@ -150,7 +150,6 @@ bool webxr_visible_ = true; // The browser may hide a presenting session. bool overlay_visible_ = false; base::OnceCallback<void()> delayed_get_frame_data_callback_; - base::OnceCallback<void()> delayed_overlay_get_frame_data_callback_; gfx::RectF left_webxr_bounds_; gfx::RectF right_webxr_bounds_;
diff --git a/third_party/blink/public/BUILD.gn b/third_party/blink/public/BUILD.gn index f4f76e4..1c6b8a32 100644 --- a/third_party/blink/public/BUILD.gn +++ b/third_party/blink/public/BUILD.gn
@@ -670,7 +670,6 @@ "platform/modules/bluetooth/web_bluetooth.mojom", ] public_deps = [ - ":android_mojo_bindings", "//components/services/font/public/interfaces", "//device/bluetooth/public/mojom", "//mojo/public/mojom/base", @@ -703,32 +702,6 @@ export_header_blink = "third_party/blink/public/platform/web_common.h" } -mojom("android_mojo_bindings") { - visibility = [ ":mojo_bindings" ] - visibility_blink = [ ":mojo_bindings_blink" ] - sources = [ - "platform/modules/font_unique_name_lookup/font_unique_name_lookup.mojom", - "platform/modules/installation/installation.mojom", - "platform/modules/mediasession/media_session.mojom", - ] - public_deps = [ - "//mojo/public/mojom/base", - "//services/media_session/public/mojom", - "//ui/gfx/geometry/mojo", - "//url/mojom:url_mojom_gurl", - ] - - component_output_prefix = "blink_android_mojo_bindings" - - # See comment above. - export_class_attribute = "CONTENT_EXPORT" - export_define = "CONTENT_IMPLEMENTATION=1" - export_header = "content/common/content_export.h" - export_class_attribute_blink = "BLINK_PLATFORM_EXPORT" - export_define_blink = "BLINK_PLATFORM_IMPLEMENTATION=1" - export_header_blink = "third_party/blink/public/platform/web_common.h" -} - # Note that this intentionally depends on the generator target of the mojom # target instead of the mojom target itself directly. This is to ensure that the # dependencies are header-only and don't link against any bindings code.
diff --git a/third_party/blink/public/mojom/BUILD.gn b/third_party/blink/public/mojom/BUILD.gn index b953e9b1..343679a 100644 --- a/third_party/blink/public/mojom/BUILD.gn +++ b/third_party/blink/public/mojom/BUILD.gn
@@ -183,10 +183,13 @@ mojom("android_mojo_bindings") { sources = [ "document_metadata/copyless_paste.mojom", + "font_unique_name_lookup/font_unique_name_lookup.mojom", "input/input_host.mojom", "input/input_messages.mojom", + "installation/installation.mojom", "installedapp/installed_app_provider.mojom", "installedapp/related_application.mojom", + "mediasession/media_session.mojom", "payments/payment_request.mojom", "remote_objects/remote_objects.mojom", "webauthn/authenticator.mojom", @@ -198,6 +201,7 @@ public_deps = [ "//components/payments/mojom", "//mojo/public/mojom/base", + "//services/media_session/public/mojom", "//url/mojom:url_mojom_gurl", "//url/mojom:url_mojom_origin", ]
diff --git a/third_party/blink/public/platform/modules/font_unique_name_lookup/OWNERS b/third_party/blink/public/mojom/font_unique_name_lookup/OWNERS similarity index 100% rename from third_party/blink/public/platform/modules/font_unique_name_lookup/OWNERS rename to third_party/blink/public/mojom/font_unique_name_lookup/OWNERS
diff --git a/third_party/blink/public/platform/modules/font_unique_name_lookup/font_unique_name_lookup.mojom b/third_party/blink/public/mojom/font_unique_name_lookup/font_unique_name_lookup.mojom similarity index 100% rename from third_party/blink/public/platform/modules/font_unique_name_lookup/font_unique_name_lookup.mojom rename to third_party/blink/public/mojom/font_unique_name_lookup/font_unique_name_lookup.mojom
diff --git a/third_party/blink/public/platform/modules/installation/OWNERS b/third_party/blink/public/mojom/installation/OWNERS similarity index 100% rename from third_party/blink/public/platform/modules/installation/OWNERS rename to third_party/blink/public/mojom/installation/OWNERS
diff --git a/third_party/blink/public/platform/modules/installation/installation.mojom b/third_party/blink/public/mojom/installation/installation.mojom similarity index 100% rename from third_party/blink/public/platform/modules/installation/installation.mojom rename to third_party/blink/public/mojom/installation/installation.mojom
diff --git a/third_party/blink/public/platform/modules/mediasession/OWNERS b/third_party/blink/public/mojom/mediasession/OWNERS similarity index 100% rename from third_party/blink/public/platform/modules/mediasession/OWNERS rename to third_party/blink/public/mojom/mediasession/OWNERS
diff --git a/third_party/blink/public/platform/modules/mediasession/media_session.mojom b/third_party/blink/public/mojom/mediasession/media_session.mojom similarity index 100% rename from third_party/blink/public/platform/modules/mediasession/media_session.mojom rename to third_party/blink/public/mojom/mediasession/media_session.mojom
diff --git a/third_party/blink/public/platform/modules/media_capabilities/web_media_capabilities_callbacks.h b/third_party/blink/public/platform/modules/media_capabilities/web_media_capabilities_callbacks.h index e7b9b57..21446a9 100644 --- a/third_party/blink/public/platform/modules/media_capabilities/web_media_capabilities_callbacks.h +++ b/third_party/blink/public/platform/modules/media_capabilities/web_media_capabilities_callbacks.h
@@ -16,9 +16,6 @@ using WebMediaCapabilitiesDecodingInfoCallbacks = WebCallbacks<std::unique_ptr<WebMediaCapabilitiesDecodingInfo>, void>; -using WebMediaCapabilitiesEncodingInfoCallbacks = - WebCallbacks<std::unique_ptr<WebMediaCapabilitiesInfo>, void>; - } // namespace blink #endif // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_MEDIA_CAPABILITIES_WEB_MEDIA_CAPABILITIES_CALLBACKS_H_
diff --git a/third_party/blink/public/platform/web_media_recorder_handler.h b/third_party/blink/public/platform/web_media_recorder_handler.h index a918cc3..a7f597e 100644 --- a/third_party/blink/public/platform/web_media_recorder_handler.h +++ b/third_party/blink/public/platform/web_media_recorder_handler.h
@@ -9,7 +9,7 @@ #include "third_party/blink/public/platform/web_common.h" -#include "third_party/blink/public/platform/modules/media_capabilities/web_media_capabilities_callbacks.h" +#include "base/callback.h" #include "third_party/blink/public/platform/web_string.h" namespace blink { @@ -17,6 +17,7 @@ class WebMediaRecorderHandlerClient; struct WebMediaConfiguration; class WebMediaStream; +struct WebMediaCapabilitiesInfo; // Platform interface of a MediaRecorder. class BLINK_PLATFORM_EXPORT WebMediaRecorderHandler { @@ -52,9 +53,10 @@ // Implements WICG Media Capabilities encodingInfo() call for local encoding. // https://wicg.github.io/media-capabilities/#media-capabilities-interface - virtual void EncodingInfo( - const WebMediaConfiguration&, - std::unique_ptr<blink::WebMediaCapabilitiesEncodingInfoCallbacks>) {} + using OnMediaCapabilitiesEncodingInfoCallback = + base::OnceCallback<void(std::unique_ptr<WebMediaCapabilitiesInfo>)>; + virtual void EncodingInfo(const WebMediaConfiguration&, + OnMediaCapabilitiesEncodingInfoCallback) {} }; } // namespace blink
diff --git a/third_party/blink/public/platform/web_media_stream_center.h b/third_party/blink/public/platform/web_media_stream_center.h index a8cb5d1..571d245 100644 --- a/third_party/blink/public/platform/web_media_stream_center.h +++ b/third_party/blink/public/platform/web_media_stream_center.h
@@ -59,7 +59,8 @@ // Caller must take the ownership of the returned |WebAudioSourceProvider| // object. virtual WebAudioSourceProvider* CreateWebAudioSourceFromMediaStreamTrack( - const WebMediaStreamTrack&) { + const WebMediaStreamTrack&, + int context_sample_rate) { return nullptr; } };
diff --git a/third_party/blink/public/platform/web_transmission_encoding_info_handler.h b/third_party/blink/public/platform/web_transmission_encoding_info_handler.h index 7818d081..bdae8b2 100644 --- a/third_party/blink/public/platform/web_transmission_encoding_info_handler.h +++ b/third_party/blink/public/platform/web_transmission_encoding_info_handler.h
@@ -26,10 +26,10 @@ // It implements WICG Media Capabilities encodingInfo() call for transmission // encoding. // https://wicg.github.io/media-capabilities/#media-capabilities-interface - virtual void EncodingInfo( - const WebMediaConfiguration&, - std::unique_ptr<blink::WebMediaCapabilitiesEncodingInfoCallbacks>) - const = 0; + using OnMediaCapabilitiesEncodingInfoCallback = + base::OnceCallback<void(std::unique_ptr<WebMediaCapabilitiesInfo>)>; + virtual void EncodingInfo(const WebMediaConfiguration&, + OnMediaCapabilitiesEncodingInfoCallback) const = 0; }; } // namespace blink
diff --git a/third_party/blink/renderer/core/dom/node.cc b/third_party/blink/renderer/core/dom/node.cc index 75c79e9e..ccc863c 100644 --- a/third_party/blink/renderer/core/dom/node.cc +++ b/third_party/blink/renderer/core/dom/node.cc
@@ -2668,7 +2668,8 @@ return; const AtomicString& event_type = event.type(); if (event_type == event_type_names::kKeydown || - event_type == event_type_names::kKeypress) { + event_type == event_type_names::kKeypress || + event_type == event_type_names::kKeyup) { if (event.IsKeyboardEvent()) { if (LocalFrame* frame = GetDocument().GetFrame()) { frame->GetEventHandler().DefaultKeyboardEventHandler(
diff --git a/third_party/blink/renderer/core/editing/editing_style.cc b/third_party/blink/renderer/core/editing/editing_style.cc index 117d671..9fda59c70 100644 --- a/third_party/blink/renderer/core/editing/editing_style.cc +++ b/third_party/blink/renderer/core/editing/editing_style.cc
@@ -61,7 +61,6 @@ #include "third_party/blink/renderer/core/html/html_font_element.h" #include "third_party/blink/renderer/core/html/html_span_element.h" #include "third_party/blink/renderer/core/html_names.h" -#include "third_party/blink/renderer/core/layout/layout_box.h" #include "third_party/blink/renderer/core/layout/layout_object.h" #include "third_party/blink/renderer/core/style/computed_style.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h"
diff --git a/third_party/blink/renderer/core/editing/editor.cc b/third_party/blink/renderer/core/editing/editor.cc index 52b36532..21d575b 100644 --- a/third_party/blink/renderer/core/editing/editor.cc +++ b/third_party/blink/renderer/core/editing/editor.cc
@@ -80,7 +80,6 @@ #include "third_party/blink/renderer/core/input/event_handler.h" #include "third_party/blink/renderer/core/input_type_names.h" #include "third_party/blink/renderer/core/layout/hit_test_result.h" -#include "third_party/blink/renderer/core/layout/layout_object.h" #include "third_party/blink/renderer/core/loader/empty_clients.h" #include "third_party/blink/renderer/core/loader/resource/image_resource_content.h" #include "third_party/blink/renderer/core/page/drag_data.h"
diff --git a/third_party/blink/renderer/core/editing/finder/find_buffer.cc b/third_party/blink/renderer/core/editing/finder/find_buffer.cc index 4587109..8ace57e 100644 --- a/third_party/blink/renderer/core/editing/finder/find_buffer.cc +++ b/third_party/blink/renderer/core/editing/finder/find_buffer.cc
@@ -17,6 +17,7 @@ #include "third_party/blink/renderer/core/layout/layout_block_flow.h" #include "third_party/blink/renderer/core/layout/layout_object.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h" +#include "third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h" #include "third_party/blink/renderer/core/style/computed_style.h" #include "third_party/blink/renderer/platform/text/unicode_utilities.h" #include "third_party/blink/renderer/platform/wtf/text/character_names.h"
diff --git a/third_party/blink/renderer/core/editing/finder/find_buffer.h b/third_party/blink/renderer/core/editing/finder/find_buffer.h index be236144..35a882f 100644 --- a/third_party/blink/renderer/core/editing/finder/find_buffer.h +++ b/third_party/blink/renderer/core/editing/finder/find_buffer.h
@@ -8,11 +8,12 @@ #include "third_party/blink/renderer/core/display_lock/display_lock_context.h" #include "third_party/blink/renderer/core/editing/finder/find_options.h" #include "third_party/blink/renderer/core/editing/iterators/text_searcher_icu.h" -#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h" +#include "third_party/blink/renderer/core/editing/position.h" namespace blink { class LayoutBlockFlow; +class NGOffsetMapping; class Node; class WebString; @@ -195,12 +196,7 @@ Vector<BufferNodeMapping> buffer_node_mappings_; Vector<DisplayLockContext::ScopedForcedUpdate> scoped_forced_update_list_; - // For legacy layout, we need to save a unique_ptr of the NGOffsetMapping - // because nobody owns it. In LayoutNG, the NGOffsetMapping is owned by - // the corresponding LayoutBlockFlow, so we don't need to save it. - std::unique_ptr<NGOffsetMapping> offset_mapping_storage_; const NGOffsetMapping* offset_mapping_ = nullptr; - bool mapping_needs_recalc_ = false; };
diff --git a/third_party/blink/renderer/core/editing/visible_units_line.cc b/third_party/blink/renderer/core/editing/visible_units_line.cc index e6e4be8b..cbb84df 100644 --- a/third_party/blink/renderer/core/editing/visible_units_line.cc +++ b/third_party/blink/renderer/core/editing/visible_units_line.cc
@@ -187,6 +187,12 @@ << "Logical line boundary for BidiCaretAffinity is not implemented yet"; const NGCaretPosition caret_position = ComputeNGCaretPosition(adjusted); + if (caret_position.IsNull()) { + // TODO(crbug.com/947593): Support |ComputeNGCaretPosition()| on content + // hidden by 'text-overflow:ellipsis' so that we always have a non-null + // |caret_position| here. + return PositionWithAffinityTemplate<Strategy>(); + } DCHECK(caret_position.fragment); DCHECK(caret_position.fragment->ContainerLineBox()); const NGPaintFragment* line_box_paint = @@ -465,6 +471,12 @@ << "Logical line boundary for BidiCaretAffinity is not implemented yet"; const NGCaretPosition caret_position = ComputeNGCaretPosition(adjusted); + if (caret_position.IsNull()) { + // TODO(crbug.com/947593): Support |ComputeNGCaretPosition()| on content + // hidden by 'text-overflow:ellipsis' so that we always have a non-null + // |caret_position| here. + return PositionWithAffinityTemplate<Strategy>(); + } DCHECK(caret_position.fragment); DCHECK(caret_position.fragment->ContainerLineBox()); const NGPaintFragment* line_box_paint =
diff --git a/third_party/blink/renderer/core/editing/visible_units_line_test.cc b/third_party/blink/renderer/core/editing/visible_units_line_test.cc index 3300eea..8fdb727 100644 --- a/third_party/blink/renderer/core/editing/visible_units_line_test.cc +++ b/third_party/blink/renderer/core/editing/visible_units_line_test.cc
@@ -699,4 +699,27 @@ EXPECT_FALSE(InSameLine(position1, position2)); } +// https://crbug.com/947462 +TEST_F(VisibleUnitsLineTest, TextOverflowEllipsis) { + LoadAhem(); + InsertStyleElement(R"HTML( + div { + width: 40px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + font: 10px/10px Ahem; + })HTML"); + SetBodyContent("<div>foo foo</div>"); + Element* div = GetDocument().QuerySelector("div"); + Node* text = div->firstChild(); + // TODO(crbug.com/947593): Support Start/EndOfLine with ellipsis on LayoutNG + EXPECT_EQ( + LayoutNGEnabled() ? Position() : Position(text, 0), + StartOfLine(CreateVisiblePositionInDOMTree(*text, 6)).DeepEquivalent()); + EXPECT_EQ( + LayoutNGEnabled() ? Position() : Position(text, 7), + EndOfLine(CreateVisiblePositionInDOMTree(*text, 6)).DeepEquivalent()); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/exported/web_frame_content_dumper.cc b/third_party/blink/renderer/core/exported/web_frame_content_dumper.cc index 8dc229b..76b81a95 100644 --- a/third_party/blink/renderer/core/exported/web_frame_content_dumper.cc +++ b/third_party/blink/renderer/core/exported/web_frame_content_dumper.cc
@@ -16,9 +16,6 @@ #include "third_party/blink/renderer/core/frame/web_local_frame_impl.h" #include "third_party/blink/renderer/core/html_element_type_helpers.h" #include "third_party/blink/renderer/core/layout/layout_embedded_content.h" -#include "third_party/blink/renderer/core/layout/layout_table_cell.h" -#include "third_party/blink/renderer/core/layout/layout_table_row.h" -#include "third_party/blink/renderer/core/layout/layout_text_fragment.h" #include "third_party/blink/renderer/core/layout/layout_tree_as_text.h" #include "third_party/blink/renderer/core/layout/layout_view.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
diff --git a/third_party/blink/renderer/core/exported/web_layer_test.cc b/third_party/blink/renderer/core/exported/web_layer_test.cc index 4efef7e..d7c9ee5 100644 --- a/third_party/blink/renderer/core/exported/web_layer_test.cc +++ b/third_party/blink/renderer/core/exported/web_layer_test.cc
@@ -4,6 +4,7 @@ #include "build/build_config.h" #include "cc/layers/picture_layer.h" +#include "cc/trees/effect_node.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/platform/web_url_loader_mock_factory.h" #include "third_party/blink/public/web/web_script_source.h" @@ -741,4 +742,46 @@ (squashed_bg_color == SK_ColorCYAN)); } +TEST_P(WebLayerListSimTest, NonDrawableLayersIgnoredForRenderSurfaces) { + // TODO(crbug.com/765003): CAP may make different layerization decisions. When + // CAP gets closer to launch, this test should be updated to pass. + if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) + return; + + InitializeWithHTML(R"HTML( + <!DOCTYPE html> + <style> + #outer { + width: 100px; + height: 100px; + opacity: 0.5; + background: blue; + } + #inner { + width: 10px; + height: 10px; + will-change: transform; + } + </style> + <div id='outer'> + <div id='inner'></div> + </div> + )HTML"); + + Compositor().BeginFrame(); + + ASSERT_GE(ContentLayerCount(), 2u); + auto* inner_element_layer = ContentLayerAt(ContentLayerCount() - 1); + EXPECT_FALSE(inner_element_layer->DrawsContent()); + auto* outer_element_layer = ContentLayerAt(ContentLayerCount() - 2); + EXPECT_TRUE(outer_element_layer->DrawsContent()); + + // The inner element layer is only needed for hit testing and does not draw + // content, so it should not cause a render surface. + auto effect_tree_index = outer_element_layer->effect_tree_index(); + auto* effect_node = GetPropertyTrees()->effect_tree.Node(effect_tree_index); + EXPECT_EQ(effect_node->opacity, 0.5f); + EXPECT_FALSE(effect_node->has_render_surface); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/html/forms/text_control_element.cc b/third_party/blink/renderer/core/html/forms/text_control_element.cc index 448af62..ea641f8b 100644 --- a/third_party/blink/renderer/core/html/forms/text_control_element.cc +++ b/third_party/blink/renderer/core/html/forms/text_control_element.cc
@@ -52,9 +52,7 @@ #include "third_party/blink/renderer/core/html/parser/html_parser_idioms.h" #include "third_party/blink/renderer/core/html/shadow/shadow_element_names.h" #include "third_party/blink/renderer/core/html_names.h" -#include "third_party/blink/renderer/core/layout/layout_block.h" #include "third_party/blink/renderer/core/layout/layout_block_flow.h" -#include "third_party/blink/renderer/core/layout/layout_theme.h" #include "third_party/blink/renderer/core/page/focus_controller.h" #include "third_party/blink/renderer/core/page/page.h" #include "third_party/blink/renderer/platform/bindings/exception_messages.h"
diff --git a/third_party/blink/renderer/core/input/keyboard_event_manager.cc b/third_party/blink/renderer/core/input/keyboard_event_manager.cc index 5099439..0c4abb2a 100644 --- a/third_party/blink/renderer/core/input/keyboard_event_manager.cc +++ b/third_party/blink/renderer/core/input/keyboard_event_manager.cc
@@ -329,13 +329,15 @@ // events that aren't necessarily arrow keys. DefaultArrowEventHandler(event, possible_focused_node); } - } - if (event->type() == event_type_names::kKeypress) { + } else if (event->type() == event_type_names::kKeypress) { frame_->GetEditor().HandleKeyboardEvent(event); if (event->DefaultHandled()) return; if (event->charCode() == ' ') DefaultSpaceEventHandler(event, possible_focused_node); + } else if (event->type() == event_type_names::kKeyup) { + if (event->key() == "Enter") + DefaultEnterEventHandler(event); } }
diff --git a/third_party/blink/renderer/core/layout/layout_block.cc b/third_party/blink/renderer/core/layout/layout_block.cc index de9b41aa..cdac8554 100644 --- a/third_party/blink/renderer/core/layout/layout_block.cc +++ b/third_party/blink/renderer/core/layout/layout_block.cc
@@ -1464,9 +1464,14 @@ // Size-contained elements don't consider their contents for preferred sizing. if (ShouldApplySizeContainment()) { - max_logical_width = LayoutUnit(scrollbar_width); - min_logical_width = LayoutUnit(scrollbar_width); - return; + // For multicol containers we need the column gaps. So allow descending into + // the flow thread, which will take care of that. + const auto* block_flow = ToLayoutBlockFlowOrNull(this); + if (!block_flow || !block_flow->MultiColumnFlowThread()) { + max_logical_width = LayoutUnit(scrollbar_width); + min_logical_width = LayoutUnit(scrollbar_width); + return; + } } if (ChildrenInline()) {
diff --git a/third_party/blink/renderer/core/layout/layout_inline.cc b/third_party/blink/renderer/core/layout/layout_inline.cc index 5ab78594..9abe2a2 100644 --- a/third_party/blink/renderer/core/layout/layout_inline.cc +++ b/third_party/blink/renderer/core/layout/layout_inline.cc
@@ -332,13 +332,17 @@ } } + bool old_style_is_containing_block = + old_style && (old_style->CanContainAbsolutePositionObjects() || + old_style->HasFilter()); + bool new_style_is_containing_block = + old_style && + (new_style.CanContainAbsolutePositionObjects() || new_style.HasFilter()); // If we are changing to/from static, we need to reposition // out-of-flow positioned descendants. - if (old_style && old_style->GetPosition() != new_style.GetPosition() && - (new_style.GetPosition() == EPosition::kStatic || - old_style->GetPosition() == EPosition::kStatic)) { + if (old_style_is_containing_block != new_style_is_containing_block) { LayoutBlock* abs_containing_block = nullptr; - if (old_style->GetPosition() == EPosition::kStatic) { + if (!old_style_is_containing_block) { abs_containing_block = ContainingBlockForAbsolutePosition(); } else { // When position was not static, containingBlockForAbsolutePosition
diff --git a/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.cc b/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.cc index e1e76b9..31e226b 100644 --- a/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.cc +++ b/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.cc
@@ -1332,8 +1332,6 @@ } void LayoutMultiColumnFlowThread::ComputePreferredLogicalWidths() { - LayoutFlowThread::ComputePreferredLogicalWidths(); - // The min/max intrinsic widths calculated really tell how much space elements // need when laid out inside the columns. In order to eventually end up with // the desired column width, we need to convert them to values pertaining to @@ -1341,9 +1339,20 @@ const ComputedStyle* multicol_style = MultiColumnBlockFlow()->Style(); LayoutUnit column_count( multicol_style->HasAutoColumnCount() ? 1 : multicol_style->ColumnCount()); - LayoutUnit column_width; LayoutUnit gap_extra((column_count - 1) * ColumnGap(*multicol_style, LayoutUnit())); + + if (MultiColumnBlockFlow()->ShouldApplySizeContainment()) { + LayoutUnit size = gap_extra; + if (!multicol_style->HasAutoColumnWidth()) + size += LayoutUnit(multicol_style->ColumnWidth()) * column_count; + max_preferred_logical_width_ = min_preferred_logical_width_ = size; + ClearPreferredLogicalWidthsDirty(); + return; + } + + LayoutFlowThread::ComputePreferredLogicalWidths(); + LayoutUnit column_width; if (multicol_style->HasAutoColumnWidth()) { min_preferred_logical_width_ = min_preferred_logical_width_ * column_count + gap_extra;
diff --git a/third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.cc b/third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.cc index b5bd25c..965bced 100644 --- a/third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.cc +++ b/third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.cc
@@ -103,11 +103,22 @@ LayoutUnit LayoutMultiColumnSpannerPlaceholder::MinPreferredLogicalWidth() const { + // There should be no contribution from a spanner if the multicol container is + // size-contained. Normally we'd stop at the object that has contain:size + // applied, but for multicol, we descend into the children, in order to get + // the flow thread to calculate the correct preferred width (to honor + // column-count, column-width and column-gap). Since spanner placeholders are + // siblings of the flow thread, we need this check. + if (MultiColumnBlockFlow()->ShouldApplySizeContainment()) + return LayoutUnit(); return layout_object_in_flow_thread_->MinPreferredLogicalWidth(); } LayoutUnit LayoutMultiColumnSpannerPlaceholder::MaxPreferredLogicalWidth() const { + // See above. + if (MultiColumnBlockFlow()->ShouldApplySizeContainment()) + return LayoutUnit(); return layout_object_in_flow_thread_->MaxPreferredLogicalWidth(); }
diff --git a/third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.h b/third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.h index 888a6bc2..eb832797 100644 --- a/third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.h +++ b/third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.h
@@ -26,6 +26,10 @@ const ComputedStyle& parent_style, LayoutBox&); + LayoutBlockFlow* MultiColumnBlockFlow() const { + return ToLayoutBlockFlow(Parent()); + } + LayoutMultiColumnFlowThread* FlowThread() const { return ToLayoutBlockFlow(Parent())->MultiColumnFlowThread(); }
diff --git a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc index cce0291..345cd3a 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
@@ -150,24 +150,43 @@ LayoutDescendantCandidates(&descendant_candidates, only_layout, &placed_objects); - // Gather candidates that weren't present in the OOF candidates list. - // This occurs when a candidate is separated from container by a legacy node. - // E.g. - // <div style="position: relative;"> - // <div style="display: flex;"> - // <div style="position: absolute;"></div> - // </div> - // </div> + if (only_layout) + return; + + while (SweepLegacyDescendants(&placed_objects)) { + container_builder_->GetAndClearOutOfFlowDescendantCandidates( + &descendant_candidates, current_container); + + // We must have at least one new candidate, otherwise we shouldn't have + // entered this branch. + DCHECK_GT(descendant_candidates.size(), 0u); + + LayoutDescendantCandidates(&descendant_candidates, only_layout, + &placed_objects); + } +} + +// Gather candidates that weren't present in the OOF candidates list. +// This occurs when a candidate is separated from container by a legacy node. +// E.g. +// <div style="position: relative;"> +// <div style="display: flex;"> +// <div style="position: absolute;"></div> +// </div> +// </div> +// Returns false if no new candidates were found. +bool NGOutOfFlowLayoutPart::SweepLegacyDescendants( + HashSet<const LayoutObject*>* placed_objects) { const LayoutBlock* container_block = ToLayoutBlockOrNull(container_builder_->GetLayoutObject()); - if (!container_block || only_layout) - return; + if (!container_block) + return false; TrackedLayoutBoxListHashSet* legacy_objects = container_block->PositionedObjects(); - if (!legacy_objects || legacy_objects->size() == placed_objects.size()) - return; + if (!legacy_objects || legacy_objects->size() == placed_objects->size()) + return false; for (LayoutObject* legacy_object : *legacy_objects) { - if (placed_objects.Contains(legacy_object)) + if (placed_objects->Contains(legacy_object)) continue; // Flex OOF children may have center alignment or similar, and in order @@ -203,16 +222,7 @@ NGBlockNode(layout_box), static_position, css_container->IsBox() ? nullptr : css_container); } - - container_builder_->GetAndClearOutOfFlowDescendantCandidates( - &descendant_candidates, current_container); - - // We must have at least one new candidate, otherwise we shouldn't have - // entered this branch. - DCHECK_GT(descendant_candidates.size(), 0u); - - LayoutDescendantCandidates(&descendant_candidates, only_layout, - &placed_objects); + return true; } NGOutOfFlowLayoutPart::ContainingBlockInfo
diff --git a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h index 388b6e9..1e9648b 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h +++ b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h
@@ -90,6 +90,8 @@ } }; + bool SweepLegacyDescendants(HashSet<const LayoutObject*>* placed_objects); + ContainingBlockInfo GetContainingBlockInfo( const NGOutOfFlowPositionedDescendant&) const;
diff --git a/third_party/blink/renderer/core/loader/base_fetch_context.cc b/third_party/blink/renderer/core/loader/base_fetch_context.cc index dac2dc4..87c488a 100644 --- a/third_party/blink/renderer/core/loader/base_fetch_context.cc +++ b/third_party/blink/renderer/core/loader/base_fetch_context.cc
@@ -178,7 +178,7 @@ "Sec-Fetch-Mode", FetchRequestModeToString(request.GetFetchRequestMode())); request.AddHttpHeaderField("Sec-Fetch-Site", site_value); - request.AddHttpHeaderField("Sec-Fetch-User", "?F"); + // We don't set `Sec-Fetch-User` for subresource requests. } } }
diff --git a/third_party/blink/renderer/core/page/scrolling/text_fragment_finder.cc b/third_party/blink/renderer/core/page/scrolling/text_fragment_finder.cc index 44160e0..48b6136 100644 --- a/third_party/blink/renderer/core/page/scrolling/text_fragment_finder.cc +++ b/third_party/blink/renderer/core/page/scrolling/text_fragment_finder.cc
@@ -6,6 +6,7 @@ #include <memory> +#include "third_party/blink/public/platform/web_string.h" #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/dom/range.h" #include "third_party/blink/renderer/core/editing/ephemeral_range.h"
diff --git a/third_party/blink/renderer/core/page/spatial_navigation_controller.cc b/third_party/blink/renderer/core/page/spatial_navigation_controller.cc index da2655d..3d9364f2 100644 --- a/third_party/blink/renderer/core/page/spatial_navigation_controller.cc +++ b/third_party/blink/renderer/core/page/spatial_navigation_controller.cc
@@ -168,10 +168,20 @@ KeyboardEvent* event) { DCHECK(page_->GetSettings().GetSpatialNavigationEnabled()); - if (interest_element_) { - interest_element_->focus(FocusParams(SelectionBehaviorOnFocus::kReset, - kWebFocusTypeSpatialNavigation, - nullptr)); + Element* interest_element = GetInterestedElement(); + + if (!interest_element) + return false; + + if (event->type() == event_type_names::kKeydown) { + if (RuntimeEnabledFeatures::FocuslessSpatialNavigationEnabled()) { + interest_element->focus(FocusParams(SelectionBehaviorOnFocus::kReset, + kWebFocusTypeSpatialNavigation, + nullptr)); + } + interest_element->SetActive(true); + } else if (event->type() == event_type_names::kKeyup) { + interest_element->SetActive(false); } return true;
diff --git a/third_party/blink/renderer/core/page/spatial_navigation_test.cc b/third_party/blink/renderer/core/page/spatial_navigation_test.cc index 09114a8..37b916c 100644 --- a/third_party/blink/renderer/core/page/spatial_navigation_test.cc +++ b/third_party/blink/renderer/core/page/spatial_navigation_test.cc
@@ -5,12 +5,17 @@ #include "third_party/blink/renderer/core/page/spatial_navigation.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/platform/web_keyboard_event.h" #include "third_party/blink/renderer/core/exported/web_remote_frame_impl.h" #include "third_party/blink/renderer/core/frame/frame_test_helpers.h" +#include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/visual_viewport.h" #include "third_party/blink/renderer/core/frame/web_local_frame_impl.h" +#include "third_party/blink/renderer/core/input/event_handler.h" #include "third_party/blink/renderer/core/testing/core_unit_test_helper.h" +#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h" #include "third_party/blink/renderer/platform/testing/url_test_helpers.h" +#include "ui/events/keycodes/dom/dom_key.h" namespace blink { @@ -653,4 +658,54 @@ EXPECT_TRUE(HasRemoteFrame(iframe)); } +class SpatialNavigationWithFocuslessModeTest + : public SpatialNavigationTest, + public ::testing::WithParamInterface<bool> { + public: + SpatialNavigationWithFocuslessModeTest() : use_focusless_mode_(GetParam()) {} + + void SetUp() override { + SpatialNavigationTest::SetUp(); + GetDocument().GetSettings()->SetSpatialNavigationEnabled(true); + } + + private: + ScopedFocuslessSpatialNavigationForTest use_focusless_mode_; +}; + +INSTANTIATE_TEST_SUITE_P(, + SpatialNavigationWithFocuslessModeTest, + ::testing::Bool()); + +TEST_P(SpatialNavigationWithFocuslessModeTest, PressEnterKeyActiveElement) { + SetBodyInnerHTML("<button id='b'>hello</button>"); + + Element* b = GetDocument().getElementById("b"); + + // Move interest to button. + WebKeyboardEvent arrow_down{WebInputEvent::kRawKeyDown, + WebInputEvent::kNoModifiers, + WebInputEvent::GetStaticTimeStampForTests()}; + arrow_down.dom_key = ui::DomKey::ARROW_DOWN; + GetDocument().GetFrame()->GetEventHandler().KeyEvent(arrow_down); + + arrow_down.SetType(WebInputEvent::kKeyUp); + GetDocument().GetFrame()->GetEventHandler().KeyEvent(arrow_down); + + EXPECT_FALSE(b->IsActive()); + + // Enter key down add :active state to element. + WebKeyboardEvent enter{WebInputEvent::kRawKeyDown, + WebInputEvent::kNoModifiers, + WebInputEvent::GetStaticTimeStampForTests()}; + enter.dom_key = ui::DomKey::ENTER; + GetDocument().GetFrame()->GetEventHandler().KeyEvent(enter); + EXPECT_TRUE(b->IsActive()); + + // Enter key up remove :active state to element. + enter.SetType(WebInputEvent::kKeyUp); + GetDocument().GetFrame()->GetEventHandler().KeyEvent(enter); + EXPECT_FALSE(b->IsActive()); +} + } // namespace blink
diff --git a/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.cc b/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.cc index a9c06509..02a7e39b 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.cc
@@ -140,8 +140,9 @@ DCHECK(!IsDetached()); if (!inline_text_box_ || !ax_object_cache_) return nullptr; - LineLayoutText line_layout_text = inline_text_box_->GetLineLayoutItem(); + if (!line_layout_text) + return nullptr; return ax_object_cache_->GetOrCreate( LineLayoutAPIShim::LayoutObjectFrom(line_layout_text)); }
diff --git a/third_party/blink/renderer/modules/installation/installation_service_impl.h b/third_party/blink/renderer/modules/installation/installation_service_impl.h index 34cae46..37f87780 100644 --- a/third_party/blink/renderer/modules/installation/installation_service_impl.h +++ b/third_party/blink/renderer/modules/installation/installation_service_impl.h
@@ -5,7 +5,7 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_INSTALLATION_INSTALLATION_SERVICE_IMPL_H_ #define THIRD_PARTY_BLINK_RENDERER_MODULES_INSTALLATION_INSTALLATION_SERVICE_IMPL_H_ -#include "third_party/blink/public/platform/modules/installation/installation.mojom-blink.h" +#include "third_party/blink/public/mojom/installation/installation.mojom-blink.h" #include "third_party/blink/renderer/modules/modules_export.h" #include "third_party/blink/renderer/platform/heap/persistent.h"
diff --git a/third_party/blink/renderer/modules/media_capabilities/BUILD.gn b/third_party/blink/renderer/modules/media_capabilities/BUILD.gn index d37c6e8e..bad5d87 100644 --- a/third_party/blink/renderer/modules/media_capabilities/BUILD.gn +++ b/third_party/blink/renderer/modules/media_capabilities/BUILD.gn
@@ -10,8 +10,6 @@ "media_capabilities.h", "media_capabilities_decoding_info_callbacks.cc", "media_capabilities_decoding_info_callbacks.h", - "media_capabilities_encoding_info_callbacks.cc", - "media_capabilities_encoding_info_callbacks.h", "navigator_media_capabilities.cc", "navigator_media_capabilities.h", ]
diff --git a/third_party/blink/renderer/modules/media_capabilities/media_capabilities.cc b/third_party/blink/renderer/modules/media_capabilities/media_capabilities.cc index 230dd86..9265e0582 100644 --- a/third_party/blink/renderer/modules/media_capabilities/media_capabilities.cc +++ b/third_party/blink/renderer/modules/media_capabilities/media_capabilities.cc
@@ -24,7 +24,6 @@ #include "third_party/blink/renderer/modules/encryptedmedia/encrypted_media_utils.h" #include "third_party/blink/renderer/modules/media_capabilities/media_capabilities_decoding_info.h" #include "third_party/blink/renderer/modules/media_capabilities/media_capabilities_decoding_info_callbacks.h" -#include "third_party/blink/renderer/modules/media_capabilities/media_capabilities_encoding_info_callbacks.h" #include "third_party/blink/renderer/modules/media_capabilities/media_capabilities_info.h" #include "third_party/blink/renderer/modules/media_capabilities/media_configuration.h" #include "third_party/blink/renderer/modules/media_capabilities/media_decoding_configuration.h" @@ -32,6 +31,7 @@ #include "third_party/blink/renderer/platform/bindings/script_state.h" #include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h" #include "third_party/blink/renderer/platform/network/parsed_content_type.h" +#include "third_party/blink/renderer/platform/wtf/functional.h" namespace blink { @@ -397,6 +397,22 @@ return media::IsSupportedAudioType({audio_codec}); } +void OnMediaCapabilitiesEncodingInfo( + ScriptPromiseResolver* resolver, + std::unique_ptr<WebMediaCapabilitiesInfo> result) { + if (!resolver->GetExecutionContext() || + resolver->GetExecutionContext()->IsContextDestroyed()) { + return; + } + + Persistent<MediaCapabilitiesInfo> info(MediaCapabilitiesInfo::Create()); + info->setSupported(result->supported); + info->setSmooth(result->smooth); + info->setPowerEfficient(result->power_efficient); + + resolver->Resolve(std::move(info)); +} + } // anonymous namespace MediaCapabilities::MediaCapabilities() = default; @@ -526,9 +542,9 @@ if (configuration->type() == "transmission") { if (auto* handler = Platform::Current()->TransmissionEncodingInfoHandler()) { - handler->EncodingInfo( - ToWebMediaConfiguration(configuration), - std::make_unique<MediaCapabilitiesEncodingInfoCallbacks>(resolver)); + handler->EncodingInfo(ToWebMediaConfiguration(configuration), + WTF::Bind(&OnMediaCapabilitiesEncodingInfo, + WrapPersistent(resolver))); return promise; } resolver->Reject(DOMException::Create( @@ -541,9 +557,9 @@ if (auto handler = Platform::Current()->CreateMediaRecorderHandler( ExecutionContext::From(script_state) ->GetTaskRunner(TaskType::kInternalMediaRealTime))) { - handler->EncodingInfo( - ToWebMediaConfiguration(configuration), - std::make_unique<MediaCapabilitiesEncodingInfoCallbacks>(resolver)); + handler->EncodingInfo(ToWebMediaConfiguration(configuration), + WTF::Bind(&OnMediaCapabilitiesEncodingInfo, + WrapPersistent(resolver))); return promise; } resolver->Reject(DOMException::Create(
diff --git a/third_party/blink/renderer/modules/media_capabilities/media_capabilities_encoding_info_callbacks.cc b/third_party/blink/renderer/modules/media_capabilities/media_capabilities_encoding_info_callbacks.cc deleted file mode 100644 index 044b9c8..0000000 --- a/third_party/blink/renderer/modules/media_capabilities/media_capabilities_encoding_info_callbacks.cc +++ /dev/null
@@ -1,37 +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. - -#include "third_party/blink/renderer/modules/media_capabilities/media_capabilities_encoding_info_callbacks.h" - -#include "third_party/blink/renderer/modules/media_capabilities/media_capabilities_info.h" - -namespace blink { - -MediaCapabilitiesEncodingInfoCallbacks::MediaCapabilitiesEncodingInfoCallbacks( - ScriptPromiseResolver* resolver) - : resolver_(resolver) {} - -MediaCapabilitiesEncodingInfoCallbacks:: - ~MediaCapabilitiesEncodingInfoCallbacks() = default; - -void MediaCapabilitiesEncodingInfoCallbacks::OnSuccess( - std::unique_ptr<WebMediaCapabilitiesInfo> result) { - if (!resolver_->GetExecutionContext() || - resolver_->GetExecutionContext()->IsContextDestroyed()) { - return; - } - - Persistent<MediaCapabilitiesInfo> info(MediaCapabilitiesInfo::Create()); - info->setSupported(result->supported); - info->setSmooth(result->smooth); - info->setPowerEfficient(result->power_efficient); - - resolver_->Resolve(std::move(info)); -} - -void MediaCapabilitiesEncodingInfoCallbacks::OnError() { - NOTREACHED(); -} - -} // namespace blink
diff --git a/third_party/blink/renderer/modules/media_capabilities/media_capabilities_encoding_info_callbacks.h b/third_party/blink/renderer/modules/media_capabilities/media_capabilities_encoding_info_callbacks.h deleted file mode 100644 index 6f847b7..0000000 --- a/third_party/blink/renderer/modules/media_capabilities/media_capabilities_encoding_info_callbacks.h +++ /dev/null
@@ -1,31 +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. - -#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CAPABILITIES_MEDIA_CAPABILITIES_ENCODING_INFO_CALLBACKS_H_ -#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CAPABILITIES_MEDIA_CAPABILITIES_ENCODING_INFO_CALLBACKS_H_ - -#include "third_party/blink/public/platform/modules/media_capabilities/web_media_capabilities_callbacks.h" -#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" -#include "third_party/blink/renderer/platform/heap/persistent.h" - -namespace blink { - -class MediaCapabilitiesEncodingInfoCallbacks - : public WebMediaCapabilitiesEncodingInfoCallbacks { - public: - explicit MediaCapabilitiesEncodingInfoCallbacks( - ScriptPromiseResolver* resolver); - - ~MediaCapabilitiesEncodingInfoCallbacks() override; - - void OnSuccess(std::unique_ptr<WebMediaCapabilitiesInfo>) override; - void OnError() override; - - private: - Persistent<ScriptPromiseResolver> resolver_; -}; - -} // namespace blink - -#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CAPABILITIES_MEDIA_CAPABILITIES_ENCODING_INFO_CALLBACKS_H_
diff --git a/third_party/blink/renderer/modules/mediasession/media_metadata_sanitizer.h b/third_party/blink/renderer/modules/mediasession/media_metadata_sanitizer.h index 16b53eb..afaf74f3 100644 --- a/third_party/blink/renderer/modules/mediasession/media_metadata_sanitizer.h +++ b/third_party/blink/renderer/modules/mediasession/media_metadata_sanitizer.h
@@ -5,7 +5,7 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASESSION_MEDIA_METADATA_SANITIZER_H_ #define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASESSION_MEDIA_METADATA_SANITIZER_H_ -#include "third_party/blink/public/platform/modules/mediasession/media_session.mojom-blink.h" +#include "third_party/blink/public/mojom/mediasession/media_session.mojom-blink.h" #include "third_party/blink/renderer/platform/wtf/allocator.h" namespace blink {
diff --git a/third_party/blink/renderer/modules/mediasession/media_session.h b/third_party/blink/renderer/modules/mediasession/media_session.h index 28972573..1f2a3b54 100644 --- a/third_party/blink/renderer/modules/mediasession/media_session.h +++ b/third_party/blink/renderer/modules/mediasession/media_session.h
@@ -7,7 +7,7 @@ #include <memory> #include "mojo/public/cpp/bindings/binding.h" -#include "third_party/blink/public/platform/modules/mediasession/media_session.mojom-blink.h" +#include "third_party/blink/public/mojom/mediasession/media_session.mojom-blink.h" #include "third_party/blink/renderer/core/execution_context/context_lifecycle_observer.h" #include "third_party/blink/renderer/modules/modules_export.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_track.cc b/third_party/blink/renderer/modules/mediastream/media_stream_track.cc index cc69226..313e3eb 100644 --- a/third_party/blink/renderer/modules/mediastream/media_stream_track.cc +++ b/third_party/blink/renderer/modules/mediastream/media_stream_track.cc
@@ -696,9 +696,10 @@ return !Ended() && HasEventListeners(event_type_names::kEnded); } -std::unique_ptr<AudioSourceProvider> MediaStreamTrack::CreateWebAudioSource() { +std::unique_ptr<AudioSourceProvider> MediaStreamTrack::CreateWebAudioSource( + int context_sample_rate) { return MediaStreamCenter::Instance().CreateWebAudioSourceFromMediaStreamTrack( - Component()); + Component(), context_sample_rate); } void MediaStreamTrack::RegisterMediaStream(MediaStream* media_stream) {
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_track.h b/third_party/blink/renderer/modules/mediastream/media_stream_track.h index ba90ba9..dbf1979 100644 --- a/third_party/blink/renderer/modules/mediastream/media_stream_track.h +++ b/third_party/blink/renderer/modules/mediastream/media_stream_track.h
@@ -111,7 +111,8 @@ // ContextLifecycleObserver void ContextDestroyed(ExecutionContext*) override; - std::unique_ptr<AudioSourceProvider> CreateWebAudioSource(); + std::unique_ptr<AudioSourceProvider> CreateWebAudioSource( + int context_sample_rate); void Trace(blink::Visitor*) override;
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_container.cc b/third_party/blink/renderer/modules/service_worker/service_worker_container.cc index 1bb7881..8424a91 100644 --- a/third_party/blink/renderer/modules/service_worker/service_worker_container.cc +++ b/third_party/blink/renderer/modules/service_worker/service_worker_container.cc
@@ -460,7 +460,7 @@ if (provider_) { provider_->GetRegistrationForReady( WTF::Bind(&ServiceWorkerContainer::OnGetRegistrationForReady, - WrapWeakPersistent(this))); + WrapPersistent(this))); } }
diff --git a/third_party/blink/renderer/modules/webaudio/media_stream_audio_source_node.cc b/third_party/blink/renderer/modules/webaudio/media_stream_audio_source_node.cc index 15dbcc9..b22626c 100644 --- a/third_party/blink/renderer/modules/webaudio/media_stream_audio_source_node.cc +++ b/third_party/blink/renderer/modules/webaudio/media_stream_audio_source_node.cc
@@ -146,7 +146,7 @@ // Use the first audio track in the media stream. MediaStreamTrack* audio_track = audio_tracks[0]; std::unique_ptr<AudioSourceProvider> provider = - audio_track->CreateWebAudioSource(); + audio_track->CreateWebAudioSource(context.sampleRate()); MediaStreamAudioSourceNode* node = MakeGarbageCollected<MediaStreamAudioSourceNode>(
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn index fbb363a..ed38474 100644 --- a/third_party/blink/renderer/platform/BUILD.gn +++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -696,7 +696,9 @@ "fonts/shaping/glyph_bounds_accumulator.h", "fonts/shaping/harfbuzz_face.cc", "fonts/shaping/harfbuzz_face.h", + "fonts/shaping/harfbuzz_font_cache.cc", "fonts/shaping/harfbuzz_font_cache.h", + "fonts/shaping/harfbuzz_font_data.h", "fonts/shaping/harfbuzz_shaper.cc", "fonts/shaping/harfbuzz_shaper.h", "fonts/shaping/run_segmenter.cc",
diff --git a/third_party/blink/renderer/platform/fonts/android/font_unique_name_lookup_android.cc b/third_party/blink/renderer/platform/fonts/android/font_unique_name_lookup_android.cc index be4552b..b7b6d66 100644 --- a/third_party/blink/renderer/platform/fonts/android/font_unique_name_lookup_android.cc +++ b/third_party/blink/renderer/platform/fonts/android/font_unique_name_lookup_android.cc
@@ -4,7 +4,7 @@ #include "third_party/blink/renderer/platform/fonts/android/font_unique_name_lookup_android.h" #include "mojo/public/mojom/base/shared_memory.mojom-blink.h" -#include "third_party/blink/public/platform/modules/font_unique_name_lookup/font_unique_name_lookup.mojom-blink.h" +#include "third_party/blink/public/mojom/font_unique_name_lookup/font_unique_name_lookup.mojom-blink.h" namespace blink {
diff --git a/third_party/blink/renderer/platform/fonts/font_global_context.cc b/third_party/blink/renderer/platform/fonts/font_global_context.cc index 20f6dd7..ff2fd24 100644 --- a/third_party/blink/renderer/platform/fonts/font_global_context.cc +++ b/third_party/blink/renderer/platform/fonts/font_global_context.cc
@@ -6,6 +6,7 @@ #include "third_party/blink/renderer/platform/fonts/font_cache.h" #include "third_party/blink/renderer/platform/fonts/font_unique_name_lookup.h" +#include "third_party/blink/renderer/platform/fonts/shaping/harfbuzz_font_cache.h" #include "third_party/blink/renderer/platform/wtf/thread_specific.h" namespace blink {
diff --git a/third_party/blink/renderer/platform/fonts/font_unique_name_lookup.cc b/third_party/blink/renderer/platform/fonts/font_unique_name_lookup.cc index ef45e99..1b5e433 100644 --- a/third_party/blink/renderer/platform/fonts/font_unique_name_lookup.cc +++ b/third_party/blink/renderer/platform/fonts/font_unique_name_lookup.cc
@@ -8,7 +8,7 @@ #include "third_party/blink/public/platform/platform.h" #if defined(OS_ANDROID) -#include "third_party/blink/public/platform/modules/font_unique_name_lookup/font_unique_name_lookup.mojom-blink.h" +#include "third_party/blink/public/mojom/font_unique_name_lookup/font_unique_name_lookup.mojom-blink.h" #include "third_party/blink/renderer/platform/fonts/android/font_unique_name_lookup_android.h" #elif defined(OS_LINUX) #include "third_party/blink/renderer/platform/fonts/linux/font_unique_name_lookup_linux.h"
diff --git a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_face.cc b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_face.cc index d42cbd0..046fd9e 100644 --- a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_face.cc +++ b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_face.cc
@@ -37,6 +37,7 @@ #include "third_party/blink/renderer/platform/fonts/font_global_context.h" #include "third_party/blink/renderer/platform/fonts/font_platform_data.h" #include "third_party/blink/renderer/platform/fonts/shaping/harfbuzz_font_cache.h" +#include "third_party/blink/renderer/platform/fonts/shaping/harfbuzz_font_data.h" #include "third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.h" #include "third_party/blink/renderer/platform/fonts/simple_font_data.h" #include "third_party/blink/renderer/platform/fonts/skia/skia_text_metrics.h"
diff --git a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_font_cache.cc b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_font_cache.cc new file mode 100644 index 0000000..02690dd --- /dev/null +++ b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_font_cache.cc
@@ -0,0 +1,20 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/platform/fonts/shaping/harfbuzz_font_cache.h" +#include "third_party/blink/renderer/platform/fonts/shaping/harfbuzz_font_data.h" + +namespace blink { + +HbFontCacheEntry::HbFontCacheEntry(hb_font_t* font) + : hb_font_(HbFontUniquePtr(font)), + hb_font_data_(std::make_unique<HarfBuzzFontData>()) {} + +HbFontCacheEntry::~HbFontCacheEntry() = default; + +scoped_refptr<HbFontCacheEntry> HbFontCacheEntry::Create(hb_font_t* hb_font) { + DCHECK(hb_font); + return base::AdoptRef(new HbFontCacheEntry(hb_font)); +} +} // namespace blink
diff --git a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_font_cache.h b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_font_cache.h index 4ecf1f2..d3ad8a1 100644 --- a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_font_cache.h +++ b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_font_cache.h
@@ -8,16 +8,15 @@ #include <memory> #include "third_party/blink/renderer/platform/fonts/font_metrics.h" -#include "third_party/blink/renderer/platform/fonts/opentype/open_type_vertical_data.h" -#include "third_party/blink/renderer/platform/fonts/shaping/harfbuzz_face.h" #include "third_party/blink/renderer/platform/fonts/unicode_range_set.h" -#include "third_party/blink/renderer/platform/wtf/assertions.h" struct hb_font_t; struct hb_face_t; namespace blink { +struct HarfBuzzFontData; + struct HbFontDeleter { void operator()(hb_font_t* font); }; @@ -30,101 +29,6 @@ using HbFaceUniquePtr = std::unique_ptr<hb_face_t, HbFaceDeleter>; -const unsigned kInvalidFallbackMetricsValue = static_cast<unsigned>(-1); - -// struct to carry user-pointer data for hb_font_t callback -// functions/operations, that require information related to a font scaled to a -// particular size. -struct HarfBuzzFontData { - USING_FAST_MALLOC(HarfBuzzFontData); - - public: - HarfBuzzFontData() - : font_(), - space_in_gpos_(SpaceGlyphInOpenTypeTables::Unknown), - space_in_gsub_(SpaceGlyphInOpenTypeTables::Unknown), - vertical_data_(nullptr), - range_set_(nullptr) {} - - // The vertical origin and vertical advance functions in HarfBuzzFace require - // the ascent and height metrics as fallback in case no specific vertical - // layout information is found from the font. - void UpdateFallbackMetricsAndScale( - const FontPlatformData& platform_data, - HarfBuzzFace::VerticalLayoutCallbacks vertical_layout) { - float ascent = 0; - float descent = 0; - unsigned dummy_ascent_inflation = 0; - unsigned dummy_descent_inflation = 0; - - font_ = SkFont(); - platform_data.SetupSkFont(&font_); - - if (UNLIKELY(vertical_layout == HarfBuzzFace::PrepareForVerticalLayout)) { - FontMetrics::AscentDescentWithHacks( - ascent, descent, dummy_ascent_inflation, dummy_descent_inflation, - platform_data, font_); - ascent_fallback_ = ascent; - // Simulate the rounding that FontMetrics does so far for returning the - // integer Height() - height_fallback_ = lroundf(ascent) + lroundf(descent); - - int units_per_em = - platform_data.GetHarfBuzzFace()->UnitsPerEmFromHeadTable(); - if (!units_per_em) { - DLOG(ERROR) - << "Units per EM is 0 for font used in vertical writing mode."; - } - size_per_unit_ = platform_data.size() / (units_per_em ? units_per_em : 1); - } else { - ascent_fallback_ = kInvalidFallbackMetricsValue; - height_fallback_ = kInvalidFallbackMetricsValue; - size_per_unit_ = kInvalidFallbackMetricsValue; - } - } - - float SizePerUnit(const SkTypeface& typeface) const { - if (size_per_unit_ != kInvalidFallbackMetricsValue) - return size_per_unit_; - int units_per_em = typeface.getUnitsPerEm(); - size_per_unit_ = font_.getSize() / units_per_em; - return size_per_unit_; - } - - scoped_refptr<OpenTypeVerticalData> VerticalData() { - if (!vertical_data_) { - DCHECK_NE(ascent_fallback_, kInvalidFallbackMetricsValue); - DCHECK_NE(height_fallback_, kInvalidFallbackMetricsValue); - DCHECK_NE(size_per_unit_, kInvalidFallbackMetricsValue); - - vertical_data_ = - OpenTypeVerticalData::CreateUnscaled(font_.refTypeface()); - } - vertical_data_->SetScaleAndFallbackMetrics(size_per_unit_, ascent_fallback_, - height_fallback_); - return vertical_data_; - } - - SkFont font_; - - // Capture these scaled fallback metrics from FontPlatformData so that a - // OpenTypeVerticalData object can be constructed from them when needed. - mutable float size_per_unit_; - float ascent_fallback_; - float height_fallback_; - - enum class SpaceGlyphInOpenTypeTables { Unknown, Present, NotPresent }; - - SpaceGlyphInOpenTypeTables space_in_gpos_; - SpaceGlyphInOpenTypeTables space_in_gsub_; - - scoped_refptr<OpenTypeVerticalData> vertical_data_; - scoped_refptr<UnicodeRangeSet> range_set_; - - private: - DISALLOW_COPY_AND_ASSIGN(HarfBuzzFontData); -}; - // Though we have FontCache class, which provides the cache mechanism for // WebKit's font objects, we also need additional caching layer for HarfBuzz to // reduce the number of hb_font_t objects created. Without it, we would create @@ -134,18 +38,15 @@ // FontPlatformData object independent of size, then consider using this here. class HbFontCacheEntry : public RefCounted<HbFontCacheEntry> { public: - static scoped_refptr<HbFontCacheEntry> Create(hb_font_t* hb_font) { - DCHECK(hb_font); - return base::AdoptRef(new HbFontCacheEntry(hb_font)); - } + static scoped_refptr<HbFontCacheEntry> Create(hb_font_t* hb_font); hb_font_t* HbFont() { return hb_font_.get(); } HarfBuzzFontData* HbFontData() { return hb_font_data_.get(); } + ~HbFontCacheEntry(); + private: - explicit HbFontCacheEntry(hb_font_t* font) - : hb_font_(HbFontUniquePtr(font)), - hb_font_data_(std::make_unique<HarfBuzzFontData>()) {} + explicit HbFontCacheEntry(hb_font_t* font); HbFontUniquePtr hb_font_; std::unique_ptr<HarfBuzzFontData> hb_font_data_;
diff --git a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_font_data.h b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_font_data.h new file mode 100644 index 0000000..b1e5bb0 --- /dev/null +++ b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_font_data.h
@@ -0,0 +1,115 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_SHAPING_HARFBUZZ_FONT_DATA_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_SHAPING_HARFBUZZ_FONT_DATA_H_ + +#include "third_party/blink/renderer/platform/fonts/font_platform_data.h" +#include "third_party/blink/renderer/platform/fonts/opentype/open_type_vertical_data.h" +#include "third_party/blink/renderer/platform/fonts/shaping/harfbuzz_face.h" +#include "third_party/blink/renderer/platform/wtf/assertions.h" +#include "third_party/skia/include/core/SkFont.h" + +struct hb_font_t; + +namespace blink { + +const unsigned kInvalidFallbackMetricsValue = static_cast<unsigned>(-1); + +// The HarfBuzzFontData struct carries user-pointer data for hb_font_t callback +// functions/operations. It contains metrics and OpenType layout information +// related to a font scaled to a particular size. +struct HarfBuzzFontData { + USING_FAST_MALLOC(HarfBuzzFontData); + + public: + HarfBuzzFontData() + : font_(), + space_in_gpos_(SpaceGlyphInOpenTypeTables::Unknown), + space_in_gsub_(SpaceGlyphInOpenTypeTables::Unknown), + vertical_data_(nullptr), + range_set_(nullptr) {} + + // The vertical origin and vertical advance functions in HarfBuzzFace require + // the ascent and height metrics as fallback in case no specific vertical + // layout information is found from the font. + void UpdateFallbackMetricsAndScale( + const FontPlatformData& platform_data, + HarfBuzzFace::VerticalLayoutCallbacks vertical_layout) { + float ascent = 0; + float descent = 0; + unsigned dummy_ascent_inflation = 0; + unsigned dummy_descent_inflation = 0; + + font_ = SkFont(); + platform_data.SetupSkFont(&font_); + + if (UNLIKELY(vertical_layout == HarfBuzzFace::PrepareForVerticalLayout)) { + FontMetrics::AscentDescentWithHacks( + ascent, descent, dummy_ascent_inflation, dummy_descent_inflation, + platform_data, font_); + ascent_fallback_ = ascent; + // Simulate the rounding that FontMetrics does so far for returning the + // integer Height() + height_fallback_ = lroundf(ascent) + lroundf(descent); + + int units_per_em = + platform_data.GetHarfBuzzFace()->UnitsPerEmFromHeadTable(); + if (!units_per_em) { + DLOG(ERROR) + << "Units per EM is 0 for font used in vertical writing mode."; + } + size_per_unit_ = platform_data.size() / (units_per_em ? units_per_em : 1); + } else { + ascent_fallback_ = kInvalidFallbackMetricsValue; + height_fallback_ = kInvalidFallbackMetricsValue; + size_per_unit_ = kInvalidFallbackMetricsValue; + } + } + + float SizePerUnit(const SkTypeface& typeface) const { + if (size_per_unit_ != kInvalidFallbackMetricsValue) + return size_per_unit_; + int units_per_em = typeface.getUnitsPerEm(); + size_per_unit_ = font_.getSize() / units_per_em; + return size_per_unit_; + } + + scoped_refptr<OpenTypeVerticalData> VerticalData() { + if (!vertical_data_) { + DCHECK_NE(ascent_fallback_, kInvalidFallbackMetricsValue); + DCHECK_NE(height_fallback_, kInvalidFallbackMetricsValue); + DCHECK_NE(size_per_unit_, kInvalidFallbackMetricsValue); + + vertical_data_ = + OpenTypeVerticalData::CreateUnscaled(font_.refTypeface()); + } + vertical_data_->SetScaleAndFallbackMetrics(size_per_unit_, ascent_fallback_, + height_fallback_); + return vertical_data_; + } + + SkFont font_; + + // Capture these scaled fallback metrics from FontPlatformData so that a + // OpenTypeVerticalData object can be constructed from them when needed. + mutable float size_per_unit_; + float ascent_fallback_; + float height_fallback_; + + enum class SpaceGlyphInOpenTypeTables { Unknown, Present, NotPresent }; + + SpaceGlyphInOpenTypeTables space_in_gpos_; + SpaceGlyphInOpenTypeTables space_in_gsub_; + + scoped_refptr<OpenTypeVerticalData> vertical_data_; + scoped_refptr<UnicodeRangeSet> range_set_; + + private: + DISALLOW_COPY_AND_ASSIGN(HarfBuzzFontData); +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_SHAPING_HARFBUZZ_FONT_DATA_H_
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc index 5fefc23..40fcb7d0 100644 --- a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc +++ b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
@@ -1048,6 +1048,8 @@ Vector<bool> pending_render_surfaces; pending_render_surfaces.resize(effect_tree.size()); for (const auto& layer : layers) { + if (!layer->DrawsContent()) + continue; bool descendant_may_have_backdrop_filter = false; auto* effect = effect_tree.Node(layer->effect_tree_index()); bool may_have_backdrop_filter =
diff --git a/third_party/blink/renderer/platform/mediastream/media_stream_center.cc b/third_party/blink/renderer/platform/mediastream/media_stream_center.cc index b357fe4a..94546a10 100644 --- a/third_party/blink/renderer/platform/mediastream/media_stream_center.cc +++ b/third_party/blink/renderer/platform/mediastream/media_stream_center.cc
@@ -97,11 +97,13 @@ std::unique_ptr<AudioSourceProvider> MediaStreamCenter::CreateWebAudioSourceFromMediaStreamTrack( - MediaStreamComponent* track) { + MediaStreamComponent* track, + int context_sample_rate) { DCHECK(track); if (private_) { - return std::make_unique<MediaStreamWebAudioSource>(base::WrapUnique( - private_->CreateWebAudioSourceFromMediaStreamTrack(track))); + return std::make_unique<MediaStreamWebAudioSource>( + base::WrapUnique(private_->CreateWebAudioSourceFromMediaStreamTrack( + track, context_sample_rate))); } return nullptr;
diff --git a/third_party/blink/renderer/platform/mediastream/media_stream_center.h b/third_party/blink/renderer/platform/mediastream/media_stream_center.h index 48fb098e..1b4ea83 100644 --- a/third_party/blink/renderer/platform/mediastream/media_stream_center.h +++ b/third_party/blink/renderer/platform/mediastream/media_stream_center.h
@@ -63,7 +63,8 @@ void DidSetMediaStreamTrackEnabled(MediaStreamComponent*); void DidSetContentHint(MediaStreamComponent*); std::unique_ptr<AudioSourceProvider> CreateWebAudioSourceFromMediaStreamTrack( - MediaStreamComponent*); + MediaStreamComponent*, + int context_sample_rate); void DidCreateMediaStreamAndTracks(MediaStreamDescriptor*);
diff --git a/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG index 71425315..307bb5e 100644 --- a/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG +++ b/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG
@@ -118,7 +118,6 @@ crbug.com/591099 external/wpt/css/css-animations/Element-getAnimations-dynamic-changes.tentative.html [ Failure ] crbug.com/591099 external/wpt/css/css-animations/Element-getAnimations.tentative.html [ Pass ] crbug.com/591099 external/wpt/css/css-contain/contain-size-grid-002.html [ Failure ] -crbug.com/591099 external/wpt/css/css-contain/contain-size-multicol-001.html [ Failure ] crbug.com/591099 external/wpt/css/css-contain/contain-style-counters-004.html [ Failure ] crbug.com/714962 external/wpt/css/css-fonts/font-features-across-space-1.html [ Pass ] crbug.com/714962 external/wpt/css/css-fonts/font-features-across-space-3.html [ Pass ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index 4f08349..2aaa945a 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -545,7 +545,6 @@ crbug.com/882367 external/wpt/css/css-contain/contain-paint-clip-015.html [ Failure ] crbug.com/882367 external/wpt/css/css-contain/contain-paint-clip-016.html [ Failure ] crbug.com/855261 external/wpt/css/css-contain/contain-size-grid-002.html [ Failure ] -crbug.com/863454 external/wpt/css/css-contain/contain-size-multicol-001.html [ Failure ] crbug.com/869296 external/wpt/css/css-contain/contain-style-counters-004.html [ Failure ] crbug.com/882383 external/wpt/css/css-contain/counter-scoping-001.html [ Failure ] crbug.com/882383 external/wpt/css/css-contain/counter-scoping-002.html [ Failure ] @@ -2980,6 +2979,8 @@ crbug.com/939181 virtual/not-site-per-process/external/wpt/html/browsers/origin/cross-origin-objects/cross-origin-objects.html [ Failure Timeout ] # ====== New tests from wpt-importer added here ====== +crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-block-002.html [ Failure ] +crbug.com/626703 external/wpt/css/css-lists/list-item-definition.html [ Failure ] crbug.com/626703 external/wpt/css/css-contain/contain-content-011.html [ Failure ] crbug.com/626703 external/wpt/css/css-contain/contain-strict-011.html [ Failure ] crbug.com/626703 external/wpt/html/semantics/forms/the-textarea-element/multiline-placeholder-cr.html [ Failure ] @@ -3235,7 +3236,6 @@ crbug.com/626703 external/wpt/css/css-text/writing-system/writing-system-line-break-001.html [ Failure ] crbug.com/626703 external/wpt/css/css-text/writing-system/writing-system-line-break-002.html [ Failure ] crbug.com/626703 external/wpt/css/css-text/writing-system/writing-system-text-transform-001.html [ Failure ] -crbug.com/903383 external/wpt/css/filter-effects/filter-cb-abspos-inline-003.html [ Failure ] crbug.com/903383 external/wpt/css/filter-effects/css-filters-animation-combined-001.html [ Failure ] crbug.com/903383 external/wpt/css/filter-effects/css-filters-animation-blur.html [ Failure ] crbug.com/903383 external/wpt/css/filter-effects/filters-test-brightness-003.html [ Failure ] @@ -3660,8 +3660,6 @@ crbug.com/626703 external/wpt/css/cssom-view/scroll-behavior-smooth.html [ Timeout ] crbug.com/626703 external/wpt/websockets/Create-Secure-extensions-empty.any.html [ Timeout ] crbug.com/626703 external/wpt/websockets/Create-Secure-extensions-empty.any.worker.html [ Timeout ] -crbug.com/626703 external/wpt/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-integrity-classic.sub.html [ Skip ] -crbug.com/626703 external/wpt/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-integrity-module.sub.html [ Skip ] crbug.com/626703 virtual/streaming-preload/external/wpt/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-integrity-classic.sub.html [ Skip ] crbug.com/626703 virtual/streaming-preload/external/wpt/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-integrity-module.sub.html [ Skip ] crbug.com/626703 external/wpt/html/browsers/history/joint-session-history/joint-session-history-remove-iframe.html [ Timeout ]
diff --git a/third_party/blink/web_tests/compositing/lots-of-img-layers-with-opacity-expected.png b/third_party/blink/web_tests/compositing/lots-of-img-layers-with-opacity-expected.png new file mode 100644 index 0000000..201b2cc --- /dev/null +++ b/third_party/blink/web_tests/compositing/lots-of-img-layers-with-opacity-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json index b208671c..fe1da414 100644 --- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json +++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json
@@ -51227,6 +51227,18 @@ {} ] ], + "css/css-lists/list-item-definition.html": [ + [ + "/css/css-lists/list-item-definition.html", + [ + [ + "/css/css-lists/list-item-definition-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-lists/list-marker-with-lineheight-and-overflow-hidden-001.html": [ [ "/css/css-lists/list-marker-with-lineheight-and-overflow-hidden-001.html", @@ -97897,6 +97909,42 @@ {} ] ], + "css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-block-002.html": [ + [ + "/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-block-002.html", + [ + [ + "/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-block-002-ref.html", + "==" + ] + ], + {} + ] + ], + "css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-block-003.html": [ + [ + "/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-block-003.html", + [ + [ + "/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-block-003-ref.html", + "==" + ] + ], + {} + ] + ], + "css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-block-004.html": [ + [ + "/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-block-004.html", + [ + [ + "/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-block-004-ref.html", + "==" + ] + ], + {} + ] + ], "css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-button-001.html": [ [ "/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-button-001.html", @@ -97969,6 +98017,42 @@ {} ] ], + "css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-inline-block-002.html": [ + [ + "/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-inline-block-002.html", + [ + [ + "/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-inline-block-002-ref.html", + "==" + ] + ], + {} + ] + ], + "css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-inline-block-003.html": [ + [ + "/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-inline-block-003.html", + [ + [ + "/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-inline-block-003-ref.html", + "==" + ] + ], + {} + ] + ], + "css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-inline-block-004.html": [ + [ + "/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-inline-block-004.html", + [ + [ + "/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-inline-block-004-ref.html", + "==" + ] + ], + {} + ] + ], "css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-inline-flex-001.html": [ [ "/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-inline-flex-001.html", @@ -99541,6 +99625,18 @@ {} ] ], + "css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-definite-sizes-005.html": [ + [ + "/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-definite-sizes-005.html", + [ + [ + "/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-definite-sizes-005-ref.html", + "==" + ] + ], + {} + ] + ], "css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-dyn-resize-001.html": [ [ "/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-dyn-resize-001.html", @@ -141575,6 +141671,11 @@ {} ] ], + "css/css-lists/list-item-definition-ref.html": [ + [ + {} + ] + ], "css/css-lists/list-marker-with-lineheight-and-overflow-hidden-001-ref.html": [ [ {} @@ -157195,6 +157296,21 @@ {} ] ], + "css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-block-002-ref.html": [ + [ + {} + ] + ], + "css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-block-003-ref.html": [ + [ + {} + ] + ], + "css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-block-004-ref.html": [ + [ + {} + ] + ], "css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-button-001-ref.html": [ [ {} @@ -157225,6 +157341,21 @@ {} ] ], + "css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-inline-block-002-ref.html": [ + [ + {} + ] + ], + "css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-inline-block-003-ref.html": [ + [ + {} + ] + ], + "css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-inline-block-004-ref.html": [ + [ + {} + ] + ], "css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-inline-flex-001-ref.html": [ [ {} @@ -157775,6 +157906,11 @@ {} ] ], + "css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-definite-sizes-005-ref.html": [ + [ + {} + ] + ], "css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-dyn-resize-001-ref.html": [ [ {} @@ -223537,6 +223673,12 @@ {} ] ], + "css/css-position/position-absolute-crash-chrome-004.html": [ + [ + "/css/css-position/position-absolute-crash-chrome-004.html", + {} + ] + ], "css/css-position/position-absolute-dynamic-containing-block.html": [ [ "/css/css-position/position-absolute-dynamic-containing-block.html", @@ -247272,7 +247414,9 @@ "fetch/sec-metadata/iframe.tentative.https.sub.html": [ [ "/fetch/sec-metadata/iframe.tentative.https.sub.html", - {} + { + "testdriver": true + } ] ], "fetch/sec-metadata/iframe.tentative.sub.html": [ @@ -257309,18 +257453,6 @@ {} ] ], - "html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-integrity-classic.sub.html": [ - [ - "/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-integrity-classic.sub.html", - {} - ] - ], - "html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-integrity-module.sub.html": [ - [ - "/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-integrity-module.sub.html", - {} - ] - ], "html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-module.html": [ [ "/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-module.html", @@ -365166,6 +365298,14 @@ "df54e8fb0df8146f896c2abd136d63d930d92d1c", "testharness" ], + "css/css-lists/list-item-definition-ref.html": [ + "72a4c90f4ada6a889fa71a27aea20146ea07bc9b", + "support" + ], + "css/css-lists/list-item-definition.html": [ + "edae4b96bd98876170145cf9bc9c834d188b5640", + "reftest" + ], "css/css-lists/list-marker-with-lineheight-and-overflow-hidden-001-ref.html": [ "ae6486147e28502db80f6b887b1a6b16c30184f2", "support" @@ -369022,6 +369162,10 @@ "c443e836e57a361c7de9bc5f9a6debe7ff832fe0", "testharness" ], + "css/css-position/position-absolute-crash-chrome-004.html": [ + "cc6de63e0011a3588592bd7bf27d5230ea8d2a48", + "testharness" + ], "css/css-position/position-absolute-dynamic-containing-block.html": [ "3968f685849663574ca213fcb90dc5fb3eaffaa3", "testharness" @@ -402442,6 +402586,30 @@ "0ed82ff8fc5b8adaeef2bfd973cd79973b8f4fa6", "reftest" ], + "css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-block-002-ref.html": [ + "1f41028faac4dfb444745567e4ac9087fefbea37", + "support" + ], + "css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-block-002.html": [ + "4dc92103eabc6231b4d8260cbb35ac7337b2362b", + "reftest" + ], + "css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-block-003-ref.html": [ + "2f6ff8322d13942bfff3c54b6a3f132a05cdfb5a", + "support" + ], + "css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-block-003.html": [ + "cf7e2310169c57658ebc688db3a927152868d97a", + "reftest" + ], + "css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-block-004-ref.html": [ + "c8647b19dd6c5b64a0aab86ff2f394f93ac7ff3d", + "support" + ], + "css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-block-004.html": [ + "b6cca54a8c65ca798b836aa7b6ea92627482dc76", + "reftest" + ], "css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-button-001-ref.html": [ "efadf9b5df49ca45f829208c03dc0feb875c74f1", "support" @@ -402490,6 +402658,30 @@ "41458550272f896d47e15210c82f4c22d386d9e0", "reftest" ], + "css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-inline-block-002-ref.html": [ + "3d0f38f7c07c4b73cc41418c87e5bc902e7ed862", + "support" + ], + "css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-inline-block-002.html": [ + "d3a69e5f357bef37bcd2dbb3a0877ea4d8bdc977", + "reftest" + ], + "css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-inline-block-003-ref.html": [ + "6079764591ff8806c88bc2644c4248e12ea0ca0a", + "support" + ], + "css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-inline-block-003.html": [ + "7ea22635d35b4471362545d0abcf7f417511323d", + "reftest" + ], + "css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-inline-block-004-ref.html": [ + "e7f03ff2d31e30b837b654ba41de220daef1c753", + "support" + ], + "css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-inline-block-004.html": [ + "1de39348b718cd90530be9a0089b4075f3190a8f", + "reftest" + ], "css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-inline-flex-001-ref.html": [ "93a263b5b2ffc131bdfe4989c3d90c312cadf6e4", "support" @@ -403454,6 +403646,14 @@ "cf54aabe9936b3963e7343d566d957633fc26c69", "reftest" ], + "css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-definite-sizes-005-ref.html": [ + "fca146671cfb80cd3ae0264a8466be0b9823b3ae", + "support" + ], + "css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-definite-sizes-005.html": [ + "76beb2a41db70d2f00de159d1285fbc5310a3d40", + "reftest" + ], "css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-dyn-resize-001-ref.html": [ "5e5561cadf2ddbd6dfd2c7b4819f146f61be006b", "support" @@ -414463,19 +414663,19 @@ "support" ], "fetch/sec-metadata/embed.tentative.https.sub.html": [ - "b97de9ef2fd4c0c41a5671ad7cd20c5814ab5223", + "c46765b37c6325260882751e9e592c2b55d8b128", "testharness" ], "fetch/sec-metadata/fetch.tentative.https.sub.html": [ - "dc4b977ac6ec6544215bcf2a41007a6adde2d36e", + "bffb4275df8e99c9d06d4fa4ef518e3b1efba747", "testharness" ], "fetch/sec-metadata/font.tentative.https.sub.html": [ - "9792f2dce9427c3e42f595adb4c67113a6bb29d7", + "60163ee714686fc1c3f5f9b7011ce03cf3028e6b", "testharness" ], "fetch/sec-metadata/iframe.tentative.https.sub.html": [ - "056d8fdba945ddc9e3daed1f6d4f915b084a3da9", + "461d9f28fa1e8987e3b05c48cb10fa6f4f8bf326", "testharness" ], "fetch/sec-metadata/iframe.tentative.sub.html": [ @@ -414483,7 +414683,7 @@ "testharness" ], "fetch/sec-metadata/img.tentative.https.sub.html": [ - "b1216db84285bc9ddd979f3ca27240803ae975f7", + "b9fc1af2f3bfcc09b7e9989fd755f3c82d6f24d9", "testharness" ], "fetch/sec-metadata/navigation.https.sub.html": [ @@ -414491,11 +414691,11 @@ "testharness" ], "fetch/sec-metadata/object.tentative.https.sub.html": [ - "474962918b03075b0fa97d199a339b5f504d8c20", + "b60ae206c78b3dd8e934dde7a7408fe4a7465932", "testharness" ], "fetch/sec-metadata/redirect/cross-site-redirect.tentative.https.sub.html": [ - "1634a29f3791490aa782435a294442d3a925ebda", + "06b58744fb5a26f16f5ed8fc923f1c91989e2eb8", "testharness" ], "fetch/sec-metadata/redirect/multiple-redirect-cross-site.tentative.https.sub-expected.txt": [ @@ -414503,7 +414703,7 @@ "support" ], "fetch/sec-metadata/redirect/multiple-redirect-cross-site.tentative.https.sub.html": [ - "7647a5b1c89a99ab4c8227a6690c457915e07a62", + "e173bb053fedd46f346a0e89990f44cf5cbc1856", "testharness" ], "fetch/sec-metadata/redirect/multiple-redirect-same-site.tentative.https.sub-expected.txt": [ @@ -414511,7 +414711,7 @@ "support" ], "fetch/sec-metadata/redirect/multiple-redirect-same-site.tentative.https.sub.html": [ - "e83d6fd97e844f84dc5fb6c39a3acc99e5e9f087", + "d19a1896ad77e69923e219292d9ae4c1ef35e70e", "testharness" ], "fetch/sec-metadata/redirect/same-origin-redirect.tentative.https.sub-expected.txt": [ @@ -414519,7 +414719,7 @@ "support" ], "fetch/sec-metadata/redirect/same-origin-redirect.tentative.https.sub.html": [ - "2033eab5979a619f918443d98788ae3caaefecb5", + "0b4fdfeec58b6f353000cf290f345b63c4c9cba9", "testharness" ], "fetch/sec-metadata/redirect/same-site-redirect.tentative.https.sub-expected.txt": [ @@ -414527,11 +414727,11 @@ "support" ], "fetch/sec-metadata/redirect/same-site-redirect.tentative.https.sub.html": [ - "c5b6830abed5f197f2640fa1ddb18be9f79480fd", + "70c0afef22883469a54a874a955a91c89c4336d7", "testharness" ], "fetch/sec-metadata/report.tentative.https.sub.html": [ - "405964e08923ae7db3becc5178f99994b8614230", + "eb6c76b57c75a70e183ebbc8a9e11e42275ff82e", "testharness" ], "fetch/sec-metadata/report.tentative.https.sub.html.sub.headers": [ @@ -414571,7 +414771,7 @@ "support" ], "fetch/sec-metadata/script.tentative.https.sub.html": [ - "a35e753c7898cc89427fa8dc22ce5fd55325ea8e", + "b2874a37da1ebb578d76702bae66abf6fa501b8e", "testharness" ], "fetch/sec-metadata/script.tentative.sub.html": [ @@ -414579,31 +414779,31 @@ "testharness" ], "fetch/sec-metadata/serviceworker.tentative.https.sub.html": [ - "590a6c33475d26e54ef31e7a766f596d4b6d5215", + "ee436d9265ff85c3e307c7c6f565e55d7cc84961", "testharness" ], "fetch/sec-metadata/sharedworker.tentative.https.sub.html": [ - "a1c558ad35dfbdb7d2f35535ba26148f31e3f2c6", + "ddd4cc9914eb28a3b85d13366dd84ca722d34d52", "testharness" ], "fetch/sec-metadata/style.tentative.https.sub.html": [ - "46f64f49bde0ce6c642a517aacaf5af8c3074edc", + "19cc16d8017cc2a86c72098fcfdd161ea4080bde", "testharness" ], "fetch/sec-metadata/track.tentative.https.sub.html": [ - "817e4845edb215cd1fdf8183e6d306a4fe4172c4", + "fe525caf15523310e4f67dc5200cc7877d5f3456", "testharness" ], "fetch/sec-metadata/trailing-dot.tentative.https.sub.html": [ - "85f9c73c6ae22fb34a8bd76b624f286367ba0265", + "ff0e842d5118cba40b73f09e29cf98be0bcabb12", "testharness" ], "fetch/sec-metadata/window-open.tentative.https.sub.html": [ - "ef2bc81824ea5f90551da75daf6e10f41ef2cdcd", + "0be9f2ce577d5cdd590e0326ed650455d87f1ee4", "testharness" ], "fetch/sec-metadata/worker.tentative.https.sub.html": [ - "dc21d0324f442a8aa801dbddb04e0b2fe93464d0", + "940e25b2a51a41610980601e0c97be5e4614c9b0", "testharness" ], "fetch/sec-metadata/xslt.tentative.https.sub-expected.txt": [ @@ -414611,7 +414811,7 @@ "support" ], "fetch/sec-metadata/xslt.tentative.https.sub.html": [ - "eea2329900e000c43cb0b347c011d6d4adb8bd46", + "0d429266288e8a77bcdc5076d3f248bf0ef509b5", "testharness" ], "fetch/security/dangling-markup-mitigation-data-url.tentative.sub.html": [ @@ -431678,14 +431878,6 @@ "34ea00abc83ce6f8c83c9b31edd77a69d356b214", "testharness" ], - "html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-integrity-classic.sub.html": [ - "80a298913a09c2cccbdfc917975ddc6e801cf411", - "testharness" - ], - "html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-integrity-module.sub.html": [ - "db3d3b1e15a8fa7ab82947c6fd96bb2d1b5fb2dc", - "testharness" - ], "html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-module.html": [ "b85d446d8dae01be803e190b593aac6ed921ca08", "testharness" @@ -436723,7 +436915,7 @@ "support" ], "interfaces/performance-timeline.idl": [ - "7766bfd7b09e56e4822643b5fdf56697b20ad3e3", + "51752b139589e64088364109d8c5e117c7811e95", "support" ], "interfaces/permissions.idl": [ @@ -449935,7 +450127,7 @@ "testharness" ], "performance-timeline/idlharness.any-expected.txt": [ - "7d03cc1c92e43122223b32d6e059dbbef3ad7df8", + "32878d3cf1b0ddece602c8c53ea21166f1ec3d41", "support" ], "performance-timeline/idlharness.any.js": [ @@ -449943,15 +450135,15 @@ "testharness" ], "performance-timeline/idlharness.any.serviceworker-expected.txt": [ - "7d03cc1c92e43122223b32d6e059dbbef3ad7df8", + "32878d3cf1b0ddece602c8c53ea21166f1ec3d41", "support" ], "performance-timeline/idlharness.any.sharedworker-expected.txt": [ - "7d03cc1c92e43122223b32d6e059dbbef3ad7df8", + "32878d3cf1b0ddece602c8c53ea21166f1ec3d41", "support" ], "performance-timeline/idlharness.any.worker-expected.txt": [ - "7d03cc1c92e43122223b32d6e059dbbef3ad7df8", + "32878d3cf1b0ddece602c8c53ea21166f1ec3d41", "support" ], "performance-timeline/performanceentry-tojson.any.js": [ @@ -463231,7 +463423,7 @@ "testharness" ], "service-workers/service-worker/fetch-request-xhr.https-expected.txt": [ - "3de90db5c4ece4734df673d0a066fa7772eb4a33", + "76e08357b6e2b1edce325a9ebefde287c962681b", "support" ], "service-workers/service-worker/fetch-request-xhr.https.html": [
diff --git a/third_party/blink/web_tests/external/wpt/css/css-contain/contain-size-multicol-001.html b/third_party/blink/web_tests/external/wpt/css/css-contain/contain-size-multicol-001.html index 5c0dba9b7..81465c0 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-contain/contain-size-multicol-001.html +++ b/third_party/blink/web_tests/external/wpt/css/css-contain/contain-size-multicol-001.html
@@ -18,6 +18,7 @@ #test { background: green; + contain: size; columns: 2 40px; column-gap: 20px; min-height: 100px;
diff --git a/third_party/blink/web_tests/external/wpt/css/css-lists/list-item-definition-ref.html b/third_party/blink/web_tests/external/wpt/css/css-lists/list-item-definition-ref.html new file mode 100644 index 0000000..72a4c90 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-lists/list-item-definition-ref.html
@@ -0,0 +1,11 @@ +<!doctype html> +<title>CSS Test Reference</title> +<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez"> +<link rel="author" href="https://mozilla.org" title="Mozilla"> +<ol> + <svg style="display: list-item"></svg> + <img style="display: list-item"> + <img style="display: list-item" alt="Foo"> + <li value="4">Foo + <li>Bar +</ol>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-lists/list-item-definition.html b/third_party/blink/web_tests/external/wpt/css/css-lists/list-item-definition.html new file mode 100644 index 0000000..edae4b9 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-lists/list-item-definition.html
@@ -0,0 +1,15 @@ +<!doctype html> +<title>The definition of what a list-item is only depends on the display value, and doesn't account for pseudo-elements</title> +<link rel="help" href="https://drafts.csswg.org/css-lists/#list-item"> +<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1539171"> +<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez"> +<link rel="author" href="https://mozilla.org" title="Mozilla"> +<link rel="match" href="list-item-definition-ref.html"> +<!-- TODO: Test pseudo-elements, see https://github.com/w3c/csswg-drafts/issues/3766 --> +<ol> + <svg style="display: list-item"></svg> + <img style="display: list-item"> + <img style="display: list-item" alt="Foo"> + <div style="display: list-item">Foo</div> + <li>Bar +</ol>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-position/position-absolute-crash-chrome-004.html b/third_party/blink/web_tests/external/wpt/css/css-position/position-absolute-crash-chrome-004.html new file mode 100644 index 0000000..cc6de63 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-position/position-absolute-crash-chrome-004.html
@@ -0,0 +1,41 @@ +<!DOCTYPE html> +<title>CSS Position Absolute: Chrome crash</title> +<link rel="author" href="mailto:atotic@chromium.org"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=946986"> +<meta name="assert" content="Nested abs/fixed/flex do not crash"> +<style> + body { overflow: scroll;} + .container { + position: relative; + contain: paint; + } + .flex { + display: flex; + } + .fixed { + position: fixed; + } + .abs { + position: absolute; + } +</style> +<!-- LayoutNG currently does not support display:flex. + Propagation of descendants across flex boundaries is error prone --> +<div id="one" class="container" style=""> + <div class="flex"> + <div class="abs"> + <div class="flex"> + <div id="fixed1" class="fixed"> + <div id="fixed2" class="fixed"></div> + </div> + </div> + </div> + </div> +</div> +<script> +test(() => { +}, 'test passes if it does not crash'); +</script> +
diff --git a/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-block-002-ref.html b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-block-002-ref.html new file mode 100644 index 0000000..1f41028 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-block-002-ref.html
@@ -0,0 +1,88 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>CSS Reftest Reference</title> + <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com"> + <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu"> + <style> + .basic { + overflow: scroll; + position: relative; + border: 2px solid green; + } + .height-ref { + height: 60px; + background: lightblue; + } + .width-ref { + width: 60px; + } + .floatLBasic-ref { + float: left; + } + .floatLWidth-ref { + float: left; + width: 60px; + } + .flexBaselineCheck { + display: flex; + align-items: baseline; + } + .innerContents { + color: transparent; + height: 100px; + width: 100px; + position: absolute; + } + .zeroHeightContents { + color: transparent; + height: 0px; + width: 0px; + } + </style> +</head> +<body> + <!-- NOTE: In the reference-case scenarios here, we use the same DOM as in + the testcase, and we simply use 'position: absolute' on the descendants + wherever the testcase has 'contain: size' on the container. This + produces an accurate reference rendering, because out-of-flow content + doesn't contribute to the container's sizing, but does create scrollable + overflow (i.e. it produces scrollbars of the appropriate size for the + amount of overflow). --> + <div class="basic"><div class="innerContents">inner</div></div> + <br> + + <div class="basic height-ref"><div class="innerContents">inner</div></div> + <br> + + <div class="basic height-ref"><div class="innerContents">inner</div></div> + <br> + + <div class="basic width-ref"><div class="innerContents">inner</div></div> + <br> + + <div class="basic width-ref"><div class="innerContents">inner</div></div> + <br> + + <div class="basic floatLBasic-ref"><div class="innerContents">inner</div></div> + <br> + + <div class="basic floatLWidth-ref"><div class="innerContents">inner</div></div> + <br> + + <div class="flexBaselineCheck"> + outside before + <div class="basic"> + <!-- We use the out-of-flow "innerContents" to create the correct + amount of scrollable overflow to match the testcase, and we + use the smaller in-flow "zeroHeightContents" to provide a + baseline that we can use to verify the testcase's baseline + alignment position. --> + <div class="innerContents">inner</div> + <div class="zeroHeightContents">i</div> + </div> + outside after + </div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-block-002.html b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-block-002.html new file mode 100644 index 0000000..4dc92103 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-block-002.html
@@ -0,0 +1,93 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>CSS Test: 'contain: size' on 'overflow:scroll' block elements should cause them to be sized as if they had no contents</title> + <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com"> + <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu"> + <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-size"> + <link rel="match" href="contain-size-block-002-ref.html"> + <style> + .contain { + contain: size; + overflow: scroll; + border: 2px solid green; + } + .innerContents { + color: transparent; + height: 100px; + width: 100px; + } + .minHeight { + min-height: 60px; + background: lightblue; + } + .height { + height: 60px; + background: lightblue; + } + .maxWidth { + max-width: 60px; + } + .width { + width: 60px; + } + .floatLBasic { + float: left; + } + .floatLWidth { + float: left; + width: 60px; + } + .flexBaselineCheck { + display: flex; + align-items: baseline; + } + </style> +</head> +<body> + <!-- NOTE: In all cases below, the expectation is that the size-contained + element should be sized as if it had no contents (while honoring + whatever sizing properties are provided). --> + + <!--CSS Test: A size-contained scrollable block with no specified size.--> + <div class="contain"><div class="innerContents">inner</div></div> + <br> + + <!--CSS Test: A size-contained scrollable block with specified min-height --> + <div class="contain minHeight"><div class="innerContents">inner</div></div> + <br> + + <!--CSS Test: A size-contained scrollable block with specified height --> + <div class="contain height"><div class="innerContents">inner</div></div> + <br> + + <!--CSS Test: A size-contained scrollable block with specified max-width --> + <div class="contain maxWidth"><div class="innerContents">inner</div></div> + <br> + + <!--CSS Test: A size-contained scrollable block with specified width --> + <div class="contain width"><div class="innerContents">inner</div></div> + <br> + + <!--CSS Test: A size-contained floated scrollable block with auto size --> + <div class="contain floatLBasic"><div class="innerContents">inner</div></div> + <br> + + <!--CSS Test: A size-contained floated scrollable block with + specified width --> + <div class="contain floatLWidth"><div class="innerContents">inner</div></div> + <br> + + <!--CSS Test: A size-contained scrollable block in a + baseline-aligning flex container: should size as if it's empty, but + still baseline-align using its contents' baseline --> + <div class="flexBaselineCheck"> + outside before + <div class="contain"> + <div class="innerContents">inner</div> + </div> + outside after + </div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-block-003-ref.html b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-block-003-ref.html new file mode 100644 index 0000000..2f6ff83 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-block-003-ref.html
@@ -0,0 +1,88 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>CSS Reftest Reference</title> + <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com"> + <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu"> + <style> + .basic { + overflow: auto; + position: relative; + border: 2px solid green; + } + .height-ref { + height: 60px; + background: lightblue; + } + .width-ref { + width: 60px; + } + .floatLBasic-ref { + float: left; + } + .floatLWidth-ref { + float: left; + width: 60px; + } + .flexBaselineCheck { + display: flex; + align-items: baseline; + } + .innerContents { + color: transparent; + height: 100px; + width: 100px; + position: absolute; + } + .zeroHeightContents { + color: transparent; + height: 0px; + width: 0px; + } + </style> +</head> +<body> + <!-- NOTE: In the reference-case scenarios here, we use the same DOM as in + the testcase, and we simply use 'position: absolute' on the descendants + wherever the testcase has 'contain: size' on the container. This + produces an accurate reference rendering, because out-of-flow content + doesn't contribute to the container's sizing, but does create scrollable + overflow (i.e. it produces scrollbars of the appropriate size for the + amount of overflow). --> + <div class="basic"><div class="innerContents">inner</div></div> + <br> + + <div class="basic height-ref"><div class="innerContents">inner</div></div> + <br> + + <div class="basic height-ref"><div class="innerContents">inner</div></div> + <br> + + <div class="basic width-ref"><div class="innerContents">inner</div></div> + <br> + + <div class="basic width-ref"><div class="innerContents">inner</div></div> + <br> + + <div class="basic floatLBasic-ref"><div class="innerContents">inner</div></div> + <br> + + <div class="basic floatLWidth-ref"><div class="innerContents">inner</div></div> + <br> + + <div class="flexBaselineCheck"> + outside before + <div class="basic"> + <!-- We use the out-of-flow "innerContents" to create the correct + amount of scrollable overflow to match the testcase, and we + use the smaller in-flow "zeroHeightContents" to provide a + baseline that we can use to verify the testcase's baseline + alignment position. --> + <div class="innerContents">inner</div> + <div class="zeroHeightContents">i</div> + </div> + outside after + </div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-block-003.html b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-block-003.html new file mode 100644 index 0000000..cf7e231 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-block-003.html
@@ -0,0 +1,93 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>CSS Test: 'contain: size' on 'overflow:auto' block elements should cause them to be sized as if they had no contents</title> + <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com"> + <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu"> + <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-size"> + <link rel="match" href="contain-size-block-003-ref.html"> + <style> + .contain { + contain: size; + overflow: auto; + border: 2px solid green; + } + .innerContents { + color: transparent; + height: 100px; + width: 100px; + } + .minHeight { + min-height: 60px; + background: lightblue; + } + .height { + height: 60px; + background: lightblue; + } + .maxWidth { + max-width: 60px; + } + .width { + width: 60px; + } + .floatLBasic { + float: left; + } + .floatLWidth { + float: left; + width: 60px; + } + .flexBaselineCheck { + display: flex; + align-items: baseline; + } + </style> +</head> +<body> + <!-- NOTE: In all cases below, the expectation is that the size-contained + element should be sized as if it had no contents (while honoring + whatever sizing properties are provided). --> + + <!--CSS Test: A size-contained scrollable block with no specified size.--> + <div class="contain"><div class="innerContents">inner</div></div> + <br> + + <!--CSS Test: A size-contained scrollable block with specified min-height --> + <div class="contain minHeight"><div class="innerContents">inner</div></div> + <br> + + <!--CSS Test: A size-contained scrollable block with specified height --> + <div class="contain height"><div class="innerContents">inner</div></div> + <br> + + <!--CSS Test: A size-contained scrollable block with specified max-width --> + <div class="contain maxWidth"><div class="innerContents">inner</div></div> + <br> + + <!--CSS Test: A size-contained scrollable block with specified width --> + <div class="contain width"><div class="innerContents">inner</div></div> + <br> + + <!--CSS Test: A size-contained floated scrollable block with auto size --> + <div class="contain floatLBasic"><div class="innerContents">inner</div></div> + <br> + + <!--CSS Test: A size-contained floated scrollable block with + specified width --> + <div class="contain floatLWidth"><div class="innerContents">inner</div></div> + <br> + + <!--CSS Test: A size-contained scrollable block in a + baseline-aligning flex container: should size as if it's empty, but + still baseline-align using its contents' baseline --> + <div class="flexBaselineCheck"> + outside before + <div class="contain"> + <div class="innerContents">inner</div> + </div> + outside after + </div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-block-004-ref.html b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-block-004-ref.html new file mode 100644 index 0000000..c8647b1 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-block-004-ref.html
@@ -0,0 +1,87 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>CSS Reftest Reference</title> + <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com"> + <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu"> + <style> + .basic { + overflow: hidden; + position: relative; + border: 2px solid green; + } + .height-ref { + height: 60px; + background: lightblue; + } + .width-ref { + width: 60px; + } + .floatLBasic-ref { + float: left; + } + .floatLWidth-ref { + float: left; + width: 60px; + } + .flexBaselineCheck { + display: flex; + align-items: baseline; + } + .innerContents { + color: transparent; + height: 100px; + width: 100px; + position: absolute; + } + .zeroHeightContents { + color: transparent; + height: 0px; + width: 0px; + } + </style> +</head> +<body> + <!-- NOTE: In the reference-case scenarios here, we use the same DOM as in + the testcase, and we simply use 'position: absolute' on the descendants + wherever the testcase has 'contain: size' on the container. This + produces an accurate reference rendering, because out-of-flow content + doesn't contribute to the container's sizing, but does create scrollable + overflow. --> + <div class="basic"><div class="innerContents">inner</div></div> + <br> + + <div class="basic height-ref"><div class="innerContents">inner</div></div> + <br> + + <div class="basic height-ref"><div class="innerContents">inner</div></div> + <br> + + <div class="basic width-ref"><div class="innerContents">inner</div></div> + <br> + + <div class="basic width-ref"><div class="innerContents">inner</div></div> + <br> + + <div class="basic floatLBasic-ref"><div class="innerContents">inner</div></div> + <br> + + <div class="basic floatLWidth-ref"><div class="innerContents">inner</div></div> + <br> + + <div class="flexBaselineCheck"> + outside before + <div class="basic"> + <!-- We use the out-of-flow "innerContents" to create the correct + amount of scrollable overflow to match the testcase, and we + use the smaller in-flow "zeroHeightContents" to provide a + baseline that we can use to verify the testcase's baseline + alignment position. --> + <div class="innerContents">inner</div> + <div class="zeroHeightContents">i</div> + </div> + outside after + </div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-block-004.html b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-block-004.html new file mode 100644 index 0000000..b6cca54a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-block-004.html
@@ -0,0 +1,93 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>CSS Test: 'contain: size' on 'overflow:hidden' block elements should cause them to be sized as if they had no contents</title> + <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com"> + <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu"> + <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-size"> + <link rel="match" href="contain-size-block-004-ref.html"> + <style> + .contain { + contain: size; + overflow: hidden; + border: 2px solid green; + } + .innerContents { + color: transparent; + height: 100px; + width: 100px; + } + .minHeight { + min-height: 60px; + background: lightblue; + } + .height { + height: 60px; + background: lightblue; + } + .maxWidth { + max-width: 60px; + } + .width { + width: 60px; + } + .floatLBasic { + float: left; + } + .floatLWidth { + float: left; + width: 60px; + } + .flexBaselineCheck { + display: flex; + align-items: baseline; + } + </style> +</head> +<body> + <!-- NOTE: In all cases below, the expectation is that the size-contained + element should be sized as if it had no contents (while honoring + whatever sizing properties are provided). --> + + <!--CSS Test: A size-contained scrollable block with no specified size.--> + <div class="contain"><div class="innerContents">inner</div></div> + <br> + + <!--CSS Test: A size-contained scrollable block with specified min-height --> + <div class="contain minHeight"><div class="innerContents">inner</div></div> + <br> + + <!--CSS Test: A size-contained scrollable block with specified height --> + <div class="contain height"><div class="innerContents">inner</div></div> + <br> + + <!--CSS Test: A size-contained scrollable block with specified max-width --> + <div class="contain maxWidth"><div class="innerContents">inner</div></div> + <br> + + <!--CSS Test: A size-contained scrollable block with specified width --> + <div class="contain width"><div class="innerContents">inner</div></div> + <br> + + <!--CSS Test: A size-contained floated scrollable block with auto size --> + <div class="contain floatLBasic"><div class="innerContents">inner</div></div> + <br> + + <!--CSS Test: A size-contained floated scrollable block with + specified width --> + <div class="contain floatLWidth"><div class="innerContents">inner</div></div> + <br> + + <!--CSS Test: A size-contained scrollable block in a + baseline-aligning flex container: should size as if it's empty, but + still baseline-align using its contents' baseline --> + <div class="flexBaselineCheck"> + outside before + <div class="contain"> + <div class="innerContents">inner</div> + </div> + outside after + </div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-inline-block-002-ref.html b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-inline-block-002-ref.html new file mode 100644 index 0000000..3d0f38f7 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-inline-block-002-ref.html
@@ -0,0 +1,56 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>CSS Reftest Reference</title> + <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com"> + <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu"> + <style> + .basic { + display: inline-block; + overflow: scroll; + position: relative; + border: 2px solid green; + } + .height-ref { + height: 60px; + } + .width-ref { + width: 60px; + } + .innerContents { + color: transparent; + height: 100px; + width: 100px; + position: absolute; + } + </style> +</head> +<body> + <!-- NOTE: In the reference-case scenarios here, we use the same DOM as in + the testcase, and we simply use 'position: absolute' on the descendants + wherever the testcase has 'contain: size' on the container. This + produces an accurate reference rendering, because out-of-flow content + doesn't contribute to the container's sizing, but does create scrollable + overflow (i.e. it produces scrollbars of the appropriate size for the + amount of overflow). --> + <div class="basic"><div class="innerContents">inner</div></div> + <br> + + outside before + <div class="basic"><div class="innerContents">inner</div></div> + outside after + <br> + + <div class="basic height-ref"><div class="innerContents">inner</div></div> + <br> + + <div class="basic height-ref"><div class="innerContents">inner</div></div> + <br> + + <div class="basic width-ref"><div class="innerContents">inner</div></div> + <br> + + <div class="basic width-ref"><div class="innerContents">inner</div></div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-inline-block-002.html b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-inline-block-002.html new file mode 100644 index 0000000..d3a69e5 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-inline-block-002.html
@@ -0,0 +1,67 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>CSS Test: 'contain: size' on 'overflow:scroll' inline-block elements should cause them to be sized as if they had no contents and baseline-aligned regularly.</title> + <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com"> + <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu"> + <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-size"> + <link rel="match" href="contain-size-inline-block-002-ref.html"> + <style> + .contain { + display: inline-block; + overflow: scroll; + contain:size; + border: 2px solid green; + } + .innerContents { + color: transparent; + height: 100px; + width: 100px; + } + .minHeight { + min-height: 60px; + } + .height { + height: 60px; + } + .minWidth { + min-width: 60px; + } + .width { + width: 60px; + } + </style> +</head> +<body> + <!-- NOTE: In all cases below, the expectation is that the size-contained + element should be sized as if it had no contents (while honoring + whatever sizing properties are provided). --> + + <!-- A size-contained scrollable inline-block with no specified size --> + <div class="contain"><div class="innerContents">inner</div></div> + <br> + + <!-- A size-contained scrollable inline-block should perform baseline + alignment regularly, based on contents' baseline. --> + outside before + <div class="contain"><div class="innerContents">inner</div></div> + outside after + <br> + + <!-- A size-contained scrollable inline-block with specified min-height --> + <div class="contain minHeight"><div class="innerContents">inner</div></div> + <br> + + <!-- A size-contained scrollable inline-block with specified height --> + <div class="contain height"><div class="innerContents">inner</div></div> + <br> + + <!-- A size-contained scrollable inline-block with specified min-width --> + <div class="contain minWidth"><div class="innerContents">inner</div></div> + <br> + + <!-- A size-contained scrollable inline-block with specified width --> + <div class="contain width"><div class="innerContents">inner</div></div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-inline-block-003-ref.html b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-inline-block-003-ref.html new file mode 100644 index 0000000..6079764 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-inline-block-003-ref.html
@@ -0,0 +1,56 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>CSS Reftest Reference</title> + <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com"> + <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu"> + <style> + .basic { + display: inline-block; + overflow: auto; + position: relative; + border: 2px solid green; + } + .height-ref { + height: 60px; + } + .width-ref { + width: 60px; + } + .innerContents { + color: transparent; + height: 100px; + width: 100px; + position: absolute; + } + </style> +</head> +<body> + <!-- NOTE: In the reference-case scenarios here, we use the same DOM as in + the testcase, and we simply use 'position: absolute' on the descendants + wherever the testcase has 'contain: size' on the container. This + produces an accurate reference rendering, because out-of-flow content + doesn't contribute to the container's sizing, but does create scrollable + overflow (i.e. it produces scrollbars of the appropriate size for the + amount of overflow). --> + <div class="basic"><div class="innerContents">inner</div></div> + <br> + + outside before + <div class="basic"><div class="innerContents">inner</div></div> + outside after + <br> + + <div class="basic height-ref"><div class="innerContents">inner</div></div> + <br> + + <div class="basic height-ref"><div class="innerContents">inner</div></div> + <br> + + <div class="basic width-ref"><div class="innerContents">inner</div></div> + <br> + + <div class="basic width-ref"><div class="innerContents">inner</div></div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-inline-block-003.html b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-inline-block-003.html new file mode 100644 index 0000000..7ea2263 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-inline-block-003.html
@@ -0,0 +1,67 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>CSS Test: 'contain: size' on 'overflow:auto' inline-block elements should cause them to be sized as if they had no contents and baseline-aligned regularly.</title> + <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com"> + <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu"> + <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-size"> + <link rel="match" href="contain-size-inline-block-003-ref.html"> + <style> + .contain { + display: inline-block; + overflow: auto; + contain:size; + border: 2px solid green; + } + .innerContents { + color: transparent; + height: 100px; + width: 100px; + } + .minHeight { + min-height: 60px; + } + .height { + height: 60px; + } + .minWidth { + min-width: 60px; + } + .width { + width: 60px; + } + </style> +</head> +<body> + <!-- NOTE: In all cases below, the expectation is that the size-contained + element should be sized as if it had no contents (while honoring + whatever sizing properties are provided). --> + + <!-- A size-contained scrollable inline-block with no specified size --> + <div class="contain"><div class="innerContents">inner</div></div> + <br> + + <!-- A size-contained scrollable inline-block should perform baseline + alignment regularly, based on contents' baseline. --> + outside before + <div class="contain"><div class="innerContents">inner</div></div> + outside after + <br> + + <!-- A size-contained scrollable inline-block with specified min-height --> + <div class="contain minHeight"><div class="innerContents">inner</div></div> + <br> + + <!-- A size-contained scrollable inline-block with specified height --> + <div class="contain height"><div class="innerContents">inner</div></div> + <br> + + <!-- A size-contained scrollable inline-block with specified min-width --> + <div class="contain minWidth"><div class="innerContents">inner</div></div> + <br> + + <!-- A size-contained scrollable inline-block with specified width --> + <div class="contain width"><div class="innerContents">inner</div></div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-inline-block-004-ref.html b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-inline-block-004-ref.html new file mode 100644 index 0000000..e7f03ff --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-inline-block-004-ref.html
@@ -0,0 +1,55 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>CSS Reftest Reference</title> + <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com"> + <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu"> + <style> + .basic { + display: inline-block; + overflow: hidden; + position: relative; + border: 2px solid green; + } + .height-ref { + height: 60px; + } + .width-ref { + width: 60px; + } + .innerContents { + color: transparent; + height: 100px; + width: 100px; + position: absolute; + } + </style> +</head> +<body> + <!-- NOTE: In the reference-case scenarios here, we use the same DOM as in + the testcase, and we simply use 'position: absolute' on the descendants + wherever the testcase has 'contain: size' on the container. This + produces an accurate reference rendering, because out-of-flow content + doesn't contribute to the container's sizing, but does create scrollable + overflow. --> + <div class="basic"><div class="innerContents">inner</div></div> + <br> + + outside before + <div class="basic"><div class="innerContents">inner</div></div> + outside after + <br> + + <div class="basic height-ref"><div class="innerContents">inner</div></div> + <br> + + <div class="basic height-ref"><div class="innerContents">inner</div></div> + <br> + + <div class="basic width-ref"><div class="innerContents">inner</div></div> + <br> + + <div class="basic width-ref"><div class="innerContents">inner</div></div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-inline-block-004.html b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-inline-block-004.html new file mode 100644 index 0000000..1de3934 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-inline-block-004.html
@@ -0,0 +1,67 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>CSS Test: 'contain: size' on 'overflow:hidden' inline-block elements should cause them to be sized as if they had no contents and baseline-aligned regularly.</title> + <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com"> + <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu"> + <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-size"> + <link rel="match" href="contain-size-inline-block-004-ref.html"> + <style> + .contain { + display: inline-block; + overflow: hidden; + contain:size; + border: 2px solid green; + } + .innerContents { + color: transparent; + height: 100px; + width: 100px; + } + .minHeight { + min-height: 60px; + } + .height { + height: 60px; + } + .minWidth { + min-width: 60px; + } + .width { + width: 60px; + } + </style> +</head> +<body> + <!-- NOTE: In all cases below, the expectation is that the size-contained + element should be sized as if it had no contents (while honoring + whatever sizing properties are provided). --> + + <!-- A size-contained scrollable inline-block with no specified size --> + <div class="contain"><div class="innerContents">inner</div></div> + <br> + + <!-- A size-contained scrollable inline-block should perform baseline + alignment regularly, based on contents' baseline. --> + outside before + <div class="contain"><div class="innerContents">inner</div></div> + outside after + <br> + + <!-- A size-contained scrollable inline-block with specified min-height --> + <div class="contain minHeight"><div class="innerContents">inner</div></div> + <br> + + <!-- A size-contained scrollable inline-block with specified height --> + <div class="contain height"><div class="innerContents">inner</div></div> + <br> + + <!-- A size-contained scrollable inline-block with specified min-width --> + <div class="contain minWidth"><div class="innerContents">inner</div></div> + <br> + + <!-- A size-contained scrollable inline-block with specified width --> + <div class="contain width"><div class="innerContents">inner</div></div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-definite-sizes-005-ref.html b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-definite-sizes-005-ref.html new file mode 100644 index 0000000..fca14667 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-definite-sizes-005-ref.html
@@ -0,0 +1,20 @@ +<!doctype html> +<meta charset="utf-8"> +<title>CSS Test Reference</title> +<link rel="author" href="mailto:dholbert@mozilla.com" title="Daniel Holbert"> +<style> + .outer { + margin-bottom: 2px; + height: 60px; + } + .inner { + background: lime; + height: 100%; + } +</style> +<p>Test passes if you see four 60px-tall lime rows (with platform-appropriate scrollbars on the last one).</p> + +<div class="outer"><div class="inner"></div></div> +<div class="outer"><div class="inner"></div></div> +<div class="outer"><div class="inner"></div></div> +<div class="outer" style="overflow: scroll"><div class="inner"></div></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-definite-sizes-005.html b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-definite-sizes-005.html new file mode 100644 index 0000000..76beb2a4 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-definite-sizes-005.html
@@ -0,0 +1,47 @@ +<!doctype html> +<meta charset="utf-8"> +<title>CSS Test: nested flex containers with definite max-height</title> +<link rel="match" href="flexbox-definite-sizes-005-ref.html"> +<link rel="author" href="mailto:dholbert@mozilla.com" title="Daniel Holbert"> +<link rel="help" href="https://drafts.csswg.org/css-flexbox/#definite-sizes"> +<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1503173"> +<style> + .horizFlex { + display: flex; + margin-bottom: 2px; + } + .vertFlex { + display: flex; + flex-grow: 1; + flex-direction: column; + min-height: 60px; + } + .item { + background: lime; + height: 100%; + } +</style> +<p>Test passes if you see four 60px-tall lime rows (with platform-appropriate scrollbars on the last one).</p> + +<div class="horizFlex"> + <div class="vertFlex"> + <div class="item"></div> + </div> +</div> + +<div class="horizFlex"> + <div class="vertFlex" style="overflow: hidden"> + <div class="item"></div> + </div> +</div> +<div class="horizFlex"> + <div class="vertFlex" style="overflow: auto"> + <div class="item"></div> + </div> +</div> + +<div class="horizFlex"> + <div class="vertFlex" style="overflow: scroll"> + <div class="item"></div> + </div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/embed.tentative.https.sub.html b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/embed.tentative.https.sub.html index b97de9e..c46765b3 100644 --- a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/embed.tentative.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/embed.tentative.https.sub.html
@@ -16,7 +16,7 @@ let e = document.createElement('embed'); e.src = "https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key; e.onload = e => { - let expected = {"dest":"embed", "site":"same-origin", "user":"?F", "mode":"no-cors"}; + let expected = {"dest":"embed", "site":"same-origin", "user":"", "mode":"no-cors"}; fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key) .then(response => response.text()) .then(text => assert_header_equals(text, expected)) @@ -35,7 +35,7 @@ let e = document.createElement('embed'); e.src = "https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key; e.onload = e => { - let expected = {"dest":"embed", "site":"same-site", "user":"?F", "mode":"no-cors"}; + let expected = {"dest":"embed", "site":"same-site", "user":"", "mode":"no-cors"}; fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key) .then(response => response.text()) .then(text => assert_header_equals(text, expected)) @@ -54,7 +54,7 @@ let e = document.createElement('embed'); e.src = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key; e.onload = e => { - let expected = {"dest":"embed", "site":"cross-site", "user":"?F", "mode":"no-cors"}; + let expected = {"dest":"embed", "site":"cross-site", "user":"", "mode":"no-cors"}; fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key) .then(response => response.text()) .then(text => assert_header_equals(text, expected))
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/fetch.tentative.https.sub.html b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/fetch.tentative.https.sub.html index dc4b977..bffb427 100644 --- a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/fetch.tentative.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/fetch.tentative.https.sub.html
@@ -11,7 +11,7 @@ assert_header_equals(j, { "dest": "empty", "site": "same-origin", - "user": "?F", + "user": "", "mode": "cors", }); }); @@ -24,7 +24,7 @@ assert_header_equals(j, { "dest": "empty", "site": "same-site", - "user": "?F", + "user": "", "mode": "cors", }); }); @@ -37,7 +37,7 @@ assert_header_equals(j, { "dest": "empty", "site": "cross-site", - "user": "?F", + "user": "", "mode": "cors", }); }); @@ -51,7 +51,7 @@ assert_header_equals(j, { "dest": "empty", "site": "same-origin", - "user": "?F", + "user": "", "mode": "same-origin", }); }); @@ -64,7 +64,7 @@ assert_header_equals(j, { "dest": "empty", "site": "same-origin", - "user": "?F", + "user": "", "mode": "cors", }); }); @@ -77,7 +77,7 @@ assert_header_equals(j, { "dest": "empty", "site": "same-origin", - "user": "?F", + "user": "", "mode": "no-cors", }); });
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/font.tentative.https.sub.html b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/font.tentative.https.sub.html index 9792f2dc..60163ee 100644 --- a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/font.tentative.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/font.tentative.https.sub.html
@@ -46,7 +46,7 @@ promise_test(t => { return new Promise((resolve, reject) => { let key = "font-same-origin"; - let expected = {"dest":"font", "site":"same-origin", "user":"?F", "mode": "cors"}; + let expected = {"dest":"font", "site":"same-origin", "user":"", "mode": "cors"}; fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key) .then(response => response.text()) .then(text => assert_header_equals(text, expected)) @@ -58,7 +58,7 @@ promise_test(t => { return new Promise((resolve, reject) => { let key = "font-same-site"; - let expected = {"dest":"font", "site":"same-site", "user":"?F", "mode": "cors"}; + let expected = {"dest":"font", "site":"same-site", "user":"", "mode": "cors"}; fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key) .then(response => response.text()) .then(text => assert_header_equals(text, expected)) @@ -70,7 +70,7 @@ promise_test(t => { return new Promise((resolve, reject) => { let key = "font-cross-site"; - let expected = {"dest":"font", "site":"cross-site", "user":"?F", "mode": "cors"}; + let expected = {"dest":"font", "site":"cross-site", "user":"", "mode": "cors"}; fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key) .then(response => response.text()) .then(text => assert_header_equals(text, expected))
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/iframe.tentative.https.sub.html b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/iframe.tentative.https.sub.html index 056d8fd..461d9f2 100644 --- a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/iframe.tentative.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/iframe.tentative.https.sub.html
@@ -1,63 +1,85 @@ <!DOCTYPE html> <script src=/resources/testharness.js></script> <script src=/resources/testharnessreport.js></script> +<script src=/resources/testdriver.js></script> +<script src=/resources/testdriver-vendor.js></script> <script src=/fetch/sec-metadata/resources/helper.js></script> +<script src=/common/utils.js></script> <body> <script> - async_test(t => { - let i = document.createElement('iframe'); - i.src = "https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/post-to-owner.py"; - window.addEventListener('message', t.step_func(e => { - if (e.source != i.contentWindow) - return; + const USER = true; + const FORCED = false; - assert_header_equals(e.data, { - "dest": "nested-document", - "site": "same-origin", - "user": "?F", - "mode": "nested-navigate" - }); - t.done(); - })); + function create_test(host, user_activated, expectations) { + async_test(t => { + let i = document.createElement('iframe'); + window.addEventListener('message', t.step_func(e => { + if (e.source != i.contentWindow) + return; - document.body.appendChild(i); - }, "Same-origin iframe"); + assert_header_equals(e.data, expectations); + t.done(); + })); - async_test(t => { - let i = document.createElement('iframe'); - i.src = "https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/post-to-owner.py"; - window.addEventListener('message', t.step_func(e => { - if (e.source != i.contentWindow) - return; + let url = `https://${host}/fetch/sec-metadata/resources/post-to-owner.py`; + if (user_activated == FORCED) { + i.src = url; + document.body.appendChild(i); + } else if (user_activated == USER) { + let uuid = token(); + i.name = uuid; + let a = document.createElement('a'); + a.href = url; + a.target = uuid; + a.text = "This is a link!"; - assert_header_equals(e.data, { - "dest": "nested-document", - "site": "same-site", - "user": "?F", - "mode": "nested-navigate" - }); - t.done(); - })); + document.body.appendChild(i); + document.body.appendChild(a); - document.body.appendChild(i); - }, "Same-site iframe"); + test_driver.click(a); + } + }, `{{host}} -> ${host} iframe: ${user_activated ? "user-activated" : "forced"}`); + } - async_test(t => { - let i = document.createElement('iframe'); - i.src = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/post-to-owner.py"; - window.addEventListener('message', t.step_func(e => { - if (e.source != i.contentWindow) - return; + create_test("{{host}}:{{ports[https][0]}}", FORCED, { + "dest": "nested-document", + "site": "same-origin", + "user": "", + "mode": "nested-navigate" + }); - assert_header_equals(e.data, { - "dest": "nested-document", - "site": "cross-site", - "user": "?F", - "mode": "nested-navigate" - }); - t.done(); - })); + create_test("{{hosts[][www]}}:{{ports[https][0]}}", FORCED, { + "dest": "nested-document", + "site": "same-site", + "user": "", + "mode": "nested-navigate" + }); - document.body.appendChild(i); - }, "Cross-site iframe"); + create_test("{{hosts[alt][www]}}:{{ports[https][0]}}", FORCED, { + "dest": "nested-document", + "site": "cross-site", + "user": "", + "mode": "nested-navigate" + }); + + create_test("{{host}}:{{ports[https][0]}}", USER, { + "dest": "nested-document", + "site": "same-origin", + "user": "?T", + "mode": "nested-navigate" + }); + + create_test("{{hosts[][www]}}:{{ports[https][0]}}", USER, { + "dest": "nested-document", + "site": "same-site", + "user": "?T", + "mode": "nested-navigate" + }); + + create_test("{{hosts[alt][www]}}:{{ports[https][0]}}", USER, { + "dest": "nested-document", + "site": "cross-site", + "user": "?T", + "mode": "nested-navigate" + }); </script>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/img.tentative.https.sub.html b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/img.tentative.https.sub.html index b1216db8..b9fc1af 100644 --- a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/img.tentative.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/img.tentative.https.sub.html
@@ -23,7 +23,9 @@ assert_header_equals(got, { "dest": "image", "site": "same-origin", - "user": "?F", + // Note that we're using `undefined` here, as opposed to "" elsewhere because of the way + // that `image.py` encodes data. + "user": undefined, "mode": "cors", // Because `loadImageInWindow` tacks on `crossorigin` }); }), @@ -45,7 +47,9 @@ assert_header_equals(got, { "dest": "image", "site": "same-site", - "user": "?F", + // Note that we're using `undefined` here, as opposed to "" elsewhere because of the way + // that `image.py` encodes data. + "user": undefined, "mode": "cors", // Because `loadImageInWindow` tacks on `crossorigin` }); }), @@ -67,7 +71,9 @@ assert_header_equals(got, { "dest": "image", "site": "cross-site", - "user": "?F", + // Note that we're using `undefined` here, as opposed to "" elsewhere because of the way + // that `image.py` encodes data. + "user": undefined, "mode": "cors", // Because `loadImageInWindow` tacks on `crossorigin` }); }),
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/object.tentative.https.sub.html b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/object.tentative.https.sub.html index 4749629..b60ae20 100644 --- a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/object.tentative.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/object.tentative.https.sub.html
@@ -16,7 +16,7 @@ let e = document.createElement('object'); e.data = "https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key; e.onload = e => { - let expected = {"dest":"object", "site":"same-origin", "user":"?F", "mode":"no-cors"}; + let expected = {"dest":"object", "site":"same-origin", "user":"", "mode":"no-cors"}; fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key) .then(response => response.text()) .then(text => assert_header_equals(text, expected)) @@ -35,7 +35,7 @@ let e = document.createElement('object'); e.data = "https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key; e.onload = e => { - let expected = {"dest":"object", "site":"same-site", "user":"?F", "mode":"no-cors"}; + let expected = {"dest":"object", "site":"same-site", "user":"", "mode":"no-cors"}; fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key) .then(response => response.text()) .then(text => assert_header_equals(text, expected)) @@ -54,7 +54,7 @@ let e = document.createElement('object'); e.data = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key; e.onload = e => { - let expected = {"dest":"object", "site":"cross-site", "user":"?F", "mode":"no-cors"}; + let expected = {"dest":"object", "site":"cross-site", "user":"", "mode":"no-cors"}; fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key) .then(response => response.text()) .then(text => assert_header_equals(text, expected))
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/cross-site-redirect.tentative.https.sub.html b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/cross-site-redirect.tentative.https.sub.html index 1634a29..06b5874 100644 --- a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/cross-site-redirect.tentative.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/cross-site-redirect.tentative.https.sub.html
@@ -15,7 +15,7 @@ let e = document.createElement('img'); e.src = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key; - let expected = {"dest":"image", "site":"cross-site", "user":"?F", "mode": "no-cors"}; + let expected = {"dest":"image", "site":"cross-site", "user":"", "mode": "no-cors"}; e.onload = e => { fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key) .then(response => response.text()) @@ -41,7 +41,7 @@ let e = document.createElement('img'); e.src = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key; - let expected = {"dest":"image", "site":"cross-site", "user":"?F", "mode": "no-cors"}; + let expected = {"dest":"image", "site":"cross-site", "user":"", "mode": "no-cors"}; e.onload = e => { fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key) .then(response => response.text()) @@ -67,7 +67,7 @@ let e = document.createElement('img'); e.src = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key; - let expected = {"dest":"image", "site":"cross-site", "user":"?F", "mode": "no-cors"}; + let expected = {"dest":"image", "site":"cross-site", "user":"", "mode": "no-cors"}; e.onload = e => { fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key) .then(response => response.text())
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/multiple-redirect-cross-site.tentative.https.sub.html b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/multiple-redirect-cross-site.tentative.https.sub.html index 7647a5b1..e173bb0 100644 --- a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/multiple-redirect-cross-site.tentative.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/multiple-redirect-cross-site.tentative.https.sub.html
@@ -17,7 +17,7 @@ e.src = "https://{{host}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=" +// same-origin "https://{{hosts[alt][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=" +// cross-site "https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;// same-origin - let expected = {"dest":"image", "site":"cross-site", "user":"?F", "mode": "no-cors"}; + let expected = {"dest":"image", "site":"cross-site", "user":"", "mode": "no-cors"}; e.onload = e => { fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/multiple-redirect-same-site.tentative.https.sub.html b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/multiple-redirect-same-site.tentative.https.sub.html index e83d6fd9..d19a189 100644 --- a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/multiple-redirect-same-site.tentative.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/multiple-redirect-same-site.tentative.https.sub.html
@@ -17,7 +17,7 @@ e.src = "https://{{host}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=" +// same-origin "https://{{hosts[][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=" +// same-site "https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;// same-origin - let expected = {"dest":"image", "site":"same-site", "user":"?F", "mode": "no-cors"}; + let expected = {"dest":"image", "site":"same-site", "user":"", "mode": "no-cors"}; e.onload = e => { fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/same-origin-redirect.tentative.https.sub.html b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/same-origin-redirect.tentative.https.sub.html index 2033eab..0b4fdfee 100644 --- a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/same-origin-redirect.tentative.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/same-origin-redirect.tentative.https.sub.html
@@ -15,7 +15,7 @@ let e = document.createElement('img'); e.src = "/xhr/resources/redirect.py?location=https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key; - let expected = {"dest":"image", "site":"same-origin", "user":"?F", "mode": "no-cors"}; + let expected = {"dest":"image", "site":"same-origin", "user":"", "mode": "no-cors"}; e.onload = e => { fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key) @@ -42,7 +42,7 @@ let e = document.createElement('img'); e.src = "/xhr/resources/redirect.py?location=https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key; - let expected = {"dest":"image", "site":"same-site", "user":"?F", "mode": "no-cors"}; + let expected = {"dest":"image", "site":"same-site", "user":"", "mode": "no-cors"}; e.onload = e => { fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key) @@ -69,7 +69,7 @@ let e = document.createElement('img'); e.src = "/xhr/resources/redirect.py?location=https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key; - let expected = {"dest":"image", "site":"cross-site", "user":"?F", "mode": "no-cors"}; + let expected = {"dest":"image", "site":"cross-site", "user":"", "mode": "no-cors"}; e.onload = e => { fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/same-site-redirect.tentative.https.sub.html b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/same-site-redirect.tentative.https.sub.html index c5b6830..70c0afe 100644 --- a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/same-site-redirect.tentative.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/same-site-redirect.tentative.https.sub.html
@@ -15,7 +15,7 @@ let e = document.createElement('img'); e.src = "https://{{hosts[][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key; - let expected = {"dest":"image", "site":"same-site", "user":"?F", "mode": "no-cors"}; + let expected = {"dest":"image", "site":"same-site", "user":"", "mode": "no-cors"}; e.onload = e => { fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key) @@ -42,7 +42,7 @@ let e = document.createElement('img'); e.src = "https://{{hosts[][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key; - let expected = {"dest":"image", "site":"same-site", "user":"?F", "mode": "no-cors"}; + let expected = {"dest":"image", "site":"same-site", "user":"", "mode": "no-cors"}; e.onload = e => { fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key) @@ -69,7 +69,7 @@ let e = document.createElement('img'); e.src = "https://{{hosts[][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key; - let expected = {"dest":"image", "site":"cross-site", "user":"?F", "mode": "no-cors"}; + let expected = {"dest":"image", "site":"cross-site", "user":"", "mode": "no-cors"}; e.onload = e => { fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/report.tentative.https.sub.html b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/report.tentative.https.sub.html index 405964e..eb6c76b5 100644 --- a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/report.tentative.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/report.tentative.https.sub.html
@@ -22,9 +22,9 @@ document.addEventListener("securitypolicyviolation", (e) => { counter++; if (counter == 3) { - generate_test({"dest":"report", "site":"same-origin", "user":"?F", "mode": "no-cors"}, "same-origin"); - generate_test({"dest":"report", "site":"same-site", "user":"?F", "mode": "no-cors"}, "same-site"); - generate_test({"dest":"report", "site":"cross-site", "user":"?F", "mode": "no-cors"}, "cross-site"); + generate_test({"dest":"report", "site":"same-origin", "user":"", "mode": "no-cors"}, "same-origin"); + generate_test({"dest":"report", "site":"same-site", "user":"", "mode": "no-cors"}, "same-site"); + generate_test({"dest":"report", "site":"cross-site", "user":"", "mode": "no-cors"}, "cross-site"); done(); }
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/script.tentative.https.sub.html b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/script.tentative.https.sub.html index a35e753..b2874a3 100644 --- a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/script.tentative.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/script.tentative.https.sub.html
@@ -12,7 +12,7 @@ assert_header_equals(header, { "dest": "script", "site": "same-origin", - "user": "?F", + "user": "", "mode": "no-cors", }); }, "Same-origin script"); @@ -27,7 +27,7 @@ assert_header_equals(header, { "dest": "script", "site": "same-site", - "user": "?F", + "user": "", "mode": "no-cors", }); }, "Same-site script"); @@ -42,7 +42,7 @@ assert_header_equals(header, { "dest": "script", "site": "cross-site", - "user": "?F", + "user": "", "mode": "no-cors", }); }, "Cross-site script"); @@ -57,7 +57,7 @@ assert_header_equals(header, { "dest": "script", "site": "same-origin", - "user": "?F", + "user": "", "mode": "cors", }); }, "Same-origin CORS script");
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/serviceworker.tentative.https.sub.html b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/serviceworker.tentative.https.sub.html index 590a6c3..ee436d9 100644 --- a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/serviceworker.tentative.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/serviceworker.tentative.https.sub.html
@@ -38,7 +38,7 @@ function test_same_origin(){ promise_test(t => { return new Promise((resolve, reject) => { - let expected = {"dest":"serviceworker", "site":"same-origin", "user":"?F", "mode": "same-origin"}; + let expected = {"dest":"serviceworker", "site":"same-origin", "user":"", "mode": "same-origin"}; fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key) .then(response => response.text()) .then(text => assert_header_equals(text, expected))
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/sharedworker.tentative.https.sub.html b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/sharedworker.tentative.https.sub.html index a1c558a..ddd4cc99 100644 --- a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/sharedworker.tentative.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/sharedworker.tentative.https.sub.html
@@ -28,7 +28,7 @@ function test_same_origin(){ promise_test(t => { return new Promise((resolve, reject) => { - let expected = {"dest":"sharedworker", "site":"same-origin", "user":"?F", "mode": "same-origin"}; + let expected = {"dest":"sharedworker", "site":"same-origin", "user":"", "mode": "same-origin"}; fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key) .then(response => response.text())
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/style.tentative.https.sub.html b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/style.tentative.https.sub.html index 46f64f4..19cc16d 100644 --- a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/style.tentative.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/style.tentative.https.sub.html
@@ -17,7 +17,7 @@ e.rel = "stylesheet"; e.href = "https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key; e.onload = e => { - let expected = {"dest":"style", "site":"same-origin", "user":"?F", "mode": "no-cors"}; + let expected = {"dest":"style", "site":"same-origin", "user":"", "mode": "no-cors"}; fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key) .then(response => response.text()) .then(text => assert_header_equals(text, expected)) @@ -37,7 +37,7 @@ e.rel = "stylesheet"; e.href = "https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key; e.onload = e => { - let expected = {"dest":"style", "site":"same-site", "user":"?F", "mode": "no-cors"}; + let expected = {"dest":"style", "site":"same-site", "user":"", "mode": "no-cors"}; fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key) .then(response => response.text()) .then(text => assert_header_equals(text, expected)) @@ -57,7 +57,7 @@ e.rel = "stylesheet"; e.href = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key; e.onload = e => { - let expected = {"dest":"style", "site":"cross-site", "user":"?F", "mode": "no-cors"}; + let expected = {"dest":"style", "site":"cross-site", "user":"", "mode": "no-cors"}; fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key) .then(response => response.text()) .then(text => assert_header_equals(text, expected)) @@ -78,7 +78,7 @@ e.href = "https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key; e.crossOrigin = "anonymous"; e.onload = e => { - let expected = {"dest":"style", "site":"same-origin", "user":"?F", "mode": "cors"}; + let expected = {"dest":"style", "site":"same-origin", "user":"", "mode": "cors"}; fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key) .then(response => response.text()) .then(text => assert_header_equals(text, expected))
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/track.tentative.https.sub.html b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/track.tentative.https.sub.html index 817e4845..fe525ca 100644 --- a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/track.tentative.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/track.tentative.https.sub.html
@@ -36,7 +36,7 @@ expected = { "dest": "track", "site": "same-origin", - "user": "?F", + "user": "", "mode": "cors" // Because the `video` element has `crossorigin` }; fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key) @@ -59,7 +59,7 @@ expected = { "dest": "track", "site": "same-site", - "user": "?F", + "user": "", "mode": "cors" // Because the `video` element has `crossorigin` }; fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key) @@ -84,7 +84,7 @@ expected = { "dest": "track", "site": "cross-site", - "user": "?F", + "user": "", "mode": "cors" // Because the `video` element has `crossorigin` }; fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key) @@ -112,7 +112,7 @@ expected = { "dest":"track", "site":"same-origin", - "user":"?F", + "user":"", "mode": "same-origin" }; fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/trailing-dot.tentative.https.sub.html b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/trailing-dot.tentative.https.sub.html index 85f9c73..ff0e842 100644 --- a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/trailing-dot.tentative.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/trailing-dot.tentative.https.sub.html
@@ -11,7 +11,7 @@ assert_header_equals(j, { "dest": "empty", "site": "cross-site", - "user": "?F", + "user": "", "mode": "cors", }); }); @@ -24,7 +24,7 @@ assert_header_equals(j, { "dest": "empty", "site": "cross-site", - "user": "?F", + "user": "", "mode": "cors", }); }); @@ -37,7 +37,7 @@ assert_header_equals(j, { "dest": "empty", "site": "cross-site", - "user": "?F", + "user": "", "mode": "cors", }); });
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/window-open.tentative.https.sub.html b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/window-open.tentative.https.sub.html index ef2bc81..0be9f2c 100644 --- a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/window-open.tentative.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/window-open.tentative.https.sub.html
@@ -17,7 +17,7 @@ assert_header_equals(e.data, { "dest": "document", "site": "same-origin", - "user": "?F", + "user": "", "mode": "navigate", }); t.done(); @@ -34,7 +34,7 @@ assert_header_equals(e.data, { "dest": "document", "site": "same-site", - "user": "?F", + "user": "", "mode": "navigate", }); t.done(); @@ -51,7 +51,7 @@ assert_header_equals(e.data, { "dest": "document", "site": "cross-site", - "user": "?F", + "user": "", "mode": "navigate", }); t.done(); @@ -70,7 +70,7 @@ assert_header_equals(e.data, { "dest": "document", "site": "same-origin", - "user": "?F", + "user": "", "mode": "navigate", }); @@ -94,7 +94,7 @@ assert_header_equals(e.data, { "dest": "document", "site": "same-site", - "user": "?F", + "user": "", "mode": "navigate", }); @@ -118,7 +118,7 @@ assert_header_equals(e.data, { "dest": "document", "site": "cross-site", - "user": "?F", + "user": "", "mode": "navigate", });
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/worker.tentative.https.sub.html b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/worker.tentative.https.sub.html index dc21d032..940e25b2 100644 --- a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/worker.tentative.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/worker.tentative.https.sub.html
@@ -13,7 +13,7 @@ let key = "worker-same-origin" + nonce; let w = new Worker("/fetch/sec-metadata/resources/record-header.py?file=" + key); w.onmessage = e => { - let expected = {"dest":"worker", "site":"same-origin", "user":"?F", "mode": "same-origin"}; + let expected = {"dest":"worker", "site":"same-origin", "user":"", "mode": "same-origin"}; fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key) .then(response => response.text()) .then(text => assert_header_equals(text, expected))
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/xslt.tentative.https.sub.html b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/xslt.tentative.https.sub.html index eea2329..0d42926 100644 --- a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/xslt.tentative.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/xslt.tentative.https.sub.html
@@ -12,21 +12,21 @@ return; promise_test(t => { - let expected = {"dest":"xslt", "site":"same-origin", "user":"?F", "mode": "same-origin"}; + let expected = {"dest":"xslt", "site":"same-origin", "user":"", "mode": "same-origin"}; return fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=xslt-same-origin") .then(response => response.text()) .then(text => assert_header_equals(text, expected)); }, "Same-Origin xslt"); promise_test(t => { - let expected = {"dest":"xslt", "site":"same-site", "user":"?F", "mode": "no-cors"}; + let expected = {"dest":"xslt", "site":"same-site", "user":"", "mode": "no-cors"}; return fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=xslt-same-site") .then(response => response.text()) .then(text => assert_header_equals(text, expected)); }, "Same-site xslt"); promise_test(t => { - let expected = {"dest":"xslt", "site":"cross-site", "user":"?F", "mode": "no-cors"}; + let expected = {"dest":"xslt", "site":"cross-site", "user":"", "mode": "no-cors"}; return fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=xslt-cross-site") .then(response => response.text()) .then(text => assert_header_equals(text, expected));
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-integrity-classic.sub.html b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-integrity-classic.sub.html deleted file mode 100644 index 80a2989..0000000 --- a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-integrity-classic.sub.html +++ /dev/null
@@ -1,52 +0,0 @@ -<!DOCTYPE html> -<meta charset="utf-8"> -<title>import() doesn't have any integrity metadata when initiated by compiled strings inside a classic script</title> -<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me"> -<meta http-equiv="Content-Security-Policy" content="require-sri-for script"> - -<script src="/resources/testharness.js" integrity="sha384-{{file_hash(sha384, resources/testharness.js)}}"></script> -<script src="/resources/testharnessreport.js" integrity="sha384-{{file_hash(sha384, resources/testharnessreport.js)}}"></script> - -<div id="dummy"></div> - -<script> -function createTestPromise() { - return new Promise((resolve, reject) => { - window.continueTest = resolve; - window.errorTest = reject; - }); -} - -const dummyDiv = document.querySelector("#dummy"); - -const evaluators = { - eval, - setTimeout, - "the Function constructor"(x) { - Function(x)(); - }, - "reflected inline event handlers"(x) { - dummyDiv.setAttribute("onclick", x); - dummyDiv.onclick(); - }, - "inline event handlers triggered via UA code"(x) { - dummyDiv.setAttribute("onclick", x); - dummyDiv.click(); // different from .**on**click() - } -}; - -for (const [label, evaluator] of Object.entries(evaluators)) { - promise_test(t => { - t.add_cleanup(() => { - dummyDiv.removeAttribute("onclick"); - delete window.evaluated_imports_a; - }); - - const promise = createTestPromise(); - - evaluator(`import('../imports-a.js?label=${label}').then(window.continueTest, window.errorTest);`); - - return promise_rejects(t, new TypeError(), promise); - }, label + " should fail to import"); -}; -</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-integrity-module.sub.html b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-integrity-module.sub.html deleted file mode 100644 index db3d3b1..0000000 --- a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-integrity-module.sub.html +++ /dev/null
@@ -1,52 +0,0 @@ -<!DOCTYPE html> -<meta charset="utf-8"> -<title>import() doesn't have any integrity metadata when initiated by compiled strings inside a module script</title> -<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me"> -<meta http-equiv="Content-Security-Policy" content="require-sri-for script"> - -<script src="/resources/testharness.js" integrity="sha384-{{file_hash(sha384, resources/testharness.js)}}"></script> -<script src="/resources/testharnessreport.js" integrity="sha384-{{file_hash(sha384, resources/testharnessreport.js)}}"></script> - -<div id="dummy"></div> - -<script type="module"> -function createTestPromise() { - return new Promise((resolve, reject) => { - window.continueTest = resolve; - window.errorTest = reject; - }); -} - -const dummyDiv = document.querySelector("#dummy"); - -const evaluators = { - eval, - setTimeout, - "the Function constructor"(x) { - Function(x)(); - }, - "reflected inline event handlers"(x) { - dummyDiv.setAttribute("onclick", x); - dummyDiv.onclick(); - }, - "inline event handlers triggered via UA code"(x) { - dummyDiv.setAttribute("onclick", x); - dummyDiv.click(); // different from .**on**click() - } -}; - -for (const [label, evaluator] of Object.entries(evaluators)) { - promise_test(t => { - t.add_cleanup(() => { - dummyDiv.removeAttribute("onclick"); - delete window.evaluated_imports_a; - }); - - const promise = createTestPromise(); - - evaluator(`import('../imports-a.js?label=${label}').then(window.continueTest, window.errorTest);`); - - return promise_rejects(t, new TypeError(), promise); - }, label + " should fail to import"); -}; -</script>
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/performance-timeline.idl b/third_party/blink/web_tests/external/wpt/interfaces/performance-timeline.idl index 7766bfd..51752b13 100644 --- a/third_party/blink/web_tests/external/wpt/interfaces/performance-timeline.idl +++ b/third_party/blink/web_tests/external/wpt/interfaces/performance-timeline.idl
@@ -23,7 +23,7 @@ PerformanceObserver observer); [Constructor(PerformanceObserverCallback callback), Exposed=(Window,Worker)] interface PerformanceObserver { - void observe(PerformanceObserverInit options); + void observe(optional PerformanceObserverInit options); void disconnect(); PerformanceEntryList takeRecords(); static readonly attribute FrozenArray<DOMString> supportedEntryTypes;
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/idlharness.any-expected.txt b/third_party/blink/web_tests/external/wpt/performance-timeline/idlharness.any-expected.txt index 7d03cc1..32878d3 100644 --- a/third_party/blink/web_tests/external/wpt/performance-timeline/idlharness.any-expected.txt +++ b/third_party/blink/web_tests/external/wpt/performance-timeline/idlharness.any-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 71 tests; 68 PASS, 3 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 71 tests; 67 PASS, 4 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS idlharness PASS idl_test setup PASS Partial interface Performance: original interface defined @@ -20,7 +20,7 @@ PASS PerformanceObserver interface: existence and properties of interface prototype object PASS PerformanceObserver interface: existence and properties of interface prototype object's "constructor" property PASS PerformanceObserver interface: existence and properties of interface prototype object's @@unscopables property -PASS PerformanceObserver interface: operation observe(PerformanceObserverInit) +FAIL PerformanceObserver interface: operation observe(PerformanceObserverInit) assert_equals: property has wrong .length expected 0 but got 1 PASS PerformanceObserver interface: operation disconnect() PASS PerformanceObserver interface: operation takeRecords() PASS PerformanceObserver interface: attribute supportedEntryTypes
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/idlharness.any.serviceworker-expected.txt b/third_party/blink/web_tests/external/wpt/performance-timeline/idlharness.any.serviceworker-expected.txt index 7d03cc1..32878d3 100644 --- a/third_party/blink/web_tests/external/wpt/performance-timeline/idlharness.any.serviceworker-expected.txt +++ b/third_party/blink/web_tests/external/wpt/performance-timeline/idlharness.any.serviceworker-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 71 tests; 68 PASS, 3 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 71 tests; 67 PASS, 4 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS idlharness PASS idl_test setup PASS Partial interface Performance: original interface defined @@ -20,7 +20,7 @@ PASS PerformanceObserver interface: existence and properties of interface prototype object PASS PerformanceObserver interface: existence and properties of interface prototype object's "constructor" property PASS PerformanceObserver interface: existence and properties of interface prototype object's @@unscopables property -PASS PerformanceObserver interface: operation observe(PerformanceObserverInit) +FAIL PerformanceObserver interface: operation observe(PerformanceObserverInit) assert_equals: property has wrong .length expected 0 but got 1 PASS PerformanceObserver interface: operation disconnect() PASS PerformanceObserver interface: operation takeRecords() PASS PerformanceObserver interface: attribute supportedEntryTypes
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/idlharness.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/performance-timeline/idlharness.any.sharedworker-expected.txt index 7d03cc1..32878d3 100644 --- a/third_party/blink/web_tests/external/wpt/performance-timeline/idlharness.any.sharedworker-expected.txt +++ b/third_party/blink/web_tests/external/wpt/performance-timeline/idlharness.any.sharedworker-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 71 tests; 68 PASS, 3 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 71 tests; 67 PASS, 4 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS idlharness PASS idl_test setup PASS Partial interface Performance: original interface defined @@ -20,7 +20,7 @@ PASS PerformanceObserver interface: existence and properties of interface prototype object PASS PerformanceObserver interface: existence and properties of interface prototype object's "constructor" property PASS PerformanceObserver interface: existence and properties of interface prototype object's @@unscopables property -PASS PerformanceObserver interface: operation observe(PerformanceObserverInit) +FAIL PerformanceObserver interface: operation observe(PerformanceObserverInit) assert_equals: property has wrong .length expected 0 but got 1 PASS PerformanceObserver interface: operation disconnect() PASS PerformanceObserver interface: operation takeRecords() PASS PerformanceObserver interface: attribute supportedEntryTypes
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/idlharness.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/performance-timeline/idlharness.any.worker-expected.txt index 7d03cc1..32878d3 100644 --- a/third_party/blink/web_tests/external/wpt/performance-timeline/idlharness.any.worker-expected.txt +++ b/third_party/blink/web_tests/external/wpt/performance-timeline/idlharness.any.worker-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 71 tests; 68 PASS, 3 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 71 tests; 67 PASS, 4 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS idlharness PASS idl_test setup PASS Partial interface Performance: original interface defined @@ -20,7 +20,7 @@ PASS PerformanceObserver interface: existence and properties of interface prototype object PASS PerformanceObserver interface: existence and properties of interface prototype object's "constructor" property PASS PerformanceObserver interface: existence and properties of interface prototype object's @@unscopables property -PASS PerformanceObserver interface: operation observe(PerformanceObserverInit) +FAIL PerformanceObserver interface: operation observe(PerformanceObserverInit) assert_equals: property has wrong .length expected 0 but got 1 PASS PerformanceObserver interface: operation disconnect() PASS PerformanceObserver interface: operation takeRecords() PASS PerformanceObserver interface: attribute supportedEntryTypes
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/fetch-request-xhr.https-expected.txt b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/fetch-request-xhr.https-expected.txt index 3de90db..76e0835 100644 --- a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/fetch-request-xhr.https-expected.txt +++ b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/fetch-request-xhr.https-expected.txt
@@ -1,9 +1,9 @@ This is a testharness.js-based test. PASS initialize global state -FAIL event.request has the expected headers for same-origin GET. promise_test: Unhandled rejection with value: object "Error: assert_array_equals: event.request has the expected headers for same-origin GET. lengths differ, expected 1 got 7" -FAIL event.request has the expected headers for same-origin POST. promise_test: Unhandled rejection with value: object "Error: assert_array_equals: event.request has the expected headers for same-origin POST. lengths differ, expected 2 got 9" -FAIL event.request has the expected headers for cross-origin GET. promise_test: Unhandled rejection with value: object "Error: assert_array_equals: event.request has the expected headers for cross-origin GET. lengths differ, expected 1 got 7" -FAIL event.request has the expected headers for cross-origin POST. promise_test: Unhandled rejection with value: object "Error: assert_array_equals: event.request has the expected headers for cross-origin POST. lengths differ, expected 2 got 9" +FAIL event.request has the expected headers for same-origin GET. promise_test: Unhandled rejection with value: object "Error: assert_array_equals: event.request has the expected headers for same-origin GET. lengths differ, expected 1 got 6" +FAIL event.request has the expected headers for same-origin POST. promise_test: Unhandled rejection with value: object "Error: assert_array_equals: event.request has the expected headers for same-origin POST. lengths differ, expected 2 got 8" +FAIL event.request has the expected headers for cross-origin GET. promise_test: Unhandled rejection with value: object "Error: assert_array_equals: event.request has the expected headers for cross-origin GET. lengths differ, expected 1 got 6" +FAIL event.request has the expected headers for cross-origin POST. promise_test: Unhandled rejection with value: object "Error: assert_array_equals: event.request has the expected headers for cross-origin POST. lengths differ, expected 2 got 8" PASS FetchEvent#request.body contains XHR request data (string) PASS FetchEvent#request.body contains XHR request data (blob) PASS FetchEvent#request.method is set to XHR method
diff --git a/third_party/blink/web_tests/http/tests/navigation/form-targets-cross-site-frame-get-expected.txt b/third_party/blink/web_tests/http/tests/navigation/form-targets-cross-site-frame-get-expected.txt index 8a57512c..4669741 100644 --- a/third_party/blink/web_tests/http/tests/navigation/form-targets-cross-site-frame-get-expected.txt +++ b/third_party/blink/web_tests/http/tests/navigation/form-targets-cross-site-frame-get-expected.txt
@@ -17,5 +17,4 @@ HTTP_SEC_FETCH_DEST = nested-document HTTP_SEC_FETCH_MODE = nested-navigate HTTP_SEC_FETCH_SITE = cross-site -HTTP_SEC_FETCH_USER = ?F HTTP_UPGRADE_INSECURE_REQUESTS = 1
diff --git a/third_party/blink/web_tests/http/tests/navigation/form-targets-cross-site-frame-no-referrer-expected.txt b/third_party/blink/web_tests/http/tests/navigation/form-targets-cross-site-frame-no-referrer-expected.txt index f6dca30..ee7518aa 100644 --- a/third_party/blink/web_tests/http/tests/navigation/form-targets-cross-site-frame-no-referrer-expected.txt +++ b/third_party/blink/web_tests/http/tests/navigation/form-targets-cross-site-frame-no-referrer-expected.txt
@@ -18,5 +18,4 @@ HTTP_SEC_FETCH_DEST = nested-document HTTP_SEC_FETCH_MODE = nested-navigate HTTP_SEC_FETCH_SITE = cross-site -HTTP_SEC_FETCH_USER = ?F HTTP_UPGRADE_INSECURE_REQUESTS = 1
diff --git a/third_party/blink/web_tests/http/tests/navigation/form-targets-cross-site-frame-post-expected.txt b/third_party/blink/web_tests/http/tests/navigation/form-targets-cross-site-frame-post-expected.txt index f31564b5..d9a55b6 100644 --- a/third_party/blink/web_tests/http/tests/navigation/form-targets-cross-site-frame-post-expected.txt +++ b/third_party/blink/web_tests/http/tests/navigation/form-targets-cross-site-frame-post-expected.txt
@@ -19,5 +19,4 @@ HTTP_SEC_FETCH_DEST = nested-document HTTP_SEC_FETCH_MODE = nested-navigate HTTP_SEC_FETCH_SITE = cross-site -HTTP_SEC_FETCH_USER = ?F HTTP_UPGRADE_INSECURE_REQUESTS = 1
diff --git a/third_party/blink/web_tests/http/tests/navigation/form-with-enctype-targets-cross-site-frame-expected.txt b/third_party/blink/web_tests/http/tests/navigation/form-with-enctype-targets-cross-site-frame-expected.txt index 9d33086d..d12ad014 100644 --- a/third_party/blink/web_tests/http/tests/navigation/form-with-enctype-targets-cross-site-frame-expected.txt +++ b/third_party/blink/web_tests/http/tests/navigation/form-with-enctype-targets-cross-site-frame-expected.txt
@@ -19,5 +19,4 @@ HTTP_SEC_FETCH_DEST = nested-document HTTP_SEC_FETCH_MODE = nested-navigate HTTP_SEC_FETCH_SITE = cross-site -HTTP_SEC_FETCH_USER = ?F HTTP_UPGRADE_INSECURE_REQUESTS = 1
diff --git a/third_party/blink/web_tests/http/tests/navigation/post-basic-expected.txt b/third_party/blink/web_tests/http/tests/navigation/post-basic-expected.txt index b423b5b0..6753a6b 100644 --- a/third_party/blink/web_tests/http/tests/navigation/post-basic-expected.txt +++ b/third_party/blink/web_tests/http/tests/navigation/post-basic-expected.txt
@@ -15,7 +15,6 @@ HTTP_SEC_FETCH_DEST = document HTTP_SEC_FETCH_MODE = navigate HTTP_SEC_FETCH_SITE = same-origin -HTTP_SEC_FETCH_USER = ?F HTTP_UPGRADE_INSECURE_REQUESTS = 1 ============== Back Forward List ==============
diff --git a/third_party/blink/web_tests/http/tests/navigation/post-frames-expected.txt b/third_party/blink/web_tests/http/tests/navigation/post-frames-expected.txt index a017c82..26db48ef 100644 --- a/third_party/blink/web_tests/http/tests/navigation/post-frames-expected.txt +++ b/third_party/blink/web_tests/http/tests/navigation/post-frames-expected.txt
@@ -20,7 +20,6 @@ HTTP_SEC_FETCH_DEST = nested-document HTTP_SEC_FETCH_MODE = nested-navigate HTTP_SEC_FETCH_SITE = same-origin -HTTP_SEC_FETCH_USER = ?F HTTP_UPGRADE_INSECURE_REQUESTS = 1 ============== Back Forward List ==============
diff --git a/third_party/blink/web_tests/http/tests/navigation/post-frames-goback1-expected.txt b/third_party/blink/web_tests/http/tests/navigation/post-frames-goback1-expected.txt index dc0b80f4..34f9b01 100644 --- a/third_party/blink/web_tests/http/tests/navigation/post-frames-goback1-expected.txt +++ b/third_party/blink/web_tests/http/tests/navigation/post-frames-goback1-expected.txt
@@ -19,7 +19,6 @@ HTTP_SEC_FETCH_DEST = nested-document HTTP_SEC_FETCH_MODE = nested-navigate HTTP_SEC_FETCH_SITE = same-origin -HTTP_SEC_FETCH_USER = ?F HTTP_UPGRADE_INSECURE_REQUESTS = 1 ============== Back Forward List ==============
diff --git a/third_party/blink/web_tests/http/tests/navigation/post-goback1-expected.txt b/third_party/blink/web_tests/http/tests/navigation/post-goback1-expected.txt index 19cd057..44c870e 100644 --- a/third_party/blink/web_tests/http/tests/navigation/post-goback1-expected.txt +++ b/third_party/blink/web_tests/http/tests/navigation/post-goback1-expected.txt
@@ -15,7 +15,6 @@ HTTP_SEC_FETCH_DEST = document HTTP_SEC_FETCH_MODE = navigate HTTP_SEC_FETCH_SITE = same-origin -HTTP_SEC_FETCH_USER = ?F HTTP_UPGRADE_INSECURE_REQUESTS = 1 ============== Back Forward List ==============
diff --git a/third_party/blink/web_tests/http/tests/navigation/rename-subframe-goback-expected.txt b/third_party/blink/web_tests/http/tests/navigation/rename-subframe-goback-expected.txt index bf24f6a..a7147c7 100644 --- a/third_party/blink/web_tests/http/tests/navigation/rename-subframe-goback-expected.txt +++ b/third_party/blink/web_tests/http/tests/navigation/rename-subframe-goback-expected.txt
@@ -23,5 +23,4 @@ HTTP_SEC_FETCH_DEST = nested-document HTTP_SEC_FETCH_MODE = nested-navigate HTTP_SEC_FETCH_SITE = same-origin -HTTP_SEC_FETCH_USER = ?F HTTP_UPGRADE_INSECURE_REQUESTS = 1
diff --git a/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/1.1/form-action-leak-path-on-redirect-expected.txt b/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/1.1/form-action-leak-path-on-redirect-expected.txt index ddca9e27..d78cc87 100644 --- a/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/1.1/form-action-leak-path-on-redirect-expected.txt +++ b/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/1.1/form-action-leak-path-on-redirect-expected.txt
@@ -11,7 +11,6 @@ HTTP_SEC_FETCH_DEST = document HTTP_SEC_FETCH_MODE = navigate HTTP_SEC_FETCH_SITE = same-origin -HTTP_SEC_FETCH_USER = ?F HTTP_UPGRADE_INSECURE_REQUESTS = 1 ============== Back Forward List ==============
diff --git a/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/1.1/form-action-src-allowed-expected.txt b/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/1.1/form-action-src-allowed-expected.txt index 8f5d29a..699d86f9 100644 --- a/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/1.1/form-action-src-allowed-expected.txt +++ b/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/1.1/form-action-src-allowed-expected.txt
@@ -14,7 +14,6 @@ HTTP_SEC_FETCH_DEST = document HTTP_SEC_FETCH_MODE = navigate HTTP_SEC_FETCH_SITE = same-origin -HTTP_SEC_FETCH_USER = ?F HTTP_UPGRADE_INSECURE_REQUESTS = 1 ============== Back Forward List ==============
diff --git a/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/1.1/form-action-src-allowed-with-redirect-expected.txt b/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/1.1/form-action-src-allowed-with-redirect-expected.txt index 7c7cb1c..36a810c 100644 --- a/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/1.1/form-action-src-allowed-with-redirect-expected.txt +++ b/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/1.1/form-action-src-allowed-with-redirect-expected.txt
@@ -11,7 +11,6 @@ HTTP_SEC_FETCH_DEST = document HTTP_SEC_FETCH_MODE = navigate HTTP_SEC_FETCH_SITE = same-origin -HTTP_SEC_FETCH_USER = ?F HTTP_UPGRADE_INSECURE_REQUESTS = 1 ============== Back Forward List ==============
diff --git a/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/1.1/form-action-src-default-ignored-expected.txt b/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/1.1/form-action-src-default-ignored-expected.txt index 25c99c6..eee3cd5 100644 --- a/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/1.1/form-action-src-default-ignored-expected.txt +++ b/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/1.1/form-action-src-default-ignored-expected.txt
@@ -14,7 +14,6 @@ HTTP_SEC_FETCH_DEST = document HTTP_SEC_FETCH_MODE = navigate HTTP_SEC_FETCH_SITE = same-origin -HTTP_SEC_FETCH_USER = ?F HTTP_UPGRADE_INSECURE_REQUESTS = 1 ============== Back Forward List ==============
diff --git a/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/1.1/form-action-src-default-ignored-with-redirect-expected.txt b/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/1.1/form-action-src-default-ignored-with-redirect-expected.txt index c162057c..962a40a 100644 --- a/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/1.1/form-action-src-default-ignored-with-redirect-expected.txt +++ b/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/1.1/form-action-src-default-ignored-with-redirect-expected.txt
@@ -11,7 +11,6 @@ HTTP_SEC_FETCH_DEST = document HTTP_SEC_FETCH_MODE = navigate HTTP_SEC_FETCH_SITE = same-origin -HTTP_SEC_FETCH_USER = ?F HTTP_UPGRADE_INSECURE_REQUESTS = 1 ============== Back Forward List ==============
diff --git a/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/1.1/form-action-src-get-allowed-expected.txt b/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/1.1/form-action-src-get-allowed-expected.txt index 20bbcf00..6c2b09e 100644 --- a/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/1.1/form-action-src-get-allowed-expected.txt +++ b/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/1.1/form-action-src-get-allowed-expected.txt
@@ -12,7 +12,6 @@ HTTP_SEC_FETCH_DEST = document HTTP_SEC_FETCH_MODE = navigate HTTP_SEC_FETCH_SITE = same-origin -HTTP_SEC_FETCH_USER = ?F HTTP_UPGRADE_INSECURE_REQUESTS = 1 ============== Back Forward List ==============
diff --git a/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/1.1/form-action-src-get-allowed-with-redirect-expected.txt b/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/1.1/form-action-src-get-allowed-with-redirect-expected.txt index e854d82..4747b394 100644 --- a/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/1.1/form-action-src-get-allowed-with-redirect-expected.txt +++ b/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/1.1/form-action-src-get-allowed-with-redirect-expected.txt
@@ -11,7 +11,6 @@ HTTP_SEC_FETCH_DEST = document HTTP_SEC_FETCH_MODE = navigate HTTP_SEC_FETCH_SITE = same-origin -HTTP_SEC_FETCH_USER = ?F HTTP_UPGRADE_INSECURE_REQUESTS = 1 ============== Back Forward List ==============
diff --git a/third_party/blink/web_tests/http/tests/serviceworker/fetch-event-headers.html b/third_party/blink/web_tests/http/tests/serviceworker/fetch-event-headers.html index f94a01a..e98cbba 100644 --- a/third_party/blink/web_tests/http/tests/serviceworker/fetch-event-headers.html +++ b/third_party/blink/web_tests/http/tests/serviceworker/fetch-event-headers.html
@@ -31,7 +31,7 @@ header_names.sort(); assert_array_equals( header_names, - ["accept", "sec-fetch-dest", "sec-fetch-mode", "sec-fetch-site", "sec-fetch-user", "upgrade-insecure-requests", "user-agent"], + ["accept", "sec-fetch-dest", "sec-fetch-mode", "sec-fetch-site", "upgrade-insecure-requests", "user-agent"], 'event.request has the expected headers.'); return service_worker_unregister_and_done(t, scope);
diff --git a/third_party/blink/web_tests/media/mediasession/mojo/callback-alive-after-gc.html b/third_party/blink/web_tests/media/mediasession/mojo/callback-alive-after-gc.html index 7f516044..fa105d5c 100644 --- a/third_party/blink/web_tests/media/mediasession/mojo/callback-alive-after-gc.html +++ b/third_party/blink/web_tests/media/mediasession/mojo/callback-alive-after-gc.html
@@ -5,7 +5,7 @@ <script src="../../../resources/gc.js"></script> <script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script> <script src="file:///gen/services/media_session/public/mojom/media_session.mojom.js"></script> -<script src="file:///gen/third_party/blink/public/platform/modules/mediasession/media_session.mojom.js"></script> +<script src="file:///gen/third_party/blink/public/mojom/mediasession/media_session.mojom.js"></script> <script src="resources/mediasessionservice-mock.js"></script> <script src="resources/utils.js"></script> <script>
diff --git a/third_party/blink/web_tests/media/mediasession/mojo/file-image-removed.html b/third_party/blink/web_tests/media/mediasession/mojo/file-image-removed.html index dbbf316..f2e2484 100644 --- a/third_party/blink/web_tests/media/mediasession/mojo/file-image-removed.html +++ b/third_party/blink/web_tests/media/mediasession/mojo/file-image-removed.html
@@ -3,7 +3,7 @@ <script src="../../../resources/testharness.js"></script> <script src="../../../resources/testharnessreport.js"></script> <script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script> -<script src="file:///gen/third_party/blink/public/platform/modules/mediasession/media_session.mojom.js"></script> +<script src="file:///gen/third_party/blink/public/mojom/mediasession/media_session.mojom.js"></script> <script src="resources/mediasessionservice-mock.js"></script> <script src="resources/utils.js"></script> <script>
diff --git a/third_party/blink/web_tests/media/mediasession/mojo/media-control-action-reaches-client.html b/third_party/blink/web_tests/media/mediasession/mojo/media-control-action-reaches-client.html index 4640c19..3033ec9 100644 --- a/third_party/blink/web_tests/media/mediasession/mojo/media-control-action-reaches-client.html +++ b/third_party/blink/web_tests/media/mediasession/mojo/media-control-action-reaches-client.html
@@ -4,7 +4,7 @@ <script src="../../../resources/testharnessreport.js"></script> <script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script> <script src="file:///gen/services/media_session/public/mojom/media_session.mojom.js"></script> -<script src="file:///gen/third_party/blink/public/platform/modules/mediasession/media_session.mojom.js"></script> +<script src="file:///gen/third_party/blink/public/mojom/mediasession/media_session.mojom.js"></script> <script src="resources/mediasessionservice-mock.js"></script> <script src="resources/utils.js"></script> <script>
diff --git a/third_party/blink/web_tests/media/mediasession/mojo/media-control-set-handler-notifies-service.html b/third_party/blink/web_tests/media/mediasession/mojo/media-control-set-handler-notifies-service.html index 2806f8ce..6e70a67 100644 --- a/third_party/blink/web_tests/media/mediasession/mojo/media-control-set-handler-notifies-service.html +++ b/third_party/blink/web_tests/media/mediasession/mojo/media-control-set-handler-notifies-service.html
@@ -4,7 +4,7 @@ <script src="../../../resources/testharnessreport.js"></script> <script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script> <script src="file:///gen/services/media_session/public/mojom/media_session.mojom.js"></script> -<script src="file:///gen/third_party/blink/public/platform/modules/mediasession/media_session.mojom.js"></script> +<script src="file:///gen/third_party/blink/public/mojom/mediasession/media_session.mojom.js"></script> <script src="resources/mediasessionservice-mock.js"></script> <script src="resources/utils.js"></script> <script>
diff --git a/third_party/blink/web_tests/media/mediasession/mojo/metadata-async.html b/third_party/blink/web_tests/media/mediasession/mojo/metadata-async.html index 65cab89..5a726b0 100644 --- a/third_party/blink/web_tests/media/mediasession/mojo/metadata-async.html +++ b/third_party/blink/web_tests/media/mediasession/mojo/metadata-async.html
@@ -3,7 +3,7 @@ <script src="../../../resources/testharness.js"></script> <script src="../../../resources/testharnessreport.js"></script> <script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script> -<script src="file:///gen/third_party/blink/public/platform/modules/mediasession/media_session.mojom.js"></script> +<script src="file:///gen/third_party/blink/public/mojom/mediasession/media_session.mojom.js"></script> <script src="resources/mediasessionservice-mock.js"></script> <script src="resources/utils.js"></script> <script>
diff --git a/third_party/blink/web_tests/media/mediasession/mojo/metadata-propagated-twice.html b/third_party/blink/web_tests/media/mediasession/mojo/metadata-propagated-twice.html index e11f5c6..dbdff47 100644 --- a/third_party/blink/web_tests/media/mediasession/mojo/metadata-propagated-twice.html +++ b/third_party/blink/web_tests/media/mediasession/mojo/metadata-propagated-twice.html
@@ -3,7 +3,7 @@ <script src="../../../resources/testharness.js"></script> <script src="../../../resources/testharnessreport.js"></script> <script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script> -<script src="file:///gen/third_party/blink/public/platform/modules/mediasession/media_session.mojom.js"></script> +<script src="file:///gen/third_party/blink/public/mojom/mediasession/media_session.mojom.js"></script> <script src="resources/mediasessionservice-mock.js"></script> <script src="resources/utils.js"></script> <script>
diff --git a/third_party/blink/web_tests/media/mediasession/mojo/metadata-propagated.html b/third_party/blink/web_tests/media/mediasession/mojo/metadata-propagated.html index d0b55dda..31fa8bf8 100644 --- a/third_party/blink/web_tests/media/mediasession/mojo/metadata-propagated.html +++ b/third_party/blink/web_tests/media/mediasession/mojo/metadata-propagated.html
@@ -3,7 +3,7 @@ <script src="../../../resources/testharness.js"></script> <script src="../../../resources/testharnessreport.js"></script> <script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script> -<script src="file:///gen/third_party/blink/public/platform/modules/mediasession/media_session.mojom.js"></script> +<script src="file:///gen/third_party/blink/public/mojom/mediasession/media_session.mojom.js"></script> <script src="resources/mediasessionservice-mock.js"></script> <script src="resources/utils.js"></script> <script>
diff --git a/third_party/blink/web_tests/media/mediasession/mojo/metadata-session-link.html b/third_party/blink/web_tests/media/mediasession/mojo/metadata-session-link.html index 961daef..6d6fe39 100644 --- a/third_party/blink/web_tests/media/mediasession/mojo/metadata-session-link.html +++ b/third_party/blink/web_tests/media/mediasession/mojo/metadata-session-link.html
@@ -3,7 +3,7 @@ <script src="../../../resources/testharness.js"></script> <script src="../../../resources/testharnessreport.js"></script> <script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script> -<script src="file:///gen/third_party/blink/public/platform/modules/mediasession/media_session.mojom.js"></script> +<script src="file:///gen/third_party/blink/public/mojom/mediasession/media_session.mojom.js"></script> <script src="resources/mediasessionservice-mock.js"></script> <script src="resources/utils.js"></script> <script>
diff --git a/third_party/blink/web_tests/media/mediasession/mojo/playback-state-propagated.html b/third_party/blink/web_tests/media/mediasession/mojo/playback-state-propagated.html index de80e260..918aa46 100644 --- a/third_party/blink/web_tests/media/mediasession/mojo/playback-state-propagated.html +++ b/third_party/blink/web_tests/media/mediasession/mojo/playback-state-propagated.html
@@ -3,7 +3,7 @@ <script src="../../../resources/testharness.js"></script> <script src="../../../resources/testharnessreport.js"></script> <script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script> -<script src="file:///gen/third_party/blink/public/platform/modules/mediasession/media_session.mojom.js"></script> +<script src="file:///gen/third_party/blink/public/mojom/mediasession/media_session.mojom.js"></script> <script src="resources/mediasessionservice-mock.js"></script> <script src="resources/utils.js"></script> <script>
diff --git a/third_party/blink/web_tests/media/mediasession/mojo/set-null-metadata.html b/third_party/blink/web_tests/media/mediasession/mojo/set-null-metadata.html index f786142a..db3479a 100644 --- a/third_party/blink/web_tests/media/mediasession/mojo/set-null-metadata.html +++ b/third_party/blink/web_tests/media/mediasession/mojo/set-null-metadata.html
@@ -3,7 +3,7 @@ <script src="../../../resources/testharness.js"></script> <script src="../../../resources/testharnessreport.js"></script> <script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script> -<script src="file:///gen/third_party/blink/public/platform/modules/mediasession/media_session.mojom.js"></script> +<script src="file:///gen/third_party/blink/public/mojom/mediasession/media_session.mojom.js"></script> <script src="resources/mediasessionservice-mock.js"></script> <script src="resources/utils.js"></script> <script>
diff --git a/third_party/blink/web_tests/platform/mac/compositing/lots-of-img-layers-with-opacity-expected.png b/third_party/blink/web_tests/platform/mac/compositing/lots-of-img-layers-with-opacity-expected.png deleted file mode 100644 index fdae228..0000000 --- a/third_party/blink/web_tests/platform/mac/compositing/lots-of-img-layers-with-opacity-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/compositing/lots-of-img-layers-with-opacity-expected.png b/third_party/blink/web_tests/platform/win/compositing/lots-of-img-layers-with-opacity-expected.png deleted file mode 100644 index 511dca7..0000000 --- a/third_party/blink/web_tests/platform/win/compositing/lots-of-img-layers-with-opacity-expected.png +++ /dev/null Binary files differ
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index fac3068..f289ed1 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -1657,6 +1657,13 @@ <int value="4" label="Failed: Cannot sign in as previous user"/> </enum> +<enum name="AndroidSearchEngineChoiceEvents"> + <summary>Events related to Search Engine Choice feature.</summary> + <int value="0" label="Snackbar shown"/> + <int value="1" label="Prompt followed"/> + <int value="2" label="Search engine changed"/> +</enum> + <enum name="AndroidSeccompSandboxStatus"> <int value="0" label="Not Supported"/> <int value="1" label="Detection Failed"/> @@ -32277,6 +32284,7 @@ <int value="-1604051051" label="SpecialLocale:disabled"/> <int value="-1603404046" label="V8VmFuture:disabled"/> <int value="-1599538279" label="enable-md-policy-page"/> + <int value="-1596859081" label="WebAuthenticationPINSupport:enabled"/> <int value="-1596559650" label="max-tiles-for-interest-area"/> <int value="-1594298767" label="FullscreenToolbarReveal:enabled"/> <int value="-1586642651" label="MaterialDesignExtensions:disabled"/> @@ -33717,6 +33725,7 @@ <int value="723619383" label="TopSitesFromSiteEngagement:enabled"/> <int value="724052572" label="EnableFilesystemInIncognito"/> <int value="724208771" label="TabsInCBD:enabled"/> + <int value="724427456" label="WebAuthenticationPINSupport:disabled"/> <int value="725270017" label="ScrollAnchorSerialization:disabled"/> <int value="726764779" label="WebXRGamepadSupport:enabled"/> <int value="727270087" label="PromosOnLocalNtp:enabled"/> @@ -50872,6 +50881,7 @@ <int value="28" label="UMA_TWA_PRIVACY_DISCLOSURE"/> <int value="29" label="UMA_AUTOFILL_ASSISTANT_STOP_UNDO"/> <int value="30" label="UMA_TAB_CLOSE_MULTIPLE_UNDO"/> + <int value="31" label="UMA_SEARCH_ENGINE_CHOICE_NOTIFICATION"/> </enum> <enum name="SnippetOpenMethod">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 77f6098..301718b 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -2775,6 +2775,35 @@ </summary> </histogram> +<histogram name="Android.SearchEngineChoice.ChosenSearchEngine" + enum="OmniboxSearchEngineType" expires_after="2020-04-01"> + <owner>fgorski@chromium.org</owner> + <owner>lzbylut@chromium.org</owner> + <summary> + The type of the search engine chosen by the user in Search Engine Choice + flow. + </summary> +</histogram> + +<histogram name="Android.SearchEngineChoice.Events" + enum="AndroidSearchEngineChoiceEvents" expires_after="2020-04-01"> + <owner>fgorski@chromium.org</owner> + <owner>lzbylut@chromium.org</owner> + <summary> + Counts occurences of various events related to Search Engine Choice feature. + </summary> +</histogram> + +<histogram name="Android.SearchEngineChoice.SearchEngineBeforeChoicePrompt" + enum="OmniboxSearchEngineType" expires_after="2020-04-01"> + <owner>fgorski@chromium.org</owner> + <owner>lzbylut@chromium.org</owner> + <summary> + The type of the search engine used before Search Engine Choice flow was + presented. + </summary> +</histogram> + <histogram name="Android.SeccompStatus.PhotoPickerSandbox" enum="AndroidSeccompSandboxStatus"> <owner>peter@chromium.org</owner> @@ -10045,6 +10074,14 @@ </summary> </histogram> +<histogram name="AutoScreenBrightness.MissingAlsWhenBrightnessChanged" + enum="BooleanError" expires_after="2019-12-31"> + <owner>jiameng@chromium.org</owner> + <summary> + Whether there was no recorded ALS reading when brightness was changed. + </summary> +</histogram> + <histogram name="AutoScreenBrightness.NewCurveSaved.Duration" units="ms" expires_after="2019-12-31"> <owner>jiameng@chromium.org</owner>
diff --git a/ui/android/java/src/org/chromium/ui/resources/ResourceExtractor.java b/ui/android/java/src/org/chromium/ui/resources/ResourceExtractor.java index 5f6e5a8..123c8f1f 100644 --- a/ui/android/java/src/org/chromium/ui/resources/ResourceExtractor.java +++ b/ui/android/java/src/org/chromium/ui/resources/ResourceExtractor.java
@@ -5,8 +5,6 @@ package org.chromium.ui.resources; import android.content.res.AssetManager; -import android.os.Handler; -import android.os.Looper; import org.chromium.base.BuildConfig; import org.chromium.base.BuildInfo; @@ -17,7 +15,8 @@ import org.chromium.base.PathUtils; import org.chromium.base.ThreadUtils; import org.chromium.base.TraceEvent; -import org.chromium.base.task.AsyncTask; +import org.chromium.base.task.PostTask; +import org.chromium.base.task.TaskTraits; import org.chromium.ui.base.LocalizationUtils; import java.io.File; @@ -27,6 +26,7 @@ import java.util.Arrays; import java.util.List; import java.util.Locale; +import java.util.concurrent.CountDownLatch; /** * Handles extracting the necessary resources bundled in an APK and moving them to a location on @@ -42,9 +42,33 @@ private static final String COMPRESSED_LOCALES_FALLBACK_DIR = "fallback-locales"; private static final int BUFFER_SIZE = 16 * 1024; - private class ExtractTask extends AsyncTask<Void> { + private class ExtractTask implements Runnable { private final List<Runnable> mCompletionCallbacks = new ArrayList<Runnable>(); private final String mUiLanguage; + private final CountDownLatch mLatch = new CountDownLatch(1); + private boolean mDone; + + public ExtractTask(String uiLanguage) { + mUiLanguage = uiLanguage; + } + + @Override + public void run() { + try (TraceEvent e = TraceEvent.scoped("ResourceExtractor.ExtractTask.doInBackground")) { + doInBackgroundImpl(); + } + synchronized (this) { + mDone = true; + } + mLatch.countDown(); + + PostTask.postTask(mResultTaskTraits, () -> { + try (TraceEvent e = + TraceEvent.scoped("ResourceExtractor.ExtractTask.onPostExecute")) { + onPostExecuteImpl(); + } + }); + } private void doInBackgroundImpl() { final File outputDir = getOutputDir(); @@ -98,40 +122,25 @@ } } - @Override - protected Void doInBackground() { - TraceEvent.begin("ResourceExtractor.ExtractTask.doInBackground"); - try { - doInBackgroundImpl(); - } finally { - TraceEvent.end("ResourceExtractor.ExtractTask.doInBackground"); - } - return null; - } - private void onPostExecuteImpl() { + ThreadUtils.assertOnUiThread(); for (int i = 0; i < mCompletionCallbacks.size(); i++) { mCompletionCallbacks.get(i).run(); } mCompletionCallbacks.clear(); } - @Override - protected void onPostExecute(Void result) { - TraceEvent.begin("ResourceExtractor.ExtractTask.onPostExecute"); - try { - onPostExecuteImpl(); - } finally { - TraceEvent.end("ResourceExtractor.ExtractTask.onPostExecute"); - } + public void await() throws Exception { + mLatch.await(); } - public ExtractTask(String uiLanguage) { - mUiLanguage = uiLanguage; + public synchronized boolean isDone() { + return mDone; } } private ExtractTask mExtractTask; + private TaskTraits mResultTaskTraits; private static ResourceExtractor sInstance; @@ -264,13 +273,20 @@ } try { - mExtractTask.get(); + mExtractTask.await(); } catch (Exception e) { assert false; } } /** + * Sets the traits to use for the reply task. + */ + public void setResultTraits(TaskTraits traits) { + mResultTaskTraits = traits; + } + + /** * Adds a callback to be notified upon the completion of resource extraction. * <p> * If the resource task has already completed, the callback will be posted to the UI message @@ -284,16 +300,14 @@ public void addCompletionCallback(Runnable callback) { ThreadUtils.assertOnUiThread(); - Handler handler = new Handler(Looper.getMainLooper()); if (shouldSkipPakExtraction()) { - handler.post(callback); + PostTask.postTask(mResultTaskTraits, callback); return; } assert mExtractTask != null; - assert !mExtractTask.isCancelled(); - if (mExtractTask.getStatus() == AsyncTask.Status.FINISHED) { - handler.post(callback); + if (mExtractTask.isDone()) { + PostTask.postTask(mResultTaskTraits, callback); } else { mExtractTask.mCompletionCallbacks.add(callback); } @@ -303,6 +317,8 @@ * This will extract the application pak resources in an * AsyncTask. Call waitForCompletion() at the point resources * are needed to block until the task completes. + * + * @param uiLanguage The language to extract. */ public void startExtractingResources(String uiLanguage) { if (mExtractTask != null) { @@ -318,7 +334,7 @@ } mExtractTask = new ExtractTask(uiLanguage); - mExtractTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + PostTask.postTask(TaskTraits.USER_BLOCKING, mExtractTask); } private File getAppDataDir() {
diff --git a/ui/gl/android/android_surface_control_compat.cc b/ui/gl/android/android_surface_control_compat.cc index a2ffb6c5..6cdf316 100644 --- a/ui/gl/android/android_surface_control_compat.cc +++ b/ui/gl/android/android_surface_control_compat.cc
@@ -7,9 +7,11 @@ #include <dlfcn.h> #include "base/android/build_info.h" +#include "base/atomic_sequence_num.h" #include "base/bind.h" #include "base/memory/ptr_util.h" #include "base/no_destructor.h" +#include "base/trace_event/trace_event.h" #include "ui/gfx/color_space.h" extern "C" { @@ -100,6 +102,8 @@ namespace gl { namespace { +base::AtomicSequenceNumber g_next_transaction_id; + // Helper function to log errors from dlsym. Calling LOG(ERROR) inside a macro // crashes clang code coverage. https://crbug.com/843356 void LogDlsymError(const char* func) { @@ -257,6 +261,7 @@ } struct TransactionAckCtx { + int id = 0; scoped_refptr<base::SingleThreadTaskRunner> task_runner; SurfaceControl::Transaction::OnCompleteCb callback; }; @@ -276,6 +281,7 @@ std::move(ack_ctx->callback).Run(std::move(transaction_stats)); } + TRACE_EVENT_ASYNC_END0("gpu", "SurfaceControlTransaction", ack_ctx->id); delete ack_ctx; } } // namespace @@ -331,13 +337,34 @@ SurfaceControl::TransactionStats& SurfaceControl::TransactionStats::operator=( TransactionStats&& other) = default; -SurfaceControl::Transaction::Transaction() { +SurfaceControl::Transaction::Transaction() + : id_(g_next_transaction_id.GetNext()) { transaction_ = SurfaceControlMethods::Get().ASurfaceTransaction_createFn(); DCHECK(transaction_); } SurfaceControl::Transaction::~Transaction() { - SurfaceControlMethods::Get().ASurfaceTransaction_deleteFn(transaction_); + if (transaction_) + SurfaceControlMethods::Get().ASurfaceTransaction_deleteFn(transaction_); +} + +SurfaceControl::Transaction::Transaction(Transaction&& other) + : id_(other.id_), transaction_(other.transaction_) { + other.transaction_ = nullptr; + other.id_ = 0; +} + +SurfaceControl::Transaction& SurfaceControl::Transaction::operator=( + Transaction&& other) { + if (transaction_) + SurfaceControlMethods::Get().ASurfaceTransaction_deleteFn(transaction_); + + transaction_ = other.transaction_; + id_ = other.id_; + + other.transaction_ = nullptr; + other.id_ = 0; + return *this; } void SurfaceControl::Transaction::SetVisibility(const Surface& surface, @@ -396,12 +423,14 @@ TransactionAckCtx* ack_ctx = new TransactionAckCtx; ack_ctx->callback = std::move(cb); ack_ctx->task_runner = std::move(task_runner); + ack_ctx->id = id_; SurfaceControlMethods::Get().ASurfaceTransaction_setOnCompleteFn( transaction_, ack_ctx, &OnTransactionCompletedOnAnyThread); } void SurfaceControl::Transaction::Apply() { + TRACE_EVENT_ASYNC_BEGIN0("gpu", "SurfaceControlTransaction", id_); SurfaceControlMethods::Get().ASurfaceTransaction_applyFn(transaction_); }
diff --git a/ui/gl/android/android_surface_control_compat.h b/ui/gl/android/android_surface_control_compat.h index 7a292f4..46d5928 100644 --- a/ui/gl/android/android_surface_control_compat.h +++ b/ui/gl/android/android_surface_control_compat.h
@@ -92,6 +92,9 @@ Transaction(); ~Transaction(); + Transaction(Transaction&& other); + Transaction& operator=(Transaction&& other); + void SetVisibility(const Surface& surface, bool show); void SetZOrder(const Surface& surface, int32_t z); void SetBuffer(const Surface& surface, @@ -118,7 +121,10 @@ void Apply(); private: + int id_; ASurfaceTransaction* transaction_; + + DISALLOW_COPY_AND_ASSIGN(Transaction); }; }; } // namespace gl
diff --git a/ui/gl/gl_surface_egl_surface_control.cc b/ui/gl/gl_surface_egl_surface_control.cc index ec92d2e..78a3eb8 100644 --- a/ui/gl/gl_surface_egl_surface_control.cc +++ b/ui/gl/gl_surface_egl_surface_control.cc
@@ -161,13 +161,20 @@ std::move(present_callback), std::move(resources_to_release)); pending_transaction_->SetOnCompleteCb(std::move(callback), gpu_task_runner_); - pending_transaction_acks_++; - pending_transaction_->Apply(); - pending_transaction_.reset(); - - DCHECK_GE(surface_list_.size(), pending_surfaces_count_); + // Cache only those surfaces which were used in this transaction. The surfaces + // removed here are persisted in |resources_to_release| so we can release + // them after receiving read fences from the framework. surface_list_.resize(pending_surfaces_count_); pending_surfaces_count_ = 0u; + + if (transaction_ack_pending_) { + pending_transaction_queue_.push(std::move(pending_transaction_).value()); + } else { + transaction_ack_pending_ = true; + pending_transaction_->Apply(); + } + + pending_transaction_.reset(); } gfx::Size GLSurfaceEGLSurfaceControl::GetSize() { @@ -311,9 +318,9 @@ ResourceRefs released_resources, SurfaceControl::TransactionStats transaction_stats) { DCHECK(gpu_task_runner_->BelongsToCurrentThread()); - DCHECK_GT(pending_transaction_acks_, 0u); + DCHECK(transaction_ack_pending_); - pending_transaction_acks_--; + transaction_ack_pending_ = false; // The presentation feedback callback must run after swap completion. std::move(completion_callback).Run(gfx::SwapResult::SWAP_ACK, nullptr); @@ -351,6 +358,12 @@ // which were updated in that transaction, the surfaces with no buffer updates // won't be present in the ack. released_resources.clear(); + + if (!pending_transaction_queue_.empty()) { + transaction_ack_pending_ = true; + pending_transaction_queue_.front().Apply(); + pending_transaction_queue_.pop(); + } } GLSurfaceEGLSurfaceControl::SurfaceState::SurfaceState(
diff --git a/ui/gl/gl_surface_egl_surface_control.h b/ui/gl/gl_surface_egl_surface_control.h index 80466a68..afb0106 100644 --- a/ui/gl/gl_surface_egl_surface_control.h +++ b/ui/gl/gl_surface_egl_surface_control.h
@@ -137,26 +137,23 @@ // Holds the surface state changes made since the last call to SwapBuffers. base::Optional<SurfaceControl::Transaction> pending_transaction_; - - // The list of Surfaces and the corresponding state. The initial - // |pending_surfaces_count_| surfaces in this list are surfaces with state - // mutated since the last SwapBuffers with the updates collected in - // |pending_transaction_|. - // On the next SwapBuffers, the updates in the transaction are applied - // atomically and any surfaces in |surface_list_| which are not reused in this - // frame are destroyed. - std::vector<SurfaceState> surface_list_; size_t pending_surfaces_count_ = 0u; - // Resources in the pending frame, for which updates are being // collected in |pending_transaction_|. These are resources for which the // pending transaction has a ref but they have not been applied and // transferred to the framework. ResourceRefs pending_frame_resources_; - // Resources in the current frame sent to the framework. The - // framework is assumed to retain ownership of these resources until the next - // frame update. + // Transactions waiting to be applied once the previous transaction is acked. + std::queue<SurfaceControl::Transaction> pending_transaction_queue_; + + // The list of Surfaces and the corresponding state based on the most recent + // updates. + std::vector<SurfaceState> surface_list_; + + // Resources in the previous transaction sent or queued to be sent to the + // framework. The framework is assumed to retain ownership of these resources + // until the next frame update. ResourceRefs current_frame_resources_; // The root surface tied to the ANativeWindow that places the content of this @@ -166,8 +163,8 @@ // The last context made current with this surface. scoped_refptr<GLContext> context_; - // Number of transaction which have been applied and are awaiting an ack. - size_t pending_transaction_acks_ = 0; + // Set if a transaction was applied and we are waiting for it to be acked. + bool transaction_ack_pending_ = false; scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner_; base::WeakPtrFactory<GLSurfaceEGLSurfaceControl> weak_factory_;
diff --git a/ui/views/view.cc b/ui/views/view.cc index 52a65e76..f6f61c6 100644 --- a/ui/views/view.cc +++ b/ui/views/view.cc
@@ -156,20 +156,24 @@ void View::ReorderChildView(View* view, int index) { DCHECK_EQ(view->parent_, this); - if (index < 0) - index = child_count() - 1; - else if (index >= child_count()) - return; - if (children_[index] == view) + const auto i = std::find(children_.begin(), children_.end(), view); + DCHECK(i != children_.end()); + + // If |view| is already at the desired position, there's nothing to do. + const bool move_to_end = (index < 0) || (size_t{index} >= children_.size()); + const auto pos = move_to_end ? std::prev(children_.end()) + : std::next(children_.begin(), index); + if (i == pos) return; - const Views::iterator i(std::find(children_.begin(), children_.end(), view)); - DCHECK(i != children_.end()); + // Rotate |view| to be at the desired position. #if DCHECK_IS_ON() DCHECK(!iterating_); #endif - children_.erase(i); - const auto pos = children_.insert(std::next(children_.begin(), index), view); + if (pos < i) + std::rotate(pos, i, std::next(i)); + else + std::rotate(i, std::next(i), std::next(pos)); // Update focus siblings. Unhook |view| from the focus cycle first so // SetFocusSiblings() won't traverse through it.
diff --git a/ui/views/view_unittest.cc b/ui/views/view_unittest.cc index 31eb14b..46e3f804 100644 --- a/ui/views/view_unittest.cc +++ b/ui/views/view_unittest.cc
@@ -3682,10 +3682,10 @@ EXPECT_EQ(0, v1.GetIndexOf(&v2)); EXPECT_EQ(1, v1.GetIndexOf(&v3)); - // Check that calling |AddChildView()| does not change the order. + // Check that calling AddChildView() moves to the end. v1.AddChildView(&v2); - EXPECT_EQ(0, v1.GetIndexOf(&v2)); - EXPECT_EQ(1, v1.GetIndexOf(&v3)); + EXPECT_EQ(1, v1.GetIndexOf(&v2)); + EXPECT_EQ(0, v1.GetIndexOf(&v3)); v1.AddChildView(&v3); EXPECT_EQ(0, v1.GetIndexOf(&v2)); EXPECT_EQ(1, v1.GetIndexOf(&v3));