diff --git a/.gitignore b/.gitignore index f2ebb3e..57e16a3 100644 --- a/.gitignore +++ b/.gitignore
@@ -83,10 +83,6 @@ /chrome/android/profiles/local.txt /chrome/angle_unittests_run.xml /chrome/app/vector_icons/google_chrome/ -/chrome/build/chrome.x64.orderfile -/chrome/build/chrome.x86.orderfile -/chrome/build/chrome_child.x64.orderfile -/chrome/build/chrome_child.x86.orderfile /chrome/build/pgo_profiles/ /chrome/gl_tests_run.xml /chrome/gles2_conform_test_run.xml
diff --git a/DEPS b/DEPS index a1dfeb4..6db5c18 100644 --- a/DEPS +++ b/DEPS
@@ -197,11 +197,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': '75ae8fcc319ed197360117c41adcf496fa7cd208', + 'skia_revision': '753e7983e04e845fec400fb3876116fe545f3fe5', # 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': '47d4ef3f896251f8ea86f2f529d46e54a7262278', + 'v8_revision': '94b2c943f7f37e0450e7c5d029fbd22a9d7f6946', # 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. @@ -209,11 +209,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - 'angle_revision': 'c151f873e4ab63fd8f58dd20864e444abfe39395', + 'angle_revision': '353770e13361f893f63cd1567db48417d65c267e', # 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': '060020166679a265a2bc8250f4d78a7a8c29de89', + 'swiftshader_revision': 'de9e649438ed3cc2ecf5c30ebf08f033d01270e6', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. @@ -244,7 +244,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling NaCl # and whatever else without interference from each other. - 'nacl_revision': 'f9e6f257d1a0934dbeed3c5c8f83b651dc4f55e1', + 'nacl_revision': '3ac0b060c794b64531b47dfded8ff8d951a5c648', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling freetype # and whatever else without interference from each other. @@ -272,7 +272,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling devtools-frontend # and whatever else without interference from each other. - 'devtools_frontend_revision': '1a5d5109644a9204fea2155bca0936287d5ffc54', + 'devtools_frontend_revision': '20cc9eb2a7f5203097f688f7b42bca9accfa6e94', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libprotobuf-mutator # and whatever else without interference from each other. @@ -324,7 +324,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'dawn_revision': 'dad44f4d824ef71a4364f0aedae30b74085a7adb', + 'dawn_revision': '1a14e7e0244114fe737caf46e3a2690355aceafe', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -887,7 +887,7 @@ # Tools used when building Chrome for Chrome OS. This affects both the Simple # Chrome workflow, as well as the chromeos-chrome ebuild. 'src/third_party/chromite': { - 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'fa9411e0a2423ca738adaa72b8315ea48a30f911', + 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'f577788041b61d7417cc5c9bb2aeba142ef13324', 'condition': 'checkout_chromeos', }, @@ -1600,7 +1600,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@745ab6e3c09a6a3426f48b688b602ac8f9780449', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@d8f42ea938ea558d8a1a5a4bd169d7cd0eebbee6', 'condition': 'checkout_src_internal', }, @@ -1608,7 +1608,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/help_app/app', - 'version': 'vYtTShBj1xqnqgqJLKObuX6STR_IQfyEJaxLgFcIolMC', + 'version': 'zwjjfdu5X9OPcMNJ2vD6-qpbr5JfXymOFoQz-LOYG6cC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal', @@ -1619,7 +1619,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/media_app/app', - 'version': 'APA3S0RS-YgKZ3C9_oaQI7zzKGGpgA7civ7-QUPYY0kC', + 'version': 'diLwXTxdRV6cbd18SoCniJNniVTvHD4wv7-x_eVBHkkC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal', @@ -4459,20 +4459,6 @@ '--bucket', 'chromium-webrtc-resources', '-d', 'src/third_party/opus/tests/resources'], }, - # Pull order files for the win/clang build. - { - 'name': 'orderfiles_win', - 'pattern': '.', - 'condition': 'checkout_win', - 'action': [ 'python', - 'src/third_party/depot_tools/download_from_google_storage.py', - '--no_resume', - '--no_auth', - '--num_threads=4', - '--bucket', 'chromium-browser-clang/orderfiles', - '-d', 'src/chrome/build', - ], - }, { 'name': 'apache_mac', 'pattern': '\\.sha1',
diff --git a/android_webview/OWNERS b/android_webview/OWNERS index 33ecbfda..7e81d72 100644 --- a/android_webview/OWNERS +++ b/android_webview/OWNERS
@@ -5,7 +5,7 @@ torne@chromium.org # Documentation changes: -per-file *.md=ntfschr@chromium.org +per-file *.md=file://android_webview/docs/OWNERS # Build file refactoring: per-file *.gn=ntfschr@chromium.org
diff --git a/android_webview/browser/gfx/scoped_app_gl_state_restore.cc b/android_webview/browser/gfx/scoped_app_gl_state_restore.cc index 47ad456..a51c8944 100644 --- a/android_webview/browser/gfx/scoped_app_gl_state_restore.cc +++ b/android_webview/browser/gfx/scoped_app_gl_state_restore.cc
@@ -225,20 +225,21 @@ glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &g_gl_max_vertex_attribs); glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &g_gl_max_texture_units); - std::string extensions; - const char* extensions_c_str = + const char* extensions_string = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS)); - if (extensions_c_str) - extensions = extensions_c_str; - g_supports_oes_vertex_array_object = - extensions.find("GL_OES_vertex_array_object") != std::string::npos; - g_supports_arm_shader_framebuffer_fetch = - extensions.find("GL_ARM_shader_framebuffer_fetch") != std::string::npos; - g_supports_nv_concervative_raster = - extensions.find("GL_NV_conservative_raster") != std::string::npos; - g_supports_disable_multisample = - extensions.find("GL_EXT_multisample_compatibility") != - std::string::npos; + + if (extensions_string) { + gfx::ExtensionSet extensions(gfx::MakeExtensionSet(extensions_string)); + + g_supports_oes_vertex_array_object = + extensions.contains("GL_OES_vertex_array_object"); + g_supports_arm_shader_framebuffer_fetch = + extensions.contains("GL_ARM_shader_framebuffer_fetch"); + g_supports_nv_concervative_raster = + extensions.contains("GL_NV_conservative_raster"); + g_supports_disable_multisample = + extensions.contains("GL_EXT_multisample_compatibility"); + } g_use_skia_renderer = features::IsUsingSkiaRenderer(); }
diff --git a/android_webview/java/src/org/chromium/android_webview/AwBrowserProcess.java b/android_webview/java/src/org/chromium/android_webview/AwBrowserProcess.java index 982a98bb..648981e7be 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwBrowserProcess.java +++ b/android_webview/java/src/org/chromium/android_webview/AwBrowserProcess.java
@@ -297,49 +297,55 @@ */ public static void handleMinidumps(final boolean userApproved) { sSequencedTaskRunner.postTask(() -> { - final Context appContext = ContextUtils.getApplicationContext(); - final File crashSpoolDir = new File(appContext.getCacheDir().getPath(), "WebView"); - if (!crashSpoolDir.isDirectory()) return; - final CrashFileManager crashFileManager = new CrashFileManager(crashSpoolDir); + try { + final Context appContext = ContextUtils.getApplicationContext(); + final File cacheDir = new File(PathUtils.getCacheDirectory()); + final CrashFileManager crashFileManager = new CrashFileManager(cacheDir); - // The lifecycle of a minidump in the app directory is very simple: foo.dmpNNNNN -- - // where NNNNN is a Process ID (PID) -- gets created, and is either deleted or - // copied over to the shared crash directory for all WebView-using apps. - Map<String, Map<String, String>> crashesInfoMap = - crashFileManager.importMinidumpsCrashKeys(); - final File[] minidumpFiles = crashFileManager.getCurrentMinidumpsSansLogcat(); - if (minidumpFiles.length == 0) return; + // The lifecycle of a minidump in the app directory is very simple: foo.dmpNNNNN -- + // where NNNNN is a Process ID (PID) -- gets created, and is either deleted or + // copied over to the shared crash directory for all WebView-using apps. + Map<String, Map<String, String>> crashesInfoMap = + crashFileManager.importMinidumpsCrashKeys(); + final File[] minidumpFiles = crashFileManager.getCurrentMinidumpsSansLogcat(); + if (minidumpFiles.length == 0) return; - // Delete the minidumps if the user doesn't allow crash data uploading. - if (!userApproved) { - deleteMinidumps(minidumpFiles); - return; - } - - final Intent intent = new Intent(); - intent.setClassName(getWebViewPackageName(), ServiceNames.CRASH_RECEIVER_SERVICE); - - ServiceConnection connection = new ServiceConnection() { - private boolean mHasConnected; - - @Override - public void onServiceConnected(ComponentName className, IBinder service) { - if (mHasConnected) return; - mHasConnected = true; - // onServiceConnected is called on the UI thread, so punt this back to - // the background thread. - sSequencedTaskRunner.postTask(() -> { - transmitMinidumps(minidumpFiles, crashesInfoMap, - ICrashReceiverService.Stub.asInterface(service)); - appContext.unbindService(this); - }); + // Delete the minidumps if the user doesn't allow crash data uploading. + if (!userApproved) { + deleteMinidumps(minidumpFiles); + return; } - @Override - public void onServiceDisconnected(ComponentName className) {} - }; - if (!appContext.bindService(intent, connection, Context.BIND_AUTO_CREATE)) { - Log.w(TAG, "Could not bind to Minidump-copying Service " + intent); + final Intent intent = new Intent(); + intent.setClassName(getWebViewPackageName(), ServiceNames.CRASH_RECEIVER_SERVICE); + + ServiceConnection connection = new ServiceConnection() { + private boolean mHasConnected; + + @Override + public void onServiceConnected(ComponentName className, IBinder service) { + if (mHasConnected) return; + mHasConnected = true; + // onServiceConnected is called on the UI thread, so punt this back to + // the background thread. + sSequencedTaskRunner.postTask(() -> { + transmitMinidumps(minidumpFiles, crashesInfoMap, + ICrashReceiverService.Stub.asInterface(service)); + appContext.unbindService(this); + }); + } + + @Override + public void onServiceDisconnected(ComponentName className) {} + }; + if (!appContext.bindService(intent, connection, Context.BIND_AUTO_CREATE)) { + Log.w(TAG, "Could not bind to Minidump-copying Service " + intent); + } + } catch (RuntimeException e) { + // We don't want to crash the app if we hit an unexpected exception during minidump + // uploading as this could potentially put the app into a persistently bad state. + // Just log it. + Log.e(TAG, "Exception during minidump uploading process!", e); } }); }
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/OWNERS b/android_webview/javatests/src/org/chromium/android_webview/test/OWNERS index c84b073..e258f091 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/OWNERS +++ b/android_webview/javatests/src/org/chromium/android_webview/test/OWNERS
@@ -1,7 +1,15 @@ -per-file AwMetricsIntegrationTest.java=ntfschr@chromium.org -per-file CookieManagerStartupTest.java=ntfschr@chromium.org -per-file CookieManagerTest.java=ntfschr@chromium.org -per-file SafeBrowsingTest.java=ntfschr@chromium.org +# Networking/Network Service +per-file AwNetworkConfigurationTest.java=file://android_webview/browser/network_service/OWNERS +per-file SslPreferencesTest.java=file://android_webview/browser/network_service/OWNERS +per-file OnDiskFileTest.java=file://android_webview/browser/network_service/OWNERS +per-file CookieManager*=file://android_webview/browser/network_service/OWNERS + +# Safe Browsing +per-file SafeBrowsingTest.java=file://android_webview/browser/safe_browsing/OWNERS + +# Metrics +per-file AwMetricsIntegrationTest.java=file://android_webview/browser/metrics/OWNERS +per-file MemoryMetricsLoggerTest.java=file://android_webview/browser/metrics/OWNERS # Variations per-file AwVariationsSeedFetcherTest*=file://android_webview/browser/variations/OWNERS
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index 9e88880..47c2ee1 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -1169,14 +1169,10 @@ "system/palette/tools/metalayer_mode.h", "system/phonehub/bluetooth_disabled_view.cc", "system/phonehub/bluetooth_disabled_view.h", - "system/phonehub/connection_error_view.cc", - "system/phonehub/connection_error_view.h", "system/phonehub/continue_browsing_chip.cc", "system/phonehub/continue_browsing_chip.h", "system/phonehub/enable_hotspot_quick_action_controller.cc", "system/phonehub/enable_hotspot_quick_action_controller.h", - "system/phonehub/initial_connecting_view.cc", - "system/phonehub/initial_connecting_view.h", "system/phonehub/interstitial_view_button.cc", "system/phonehub/interstitial_view_button.h", "system/phonehub/locate_phone_quick_action_controller.cc", @@ -1187,6 +1183,10 @@ "system/phonehub/onboarding_view.h", "system/phonehub/phone_connected_view.cc", "system/phonehub/phone_connected_view.h", + "system/phonehub/phone_connecting_view.cc", + "system/phonehub/phone_connecting_view.h", + "system/phonehub/phone_disconnected_view.cc", + "system/phonehub/phone_disconnected_view.h", "system/phonehub/phone_hub_content_view.cc", "system/phonehub/phone_hub_content_view.h", "system/phonehub/phone_hub_interstitial_view.cc",
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd index acd6f73..f0ea790 100644 --- a/ash/ash_strings.grd +++ b/ash/ash_strings.grd
@@ -1129,22 +1129,22 @@ <message name="IDS_ASH_PHONE_HUB_ONBOARDING_DISMISS_DIALOG_OK_BUTTON" desc="Confirm button on the onboarding dismiss dialog to acknowledge."> OK </message> - <message name="IDS_ASH_PHONE_HUB_INITIAL_CONNECTING_DIALOG_TITLE" desc="The title of the initial connecting dialog that indicates the device is trying to connect to your phone after the user has opted in the Phone Hub feature."> + <message name="IDS_ASH_PHONE_HUB_PHONE_CONNECTING_DIALOG_TITLE" desc="The title of the generic connecting dialog that indicates the device is trying to connect to your phone."> Connecting... </message> - <message name="IDS_ASH_PHONE_HUB_INITIAL_CONNECTING_DIALOG_DESCRIPTION" desc="The description of the onboarding dialog that indicates the device is trying to connect to your phone after the user has opted in the Phone Hub feature."> + <message name="IDS_ASH_PHONE_HUB_PHONE_CONNECTING_DIALOG_DESCRIPTION" desc="The description of the generic connecting dialog that indicates the device is trying to connect to your phone."> Make sure your phone is nearby with Bluetooth and Wi-Fi is turned on. </message> - <message name="IDS_ASH_PHONE_HUB_CONNECTION_ERROR_DIALOG_TITLE" desc="The title of the dialog that pops up when the Phone Hub feature is not available because there is currently no active connection to the phone."> + <message name="IDS_ASH_PHONE_HUB_PHONE_DISCONNECTED_DIALOG_TITLE" desc="The title of the dialog that pops up when the Phone Hub feature is not available because there is currently no active connection to the phone."> Can’t find your phone </message> - <message name="IDS_ASH_PHONE_HUB_CONNECTION_ERROR_DIALOG_DESCRIPTION" desc="The description of the dialog that pops up when the Phone Hub feature is not available because there is currently no active connection to the phone."> + <message name="IDS_ASH_PHONE_HUB_PHONE_DISCONNECTED_DIALOG_DESCRIPTION" desc="The description of the dialog that pops up when the Phone Hub feature is not available because there is currently no active connection to the phone."> Looks like your phone is not online and we are not able to connect to it. </message> - <message name="IDS_ASH_PHONE_HUB_CONNECTION_ERROR_DIALOG_REFRESH_BUTTON" desc="Refresh button on the connection error dialog to retry the connection attempt to the phone."> + <message name="IDS_ASH_PHONE_HUB_PHONE_DISCONNECTED_DIALOG_REFRESH_BUTTON" desc="Refresh button on the disconnected dialog to retry the connection attempt to the phone."> Refresh </message> - <message name="IDS_ASH_PHONE_HUB_CONNECTION_ERROR_DIALOG_LEARN_MORE_BUTTON" desc="Learn more button on the connection error dialog to show more related information."> + <message name="IDS_ASH_PHONE_HUB_PHONE_DISCONNECTED_DIALOG_LEARN_MORE_BUTTON" desc="Learn more button on the disconnected dialog to show more related information."> Learn more </message> <message name="IDS_ASH_PHONE_HUB_BLUETOOTH_DISABLED_DIALOG_TITLE" desc="The title of the dialog that pops up when the phone hub feature is not available because Bluetooth is disabled on this device.">
diff --git a/ash/ash_strings_grd/IDS_ASH_PHONE_HUB_INITIAL_CONNECTING_DIALOG_DESCRIPTION.png.sha1 b/ash/ash_strings_grd/IDS_ASH_PHONE_HUB_PHONE_CONNECTING_DIALOG_DESCRIPTION.png.sha1 similarity index 100% rename from ash/ash_strings_grd/IDS_ASH_PHONE_HUB_INITIAL_CONNECTING_DIALOG_DESCRIPTION.png.sha1 rename to ash/ash_strings_grd/IDS_ASH_PHONE_HUB_PHONE_CONNECTING_DIALOG_DESCRIPTION.png.sha1
diff --git a/ash/ash_strings_grd/IDS_ASH_PHONE_HUB_INITIAL_CONNECTING_DIALOG_TITLE.png.sha1 b/ash/ash_strings_grd/IDS_ASH_PHONE_HUB_PHONE_CONNECTING_DIALOG_TITLE.png.sha1 similarity index 100% rename from ash/ash_strings_grd/IDS_ASH_PHONE_HUB_INITIAL_CONNECTING_DIALOG_TITLE.png.sha1 rename to ash/ash_strings_grd/IDS_ASH_PHONE_HUB_PHONE_CONNECTING_DIALOG_TITLE.png.sha1
diff --git a/ash/ash_strings_grd/IDS_ASH_PHONE_HUB_CONNECTION_ERROR_DIALOG_DESCRIPTION.png.sha1 b/ash/ash_strings_grd/IDS_ASH_PHONE_HUB_PHONE_DISCONNECTED_DIALOG_DESCRIPTION.png.sha1 similarity index 100% rename from ash/ash_strings_grd/IDS_ASH_PHONE_HUB_CONNECTION_ERROR_DIALOG_DESCRIPTION.png.sha1 rename to ash/ash_strings_grd/IDS_ASH_PHONE_HUB_PHONE_DISCONNECTED_DIALOG_DESCRIPTION.png.sha1
diff --git a/ash/ash_strings_grd/IDS_ASH_PHONE_HUB_CONNECTION_ERROR_DIALOG_LEARN_MORE_BUTTON.png.sha1 b/ash/ash_strings_grd/IDS_ASH_PHONE_HUB_PHONE_DISCONNECTED_DIALOG_LEARN_MORE_BUTTON.png.sha1 similarity index 100% rename from ash/ash_strings_grd/IDS_ASH_PHONE_HUB_CONNECTION_ERROR_DIALOG_LEARN_MORE_BUTTON.png.sha1 rename to ash/ash_strings_grd/IDS_ASH_PHONE_HUB_PHONE_DISCONNECTED_DIALOG_LEARN_MORE_BUTTON.png.sha1
diff --git a/ash/ash_strings_grd/IDS_ASH_PHONE_HUB_CONNECTION_ERROR_DIALOG_REFRESH_BUTTON.png.sha1 b/ash/ash_strings_grd/IDS_ASH_PHONE_HUB_PHONE_DISCONNECTED_DIALOG_REFRESH_BUTTON.png.sha1 similarity index 100% rename from ash/ash_strings_grd/IDS_ASH_PHONE_HUB_CONNECTION_ERROR_DIALOG_REFRESH_BUTTON.png.sha1 rename to ash/ash_strings_grd/IDS_ASH_PHONE_HUB_PHONE_DISCONNECTED_DIALOG_REFRESH_BUTTON.png.sha1
diff --git a/ash/ash_strings_grd/IDS_ASH_PHONE_HUB_CONNECTION_ERROR_DIALOG_TITLE.png.sha1 b/ash/ash_strings_grd/IDS_ASH_PHONE_HUB_PHONE_DISCONNECTED_DIALOG_TITLE.png.sha1 similarity index 100% rename from ash/ash_strings_grd/IDS_ASH_PHONE_HUB_CONNECTION_ERROR_DIALOG_TITLE.png.sha1 rename to ash/ash_strings_grd/IDS_ASH_PHONE_HUB_PHONE_DISCONNECTED_DIALOG_TITLE.png.sha1
diff --git a/ash/clipboard/clipboard_history_controller_impl.cc b/ash/clipboard/clipboard_history_controller_impl.cc index e49afc3..c935548 100644 --- a/ash/clipboard/clipboard_history_controller_impl.cc +++ b/ash/clipboard/clipboard_history_controller_impl.cc
@@ -281,9 +281,6 @@ void ClipboardHistoryControllerImpl::ExecuteSelectedMenuItem(int event_flags) { DCHECK(IsMenuShowing()); - // Deactivate ClipboardImageModelFactory prior to pasting to ensure that any - // modifications to the clipboard for HTML rendering purposes are reversed. - ClipboardImageModelFactory::Get()->Deactivate(); auto command = context_menu_->GetSelectedMenuItemCommand(); @@ -322,6 +319,11 @@ UMA_HISTOGRAM_ENUMERATION( "Ash.ClipboardHistory.ContextMenu.MenuOptionSelected", command_id, ClipboardHistoryUtil::kMaxCommandId); + + // Deactivate ClipboardImageModelFactory prior to pasting to ensure that any + // modifications to the clipboard for HTML rendering purposes are reversed. + ClipboardImageModelFactory::Get()->Deactivate(); + // Force close the context menu. Failure to do so before dispatching our // synthetic key event will result in the context menu consuming the event. DCHECK(context_menu_);
diff --git a/ash/login/ui/login_user_menu_view.cc b/ash/login/ui/login_user_menu_view.cc index bf3900a..c9fb416 100644 --- a/ash/login/ui/login_user_menu_view.cc +++ b/ash/login/ui/login_user_menu_view.cc
@@ -143,7 +143,6 @@ bubble_opener_(bubble_opener), on_remove_user_warning_shown_(on_remove_user_warning_shown), on_remove_user_requested_(on_remove_user_requested) { - set_notify_alert_on_show(false); const base::string16& email = base::UTF8ToUTF16(user.basic_user_info.display_email); @@ -172,11 +171,11 @@ kUserMenuFontSizeUsername, gfx::Font::Weight::MEDIUM), kUserMenuLineHeightUsername); container->AddChildView(username_label_); - views::Label* email_label = login_views_utils::CreateBubbleLabel( + email_label_ = login_views_utils::CreateBubbleLabel( email, nullptr, AshColorProvider::Get()->GetContentLayerColor( AshColorProvider::ContentLayerType::kTextColorSecondary)); - container->AddChildView(email_label); + container->AddChildView(email_label_); } // User is managed. @@ -193,6 +192,11 @@ AddChildView(managed_user_data_); } + // If we can remove the user, the focus will be trapped by the bubble, and + // button. If we can't, and there is no button, we set this so that the bubble + // accessible data is displayed by accessibility tools. + set_notify_alert_on_show(!user.can_remove); + // Remove user. if (user.can_remove) { DCHECK(!is_owner); @@ -276,10 +280,21 @@ } void LoginUserMenuView::GetAccessibleNodeData(ui::AXNodeData* node_data) { - node_data->SetName(l10n_util::GetStringUTF16( - IDS_ASH_LOGIN_POD_REMOVE_ACCOUNT_ACCESSIBLE_NAME)); - node_data->SetDescription(l10n_util::GetStringUTF16( - IDS_ASH_LOGIN_POD_REMOVE_ACCOUNT_DIALOG_ACCESSIBLE_DESCRIPTION)); + if (remove_user_button_) { + node_data->SetName(l10n_util::GetStringUTF16( + IDS_ASH_LOGIN_POD_REMOVE_ACCOUNT_ACCESSIBLE_NAME)); + node_data->SetDescription(l10n_util::GetStringUTF16( + IDS_ASH_LOGIN_POD_REMOVE_ACCOUNT_DIALOG_ACCESSIBLE_DESCRIPTION)); + } else { + node_data->SetName(username_label_->GetText()); + if (management_disclosure_label_) { + node_data->SetDescription( + base::StrCat({email_label_->GetText(), base::ASCIIToUTF16(" "), + management_disclosure_label_->GetText()})); + } else { + node_data->SetDescription(email_label_->GetText()); + } + } node_data->role = ax::mojom::Role::kDialog; node_data->AddBoolAttribute(ax::mojom::BoolAttribute::kModal, true); }
diff --git a/ash/login/ui/login_user_menu_view.h b/ash/login/ui/login_user_menu_view.h index 44c33d1..98de355 100644 --- a/ash/login/ui/login_user_menu_view.h +++ b/ash/login/ui/login_user_menu_view.h
@@ -73,6 +73,7 @@ views::View* remove_user_confirm_data_ = nullptr; RemoveUserButton* remove_user_button_ = nullptr; views::Label* username_label_ = nullptr; + views::Label* email_label_ = nullptr; views::Label* management_disclosure_label_ = nullptr; base::string16 warning_message_;
diff --git a/ash/system/phonehub/connection_error_view.cc b/ash/system/phonehub/connection_error_view.cc deleted file mode 100644 index 2043c4f..0000000 --- a/ash/system/phonehub/connection_error_view.cc +++ /dev/null
@@ -1,113 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/phonehub/connection_error_view.h" - -#include <memory> - -#include "ash/public/cpp/new_window_delegate.h" -#include "ash/public/cpp/resources/grit/ash_public_unscaled_resources.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/style/ash_color_provider.h" -#include "ash/system/phonehub/interstitial_view_button.h" -#include "ash/system/phonehub/phone_hub_interstitial_view.h" -#include "ash/system/phonehub/phone_hub_metrics.h" -#include "ash/system/phonehub/phone_hub_view_ids.h" -#include "ash/system/phonehub/ui_constants.h" -#include "chromeos/components/phonehub/connection_scheduler.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/views/layout/fill_layout.h" -#include "ui/views/metadata/metadata_impl_macros.h" - -namespace ash { - -using phone_hub_metrics::InterstitialScreenEvent; -using phone_hub_metrics::Screen; - -ConnectionErrorView::ConnectionErrorView( - ErrorStatus error, - chromeos::phonehub::ConnectionScheduler* connection_scheduler) - : connection_scheduler_(connection_scheduler) { - SetID(error == ErrorStatus::kDisconnected - ? PhoneHubViewID::kDisconnectedView - : PhoneHubViewID::kReconnectingView); - SetLayoutManager(std::make_unique<views::FillLayout>()); - content_view_ = AddChildView(std::make_unique<PhoneHubInterstitialView>( - /*show_progress=*/error == ErrorStatus::kReconnecting)); - - // TODO(crbug.com/1127996): Replace PNG file with vector icon. - const int image_id = (error == ErrorStatus::kDisconnected) - ? IDR_PHONE_HUB_ERROR_STATE_IMAGE - : IDR_PHONE_HUB_CONNECTING_IMAGE; - gfx::ImageSkia* image = - ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(image_id); - content_view_->SetImage(*image); - - const int title = (error == ErrorStatus::kDisconnected) - ? IDS_ASH_PHONE_HUB_CONNECTION_ERROR_DIALOG_TITLE - : IDS_ASH_PHONE_HUB_INITIAL_CONNECTING_DIALOG_TITLE; - content_view_->SetTitle(l10n_util::GetStringUTF16(title)); - content_view_->SetDescription(l10n_util::GetStringUTF16( - IDS_ASH_PHONE_HUB_CONNECTION_ERROR_DIALOG_DESCRIPTION)); - - if (error == ErrorStatus::kReconnecting) { - phone_hub_metrics::LogInterstitialScreenEvent( - Screen::kReconnecting, InterstitialScreenEvent::kShown); - return; - } - - // Add "Learn more" and "Refresh" buttons only for disconnected state. - auto learn_more = std::make_unique<InterstitialViewButton>( - base::BindRepeating( - &ConnectionErrorView::ButtonPressed, base::Unretained(this), - InterstitialScreenEvent::kLearnMore, - base::BindRepeating( - &NewWindowDelegate::NewTabWithUrl, - base::Unretained(NewWindowDelegate::GetInstance()), - GURL(kLearnMoreUrl), /*from_user_interaction=*/true)), - l10n_util::GetStringUTF16( - IDS_ASH_PHONE_HUB_CONNECTION_ERROR_DIALOG_LEARN_MORE_BUTTON), - /*paint_background=*/false); - learn_more->SetEnabledTextColors( - AshColorProvider::Get()->GetContentLayerColor( - AshColorProvider::ContentLayerType::kTextColorPrimary)); - learn_more->SetID(PhoneHubViewID::kDisconnectedLearnMoreButton); - content_view_->AddButton(std::move(learn_more)); - - auto refresh = std::make_unique<InterstitialViewButton>( - base::BindRepeating( - &ConnectionErrorView::ButtonPressed, base::Unretained(this), - InterstitialScreenEvent::kConfirm, - base::BindRepeating( - &chromeos::phonehub::ConnectionScheduler::ScheduleConnectionNow, - base::Unretained(connection_scheduler_))), - l10n_util::GetStringUTF16( - IDS_ASH_PHONE_HUB_CONNECTION_ERROR_DIALOG_REFRESH_BUTTON), - /*paint_background=*/true); - refresh->SetID(PhoneHubViewID::kDisconnectedRefreshButton); - content_view_->AddButton(std::move(refresh)); - - phone_hub_metrics::LogInterstitialScreenEvent( - Screen::kConnectionError, InterstitialScreenEvent::kShown); -} - -ConnectionErrorView::~ConnectionErrorView() = default; - -phone_hub_metrics::Screen ConnectionErrorView::GetScreenForMetrics() const { - return GetID() == PhoneHubViewID::kReconnectingView - ? Screen::kReconnecting - : Screen::kConnectionError; -} - -void ConnectionErrorView::ButtonPressed(InterstitialScreenEvent event, - base::RepeatingClosure callback) { - LogInterstitialScreenEvent(event); - std::move(callback).Run(); -} - -BEGIN_METADATA(ConnectionErrorView, views::View) -END_METADATA - -} // namespace ash
diff --git a/ash/system/phonehub/connection_error_view.h b/ash/system/phonehub/connection_error_view.h deleted file mode 100644 index 2865f160..0000000 --- a/ash/system/phonehub/connection_error_view.h +++ /dev/null
@@ -1,58 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_PHONEHUB_CONNECTION_ERROR_VIEW_H_ -#define ASH_SYSTEM_PHONEHUB_CONNECTION_ERROR_VIEW_H_ - -#include "ash/ash_export.h" -#include "ash/system/phonehub/phone_hub_content_view.h" - -namespace chromeos { -namespace phonehub { -class ConnectionScheduler; -} // namespace phonehub -} // namespace chromeos - -namespace ash { - -class PhoneHubInterstitialView; - -namespace phone_hub_metrics { -enum class InterstitialScreenEvent; -} - -// An interstitial view represeting that the Phone Hub feature is not available -// due to connection issues. -class ASH_EXPORT ConnectionErrorView : public PhoneHubContentView { - public: - METADATA_HEADER(ConnectionErrorView); - - // Defines possible connection error states of the Phone Hub feature. - enum class ErrorStatus { - kDisconnected, // The connection to the phone has been interrupted. - kReconnecting, // Attempts to resume the connection to the phone. - }; - - ConnectionErrorView( - ErrorStatus error, - chromeos::phonehub::ConnectionScheduler* connection_scheduler); - ConnectionErrorView(const ConnectionErrorView&) = delete; - ConnectionErrorView& operator=(const ConnectionErrorView&) = delete; - ~ConnectionErrorView() override; - - // PhoneHubContentView: - phone_hub_metrics::Screen GetScreenForMetrics() const override; - - private: - void ButtonPressed(phone_hub_metrics::InterstitialScreenEvent event, - base::RepeatingClosure callback); - - chromeos::phonehub::ConnectionScheduler* connection_scheduler_ = nullptr; - - PhoneHubInterstitialView* content_view_ = nullptr; -}; - -} // namespace ash - -#endif // ASH_SYSTEM_PHONEHUB_CONNECTION_ERROR_VIEW_H_
diff --git a/ash/system/phonehub/initial_connecting_view.h b/ash/system/phonehub/initial_connecting_view.h deleted file mode 100644 index db9d0dbc..0000000 --- a/ash/system/phonehub/initial_connecting_view.h +++ /dev/null
@@ -1,40 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_PHONEHUB_INITIAL_CONNECTING_VIEW_H_ -#define ASH_SYSTEM_PHONEHUB_INITIAL_CONNECTING_VIEW_H_ - -#include "ash/ash_export.h" -#include "ash/system/phonehub/phone_hub_content_view.h" -#include "ui/views/metadata/metadata_header_macros.h" -#include "ui/views/view.h" - -namespace ash { - -class PhoneHubInterstitialView; - -// An interstitial view representing this device is trying to connect to your -// phone after the user has opted in the Phone Hub feature through the -// onboarding UI. -class ASH_EXPORT InitialConnectingView : public PhoneHubContentView { - public: - METADATA_HEADER(InitialConnectingView); - - InitialConnectingView(); - InitialConnectingView(const InitialConnectingView&) = delete; - InitialConnectingView& operator=(const InitialConnectingView&) = delete; - ~InitialConnectingView() override; - - // PhoneHubContentView: - phone_hub_metrics::Screen GetScreenForMetrics() const override; - - private: - // Responsible for displaying the connecting UI contents. - // Owned by view hierarchy. - PhoneHubInterstitialView* content_view_ = nullptr; -}; - -} // namespace ash - -#endif // ASH_SYSTEM_PHONEHUB_INITIAL_CONNECTING_VIEW_H_
diff --git a/ash/system/phonehub/initial_connecting_view.cc b/ash/system/phonehub/phone_connecting_view.cc similarity index 73% rename from ash/system/phonehub/initial_connecting_view.cc rename to ash/system/phonehub/phone_connecting_view.cc index 32a5d4504..d1b18e6 100644 --- a/ash/system/phonehub/initial_connecting_view.cc +++ b/ash/system/phonehub/phone_connecting_view.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/system/phonehub/initial_connecting_view.h" +#include "ash/system/phonehub/phone_connecting_view.h" #include <algorithm> #include <memory> @@ -23,8 +23,8 @@ using phone_hub_metrics::InterstitialScreenEvent; using phone_hub_metrics::Screen; -InitialConnectingView::InitialConnectingView() { - SetID(PhoneHubViewID::kInitialConnectingView); +PhoneConnectingView::PhoneConnectingView() { + SetID(PhoneHubViewID::kPhoneConnectingView); SetLayoutManager(std::make_unique<views::FillLayout>()); content_view_ = AddChildView( std::make_unique<PhoneHubInterstitialView>(/*show_progress=*/true)); @@ -35,20 +35,20 @@ IDR_PHONE_HUB_CONNECTING_IMAGE); content_view_->SetImage(*image); content_view_->SetTitle(l10n_util::GetStringUTF16( - IDS_ASH_PHONE_HUB_INITIAL_CONNECTING_DIALOG_TITLE)); + IDS_ASH_PHONE_HUB_PHONE_CONNECTING_DIALOG_TITLE)); content_view_->SetDescription(l10n_util::GetStringUTF16( - IDS_ASH_PHONE_HUB_INITIAL_CONNECTING_DIALOG_DESCRIPTION)); + IDS_ASH_PHONE_HUB_PHONE_CONNECTING_DIALOG_DESCRIPTION)); LogInterstitialScreenEvent(InterstitialScreenEvent::kShown); } -InitialConnectingView::~InitialConnectingView() = default; +PhoneConnectingView::~PhoneConnectingView() = default; -phone_hub_metrics::Screen InitialConnectingView::GetScreenForMetrics() const { - return Screen::kInitialConnecting; +phone_hub_metrics::Screen PhoneConnectingView::GetScreenForMetrics() const { + return Screen::kPhoneConnecting; } -BEGIN_METADATA(InitialConnectingView, views::View) +BEGIN_METADATA(PhoneConnectingView, views::View) END_METADATA } // namespace ash
diff --git a/ash/system/phonehub/phone_connecting_view.h b/ash/system/phonehub/phone_connecting_view.h new file mode 100644 index 0000000..199125f --- /dev/null +++ b/ash/system/phonehub/phone_connecting_view.h
@@ -0,0 +1,40 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_SYSTEM_PHONEHUB_PHONE_CONNECTING_VIEW_H_ +#define ASH_SYSTEM_PHONEHUB_PHONE_CONNECTING_VIEW_H_ + +#include "ash/ash_export.h" +#include "ash/system/phonehub/phone_hub_content_view.h" +#include "ui/views/metadata/metadata_header_macros.h" +#include "ui/views/view.h" + +namespace ash { + +class PhoneHubInterstitialView; + +// A generic connecting view representing this device is trying to connect to +// your phone either for the first time after user has opted in or for resuming +// an interrupted connection. +class ASH_EXPORT PhoneConnectingView : public PhoneHubContentView { + public: + METADATA_HEADER(PhoneConnectingView); + + PhoneConnectingView(); + PhoneConnectingView(const PhoneConnectingView&) = delete; + PhoneConnectingView& operator=(const PhoneConnectingView&) = delete; + ~PhoneConnectingView() override; + + // PhoneHubContentView: + phone_hub_metrics::Screen GetScreenForMetrics() const override; + + private: + // Responsible for displaying the connecting UI contents. + // Owned by view hierarchy. + PhoneHubInterstitialView* content_view_ = nullptr; +}; + +} // namespace ash + +#endif // ASH_SYSTEM_PHONEHUB_PHONE_CONNECTING_VIEW_H_
diff --git a/ash/system/phonehub/phone_disconnected_view.cc b/ash/system/phonehub/phone_disconnected_view.cc new file mode 100644 index 0000000..d275ea2 --- /dev/null +++ b/ash/system/phonehub/phone_disconnected_view.cc
@@ -0,0 +1,97 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/system/phonehub/phone_disconnected_view.h" + +#include <memory> + +#include "ash/public/cpp/new_window_delegate.h" +#include "ash/public/cpp/resources/grit/ash_public_unscaled_resources.h" +#include "ash/strings/grit/ash_strings.h" +#include "ash/style/ash_color_provider.h" +#include "ash/system/phonehub/interstitial_view_button.h" +#include "ash/system/phonehub/phone_hub_interstitial_view.h" +#include "ash/system/phonehub/phone_hub_metrics.h" +#include "ash/system/phonehub/phone_hub_view_ids.h" +#include "ash/system/phonehub/ui_constants.h" +#include "chromeos/components/phonehub/connection_scheduler.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/views/layout/fill_layout.h" +#include "ui/views/metadata/metadata_impl_macros.h" + +namespace ash { + +using phone_hub_metrics::InterstitialScreenEvent; +using phone_hub_metrics::Screen; + +PhoneDisconnectedView::PhoneDisconnectedView( + chromeos::phonehub::ConnectionScheduler* connection_scheduler) + : connection_scheduler_(connection_scheduler) { + SetID(PhoneHubViewID::kDisconnectedView); + SetLayoutManager(std::make_unique<views::FillLayout>()); + content_view_ = AddChildView(std::make_unique<PhoneHubInterstitialView>( + /*show_progress=*/false)); + + // TODO(crbug.com/1127996): Replace PNG file with vector icon. + gfx::ImageSkia* image = + ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( + IDR_PHONE_HUB_ERROR_STATE_IMAGE); + content_view_->SetImage(*image); + + content_view_->SetTitle(l10n_util::GetStringUTF16( + IDS_ASH_PHONE_HUB_PHONE_DISCONNECTED_DIALOG_TITLE)); + content_view_->SetDescription(l10n_util::GetStringUTF16( + IDS_ASH_PHONE_HUB_PHONE_DISCONNECTED_DIALOG_DESCRIPTION)); + + // Add "Learn more" and "Refresh" buttons. + auto learn_more = std::make_unique<InterstitialViewButton>( + base::BindRepeating( + &PhoneDisconnectedView::ButtonPressed, base::Unretained(this), + InterstitialScreenEvent::kLearnMore, + base::BindRepeating( + &NewWindowDelegate::NewTabWithUrl, + base::Unretained(NewWindowDelegate::GetInstance()), + GURL(kLearnMoreUrl), /*from_user_interaction=*/true)), + l10n_util::GetStringUTF16( + IDS_ASH_PHONE_HUB_PHONE_DISCONNECTED_DIALOG_LEARN_MORE_BUTTON), + /*paint_background=*/false); + learn_more->SetEnabledTextColors( + AshColorProvider::Get()->GetContentLayerColor( + AshColorProvider::ContentLayerType::kTextColorPrimary)); + learn_more->SetID(PhoneHubViewID::kDisconnectedLearnMoreButton); + content_view_->AddButton(std::move(learn_more)); + + auto refresh = std::make_unique<InterstitialViewButton>( + base::BindRepeating( + &PhoneDisconnectedView::ButtonPressed, base::Unretained(this), + InterstitialScreenEvent::kConfirm, + base::BindRepeating( + &chromeos::phonehub::ConnectionScheduler::ScheduleConnectionNow, + base::Unretained(connection_scheduler_))), + l10n_util::GetStringUTF16( + IDS_ASH_PHONE_HUB_PHONE_DISCONNECTED_DIALOG_REFRESH_BUTTON), + /*paint_background=*/true); + refresh->SetID(PhoneHubViewID::kDisconnectedRefreshButton); + content_view_->AddButton(std::move(refresh)); + + LogInterstitialScreenEvent(InterstitialScreenEvent::kShown); +} + +PhoneDisconnectedView::~PhoneDisconnectedView() = default; + +phone_hub_metrics::Screen PhoneDisconnectedView::GetScreenForMetrics() const { + return Screen::kPhoneDisconnected; +} + +void PhoneDisconnectedView::ButtonPressed(InterstitialScreenEvent event, + base::RepeatingClosure callback) { + LogInterstitialScreenEvent(event); + std::move(callback).Run(); +} + +BEGIN_METADATA(PhoneDisconnectedView, views::View) +END_METADATA + +} // namespace ash
diff --git a/ash/system/phonehub/phone_disconnected_view.h b/ash/system/phonehub/phone_disconnected_view.h new file mode 100644 index 0000000..a3e84588 --- /dev/null +++ b/ash/system/phonehub/phone_disconnected_view.h
@@ -0,0 +1,51 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_SYSTEM_PHONEHUB_PHONE_DISCONNECTED_VIEW_H_ +#define ASH_SYSTEM_PHONEHUB_PHONE_DISCONNECTED_VIEW_H_ + +#include "ash/ash_export.h" +#include "ash/system/phonehub/phone_hub_content_view.h" + +namespace chromeos { +namespace phonehub { +class ConnectionScheduler; +} // namespace phonehub +} // namespace chromeos + +namespace ash { + +class PhoneHubInterstitialView; + +namespace phone_hub_metrics { +enum class InterstitialScreenEvent; +} + +// An interstitial view represeting that connection to the phone has been +// interrupted. +class ASH_EXPORT PhoneDisconnectedView : public PhoneHubContentView { + public: + METADATA_HEADER(PhoneDisconnectedView); + + explicit PhoneDisconnectedView( + chromeos::phonehub::ConnectionScheduler* connection_scheduler); + PhoneDisconnectedView(const PhoneDisconnectedView&) = delete; + PhoneDisconnectedView& operator=(const PhoneDisconnectedView&) = delete; + ~PhoneDisconnectedView() override; + + // PhoneHubContentView: + phone_hub_metrics::Screen GetScreenForMetrics() const override; + + private: + void ButtonPressed(phone_hub_metrics::InterstitialScreenEvent event, + base::RepeatingClosure callback); + + chromeos::phonehub::ConnectionScheduler* connection_scheduler_ = nullptr; + + PhoneHubInterstitialView* content_view_ = nullptr; +}; + +} // namespace ash + +#endif // ASH_SYSTEM_PHONEHUB_PHONE_DISCONNECTED_VIEW_H_
diff --git a/ash/system/phonehub/phone_hub_metrics.cc b/ash/system/phonehub/phone_hub_metrics.cc index c4b3639e..1b4513c 100644 --- a/ash/system/phonehub/phone_hub_metrics.cc +++ b/ash/system/phonehub/phone_hub_metrics.cc
@@ -14,14 +14,12 @@ std::string GetInterstitialScreenEventHistogramName(Screen screen) { switch (screen) { - case Screen::kConnectionError: - return "Ash.PhoneHub.InterstitialScreenEvent.ConnectionError"; + case Screen::kPhoneDisconnected: + return "Ash.PhoneHub.InterstitialScreenEvent.PhoneDisconnected"; case Screen::kBluetoothOrWifiDisabled: return "Ash.PhoneHub.InterstitialScreenEvent.BluetoothOrWifiDisabled"; - case Screen::kReconnecting: - return "Ash.PhoneHub.InterstitialScreenEvent.Reconnecting"; - case Screen::kInitialConnecting: - return "Ash.PhoneHub.InterstitialScreenEvent.InitialConnecting"; + case Screen::kPhoneConnecting: + return "Ash.PhoneHub.InterstitialScreenEvent.PhoneConnecting"; case Screen::kOnboardingExistingMultideviceUser: return "Ash.PhoneHub.InterstitialScreenEvent.Onboarding." "ExistingMultideviceUser";
diff --git a/ash/system/phonehub/phone_hub_metrics.h b/ash/system/phonehub/phone_hub_metrics.h index 891c78cd..2a6af4d 100644 --- a/ash/system/phonehub/phone_hub_metrics.h +++ b/ash/system/phonehub/phone_hub_metrics.h
@@ -18,17 +18,19 @@ }; // Keep in sync with corresponding enum in tools/metrics/histograms/enums.xml. +// These values are persisted to logs. Entries should not be renumbered and +// numeric values should never be reused. +// Note that value 2 and 3 have been deprecated and should not be reused. enum class Screen { kBluetoothOrWifiDisabled = 0, - kConnectionError = 1, - kInitialConnecting = 2, - kReconnecting = 3, + kPhoneDisconnected = 1, kOnboardingExistingMultideviceUser = 4, kOnboardingNewMultideviceUser = 5, kPhoneConnected = 6, kOnboardingDismissPrompt = 7, kInvalid = 8, - kMaxValue = kInvalid + kPhoneConnecting = 9, + kMaxValue = kPhoneConnecting }; // Keep in sync with corresponding enum in tools/metrics/histograms/enums.xml.
diff --git a/ash/system/phonehub/phone_hub_ui_controller.cc b/ash/system/phonehub/phone_hub_ui_controller.cc index 340c96b0..78e3d4e 100644 --- a/ash/system/phonehub/phone_hub_ui_controller.cc +++ b/ash/system/phonehub/phone_hub_ui_controller.cc
@@ -7,10 +7,10 @@ #include <memory> #include "ash/system/phonehub/bluetooth_disabled_view.h" -#include "ash/system/phonehub/connection_error_view.h" -#include "ash/system/phonehub/initial_connecting_view.h" #include "ash/system/phonehub/onboarding_view.h" #include "ash/system/phonehub/phone_connected_view.h" +#include "ash/system/phonehub/phone_connecting_view.h" +#include "ash/system/phonehub/phone_disconnected_view.h" #include "ash/system/phonehub/phone_hub_content_view.h" #include "base/logging.h" #include "chromeos/components/phonehub/connection_scheduler.h" @@ -65,15 +65,10 @@ OnboardingView::kExistingMultideviceUser); case UiState::kBluetoothDisabled: return std::make_unique<BluetoothDisabledView>(); - case UiState::kInitialConnecting: - return std::make_unique<InitialConnectingView>(); case UiState::kPhoneConnecting: - return std::make_unique<ConnectionErrorView>( - ConnectionErrorView::ErrorStatus::kReconnecting, - phone_hub_manager_->GetConnectionScheduler()); - case UiState::kConnectionError: - return std::make_unique<ConnectionErrorView>( - ConnectionErrorView::ErrorStatus::kDisconnected, + return std::make_unique<PhoneConnectingView>(); + case UiState::kPhoneDisconnected: + return std::make_unique<PhoneDisconnectedView>( phone_hub_manager_->GetConnectionScheduler()); case UiState::kPhoneConnected: return std::make_unique<PhoneConnectedView>(phone_hub_manager_); @@ -138,11 +133,11 @@ return should_show_onboarding_ui ? UiState::kOnboardingWithoutPhone : UiState::kHidden; case FeatureStatus::kPhoneSelectedAndPendingSetup: - return UiState::kInitialConnecting; + return UiState::kPhoneConnecting; case FeatureStatus::kUnavailableBluetoothOff: return UiState::kBluetoothDisabled; case FeatureStatus::kEnabledButDisconnected: - return UiState::kConnectionError; + return UiState::kPhoneDisconnected; case FeatureStatus::kEnabledAndConnecting: return UiState::kPhoneConnecting; case FeatureStatus::kEnabledAndConnected:
diff --git a/ash/system/phonehub/phone_hub_ui_controller.h b/ash/system/phonehub/phone_hub_ui_controller.h index 53d115dd..b4a4570 100644 --- a/ash/system/phonehub/phone_hub_ui_controller.h +++ b/ash/system/phonehub/phone_hub_ui_controller.h
@@ -46,9 +46,8 @@ kOnboardingWithoutPhone, kOnboardingWithPhone, kBluetoothDisabled, - kInitialConnecting, kPhoneConnecting, - kConnectionError, + kPhoneDisconnected, kPhoneConnected, };
diff --git a/ash/system/phonehub/phone_hub_ui_controller_unittest.cc b/ash/system/phonehub/phone_hub_ui_controller_unittest.cc index 9d29b545..4d664cb 100644 --- a/ash/system/phonehub/phone_hub_ui_controller_unittest.cc +++ b/ash/system/phonehub/phone_hub_ui_controller_unittest.cc
@@ -100,11 +100,11 @@ TEST_F(PhoneHubUiControllerTest, PhoneConnectingForOnboarding) { GetFeatureStatusProvider()->SetStatus( FeatureStatus::kPhoneSelectedAndPendingSetup); - EXPECT_EQ(PhoneHubUiController::UiState::kInitialConnecting, + EXPECT_EQ(PhoneHubUiController::UiState::kPhoneConnecting, controller_.ui_state()); auto content_view = controller_.CreateContentView(/*delegate=*/nullptr); - EXPECT_EQ(PhoneHubViewID::kInitialConnectingView, content_view->GetID()); + EXPECT_EQ(PhoneHubViewID::kPhoneConnectingView, content_view->GetID()); } TEST_F(PhoneHubUiControllerTest, BluetoothOff) { @@ -119,7 +119,7 @@ TEST_F(PhoneHubUiControllerTest, PhoneDisconnected) { GetFeatureStatusProvider()->SetStatus(FeatureStatus::kEnabledButDisconnected); - EXPECT_EQ(PhoneHubUiController::UiState::kConnectionError, + EXPECT_EQ(PhoneHubUiController::UiState::kPhoneDisconnected, controller_.ui_state()); auto content_view = controller_.CreateContentView(/*delegate=*/nullptr); @@ -132,7 +132,7 @@ controller_.ui_state()); auto content_view = controller_.CreateContentView(/*delegate=*/nullptr); - EXPECT_EQ(PhoneHubViewID::kReconnectingView, content_view->GetID()); + EXPECT_EQ(PhoneHubViewID::kPhoneConnectingView, content_view->GetID()); } TEST_F(PhoneHubUiControllerTest, PhoneConnected) {
diff --git a/ash/system/phonehub/phone_hub_view_ids.h b/ash/system/phonehub/phone_hub_view_ids.h index f1e1752..6a41a39 100644 --- a/ash/system/phonehub/phone_hub_view_ids.h +++ b/ash/system/phonehub/phone_hub_view_ids.h
@@ -30,9 +30,8 @@ kOnboardingDismissPromptView, kOnboardingDismissAckButton, - // Connection error view and its components. + // Phone disconnected view and its components. kDisconnectedView, - kReconnectingView, kDisconnectedLearnMoreButton, kDisconnectedRefreshButton, @@ -41,7 +40,7 @@ kBluetoothDisabledLearnMoreButton, kPhoneConnectedView, - kInitialConnectingView, + kPhoneConnectingView, }; } // namespace ash
diff --git a/base/allocator/partition_allocator/pcscan.cc b/base/allocator/partition_allocator/pcscan.cc index df5730c..d4b5d1a 100644 --- a/base/allocator/partition_allocator/pcscan.cc +++ b/base/allocator/partition_allocator/pcscan.cc
@@ -205,7 +205,7 @@ // Check if pointer was in the quarantine bitmap. const uintptr_t base = GetObjectStartInSuperPage<thread_safe>(maybe_ptr, root_); - if (!bitmap->CheckBit(base)) + if (!base || !bitmap->CheckBit(base)) return 0; PA_DCHECK((maybe_ptr & kSuperPageBaseMask) == (base & kSuperPageBaseMask));
diff --git a/base/metrics/histogram_macros_local.h b/base/metrics/histogram_macros_local.h index 47e5ba4..771b01a0 100644 --- a/base/metrics/histogram_macros_local.h +++ b/base/metrics/histogram_macros_local.h
@@ -69,6 +69,12 @@ base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \ base::HistogramBase::kNoFlags)) +#define LOCAL_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES(name, sample, min, max, \ + bucket_count) \ + STATIC_HISTOGRAM_POINTER_BLOCK( \ + name, AddTimeMicrosecondsGranularity(sample), \ + base::Histogram::FactoryMicrosecondsTimeGet( \ + name, min, max, bucket_count, base::HistogramBase::kNoFlags)) //------------------------------------------------------------------------------ // Memory histograms. //
diff --git a/base/run_loop.cc b/base/run_loop.cc index af1ca56..a0517fa 100644 --- a/base/run_loop.cc +++ b/base/run_loop.cc
@@ -11,6 +11,7 @@ #include "base/single_thread_task_runner.h" #include "base/threading/thread_local.h" #include "base/threading/thread_task_runner_handle.h" +#include "base/trace_event/base_tracing.h" #include "build/build_config.h" namespace base { @@ -64,7 +65,13 @@ } bool RunLoop::Delegate::ShouldQuitWhenIdle() { - return active_run_loops_.top()->quit_when_idle_received_; + const auto* top_loop = active_run_loops_.top(); + if (top_loop->quit_when_idle_received_) { + TRACE_EVENT_WITH_FLOW0("toplevel.flow", "RunLoop_ExitedOnIdle", + TRACE_ID_LOCAL(top_loop), TRACE_EVENT_FLAG_FLOW_IN); + return true; + } + return false; } // static @@ -145,6 +152,12 @@ return; } + // While Quit() is an "OUT" call to reach one of the quit-states ("IN"), + // OUT|IN is used to visually link multiple Quit*() together which can help + // when debugging flaky tests. + TRACE_EVENT_WITH_FLOW0("toplevel.flow", "RunLoop::Quit", TRACE_ID_LOCAL(this), + TRACE_EVENT_FLAG_FLOW_OUT | TRACE_EVENT_FLAG_FLOW_IN); + quit_called_ = true; if (running_ && delegate_->active_run_loops_.top() == this) { // This is the inner-most RunLoop, so quit now. @@ -164,6 +177,11 @@ return; } + // OUT|IN as in Quit() to link all Quit*() together should there be multiple. + TRACE_EVENT_WITH_FLOW0("toplevel.flow", "RunLoop::QuitWhenIdle", + TRACE_ID_LOCAL(this), + TRACE_EVENT_FLAG_FLOW_OUT | TRACE_EVENT_FLAG_FLOW_IN); + quit_when_idle_received_ = true; } @@ -299,8 +317,11 @@ #endif // DCHECK_IS_ON() // Allow Quit to be called before Run. - if (quit_called_) + if (quit_called_) { + TRACE_EVENT_WITH_FLOW0("toplevel.flow", "RunLoop_ExitedEarly", + TRACE_ID_LOCAL(this), TRACE_EVENT_FLAG_FLOW_IN); return false; + } auto& active_run_loops = delegate_->active_run_loops_; active_run_loops.push(this); @@ -323,6 +344,9 @@ running_ = false; + TRACE_EVENT_WITH_FLOW0("toplevel.flow", "RunLoop_Exited", + TRACE_ID_LOCAL(this), TRACE_EVENT_FLAG_FLOW_IN); + auto& active_run_loops = delegate_->active_run_loops_; DCHECK_EQ(active_run_loops.top(), this); active_run_loops.pop();
diff --git a/base/run_loop.h b/base/run_loop.h index 9af82b7..efd4895 100644 --- a/base/run_loop.h +++ b/base/run_loop.h
@@ -209,7 +209,8 @@ protected: // Returns the result of this Delegate's |should_quit_when_idle_callback_|. - // "protected" so it can be invoked only by the Delegate itself. + // "protected" so it can be invoked only by the Delegate itself. The + // Delegate is expected to quit Run() if this returns true. bool ShouldQuitWhenIdle(); private:
diff --git a/base/threading/platform_thread_mac.mm b/base/threading/platform_thread_mac.mm index 4c6cfac..3a32146 100644 --- a/base/threading/platform_thread_mac.mm +++ b/base/threading/platform_thread_mac.mm
@@ -69,13 +69,40 @@ const Feature kOptimizedRealtimeThreadingMac{"OptimizedRealtimeThreadingMac", FEATURE_DISABLED_BY_DEFAULT}; +// Fine-tuning optimized realt-time thread config: +// Whether or not the thread should be preeptible. +const FeatureParam<bool> kOptimizedRealtimeThreadingMacPreemptible{ + &kOptimizedRealtimeThreadingMac, "preemptible", true}; +// Portion of the time quantum the thread is expected to be busy, (0, 1]. +const FeatureParam<double> kOptimizedRealtimeThreadingMacBusy{ + &kOptimizedRealtimeThreadingMac, "busy", 0.5}; +// Maximum portion of the time quantum the thread is expected to be busy, +// (kOptimizedRealtimeThreadingMacBusy, 1]. +const FeatureParam<double> kOptimizedRealtimeThreadingMacBusyLimit{ + &kOptimizedRealtimeThreadingMac, "busy_limit", 1.0}; + namespace { -// PlatformThread::SetCurrentThreadRealtimePeriodValue() doesn't query the state -// of kOptimizedRealtimeThreadingMac feature directly because FeatureList -// initialization is not always synchronized with -// PlatformThread::SetCurrentThreadRealtimePeriodValue(). The initial value -// should match the default state of kOptimizedRealtimeThreadingMac. -std::atomic<bool> g_use_optimized_realtime_threading(false); + +struct TimeConstraints { + bool preemptible{kOptimizedRealtimeThreadingMacPreemptible.default_value}; + double busy{kOptimizedRealtimeThreadingMacBusy.default_value}; + double busy_limit{kOptimizedRealtimeThreadingMacBusyLimit.default_value}; + + static TimeConstraints ReadFromFeatureParams() { + double busy_limit = kOptimizedRealtimeThreadingMacBusyLimit.Get(); + return TimeConstraints{ + kOptimizedRealtimeThreadingMacPreemptible.Get(), + std::min(busy_limit, kOptimizedRealtimeThreadingMacBusy.Get()), + busy_limit}; + } +}; + +// Use atomics to access FeatureList values when setting up a thread, since +// there are cases when FeatureList initialization is not synchronized with +// PlatformThread creation. +std::atomic<bool> g_use_optimized_realtime_threading( + kOptimizedRealtimeThreadingMac.default_state == FEATURE_ENABLED_BY_DEFAULT); +std::atomic<TimeConstraints> g_time_constraints; } // namespace @@ -86,6 +113,7 @@ // tests that call this before initializing the FeatureList, only check the // state of the feature if the FeatureList is initialized. if (FeatureList::GetInstance()) { + g_time_constraints.store(TimeConstraints::ReadFromFeatureParams()); g_use_optimized_realtime_threading.store( FeatureList::IsEnabled(kOptimizedRealtimeThreadingMac)); } @@ -123,11 +151,14 @@ uint32_t abs_realtime_period = saturated_cast<uint32_t>(realtime_period.InNanoseconds() * (double(tb_info.denom) / tb_info.numer)); - + TimeConstraints config = g_time_constraints.load(); time_constraints.period = abs_realtime_period; - time_constraints.computation = abs_realtime_period / 2; - time_constraints.constraint = abs_realtime_period; - time_constraints.preemptible = YES; + time_constraints.constraint = std::min( + abs_realtime_period, uint32_t(abs_realtime_period * config.busy_limit)); + time_constraints.computation = + std::min(time_constraints.constraint, + uint32_t(abs_realtime_period * config.busy)); + time_constraints.preemptible = config.preemptible ? YES : NO; return time_constraints; }
diff --git a/base/threading/platform_thread_unittest.cc b/base/threading/platform_thread_unittest.cc index ed1697c..e7874bdd 100644 --- a/base/threading/platform_thread_unittest.cc +++ b/base/threading/platform_thread_unittest.cc
@@ -25,6 +25,7 @@ #include <mach/mach.h> #include <mach/mach_time.h> #include <mach/thread_policy.h> +#include "base/metrics/field_trial_params.h" #include "base/time/time.h" #endif @@ -468,9 +469,16 @@ (static_cast<double>(tb_info.denom) / tb_info.numer)); EXPECT_EQ(time_constraints.period, abs_realtime_period); - EXPECT_EQ(time_constraints.computation, abs_realtime_period / 2); - EXPECT_EQ(time_constraints.constraint, abs_realtime_period); - EXPECT_TRUE(time_constraints.preemptible); + EXPECT_EQ( + time_constraints.computation, + static_cast<uint32_t>(abs_realtime_period * + kOptimizedRealtimeThreadingMacBusy.Get())); + EXPECT_EQ( + time_constraints.constraint, + static_cast<uint32_t>(abs_realtime_period * + kOptimizedRealtimeThreadingMacBusyLimit.Get())); + EXPECT_EQ(time_constraints.preemptible, + kOptimizedRealtimeThreadingMacPreemptible.Get()); } else { // Old-style empirical values. const double kTimeQuantum = 2.9; @@ -494,7 +502,9 @@ const TimeDelta realtime_period_; }; -class RealtimePlatformThreadTest : public testing::TestWithParam<TimeDelta> { +class RealtimePlatformThreadTest + : public testing::TestWithParam< + std::tuple<bool, FieldTrialParams, TimeDelta>> { protected: void VerifyRealtimeConfig(TimeDelta period) { RealtimeTestThread thread(period); @@ -512,29 +522,44 @@ } }; -TEST_P(RealtimePlatformThreadTest, RealtimeAudioConfigMacFeatureOn) { +TEST_P(RealtimePlatformThreadTest, RealtimeAudioConfigMac) { test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeature(kOptimizedRealtimeThreadingMac); + if (std::get<0>(GetParam())) { + feature_list.InitAndEnableFeatureWithParameters( + kOptimizedRealtimeThreadingMac, std::get<1>(GetParam())); + } else { + feature_list.InitAndDisableFeature(kOptimizedRealtimeThreadingMac); + } + PlatformThread::InitializeOptimizedRealtimeThreadingFeature(); - VerifyRealtimeConfig(GetParam()); + VerifyRealtimeConfig(std::get<2>(GetParam())); } -TEST_P(RealtimePlatformThreadTest, RealtimeAudioConfigMacFeatureOff) { - test::ScopedFeatureList feature_list; - feature_list.InitAndDisableFeature(kOptimizedRealtimeThreadingMac); - PlatformThread::InitializeOptimizedRealtimeThreadingFeature(); - VerifyRealtimeConfig(GetParam()); -} - -INSTANTIATE_TEST_SUITE_P(RealtimePlatformThreadTest, - RealtimePlatformThreadTest, - testing::Values(TimeDelta(), - TimeDelta::FromSeconds(256.0 / 48000), - TimeDelta::FromMilliseconds(5), - TimeDelta::FromMilliseconds(10), - TimeDelta::FromSeconds(1024.0 / 44100), - TimeDelta::FromSeconds(1024.0 / - 16000))); +INSTANTIATE_TEST_SUITE_P( + RealtimePlatformThreadTest, + RealtimePlatformThreadTest, + testing::Combine( + testing::Bool(), + testing::Values( + FieldTrialParams{ + {kOptimizedRealtimeThreadingMacPreemptible.name, "true"}}, + FieldTrialParams{ + {kOptimizedRealtimeThreadingMacPreemptible.name, "false"}}, + FieldTrialParams{ + {kOptimizedRealtimeThreadingMacBusy.name, "0.5"}, + {kOptimizedRealtimeThreadingMacBusyLimit.name, "0.75"}}, + FieldTrialParams{ + {kOptimizedRealtimeThreadingMacBusy.name, "0.7"}, + {kOptimizedRealtimeThreadingMacBusyLimit.name, "0.7"}}, + FieldTrialParams{ + {kOptimizedRealtimeThreadingMacBusy.name, "1.0"}, + {kOptimizedRealtimeThreadingMacBusyLimit.name, "1.0"}}), + testing::Values(TimeDelta(), + TimeDelta::FromSeconds(256.0 / 48000), + TimeDelta::FromMilliseconds(5), + TimeDelta::FromMilliseconds(10), + TimeDelta::FromSeconds(1024.0 / 44100), + TimeDelta::FromSeconds(1024.0 / 16000)))); } // namespace
diff --git a/base/threading/threading_features.h b/base/threading/threading_features.h index e4365cb..5c9a08ac 100644 --- a/base/threading/threading_features.h +++ b/base/threading/threading_features.h
@@ -14,6 +14,12 @@ #if defined(OS_APPLE) extern const BASE_EXPORT Feature kOptimizedRealtimeThreadingMac; +extern const BASE_EXPORT FeatureParam<bool> + kOptimizedRealtimeThreadingMacPreemptible; +extern const BASE_EXPORT FeatureParam<double> + kOptimizedRealtimeThreadingMacBusy; +extern const BASE_EXPORT FeatureParam<double> + kOptimizedRealtimeThreadingMacBusyLimit; #endif } // namespace base
diff --git a/build/config/BUILD.gn b/build/config/BUILD.gn index d16b245..c0a6860 100644 --- a/build/config/BUILD.gn +++ b/build/config/BUILD.gn
@@ -266,10 +266,6 @@ public_deps += [ "//base/android/orderfile:orderfile_instrumentation" ] } - if (is_win && generate_order_files && !is_nacl) { - public_deps += [ "//tools/cygprofile_win" ] - } - if (is_fuchsia) { public_deps += [ "//third_party/fuchsia-sdk/sdk/build/config:runtime_library_group" ]
diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn index e0984fa..f3b7e7a 100644 --- a/build/config/BUILDCONFIG.gn +++ b/build/config/BUILDCONFIG.gn
@@ -361,11 +361,6 @@ [ "//build/config/android:default_orderfile_instrumentation" ] } -if (is_win) { - default_compiler_configs += - [ "//build/config/win:default_cygprofile_instrumentation" ] -} - if (is_clang && !is_nacl) { default_compiler_configs += [ "//build/config/clang:find_bad_constructs",
diff --git a/build/config/chrome_build.gni b/build/config/chrome_build.gni index e8f9660..5c51d7f2 100644 --- a/build/config/chrome_build.gni +++ b/build/config/chrome_build.gni
@@ -7,10 +7,6 @@ # true means official Google Chrome branding (requires extra Google-internal # resources). is_chrome_branded = false - - # Turn this on to generate order files. See - # https://chromium.googlesource.com/chromium/src/+/master/docs/win_order_files.md - generate_order_files = false } declare_args() {
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn index b0cf24d..ec939f2 100644 --- a/build/config/compiler/BUILD.gn +++ b/build/config/compiler/BUILD.gn
@@ -176,7 +176,7 @@ current_cpu == "x64")))) } -if (is_win || is_android || (is_chromeos && is_chromeos_device)) { +if (is_android || (is_chromeos && is_chromeos_device)) { # Set the path to use orderfile for linking Chrome # Note that this is for using only one orderfile for linking # the Chrome binary/library. @@ -187,8 +187,6 @@ # Allow downstream tools to set orderfile path with # another variable. chrome_orderfile_path = default_chrome_orderfile - } else if (is_win && is_clang && is_official_build) { - chrome_orderfile_path = "//chrome/build/chrome.$target_cpu.orderfile" } else if (is_chromeos && is_chromeos_device) { chrome_orderfile_path = "//chromeos/profiles/chromeos.orderfile.txt" } @@ -2470,29 +2468,19 @@ } } -if (is_win || is_android || (is_chromeos && is_chromeos_device)) { - # Use orderfile for linking Chrome on win, android, and Chrome OS. +if (is_android || (is_chromeos && is_chromeos_device)) { + # Use orderfile for linking Chrome on Android and Chrome OS. # This config enables using an orderfile for linking in LLD. + # TODO: Consider using call graph sort instead, at least on Android. config("chrome_orderfile_config") { if (chrome_orderfile_path != "" && !enable_call_graph_profile_sort) { assert(use_lld) _rebased_orderfile = rebase_path(chrome_orderfile_path, root_build_dir) - if (is_android || (is_chromeos && is_chromeos_device)) { - ldflags = [ - "-Wl,--symbol-ordering-file", - "-Wl,$_rebased_orderfile", - "-Wl,--no-warn-symbol-ordering", - ] - } else { - ldflags = [ - "/order:@$_rebased_orderfile", - - # Ignore warnings about missing functions or functions not in their - # own section. - "/ignore:4037", - "/ignore:4065", - ] - } + ldflags = [ + "-Wl,--symbol-ordering-file", + "-Wl,$_rebased_orderfile", + "-Wl,--no-warn-symbol-ordering", + ] inputs = [ chrome_orderfile_path ] } }
diff --git a/build/config/win/BUILD.gn b/build/config/win/BUILD.gn index 132ebc85e..e72cbd4f 100644 --- a/build/config/win/BUILD.gn +++ b/build/config/win/BUILD.gn
@@ -579,21 +579,3 @@ config("nominmax") { defines = [ "NOMINMAX" ] } - -# Generating order files ------------------------------------------------------- - -config("default_cygprofile_instrumentation") { - if (generate_order_files) { - assert(is_clang, "cygprofile instrumentation only works with clang") - assert(is_official_build, "order files should be made w/ official builds") - assert(!is_chrome_branded, "order files could leak internal symbol names") - configs = [ ":cygprofile_instrumentation" ] - } -} - -config("cygprofile_instrumentation") { - cflags = [ - "-Xclang", - "-finstrument-functions-after-inlining", - ] -}
diff --git a/cc/layers/texture_layer_unittest.cc b/cc/layers/texture_layer_unittest.cc index 3511e89..fdc4f746 100644 --- a/cc/layers/texture_layer_unittest.cc +++ b/cc/layers/texture_layer_unittest.cc
@@ -1004,6 +1004,7 @@ ++prepare_called_; if (!resource_changed_) return false; + resource_changed_ = false; *resource = resource_; *release_callback = viz::SingleReleaseCallback::Create(base::BindOnce( &TextureLayerChangeInvisibleMailboxTest::ResourceReleased,
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn index c0dfc37..a9bbcad3 100644 --- a/chrome/BUILD.gn +++ b/chrome/BUILD.gn
@@ -360,8 +360,6 @@ "//content/public/app", "//headless:headless_renderer", ] - - configs += [ "//build/config/compiler:chrome_orderfile_config" ] } copy("copy_first_run") {
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index 303fc13..21bcd3d 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -2173,14 +2173,6 @@ deps += [ "//chrome/android/modules/dev_ui/provider:java" ] } - # The arcore manifest needs to be merged into the base module because the Play - # Store verifies the com.google.ar.core.min_apk_version meta-data tag is in - # the base manifest. - if (enable_arcore) { - deps += - [ "//third_party/arcore-android-sdk-client:com_google_ar_core_java" ] - } - srcjar_deps = [ ":chrome_product_config" ] # Add the actual implementation where necessary so that downstream targets
diff --git a/chrome/android/chrome_public_apk_tmpl.gni b/chrome/android/chrome_public_apk_tmpl.gni index 5bd97107..fd5fdd9e2 100644 --- a/chrome/android/chrome_public_apk_tmpl.gni +++ b/chrome/android/chrome_public_apk_tmpl.gni
@@ -528,6 +528,15 @@ # Add all loadable modules and shared libraries from DFMs. if (_enable_chrome_module) { + # The arcore manifest needs to be merged into the base module because the Play + # Store verifies the com.google.ar.core.min_apk_version meta-data tag is in + # the base manifest. + if (enable_arcore) { + deps += [ + "//third_party/arcore-android-sdk-client:com_google_ar_core_java", + ] + } + if (is_monochrome) { deps += [ "//chrome/android:base_monochrome_module_java" ] } else {
diff --git a/chrome/android/expectations/lint-suppressions.xml b/chrome/android/expectations/lint-suppressions.xml index ae96771..c7bed24 100644 --- a/chrome/android/expectations/lint-suppressions.xml +++ b/chrome/android/expectations/lint-suppressions.xml
@@ -1,18 +1,9 @@ <?xml version="1.0" encoding="utf-8" ?> -<lint> - <!-- -STOP! It looks like you want to suppress some lint errors: -- Have you tried identifing the offending patch? - Ask the author for a fix and/or revert the patch. -- It is preferred to add suppressions in the code instead of - sweeping it under the rug here. See: - http://developer.android.com/tools/debugging/improving-w-lint.html - -Still reading? -- Edit this file manually to suppress an issue. Please make the suppression as - local as possible, i.e. by warning message or by file. -- When adding new issues, please keep the issue ids in sorted order. +<!-- +Please refer to the lint doc for how to use this file and what should go in it: +https://chromium.googlesource.com/chromium/src/+/master/build/android/docs/lint.md --> +<lint> <!-- Ignore all lint errors in clank code. --> <issue id="all"> <ignore regexp="^\.\./\.\./clank/"/> @@ -31,15 +22,10 @@ <issue id="IconDensities"> <!-- This is intentional to reduce APK size. See: http://crrev/c/1352161 --> <ignore regexp="chrome/android/features/autofill_assistant/java/res/drawable-*"/> - <!-- crbug.com/457918 is tracking missing assets --> - <ignore regexp="chrome/android/java/res/drawable-xxhdpi"/> - <ignore regexp="chrome/android/java/res/drawable-xxxhdpi"/> + <!-- Originals are gone, so ignore these specific ones: crbug.com/457918 --> + <ignore regexp="btn_bg_holo_active_normal.png, btn_bg_holo_active_pressed.png, btn_bg_holo_pressed.png, logo_card_back.png"/> <!-- This is intentional to save on WebAPKs' size. --> <ignore regexp="chrome/android/webapk/shell_apk/res/drawable-*"/> - <ignore regexp="content/public/android/java/res/drawable-xxhdpi"/> - <ignore regexp="content/public/android/java/res/drawable-xxxhdpi"/> - <ignore regexp="ui/android/java/res/drawable-xxhdpi"/> - <ignore regexp="ui/android/java/res/drawable-xxxhdpi"/> </issue> <issue id="IconDipSize"> <!-- These only need to be 1px for all densities. See: crbug.com/804449 --> @@ -52,16 +38,10 @@ <ignore regexp="tools/android/memconsumer/java/res/drawable/"/> </issue> <issue id="IconMissingDensityFolder"> - <!-- see crbug.com/542435 --> - <ignore regexp="android_webview/nonembedded/java/res"/> - <ignore regexp="android_webview/tools/system_webview_shell/apk/res"/> <!-- This is intentional to reduce APK size. See: http://crrev/c/1352161 --> <ignore regexp="chrome/android/features/autofill_assistant/java/res"/> - <ignore regexp="chrome/android/webapk/shell_apk/res"/> - <!-- crbug.com/457918 is tracking missing assets --> + <!-- Originals are gone, so ignore these specific ones: crbug.com/457918 --> <ignore regexp="components/embedder_support/android/java/res"/> - <ignore regexp="tools/android/push_apps_to_background/res"/> - <ignore regexp="ui/android/java/res"/> </issue> <issue id="ImpliedQuantity"> <ignore regexp="chrome/browser/ui/android/strings/ui_strings_grd"/> @@ -71,18 +51,7 @@ <!-- See https://crbug.com/827265 and comment in the file for context. --> <ignore regexp="chrome/android/java/res_base/xml/network_security_config.xml"/> </issue> - <issue id="InconsistentArrays"> - <ignore regexp="android_webview/locale_paks.resources.zip/values/locale-paks.xml"/> - <ignore regexp="chrome/android/chrome_locale_paks.resources.zip/values/locale-paks.xml"/> - <ignore regexp="preloaded_fonts.xml"/> - </issue> - <issue id="InefficientWeight"> - <ignore regexp="android_webview/tools/system_webview_shell/apk/res/layout/activity_webview_browser.xml"/> - </issue> <issue id="InvalidVectorPath" severity="ignore"/> - <issue id="LabelFor"> - <ignore regexp="android_webview/tools/system_webview_shell/apk/res/layout/activity_webview_browser.xml"/> - </issue> <issue id="LogConditional" severity="ignore"/> <issue id="LongLogTag" severity="ignore"/> <issue id="MergeRootFrame"> @@ -153,10 +122,6 @@ <issue id="ScopedStorage" severity="ignore"/> <issue id="SetJavaScriptEnabled" severity="ignore"/> <issue id="SignatureOrSystemPermissions" severity="ignore"/> - <issue id="StaticFieldLeak"> - <!-- Nice to fix, but not necessary or performance critical. --> - <ignore regexp="This `AsyncTask` class should be static or leaks might occur"/> - </issue> <issue id="StringFormatCount"> <ignore regexp="chrome/browser/ui/android/strings/ui_strings_grd.resources.zip/values-af/android_chrome_strings.xml"/> <ignore regexp="chrome/browser/ui/android/strings/ui_strings_grd.resources.zip/values-cs/android_chrome_strings.xml"/>
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/trigger_scripts/AssistantTriggerScriptBridge.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/trigger_scripts/AssistantTriggerScriptBridge.java index f7a0e0c..fd22c42e 100644 --- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/trigger_scripts/AssistantTriggerScriptBridge.java +++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/trigger_scripts/AssistantTriggerScriptBridge.java
@@ -39,6 +39,7 @@ private long mNativeBridge; private Delegate mDelegate; private Context mContext; + private WebContents mWebContents; private ActivityKeyboardVisibilityDelegate mKeyboardVisibilityDelegate; private KeyboardVisibilityDelegate.KeyboardVisibilityListener mKeyboardVisibilityListener; @@ -59,6 +60,7 @@ Delegate delegate) { mDelegate = delegate; mContext = context; + mWebContents = webContents; mKeyboardVisibilityDelegate = keyboardVisibilityDelegate; mTriggerScript = new AssistantTriggerScript(context, new AssistantTriggerScript.Delegate() { @Override @@ -111,12 +113,19 @@ /** * Used by native to update and show the UI. The header should be updated using {@code * getHeaderModel} prior to calling this function. + * @return true if the trigger script was displayed, else false. */ @CalledByNative - private void showTriggerScript(String[] cancelPopupMenuItems, int[] cancelPopupMenuActions, + private boolean showTriggerScript(String[] cancelPopupMenuItems, int[] cancelPopupMenuActions, List<AssistantChip> leftAlignedChips, int[] leftAlignedChipsActions, List<AssistantChip> rightAlignedChips, int[] rightAlignedChipsActions, boolean resizeVisualViewport) { + // Trigger scripts currently do not support switching activities (such as CCT->tab). + // TODO(b/171776026): Re-inject dependencies on activity change to support CCT->tab. + if (TabUtils.getActivity(TabUtils.fromWebContents(mWebContents)) != mContext) { + return false; + } + // NOTE: the cancel popup menu must be set before the chips are bound. mTriggerScript.setCancelPopupMenu(cancelPopupMenuItems, cancelPopupMenuActions); mTriggerScript.setLeftAlignedChips(leftAlignedChips, leftAlignedChipsActions); @@ -125,6 +134,7 @@ // A trigger script was displayed, users are no longer considered first-time users. AutofillAssistantPreferencesUtil.setAutofillAssistantReturningLiteScriptUser(); + return true; } @CalledByNative @@ -134,6 +144,9 @@ @CalledByNative private void onTriggerScriptFinished(@LiteScriptFinishedState int state) { + if (state == LiteScriptFinishedState.LITE_SCRIPT_PROMPT_FAILED_CANCEL_FOREVER) { + AutofillAssistantPreferencesUtil.setProactiveHelpSwitch(false); + } mDelegate.onTriggerScriptFinished(state); }
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantTriggerScriptIntegrationTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantTriggerScriptIntegrationTest.java index 4effffc..a9aa301 100644 --- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantTriggerScriptIntegrationTest.java +++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantTriggerScriptIntegrationTest.java
@@ -6,15 +6,19 @@ import static androidx.test.espresso.Espresso.onView; import static androidx.test.espresso.action.ViewActions.click; +import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist; import static androidx.test.espresso.assertion.ViewAssertions.matches; import static androidx.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed; import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; +import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription; import static androidx.test.espresso.matcher.ViewMatchers.withId; import static androidx.test.espresso.matcher.ViewMatchers.withText; import static org.hamcrest.CoreMatchers.not; +import static org.chromium.base.test.util.CriteriaHelper.DEFAULT_MAX_TIME_TO_POLL; import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.tapElement; +import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.waitUntilViewAssertionTrue; import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.waitUntilViewMatchesCondition; import android.support.test.InstrumentationRegistry; @@ -219,6 +223,37 @@ @Test @MediumTest @Features.EnableFeatures(ChromeFeatureList.AUTOFILL_ASSISTANT_PROACTIVE_HELP) + public void setCancelForeverFlag() { + TriggerScriptProto.Builder triggerScript = + TriggerScriptProto + .newBuilder() + /* no trigger condition */ + .setUserInterface(createDefaultUI("Hello world", + /* bubbleMessage = */ "", + /* withProgressBar = */ true)); + GetTriggerScriptsResponseProto triggerScripts = + (GetTriggerScriptsResponseProto) GetTriggerScriptsResponseProto.newBuilder() + .addTriggerScripts(triggerScript) + .build(); + setupTriggerScripts(triggerScripts); + startAutofillAssistantOnTab(TEST_PAGE); + + Assert.assertTrue(AutofillAssistantPreferencesUtil.isProactiveHelpSwitchOn()); + waitUntilViewMatchesCondition( + withContentDescription(R.string.autofill_assistant_overflow_options), + isCompletelyDisplayed()); + onView(withContentDescription(R.string.autofill_assistant_overflow_options)) + .perform(click()); + waitUntilViewMatchesCondition(withText("Never show again"), isCompletelyDisplayed()); + onView(withText("Never show again")).perform(click()); + waitUntilViewAssertionTrue( + withText("Hello world"), doesNotExist(), DEFAULT_MAX_TIME_TO_POLL); + Assert.assertFalse(AutofillAssistantPreferencesUtil.isProactiveHelpSwitchOn()); + } + + @Test + @MediumTest + @Features.EnableFeatures(ChromeFeatureList.AUTOFILL_ASSISTANT_PROACTIVE_HELP) public void elementCondition() throws Exception { SelectorProto.Builder touch_area_four = SelectorProto.newBuilder().addFilters( SelectorProto.Filter.newBuilder().setCssSelector("#touch_area_four"));
diff --git a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPreferencesUtil.java b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPreferencesUtil.java index f96a8582..1d485be 100644 --- a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPreferencesUtil.java +++ b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPreferencesUtil.java
@@ -36,6 +36,12 @@ ChromePreferenceKeys.AUTOFILL_ASSISTANT_PROACTIVE_HELP, true); } + /** Enables or disables the proactive help setting. */ + public static void setProactiveHelpSwitch(boolean enabled) { + SharedPreferencesManager.getInstance().writeBoolean( + ChromePreferenceKeys.AUTOFILL_ASSISTANT_PROACTIVE_HELP, enabled); + } + /** Returns whether the user has seen a lite script before or not. */ static boolean isAutofillAssistantFirstTimeLiteScriptUser() { return SharedPreferencesManager.getInstance().readBoolean(
diff --git a/chrome/android/features/cablev2_authenticator/java/src/org/chromium/chrome/browser/webauth/authenticator/QRScanDialog.java b/chrome/android/features/cablev2_authenticator/java/src/org/chromium/chrome/browser/webauth/authenticator/QRScanDialog.java index 6b1ddd91..8ab1422 100644 --- a/chrome/android/features/cablev2_authenticator/java/src/org/chromium/chrome/browser/webauth/authenticator/QRScanDialog.java +++ b/chrome/android/features/cablev2_authenticator/java/src/org/chromium/chrome/browser/webauth/authenticator/QRScanDialog.java
@@ -31,8 +31,10 @@ /** * Displays a preview of what the default (rear) camera can see and processes images for QR * codes. Closes once an applicable QR code has been found. + * + * (Needs to be public because of the way that the Android system works.) */ -class QRScanDialog extends DialogFragment implements Camera.PreviewCallback { +public class QRScanDialog extends DialogFragment implements Camera.PreviewCallback { /** * FIDO QR codes begin with this prefix. This class will ignore QR codes that don't match * this.
diff --git a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java index e0457d78..b112939 100644 --- a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java +++ b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java
@@ -1392,6 +1392,7 @@ @Feature({"StartSurface"}) // clang-format off @CommandLineFlags.Add({BASE_PARAMS + "/single"}) + @DisableIf.Build(sdk_is_less_than = P, message = "https://crbug.com/1150937") public void testShow_SingleAsHomepage_BottomSheet() { // clang-format on if (!mImmediateReturn) {
diff --git a/chrome/android/java/res/menu/main_menu_regroup.xml b/chrome/android/java/res/menu/main_menu_regroup.xml index 840be2e..dad44d2 100644 --- a/chrome/android/java/res/menu/main_menu_regroup.xml +++ b/chrome/android/java/res/menu/main_menu_regroup.xml
@@ -99,13 +99,13 @@ android:icon="@drawable/ic_add" > <menu> <item android:id="@+id/add_to_bookmarks_menu_id" - android:title="@string/menu_add_to_bookmarks" + android:title="@string/menu_bookmarks" android:icon="@drawable/btn_star" /> <item android:id="@+id/add_to_downloads_menu_id" - android:title="@string/menu_add_to_downloads" + android:title="@string/menu_downloads" android:icon="@drawable/ic_file_download_white_24dp" /> <item android:id="@+id/add_to_homescreen_menu_id" - android:title="@string/menu_add_to_homescreen" + android:title="@string/menu_homescreen" android:icon="@drawable/ic_add_to_home_screen" /> </menu> </item>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/appmenu/AppMenuPropertiesDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/app/appmenu/AppMenuPropertiesDelegateImpl.java index 76daf15..484f052 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/app/appmenu/AppMenuPropertiesDelegateImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/app/appmenu/AppMenuPropertiesDelegateImpl.java
@@ -451,6 +451,10 @@ menuOpenWebApkItem, menu, currentTab, shouldShowHomeScreenMenuItem( isChromeScheme, isFileScheme, isContentScheme, isIncognito, url)); + if (addToHomescreenMenuItem.isVisible()) { + // addToHomescreenMenuItem in "Add to" dialog uses a different string. + addToHomescreenMenuItem.setTitle(R.string.menu_homescreen); + } } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java index 639f559..24150a9e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java
@@ -748,6 +748,9 @@ public void onIncognitoStateChanged() {} @Override + public void onNtpStartedLoading() {} + + @Override public void updateLoadingState(boolean updateUrl) { if (updateUrl) onUrlChanged(); updateStatusIcon();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBar.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBar.java index 2028dd3..f9cbfcd 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBar.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBar.java
@@ -11,7 +11,6 @@ import org.chromium.chrome.browser.lifecycle.Destroyable; import org.chromium.chrome.browser.ntp.FakeboxDelegate; -import org.chromium.chrome.browser.ntp.NewTabPage; import org.chromium.chrome.browser.omnibox.voice.VoiceRecognitionHandler; import org.chromium.chrome.browser.tab.Tab; @@ -22,9 +21,6 @@ /** Handle all necessary tasks that can be delayed until initialization completes. */ default void onDeferredStartup() {} - /** Triggered when the current tab has changed to a {@link NewTabPage}. */ - default void onTabLoadingNTP(NewTabPage ntp) {} - /** * Call to force the UI to update the state of various buttons based on whether or not the * current tab is incognito.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarCoordinator.java index 8ddcfa3..23ef7b0 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarCoordinator.java
@@ -22,7 +22,6 @@ import org.chromium.chrome.browser.lifecycle.Destroyable; import org.chromium.chrome.browser.lifecycle.NativeInitObserver; import org.chromium.chrome.browser.ntp.FakeboxDelegate; -import org.chromium.chrome.browser.ntp.NewTabPage; import org.chromium.chrome.browser.omnibox.status.StatusCoordinator; import org.chromium.chrome.browser.omnibox.status.StatusView; import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteCoordinator; @@ -191,11 +190,6 @@ } @Override - public void onTabLoadingNTP(NewTabPage ntp) { - mLocationBarMediator.onTabLoadingNTP(ntp); - } - - @Override public void updateVisualsForState() { mLocationBarMediator.updateVisualsForState(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarDataProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarDataProvider.java index 829d92d..10008af 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarDataProvider.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarDataProvider.java
@@ -33,8 +33,9 @@ void onTitleChanged(); void onUrlChanged(); void onIncognitoStateChanged(); + void onNtpStartedLoading(); // TODO(https://crbug.com/1139481): Add methods for other LocationBarDataProvider - // data, e.g. NTP and security state. + // data, e.g. security state. } /** Adds an observer of changes to LocationBarDataProvider's data. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java index 8e4905a..0356a73 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
@@ -44,7 +44,6 @@ import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.browser.locale.LocaleManager; import org.chromium.chrome.browser.native_page.NativePageFactory; -import org.chromium.chrome.browser.ntp.NewTabPage; import org.chromium.chrome.browser.ntp.NewTabPageUma; import org.chromium.chrome.browser.omnibox.UrlBar.ScrollType; import org.chromium.chrome.browser.omnibox.UrlBarCoordinator.SelectionState; @@ -633,8 +632,7 @@ } } - @CallSuper - /* package */ void onTabLoadingNTP(NewTabPage ntp) {} + protected void onNtpStartedLoading() {} public View getContainerView() { return this;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediator.java index bd78218..18887f6 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediator.java
@@ -14,7 +14,6 @@ import org.chromium.chrome.browser.AppHooks; import org.chromium.chrome.browser.gsa.GSAState; import org.chromium.chrome.browser.ntp.FakeboxDelegate; -import org.chromium.chrome.browser.ntp.NewTabPage; import org.chromium.chrome.browser.omnibox.UrlBar.UrlBarDelegate; import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteCoordinator; import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteDelegate; @@ -93,6 +92,11 @@ mLocationBarLayout.updateMicButtonState(); } + @Override + public void onNtpStartedLoading() { + mLocationBarLayout.onNtpStartedLoading(); + } + // LocationBar implementation. @Override @@ -108,12 +112,6 @@ } @Override - public void onTabLoadingNTP(NewTabPage ntp) { - ntp.setFakeboxDelegate(this); - mLocationBarLayout.onTabLoadingNTP(ntp); - } - - @Override public void updateVisualsForState() { mLocationBarLayout.updateVisualsForState(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarPhone.java index 5b6e2d58..129e91bc 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarPhone.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarPhone.java
@@ -16,7 +16,6 @@ import org.chromium.base.TraceEvent; import org.chromium.chrome.R; -import org.chromium.chrome.browser.ntp.NewTabPage; import org.chromium.ui.interpolators.BakedBezierInterpolator; import java.util.List; @@ -187,8 +186,8 @@ } @Override - void onTabLoadingNTP(NewTabPage ntp) { - super.onTabLoadingNTP(ntp); + protected void onNtpStartedLoading() { + super.onNtpStartedLoading(); updateStatusVisibility(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/voice/VoiceRecognitionHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/voice/VoiceRecognitionHandler.java index 7c32f6f..1dad480 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/voice/VoiceRecognitionHandler.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/voice/VoiceRecognitionHandler.java
@@ -17,11 +17,13 @@ import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; +import org.chromium.base.FeatureList; import org.chromium.base.Log; import org.chromium.base.ThreadUtils; import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.supplier.Supplier; import org.chromium.chrome.R; +import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.omnibox.LocationBarDataProvider; import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteCoordinator; import org.chromium.chrome.browser.preferences.SharedPreferencesManager; @@ -29,6 +31,7 @@ import org.chromium.chrome.browser.settings.SettingsLauncherImpl; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.util.VoiceRecognitionUtil; +import org.chromium.components.embedder_support.util.UrlUtilities; import org.chromium.content_public.browser.NavigationHandle; import org.chromium.content_public.browser.RenderFrameHost; import org.chromium.content_public.browser.WebContents; @@ -54,6 +57,14 @@ // This language is only returned for queries handled by Assistant. @VisibleForTesting static final String VOICE_QUERY_RESULT_LANGUAGES = "android.speech.extra.LANGUAGE"; + // Extra containing the URL of the current page. This is only populated for intents initiated + // via the toolbar button, and is not populated for internal Chrome URLs. + @VisibleForTesting + static final String EXTRA_PAGE_URL = "com.android.chrome.voice.PAGE_URL"; + // Extra containing a string that represents the action taken by Assistant after being opened + // for voice transcription. See AssistantActionPerformed, below. + @VisibleForTesting + static final String EXTRA_ACTION_PERFORMED = "com.android.chrome.voice.ACTION_PERFORMED"; private final Delegate mDelegate; private Long mQueryStartTimeMs; @@ -76,6 +87,20 @@ int HISTOGRAM_BOUNDARY = 5; } + // AssistantActionPerformed defined in tools/metrics/histograms/enums.xml. + // Do not reorder or remove items, only add new items before HISTOGRAM_BOUNDARY. + @IntDef({AssistantActionPerformed.UNKNOWN, AssistantActionPerformed.TRANSCRIPTION, + AssistantActionPerformed.TRANSLATE, AssistantActionPerformed.READOUT}) + public @interface AssistantActionPerformed { + int UNKNOWN = 0; + int TRANSCRIPTION = 1; + int TRANSLATE = 2; + int READOUT = 3; + + // Be sure to also update enums.xml when updating these values. + int HISTOGRAM_BOUNDARY = 4; + } + /** * Delegate interface to provide data to this class from the location bar implementation. */ @@ -238,23 +263,40 @@ } mCallbackComplete = true; + if (resultCode == Activity.RESULT_CANCELED) { + recordVoiceSearchDismissedEventSource(mSource); + return; + } if (resultCode != Activity.RESULT_OK || data.getExtras() == null) { - if (resultCode == Activity.RESULT_CANCELED) { - recordVoiceSearchDismissedEventSource(mSource); - } else { - recordVoiceSearchFailureEventSource(mSource); - } + recordVoiceSearchFailureEventSource(mSource); return; } - // Only record query duration on success. - stopTrackingAndRecordQueryDuration(); + // Assume transcription by default when the page URL feature is disabled. + @AssistantActionPerformed + int actionPerformed = AssistantActionPerformed.TRANSCRIPTION; + if (FeatureList.isInitialized() + && ChromeFeatureList.isEnabled(ChromeFeatureList.ASSISTANT_INTENT_PAGE_URL)) { + actionPerformed = getActionPerformed(data.getExtras()); + } + + recordSuccessMetrics(mSource, actionPerformed); + + if (actionPerformed == AssistantActionPerformed.TRANSCRIPTION) { + handleTranscriptionResult(data); + } + } + + /** + * Processes the transcription results within the given Intent, potentially initiating a + * search or navigation. + * @param data The {@link Intent} with returned transcription data. + */ + private void handleTranscriptionResult(Intent data) { AutocompleteCoordinator autocompleteCoordinator = mDelegate.getAutocompleteCoordinator(); assert autocompleteCoordinator != null; - recordVoiceSearchFinishEventSource(mSource); - List<VoiceResult> voiceResults = convertBundleToVoiceResults(data.getExtras()); autocompleteCoordinator.onVoiceResults(voiceResults); VoiceResult topResult = @@ -314,6 +356,80 @@ } } + /** Returns the action performed by Assistant from the Assistant Intent callback bundle. */ + private static @AssistantActionPerformed int getActionPerformed(Bundle extras) { + assert extras != null; + String actionPerformed = extras.getString(EXTRA_ACTION_PERFORMED); + if (actionPerformed == null) { + // Older versions of Assistant will not set EXTRA_ACTION_PERFORMED. These versions of + // Assistant also do not handle translate or readout, so we should assume transcription. + return AssistantActionPerformed.TRANSCRIPTION; + } + return parseActionPerformed(actionPerformed); + } + + /** + * Parses actionPerformed and returns the associated AssistantActionPerformedValue. + * @param actionPerformed A String representation of the action enum. + * @return The parsed action or AssistantActionPerformed.UNKNOWN if no match was found. + */ + private static @AssistantActionPerformed int parseActionPerformed(String actionPerformed) { + switch (actionPerformed) { + case "TRANSCRIPTION": + return AssistantActionPerformed.TRANSCRIPTION; + case "TRANSLATE": + return AssistantActionPerformed.TRANSLATE; + case "READOUT": + return AssistantActionPerformed.READOUT; + default: + return AssistantActionPerformed.UNKNOWN; + } + } + + /** + * Returns a String for use as a histogram suffix for histograms split by + * AssistantActionPerformed. + * @param action The action performed by the Assistant. + * @return The histogram suffix for the given action. No '.' separator is included. + */ + private static String getHistogramSuffixForAction(@AssistantActionPerformed int action) { + switch (action) { + case AssistantActionPerformed.TRANSCRIPTION: + return "Transcription"; + case AssistantActionPerformed.TRANSLATE: + return "Translate"; + case AssistantActionPerformed.READOUT: + return "Readout"; + default: + return "Unknown"; + } + } + /** + * Returns a String for use as a histogram suffix for histograms split by + * VoiceInteractionSource. + * @param source The source of the voice interaction. + * @return The histogram suffix for the given source or null if unknown. No '.' separator is + * included. + */ + private static @Nullable String getHistogramSuffixForSource( + @VoiceInteractionSource int source) { + switch (source) { + case VoiceInteractionSource.OMNIBOX: + return "Omnibox"; + case VoiceInteractionSource.NTP: + return "NTP"; + case VoiceInteractionSource.SEARCH_WIDGET: + return "SearchWidget"; + case VoiceInteractionSource.TASKS_SURFACE: + return "TasksSurface"; + case VoiceInteractionSource.TOOLBAR: + return "Toolbar"; + default: + assert false : "Unknown VoiceInteractionSource: " + source; + return null; + } + } + /** Convert the android voice intent bundle to a list of result objects. */ @VisibleForTesting protected List<VoiceResult> convertBundleToVoiceResults(Bundle extras) { @@ -466,6 +582,13 @@ Intent intent = assistantVoiceSearchService.getAssistantVoiceSearchIntent(); + if (shouldAddPageUrl(source)) { + String url = getUrl(); + if (url != null) { + intent.putExtra(EXTRA_PAGE_URL, url); + } + } + if (!showSpeechRecognitionIntent(windowAndroid, intent, source)) { mDelegate.updateMicButtonState(); recordVoiceSearchFailureEventSource(source); @@ -477,6 +600,38 @@ } /** + * Returns true if the current tab's URL should be included with an Assistant intent initiated + * via the given source. + */ + private static boolean shouldAddPageUrl(@VoiceInteractionSource int source) { + // Non-toolbar entrypoints (Omnibox, NTP, etc) obscure the current page contents and make it + // less obvious that user actions in Assistant may interact with the current page. Omit the + // page URL in those cases to signal to Assistant that page-actions (e.g. translate, + // readout) should be disallowed. + return source == VoiceInteractionSource.TOOLBAR && FeatureList.isInitialized() + && ChromeFeatureList.isEnabled(ChromeFeatureList.ASSISTANT_INTENT_PAGE_URL); + } + + /** + * Returns the URL of the tab associated with this VoiceRecognitionHandler or null if it is not + * available. + */ + @Nullable + private String getUrl() { + LocationBarDataProvider locationBarDataProvider = mDelegate.getLocationBarDataProvider(); + if (locationBarDataProvider == null) return null; + + Tab currentTab = locationBarDataProvider.getTab(); + if (currentTab == null || currentTab.isIncognito()) { + return null; + } + + GURL pageUrl = currentTab.getUrl(); + if (!UrlUtilities.isHttpOrHttps(pageUrl)) return null; + return pageUrl.getSpec(); + } + + /** * Shows a cancelable speech recognition intent, returning a boolean that indicates if it was * successfully shown. * @@ -519,16 +674,26 @@ mQueryStartTimeMs = SystemClock.elapsedRealtime(); } - /** Calculate the query duration and report it and cleanup afterwards. */ + /** Record metrics that are only logged for successful intent responses. */ @VisibleForTesting - void stopTrackingAndRecordQueryDuration() { + protected void recordSuccessMetrics( + @VoiceInteractionSource int source, @AssistantActionPerformed int action) { // Defensive check to guard against onIntentResult being called more than once. This only // happens with assistant experiments. See crbug.com/1116927 for details. if (mQueryStartTimeMs == null) return; - long elapsedTimeMs = SystemClock.elapsedRealtime() - mQueryStartTimeMs; - recordVoiceSearchOpenDuration(elapsedTimeMs); mQueryStartTimeMs = null; + + recordVoiceSearchFinishEventSource(source); + recordVoiceSearchOpenDuration(elapsedTimeMs); + + // We should only record per-action metrics when the page URL feature is enabled. When + // disabled, only transcription should occur. + if (FeatureList.isInitialized() + && ChromeFeatureList.isEnabled(ChromeFeatureList.ASSISTANT_INTENT_PAGE_URL)) { + recordAssistantActionPerformed(source, action); + recordPerActionVoiceSearchOpenDuration(action, elapsedTimeMs); + } } /** @@ -587,6 +752,22 @@ } /** + * Records the action performed by Assistant as a result of the voice search intent. + * @param action The action performed, such as transcription or translation. Values taken from + * the enum AssistantActionPerformed in enums.xml. + */ + @VisibleForTesting + protected void recordAssistantActionPerformed( + @VoiceInteractionSource int source, @AssistantActionPerformed int action) { + String sourceSuffix = getHistogramSuffixForSource(source); + if (sourceSuffix != null) { + RecordHistogram.recordEnumeratedHistogram( + "VoiceInteraction.AssistantActionPerformed." + sourceSuffix, action, + AssistantActionPerformed.HISTOGRAM_BOUNDARY); + } + } + + /** * Records the result of a voice search. * @param result The result of a voice search, true if results were successfully returned. */ @@ -613,6 +794,14 @@ "VoiceInteraction.QueryDuration.Android", openDurationMs); } + /** Records end-to-end voice search duration split by the action performed. */ + private void recordPerActionVoiceSearchOpenDuration( + @AssistantActionPerformed int action, long openDurationMs) { + String actionSuffix = getHistogramSuffixForAction(action); + RecordHistogram.recordMediumTimesHistogram( + "VoiceInteraction.QueryDuration.Android." + actionSuffix, openDurationMs); + } + /** * Calls into {@link VoiceRecognitionUtil} to determine whether or not the * {@link RecognizerIntent#ACTION_RECOGNIZE_SPEECH} {@link Intent} is handled by any
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninUtils.java index 5ac3931d..f48599c8 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninUtils.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninUtils.java
@@ -20,7 +20,6 @@ import org.chromium.base.annotations.NativeMethods; import org.chromium.chrome.browser.app.ChromeActivity; import org.chromium.chrome.browser.feedback.HelpAndFeedbackLauncherImpl; -import org.chromium.chrome.browser.incognito.interstitial.IncognitoInterstitialDelegate; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.signin.account_picker.AccountConsistencyPromoAction; import org.chromium.chrome.browser.signin.account_picker.AccountPickerBottomSheetCoordinator; @@ -115,15 +114,11 @@ // To create a new incognito tab after after the user clicks on "Continue" in the incognito // interstitial. TabCreator incognitoTabCreator = activity.getTabCreator(/*incognito=*/true); - IncognitoInterstitialDelegate incognitoInterstitialDelegate = - new IncognitoInterstitialDelegate(activity, regularTabModel, incognitoTabCreator, - HelpAndFeedbackLauncherImpl.getInstance()); - - AccountPickerBottomSheetCoordinator coordinator = - new AccountPickerBottomSheetCoordinator(activity, bottomSheetController, - new AccountPickerDelegateImpl(windowAndroid, activity.getActivityTab(), - new WebSigninBridge.Factory(), continueUrl), - incognitoInterstitialDelegate); + AccountPickerBottomSheetCoordinator coordinator = new AccountPickerBottomSheetCoordinator( + activity, bottomSheetController, + new AccountPickerDelegateImpl(windowAndroid, activity.getActivityTab(), + new WebSigninBridge.Factory(), continueUrl), + regularTabModel, incognitoTabCreator, HelpAndFeedbackLauncherImpl.getInstance()); } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetCoordinator.java index 7bd9c3f..4519d33 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetCoordinator.java
@@ -10,8 +10,11 @@ import androidx.annotation.MainThread; import androidx.annotation.VisibleForTesting; +import org.chromium.chrome.browser.feedback.HelpAndFeedbackLauncher; import org.chromium.chrome.browser.incognito.interstitial.IncognitoInterstitialCoordinator; import org.chromium.chrome.browser.incognito.interstitial.IncognitoInterstitialDelegate; +import org.chromium.chrome.browser.tabmodel.TabCreator; +import org.chromium.chrome.browser.tabmodel.TabModel; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController.StateChangeReason; import org.chromium.components.browser_ui.bottomsheet.BottomSheetObserver; @@ -58,6 +61,21 @@ @MainThread public AccountPickerBottomSheetCoordinator(Activity activity, BottomSheetController bottomSheetController, + AccountPickerDelegate accountPickerDelegate, TabModel regularTabModel, + TabCreator incognitoTabCreator, HelpAndFeedbackLauncher helpAndFeedbackLauncher) { + this(activity, bottomSheetController, accountPickerDelegate, + new IncognitoInterstitialDelegate( + activity, regularTabModel, incognitoTabCreator, helpAndFeedbackLauncher)); + } + + /** + * Constructs the AccountPickerBottomSheetCoordinator and shows the + * bottom sheet on the screen. + */ + @VisibleForTesting + @MainThread + public AccountPickerBottomSheetCoordinator(Activity activity, + BottomSheetController bottomSheetController, AccountPickerDelegate accountPickerDelegate, IncognitoInterstitialDelegate incognitoInterstitialDelegate) { AccountPickerDelegate.recordAccountConsistencyPromoAction(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java index 4f64de8..49d67daa 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java
@@ -459,9 +459,7 @@ } // Restore the tabs from the second activity asynchronously. - PostTask.postTask(TaskTraits.BEST_EFFORT_MAY_BLOCK, () -> { - restoreTabs(false); - }); + loadNextTab(); } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java index b26a0873..2d53db6 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java
@@ -172,6 +172,12 @@ return mNtpDelegate; } + void notifyNtpStartedLoading() { + for (Observer observer : mLocationBarDataObservers) { + observer.onNtpStartedLoading(); + } + } + @Override public UrlBarData getUrlBarData() { if (!hasTab()) return UrlBarData.EMPTY;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java index a1c8e89..85323e1 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -460,7 +460,7 @@ if (tab == null) return; refreshSelectedTab(tab); - mToolbar.onTabOrModelChanged(); + onTabOrModelChanged(); } @Override @@ -516,6 +516,7 @@ @Override public void onContentChanged(Tab tab) { if (tab.isNativePage()) TabThemeColorHelper.get(tab).updateIfNeeded(false); + checkIfNtpLoaded(); mToolbar.onTabContentViewChanged(); if (shouldShowCursorInLocationBar()) { mLocationBar.showUrlBarCursorWithoutFocusAnimations(); @@ -537,7 +538,7 @@ if (!UrlUtilities.isNTPUrl(params.getUrl()) && loadType != TabLoadStatus.PAGE_LOAD_FAILED) { ntp.setUrlFocusAnimationsDisabled(true); - mToolbar.onTabOrModelChanged(); + onTabOrModelChanged(); } } @@ -594,7 +595,7 @@ if (ntp == null) return; ntp.setUrlFocusAnimationsDisabled(false); - mToolbar.onTabOrModelChanged(); + onTabOrModelChanged(); } } @@ -766,10 +767,8 @@ client.run(); } }, () -> identityDiscController.getForStartSurface(mStartSurfaceState), - startSurfaceSupplier, () -> { - NewTabPage ntp = getNewTabPageForCurrentTab(); - if (ntp != null) mLocationBar.onTabLoadingNTP(ntp); - }, () -> mLayoutManager.getResourceManager()); + startSurfaceSupplier, + () -> mLayoutManager.getResourceManager()); // clang-format on mHomepageStateListener = () -> { mHomeButtonVisibilitySupplier.set(HomepageManager.isHomepageEnabled()); @@ -1555,7 +1554,7 @@ tab != null ? TabThemeColorHelper.getColor(tab) : defaultPrimaryColor; onThemeColorChanged(primaryColor, false); - mToolbar.onTabOrModelChanged(); + onTabOrModelChanged(); if (tab != null) { mToolbar.onNavigatedToDifferentPage(); @@ -1576,6 +1575,19 @@ updateButtonStatus(); } + private void onTabOrModelChanged() { + mToolbar.onTabOrModelChanged(); + checkIfNtpLoaded(); + } + + private void checkIfNtpLoaded() { + NewTabPage ntp = getNewTabPageForCurrentTab(); + if (ntp != null) { + ntp.setFakeboxDelegate(mLocationBar.getFakeboxDelegate()); + mLocationBarModel.notifyNtpStartedLoading(); + } + } + private void setBookmarkBridge(BookmarkBridge bookmarkBridge) { if (bookmarkBridge == null) return; bookmarkBridge.addObserver(mBookmarksObserver);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java index 8e5d63f..2825fbd 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java
@@ -84,7 +84,6 @@ private AppMenuButtonHelper mAppMenuButtonHelper; private Callback<Boolean> mOverlayVisibilityCallback; - private Runnable mTabOrModelChangeRunnable; /** * Basic constructor for {@link ToolbarLayout}. @@ -116,12 +115,10 @@ */ @CallSuper protected void initialize(ToolbarDataProvider toolbarDataProvider, - ToolbarTabController tabController, MenuButtonCoordinator menuButtonCoordinator, - Runnable tabOrModelChangeRunnable) { + ToolbarTabController tabController, MenuButtonCoordinator menuButtonCoordinator) { mToolbarDataProvider = toolbarDataProvider; mToolbarTabController = tabController; mMenuButtonCoordinator = menuButtonCoordinator; - mTabOrModelChangeRunnable = tabOrModelChangeRunnable; } /** @@ -523,9 +520,7 @@ * tabs but no normal tabs will still allow you to select the normal model), this should * not guarantee that the model's current tab is non-null. */ - void onTabOrModelChanged() { - mTabOrModelChangeRunnable.run(); - } + void onTabOrModelChanged() {} /** * For extending classes to override and carry out the changes related with the primary color @@ -573,9 +568,7 @@ /** * Triggered when the content view for the specified tab has changed. */ - void onTabContentViewChanged() { - mTabOrModelChangeRunnable.run(); - } + void onTabContentViewChanged() {} boolean isReadyForTextureCapture() { return true;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarTablet.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarTablet.java index 5b7700e..db498d8 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarTablet.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarTablet.java
@@ -477,10 +477,8 @@ @Override protected void initialize(ToolbarDataProvider toolbarDataProvider, - ToolbarTabController tabController, MenuButtonCoordinator menuButtonCoordinator, - Runnable tabOrModelChangeRunnable) { - super.initialize(toolbarDataProvider, tabController, menuButtonCoordinator, - tabOrModelChangeRunnable); + ToolbarTabController tabController, MenuButtonCoordinator menuButtonCoordinator) { + super.initialize(toolbarDataProvider, tabController, menuButtonCoordinator); menuButtonCoordinator.setVisibility(true); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java index 305e33f7..8b0609c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java
@@ -121,7 +121,7 @@ ObservableSupplier<Boolean> homeButtonVisibilitySupplier, ObservableSupplier<Boolean> identityDiscStateSupplier, Callback<Runnable> invalidatorCallback, Supplier<ButtonData> identityDiscButtonSupplier, - OneshotSupplier<StartSurface> startSurfaceSupplier, Runnable tabOrModelChangeRunnable, + OneshotSupplier<StartSurface> startSurfaceSupplier, Supplier<ResourceManager> resourceManagerSupplier) { mControlContainer = controlContainer; mToolbarLayout = toolbarLayout; @@ -150,8 +150,7 @@ } } controlContainer.setToolbar(this); - mToolbarLayout.initialize(toolbarDataProvider, tabController, mMenuButtonCoordinator, - tabOrModelChangeRunnable); + mToolbarLayout.initialize(toolbarDataProvider, tabController, mMenuButtonCoordinator); mToolbarLayout.setThemeColorProvider(normalThemeColorProvider); mAppMenuButtonHelperSupplier = appMenuButtonHelperSupplier;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/app/appmenu/TabbedAppMenuTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/app/appmenu/TabbedAppMenuTest.java index e1881e4..8aa1368 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/app/appmenu/TabbedAppMenuTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/app/appmenu/TabbedAppMenuTest.java
@@ -465,10 +465,10 @@ Assert.assertEquals("The dialog should have 2 children, one is title, another is ListView.", 2, addToCustomView.getChildCount()); TextView addToTitle = (TextView) addToCustomView.getChildAt(0); - mRenderTestRule.render(addToTitle, "add_to_dialog_title"); + mRenderTestRule.render(addToTitle, "menu_add_to_dialog_title"); ListView addToList = (ListView) addToCustomView.getChildAt(1); Assert.assertEquals(3, addToList.getChildCount()); - mRenderTestRule.render(addToList, "add_to_dialog_not_bookmarked"); + mRenderTestRule.render(addToList, "items_in_add_to_dialog_not_bookmarked"); } @Test @@ -501,10 +501,10 @@ Assert.assertEquals("The dialog should have 2 children, one is title, another is ListView.", 2, addToCustomView.getChildCount()); TextView addToTitle = (TextView) addToCustomView.getChildAt(0); - mRenderTestRule.render(addToTitle, "add_to_dialog_title"); + mRenderTestRule.render(addToTitle, "menu_add_to_dialog_title"); ListView addToList = (ListView) addToCustomView.getChildAt(1); Assert.assertEquals(3, addToList.getChildCount()); - mRenderTestRule.render(addToList, "add_to_dialog_bookmarked"); + mRenderTestRule.render(addToList, "items_in_add_to_dialog_bookmarked"); AppMenuPropertiesDelegateImpl.setPageBookmarkedForTesting(null); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java index d0ac80c..d6c314c 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java
@@ -188,7 +188,7 @@ @SmallTest @Feature({"NewTabPage", "FeedNewTabPage", "RenderTest"}) @Features.EnableFeatures(ChromeFeatureList.MOBILE_IDENTITY_CONSISTENCY) - public void testRender_SignInPromo() throws Exception { + public void testRender_SignInPromoNoAccounts() throws Exception { // Scroll to the sign in promo in case it is not visible. onView(instanceOf(RecyclerView.class)) .perform(RecyclerViewActions.scrollToPosition(SIGNIN_PROMO_POSITION)); @@ -200,6 +200,20 @@ @SmallTest @Feature({"NewTabPage", "FeedNewTabPage", "RenderTest"}) @Features.EnableFeatures(ChromeFeatureList.MOBILE_IDENTITY_CONSISTENCY) + public void testRender_SignInPromoWithAccount() throws Exception { + mAccountManagerTestRule.addAccount(mAccountManagerTestRule.createProfileDataFromName( + AccountManagerTestRule.TEST_ACCOUNT_EMAIL)); + // Scroll to the sign in promo in case it is not visible. + onView(instanceOf(RecyclerView.class)) + .perform(RecyclerViewActions.scrollToPosition(SIGNIN_PROMO_POSITION)); + mRenderTestRule.render(mNtp.getCoordinatorForTesting().getSignInPromoViewForTesting(), + "sign_in_promo_with_account"); + } + + @Test + @SmallTest + @Feature({"NewTabPage", "FeedNewTabPage", "RenderTest"}) + @Features.EnableFeatures(ChromeFeatureList.MOBILE_IDENTITY_CONSISTENCY) public void testRender_SyncPromo() throws Exception { mAccountManagerTestRule.addTestAccountThenSignin(); // Scroll to the sign in promo in case it is not visible.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/voice/VoiceRecognitionHandlerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/voice/VoiceRecognitionHandlerTest.java index d7aabc3..7182d6a 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/voice/VoiceRecognitionHandlerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/voice/VoiceRecognitionHandlerTest.java
@@ -4,7 +4,10 @@ package org.chromium.chrome.browser.omnibox.voice; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import android.app.Activity; @@ -32,6 +35,7 @@ import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; +import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; import org.chromium.chrome.browser.omnibox.LocationBarDataProvider; @@ -41,15 +45,16 @@ import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteCoordinator; import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteDelegate; import org.chromium.chrome.browser.omnibox.suggestions.OmniboxSuggestionsDropdownEmbedder; +import org.chromium.chrome.browser.omnibox.voice.VoiceRecognitionHandler.AssistantActionPerformed; import org.chromium.chrome.browser.omnibox.voice.VoiceRecognitionHandler.VoiceInteractionSource; import org.chromium.chrome.browser.omnibox.voice.VoiceRecognitionHandler.VoiceResult; import org.chromium.chrome.browser.profiles.Profile; -import org.chromium.chrome.browser.tab.MockTab; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.toolbar.NewTabPageDelegate; import org.chromium.chrome.browser.toolbar.ToolbarDataProvider; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.chrome.test.ChromeTabbedActivityTestRule; +import org.chromium.chrome.test.util.browser.Features.DisableFeatures; import org.chromium.chrome.test.util.browser.Features.EnableFeatures; import org.chromium.components.metrics.OmniboxEventProtos.OmniboxEventProto.PageClassification; import org.chromium.components.omnibox.AutocompleteResult; @@ -60,6 +65,7 @@ import org.chromium.ui.base.WindowAndroid; import org.chromium.ui.base.WindowAndroid.IntentCallback; import org.chromium.ui.modaldialog.ModalDialogManager; +import org.chromium.url.GURL; import java.lang.ref.WeakReference; import java.util.ArrayList; @@ -82,6 +88,8 @@ AssistantVoiceSearchService mAssistantVoiceSearchService; @Mock ModalDialogManager mModalDialogManager; + @Mock + Tab mTab; private TestDataProvider mDataProvider; private TestDelegate mDelegate; @@ -89,7 +97,6 @@ private TestAndroidPermissionDelegate mPermissionDelegate; private TestWindowAndroid mWindowAndroid; private ActivityLifecycleDispatcher mLifecycleDispatcher; - private Tab mTab; private List<VoiceResult> mAutocompleteVoiceResults; private static final OnSuggestionsReceivedListener sEmptySuggestionListener = @@ -114,6 +121,10 @@ private int mFailureSource = -1; @VoiceInteractionSource private int mUnexpectedResultSource = -1; + @AssistantActionPerformed + private int mActionPerformed = -1; + @VoiceInteractionSource + private int mActionPerformedSource = -1; private Boolean mResult; private Float mVoiceConfidenceValue; @@ -132,6 +143,13 @@ } @Override + protected void recordAssistantActionPerformed( + @VoiceInteractionSource int source, @AssistantActionPerformed int action) { + mActionPerformedSource = source; + mActionPerformed = action; + } + + @Override protected void recordVoiceSearchFailureEventSource(@VoiceInteractionSource int source) { mFailureSource = source; } @@ -186,6 +204,16 @@ return mUnexpectedResultSource; } + @AssistantActionPerformed + public int getAssistantActionPerformed() { + return mActionPerformed; + } + + @VoiceInteractionSource + public int getAssistantActionPerformedSource() { + return mActionPerformedSource; + } + public Boolean getVoiceSearchResult() { return mResult; } @@ -517,7 +545,6 @@ TestThreadUtils.runOnUiThreadBlocking(() -> { mWindowAndroid.setAndroidPermissionDelegate(mPermissionDelegate); - mTab = new MockTab(0, false); }); doReturn(false).when(mAssistantVoiceSearchService).shouldRequestAssistantVoiceSearch(); @@ -597,8 +624,8 @@ @Test @SmallTest - @Feature("OmniboxAssistantVoiceSearch") - @EnableFeatures("OmniboxAssistantVoiceSearch") + @Feature({"OmniboxAssistantVoiceSearch"}) + @EnableFeatures({ChromeFeatureList.OMNIBOX_ASSISTANT_VOICE_SEARCH}) public void testStartVoiceRecognition_StartsAssistantVoiceSearch() { doReturn(true).when(mAssistantVoiceSearchService).shouldRequestAssistantVoiceSearch(); startVoiceRecognition(VoiceInteractionSource.OMNIBOX); @@ -610,6 +637,96 @@ @Test @SmallTest + @Feature("AssistantIntentPageUrl") + @EnableFeatures(ChromeFeatureList.ASSISTANT_INTENT_PAGE_URL) + public void testStartVoiceRecognition_ToolbarButtonIncludesPageUrl() { + doReturn(true).when(mAssistantVoiceSearchService).shouldRequestAssistantVoiceSearch(); + GURL url = new GURL("https://example.com"); + doReturn(url).when(mTab).getUrl(); + + startVoiceRecognition(VoiceInteractionSource.TOOLBAR); + + Assert.assertTrue(mWindowAndroid.wasCancelableIntentShown()); + Assert.assertEquals(mIntent, mWindowAndroid.getCancelableIntent()); + verify(mAssistantVoiceSearchService).reportUserEligibility(); + verify(mIntent).putExtra(eq(VoiceRecognitionHandler.EXTRA_PAGE_URL), eq(url.getSpec())); + } + + @Test + @SmallTest + @Feature("AssistantIntentPageUrl") + @EnableFeatures(ChromeFeatureList.ASSISTANT_INTENT_PAGE_URL) + public void testStartVoiceRecognition_OmitPageUrlWhenAssistantVoiceSearchDisabled() { + doReturn(false).when(mAssistantVoiceSearchService).shouldRequestAssistantVoiceSearch(); + GURL url = new GURL("https://example.com"); + doReturn(url).when(mTab).getUrl(); + + startVoiceRecognition(VoiceInteractionSource.TOOLBAR); + + Assert.assertTrue(mWindowAndroid.wasCancelableIntentShown()); + Assert.assertFalse(mWindowAndroid.getCancelableIntent().hasExtra( + VoiceRecognitionHandler.EXTRA_PAGE_URL)); + } + + @Test + @SmallTest + @Feature("AssistantIntentPageUrl") + @EnableFeatures(ChromeFeatureList.ASSISTANT_INTENT_PAGE_URL) + public void testStartVoiceRecognition_OmitPageUrlForNonToolbar() { + doReturn(true).when(mAssistantVoiceSearchService).shouldRequestAssistantVoiceSearch(); + GURL url = new GURL("https://example.com"); + doReturn(url).when(mTab).getUrl(); + + startVoiceRecognition(VoiceInteractionSource.NTP); + + verify(mIntent, never()).putExtra(eq(VoiceRecognitionHandler.EXTRA_PAGE_URL), anyString()); + } + + @Test + @SmallTest + @Feature("AssistantIntentPageUrl") + @EnableFeatures(ChromeFeatureList.ASSISTANT_INTENT_PAGE_URL) + public void testStartVoiceRecognition_OmitPageUrlForIncognito() { + doReturn(true).when(mAssistantVoiceSearchService).shouldRequestAssistantVoiceSearch(); + GURL url = new GURL("https://example.com"); + doReturn(url).when(mTab).getUrl(); + doReturn(true).when(mTab).isIncognito(); + + startVoiceRecognition(VoiceInteractionSource.TOOLBAR); + + verify(mIntent, never()).putExtra(eq(VoiceRecognitionHandler.EXTRA_PAGE_URL), anyString()); + } + + @Test + @SmallTest + @Feature("AssistantIntentPageUrl") + @EnableFeatures(ChromeFeatureList.ASSISTANT_INTENT_PAGE_URL) + public void testStartVoiceRecognition_OmitPageUrlForInternalPages() { + doReturn(true).when(mAssistantVoiceSearchService).shouldRequestAssistantVoiceSearch(); + GURL url = new GURL("chrome://version"); + doReturn(url).when(mTab).getUrl(); + + startVoiceRecognition(VoiceInteractionSource.TOOLBAR); + + verify(mIntent, never()).putExtra(eq(VoiceRecognitionHandler.EXTRA_PAGE_URL), anyString()); + } + + @Test + @SmallTest + @Feature("AssistantIntentPageUrl") + @EnableFeatures(ChromeFeatureList.ASSISTANT_INTENT_PAGE_URL) + public void testStartVoiceRecognition_OmitPageUrlForNonHttp() { + doReturn(true).when(mAssistantVoiceSearchService).shouldRequestAssistantVoiceSearch(); + GURL url = new GURL("ftp://example.org"); + doReturn(url).when(mTab).getUrl(); + + startVoiceRecognition(VoiceInteractionSource.TOOLBAR); + + verify(mIntent, never()).putExtra(eq(VoiceRecognitionHandler.EXTRA_PAGE_URL), anyString()); + } + + @Test + @SmallTest public void testStartVoiceRecognition_StartsVoiceSearchWithFailedIntent() { mWindowAndroid.setCancelableIntentSuccess(false); startVoiceRecognition(VoiceInteractionSource.OMNIBOX); @@ -704,7 +821,7 @@ VoiceInteractionSource.OMNIBOX, mHandler.getVoiceSearchStartEventSource()); Assert.assertEquals( VoiceInteractionSource.OMNIBOX, mHandler.getVoiceSearchFinishEventSource()); - Assert.assertEquals(true, mHandler.getVoiceSearchResult()); + Assert.assertTrue(mHandler.getVoiceSearchResult()); Assert.assertTrue(confidence == mHandler.getVoiceConfidenceValue()); assertVoiceResultsAreEqual( mAutocompleteVoiceResults, new String[] {"testing"}, new float[] {confidence}); @@ -726,7 +843,7 @@ VoiceInteractionSource.OMNIBOX, mHandler.getVoiceSearchStartEventSource()); Assert.assertEquals( VoiceInteractionSource.OMNIBOX, mHandler.getVoiceSearchFinishEventSource()); - Assert.assertEquals(true, mHandler.getVoiceSearchResult()); + Assert.assertTrue(mHandler.getVoiceSearchResult()); Assert.assertTrue(VoiceRecognitionHandler.VOICE_SEARCH_CONFIDENCE_NAVIGATE_THRESHOLD == mHandler.getVoiceConfidenceValue()); assertVoiceResultsAreEqual(mAutocompleteVoiceResults, new String[] {"testing"}, @@ -740,7 +857,7 @@ @Test @SmallTest - public void testCallback_successWithLangues() { + public void testCallback_successWithLanguages() { // Needs to run on the UI thread because we use the TemplateUrlService on success. TestThreadUtils.runOnUiThreadBlocking(() -> { mWindowAndroid.setVoiceResults(createDummyBundle("testing", @@ -750,7 +867,7 @@ VoiceInteractionSource.OMNIBOX, mHandler.getVoiceSearchStartEventSource()); Assert.assertEquals( VoiceInteractionSource.OMNIBOX, mHandler.getVoiceSearchFinishEventSource()); - Assert.assertEquals(true, mHandler.getVoiceSearchResult()); + Assert.assertTrue(mHandler.getVoiceSearchResult()); Assert.assertTrue(VoiceRecognitionHandler.VOICE_SEARCH_CONFIDENCE_NAVIGATE_THRESHOLD == mHandler.getVoiceConfidenceValue()); assertVoiceResultsAreEqual(mAutocompleteVoiceResults, new String[] {"testing"}, @@ -763,6 +880,70 @@ @Test @SmallTest + @Feature("AssistantIntentPageUrl") + @EnableFeatures(ChromeFeatureList.ASSISTANT_INTENT_PAGE_URL) + public void testCallback_nonTranscriptionAction() { + TestThreadUtils.runOnUiThreadBlocking(() -> { + Bundle bundle = new Bundle(); + bundle.putString(VoiceRecognitionHandler.EXTRA_ACTION_PERFORMED, "TRANSLATE"); + + mWindowAndroid.setVoiceResults(bundle); + startVoiceRecognition(VoiceInteractionSource.TOOLBAR); + Assert.assertEquals( + VoiceInteractionSource.TOOLBAR, mHandler.getVoiceSearchStartEventSource()); + Assert.assertEquals( + VoiceInteractionSource.TOOLBAR, mHandler.getVoiceSearchFinishEventSource()); + Assert.assertEquals( + AssistantActionPerformed.TRANSLATE, mHandler.getAssistantActionPerformed()); + Assert.assertEquals( + VoiceInteractionSource.TOOLBAR, mHandler.getAssistantActionPerformedSource()); + Assert.assertEquals(1, + RecordHistogram.getHistogramTotalCountForTesting( + "VoiceInteraction.QueryDuration.Android")); + Assert.assertEquals(1, + RecordHistogram.getHistogramTotalCountForTesting( + "VoiceInteraction.QueryDuration.Android")); + }); + } + + @Test + @SmallTest + @Feature("AssistantIntentPageUrl") + @EnableFeatures(ChromeFeatureList.ASSISTANT_INTENT_PAGE_URL) + public void testCallback_defaultToTranscription() { + TestThreadUtils.runOnUiThreadBlocking(() -> { + mWindowAndroid.setVoiceResults(createDummyBundle( + "testing", VoiceRecognitionHandler.VOICE_SEARCH_CONFIDENCE_NAVIGATE_THRESHOLD)); + startVoiceRecognition(VoiceInteractionSource.TOOLBAR); + Assert.assertEquals( + AssistantActionPerformed.TRANSCRIPTION, mHandler.getAssistantActionPerformed()); + Assert.assertEquals( + VoiceInteractionSource.TOOLBAR, mHandler.getAssistantActionPerformedSource()); + Assert.assertTrue(mHandler.getVoiceSearchResult()); + assertVoiceResultsAreEqual(mAutocompleteVoiceResults, new String[] {"testing"}, + new float[] { + VoiceRecognitionHandler.VOICE_SEARCH_CONFIDENCE_NAVIGATE_THRESHOLD}); + }); + } + + @Test + @SmallTest + @Feature("AssistantIntentPageUrl") + @DisableFeatures(ChromeFeatureList.ASSISTANT_INTENT_PAGE_URL) + public void testCallback_pageUrlExtraDisabled() { + TestThreadUtils.runOnUiThreadBlocking(() -> { + mWindowAndroid.setVoiceResults(createDummyBundle( + "testing", VoiceRecognitionHandler.VOICE_SEARCH_CONFIDENCE_NAVIGATE_THRESHOLD)); + startVoiceRecognition(VoiceInteractionSource.TOOLBAR); + Assert.assertTrue(mHandler.getVoiceSearchResult()); + // Ensure that we don't record UMA when the feature is disabled. + Assert.assertEquals(-1, mHandler.getAssistantActionPerformed()); + Assert.assertEquals(-1, mHandler.getAssistantActionPerformedSource()); + }); + } + + @Test + @SmallTest public void testParseResults_EmptyBundle() { Assert.assertNull(mHandler.convertBundleToVoiceResults(new Bundle())); } @@ -810,22 +991,60 @@ @Test @SmallTest - public void testStopTrackingAndRecordQueryDuration() { + @DisableFeatures(ChromeFeatureList.ASSISTANT_INTENT_PAGE_URL) + public void testRecordSuccessMetrics_noActionMetrics() { mHandler.setQueryStartTimeForTesting(100L); - mHandler.stopTrackingAndRecordQueryDuration(); + mHandler.recordSuccessMetrics( + VoiceInteractionSource.OMNIBOX, AssistantActionPerformed.TRANSCRIPTION); + Assert.assertEquals( + VoiceInteractionSource.OMNIBOX, mHandler.getVoiceSearchFinishEventSource()); + Assert.assertEquals(-1, mHandler.getAssistantActionPerformed()); + Assert.assertEquals(-1, mHandler.getAssistantActionPerformedSource()); Assert.assertEquals(1, RecordHistogram.getHistogramTotalCountForTesting( "VoiceInteraction.QueryDuration.Android")); + // Split action metrics should not be recorded. + Assert.assertEquals(0, + RecordHistogram.getHistogramTotalCountForTesting( + "VoiceInteraction.QueryDuration.Android.Transcription")); } @Test @SmallTest - public void testStopTrackingAndRecordQueryDuration_calledWithNull() { + @EnableFeatures(ChromeFeatureList.ASSISTANT_INTENT_PAGE_URL) + public void testRecordSuccessMetrics_splitActionMetrics() { + mHandler.setQueryStartTimeForTesting(100L); + mHandler.recordSuccessMetrics( + VoiceInteractionSource.OMNIBOX, AssistantActionPerformed.TRANSLATE); + Assert.assertEquals( + VoiceInteractionSource.OMNIBOX, mHandler.getVoiceSearchFinishEventSource()); + Assert.assertEquals( + AssistantActionPerformed.TRANSLATE, mHandler.getAssistantActionPerformed()); + Assert.assertEquals( + VoiceInteractionSource.OMNIBOX, mHandler.getAssistantActionPerformedSource()); + Assert.assertEquals(1, + RecordHistogram.getHistogramTotalCountForTesting( + "VoiceInteraction.QueryDuration.Android")); + Assert.assertEquals(0, + RecordHistogram.getHistogramTotalCountForTesting( + "VoiceInteraction.QueryDuration.Android.Transcription")); + Assert.assertEquals(1, + RecordHistogram.getHistogramTotalCountForTesting( + "VoiceInteraction.QueryDuration.Android.Translate")); + } + + @Test + @SmallTest + public void testRecordSuccessMetrics_calledWithNullStartTime() { mHandler.setQueryStartTimeForTesting(null); - mHandler.stopTrackingAndRecordQueryDuration(); + mHandler.recordSuccessMetrics( + VoiceInteractionSource.OMNIBOX, AssistantActionPerformed.TRANSCRIPTION); Assert.assertEquals(0, RecordHistogram.getHistogramTotalCountForTesting( "VoiceInteraction.QueryDuration.Android")); + Assert.assertEquals(0, + RecordHistogram.getHistogramTotalCountForTesting( + "VoiceInteraction.QueryDuration.Android.Transcription")); } @Test
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/LocationBarMediatorTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/LocationBarMediatorTest.java index 24c1e73..267fa5c 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/LocationBarMediatorTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/LocationBarMediatorTest.java
@@ -8,7 +8,6 @@ import static org.mockito.ArgumentMatchers.notNull; import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import android.content.Context; @@ -26,7 +25,6 @@ import org.chromium.base.supplier.OneshotSupplierImpl; import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.chrome.browser.flags.ChromeFeatureList; -import org.chromium.chrome.browser.ntp.NewTabPage; import org.chromium.chrome.browser.omnibox.voice.AssistantVoiceSearchService; import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory; import org.chromium.chrome.test.util.browser.Features; @@ -85,9 +83,7 @@ @Test public void testOnTabLoadingNtp() { - NewTabPage ntp = mock(NewTabPage.class); - mMediator.onTabLoadingNTP(ntp); - verify(ntp).setFakeboxDelegate(mMediator); - verify(mLocationBarLayout).onTabLoadingNTP(ntp); + mMediator.onNtpStartedLoading(); + verify(mLocationBarLayout).onNtpStartedLoading(); } }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/signin/ConfirmSyncDataStateMachineDelegateTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/signin/ConfirmSyncDataStateMachineDelegateTest.java index dbf1e6cf..17d291e2 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/signin/ConfirmSyncDataStateMachineDelegateTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/signin/ConfirmSyncDataStateMachineDelegateTest.java
@@ -19,7 +19,6 @@ import org.robolectric.shadows.ShadowAlertDialog; import org.chromium.base.test.BaseRobolectricTestRunner; -import org.chromium.base.test.util.DisabledTest; /** Tests for {@link ConfirmSyncDataStateMachineDelegate}. */ @RunWith(BaseRobolectricTestRunner.class) @@ -36,7 +35,6 @@ } @Test - @DisabledTest(message = "https://crbug.com/1145573") public void testTimeoutDialogWhenPositiveButtonPressed() { ConfirmSyncDataStateMachineDelegate.TimeoutDialogListener mockListener = mock(ConfirmSyncDataStateMachineDelegate.TimeoutDialogListener.class); @@ -47,7 +45,6 @@ } @Test - @DisabledTest(message = "https://crbug.com/1145573") public void testTimeoutDialogWhenNegativeButtonPressed() { ConfirmSyncDataStateMachineDelegate.TimeoutDialogListener mockListener = mock(ConfirmSyncDataStateMachineDelegate.TimeoutDialogListener.class); @@ -58,7 +55,6 @@ } @Test - @DisabledTest(message = "https://crbug.com/1145573") public void testProgressDialog() { ConfirmSyncDataStateMachineDelegate.ProgressDialogListener mockListener = mock(ConfirmSyncDataStateMachineDelegate.ProgressDialogListener.class); @@ -69,7 +65,6 @@ } @Test - @DisabledTest(message = "https://crbug.com/1145573") public void testDismissAllDialogs() { ConfirmSyncDataStateMachineDelegate.TimeoutDialogListener mockListener = mock(ConfirmSyncDataStateMachineDelegate.TimeoutDialogListener.class);
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/LocationBarModelUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/LocationBarModelUnitTest.java index 9c0a78c..b461f56d 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/LocationBarModelUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/LocationBarModelUnitTest.java
@@ -167,4 +167,15 @@ regularLocationBarModel.notifyUrlChanged(); verify(mLocationBarDataObserver, times(2)).onUrlChanged(); } + + @Test + @MediumTest + public void testObserversNotified_ntpLoaded() { + LocationBarModel regularLocationBarModel = new TestRegularLocationBarModel(null); + regularLocationBarModel.addObserver(mLocationBarDataObserver); + verify(mLocationBarDataObserver, never()).onNtpStartedLoading(); + + regularLocationBarModel.notifyNtpStartedLoading(); + verify(mLocationBarDataObserver).onNtpStartedLoading(); + } }
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 2af946a04..aab817c 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -1222,6 +1222,7 @@ "policy/messaging_layer/public/report_queue_configuration.h", "policy/messaging_layer/storage/storage.cc", "policy/messaging_layer/storage/storage.h", + "policy/messaging_layer/storage/storage_configuration.h", "policy/messaging_layer/storage/storage_module.cc", "policy/messaging_layer/storage/storage_module.h", "policy/messaging_layer/storage/storage_queue.cc", @@ -1346,8 +1347,12 @@ "prefetch/prefetch_proxy/prefetch_proxy_url_loader_interceptor.h", "prefetch/prefetch_proxy/prefetched_mainframe_response_container.cc", "prefetch/prefetch_proxy/prefetched_mainframe_response_container.h", + "prefetch/search_prefetch/base_search_prefetch_request.cc", + "prefetch/search_prefetch/base_search_prefetch_request.h", "prefetch/search_prefetch/field_trial_settings.cc", "prefetch/search_prefetch/field_trial_settings.h", + "prefetch/search_prefetch/full_body_search_prefetch_request.cc", + "prefetch/search_prefetch/full_body_search_prefetch_request.h", "prefetch/search_prefetch/prefetched_response_container.cc", "prefetch/search_prefetch/prefetched_response_container.h", "prefetch/search_prefetch/search_prefetch_from_string_url_loader.cc", @@ -1356,6 +1361,7 @@ "prefetch/search_prefetch/search_prefetch_service.h", "prefetch/search_prefetch/search_prefetch_service_factory.cc", "prefetch/search_prefetch/search_prefetch_service_factory.h", + "prefetch/search_prefetch/search_prefetch_url_loader.h", "prefetch/search_prefetch/search_prefetch_url_loader_interceptor.cc", "prefetch/search_prefetch/search_prefetch_url_loader_interceptor.h", "prefs/browser_prefs.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index c9c3457..7a1de50da 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -3040,6 +3040,10 @@ flag_descriptions::kVoiceButtonInTopToolbarName, flag_descriptions::kVoiceButtonInTopToolbarDescription, kOsAndroid, FEATURE_VALUE_TYPE(chrome::android::kVoiceButtonInTopToolbar)}, + {"assistant-intent-page-url", + flag_descriptions::kAssistantIntentPageUrlName, + flag_descriptions::kAssistantIntentPageUrlDescription, kOsAndroid, + FEATURE_VALUE_TYPE(chrome::android::kAssistantIntentPageUrl)}, {"share-button-in-top-toolbar", flag_descriptions::kShareButtonInTopToolbarName, flag_descriptions::kShareButtonInTopToolbarDescription, kOsAndroid, @@ -6002,6 +6006,9 @@ {"media-app-annotation", flag_descriptions::kMediaAppAnnotationName, flag_descriptions::kMediaAppAnnotationDescription, kOsCrOS, FEATURE_VALUE_TYPE(chromeos::features::kMediaAppAnnotation)}, + {"media-app-pdf-in-ink", flag_descriptions::kMediaAppPdfInInkName, + flag_descriptions::kMediaAppPdfInInkDescription, kOsCrOS, + FEATURE_VALUE_TYPE(chromeos::features::kMediaAppPdfInInk)}, {"os-settings-polymer3", flag_descriptions::kOsSettingsPolymer3Name, flag_descriptions::kOsSettingsPolymer3Description, kOsCrOS, FEATURE_VALUE_TYPE(chromeos::features::kOsSettingsPolymer3)},
diff --git a/chrome/browser/accessibility/caption_controller.h b/chrome/browser/accessibility/caption_controller.h index 58abc21a..8feb5924 100644 --- a/chrome/browser/accessibility/caption_controller.h +++ b/chrome/browser/accessibility/caption_controller.h
@@ -40,20 +40,6 @@ // class CaptionController : public BrowserListObserver, public KeyedService { public: - // These values are persisted to logs. Entries should not be renumbered and - // numeric values should never be reused. These should be the same as - // LiveCaptionSessionEvent in enums.xml. - enum class SessionEvent { - // We began receiving captions for an audio stream. - kStreamStarted = 0, - // The audio stream ended, meaning no more captions will be received on that - // stream. - kStreamEnded = 1, - // The close button was clicked, so we stopped listening to an audio stream. - kCloseButtonClicked = 2, - kMaxValue = kCloseButtonClicked, - }; - explicit CaptionController(Profile* profile); ~CaptionController() override; CaptionController(const CaptionController&) = delete;
diff --git a/chrome/browser/android/autofill_assistant/trigger_script_bridge_android.cc b/chrome/browser/android/autofill_assistant/trigger_script_bridge_android.cc index c781f71..6eeffd84d 100644 --- a/chrome/browser/android/autofill_assistant/trigger_script_bridge_android.cc +++ b/chrome/browser/android/autofill_assistant/trigger_script_bridge_android.cc
@@ -173,12 +173,13 @@ } last_shown_trigger_script_ = proto; - Java_AssistantTriggerScriptBridge_showTriggerScript( + jboolean success = Java_AssistantTriggerScriptBridge_showTriggerScript( env, java_object_, ToJavaArrayOfStrings(env, cancel_popup_items), ToJavaIntArray(env, cancel_popup_actions), jleft_aligned_chips, ToJavaIntArray(env, left_aligned_chip_actions), jright_aligned_chips, ToJavaIntArray(env, right_aligned_chip_actions), proto.resize_visual_viewport()); + trigger_script_coordinator_->OnTriggerScriptShown(success); } void TriggerScriptBridgeAndroid::OnTriggerScriptHidden() {
diff --git a/chrome/browser/apps/guest_view/web_view_browsertest.cc b/chrome/browser/apps/guest_view/web_view_browsertest.cc index 9f53971..7884bbb 100644 --- a/chrome/browser/apps/guest_view/web_view_browsertest.cc +++ b/chrome/browser/apps/guest_view/web_view_browsertest.cc
@@ -3335,12 +3335,8 @@ registry_service->GetRulesRegistry(rules_registry_id, "ui").get()); // Kill the embedder's render process, so the webview will go as well. - base::Process process = base::Process::DeprecatedGetProcessFromHandle( - embedder_web_contents->GetMainFrame() - ->GetProcess() - ->GetProcess() - .Handle()); - process.Terminate(0, false); + embedder_web_contents->GetMainFrame()->GetProcess()->GetProcess().Terminate( + 0, false); observer->WaitForEmbedderRenderProcessTerminate(); EXPECT_FALSE(
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager.cc b/chrome/browser/chromeos/accessibility/accessibility_manager.cc index 14524078..db763253d2 100644 --- a/chrome/browser/chromeos/accessibility/accessibility_manager.cc +++ b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
@@ -1636,12 +1636,25 @@ } void AccessibilityManager::SetSwitchAccessKeysForTest( - const std::vector<int>& keys) { - // Sets all keys to "Select" command. - ListPrefUpdate update(profile_->GetPrefs(), - ash::prefs::kAccessibilitySwitchAccessSelectKeyCodes); - for (int key : keys) - update->AppendInteger(key); + const std::set<int>& select_keys, + const std::set<int>& next_keys, + const std::set<int>& previous_keys) { + ListPrefUpdate select_update( + profile_->GetPrefs(), + ash::prefs::kAccessibilitySwitchAccessSelectKeyCodes); + for (int key : select_keys) + select_update->AppendInteger(key); + + ListPrefUpdate next_update( + profile_->GetPrefs(), ash::prefs::kAccessibilitySwitchAccessNextKeyCodes); + for (int key : next_keys) + next_update->AppendInteger(key); + + ListPrefUpdate previous_update( + profile_->GetPrefs(), + ash::prefs::kAccessibilitySwitchAccessPreviousKeyCodes); + for (int key : previous_keys) + previous_update->AppendInteger(key); profile_->GetPrefs()->CommitPendingWrite(); }
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager.h b/chrome/browser/chromeos/accessibility/accessibility_manager.h index e297382..4ed94bd1 100644 --- a/chrome/browser/chromeos/accessibility/accessibility_manager.h +++ b/chrome/browser/chromeos/accessibility/accessibility_manager.h
@@ -346,7 +346,9 @@ base::RepeatingCallback<void()> observer); void SetCaretBoundsObserverForTest( base::RepeatingCallback<void(const gfx::Rect&)> observer); - void SetSwitchAccessKeysForTest(const std::vector<int>& keys); + void SetSwitchAccessKeysForTest(const std::set<int>& select_keys, + const std::set<int>& next_keys, + const std::set<int>& previous_keys); const std::set<std::string>& GetAccessibilityCommonEnabledFeaturesForTest() { return accessibility_common_enabled_features_;
diff --git a/chrome/browser/chromeos/accessibility/switch_access_browsertest.cc b/chrome/browser/chromeos/accessibility/switch_access_browsertest.cc index ef46d6dd..1f031be 100644 --- a/chrome/browser/chromeos/accessibility/switch_access_browsertest.cc +++ b/chrome/browser/chromeos/accessibility/switch_access_browsertest.cc
@@ -5,12 +5,15 @@ #include "ash/public/cpp/accessibility_controller.h" #include "chrome/browser/chromeos/accessibility/accessibility_manager.h" #include "chrome/browser/ui/browser.h" +#include "chrome/common/extensions/extension_constants.h" +#include "chrome/test/base/extension_load_waiter_one_shot.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/interactive_test_utils.h" #include "chrome/test/base/ui_test_utils.h" #include "chromeos/constants/chromeos_switches.h" #include "content/public/test/browser_test.h" #include "content/public/test/browser_test_utils.h" +#include "extensions/browser/browsertest_util.h" namespace chromeos { @@ -21,12 +24,17 @@ nullptr, key, false, false, false, false))); } - void EnableSwitchAccess(const std::vector<int>& key_codes) { + void EnableSwitchAccess(const std::set<int>& select_key_codes, + const std::set<int>& next_key_codes, + const std::set<int>& previous_key_codes) { AccessibilityManager* manager = AccessibilityManager::Get(); manager->SetSwitchAccessEnabled(true); - manager->SetSwitchAccessKeysForTest(key_codes); + manager->SetSwitchAccessKeysForTest(select_key_codes, next_key_codes, + previous_key_codes); EXPECT_TRUE(manager->IsSwitchAccessEnabled()); + + InjectFocusRingWatcher(); } std::string GetInputString() { @@ -43,13 +51,109 @@ SwitchAccessTest() = default; ~SwitchAccessTest() override = default; - void SetUpOnMainThread() override {} + void InjectFocusRingWatcher() { + std::string script = R"JS( + let focusRingState = { + 'primary': { + 'role': '', + 'name': '' + }, + 'preview': { + 'role': '', + 'name': '' + } + }; + let expectedType = ''; + let expectedRole = ''; + let expectedName = ''; + let successCallback = null; + + function checkFocusRingState() { + if (expectedType != '' && + focusRingState[expectedType].role == expectedRole && + focusRingState[expectedType].name == expectedName) { + if (successCallback) { + successCallback(); + successCallback = null; + } + } + } + + function waitForFocusRing(type, role, name, callback) { + expectedType = type; + expectedRole = role; + expectedName = name; + successCallback = callback; + checkFocusRingState(); + } + + FocusRingManager.setObserver((primary, preview) => { + if (primary && primary instanceof BackButtonNode) { + focusRingState['primary']['role'] = 'back'; + focusRingState['primary']['name'] = ''; + } else if (primary && primary.automationNode) { + let node = primary.automationNode; + focusRingState['primary']['role'] = node.role; + focusRingState['primary']['name'] = node.name; + } else { + focusRingState['primary']['role'] = ''; + focusRingState['primary']['name'] = ''; + } + if (preview && preview.automationNode) { + let node = preview.automationNode; + focusRingState['preview']['role'] = node.role; + focusRingState['preview']['name'] = node.name; + } else { + focusRingState['preview']['role'] = ''; + focusRingState['preview']['name'] = ''; + } + checkFocusRingState(); + }); + window.domAutomationController.send('ready'); + )JS"; + + // Wait for the extension to load. + base::RunLoop loop; + ExtensionLoadWaiterOneShot waiter; + waiter.WaitForExtension(extension_misc::kSwitchAccessExtensionId, + loop.QuitClosure()); + loop.Run(); + + std::string result = + extensions::browsertest_util::ExecuteScriptInBackgroundPage( + browser()->profile(), extension_misc::kSwitchAccessExtensionId, + script); + ASSERT_EQ("ready", result); + } + + // Waits for a focus ring of type |type| (primary or preview) with a + // role of |role| and a name of |name| to appear and then returns. + void WaitForFocusRing(const std::string& type, + const std::string& role, + const std::string& name) { + ASSERT_TRUE(type == "primary" || type == "preview"); + std::string script = base::StringPrintf( + R"JS( + waitForFocusRing("%s", "%s", "%s", () => { + window.domAutomationController.send('ok'); + }); + )JS", + type.c_str(), role.c_str(), name.c_str()); + + std::string result = + extensions::browsertest_util::ExecuteScriptInBackgroundPage( + browser()->profile(), extension_misc::kSwitchAccessExtensionId, + script, + extensions::browsertest_util::ScriptUserActivation::kDontActivate); + ASSERT_EQ(result, "ok"); + } }; // TODO(anastasi): Add a test for typing with the virtual keyboard. IN_PROC_BROWSER_TEST_F(SwitchAccessTest, ConsumesKeyEvents) { - EnableSwitchAccess({'1', '2', '3', '4'}); + EnableSwitchAccess({'1', 'A'} /* select */, {'2', 'B'} /* next */, + {'3', 'C'} /* previous */); // Load a webpage with a text box. ui_test_utils::NavigateToURL( browser(), GURL("data:text/html;charset=utf-8,<input type=text id=in>")); @@ -70,4 +174,32 @@ EXPECT_STREQ("x", GetInputString().c_str()); } +IN_PROC_BROWSER_TEST_F(SwitchAccessTest, NavigateGroupings) { + EnableSwitchAccess({'1', 'A'} /* select */, {'2', 'B'} /* next */, + {'3', 'C'} /* previous */); + + // Load a webpage with two groups of controls. + ui_test_utils::NavigateToURL(browser(), GURL(R"HTML(data:text/html, + <div aria-label=Top> + <button autofocus>Northwest</button> + <button>Northeast</button> + </div> + <div aria-label=Bottom> + <button>Southwest</button> + <button>Southeast</button> + </div> + )HTML")); + + // Wait for switch access to focus on the first button. + WaitForFocusRing("primary", "button", "Northwest"); + + // Go to the next element by pressing the next switch. + SendVirtualKeyPress(ui::KeyboardCode::VKEY_2); + WaitForFocusRing("primary", "button", "Northeast"); + + // Next is the back button. + SendVirtualKeyPress(ui::KeyboardCode::VKEY_2); + WaitForFocusRing("primary", "back", ""); +} + } // namespace chromeos
diff --git a/chrome/browser/chromeos/arc/session/arc_service_launcher.cc b/chrome/browser/chromeos/arc/session/arc_service_launcher.cc index d5dfb80..0f33b7f 100644 --- a/chrome/browser/chromeos/arc/session/arc_service_launcher.cc +++ b/chrome/browser/chromeos/arc/session/arc_service_launcher.cc
@@ -237,7 +237,7 @@ ArcVolumeMounterBridge::GetForBrowserContext(profile); ArcWakeLockBridge::GetForBrowserContext(profile); ArcWallpaperService::GetForBrowserContext(profile); - GpuArcVideoServiceHost::GetForBrowserContext(profile); + GpuArcVideoKeyedService::GetForBrowserContext(profile); apps::ArcAppsFactory::GetForProfile(profile); chromeos::ApkWebAppService::Get(profile);
diff --git a/chrome/browser/chromeos/arc/video/gpu_arc_video_service_host.cc b/chrome/browser/chromeos/arc/video/gpu_arc_video_service_host.cc index 3ef2f965..d34c2da 100644 --- a/chrome/browser/chromeos/arc/video/gpu_arc_video_service_host.cc +++ b/chrome/browser/chromeos/arc/video/gpu_arc_video_service_host.cc
@@ -11,7 +11,6 @@ #include "base/bind.h" #include "base/check_op.h" #include "base/location.h" -#include "base/memory/singleton.h" #include "base/rand_util.h" #include "base/strings/string_number_conversions.h" #include "base/threading/thread_checker.h" @@ -32,23 +31,24 @@ namespace { -// Singleton factory for GpuArcVideoServiceHost. -class GpuArcVideoServiceHostFactory +// Singleton factory for GpuArcVideoKeyedService. +class GpuArcVideoKeyedServiceFactory : public internal::ArcBrowserContextKeyedServiceFactoryBase< - GpuArcVideoServiceHost, - GpuArcVideoServiceHostFactory> { + GpuArcVideoKeyedService, + GpuArcVideoKeyedServiceFactory> { public: // Factory name used by ArcBrowserContextKeyedServiceFactoryBase. - static constexpr const char* kName = "GpuArcVideoServiceHostFactory"; + static constexpr const char* kName = "GpuArcVideoKeyedServiceFactory"; - static GpuArcVideoServiceHostFactory* GetInstance() { - return base::Singleton<GpuArcVideoServiceHostFactory>::get(); + static GpuArcVideoKeyedServiceFactory* GetInstance() { + static base::NoDestructor<GpuArcVideoKeyedServiceFactory> instance; + return instance.get(); } private: - friend base::DefaultSingletonTraits<GpuArcVideoServiceHostFactory>; - GpuArcVideoServiceHostFactory() = default; - ~GpuArcVideoServiceHostFactory() override = default; + friend class base::NoDestructor<GpuArcVideoKeyedServiceFactory>; + GpuArcVideoKeyedServiceFactory() = default; + ~GpuArcVideoKeyedServiceFactory() override = default; }; class VideoAcceleratorFactoryService : public mojom::VideoAcceleratorFactory { @@ -91,25 +91,38 @@ } // namespace // static -GpuArcVideoServiceHost* GpuArcVideoServiceHost::GetForBrowserContext( +GpuArcVideoKeyedService* GpuArcVideoKeyedService::GetForBrowserContext( content::BrowserContext* context) { - return GpuArcVideoServiceHostFactory::GetForBrowserContext(context); + return GpuArcVideoKeyedServiceFactory::GetForBrowserContext(context); } -GpuArcVideoServiceHost::GpuArcVideoServiceHost(content::BrowserContext* context, - ArcBridgeService* bridge_service) - : arc_bridge_service_(bridge_service), - video_accelerator_factory_( - std::make_unique<VideoAcceleratorFactoryService>()) { +GpuArcVideoKeyedService::GpuArcVideoKeyedService( + content::BrowserContext* context, + ArcBridgeService* bridge_service) + : arc_bridge_service_(bridge_service) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - arc_bridge_service_->video()->SetHost(this); + arc_bridge_service_->video()->SetHost(GpuArcVideoServiceHost::Get()); } -GpuArcVideoServiceHost::~GpuArcVideoServiceHost() { +GpuArcVideoKeyedService::~GpuArcVideoKeyedService() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); arc_bridge_service_->video()->SetHost(nullptr); } +GpuArcVideoServiceHost::GpuArcVideoServiceHost() + : video_accelerator_factory_( + std::make_unique<VideoAcceleratorFactoryService>()) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); +} + +GpuArcVideoServiceHost::~GpuArcVideoServiceHost() = default; + +// static +GpuArcVideoServiceHost* GpuArcVideoServiceHost::GpuArcVideoServiceHost::Get() { + static base::NoDestructor<GpuArcVideoServiceHost> instance; + return instance.get(); +} + void GpuArcVideoServiceHost::OnBootstrapVideoAcceleratorFactory( OnBootstrapVideoAcceleratorFactoryCallback callback) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
diff --git a/chrome/browser/chromeos/arc/video/gpu_arc_video_service_host.h b/chrome/browser/chromeos/arc/video/gpu_arc_video_service_host.h index a2d7491..3d17f2f 100644 --- a/chrome/browser/chromeos/arc/video/gpu_arc_video_service_host.h +++ b/chrome/browser/chromeos/arc/video/gpu_arc_video_service_host.h
@@ -6,6 +6,7 @@ #define CHROME_BROWSER_CHROMEOS_ARC_VIDEO_GPU_ARC_VIDEO_SERVICE_HOST_H_ #include "base/macros.h" +#include "base/no_destructor.h" #include "components/arc/mojom/video.mojom.h" #include "components/keyed_service/core/keyed_service.h" #include "mojo/public/cpp/bindings/receiver_set.h" @@ -25,29 +26,43 @@ // VideoDecodeAccelerator or VideoEncodeAccelerator run in the GPU process. // // Lives on the UI thread. -class GpuArcVideoServiceHost : public KeyedService, - public mojom::VideoHost { +class GpuArcVideoServiceHost : public mojom::VideoHost { public: - // Returns singleton instance for the given BrowserContext, - // or nullptr if the browser |context| is not allowed to use ARC. - static GpuArcVideoServiceHost* GetForBrowserContext( - content::BrowserContext* context); - - GpuArcVideoServiceHost(content::BrowserContext* context, - ArcBridgeService* bridge_service); - ~GpuArcVideoServiceHost() override; + static GpuArcVideoServiceHost* Get(); // arc::mojom::VideoHost implementation. void OnBootstrapVideoAcceleratorFactory( OnBootstrapVideoAcceleratorFactoryCallback callback) override; + GpuArcVideoServiceHost(const GpuArcVideoServiceHost&) = delete; + GpuArcVideoServiceHost& operator=(const GpuArcVideoServiceHost&) = delete; + private: - ArcBridgeService* const arc_bridge_service_; // Owned by ArcServiceManager. + friend class base::NoDestructor<GpuArcVideoServiceHost>; + + GpuArcVideoServiceHost(); + ~GpuArcVideoServiceHost() override; + std::unique_ptr<mojom::VideoAcceleratorFactory> video_accelerator_factory_; mojo::ReceiverSet<mojom::VideoAcceleratorFactory> video_accelerator_factory_receivers_; +}; - DISALLOW_COPY_AND_ASSIGN(GpuArcVideoServiceHost); +class GpuArcVideoKeyedService : public KeyedService { + public: + // Returns singleton instance for the given BrowserContext, + // or nullptr if the browser |context| is not allowed to use ARC. + static GpuArcVideoKeyedService* GetForBrowserContext( + content::BrowserContext* context); + + GpuArcVideoKeyedService(content::BrowserContext* context, + ArcBridgeService* bridge_service); + GpuArcVideoKeyedService(const GpuArcVideoKeyedService&) = delete; + GpuArcVideoKeyedService& operator=(const GpuArcVideoKeyedService&) = delete; + ~GpuArcVideoKeyedService() override; + + private: + ArcBridgeService* const arc_bridge_service_; // Owned by ArcServiceManager. }; } // namespace arc
diff --git a/chrome/browser/chromeos/dbus/libvda_service_provider.cc b/chrome/browser/chromeos/dbus/libvda_service_provider.cc index 7f5528ef..f7de325 100644 --- a/chrome/browser/chromeos/dbus/libvda_service_provider.cc +++ b/chrome/browser/chromeos/dbus/libvda_service_provider.cc
@@ -8,9 +8,7 @@ #include <utility> #include "base/bind.h" -#include "chrome/browser/chromeos/arc/session/arc_session_manager.h" #include "chrome/browser/chromeos/arc/video/gpu_arc_video_service_host.h" -#include "chrome/browser/profiles/profile.h" #include "dbus/bus.h" #include "dbus/message.h" #include "mojo/public/cpp/system/platform_handle.h" @@ -42,20 +40,8 @@ void LibvdaServiceProvider::ProvideMojoConnection( dbus::MethodCall* method_call, dbus::ExportedObject::ResponseSender response_sender) { - arc::ArcSessionManager* arc_session_manager = arc::ArcSessionManager::Get(); - if (!arc_session_manager) { - std::move(response_sender) - .Run(dbus::ErrorResponse::FromMethodCall( - method_call, DBUS_ERROR_FAILED, - "Could not find ARC session manager")); - return; - } - // LibvdaService will return the GpuArcVideoServiceHost instance that - // corresponds to the same profile used by ARC++. This might have to be - // changed if callers other than ARCVM use this service. arc::GpuArcVideoServiceHost* gpu_arc_video_service_host = - arc::GpuArcVideoServiceHost::GetForBrowserContext( - arc_session_manager->profile()); + arc::GpuArcVideoServiceHost::Get(); gpu_arc_video_service_host->OnBootstrapVideoAcceleratorFactory(base::BindOnce( &LibvdaServiceProvider::OnBootstrapVideoAcceleratorFactoryCallback, weak_ptr_factory_.GetWeakPtr(), method_call, std::move(response_sender)));
diff --git a/chrome/browser/chromeos/login/saml/password_sync_token_verifier.cc b/chrome/browser/chromeos/login/saml/password_sync_token_verifier.cc index 9421f9f..8dc5d97 100644 --- a/chrome/browser/chromeos/login/saml/password_sync_token_verifier.cc +++ b/chrome/browser/chromeos/login/saml/password_sync_token_verifier.cc
@@ -171,9 +171,16 @@ void PasswordSyncTokenVerifier::OnApiCallFailed( PasswordSyncTokenFetcher::ErrorType error_type) { retry_backoff_.InformOfRequest(false); - // Schedule next token check with interval calculated with exponential - // backoff. - RecheckAfter(retry_backoff_.GetTimeUntilRelease()); + password_sync_token_fetcher_.reset(); + if (error_type == PasswordSyncTokenFetcher::ErrorType::kGetNoList || + error_type == PasswordSyncTokenFetcher::ErrorType::kGetNoToken) { + // Token sync API has not been initialized yet. Create a sync token. + CreateTokenAsync(); + } else { + // Schedule next token check with interval calculated with exponential + // backoff. + RecheckAfter(retry_backoff_.GetTimeUntilRelease()); + } } } // namespace chromeos
diff --git a/chrome/browser/chromeos/login/saml/password_sync_token_verifier_unittest.cc b/chrome/browser/chromeos/login/saml/password_sync_token_verifier_unittest.cc index 80bc516..2488bf6 100644 --- a/chrome/browser/chromeos/login/saml/password_sync_token_verifier_unittest.cc +++ b/chrome/browser/chromeos/login/saml/password_sync_token_verifier_unittest.cc
@@ -201,6 +201,19 @@ kSyncToken); } +TEST_F(PasswordSyncTokenVerifierTest, InitialSyncTokenListEmpty) { + CreatePasswordSyncTokenVerifier(); + verifier_->FetchSyncTokenOnReauth(); + verifier_->OnApiCallFailed(PasswordSyncTokenFetcher::ErrorType::kGetNoList); + verifier_->OnTokenCreated(kSyncToken); + EXPECT_EQ( + user_manager::known_user::GetPasswordSyncToken(saml_login_account_id_), + kSyncToken); + EXPECT_EQ( + primary_profile_->GetPrefs()->GetString(prefs::kSamlPasswordSyncToken), + kSyncToken); +} + TEST_F(PasswordSyncTokenVerifierTest, SyncTokenInitForUser) { CreatePasswordSyncTokenVerifier(); verifier_->FetchSyncTokenOnReauth();
diff --git a/chrome/browser/chromeos/policy/auto_enrollment_client_impl.cc b/chrome/browser/chromeos/policy/auto_enrollment_client_impl.cc index 6cf610547..296252fa 100644 --- a/chrome/browser/chromeos/policy/auto_enrollment_client_impl.cc +++ b/chrome/browser/chromeos/policy/auto_enrollment_client_impl.cc
@@ -23,6 +23,7 @@ #include "components/policy/core/common/cloud/device_management_service.h" #include "components/policy/core/common/cloud/dm_auth.h" #include "components/policy/core/common/cloud/dmserver_job_configurations.h" +#include "components/policy/core/common/cloud/enterprise_metrics.h" #include "components/policy/proto/device_management_backend.pb.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_service.h" @@ -50,15 +51,9 @@ constexpr base::TimeDelta kPrivateSetMembershipTimeout = base::TimeDelta::FromSeconds(15); -// UMA histogram names. +// Hash dance success time UMA histogram. constexpr char kUMAHashDanceSuccessTime[] = "Enterprise.AutoEnrollmentHashDanceSuccessTime"; -constexpr char kUMAPrivateSetMembershipHashDanceComparison[] = - "Enterprise.AutoEnrollmentPrivateSetMembershipHashDanceComparison"; -constexpr char kUMAPrivateSetMembershipSuccessTime[] = - "Enterprise.AutoEnrollmentPrivateSetMembershipSuccessTime"; -constexpr char kUMAPrivateSetMembershipRequestStatus[] = - "Enterprise.AutoEnrollmentPrivateSetMembershipRequestStatus"; // The following histogram names where added before private set membership // existed. They are only recorded for hash dance.
diff --git a/chrome/browser/chromeos/policy/auto_enrollment_client_impl_unittest.cc b/chrome/browser/chromeos/policy/auto_enrollment_client_impl_unittest.cc index a58acd36..8bd73ff 100644 --- a/chrome/browser/chromeos/policy/auto_enrollment_client_impl_unittest.cc +++ b/chrome/browser/chromeos/policy/auto_enrollment_client_impl_unittest.cc
@@ -103,7 +103,7 @@ enum class AutoEnrollmentProtocol { kFRE = 0, kInitialEnrollment = 1 }; -enum class PrivateSetMembershipStatus { kEnabled = 0, kDisabled = 1 }; +enum class PrivateSetMembershipState { kEnabled = 0, kDisabled = 1 }; // Holds the state of the AutoEnrollmentClientImplTest and its subclass i.e. // PrivateSetMembershipHelperTest. It will be used to run their tests with @@ -111,12 +111,12 @@ struct AutoEnrollmentClientImplTestState final { AutoEnrollmentClientImplTestState( AutoEnrollmentProtocol auto_enrollment_protocol, - PrivateSetMembershipStatus private_set_membership_status) + PrivateSetMembershipState private_set_membership_state) : auto_enrollment_protocol(auto_enrollment_protocol), - private_set_membership_status(private_set_membership_status) {} + private_set_membership_state(private_set_membership_state) {} AutoEnrollmentProtocol auto_enrollment_protocol; - PrivateSetMembershipStatus private_set_membership_status; + PrivateSetMembershipState private_set_membership_state; }; // The integer parameter represents the index of private set membership test @@ -146,8 +146,8 @@ return std::get<0>(GetParam()).auto_enrollment_protocol; } - PrivateSetMembershipStatus GetPrivateSetMembershipStatus() { - return std::get<0>(GetParam()).private_set_membership_status; + PrivateSetMembershipState GetPrivateSetMembershipState() { + return std::get<0>(GetParam()).private_set_membership_state; } int GetPrivateSetMembershipTestCaseIndex() { return std::get<1>(GetParam()); } @@ -1139,7 +1139,7 @@ testing::Combine( testing::Values(AutoEnrollmentClientImplTestState( AutoEnrollmentProtocol::kFRE, - PrivateSetMembershipStatus::kDisabled)), + PrivateSetMembershipState::kDisabled)), testing::Values(kInvalidPrivateSetMembershipTestCaseIndex))); // Private set membership is disabed to test only initial enrollment case @@ -1151,7 +1151,7 @@ testing::Combine( testing::Values(AutoEnrollmentClientImplTestState( AutoEnrollmentProtocol::kInitialEnrollment, - PrivateSetMembershipStatus::kDisabled)), + PrivateSetMembershipState::kDisabled)), testing::Values(kInvalidPrivateSetMembershipTestCaseIndex))); using AutoEnrollmentClientImplFREToInitialEnrollmentTest = @@ -1258,11 +1258,11 @@ testing::Combine( testing::Values(AutoEnrollmentClientImplTestState( AutoEnrollmentProtocol::kFRE, - PrivateSetMembershipStatus::kDisabled)), + PrivateSetMembershipState::kDisabled)), testing::Values(kInvalidPrivateSetMembershipTestCaseIndex))); // This class is used to test any private set membership related test cases -// only. Therefore, the PrivateSetMembershipStatus param has to be kEnabled. +// only. Therefore, the PrivateSetMembershipState param has to be kEnabled. class PrivateSetMembershipHelperTest : public AutoEnrollmentClientImplTest { protected: // Indicates the state of the private set membership protocol. @@ -1284,11 +1284,11 @@ } void SetUp() override { - // Verify that PrivateSetMembershipStatus has value kEnabled, then enable + // Verify that PrivateSetMembershipState has value kEnabled, then enable // private set membership switch // prefs::kEnterpriseEnablePrivateSetMembership. - ASSERT_EQ(GetPrivateSetMembershipStatus(), - PrivateSetMembershipStatus::kEnabled); + ASSERT_EQ(GetPrivateSetMembershipState(), + PrivateSetMembershipState::kEnabled); base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( chromeos::switches::kEnterpriseEnablePrivateSetMembership, "always"); @@ -1642,7 +1642,7 @@ PrivateSetMembershipHelperTest, testing::Combine(testing::Values(AutoEnrollmentClientImplTestState( AutoEnrollmentProtocol::kInitialEnrollment, - PrivateSetMembershipStatus::kEnabled)), + PrivateSetMembershipState::kEnabled)), ::testing::Range(0, kNumberOfPrivateSetMembershipTestCases))); @@ -1937,7 +1937,7 @@ PrivateSetMembershipHelperAndHashDanceTest, testing::Combine(testing::Values(AutoEnrollmentClientImplTestState( AutoEnrollmentProtocol::kInitialEnrollment, - PrivateSetMembershipStatus::kEnabled)), + PrivateSetMembershipState::kEnabled)), ::testing::Range(0, kNumberOfPrivateSetMembershipTestCases))); } // namespace
diff --git a/chrome/browser/chromeos/web_applications/chrome_media_app_ui_delegate.cc b/chrome/browser/chromeos/web_applications/chrome_media_app_ui_delegate.cc index 6f099e3..3bcf980 100644 --- a/chrome/browser/chromeos/web_applications/chrome_media_app_ui_delegate.cc +++ b/chrome/browser/chromeos/web_applications/chrome_media_app_ui_delegate.cc
@@ -43,7 +43,8 @@ source->AddBoolean( "imageAnnotation", base::FeatureList::IsEnabled(chromeos::features::kMediaAppAnnotation)); - + source->AddBoolean("pdfInInk", base::FeatureList::IsEnabled( + chromeos::features::kMediaAppPdfInInk)); version_info::Channel channel = chrome::GetChannel(); source->AddBoolean("flagsMenu", channel != version_info::Channel::BETA && channel != version_info::Channel::STABLE);
diff --git a/chrome/browser/extensions/api/content_settings/content_settings_apitest.cc b/chrome/browser/extensions/api/content_settings/content_settings_apitest.cc index ddc737f..62f6f4f7 100644 --- a/chrome/browser/extensions/api/content_settings/content_settings_apitest.cc +++ b/chrome/browser/extensions/api/content_settings/content_settings_apitest.cc
@@ -259,28 +259,7 @@ ExtensionContentSettingsApiLazyTest, ::testing::Values(ContextType::kServiceWorker)); -class ExtensionContentSettingsApiTestWithStandardFeatures - : public ExtensionContentSettingsApiLazyTest { - public: - ExtensionContentSettingsApiTestWithStandardFeatures() { - scoped_feature_list_.InitAndEnableFeature( - content_settings::kDisallowWildcardsInPluginContentSettings); - } - - private: - base::test::ScopedFeatureList scoped_feature_list_; -}; - -INSTANTIATE_TEST_SUITE_P(EventPage, - ExtensionContentSettingsApiTestWithStandardFeatures, - ::testing::Values(ContextType::kEventPage)); - -INSTANTIATE_TEST_SUITE_P(ServiceWorker, - ExtensionContentSettingsApiTestWithStandardFeatures, - ::testing::Values(ContextType::kServiceWorker)); - -IN_PROC_BROWSER_TEST_P(ExtensionContentSettingsApiTestWithStandardFeatures, - Standard) { +IN_PROC_BROWSER_TEST_P(ExtensionContentSettingsApiLazyTest, Standard) { CheckContentSettingsDefault(); const char kExtensionPath[] = "content_settings/standard"; @@ -384,34 +363,12 @@ "ContentSettings.ExtensionNonEmbeddedSettingSet", 2); } -class ExtensionContentSettingsApiTestWithPluginsApiDisabled - : public ExtensionContentSettingsApiLazyTest { - public: - ExtensionContentSettingsApiTestWithPluginsApiDisabled() { - scoped_feature_list_.InitAndEnableFeature( - content_settings::kDisallowWildcardsInPluginContentSettings); - } - - private: - base::test::ScopedFeatureList scoped_feature_list_; -}; - -INSTANTIATE_TEST_SUITE_P(EventPage, - ExtensionContentSettingsApiTestWithPluginsApiDisabled, - ::testing::Values(ContextType::kEventPage)); - -INSTANTIATE_TEST_SUITE_P(ServiceWorker, - ExtensionContentSettingsApiTestWithPluginsApiDisabled, - ::testing::Values(ContextType::kServiceWorker)); - -IN_PROC_BROWSER_TEST_P(ExtensionContentSettingsApiTestWithPluginsApiDisabled, - PluginsApiTest) { +IN_PROC_BROWSER_TEST_P(ExtensionContentSettingsApiLazyTest, PluginsApiTest) { constexpr char kExtensionPath[] = "content_settings/disablepluginsapi"; EXPECT_TRUE(RunLazyTest(kExtensionPath)) << message_; } -IN_PROC_BROWSER_TEST_P(ExtensionContentSettingsApiTestWithPluginsApiDisabled, - ConsoleErrorTest) { +IN_PROC_BROWSER_TEST_P(ExtensionContentSettingsApiLazyTest, ConsoleErrorTest) { constexpr char kExtensionPath[] = "content_settings/disablepluginsapi"; const extensions::Extension* extension = LoadExtension(test_data_dir_.AppendASCII(kExtensionPath));
diff --git a/chrome/browser/extensions/api/content_settings/content_settings_store.cc b/chrome/browser/extensions/api/content_settings/content_settings_store.cc index 8efe962..6e380a9d 100644 --- a/chrome/browser/extensions/api/content_settings/content_settings_store.cc +++ b/chrome/browser/extensions/api/content_settings/content_settings_store.cc
@@ -26,7 +26,6 @@ #include "components/content_settings/core/browser/website_settings_info.h" #include "components/content_settings/core/common/content_settings_pattern.h" #include "components/content_settings/core/common/content_settings_utils.h" -#include "components/content_settings/core/common/features.h" #include "components/permissions/features.h" #include "content/public/browser/browser_thread.h" @@ -105,12 +104,6 @@ ContentSettingsType type, ContentSetting setting, ExtensionPrefsScope scope) { - if (base::FeatureList::IsEnabled( - content_settings::kDisallowWildcardsInPluginContentSettings) && - type == ContentSettingsType::PLUGINS && - primary_pattern.HasHostWildcards()) { - return; - } { base::AutoLock lock(lock_); OriginIdentifierValueMap* map = GetValueMap(ext_id, scope);
diff --git a/chrome/browser/extensions/api/content_settings/content_settings_store_unittest.cc b/chrome/browser/extensions/api/content_settings/content_settings_store_unittest.cc index 41d2b8e..842689dd 100644 --- a/chrome/browser/extensions/api/content_settings/content_settings_store_unittest.cc +++ b/chrome/browser/extensions/api/content_settings/content_settings_store_unittest.cc
@@ -339,38 +339,4 @@ store()->RemoveObserver(&observer); } -TEST_F(ContentSettingsStoreTest, DisallowWildcardsInFlash) { - // Enabling the feature which disallows wildcard matching for Plugin content - // settings. - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndEnableFeature( - content_settings::kDisallowWildcardsInPluginContentSettings); - - // Register extension. - std::string ext_id("my_extension"); - RegisterExtension(ext_id); - ContentSettingsPattern primary_pattern = - ContentSettingsPattern::FromString("https://[*.]google.com"); - ContentSettingsPattern secondary_pattern = ContentSettingsPattern::Wildcard(); - store()->SetExtensionContentSetting( - ext_id, primary_pattern, secondary_pattern, ContentSettingsType::PLUGINS, - CONTENT_SETTING_ALLOW, kExtensionPrefsScopeRegular); - store()->SetExtensionContentSetting( - ext_id, primary_pattern, secondary_pattern, ContentSettingsType::COOKIES, - CONTENT_SETTING_ALLOW, kExtensionPrefsScopeRegular); - - std::vector<content_settings::Rule> rules; - rules = GetSettingsForOneTypeFromStore(store(), ContentSettingsType::PLUGINS, - false); - // Number of rules will be zero because we tried to add a pattern with - // wildcards. - ASSERT_EQ(rules.size(), 0u); - - rules = GetSettingsForOneTypeFromStore(store(), ContentSettingsType::COOKIES, - false); - // Here we will have one rule because wildcard patterns are allowed for - // ContentSettingsType::COOKIES. - ASSERT_EQ(rules.size(), 1u); -} - } // namespace extensions
diff --git a/chrome/browser/extensions/api/declarative_content/content_action_unittest.cc b/chrome/browser/extensions/api/declarative_content/content_action_unittest.cc index 2d320ee2..a45f0f1a 100644 --- a/chrome/browser/extensions/api/declarative_content/content_action_unittest.cc +++ b/chrome/browser/extensions/api/declarative_content/content_action_unittest.cc
@@ -297,49 +297,6 @@ } } -TEST(DeclarativeContentActionTest, SetInvalidIcon) { - TestExtensionEnvironment env; - content::RenderViewHostTestEnabler rvh_enabler; - - // This bitmap type is allowed by skia::mojom::InlineBitmap but we should - // convert to N32 upon receipt. - SkBitmap bitmap; - EXPECT_TRUE(bitmap.tryAllocPixels( - SkImageInfo::Make(19, 19, kAlpha_8_SkColorType, kPremul_SkAlphaType))); - bitmap.eraseARGB(255, 255, 0, 0); - - DictionaryBuilder builder; - builder.Set("instanceType", "declarativeContent.SetIcon"); - - std::vector<uint8_t> s = skia::mojom::InlineBitmap::Serialize(&bitmap); - builder.Set("imageData", DictionaryBuilder().Set("19", s).Build()); - - std::unique_ptr<base::DictionaryValue> dict = builder.Build(); - - const Extension* extension = env.MakeExtension( - ParseJson(R"({"page_action": {"default_title": "Extension"}})")); - base::HistogramTester histogram_tester; - TestingProfile profile; - std::string error; - std::unique_ptr<const ContentAction> result = - ContentAction::Create(&profile, extension, *dict, &error); - EXPECT_EQ("", error); - ASSERT_TRUE(result.get()); - - ExtensionAction* action = ExtensionActionManager::Get(env.profile()) - ->GetExtensionAction(*extension); - - std::unique_ptr<content::WebContents> contents = env.MakeTab(); - const int tab_id = ExtensionTabUtil::GetTabId(contents.get()); - ContentAction::ApplyInfo apply_info = {extension, env.profile(), - contents.get(), 100}; - EXPECT_TRUE(action->GetDeclarativeIcon(tab_id).IsEmpty()); - result->Apply(apply_info); - EXPECT_FALSE(action->GetDeclarativeIcon(tab_id).IsEmpty()); - EXPECT_EQ(kN32_SkColorType, - action->GetDeclarativeIcon(tab_id).ToSkBitmap()->colorType()); -} - TEST(DeclarativeContentActionTest, SetInvisibleIcon) { TestExtensionEnvironment env;
diff --git a/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_unittest.cc b/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_unittest.cc index d6c3a64..bff715c 100644 --- a/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_unittest.cc +++ b/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_unittest.cc
@@ -2094,6 +2094,107 @@ VerifyGetAvailableStaticRuleCountFunction(*second_extension.get(), 0); } +// Test that an extension's allocation is reclaimed when unloaded in certain +// scenarios. +TEST_P(MultipleRulesetsGlobalRulesTest, ReclaimAllocationOnUnload) { + const size_t ext_1_allocation = 50; + + AddRuleset(CreateRuleset( + kId1, GetStaticGuaranteedMinimumRuleCount() + ext_1_allocation, 0, true)); + + RulesetManagerObserver ruleset_waiter(manager()); + LoadAndExpectSuccess(GetStaticGuaranteedMinimumRuleCount() + + ext_1_allocation); + ruleset_waiter.WaitForExtensionsWithRulesetsCount(1); + ExtensionId first_extension_id = extension()->id(); + + // The |ext_1_allocation| rules that contribute to the global pool should be + // tracked. + GlobalRulesTracker& global_rules_tracker = + RulesMonitorService::Get(browser_context())->global_rules_tracker(); + EXPECT_EQ(ext_1_allocation, + global_rules_tracker.GetAllocatedGlobalRuleCountForTesting()); + + // An entry for these |ext_1_allocation| rules should be persisted for the + // extension in prefs. + CheckExtensionAllocationInPrefs(first_extension_id, ext_1_allocation); + + auto disable_extension_and_check_allocation = + [this, &ext_1_allocation, &global_rules_tracker, &ruleset_waiter, + &first_extension_id](int disable_reasons, + bool expect_allocation_released) { + service()->DisableExtension(first_extension_id, disable_reasons); + ruleset_waiter.WaitForExtensionsWithRulesetsCount(0); + + size_t expected_tracker_allocation = + expect_allocation_released ? 0 : ext_1_allocation; + base::Optional<size_t> expected_pref_allocation = + expect_allocation_released + ? base::nullopt + : base::make_optional<size_t>(ext_1_allocation); + EXPECT_EQ(expected_tracker_allocation, + global_rules_tracker.GetAllocatedGlobalRuleCountForTesting()); + CheckExtensionAllocationInPrefs(first_extension_id, + expected_pref_allocation); + + service()->EnableExtension(first_extension_id); + ruleset_waiter.WaitForExtensionsWithRulesetsCount(1); + + EXPECT_EQ(ext_1_allocation, + global_rules_tracker.GetAllocatedGlobalRuleCountForTesting()); + CheckExtensionAllocationInPrefs(first_extension_id, ext_1_allocation); + }; + + // Test some DisableReasons that shouldn't cause the allocation to be + // released. + disable_extension_and_check_allocation(disable_reason::DISABLE_USER_ACTION, + false); + + disable_extension_and_check_allocation( + disable_reason::DISABLE_PERMISSIONS_INCREASE | + disable_reason::DISABLE_GREYLIST, + false); + + // Test the DisableReasons that should cause the allocation to be released. + disable_extension_and_check_allocation( + disable_reason::DISABLE_BLOCKED_BY_POLICY, true); + + disable_extension_and_check_allocation( + disable_reason::DISABLE_REMOTELY_FOR_MALWARE, true); + + disable_extension_and_check_allocation( + disable_reason::DISABLE_REMOTELY_FOR_MALWARE | + disable_reason::DISABLE_USER_ACTION, + true); + + // We should reclaim the extension's allocation if it is blocklisted. + service()->BlocklistExtensionForTest(first_extension_id); + ruleset_waiter.WaitForExtensionsWithRulesetsCount(0); + EXPECT_EQ(0u, global_rules_tracker.GetAllocatedGlobalRuleCountForTesting()); + CheckExtensionAllocationInPrefs(first_extension_id, base::nullopt); + + // Load another extension, only to have it be terminated. + const size_t ext_2_allocation = 50; + UpdateExtensionLoaderAndPath( + temp_dir().GetPath().Append(FILE_PATH_LITERAL("test_extension_2"))); + ClearRulesets(); + + AddRuleset(CreateRuleset( + kId2, GetStaticGuaranteedMinimumRuleCount() + ext_2_allocation, 0, true)); + LoadAndExpectSuccess(GetStaticGuaranteedMinimumRuleCount() + + ext_2_allocation); + + ruleset_waiter.WaitForExtensionsWithRulesetsCount(1); + ExtensionId second_extension_id = extension()->id(); + + // The extension should have its allocation kept when it is terminated. + service()->TerminateExtension(second_extension_id); + ruleset_waiter.WaitForExtensionsWithRulesetsCount(0); + EXPECT_EQ(ext_2_allocation, + global_rules_tracker.GetAllocatedGlobalRuleCountForTesting()); + CheckExtensionAllocationInPrefs(second_extension_id, ext_2_allocation); +} + INSTANTIATE_TEST_SUITE_P(All, SingleRulesetTest, ::testing::Values(ExtensionLoadType::PACKED,
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index af75ecd..887c7749 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -226,6 +226,11 @@ "expiry_milestone": 78 }, { + "name": "assistant-intent-page-url", + "owners": [ "jds", "chrome-language" ], + "expiry_milestone": 94 + }, + { "name": "audio-player-js-modules", "owners": [ "lucmult", "jboulic", "simmonsjosh" ], "expiry_milestone": 91 @@ -3131,6 +3136,11 @@ "expiry_milestone": 93 }, { + "name": "media-app-pdf-in-ink", + "owners": [ "//chromeos/components/media_app_ui/OWNERS" ], + "expiry_milestone": 93 + }, + { "name": "media-history", "owners": [ "beccahughes", "media-dev" ], "expiry_milestone": 88
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index b8924acc..b99df2a7 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -2586,6 +2586,12 @@ "Enables messaging in site permissions UI informing user when " "notifications are disabled for the entire app."; +const char kAssistantIntentPageUrlName[] = + "Include page URL in Assistant intent"; +const char kAssistantIntentPageUrlDescription[] = + "Include the current page's URL in the Assistant voice transcription " + "intent."; + const char kAsyncDnsName[] = "Async DNS resolver"; const char kAsyncDnsDescription[] = "Enables the built-in DNS resolver."; @@ -4336,6 +4342,10 @@ const char kMediaAppAnnotationDescription[] = "Enables image annotation in chrome://media-app"; +const char kMediaAppPdfInInkName[] = "Media App Pdf in Ink"; +const char kMediaAppPdfInInkDescription[] = + "Enables loading PDFs into Ink in chrome://media-app"; + const char kMediaNotificationsCounterName[] = "Media Notifications Counter"; const char kMediaNotificationsCounterDescription[] = "Remove media notifications from the notification counter in the status "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 6e941251..dbde51e9 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -1507,6 +1507,9 @@ extern const char kAppNotificationStatusMessagingName[]; extern const char kAppNotificationStatusMessagingDescription[]; +extern const char kAssistantIntentPageUrlName[]; +extern const char kAssistantIntentPageUrlDescription[]; + extern const char kAsyncDnsName[]; extern const char kAsyncDnsDescription[]; @@ -2534,6 +2537,9 @@ extern const char kMediaAppAnnotationName[]; extern const char kMediaAppAnnotationDescription[]; +extern const char kMediaAppPdfInInkName[]; +extern const char kMediaAppPdfInInkDescription[]; + extern const char kMediaNotificationsCounterName[]; extern const char kMediaNotificationsCounterDescription[];
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc index 3b5d844..c1d6933 100644 --- a/chrome/browser/flags/android/chrome_feature_list.cc +++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -118,8 +118,8 @@ &kAndroidMultipleDisplay, &kAndroidNightModeTabReparenting, &kAndroidPartnerCustomizationPhenotype, - &kAndroidPayIntegrationV2, &kAndroidSearchEngineChoiceNotification, + &kAssistantIntentPageUrl, &kBentoOffline, &kCastDeviceFilter, &kCloseTabSuggestions, @@ -182,7 +182,6 @@ &kNotificationSuspender, &kOfflineIndicatorV2, &kOmniboxSpareRenderer, - &kPayWithGoogleV1, &kPhotoPickerVideoSupport, &kPhotoPickerZoom, &kProbabilisticCryptidRenderer, @@ -319,14 +318,12 @@ const base::Feature kAndroidPartnerCustomizationPhenotype{ "AndroidPartnerCustomizationPhenotype", base::FEATURE_ENABLED_BY_DEFAULT}; -// TODO(rouslan): Remove this. (Currently used in -// GooglePayPaymentAppFactory.java) -const base::Feature kAndroidPayIntegrationV2{"AndroidPayIntegrationV2", - base::FEATURE_ENABLED_BY_DEFAULT}; - const base::Feature kAndroidSearchEngineChoiceNotification{ "AndroidSearchEngineChoiceNotification", base::FEATURE_ENABLED_BY_DEFAULT}; +const base::Feature kAssistantIntentPageUrl{"AssistantIntentPageUrl", + base::FEATURE_DISABLED_BY_DEFAULT}; + const base::Feature kBackgroundTaskComponentUpdate{ "BackgroundTaskComponentUpdate", base::FEATURE_DISABLED_BY_DEFAULT}; @@ -529,11 +526,6 @@ const base::Feature kOmniboxSpareRenderer{"OmniboxSpareRenderer", base::FEATURE_DISABLED_BY_DEFAULT}; -// TODO(rouslan): Remove this. (Currently used in -// GooglePayPaymentAppFactory.java) -const base::Feature kPayWithGoogleV1{"PayWithGoogleV1", - base::FEATURE_ENABLED_BY_DEFAULT}; - const base::Feature kPhotoPickerVideoSupport{"PhotoPickerVideoSupport", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chrome/browser/flags/android/chrome_feature_list.h b/chrome/browser/flags/android/chrome_feature_list.h index eedb563..69aa1d0 100644 --- a/chrome/browser/flags/android/chrome_feature_list.h +++ b/chrome/browser/flags/android/chrome_feature_list.h
@@ -20,8 +20,8 @@ extern const base::Feature kAndroidMultipleDisplay; extern const base::Feature kAndroidNightModeTabReparenting; extern const base::Feature kAndroidPartnerCustomizationPhenotype; -extern const base::Feature kAndroidPayIntegrationV2; extern const base::Feature kAndroidSearchEngineChoiceNotification; +extern const base::Feature kAssistantIntentPageUrl; extern const base::Feature kBackgroundTaskComponentUpdate; extern const base::Feature kBentoOffline; extern const base::Feature kCloseTabSuggestions; @@ -91,7 +91,6 @@ extern const base::Feature kNotificationSuspender; extern const base::Feature kOfflineIndicatorV2; extern const base::Feature kOmniboxSpareRenderer; -extern const base::Feature kPayWithGoogleV1; extern const base::Feature kPhotoPickerVideoSupport; extern const base::Feature kPhotoPickerZoom; extern const base::Feature kProbabilisticCryptidRenderer;
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java index 409bf05..38193b67 100644 --- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java +++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -213,9 +213,9 @@ "AndroidNightModeTabReparenting"; public static final String ANDROID_PARTNER_CUSTOMIZATION_PHENOTYPE = "AndroidPartnerCustomizationPhenotype"; - public static final String ANDROID_PAY_INTEGRATION_V2 = "AndroidPayIntegrationV2"; public static final String ANDROID_SEARCH_ENGINE_CHOICE_NOTIFICATION = "AndroidSearchEngineChoiceNotification"; + public static final String ASSISTANT_INTENT_PAGE_URL = "AssistantIntentPageUrl"; public static final String AUTOFILL_ASSISTANT = "AutofillAssistant"; public static final String AUTOFILL_ASSISTANT_CHROME_ENTRY = "AutofillAssistantChromeEntry"; public static final String AUTOFILL_ASSISTANT_DIRECT_ACTIONS = "AutofillAssistantDirectActions"; @@ -362,7 +362,6 @@ public static final String PAINT_PREVIEW_SHOW_ON_STARTUP = "PaintPreviewShowOnStartup"; public static final String PASSWORD_CHECK = "PasswordCheck"; public static final String PASSWORD_SCRIPTS_FETCHING = "PasswordScriptsFetching"; - public static final String PAY_WITH_GOOGLE_V1 = "PayWithGoogleV1"; public static final String PERMISSION_DELEGATION = "PermissionDelegation"; public static final String PHOTO_PICKER_VIDEO_SUPPORT = "PhotoPickerVideoSupport"; public static final String PHOTO_PICKER_ZOOM = "PhotoPickerZoom";
diff --git a/chrome/browser/nearby_sharing/sharesheet/nearby_share_action.cc b/chrome/browser/nearby_sharing/sharesheet/nearby_share_action.cc index 1eaef22..d340629c 100644 --- a/chrome/browser/nearby_sharing/sharesheet/nearby_share_action.cc +++ b/chrome/browser/nearby_sharing/sharesheet/nearby_share_action.cc
@@ -132,5 +132,4 @@ nearby_ui_->RemoveObserver(this); nearby_ui_ = nullptr; } - controller_ = nullptr; }
diff --git a/chrome/browser/policy/content_settings_policy_browsertest.cc b/chrome/browser/policy/content_settings_policy_browsertest.cc index c1787dd..c1a4299 100644 --- a/chrome/browser/policy/content_settings_policy_browsertest.cc +++ b/chrome/browser/policy/content_settings_policy_browsertest.cc
@@ -20,7 +20,6 @@ #include "chrome/test/base/ui_test_utils.h" #include "components/content_settings/core/browser/host_content_settings_map.h" #include "components/content_settings/core/browser/private_network_settings.h" -#include "components/content_settings/core/common/features.h" #include "components/permissions/permission_manager.h" #include "components/permissions/permission_result.h" #include "components/policy/core/common/policy_map.h" @@ -314,18 +313,6 @@ settings_map, GURL("http://woohoo.com/index.html"))); } -class DisallowWildcardPolicyTest : public PolicyTest { - public: - DisallowWildcardPolicyTest() { - scoped_feature_list_.InitAndEnableFeature( - content_settings::kDisallowWildcardsInPluginContentSettings); - } - - private: - base::test::ScopedFeatureList scoped_feature_list_; -}; - - class ScrollToTextFragmentPolicyTest : public PolicyTest, public ::testing::WithParamInterface<bool> {
diff --git a/chrome/browser/policy/download_directory_browsertest.cc b/chrome/browser/policy/download_directory_browsertest.cc new file mode 100644 index 0000000..34ffa48 --- /dev/null +++ b/chrome/browser/policy/download_directory_browsertest.cc
@@ -0,0 +1,128 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/files/file_enumerator.h" +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/test/test_file_util.h" +#include "base/threading/thread_restrictions.h" +#include "base/values.h" +#include "chrome/browser/download/download_prefs.h" +#include "chrome/browser/policy/policy_test_utils.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/common/pref_names.h" +#include "chrome/test/base/ui_test_utils.h" +#include "components/download/public/common/download_item.h" +#include "components/policy/core/common/policy_map.h" +#include "components/policy/policy_constants.h" +#include "components/prefs/pref_service.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/download_manager.h" +#include "content/public/test/browser_test.h" +#include "content/public/test/download_test_observer.h" +#include "net/test/embedded_test_server/embedded_test_server.h" + +#if defined(OS_CHROMEOS) +#include "chrome/browser/chromeos/drive/drive_integration_service.h" +#endif // defined(OS_CHROMEOS) + +namespace policy { + +namespace { +// Downloads a file named |file| and expects it to be saved to |dir|, which +// must be empty. +void DownloadAndVerifyFile(Browser* browser, + const base::FilePath& dir, + const base::FilePath& file) { + net::EmbeddedTestServer embedded_test_server; + base::FilePath test_data_directory; + GetTestDataDirectory(&test_data_directory); + embedded_test_server.ServeFilesFromDirectory(test_data_directory); + ASSERT_TRUE(embedded_test_server.Start()); + content::DownloadManager* download_manager = + content::BrowserContext::GetDownloadManager(browser->profile()); + content::DownloadTestObserverTerminal observer( + download_manager, 1, + content::DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL); + GURL url(embedded_test_server.GetURL("/" + file.MaybeAsASCII())); + base::FilePath downloaded = dir.Append(file); + EXPECT_FALSE(base::PathExists(downloaded)); + ui_test_utils::NavigateToURL(browser, url); + observer.WaitForFinished(); + EXPECT_EQ(1u, + observer.NumDownloadsSeenInState(download::DownloadItem::COMPLETE)); + EXPECT_TRUE(base::PathExists(downloaded)); + base::FileEnumerator enumerator(dir, false, base::FileEnumerator::FILES); + EXPECT_EQ(file, enumerator.Next().BaseName()); + EXPECT_EQ(base::FilePath(), enumerator.Next()); +} + +} // namespace + +// Verifies that the download directory can be forced by policy. +IN_PROC_BROWSER_TEST_F(PolicyTest, DownloadDirectory) { + // Don't prompt for the download location during this test. + browser()->profile()->GetPrefs()->SetBoolean(prefs::kPromptForDownload, + false); + + base::FilePath initial_dir = + DownloadPrefs(browser()->profile()).DownloadPath(); + + // Verify that downloads end up on the default directory. + base::ScopedAllowBlockingForTesting allow_blocking; + base::FilePath file(FILE_PATH_LITERAL("download-test1.lib")); + DownloadAndVerifyFile(browser(), initial_dir, file); + base::DieFileDie(initial_dir.Append(file), false); + + // Override the download directory with the policy and verify a download. + base::FilePath forced_dir = initial_dir.AppendASCII("forced"); + + PolicyMap policies; + policies.Set(key::kDownloadDirectory, POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, + base::Value(forced_dir.value()), nullptr); + UpdateProviderPolicy(policies); + DownloadAndVerifyFile(browser(), forced_dir, file); + // Verify that the first download location wasn't affected. + EXPECT_FALSE(base::PathExists(initial_dir.Append(file))); +} + +#if defined(OS_CHROMEOS) +// Verifies that the download directory can be forced to Google Drive by policy. +IN_PROC_BROWSER_TEST_F(PolicyTest, DownloadDirectory_Drive) { + // Override the download directory with the policy. + { + PolicyMap policies; + policies.Set(key::kDownloadDirectory, POLICY_LEVEL_RECOMMENDED, + POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, + base::Value("${google_drive}/"), nullptr); + UpdateProviderPolicy(policies); + + EXPECT_EQ(drive::DriveIntegrationServiceFactory::FindForProfile( + browser()->profile()) + ->GetMountPointPath() + .AppendASCII("root"), + DownloadPrefs(browser()->profile()) + .DownloadPath() + .StripTrailingSeparators()); + } + + PolicyMap policies; + policies.Set(key::kDownloadDirectory, POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, + base::Value("${google_drive}/Downloads"), nullptr); + UpdateProviderPolicy(policies); + + EXPECT_EQ(drive::DriveIntegrationServiceFactory::FindForProfile( + browser()->profile()) + ->GetMountPointPath() + .AppendASCII("root/Downloads"), + DownloadPrefs(browser()->profile()) + .DownloadPath() + .StripTrailingSeparators()); +} +#endif // defined(OS_CHROMEOS) + +} // namespace policy
diff --git a/chrome/browser/policy/extension_policy_browsertest.cc b/chrome/browser/policy/extension_policy_browsertest.cc index 2099785..228fd98 100644 --- a/chrome/browser/policy/extension_policy_browsertest.cc +++ b/chrome/browser/policy/extension_policy_browsertest.cc
@@ -74,6 +74,7 @@ #include "chrome/browser/chromeos/web_applications/default_web_app_ids.h" #include "chrome/browser/extensions/updater/local_extension_cache.h" #include "chrome/browser/web_applications/components/externally_installed_web_app_prefs.h" +#include "chromeos/constants/chromeos_features.h" #include "chromeos/constants/chromeos_switches.h" #endif @@ -172,6 +173,14 @@ } class ExtensionPolicyTest : public PolicyTest { + public: + ExtensionPolicyTest() { +#if defined(OS_CHROMEOS) + scoped_feature_list_.InitAndDisableFeature( + chromeos::features::kCameraSystemWebApp); +#endif // defined(OS_CHROMEOS) + } + protected: void SetUp() override { // Set default verification mode for content verifier to be enabled. @@ -375,6 +384,8 @@ skip_scheduled_extension_checks_; private: + base::test::ScopedFeatureList scoped_feature_list_; + web_app::ScopedOsHooksSuppress os_hooks_suppress_; };
diff --git a/chrome/browser/policy/messaging_layer/public/report_client.cc b/chrome/browser/policy/messaging_layer/public/report_client.cc index 68494c1..e7ed7fa 100644 --- a/chrome/browser/policy/messaging_layer/public/report_client.cc +++ b/chrome/browser/policy/messaging_layer/public/report_client.cc
@@ -21,6 +21,7 @@ #include "chrome/browser/net/system_network_context_manager.h" #include "chrome/browser/policy/messaging_layer/public/report_queue.h" #include "chrome/browser/policy/messaging_layer/public/report_queue_configuration.h" +#include "chrome/browser/policy/messaging_layer/storage/storage_configuration.h" #include "chrome/browser/policy/messaging_layer/storage/storage_module.h" #include "chrome/browser/policy/messaging_layer/util/status.h" #include "chrome/browser/policy/messaging_layer/util/status_macros.h" @@ -442,7 +443,7 @@ base::FilePath reporting_path = user_data_dir.Append(kReportingDirectory); StorageModule::Create( - Storage::Options().set_directory(reporting_path), + StorageOptions().set_directory(reporting_path), std::move(start_upload_cb_), base::MakeRefCounted<EncryptionModule>(), base::BindOnce( &ReportingClient::InitializingContext::OnStorageModuleConfigured,
diff --git a/chrome/browser/policy/messaging_layer/storage/storage.cc b/chrome/browser/policy/messaging_layer/storage/storage.cc index d78b6724..b7bd603 100644 --- a/chrome/browser/policy/messaging_layer/storage/storage.cc +++ b/chrome/browser/policy/messaging_layer/storage/storage.cc
@@ -16,6 +16,7 @@ #include "base/threading/thread.h" #include "base/threading/thread_task_runner_handle.h" #include "chrome/browser/policy/messaging_layer/encryption/encryption_module.h" +#include "chrome/browser/policy/messaging_layer/storage/storage_configuration.h" #include "chrome/browser/policy/messaging_layer/storage/storage_queue.h" #include "chrome/browser/policy/messaging_layer/util/status_macros.h" #include "chrome/browser/policy/messaging_layer/util/task_runner_context.h" @@ -32,13 +33,11 @@ FILE_PATH_LITERAL("Immediate"); constexpr base::FilePath::CharType immediate_queue_prefix[] = FILE_PATH_LITERAL("P_Immediate"); -const uint64_t immediate_queue_total = 4 * 1024LL; constexpr base::FilePath::CharType fast_batch_queue_subdir[] = FILE_PATH_LITERAL("FastBatch"); constexpr base::FilePath::CharType fast_batch_queue_prefix[] = FILE_PATH_LITERAL("P_FastBatch"); -const uint64_t fast_batch_queue_total = 64 * 1024LL; constexpr base::TimeDelta fast_batch_upload_period = base::TimeDelta::FromSeconds(1); @@ -46,7 +45,6 @@ FILE_PATH_LITERAL("SlowBatch"); constexpr base::FilePath::CharType slow_batch_queue_prefix[] = FILE_PATH_LITERAL("P_SlowBatch"); -const uint64_t slow_batch_queue_total = 16 * 1024LL * 1024LL; constexpr base::TimeDelta slow_batch_upload_period = base::TimeDelta::FromSeconds(20); @@ -54,7 +52,6 @@ FILE_PATH_LITERAL("Background"); constexpr base::FilePath::CharType background_queue_prefix[] = FILE_PATH_LITERAL("P_Background"); -const uint64_t background_queue_total = 64 * 1024LL * 1024LL; constexpr base::TimeDelta background_upload_period = base::TimeDelta::FromMinutes(1); @@ -62,47 +59,36 @@ FILE_PATH_LITERAL("Manual"); constexpr base::FilePath::CharType manual_queue_prefix[] = FILE_PATH_LITERAL("P_Manual"); -const uint64_t manual_queue_total = 64 * 1024LL * 1024LL; constexpr base::TimeDelta manual_upload_period = base::TimeDelta::Max(); // Returns vector of <priority, queue_options> for all expected queues in // Storage. Queues are all located under the given root directory. -std::vector<std::pair<Priority, StorageQueue::Options>> ExpectedQueues( - const base::FilePath& root_directory) { +std::vector<std::pair<Priority, QueueOptions>> ExpectedQueues( + const StorageOptions& options) { return { - std::make_pair(IMMEDIATE, StorageQueue::Options() - .set_directory(root_directory.Append( - immediate_queue_subdir)) - .set_file_prefix(immediate_queue_prefix) - .set_total_size(immediate_queue_total)), - std::make_pair( - FAST_BATCH, - StorageQueue::Options() - .set_directory(root_directory.Append(fast_batch_queue_subdir)) - .set_file_prefix(fast_batch_queue_prefix) - .set_total_size(fast_batch_queue_total) - .set_upload_period(fast_batch_upload_period)), - std::make_pair( - SLOW_BATCH, - StorageQueue::Options() - .set_directory(root_directory.Append(slow_batch_queue_subdir)) - .set_file_prefix(slow_batch_queue_prefix) - .set_total_size(slow_batch_queue_total) - .set_upload_period(slow_batch_upload_period)), - std::make_pair( - BACKGROUND_BATCH, - StorageQueue::Options() - .set_directory(root_directory.Append(background_queue_subdir)) - .set_file_prefix(background_queue_prefix) - .set_total_size(background_queue_total) - .set_upload_period(background_upload_period)), - std::make_pair( - MANUAL_BATCH, - StorageQueue::Options() - .set_directory(root_directory.Append(manual_queue_subdir)) - .set_file_prefix(manual_queue_prefix) - .set_total_size(manual_queue_total) - .set_upload_period(manual_upload_period)), + std::make_pair(IMMEDIATE, QueueOptions(options) + .set_subdirectory(immediate_queue_subdir) + .set_file_prefix(immediate_queue_prefix)), + std::make_pair(FAST_BATCH, + QueueOptions(options) + .set_subdirectory(fast_batch_queue_subdir) + .set_file_prefix(fast_batch_queue_prefix) + .set_upload_period(fast_batch_upload_period)), + std::make_pair(SLOW_BATCH, + QueueOptions(options) + .set_subdirectory(slow_batch_queue_subdir) + .set_file_prefix(slow_batch_queue_prefix) + .set_upload_period(slow_batch_upload_period)), + std::make_pair(BACKGROUND_BATCH, + QueueOptions(options) + .set_subdirectory(background_queue_subdir) + .set_file_prefix(background_queue_prefix) + .set_upload_period(background_upload_period)), + std::make_pair(MANUAL_BATCH, + QueueOptions(options) + .set_subdirectory(manual_queue_subdir) + .set_file_prefix(manual_queue_prefix) + .set_upload_period(manual_upload_period)), }; } @@ -154,7 +140,7 @@ }; void Storage::Create( - const Options& options, + const StorageOptions& options, StartUploadCb start_upload_cb, scoped_refptr<EncryptionModule> encryption_module, base::OnceCallback<void(StatusOr<scoped_refptr<Storage>>)> completion_cb) { @@ -163,8 +149,7 @@ : public TaskRunnerContext<StatusOr<scoped_refptr<Storage>>> { public: StorageInitContext( - const std::vector<std::pair<Priority, StorageQueue::Options>>& - queues_options, + const std::vector<std::pair<Priority, QueueOptions>>& queues_options, scoped_refptr<EncryptionModule> encryption_module, scoped_refptr<Storage> storage, base::OnceCallback<void(StatusOr<scoped_refptr<Storage>>)> callback) @@ -228,8 +213,7 @@ Response(std::move(storage_)); } - const std::vector<std::pair<Priority, StorageQueue::Options>> - queues_options_; + const std::vector<std::pair<Priority, QueueOptions>> queues_options_; scoped_refptr<EncryptionModule> encryption_module_; scoped_refptr<Storage> storage_; int32_t count_; @@ -242,12 +226,12 @@ base::WrapRefCounted(new Storage(options, std::move(start_upload_cb))); // Asynchronously run initialization. - Start<StorageInitContext>(ExpectedQueues(storage->options_.directory()), + Start<StorageInitContext>(ExpectedQueues(storage->options_), encryption_module, std::move(storage), std::move(completion_cb)); } -Storage::Storage(const Options& options, StartUploadCb start_upload_cb) +Storage::Storage(const StorageOptions& options, StartUploadCb start_upload_cb) : options_(options), start_upload_cb_(std::move(start_upload_cb)) {} Storage::~Storage() = default;
diff --git a/chrome/browser/policy/messaging_layer/storage/storage.h b/chrome/browser/policy/messaging_layer/storage/storage.h index cbe929a9..afa2ee7 100644 --- a/chrome/browser/policy/messaging_layer/storage/storage.h +++ b/chrome/browser/policy/messaging_layer/storage/storage.h
@@ -16,6 +16,7 @@ #include "base/memory/scoped_refptr.h" #include "base/strings/string_piece.h" #include "chrome/browser/policy/messaging_layer/encryption/encryption_module.h" +#include "chrome/browser/policy/messaging_layer/storage/storage_configuration.h" #include "chrome/browser/policy/messaging_layer/storage/storage_queue.h" #include "chrome/browser/policy/messaging_layer/util/status.h" #include "chrome/browser/policy/messaging_layer/util/statusor.h" @@ -36,29 +37,9 @@ base::RepeatingCallback<StatusOr<std::unique_ptr<UploaderInterface>>( Priority priority)>; - // Options class allowing to set parameters individually, e.g.: - // Storage::Create(Options() - // .set_directory("/var/cache/reporting"), - // callback); - class Options { - public: - Options() = default; - Options(const Options& options) = default; - Options& operator=(const Options& options) = default; - Options& set_directory(const base::FilePath& directory) { - directory_ = directory; - return *this; - } - const base::FilePath& directory() const { return directory_; } - - private: - // Subdirectory of the location assigned for this Storage. - base::FilePath directory_; - }; - // Creates Storage instance, and returns it with the completion callback. static void Create( - const Options& options, + const StorageOptions& options, StartUploadCb start_upload_cb, scoped_refptr<EncryptionModule> encryption_module, base::OnceCallback<void(StatusOr<scoped_refptr<Storage>>)> completion_cb); @@ -98,7 +79,7 @@ // Private constructor, to be called by Create factory method only. // Queues need to be added afterwards. - Storage(const Options& options, StartUploadCb start_upload_cb); + Storage(const StorageOptions& options, StartUploadCb start_upload_cb); // Initializes the object by adding all queues for all priorities. // Must be called once and only once after construction. @@ -111,7 +92,7 @@ // need to protect or serialize access to it. StatusOr<scoped_refptr<StorageQueue>> GetQueue(Priority priority); - const Options options_; + const StorageOptions options_; // Map priority->StorageQueue. base::flat_map<Priority, scoped_refptr<StorageQueue>> queues_;
diff --git a/chrome/browser/policy/messaging_layer/storage/storage_configuration.h b/chrome/browser/policy/messaging_layer/storage/storage_configuration.h new file mode 100644 index 0000000..8c847bd --- /dev/null +++ b/chrome/browser/policy/messaging_layer/storage/storage_configuration.h
@@ -0,0 +1,125 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_POLICY_MESSAGING_LAYER_STORAGE_STORAGE_CONFIGURATION_H_ +#define CHROME_BROWSER_POLICY_MESSAGING_LAYER_STORAGE_STORAGE_CONFIGURATION_H_ + +namespace reporting { + +// Storage options class allowing to set parameters individually, e.g.: +// Storage::Create(Options() +// .set_directory("/var/cache/reporting") +// .set_max_record_size(4 * 1024u) +// .set_max_total_files_size(64 * 1024u * 1024u) +// .set_max_total_memory_size(256 * 1024u), +// callback); +class StorageOptions { + public: + StorageOptions() = default; + StorageOptions(const StorageOptions& options) = default; + StorageOptions& operator=(const StorageOptions& options) = default; + StorageOptions& set_directory(const base::FilePath& directory) { + directory_ = directory; + return *this; + } + StorageOptions& set_max_record_size(size_t max_record_size) { + max_record_size_ = max_record_size; + return *this; + } + StorageOptions& set_max_total_files_size(uint64_t max_total_files_size) { + max_total_files_size_ = max_total_files_size; + return *this; + } + StorageOptions& set_max_total_memory_size(uint64_t max_total_memory_size) { + max_total_memory_size_ = max_total_memory_size; + return *this; + } + StorageOptions& set_single_file_size(uint64_t single_file_size) { + single_file_size_ = single_file_size; + return *this; + } + const base::FilePath& directory() const { return directory_; } + size_t max_record_size() const { return max_record_size_; } + uint64_t max_total_files_size() const { return max_total_files_size_; } + uint64_t max_total_memory_size() const { return max_total_memory_size_; } + uint64_t single_file_size() const { return single_file_size_; } + + private: + // Subdirectory of the location assigned for this Storage. + base::FilePath directory_; + + // Maximum record size. + size_t max_record_size_ = 1 * 1024LL * 1024LL; // 1 MiB + + // Maximum total size of all files in all queues. + uint64_t max_total_files_size_ = 64 * 1024LL * 1024LL; // 64 MiB + + // Maximum memory usage (reading buffers). + uint64_t max_total_memory_size_ = 4 * 1024LL * 1024LL; // 4 MiB + + // Cut-off size of an individual file in all queues. + // When file exceeds this size, the new file is created + // for further records. Note that each file must have at least + // one record before it is closed, regardless of that record size. + uint64_t single_file_size_ = 1 * 1024LL * 1024LL; // 1 MiB +}; + +// Single queue options class allowing to set parameters individually, e.g.: +// StorageQueue::Create(QueueOptions(storage_options) +// .set_subdirectory("reporting") +// .set_file_prefix(FILE_PATH_LITERAL("p00000001")), +// callback); +// storage_options must outlive QueueOptions. +class QueueOptions { + public: + explicit QueueOptions(const StorageOptions& storage_options) + : storage_options_(storage_options) {} + QueueOptions(const QueueOptions& options) = default; + // QueueOptions& operator=(const QueueOptions& options) = default; + QueueOptions& set_subdirectory( + const base::FilePath::StringType& subdirectory) { + directory_ = storage_options_.directory().Append(subdirectory); + return *this; + } + QueueOptions& set_file_prefix(const base::FilePath::StringType& file_prefix) { + file_prefix_ = file_prefix; + return *this; + } + QueueOptions& set_upload_period(base::TimeDelta upload_period) { + upload_period_ = upload_period; + return *this; + } + const base::FilePath& directory() const { return directory_; } + const base::FilePath::StringType& file_prefix() const { return file_prefix_; } + size_t max_record_size() const { return storage_options_.max_record_size(); } + size_t max_total_files_size() const { + return storage_options_.max_total_files_size(); + } + size_t max_total_memory_size() const { + return storage_options_.max_total_memory_size(); + } + uint64_t single_file_size() const { + return storage_options_.single_file_size(); + } + base::TimeDelta upload_period() const { return upload_period_; } + + private: + // Whole storage options, which this queue options are based on. + const StorageOptions& storage_options_; + + // Subdirectory of the Storage location assigned for this StorageQueue. + base::FilePath directory_; + // Prefix of data files assigned for this StorageQueue. + base::FilePath::StringType file_prefix_; + // Time period the data is uploaded with. + // If 0, uploaded immediately after a new record is stored + // (this setting is intended for the immediate priority). + // Can be set to infinity - in that case Flush() is expected to be + // called from time to time. + base::TimeDelta upload_period_; +}; + +} // namespace reporting + +#endif // CHROME_BROWSER_POLICY_MESSAGING_LAYER_STORAGE_STORAGE_CONFIGURATION_H_
diff --git a/chrome/browser/policy/messaging_layer/storage/storage_module.cc b/chrome/browser/policy/messaging_layer/storage/storage_module.cc index e334460..feed34c2 100644 --- a/chrome/browser/policy/messaging_layer/storage/storage_module.cc +++ b/chrome/browser/policy/messaging_layer/storage/storage_module.cc
@@ -11,6 +11,7 @@ #include "base/memory/ptr_util.h" #include "chrome/browser/policy/messaging_layer/encryption/encryption_module.h" #include "chrome/browser/policy/messaging_layer/storage/storage.h" +#include "chrome/browser/policy/messaging_layer/storage/storage_configuration.h" #include "chrome/browser/policy/messaging_layer/storage/storage_module.h" #include "chrome/browser/policy/messaging_layer/util/status.h" #include "chrome/browser/policy/messaging_layer/util/statusor.h" @@ -42,7 +43,7 @@ // static void StorageModule::Create( - const Storage::Options& options, + const StorageOptions& options, Storage::StartUploadCb start_upload_cb, scoped_refptr<EncryptionModule> encryption_module, base::OnceCallback<void(StatusOr<scoped_refptr<StorageModule>>)> callback) {
diff --git a/chrome/browser/policy/messaging_layer/storage/storage_module.h b/chrome/browser/policy/messaging_layer/storage/storage_module.h index fe72eb8..545c968 100644 --- a/chrome/browser/policy/messaging_layer/storage/storage_module.h +++ b/chrome/browser/policy/messaging_layer/storage/storage_module.h
@@ -12,6 +12,7 @@ #include "base/memory/scoped_refptr.h" #include "chrome/browser/policy/messaging_layer/encryption/encryption_module.h" #include "chrome/browser/policy/messaging_layer/storage/storage.h" +#include "chrome/browser/policy/messaging_layer/storage/storage_configuration.h" #include "chrome/browser/policy/messaging_layer/util/status.h" #include "chrome/browser/policy/messaging_layer/util/statusor.h" #include "components/policy/proto/record.pb.h" @@ -23,7 +24,7 @@ public: // Factory method creates |StorageModule| object. static void Create( - const Storage::Options& options, + const StorageOptions& options, Storage::StartUploadCb start_upload_cb, scoped_refptr<EncryptionModule> encryption_module, base::OnceCallback<void(StatusOr<scoped_refptr<StorageModule>>)>
diff --git a/chrome/browser/policy/messaging_layer/storage/storage_queue.cc b/chrome/browser/policy/messaging_layer/storage/storage_queue.cc index 7d8a3cb..cd4af1fa 100644 --- a/chrome/browser/policy/messaging_layer/storage/storage_queue.cc +++ b/chrome/browser/policy/messaging_layer/storage/storage_queue.cc
@@ -33,6 +33,7 @@ #include "base/task/post_task.h" #include "base/task_runner.h" #include "chrome/browser/policy/messaging_layer/encryption/encryption_module.h" +#include "chrome/browser/policy/messaging_layer/storage/storage_configuration.h" #include "chrome/browser/policy/messaging_layer/util/status.h" #include "chrome/browser/policy/messaging_layer/util/status_macros.h" #include "chrome/browser/policy/messaging_layer/util/statusor.h" @@ -77,7 +78,7 @@ // static void StorageQueue::Create( - const Options& options, + const QueueOptions& options, StartUploadCb start_upload_cb, scoped_refptr<EncryptionModule> encryption_module, base::OnceCallback<void(StatusOr<scoped_refptr<StorageQueue>>)> @@ -124,7 +125,7 @@ std::move(completion_cb)); } -StorageQueue::StorageQueue(const Options& options, +StorageQueue::StorageQueue(const QueueOptions& options, StartUploadCb start_upload_cb, scoped_refptr<EncryptionModule> encryption_module) : options_(options), @@ -384,7 +385,7 @@ /*size=*/0)); DCHECK(insert_result.second); } - if (size > options_.total_size()) { + if (size > options_.max_record_size()) { return Status(error::OUT_OF_RANGE, "Too much data to be recorded at once"); } scoped_refptr<SingleFile> last_file = files_.rbegin()->second;
diff --git a/chrome/browser/policy/messaging_layer/storage/storage_queue.h b/chrome/browser/policy/messaging_layer/storage/storage_queue.h index c34b2082..4658aeb2c 100644 --- a/chrome/browser/policy/messaging_layer/storage/storage_queue.h +++ b/chrome/browser/policy/messaging_layer/storage/storage_queue.h
@@ -24,6 +24,7 @@ #include "base/threading/thread_task_runner_handle.h" #include "base/timer/timer.h" #include "chrome/browser/policy/messaging_layer/encryption/encryption_module.h" +#include "chrome/browser/policy/messaging_layer/storage/storage_configuration.h" #include "chrome/browser/policy/messaging_layer/util/status.h" #include "chrome/browser/policy/messaging_layer/util/statusor.h" #include "components/policy/proto/record.pb.h" @@ -36,67 +37,6 @@ // sequencing number to be eliminated. class StorageQueue : public base::RefCountedThreadSafe<StorageQueue> { public: - // Options class allowing to set parameters individually, e.g.: - // StorageQueue::Create(Options() - // .set_directory("/var/cache/reporting") - // .set_file_prefix(FILE_PATH_LITERAL("p00000001")) - // .set_total_size(128 * 1024LL * 1024LL), - // callback); - class Options { - public: - Options() = default; - Options(const Options& options) = default; - Options& operator=(const Options& options) = default; - Options& set_directory(const base::FilePath& directory) { - directory_ = directory; - return *this; - } - Options& set_file_prefix(const base::FilePath::StringType& file_prefix) { - file_prefix_ = file_prefix; - return *this; - } - Options& set_single_file_size(uint64_t single_file_size) { - single_file_size_ = single_file_size; - return *this; - } - Options& set_total_size(uint64_t total_size) { - total_size_ = total_size; - return *this; - } - Options& set_upload_period(base::TimeDelta upload_period) { - upload_period_ = upload_period; - return *this; - } - const base::FilePath& directory() const { return directory_; } - const base::FilePath::StringType& file_prefix() const { - return file_prefix_; - } - uint64_t single_file_size() const { return single_file_size_; } - uint64_t total_size() const { return total_size_; } - base::TimeDelta upload_period() const { return upload_period_; } - - private: - // Subdirectory of the Storage location assigned for this StorageQueue. - base::FilePath directory_; - // Prefix of data files assigned for this StorageQueue. - base::FilePath::StringType file_prefix_; - // Cut-off size of an individual file in the set. - // When file exceeds this size, the new file is created - // for further records. Note that each file must have at least - // one record before it is closed, regardless of that record size. - uint64_t single_file_size_ = 1 * 1024LL * 1024LL; // 1 MiB - // Cut-off total size of all files in the set. - // When the storage queue exceeds this size, oldest records can be - // dropped. - uint64_t total_size_ = 256 * 256LL * 256LL; // 256 MiB - // Time period the data is uploaded with. - // If 0, uploaded immediately after a new record is stored - // (this setting is intended for the immediate priority). - // Can be set to infinity - in that case Flush() is expected to be - // called from time to time. - base::TimeDelta upload_period_; - }; - // Interface for Upload, which must be implemented by an object returned by // |StartUpload| callback (see below). // Every time StorageQueue starts an upload (by timer or immediately after @@ -137,7 +77,7 @@ // records - periodically or immediately after Write (and in the near future - // upon explicit Flush request). static void Create( - const Options& options, + const QueueOptions& options, StartUploadCb start_upload_cb, scoped_refptr<EncryptionModule> encryption_module, base::OnceCallback<void(StatusOr<scoped_refptr<StorageQueue>>)> @@ -186,7 +126,7 @@ void TestInjectBlockReadErrors(std::initializer_list<uint64_t> seq_numbers); // Access queue options. - const Options& options() const { return options_; } + const QueueOptions& options() const { return options_; } StorageQueue(const StorageQueue& other) = delete; StorageQueue& operator=(const StorageQueue& other) = delete; @@ -256,7 +196,7 @@ }; // Private constructor, to be called by Create factory method only. - StorageQueue(const Options& options, + StorageQueue(const QueueOptions& options, StartUploadCb start_upload_cb, scoped_refptr<EncryptionModule> encryption_module); @@ -345,7 +285,7 @@ Status RemoveConfirmedData(uint64_t seq_number); // Immutable options, stored at the time of creation. - const Options options_; + const QueueOptions options_; // Current generation id, unique per device and queue. // Set up once during initialization by reading from the 'gen_id.NNNN' file
diff --git a/chrome/browser/policy/messaging_layer/storage/storage_queue_unittest.cc b/chrome/browser/policy/messaging_layer/storage/storage_queue_unittest.cc index 699282b1..384ed60 100644 --- a/chrome/browser/policy/messaging_layer/storage/storage_queue_unittest.cc +++ b/chrome/browser/policy/messaging_layer/storage/storage_queue_unittest.cc
@@ -18,6 +18,7 @@ #include "base/synchronization/waitable_event.h" #include "base/test/task_environment.h" #include "chrome/browser/policy/messaging_layer/encryption/test_encryption_module.h" +#include "chrome/browser/policy/messaging_layer/storage/storage_configuration.h" #include "chrome/browser/policy/messaging_layer/util/status.h" #include "chrome/browser/policy/messaging_layer/util/statusor.h" #include "components/policy/proto/record.pb.h" @@ -261,9 +262,13 @@ class StorageQueueTest : public ::testing::TestWithParam<size_t> { protected: - void SetUp() override { ASSERT_TRUE(location_.CreateUniqueTempDir()); } + void SetUp() override { + ASSERT_TRUE(location_.CreateUniqueTempDir()); + options_.set_directory(base::FilePath(location_.GetPath())) + .set_single_file_size(GetParam()); + } - void CreateStorageQueueOrDie(const StorageQueue::Options& options) { + void CreateStorageQueueOrDie(const QueueOptions& options) { ASSERT_FALSE(storage_queue_) << "StorageQueue already assigned"; test_encryption_module_ = base::MakeRefCounted<test::TestEncryptionModule>(); @@ -283,20 +288,18 @@ storage_queue_->TestInjectBlockReadErrors(seq_numbers); } - StorageQueue::Options BuildStorageQueueOptionsImmediate() const { - return StorageQueue::Options() - .set_directory( - base::FilePath(location_.GetPath()).Append(FILE_PATH_LITERAL("D1"))) - .set_file_prefix(FILE_PATH_LITERAL("F0001")) - .set_single_file_size(GetParam()); + QueueOptions BuildStorageQueueOptionsImmediate() const { + return QueueOptions(options_) + .set_subdirectory(FILE_PATH_LITERAL("D1")) + .set_file_prefix(FILE_PATH_LITERAL("F0001")); } - StorageQueue::Options BuildStorageQueueOptionsPeriodic( + QueueOptions BuildStorageQueueOptionsPeriodic( base::TimeDelta upload_period = base::TimeDelta::FromSeconds(1)) const { return BuildStorageQueueOptionsImmediate().set_upload_period(upload_period); } - StorageQueue::Options BuildStorageQueueOptionsOnlyManual() const { + QueueOptions BuildStorageQueueOptionsOnlyManual() const { return BuildStorageQueueOptionsPeriodic(base::TimeDelta::Max()); } @@ -332,6 +335,7 @@ } base::ScopedTempDir location_; + StorageOptions options_; scoped_refptr<test::TestEncryptionModule> test_encryption_module_; scoped_refptr<StorageQueue> storage_queue_; @@ -455,7 +459,7 @@ WriteStringOrDie(data[2]); // Save copy of options. - const StorageQueue::Options options = storage_queue_->options(); + const QueueOptions options = storage_queue_->options(); storage_queue_.reset(); @@ -496,7 +500,7 @@ WriteStringOrDie(data[2]); // Save copy of options. - const StorageQueue::Options options = storage_queue_->options(); + const QueueOptions options = storage_queue_->options(); storage_queue_.reset();
diff --git a/chrome/browser/policy/messaging_layer/storage/storage_unittest.cc b/chrome/browser/policy/messaging_layer/storage/storage_unittest.cc index 35546dc..ad208ed6 100644 --- a/chrome/browser/policy/messaging_layer/storage/storage_unittest.cc +++ b/chrome/browser/policy/messaging_layer/storage/storage_unittest.cc
@@ -15,6 +15,7 @@ #include "base/synchronization/waitable_event.h" #include "base/test/task_environment.h" #include "chrome/browser/policy/messaging_layer/encryption/test_encryption_module.h" +#include "chrome/browser/policy/messaging_layer/storage/storage_configuration.h" #include "chrome/browser/policy/messaging_layer/util/status.h" #include "chrome/browser/policy/messaging_layer/util/statusor.h" #include "components/policy/proto/record.pb.h" @@ -231,11 +232,11 @@ Sequence test_upload_sequence_; }; -class StorageTest : public ::testing::Test { +class StorageTest : public ::testing::TestWithParam<size_t> { protected: void SetUp() override { ASSERT_TRUE(location_.CreateUniqueTempDir()); } - void CreateStorageTestOrDie(const Storage::Options& options) { + void CreateStorageTestOrDie(const StorageOptions& options) { ASSERT_FALSE(storage_) << "StorageTest already assigned"; test_encryption_module_ = base::MakeRefCounted<test::TestEncryptionModule>(); @@ -250,9 +251,10 @@ storage_ = std::move(storage_result.ValueOrDie()); } - Storage::Options BuildStorageOptions() const { - return Storage::Options().set_directory( - base::FilePath(location_.GetPath())); + StorageOptions BuildStorageOptions() const { + return StorageOptions() + .set_directory(base::FilePath(location_.GetPath())) + .set_single_file_size(GetParam()); } StatusOr<std::unique_ptr<Storage::UploaderInterface>> BuildMockUploader( @@ -305,7 +307,7 @@ constexpr std::array<const char*, 3> more_data = {"More1111", "More222", "More33"}; -TEST_F(StorageTest, WriteIntoNewStorageAndReopen) { +TEST_P(StorageTest, WriteIntoNewStorageAndReopen) { EXPECT_CALL(set_mock_uploader_expectations_, Call(_, NotNull())).Times(0); CreateStorageTestOrDie(BuildStorageOptions()); WriteStringOrDie(FAST_BATCH, data[0]); @@ -317,7 +319,7 @@ CreateStorageTestOrDie(BuildStorageOptions()); } -TEST_F(StorageTest, WriteIntoNewStorageReopenAndWriteMore) { +TEST_P(StorageTest, WriteIntoNewStorageReopenAndWriteMore) { EXPECT_CALL(set_mock_uploader_expectations_, Call(_, NotNull())).Times(0); CreateStorageTestOrDie(BuildStorageOptions()); WriteStringOrDie(FAST_BATCH, data[0]); @@ -332,7 +334,7 @@ WriteStringOrDie(FAST_BATCH, more_data[2]); } -TEST_F(StorageTest, WriteIntoNewStorageAndUpload) { +TEST_P(StorageTest, WriteIntoNewStorageAndUpload) { CreateStorageTestOrDie(BuildStorageOptions()); WriteStringOrDie(FAST_BATCH, data[0]); WriteStringOrDie(FAST_BATCH, data[1]); @@ -352,7 +354,7 @@ task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(1)); } -TEST_F(StorageTest, WriteIntoNewStorageReopenWriteMoreAndUpload) { +TEST_P(StorageTest, WriteIntoNewStorageReopenWriteMoreAndUpload) { CreateStorageTestOrDie(BuildStorageOptions()); WriteStringOrDie(FAST_BATCH, data[0]); WriteStringOrDie(FAST_BATCH, data[1]); @@ -382,7 +384,7 @@ task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(1)); } -TEST_F(StorageTest, WriteIntoNewStorageAndFlush) { +TEST_P(StorageTest, WriteIntoNewStorageAndFlush) { CreateStorageTestOrDie(BuildStorageOptions()); WriteStringOrDie(MANUAL_BATCH, data[0]); WriteStringOrDie(MANUAL_BATCH, data[1]); @@ -403,7 +405,7 @@ EXPECT_OK(storage_->Flush(MANUAL_BATCH)); } -TEST_F(StorageTest, WriteIntoNewStorageReopenWriteMoreAndFlush) { +TEST_P(StorageTest, WriteIntoNewStorageReopenWriteMoreAndFlush) { CreateStorageTestOrDie(BuildStorageOptions()); WriteStringOrDie(MANUAL_BATCH, data[0]); WriteStringOrDie(MANUAL_BATCH, data[1]); @@ -434,7 +436,7 @@ EXPECT_OK(storage_->Flush(MANUAL_BATCH)); } -TEST_F(StorageTest, WriteAndRepeatedlyUploadWithConfirmations) { +TEST_P(StorageTest, WriteAndRepeatedlyUploadWithConfirmations) { CreateStorageTestOrDie(BuildStorageOptions()); WriteStringOrDie(FAST_BATCH, data[0]); @@ -511,7 +513,7 @@ task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(1)); } -TEST_F(StorageTest, WriteAndRepeatedlyImmediateUpload) { +TEST_P(StorageTest, WriteAndRepeatedlyImmediateUpload) { CreateStorageTestOrDie(BuildStorageOptions()); // Upload is initiated asynchronously, so it may happen after the next @@ -549,7 +551,7 @@ data[2]); // Immediately uploads and verifies. } -TEST_F(StorageTest, WriteAndRepeatedlyImmediateUploadWithConfirmations) { +TEST_P(StorageTest, WriteAndRepeatedlyImmediateUploadWithConfirmations) { CreateStorageTestOrDie(BuildStorageOptions()); // Upload is initiated asynchronously, so it may happen after the next @@ -623,7 +625,7 @@ WriteStringOrDie(IMMEDIATE, more_data[2]); } -TEST_F(StorageTest, WriteAndRepeatedlyUploadMultipleQueues) { +TEST_P(StorageTest, WriteAndRepeatedlyUploadMultipleQueues) { CreateStorageTestOrDie(BuildStorageOptions()); // Upload is initiated asynchronously, so it may happen after the next @@ -699,7 +701,7 @@ task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(20)); } -TEST_F(StorageTest, WriteEncryptFailure) { +TEST_P(StorageTest, WriteEncryptFailure) { CreateStorageTestOrDie(BuildStorageOptions()); DCHECK(test_encryption_module_); EXPECT_CALL(*test_encryption_module_, EncryptRecord(_, _)) @@ -712,5 +714,11 @@ EXPECT_EQ(result.error_code(), error::UNKNOWN); } +INSTANTIATE_TEST_SUITE_P(VaryingFileSize, + StorageTest, + testing::Values(128 * 1024LL * 1024LL, + 256 /* two records in file */, + 1 /* single record in file */)); + } // namespace } // namespace reporting
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc index a3bfd26b..47e9734b 100644 --- a/chrome/browser/policy/policy_browsertest.cc +++ b/chrome/browser/policy/policy_browsertest.cc
@@ -34,7 +34,6 @@ #include "base/feature_list.h" #include "base/files/file_enumerator.h" #include "base/files/file_path.h" -#include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" #include "base/memory/ptr_util.h" #include "base/memory/ref_counted.h" @@ -51,8 +50,6 @@ #include "base/task/post_task.h" #include "base/test/bind.h" #include "base/test/scoped_feature_list.h" -#include "base/test/test_file_util.h" -#include "base/threading/thread_restrictions.h" #include "base/time/time.h" #include "base/values.h" #include "build/build_config.h" @@ -96,7 +93,6 @@ #include "components/content_settings/core/common/content_settings.h" #include "components/content_settings/core/common/content_settings_pattern.h" #include "components/content_settings/core/common/pref_names.h" -#include "components/download/public/common/download_item.h" #include "components/network_session_configurator/common/network_switches.h" #include "components/network_time/network_time_tracker.h" #include "components/policy/core/browser/browser_policy_connector.h" @@ -119,7 +115,6 @@ #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/child_process_data.h" -#include "content/public/browser/download_manager.h" #include "content/public/browser/gpu_data_manager.h" #include "content/public/browser/network_service_instance.h" #include "content/public/browser/notification_details.h" @@ -140,7 +135,6 @@ #include "content/public/common/url_constants.h" #include "content/public/test/browser_test.h" #include "content/public/test/browser_test_utils.h" -#include "content/public/test/download_test_observer.h" #include "content/public/test/mock_notification_observer.h" #include "content/public/test/network_service_test_helper.h" #include "content/public/test/no_renderer_crashes_assertion.h" @@ -182,7 +176,6 @@ #include "ash/public/cpp/ash_pref_names.h" #include "ash/public/cpp/ash_switches.h" #include "ash/shell.h" -#include "chrome/browser/chromeos/drive/drive_integration_service.h" #include "chrome/browser/chromeos/login/test/js_checker.h" #include "chrome/browser/chromeos/note_taking_helper.h" #include "chrome/browser/chromeos/profiles/profile_helper.h" @@ -223,34 +216,6 @@ const int kThreeHoursInMs = 180 * 60 * 1000; #endif -// Downloads a file named |file| and expects it to be saved to |dir|, which -// must be empty. -void DownloadAndVerifyFile(Browser* browser, - const base::FilePath& dir, - const base::FilePath& file) { - net::EmbeddedTestServer embedded_test_server; - base::FilePath test_data_directory; - GetTestDataDirectory(&test_data_directory); - embedded_test_server.ServeFilesFromDirectory(test_data_directory); - ASSERT_TRUE(embedded_test_server.Start()); - content::DownloadManager* download_manager = - content::BrowserContext::GetDownloadManager(browser->profile()); - content::DownloadTestObserverTerminal observer( - download_manager, 1, - content::DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL); - GURL url(embedded_test_server.GetURL("/" + file.MaybeAsASCII())); - base::FilePath downloaded = dir.Append(file); - EXPECT_FALSE(base::PathExists(downloaded)); - ui_test_utils::NavigateToURL(browser, url); - observer.WaitForFinished(); - EXPECT_EQ(1u, - observer.NumDownloadsSeenInState(download::DownloadItem::COMPLETE)); - EXPECT_TRUE(base::PathExists(downloaded)); - base::FileEnumerator enumerator(dir, false, base::FileEnumerator::FILES); - EXPECT_EQ(file, enumerator.Next().BaseName()); - EXPECT_EQ(base::FilePath(), enumerator.Next()); -} - #if defined(OS_CHROMEOS) int CountScreenshots() { DownloadPrefs* download_prefs = DownloadPrefs::FromBrowserContext( @@ -415,71 +380,6 @@ EXPECT_TRUE(IsWebGLEnabled(contents)); } -IN_PROC_BROWSER_TEST_F(PolicyTest, DownloadDirectory) { - // Verifies that the download directory can be forced by policy. - - // Don't prompt for the download location during this test. - browser()->profile()->GetPrefs()->SetBoolean( - prefs::kPromptForDownload, false); - - base::FilePath initial_dir = - DownloadPrefs(browser()->profile()).DownloadPath(); - - // Verify that downloads end up on the default directory. - base::ScopedAllowBlockingForTesting allow_blocking; - base::FilePath file(FILE_PATH_LITERAL("download-test1.lib")); - DownloadAndVerifyFile(browser(), initial_dir, file); - base::DieFileDie(initial_dir.Append(file), false); - - // Override the download directory with the policy and verify a download. - base::FilePath forced_dir = initial_dir.AppendASCII("forced"); - - PolicyMap policies; - policies.Set(key::kDownloadDirectory, POLICY_LEVEL_MANDATORY, - POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, - base::Value(forced_dir.value()), nullptr); - UpdateProviderPolicy(policies); - DownloadAndVerifyFile(browser(), forced_dir, file); - // Verify that the first download location wasn't affected. - EXPECT_FALSE(base::PathExists(initial_dir.Append(file))); -} - -#if defined(OS_CHROMEOS) -// Verifies that the download directory can be forced to Google Drive by policy. -IN_PROC_BROWSER_TEST_F(PolicyTest, DownloadDirectory_Drive) { - // Override the download directory with the policy. - { - PolicyMap policies; - policies.Set(key::kDownloadDirectory, POLICY_LEVEL_RECOMMENDED, - POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, - base::Value("${google_drive}/"), nullptr); - UpdateProviderPolicy(policies); - - EXPECT_EQ(drive::DriveIntegrationServiceFactory::FindForProfile( - browser()->profile()) - ->GetMountPointPath() - .AppendASCII("root"), - DownloadPrefs(browser()->profile()) - .DownloadPath() - .StripTrailingSeparators()); - } - - PolicyMap policies; - policies.Set(key::kDownloadDirectory, POLICY_LEVEL_MANDATORY, - POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, - base::Value("${google_drive}/Downloads"), nullptr); - UpdateProviderPolicy(policies); - - EXPECT_EQ(drive::DriveIntegrationServiceFactory::FindForProfile( - browser()->profile()) - ->GetMountPointPath() - .AppendASCII("root/Downloads"), - DownloadPrefs(browser()->profile()) - .DownloadPath() - .StripTrailingSeparators()); -} -#endif // !defined(OS_CHROMEOS) - IN_PROC_BROWSER_TEST_F(PolicyTest, HomepageLocation) { // Verifies that the homepage can be configured with policies. // Set a default, and check that the home button navigates there.
diff --git a/chrome/browser/policy/system_features_policy_browsertest.cc b/chrome/browser/policy/system_features_policy_browsertest.cc index bb94e30e..6d3b75d 100644 --- a/chrome/browser/policy/system_features_policy_browsertest.cc +++ b/chrome/browser/policy/system_features_policy_browsertest.cc
@@ -14,6 +14,7 @@ #include "chrome/common/webui_url_constants.h" #include "chrome/grit/generated_resources.h" #include "chrome/test/base/ui_test_utils.h" +#include "chromeos/constants/chromeos_features.h" #include "components/policy/core/common/policy_pref_names.h" #include "components/policy/policy_constants.h" #include "components/strings/grit/components_strings.h" @@ -26,6 +27,12 @@ namespace policy { class SystemFeaturesPolicyTest : public PolicyTest { + public: + SystemFeaturesPolicyTest() { + scoped_feature_list_.InitAndDisableFeature( + chromeos::features::kCameraSystemWebApp); + } + protected: base::string16 GetWebUITitle(const GURL& url) { content::WebContents* web_contents = @@ -35,6 +42,9 @@ EXPECT_TRUE(content::WaitForLoadStop(web_contents)); return web_contents->GetTitle(); } + + private: + base::test::ScopedFeatureList scoped_feature_list_; }; IN_PROC_BROWSER_TEST_F(SystemFeaturesPolicyTest, DisableCameraBeforeInstall) {
diff --git a/chrome/browser/policy/url_blacklist_policy_browsertest.cc b/chrome/browser/policy/url_blacklist_policy_browsertest.cc index 8920955c..cad7238 100644 --- a/chrome/browser/policy/url_blacklist_policy_browsertest.cc +++ b/chrome/browser/policy/url_blacklist_policy_browsertest.cc
@@ -308,13 +308,7 @@ browser()->tab_strip_model()->GetActiveWebContents()->GetTitle()); } -#if defined(OS_MAC) -// http://crbug.com/339240 -#define MAYBE_FileURLBlacklist DISABLED_FileURLBlacklist -#else -#define MAYBE_FileURLBlacklist FileURLBlacklist -#endif -IN_PROC_BROWSER_TEST_F(PolicyTest, MAYBE_FileURLBlacklist) { +IN_PROC_BROWSER_TEST_F(PolicyTest, FileURLBlacklist) { // Check that FileURLs can be blacklisted and DisabledSchemes works together // with URLblacklisting and URLwhitelisting.
diff --git a/chrome/browser/prefetch/search_prefetch/base_search_prefetch_request.cc b/chrome/browser/prefetch/search_prefetch/base_search_prefetch_request.cc new file mode 100644 index 0000000..6f2cad4 --- /dev/null +++ b/chrome/browser/prefetch/search_prefetch/base_search_prefetch_request.cc
@@ -0,0 +1,78 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/prefetch/search_prefetch/base_search_prefetch_request.h" + +#include "chrome/browser/profiles/profile.h" +#include "components/variations/net/variations_http_headers.h" +#include "content/public/browser/frame_accept_header.h" +#include "content/public/common/content_constants.h" +#include "net/base/load_flags.h" +#include "net/traffic_annotation/network_traffic_annotation.h" +#include "services/network/public/cpp/resource_request.h" + +BaseSearchPrefetchRequest::BaseSearchPrefetchRequest( + const GURL& prefetch_url, + base::OnceClosure report_error_callback) + : prefetch_url_(prefetch_url), + report_error_callback_(std::move(report_error_callback)) {} + +BaseSearchPrefetchRequest::~BaseSearchPrefetchRequest() = default; + +void BaseSearchPrefetchRequest::StartPrefetchRequest(Profile* profile) { + net::NetworkTrafficAnnotationTag network_traffic_annotation = + net::DefineNetworkTrafficAnnotation("search_prefetch_service", R"( + semantics { + sender: "Search Prefetch Service" + description: + "Prefetches search results page (HTML) based on omnibox hints " + "provided by the user's default search engine. This allows the " + "prefetched content to be served when the user navigates to the " + "omnibox hint." + trigger: + "User typing in the omnibox and the default search provider " + "indicates the provided omnibox hint entry is likely to be " + "navigated which would result in loading a search results page for " + "that hint." + data: "Credentials if user is signed in." + destination: OTHER + destination_other: "The user's default search engine." + } + policy { + cookies_allowed: YES + cookies_store: "user" + setting: + "Users can control this feature by opting out of 'Preload pages " + "for faster browsing and searching'" + chrome_policy { + DefaultSearchProviderEnabled { + policy_options {mode: MANDATORY} + DefaultSearchProviderEnabled: false + } + NetworkPredictionOptions { + NetworkPredictionOptions: 2 + } + } + })"); + + auto resource_request = std::make_unique<network::ResourceRequest>(); + resource_request->load_flags |= net::LOAD_PREFETCH; + resource_request->url = prefetch_url_; + resource_request->credentials_mode = + network::mojom::CredentialsMode::kInclude; + variations::AppendVariationsHeaderUnknownSignedIn( + prefetch_url_, variations::InIncognito::kNo, resource_request.get()); + resource_request->headers.SetHeader(content::kCorsExemptPurposeHeaderName, + "prefetch"); + resource_request->headers.SetHeader( + net::HttpRequestHeaders::kAccept, + content::FrameAcceptHeaderValue(/*allow_sxg_responses=*/true, profile)); + // TODO(ryansturm): Find other headers that may need to be set. + // https://crbug.com/1138648 + + current_status_ = SearchPrefetchStatus::kInFlight; + + StartPrefetchRequestInternal(profile, std::move(resource_request), + network_traffic_annotation); +}
diff --git a/chrome/browser/prefetch/search_prefetch/base_search_prefetch_request.h b/chrome/browser/prefetch/search_prefetch/base_search_prefetch_request.h new file mode 100644 index 0000000..bbc5dd6 --- /dev/null +++ b/chrome/browser/prefetch/search_prefetch/base_search_prefetch_request.h
@@ -0,0 +1,78 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_PREFETCH_SEARCH_PREFETCH_BASE_SEARCH_PREFETCH_REQUEST_H_ +#define CHROME_BROWSER_PREFETCH_SEARCH_PREFETCH_BASE_SEARCH_PREFETCH_REQUEST_H_ + +#include <memory> + +#include "base/callback.h" +#include "net/traffic_annotation/network_traffic_annotation.h" +#include "services/network/public/cpp/resource_request.h" +#include "url/gurl.h" + +class Profile; +class SearchPrefetchURLLoader; + +enum class SearchPrefetchStatus { + // The request has not started yet. This status should ideally never be + // recorded as Start() should be called on the same stack as creating the + // fetcher (as of now). + kNotStarted = 0, + // The request is on the network and may move to any other state. + kInFlight = 1, + // The request received all the data and is ready to serve. + kSuccessfullyCompleted = 2, + // The request hit an error and cannot be served. + kRequestFailed = 3, + // The request was cancelled before completion. + kRequestCancelled = 4, +}; + +// A class representing a prefetch used by the Search Prefetch Service. +// Implementors should provide the fetch and storage functionality as well as +// updating |current_status_|. +class BaseSearchPrefetchRequest { + public: + BaseSearchPrefetchRequest(const GURL& prefetch_url, + base::OnceClosure report_error_callback); + virtual ~BaseSearchPrefetchRequest(); + + BaseSearchPrefetchRequest(const BaseSearchPrefetchRequest&) = delete; + BaseSearchPrefetchRequest& operator=(const BaseSearchPrefetchRequest&) = + delete; + + // Starts the network request to prefetch |prefetch_url_|. Sets various fields + // on a resource request and calls |StartPrefetchRequestInternal()|. + void StartPrefetchRequest(Profile* profile); + + // Starts and begins processing |resource_request|. + virtual void StartPrefetchRequestInternal( + Profile* profile, + std::unique_ptr<network::ResourceRequest> resource_request, + const net::NetworkTrafficAnnotationTag& traffic_annotation) = 0; + + // Cancels the on-going prefetch and should mark |current_status_| + // appropriately. + virtual void CancelPrefetch() = 0; + + SearchPrefetchStatus current_status() const { return current_status_; } + + const GURL& prefetch_url() const { return prefetch_url_; } + + // Takes ownership of underlying data/objects needed to serve the response. + virtual std::unique_ptr<SearchPrefetchURLLoader> + TakeSearchPrefetchURLLoader() = 0; + + protected: + SearchPrefetchStatus current_status_ = SearchPrefetchStatus::kNotStarted; + + // The URL to prefetch the search terms from. + const GURL prefetch_url_; + + // Called when there is a network/server error on the prefetch request. + base::OnceClosure report_error_callback_; +}; + +#endif // CHROME_BROWSER_PREFETCH_SEARCH_PREFETCH_BASE_SEARCH_PREFETCH_REQUEST_H_
diff --git a/chrome/browser/prefetch/search_prefetch/full_body_search_prefetch_request.cc b/chrome/browser/prefetch/search_prefetch/full_body_search_prefetch_request.cc new file mode 100644 index 0000000..3f320097 --- /dev/null +++ b/chrome/browser/prefetch/search_prefetch/full_body_search_prefetch_request.cc
@@ -0,0 +1,95 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/prefetch/search_prefetch/full_body_search_prefetch_request.h" + +#include "base/bind.h" +#include "base/callback.h" +#include "base/location.h" +#include "chrome/browser/net/prediction_options.h" +#include "chrome/browser/prefetch/search_prefetch/field_trial_settings.h" +#include "chrome/browser/prefetch/search_prefetch/prefetched_response_container.h" +#include "chrome/browser/prefetch/search_prefetch/search_prefetch_from_string_url_loader.h" +#include "chrome/browser/profiles/profile.h" +#include "components/omnibox/browser/autocomplete_controller.h" +#include "components/omnibox/browser/base_search_provider.h" +#include "components/search_engines/template_url_service.h" +#include "components/variations/net/variations_http_headers.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/render_process_host.h" +#include "content/public/browser/storage_partition.h" +#include "content/public/common/content_constants.h" +#include "net/base/load_flags.h" +#include "net/http/http_status_code.h" +#include "net/traffic_annotation/network_traffic_annotation.h" +#include "services/network/public/cpp/resource_request.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" +#include "url/origin.h" + +FullBodySearchPrefetchRequest::FullBodySearchPrefetchRequest( + const GURL& prefetch_url, + base::OnceClosure report_error_callback) + : BaseSearchPrefetchRequest(prefetch_url, + std::move(report_error_callback)) {} + +FullBodySearchPrefetchRequest::~FullBodySearchPrefetchRequest() = default; + +void FullBodySearchPrefetchRequest::StartPrefetchRequestInternal( + Profile* profile, + std::unique_ptr<network::ResourceRequest> resource_request, + const net::NetworkTrafficAnnotationTag& network_traffic_annotation) { + simple_loader_ = network::SimpleURLLoader::Create(std::move(resource_request), + network_traffic_annotation); + + auto url_loader_factory = + content::BrowserContext::GetDefaultStoragePartition(profile) + ->GetURLLoaderFactoryForBrowserProcess(); + + simple_loader_->DownloadToString( + url_loader_factory.get(), + base::BindOnce(&FullBodySearchPrefetchRequest::LoadDone, + base::Unretained(this)), + 1024 * 1024); +} + +void FullBodySearchPrefetchRequest::LoadDone( + std::unique_ptr<std::string> response_body) { + DCHECK(!report_error_callback_.is_null()); + bool success = simple_loader_->NetError() == net::OK; + // TODO(ryansturm): Handle these errors more robustly by reporting them to the + // service. We need to prevent prefetches for x amount of time based on the + // error. https://crbug.com/1138641 + if (!success || response_body->empty()) { + current_status_ = SearchPrefetchStatus::kRequestFailed; + std::move(report_error_callback_).Run(); + return; + } + if (!simple_loader_->ResponseInfo() || + !simple_loader_->ResponseInfo()->headers || + simple_loader_->ResponseInfo()->headers->response_code() != + net::HTTP_OK) { + current_status_ = SearchPrefetchStatus::kRequestFailed; + std::move(report_error_callback_).Run(); + return; + } + current_status_ = SearchPrefetchStatus::kSuccessfullyCompleted; + + prefetch_response_container_ = std::make_unique<PrefetchedResponseContainer>( + simple_loader_->ResponseInfo()->Clone(), std::move(response_body)); + + simple_loader_.reset(); +} + +std::unique_ptr<SearchPrefetchURLLoader> +FullBodySearchPrefetchRequest::TakeSearchPrefetchURLLoader() { + return std::make_unique<SearchPrefetchFromStringURLLoader>( + std::move(prefetch_response_container_)); +} + +void FullBodySearchPrefetchRequest::CancelPrefetch() { + DCHECK_EQ(current_status_, SearchPrefetchStatus::kInFlight); + current_status_ = SearchPrefetchStatus::kRequestCancelled; + + simple_loader_.reset(); +}
diff --git a/chrome/browser/prefetch/search_prefetch/full_body_search_prefetch_request.h b/chrome/browser/prefetch/search_prefetch/full_body_search_prefetch_request.h new file mode 100644 index 0000000..5b2185f --- /dev/null +++ b/chrome/browser/prefetch/search_prefetch/full_body_search_prefetch_request.h
@@ -0,0 +1,54 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_PREFETCH_SEARCH_PREFETCH_FULL_BODY_SEARCH_PREFETCH_REQUEST_H_ +#define CHROME_BROWSER_PREFETCH_SEARCH_PREFETCH_FULL_BODY_SEARCH_PREFETCH_REQUEST_H_ + +#include <memory> + +#include "base/callback.h" +#include "chrome/browser/prefetch/search_prefetch/base_search_prefetch_request.h" +#include "net/traffic_annotation/network_traffic_annotation.h" +#include "services/network/public/cpp/resource_request.h" +#include "services/network/public/cpp/simple_url_loader.h" +#include "url/gurl.h" + +class Profile; +class SearchPrefetchURLLoader; +class PrefetchedResponseContainer; + +class FullBodySearchPrefetchRequest : public BaseSearchPrefetchRequest { + public: + FullBodySearchPrefetchRequest(const GURL& prefetch_url, + base::OnceClosure report_error_callback); + ~FullBodySearchPrefetchRequest() override; + + FullBodySearchPrefetchRequest(const FullBodySearchPrefetchRequest&) = delete; + FullBodySearchPrefetchRequest& operator=( + const FullBodySearchPrefetchRequest&) = delete; + + // BaseSearchPrefetchRequest: + void StartPrefetchRequestInternal( + Profile* profile, + std::unique_ptr<network::ResourceRequest> resource_request, + const net::NetworkTrafficAnnotationTag& network_traffic_annotation) + override; + void CancelPrefetch() override; + std::unique_ptr<SearchPrefetchURLLoader> TakeSearchPrefetchURLLoader() + override; + + private: + // Called as a callback when the prefetch request is complete. Stores the + // response and other metadata in |prefetch_response_container_|. + void LoadDone(std::unique_ptr<std::string> response_body); + + // The ongoing prefetch request. Null before and after the fetch. + std::unique_ptr<network::SimpleURLLoader> simple_loader_; + + // Once a prefetch is completed successfully, the associated prefetch data + // and metadata about the request. + std::unique_ptr<PrefetchedResponseContainer> prefetch_response_container_; +}; + +#endif // CHROME_BROWSER_PREFETCH_SEARCH_PREFETCH_FULL_BODY_SEARCH_PREFETCH_REQUEST_H_
diff --git a/chrome/browser/prefetch/search_prefetch/search_prefetch_from_string_url_loader.cc b/chrome/browser/prefetch/search_prefetch/search_prefetch_from_string_url_loader.cc index 37c22d9..eb4c097 100644 --- a/chrome/browser/prefetch/search_prefetch/search_prefetch_from_string_url_loader.cc +++ b/chrome/browser/prefetch/search_prefetch/search_prefetch_from_string_url_loader.cc
@@ -17,8 +17,7 @@ #include "services/network/public/mojom/url_response_head.mojom.h" SearchPrefetchFromStringURLLoader::SearchPrefetchFromStringURLLoader( - std::unique_ptr<PrefetchedResponseContainer> response, - const network::ResourceRequest& tentative_resource_request) + std::unique_ptr<PrefetchedResponseContainer> response) : head_(response->TakeHead()), body_buffer_( base::MakeRefCounted<net::StringIOBuffer>(response->TakeBody())), @@ -78,7 +77,7 @@ } } -SearchPrefetchFromStringURLLoader::RequestHandler +SearchPrefetchURLLoader::RequestHandler SearchPrefetchFromStringURLLoader::ServingResponseHandler() { return base::BindOnce(&SearchPrefetchFromStringURLLoader::BindAndStart, weak_ptr_factory_.GetWeakPtr());
diff --git a/chrome/browser/prefetch/search_prefetch/search_prefetch_from_string_url_loader.h b/chrome/browser/prefetch/search_prefetch/search_prefetch_from_string_url_loader.h index b9acd41..14e1301 100644 --- a/chrome/browser/prefetch/search_prefetch/search_prefetch_from_string_url_loader.h +++ b/chrome/browser/prefetch/search_prefetch/search_prefetch_from_string_url_loader.h
@@ -11,6 +11,7 @@ #include "base/memory/weak_ptr.h" #include "chrome/browser/prefetch/search_prefetch/prefetched_response_container.h" +#include "chrome/browser/prefetch/search_prefetch/search_prefetch_url_loader.h" #include "content/public/browser/url_loader_request_interceptor.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/pending_remote.h" @@ -28,16 +29,11 @@ class StringIOBuffer; } -class SearchPrefetchFromStringURLLoader : public network::mojom::URLLoader { +class SearchPrefetchFromStringURLLoader : public network::mojom::URLLoader, + public SearchPrefetchURLLoader { public: - using RequestHandler = base::OnceCallback<void( - const network::ResourceRequest& resource_request, - mojo::PendingReceiver<network::mojom::URLLoader> url_loader_receiver, - mojo::PendingRemote<network::mojom::URLLoaderClient> client)>; - - SearchPrefetchFromStringURLLoader( - std::unique_ptr<PrefetchedResponseContainer> response, - const network::ResourceRequest& tentative_resource_request); + explicit SearchPrefetchFromStringURLLoader( + std::unique_ptr<PrefetchedResponseContainer> response); ~SearchPrefetchFromStringURLLoader() override; @@ -46,8 +42,8 @@ SearchPrefetchFromStringURLLoader& operator=( const SearchPrefetchFromStringURLLoader&) = delete; - // Called when the response should be served to the user. Returns a handler. - RequestHandler ServingResponseHandler(); + // SearchPrefetchURLLoader: + SearchPrefetchURLLoader::RequestHandler ServingResponseHandler() override; private: // network::mojom::URLLoader:
diff --git a/chrome/browser/prefetch/search_prefetch/search_prefetch_service.cc b/chrome/browser/prefetch/search_prefetch/search_prefetch_service.cc index dff243e4..f0416bcb 100644 --- a/chrome/browser/prefetch/search_prefetch/search_prefetch_service.cc +++ b/chrome/browser/prefetch/search_prefetch/search_prefetch_service.cc
@@ -9,24 +9,14 @@ #include "base/location.h" #include "chrome/browser/net/prediction_options.h" #include "chrome/browser/prefetch/search_prefetch/field_trial_settings.h" -#include "chrome/browser/prefetch/search_prefetch/prefetched_response_container.h" +#include "chrome/browser/prefetch/search_prefetch/full_body_search_prefetch_request.h" +#include "chrome/browser/prefetch/search_prefetch/search_prefetch_url_loader.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/search_engines/template_url_service_factory.h" #include "chrome/browser/search_engines/ui_thread_search_terms_data.h" #include "components/omnibox/browser/autocomplete_controller.h" #include "components/omnibox/browser/base_search_provider.h" #include "components/search_engines/template_url_service.h" -#include "components/variations/net/variations_http_headers.h" -#include "content/public/browser/browser_context.h" -#include "content/public/browser/frame_accept_header.h" -#include "content/public/browser/render_process_host.h" -#include "content/public/browser/storage_partition.h" -#include "content/public/common/content_constants.h" -#include "net/base/load_flags.h" -#include "net/http/http_status_code.h" -#include "net/traffic_annotation/network_traffic_annotation.h" -#include "services/network/public/cpp/resource_request.h" -#include "services/network/public/cpp/shared_url_loader_factory.h" #include "url/origin.h" namespace { @@ -47,120 +37,6 @@ } // namespace -SearchPrefetchService::PrefetchRequest::PrefetchRequest( - const GURL& prefetch_url, - base::OnceClosure report_error_callback) - : prefetch_url_(prefetch_url), - report_error_callback_(std::move(report_error_callback)) {} - -SearchPrefetchService::PrefetchRequest::~PrefetchRequest() = default; - -void SearchPrefetchService::PrefetchRequest::StartPrefetchRequest( - Profile* profile) { - net::NetworkTrafficAnnotationTag traffic_annotation = - net::DefineNetworkTrafficAnnotation("search_prefetch_service", R"( - semantics { - sender: "Search Prefetch Service" - description: - "Prefetches search results page (HTML) based on omnibox hints " - "provided by the user's default search engine. This allows the " - "prefetched content to be served when the user navigates to the " - "omnibox hint." - trigger: - "User typing in the omnibox and the default search provider " - "indicates the provided omnibox hint entry is likely to be " - "navigated which would result in loading a search results page for " - "that hint." - data: "Credentials if user is signed in." - destination: OTHER - destination_other: "The user's default search engine." - } - policy { - cookies_allowed: YES - cookies_store: "user" - setting: - "Users can control this feature by opting out of 'Preload pages " - "for faster browsing and searching'" - chrome_policy { - DefaultSearchProviderEnabled { - policy_options {mode: MANDATORY} - DefaultSearchProviderEnabled: false - } - NetworkPredictionOptions { - NetworkPredictionOptions: 2 - } - } - })"); - - auto resource_request = std::make_unique<network::ResourceRequest>(); - resource_request->load_flags |= net::LOAD_PREFETCH; - resource_request->url = prefetch_url_; - resource_request->credentials_mode = - network::mojom::CredentialsMode::kInclude; - variations::AppendVariationsHeaderUnknownSignedIn( - prefetch_url_, variations::InIncognito::kNo, resource_request.get()); - resource_request->headers.SetHeader(content::kCorsExemptPurposeHeaderName, - "prefetch"); - resource_request->headers.SetHeader( - net::HttpRequestHeaders::kAccept, - content::FrameAcceptHeaderValue(/*allow_sxg_responses=*/true, profile)); - // TODO(ryansturm): Find other headers that may need to be set. - // https://crbug.com/1138648 - - simple_loader_ = network::SimpleURLLoader::Create(std::move(resource_request), - traffic_annotation); - - auto url_loader_factory = - content::BrowserContext::GetDefaultStoragePartition(profile) - ->GetURLLoaderFactoryForBrowserProcess(); - - simple_loader_->DownloadToString( - url_loader_factory.get(), - base::BindOnce(&SearchPrefetchService::PrefetchRequest::LoadDone, - base::Unretained(this)), - 1024 * 1024); -} - -void SearchPrefetchService::PrefetchRequest::LoadDone( - std::unique_ptr<std::string> response_body) { - bool success = simple_loader_->NetError() == net::OK; - int response_code = 0; - - // TODO(ryansturm): Handle these errors more robustly by reporting them to the - // service. We need to prevent prefetches for x amount of time based on the - // error. https://crbug.com/1138641 - if (!success || response_body->empty()) { - current_status_ = SearchPrefetchStatus::kRequestFailed; - std::move(report_error_callback_).Run(); - return; - } - if (simple_loader_->ResponseInfo() && simple_loader_->ResponseInfo()->headers) - response_code = simple_loader_->ResponseInfo()->headers->response_code(); - if (response_code != net::HTTP_OK) { - current_status_ = SearchPrefetchStatus::kRequestFailed; - std::move(report_error_callback_).Run(); - return; - } - current_status_ = SearchPrefetchStatus::kSuccessfullyCompleted; - - prefetch_response_container_ = std::make_unique<PrefetchedResponseContainer>( - simple_loader_->ResponseInfo()->Clone(), std::move(response_body)); - - simple_loader_.reset(); -} - -std::unique_ptr<PrefetchedResponseContainer> -SearchPrefetchService::PrefetchRequest::TakePrefetchResponse() { - return std::move(prefetch_response_container_); -} - -void SearchPrefetchService::PrefetchRequest::CancelPrefetch() { - DCHECK_EQ(current_status_, SearchPrefetchStatus::kInFlight); - current_status_ = SearchPrefetchStatus::kRequestCancelled; - - simple_loader_.reset(); -} - SearchPrefetchService::SearchPrefetchService(Profile* profile) : profile_(profile) { DCHECK(!profile_->IsOffTheRecord()); @@ -221,7 +97,7 @@ } prefetches_.emplace( - search_terms, std::make_unique<PrefetchRequest>( + search_terms, std::make_unique<FullBodySearchPrefetchRequest>( url, base::BindOnce(&SearchPrefetchService::ReportError, base::Unretained(this)))); prefetches_[search_terms]->StartPrefetchRequest(profile_); @@ -242,7 +118,7 @@ return prefetches_[search_terms]->current_status(); } -std::unique_ptr<PrefetchedResponseContainer> +std::unique_ptr<SearchPrefetchURLLoader> SearchPrefetchService::TakePrefetchResponse(const GURL& url) { auto* template_url_service = TemplateURLServiceFactory::GetForProfile(profile_); @@ -278,8 +154,8 @@ return nullptr; } - std::unique_ptr<PrefetchedResponseContainer> response = - iter->second->TakePrefetchResponse(); + std::unique_ptr<SearchPrefetchURLLoader> response = + iter->second->TakeSearchPrefetchURLLoader(); // TODO(ryansturm): For metrics reporting, the prefetch request data should be // moved to the correct tab helper object, for now, the object can be deleted
diff --git a/chrome/browser/prefetch/search_prefetch/search_prefetch_service.h b/chrome/browser/prefetch/search_prefetch/search_prefetch_service.h index 3fd2fdcb..feea27f 100644 --- a/chrome/browser/prefetch/search_prefetch/search_prefetch_service.h +++ b/chrome/browser/prefetch/search_prefetch/search_prefetch_service.h
@@ -12,30 +12,18 @@ #include "base/scoped_observation.h" #include "base/strings/string16.h" #include "base/timer/timer.h" +#include "chrome/browser/prefetch/search_prefetch/base_search_prefetch_request.h" #include "components/keyed_service/core/keyed_service.h" #include "components/search_engines/template_url_data.h" #include "components/search_engines/template_url_service.h" #include "components/search_engines/template_url_service_observer.h" -#include "services/network/public/cpp/simple_url_loader.h" #include "url/gurl.h" class Profile; -class GURL; -class PrefetchedResponseContainer; +class SearchPrefetchURLLoader; class AutocompleteController; -enum class SearchPrefetchStatus { - // The request is on the network and may move to any other state. - kInFlight = 1, - // The request received all the data and is ready to serve. - kSuccessfullyCompleted = 2, - // The request hit an error and cannot be served. - kRequestFailed = 3, - // The request was cancelled before completion. - kRequestCancelled = 4, -}; - class SearchPrefetchService : public KeyedService, public TemplateURLServiceObserver { public: @@ -62,7 +50,7 @@ void ClearPrefetches(); // Takes the response from this object if |url| matches a prefetched URL. - std::unique_ptr<PrefetchedResponseContainer> TakePrefetchResponse( + std::unique_ptr<SearchPrefetchURLLoader> TakePrefetchResponse( const GURL& url); // Reports the status of a prefetch for a given search term. @@ -76,56 +64,11 @@ // Records the current time to prevent prefetches for a set duration. void ReportError(); - // Internal class to represent an ongoing or completed prefetch. - class PrefetchRequest { - public: - // |service| must outlive this class and be able to manage this class's - // lifetime. - PrefetchRequest(const GURL& prefetch_url, - base::OnceClosure report_error_callback); - ~PrefetchRequest(); - - PrefetchRequest(const PrefetchRequest&) = delete; - PrefetchRequest& operator=(const PrefetchRequest&) = delete; - - // Starts the network request to prefetch |prefetch_url_|. - void StartPrefetchRequest(Profile* profile); - - // Cancels the on-going prefetch and marks the status appropriately. - void CancelPrefetch(); - - SearchPrefetchStatus current_status() const { return current_status_; } - - const GURL& prefetch_url() const { return prefetch_url_; } - - // Takes ownership of the prefetched data. - std::unique_ptr<PrefetchedResponseContainer> TakePrefetchResponse(); - - private: - // Called as a callback when the prefetch request is complete. Stores the - // response and other metadata in |prefetch_response_container_|. - void LoadDone(std::unique_ptr<std::string> response_body); - - SearchPrefetchStatus current_status_ = SearchPrefetchStatus::kInFlight; - - // The URL to prefetch the search terms from. - const GURL prefetch_url_; - - // The ongoing prefetch request. Null before and after the fetch. - std::unique_ptr<network::SimpleURLLoader> simple_loader_; - - // Once a prefetch is completed successfully, the associated prefetch data - // and metadata about the request. - std::unique_ptr<PrefetchedResponseContainer> prefetch_response_container_; - - // Called when there is a network/server error on the prefetch request. - base::OnceClosure report_error_callback_; - }; - // Prefetches that are started are stored using search terms as a key. Only // one prefetch should be started for a given search term until the old // prefetch expires. - std::map<base::string16, std::unique_ptr<PrefetchRequest>> prefetches_; + std::map<base::string16, std::unique_ptr<BaseSearchPrefetchRequest>> + prefetches_; // A group of timers to expire |prefetches_| based on the same key. std::map<base::string16, std::unique_ptr<base::OneShotTimer>>
diff --git a/chrome/browser/prefetch/search_prefetch/search_prefetch_url_loader.h b/chrome/browser/prefetch/search_prefetch/search_prefetch_url_loader.h new file mode 100644 index 0000000..e5447552 --- /dev/null +++ b/chrome/browser/prefetch/search_prefetch/search_prefetch_url_loader.h
@@ -0,0 +1,28 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_PREFETCH_SEARCH_PREFETCH_SEARCH_PREFETCH_URL_LOADER_H_ +#define CHROME_BROWSER_PREFETCH_SEARCH_PREFETCH_SEARCH_PREFETCH_URL_LOADER_H_ + +#include "mojo/public/cpp/bindings/pending_receiver.h" +#include "mojo/public/cpp/bindings/pending_remote.h" +#include "services/network/public/mojom/url_loader.mojom.h" +#include "services/network/public/mojom/url_response_head.mojom.h" + +// A simple interface that defines the behavior that a search prefetch URL +// loader must provide. +class SearchPrefetchURLLoader { + public: + virtual ~SearchPrefetchURLLoader() = default; + + using RequestHandler = base::OnceCallback<void( + const network::ResourceRequest& resource_request, + mojo::PendingReceiver<network::mojom::URLLoader> url_loader_receiver, + mojo::PendingRemote<network::mojom::URLLoaderClient> client)>; + + // Called when the response should be served to the user. Returns a handler. + virtual RequestHandler ServingResponseHandler() = 0; +}; + +#endif // CHROME_BROWSER_PREFETCH_SEARCH_PREFETCH_SEARCH_PREFETCH_URL_LOADER_H_
diff --git a/chrome/browser/prefetch/search_prefetch/search_prefetch_url_loader_interceptor.cc b/chrome/browser/prefetch/search_prefetch/search_prefetch_url_loader_interceptor.cc index 306d780..6abfa3f 100644 --- a/chrome/browser/prefetch/search_prefetch/search_prefetch_url_loader_interceptor.cc +++ b/chrome/browser/prefetch/search_prefetch/search_prefetch_url_loader_interceptor.cc
@@ -11,9 +11,9 @@ #include "base/feature_list.h" #include "base/metrics/histogram_macros.h" #include "chrome/browser/prefetch/search_prefetch/prefetched_response_container.h" -#include "chrome/browser/prefetch/search_prefetch/search_prefetch_from_string_url_loader.h" #include "chrome/browser/prefetch/search_prefetch/search_prefetch_service.h" #include "chrome/browser/prefetch/search_prefetch/search_prefetch_service_factory.h" +#include "chrome/browser/prefetch/search_prefetch/search_prefetch_url_loader.h" #include "chrome/browser/profiles/profile.h" #include "components/no_state_prefetch/browser/prerender_manager.h" #include "content/public/browser/browser_context.h" @@ -49,33 +49,28 @@ loader_callback_ = std::move(callback); url_ = tentative_resource_request.url; - std::unique_ptr<PrefetchedResponseContainer> prefetch = + std::unique_ptr<SearchPrefetchURLLoader> prefetch = GetPrefetchedResponse(url_); if (!prefetch) { DoNotInterceptPrefetchedNavigation(); return; } - InterceptPrefetchedNavigation(tentative_resource_request, - std::move(prefetch)); + InterceptPrefetchedNavigation(std::move(prefetch)); } void SearchPrefetchURLLoaderInterceptor::InterceptPrefetchedNavigation( - const network::ResourceRequest& tentative_resource_request, - std::unique_ptr<PrefetchedResponseContainer> prefetch) { - std::unique_ptr<SearchPrefetchFromStringURLLoader> url_loader = - std::make_unique<SearchPrefetchFromStringURLLoader>( - std::move(prefetch), tentative_resource_request); - std::move(loader_callback_).Run(url_loader->ServingResponseHandler()); + std::unique_ptr<SearchPrefetchURLLoader> prefetch) { + std::move(loader_callback_).Run(prefetch->ServingResponseHandler()); // url_loader manages its own lifetime once bound to the mojo pipes. - url_loader.release(); + prefetch.release(); } void SearchPrefetchURLLoaderInterceptor::DoNotInterceptPrefetchedNavigation() { std::move(loader_callback_).Run({}); } -std::unique_ptr<PrefetchedResponseContainer> +std::unique_ptr<SearchPrefetchURLLoader> SearchPrefetchURLLoaderInterceptor::GetPrefetchedResponse(const GURL& url) { auto* profile = ProfileFromFrameTreeNodeID(frame_tree_node_id_); if (!profile)
diff --git a/chrome/browser/prefetch/search_prefetch/search_prefetch_url_loader_interceptor.h b/chrome/browser/prefetch/search_prefetch/search_prefetch_url_loader_interceptor.h index fd954a8..741f197 100644 --- a/chrome/browser/prefetch/search_prefetch/search_prefetch_url_loader_interceptor.h +++ b/chrome/browser/prefetch/search_prefetch/search_prefetch_url_loader_interceptor.h
@@ -21,7 +21,7 @@ class BrowserContext; } // namespace content -class PrefetchedResponseContainer; +class SearchPrefetchURLLoader; // Intercepts search navigations that were previously prefetched. class SearchPrefetchURLLoaderInterceptor @@ -43,13 +43,12 @@ protected: // Virtual for testing - virtual std::unique_ptr<PrefetchedResponseContainer> GetPrefetchedResponse( + virtual std::unique_ptr<SearchPrefetchURLLoader> GetPrefetchedResponse( const GURL& url); private: void InterceptPrefetchedNavigation( - const network::ResourceRequest& tentative_resource_request, - std::unique_ptr<PrefetchedResponseContainer>); + std::unique_ptr<SearchPrefetchURLLoader> prefetch); void DoNotInterceptPrefetchedNavigation(); bool MaybeInterceptNavigation(
diff --git a/chrome/browser/resources/chromeos/accessibility/switch_access/focus_ring_manager.js b/chrome/browser/resources/chromeos/accessibility/switch_access/focus_ring_manager.js index fca01b2a..8ffdc05e 100644 --- a/chrome/browser/resources/chromeos/accessibility/switch_access/focus_ring_manager.js +++ b/chrome/browser/resources/chromeos/accessibility/switch_access/focus_ring_manager.js
@@ -65,13 +65,13 @@ // Clear the dashed ring between transitions, as the animation is // distracting. manager.rings_.get(SAConstants.Focus.ID.PREVIEW).rects = []; - manager.updateFocusRings_(); + manager.updateFocusRings_(node, null); // The dashed focus ring should not be shown around the menu when exiting. if (!MenuManager.isMenuOpen()) { manager.rings_.get(SAConstants.Focus.ID.PREVIEW).rects = [backButton.group.location]; - manager.updateFocusRings_(); + manager.updateFocusRings_(node, null); } return; } @@ -91,7 +91,6 @@ // Clear the dashed ring between transitions, as the animation is // distracting. manager.rings_.get(SAConstants.Focus.ID.PREVIEW).rects = []; - manager.updateFocusRings_(); let focusRect = node.location; const childRect = firstChild ? firstChild.location : null; @@ -103,20 +102,33 @@ manager.rings_.get(SAConstants.Focus.ID.PREVIEW).rects = [childRect]; } manager.rings_.get(SAConstants.Focus.ID.PRIMARY).rects = [focusRect]; - manager.updateFocusRings_(); + manager.updateFocusRings_(node, firstChild); return; } manager.rings_.get(SAConstants.Focus.ID.PRIMARY).rects = [node.location]; manager.rings_.get(SAConstants.Focus.ID.PREVIEW).rects = []; - manager.updateFocusRings_(); + manager.updateFocusRings_(node, null); } /** Clears all focus rings. */ static clearAll() { const manager = FocusRingManager.instance; - manager.rings_.forEach((ring) => ring.rects = []); - manager.updateFocusRings_(); + manager.rings_.forEach((ring) => { + ring.rects = []; + }); + manager.updateFocusRings_(null, null); + } + + /** + * Set an observer that will be called every time the focus rings + * are updated. It will be called with two arguments: the node for + * the primary ring, and the node for the preview ring. Either may + * be null. + * @param {function(SAChildNode, SAChildNode)} observer + */ + static setObserver(observer) { + FocusRingManager.instance.observer_ = observer; } /** @@ -151,12 +163,20 @@ /** * Updates all focus rings to reflect new location, color, style, or other - * changes. + * changes. Enables observers to monitor what's focused. * @private */ - updateFocusRings_() { + updateFocusRings_(primaryRingNode, previewRingNode) { const focusRings = []; this.rings_.forEach((ring) => focusRings.push(ring)); chrome.accessibilityPrivate.setFocusRings(focusRings); + + const observer = FocusRingManager.instance.observer_; + if (observer) { + observer(primaryRingNode, previewRingNode); + } } } + +// Needed for switch_access_browsertest.cc +window.FocusRingManager = FocusRingManager;
diff --git a/chrome/browser/resources/chromeos/login/cr_ui.js b/chrome/browser/resources/chromeos/login/cr_ui.js index cc3faa3..d7d6a91 100644 --- a/chrome/browser/resources/chromeos/login/cr_ui.js +++ b/chrome/browser/resources/chromeos/login/cr_ui.js
@@ -312,15 +312,22 @@ /** * Returns true if enrollment was successful. Dismisses the enrollment * attribute screen if it's present. + * + * TODO(crbug.com/1111387) - Remove inline values from + * ENROLLMENT_STEP once fully migrated to JS modules. */ Oobe.isEnrollmentSuccessfulForTest = function() { const step = $('enterprise-enrollment').uiStep; - if (step === ENROLLMENT_STEP.ATTRIBUTE_PROMPT) { + // See [ENROLLMENT_STEP.ATTRIBUTE_PROMPT] + // from c/b/r/chromeos/login/enterprise_enrollment.js + if (step === 'attribute-prompt') { chrome.send('oauthEnrollAttributes', ['', '']); return true; } - return step === ENROLLMENT_STEP.SUCCESS; + // See [ENROLLMENT_STEP.SUCCESS] + // from c/b/r/chromeos/login/enterprise_enrollment.js + return step === 'success'; }; /**
diff --git a/chrome/browser/resources/chromeos/login/enterprise_enrollment.js b/chrome/browser/resources/chromeos/login/enterprise_enrollment.js index 4e0caa1..5a384210 100644 --- a/chrome/browser/resources/chromeos/login/enterprise_enrollment.js +++ b/chrome/browser/resources/chromeos/login/enterprise_enrollment.js
@@ -14,7 +14,14 @@ keyboard.initializeKeyboardFlow(true); })();`; -/** @const */ var ENROLLMENT_STEP = { +/** + * @const + * When making changes to any of these parameters, make sure that their use in + * chrome/browser/resources/chromeos/login/cr_ui.js is updated as well. + * TODO(crbug.com/1111387) - Remove this dependency when fully migrated + * to JS modules. + * */ +var ENROLLMENT_STEP = { SIGNIN: 'signin', AD_JOIN: 'ad-join', WORKING: 'working',
diff --git a/chrome/browser/resources/chromeos/login/security_token_pin_browsertest.js b/chrome/browser/resources/chromeos/login/security_token_pin_browsertest.js index f183dc0..c21f84f 100644 --- a/chrome/browser/resources/chromeos/login/security_token_pin_browsertest.js +++ b/chrome/browser/resources/chromeos/login/security_token_pin_browsertest.js
@@ -17,6 +17,10 @@ get browsePreload() { return 'chrome://oobe/login'; } + + get extraLibraries() { + return super.extraLibraries.concat(['components/oobe_types.js']); + } }; TEST_F('PolymerSecurityTokenPinTest', 'All', function() {
diff --git a/chrome/browser/resources/settings/a11y_page/a11y_page.js b/chrome/browser/resources/settings/a11y_page/a11y_page.js index 782f0b7..fe7eaa29 100644 --- a/chrome/browser/resources/settings/a11y_page/a11y_page.js +++ b/chrome/browser/resources/settings/a11y_page/a11y_page.js
@@ -187,7 +187,7 @@ onA11yLiveCaptionChange_(event) { const a11yLiveCaptionOn = event.target.checked; chrome.metricsPrivate.recordBoolean( - 'Accessibility.LiveCaption.ToggleEnabled', a11yLiveCaptionOn); + 'Accessibility.LiveCaption.EnableFromSettings', a11yLiveCaptionOn); }, /**
diff --git a/chrome/browser/resources/settings/a11y_page/captions_subpage.js b/chrome/browser/resources/settings/a11y_page/captions_subpage.js index c4d29e2..1ec6d89 100644 --- a/chrome/browser/resources/settings/a11y_page/captions_subpage.js +++ b/chrome/browser/resources/settings/a11y_page/captions_subpage.js
@@ -303,7 +303,7 @@ onA11yLiveCaptionChange_(event) { const a11yLiveCaptionOn = event.target.checked; chrome.metricsPrivate.recordBoolean( - 'Accessibility.LiveCaption.ToggleEnabled', a11yLiveCaptionOn); + 'Accessibility.LiveCaption.EnableFromSettings', a11yLiveCaptionOn); }, /**
diff --git a/chrome/browser/resources/settings/chromeos/ambient_mode_page/album_list.html b/chrome/browser/resources/settings/chromeos/ambient_mode_page/album_list.html index e7d4242..6b02e5a 100644 --- a/chrome/browser/resources/settings/chromeos/ambient_mode_page/album_list.html +++ b/chrome/browser/resources/settings/chromeos/ambient_mode_page/album_list.html
@@ -30,7 +30,7 @@ <paper-spinner-lite active="[[!albums]]" hidden="[[albums]]"> </paper-spinner-lite> - <iron-list grid scrollable scroll-target="document" items="{{albums}}"> + <iron-list grid items="{{albums}}"> <template> <album-item album="{{item}}" checked="{{item.checked}}" topic-source="[[topicSource]]" tabindex$="[[tabIndex]]"
diff --git a/chrome/browser/resources/settings/chromeos/os_a11y_page/manage_a11y_page.js b/chrome/browser/resources/settings/chromeos/os_a11y_page/manage_a11y_page.js index 98952cec..7e5b31b2 100644 --- a/chrome/browser/resources/settings/chromeos/os_a11y_page/manage_a11y_page.js +++ b/chrome/browser/resources/settings/chromeos/os_a11y_page/manage_a11y_page.js
@@ -496,7 +496,7 @@ return; } - const enabled = this.$.shelfNavigationButtonsEnabledControl.checked; + const enabled = this.$$('#shelfNavigationButtonsEnabledControl').checked; this.set( 'prefs.settings.a11y.tablet_mode_shelf_nav_buttons_enabled.value', enabled);
diff --git a/chrome/browser/sessions/session_restore_browsertest.cc b/chrome/browser/sessions/session_restore_browsertest.cc index b0b03fd..e41d9d8e 100644 --- a/chrome/browser/sessions/session_restore_browsertest.cc +++ b/chrome/browser/sessions/session_restore_browsertest.cc
@@ -2239,6 +2239,8 @@ // Test that it is possible to navigate back to a restored about:blank history // entry with a non-null initiator origin. This test cases covers the original // repro steps reported in https://crbug.com/1026474. +// +// See also TabRestoreTest.BackToAboutBlank IN_PROC_BROWSER_TEST_F(MultiOriginSessionRestoreTest, BackToAboutBlank1) { // Open about:blank in a new tab. GURL initial_url = embedded_test_server()->GetURL("foo.com", "/title1.html");
diff --git a/chrome/browser/sessions/tab_restore_browsertest.cc b/chrome/browser/sessions/tab_restore_browsertest.cc index b5139f7..aa9c1050 100644 --- a/chrome/browser/sessions/tab_restore_browsertest.cc +++ b/chrome/browser/sessions/tab_restore_browsertest.cc
@@ -49,7 +49,9 @@ #include "content/public/browser/web_contents.h" #include "content/public/test/browser_test.h" #include "content/public/test/browser_test_utils.h" +#include "content/public/test/test_navigation_observer.h" #include "content/public/test/test_utils.h" +#include "net/dns/mock_host_resolver.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "ui/gfx/animation/animation_test_api.h" #include "url/gurl.h" @@ -82,6 +84,9 @@ protected: void SetUpOnMainThread() override { active_browser_list_ = BrowserList::GetInstance(); + + host_resolver()->AddRule("*", "127.0.0.1"); + content::SetupCrossSiteRedirector(embedded_test_server()); } Browser* GetBrowser(int index) { @@ -1428,3 +1433,74 @@ ASSERT_NO_FATAL_FAILURE(RestoreTab(0, 2)); EXPECT_EQ(url1_, browser()->tab_strip_model()->GetWebContentsAt(2)->GetURL()); } + +// Test that it is possible to navigate back to a restored about:blank history +// entry with a non-null initiator origin. This test cases covers +// https://crbug.com/1116320 - a scenario where the restore type is different +// from LAST_SESSION_EXITED_CLEANLY (e.g. the test below uses CURRENT_SESSION). +// +// See also MultiOriginSessionRestoreTest.BackToAboutBlank1 +IN_PROC_BROWSER_TEST_F(TabRestoreTest, BackToAboutBlank) { + ASSERT_TRUE(embedded_test_server()->Start()); + GURL initial_url = embedded_test_server()->GetURL("foo.com", "/title1.html"); + url::Origin initial_origin = url::Origin::Create(initial_url); + ui_test_utils::NavigateToURL(browser(), initial_url); + + // Open about:blank in a new tab. + content::WebContents* old_popup = nullptr; + { + EXPECT_EQ(0, browser()->tab_strip_model()->active_index()); + content::WebContents* tab1 = + browser()->tab_strip_model()->GetActiveWebContents(); + content::WebContentsAddedObserver popup_observer; + ASSERT_TRUE(ExecJs(tab1, "window.open('about:blank')")); + old_popup = popup_observer.GetWebContents(); + EXPECT_EQ(1, browser()->tab_strip_model()->active_index()); + EXPECT_EQ(GURL(url::kAboutBlankURL), + old_popup->GetMainFrame()->GetLastCommittedURL()); + EXPECT_EQ(initial_origin, + old_popup->GetMainFrame()->GetLastCommittedOrigin()); + } + + // Navigate the popup to another site. + GURL other_url = embedded_test_server()->GetURL("bar.com", "/title1.html"); + url::Origin other_origin = url::Origin::Create(other_url); + { + content::TestNavigationObserver nav_observer(old_popup); + ASSERT_TRUE(content::ExecJs( + old_popup, content::JsReplace("location = $1", other_url))); + nav_observer.Wait(); + } + EXPECT_EQ(other_url, old_popup->GetMainFrame()->GetLastCommittedURL()); + EXPECT_EQ(other_origin, old_popup->GetMainFrame()->GetLastCommittedOrigin()); + ASSERT_TRUE(old_popup->GetController().CanGoBack()); + + // Close the popup. + int closed_tab_index = browser()->tab_strip_model()->active_index(); + EXPECT_EQ(1, closed_tab_index); + CloseTab(closed_tab_index); + EXPECT_EQ(1, browser()->tab_strip_model()->count()); + + // Reopen the popup. + content::WebContents* new_popup = nullptr; + { + content::WebContentsAddedObserver restored_tab_observer; + RestoreTab(0, closed_tab_index); + EXPECT_EQ(2, browser()->tab_strip_model()->count()); + new_popup = restored_tab_observer.GetWebContents(); + } + EXPECT_EQ(other_url, new_popup->GetMainFrame()->GetLastCommittedURL()); + EXPECT_EQ(other_origin, new_popup->GetMainFrame()->GetLastCommittedOrigin()); + ASSERT_TRUE(new_popup->GetController().CanGoBack()); + int reopened_tab_index = browser()->tab_strip_model()->active_index(); + EXPECT_EQ(1, reopened_tab_index); + + // Navigate the popup back to about:blank. + GoBack(browser()); + EXPECT_EQ(GURL(url::kAboutBlankURL), + new_popup->GetMainFrame()->GetLastCommittedURL()); + // TODO(lukasza): https://crbug.com/888079: The browser process should tell + // the renderer which (initiator-based) origin to commit. Right now, Blink + // just falls back to an opaque origin. + EXPECT_TRUE(new_popup->GetMainFrame()->GetLastCommittedOrigin().opaque()); +}
diff --git a/chrome/browser/speech/extension_api/tts_extension_apitest.cc b/chrome/browser/speech/extension_api/tts_extension_apitest.cc index e8567d5..d7087f9 100644 --- a/chrome/browser/speech/extension_api/tts_extension_apitest.cc +++ b/chrome/browser/speech/extension_api/tts_extension_apitest.cc
@@ -452,9 +452,11 @@ IN_PROC_BROWSER_TEST_F(TtsApiTest, PlatformPauseSpeakNoEnqueue) { // While paused, one utterance is enqueued, and then a second utterance that - // cannot be enqueued cancels both. + // cannot be enqueued cancels only the first. InSequence s; EXPECT_CALL(mock_platform_impl_, StopSpeaking()).WillOnce(Return(true)); + EXPECT_CALL(mock_platform_impl_, DoSpeak(_, "text 2", _, _, _)); + EXPECT_CALL(mock_platform_impl_, StopSpeaking()).WillOnce(Return(false)); ASSERT_TRUE(RunExtensionTest("tts/pause_speak_no_enqueue")) << message_; }
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd index 6816ba8..040b7b6 100644 --- a/chrome/browser/ui/android/strings/android_chrome_strings.grd +++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -2959,13 +2959,10 @@ Add to… </message> <message name="IDS_MENU_ADD_TO_DIALOG_TITLE" desc="Menu item for opening the 'Add to' dialog which can add the page to bookmarks, downloads, home screen, etc."> - Add to: + Add to </message> - <message name="IDS_MENU_ADD_TO_BOOKMARKS" desc="Menu item to save the web page to 'Bookmarks' section. The word 'Bookmarks' should match the translation in TC ID 1792806198663410166."> - Add to Bookmarks - </message> - <message name="IDS_MENU_ADD_TO_DOWNLOADS" desc="Menu item to download the current web page. The word 'Downloads' should match the translation in TC ID 9040361513231775562."> - Add to Downloads + <message name="IDS_MENU_HOMESCREEN" desc="Menu item for adding a shortcut to the Home screen (default title). [CHAR-LIMIT=27]"> + Home screen </message> <!-- Bookmarks strings -->
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_MENU_ADD_TO_BOOKMARKS.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_MENU_ADD_TO_BOOKMARKS.png.sha1 deleted file mode 100644 index bc684c3..0000000 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_MENU_ADD_TO_BOOKMARKS.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -34dfdcb5f9bc4418c211b5ed2764752f4fee129a \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_MENU_ADD_TO_DIALOG_TITLE.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_MENU_ADD_TO_DIALOG_TITLE.png.sha1 index bc684c3..67c7bbad 100644 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_MENU_ADD_TO_DIALOG_TITLE.png.sha1 +++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_MENU_ADD_TO_DIALOG_TITLE.png.sha1
@@ -1 +1 @@ -34dfdcb5f9bc4418c211b5ed2764752f4fee129a \ No newline at end of file +86bdc5f6d61661f7154a287c20c41de48529eb97 \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_MENU_ADD_TO_DOWNLOADS.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_MENU_ADD_TO_DOWNLOADS.png.sha1 deleted file mode 100644 index bc684c3..0000000 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_MENU_ADD_TO_DOWNLOADS.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -34dfdcb5f9bc4418c211b5ed2764752f4fee129a \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_MENU_HOMESCREEN.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_MENU_HOMESCREEN.png.sha1 new file mode 100644 index 0000000..67c7bbad --- /dev/null +++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_MENU_HOMESCREEN.png.sha1
@@ -0,0 +1 @@ +86bdc5f6d61661f7154a287c20c41de48529eb97 \ No newline at end of file
diff --git a/chrome/browser/ui/ash/README.md b/chrome/browser/ui/ash/README.md index adbdf51..a47b61d 100644 --- a/chrome/browser/ui/ash/README.md +++ b/chrome/browser/ui/ash/README.md
@@ -7,8 +7,5 @@ Code in this directory may have `ash/public` dependencies. *Any non-public `ash/` dependencies will need to be removed.* -See [ash/README.md#Mustash](/ash/README.md#Mustash) for more information about -the Mustash project. - Code in this directory may depend on code in [`chrome/browser/chromeos`](/chrome/browser/chromeos/README.md).
diff --git a/chrome/browser/ui/views/accessibility/caption_bubble.cc b/chrome/browser/ui/views/accessibility/caption_bubble.cc index f51f86c..5a24adc 100644 --- a/chrome/browser/ui/views/accessibility/caption_bubble.cc +++ b/chrome/browser/ui/views/accessibility/caption_bubble.cc
@@ -10,7 +10,7 @@ #include <utility> #include <vector> -#include "base/metrics/histogram_macros.h" +#include "base/metrics/histogram_functions.h" #include "base/strings/string16.h" #include "base/time/default_tick_clock.h" #include "base/timer/timer.h" @@ -75,6 +75,23 @@ static constexpr int kWidgetDisplacementWithArrowKeyDip = 16; static constexpr int kNoActivityIntervalSeconds = 5; +// These values are persisted to logs. Entries should not be renumbered and +// numeric values should never be reused. These should be the same as +// LiveCaptionSessionEvent in enums.xml. +enum class SessionEvent { + // We began showing captions for an audio stream. + kStreamStarted = 0, + // The audio stream ended and the caption bubble closes. + kStreamEnded = 1, + // The close button was clicked, so we stopped listening to an audio stream. + kCloseButtonClicked = 2, + kMaxValue = kCloseButtonClicked, +}; + +void LogSessionEvent(SessionEvent event) { + base::UmaHistogramEnumeration("Accessibility.LiveCaption.Session", event); +} + } // namespace namespace captions { @@ -507,18 +524,15 @@ } void CaptionBubble::CloseButtonPressed() { - // TODO(crbug.com/1055150): This histogram currently only reports a single - // bucket, but it will eventually be extended to report session starts and - // natural session ends (when the audio stream ends). - UMA_HISTOGRAM_ENUMERATION( - "Accessibility.LiveCaption.Session", - CaptionController::SessionEvent::kCloseButtonClicked); + LogSessionEvent(SessionEvent::kCloseButtonClicked); if (model_) model_->Close(); } void CaptionBubble::ExpandOrCollapseButtonPressed() { is_expanded_ = !is_expanded_; + base::UmaHistogramBoolean("Accessibility.LiveCaption.ExpandBubble", + is_expanded_); views::Button *old_button = collapse_button_, *new_button = expand_button_; if (is_expanded_) std::swap(old_button, new_button); @@ -656,6 +670,7 @@ GetWidget()->ShowInactive(); GetViewAccessibility().AnnounceText(l10n_util::GetStringUTF16( IDS_LIVE_CAPTION_BUBBLE_APPEAR_SCREENREADER_ANNOUNCEMENT)); + LogSessionEvent(SessionEvent::kStreamStarted); } } else if (GetWidget()->IsVisible()) { // No text and no error. Hide it. @@ -756,6 +771,7 @@ } void CaptionBubble::OnInactivityTimeout() { + LogSessionEvent(SessionEvent::kStreamEnded); if (GetWidget()->IsVisible()) GetWidget()->Hide(); }
diff --git a/chrome/browser/ui/views/autofill/autofill_bubble_handler_impl.cc b/chrome/browser/ui/views/autofill/autofill_bubble_handler_impl.cc index 9909684..d2d73fb 100644 --- a/chrome/browser/ui/views/autofill/autofill_bubble_handler_impl.cc +++ b/chrome/browser/ui/views/autofill/autofill_bubble_handler_impl.cc
@@ -36,13 +36,14 @@ ToolbarButtonProvider* toolbar_button_provider) : browser_(browser), toolbar_button_provider_(toolbar_button_provider) { if (browser->profile()) { - personal_data_manager_observer_.Add( + personal_data_manager_observation_.Observe( PersonalDataManagerFactory::GetForProfile( browser->profile()->GetOriginalProfile())); } - if (toolbar_button_provider_->GetAvatarToolbarButton()) - avatar_toolbar_button_observer_.Add( + if (toolbar_button_provider_->GetAvatarToolbarButton()) { + avatar_toolbar_button_observation_.Observe( toolbar_button_provider_->GetAvatarToolbarButton()); + } } AutofillBubbleHandlerImpl::~AutofillBubbleHandlerImpl() = default;
diff --git a/chrome/browser/ui/views/autofill/autofill_bubble_handler_impl.h b/chrome/browser/ui/views/autofill/autofill_bubble_handler_impl.h index e18898fa..935c65d1 100644 --- a/chrome/browser/ui/views/autofill/autofill_bubble_handler_impl.h +++ b/chrome/browser/ui/views/autofill/autofill_bubble_handler_impl.h
@@ -6,7 +6,7 @@ #define CHROME_BROWSER_UI_VIEWS_AUTOFILL_AUTOFILL_BUBBLE_HANDLER_IMPL_H_ #include "base/macros.h" -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "chrome/browser/ui/autofill/autofill_bubble_handler.h" #include "chrome/browser/ui/views/profiles/avatar_toolbar_button.h" #include "components/autofill/core/browser/personal_data_manager.h" @@ -70,10 +70,10 @@ // button after the highlight animation finishes. bool should_show_sign_in_promo_if_applicable_ = false; - ScopedObserver<PersonalDataManager, PersonalDataManagerObserver> - personal_data_manager_observer_{this}; - ScopedObserver<AvatarToolbarButton, AvatarToolbarButton::Observer> - avatar_toolbar_button_observer_{this}; + base::ScopedObservation<PersonalDataManager, PersonalDataManagerObserver> + personal_data_manager_observation_{this}; + base::ScopedObservation<AvatarToolbarButton, AvatarToolbarButton::Observer> + avatar_toolbar_button_observation_{this}; DISALLOW_COPY_AND_ASSIGN(AutofillBubbleHandlerImpl); };
diff --git a/chrome/browser/ui/views/bubble/webui_bubble_manager.cc b/chrome/browser/ui/views/bubble/webui_bubble_manager.cc index 663ebcd1..4a56b6f 100644 --- a/chrome/browser/ui/views/bubble/webui_bubble_manager.cc +++ b/chrome/browser/ui/views/bubble/webui_bubble_manager.cc
@@ -54,7 +54,7 @@ bubble_view_ = WebUIBubbleDialogView::CreateWebUIBubbleDialog( std::make_unique<WebUIBubbleDialogView>(anchor_view_, std::move(cached_web_view_))); - observed_bubble_widget_.Add(bubble_view_->GetWidget()); + bubble_widget_observation_.Observe(bubble_view_->GetWidget()); close_bubble_helper_ = std::make_unique<CloseBubbleOnTabActivationHelper>( bubble_view_.get(), BrowserList::GetInstance()->GetLastActive()); return true; @@ -76,7 +76,7 @@ DCHECK(bubble_view_); DCHECK_EQ(bubble_view_->GetWidget(), widget); cached_web_view_ = bubble_view_->RemoveWebView(); - observed_bubble_widget_.Remove(bubble_view_->GetWidget()); + bubble_widget_observation_.RemoveObservation(); DCHECK(close_bubble_helper_); close_bubble_helper_.reset(); cache_timer_->Reset();
diff --git a/chrome/browser/ui/views/bubble/webui_bubble_manager.h b/chrome/browser/ui/views/bubble/webui_bubble_manager.h index 390fb974..2d3a229 100644 --- a/chrome/browser/ui/views/bubble/webui_bubble_manager.h +++ b/chrome/browser/ui/views/bubble/webui_bubble_manager.h
@@ -8,7 +8,7 @@ #include <memory> #include <utility> -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "chrome/browser/extensions/chrome_extension_web_contents_observer.h" #include "chrome/browser/ui/views/bubble/webui_bubble_view.h" #include "chrome/browser/ui/views/close_bubble_on_tab_activation_helper.h" @@ -77,8 +77,8 @@ // A timer controlling how long the |cached_web_view_| is cached for. std::unique_ptr<base::RetainingOneShotTimer> cache_timer_; - ScopedObserver<views::Widget, views::WidgetObserver> observed_bubble_widget_{ - this}; + base::ScopedObservation<views::Widget, views::WidgetObserver> + bubble_widget_observation_{this}; // This is necessary to prevent a bug closing the active tab in the bubble. // See https://crbug.com/1139028.
diff --git a/chrome/browser/ui/views/exclusive_access_bubble_views.cc b/chrome/browser/ui/views/exclusive_access_bubble_views.cc index c60701c..282a0433 100644 --- a/chrome/browser/ui/views/exclusive_access_bubble_views.cc +++ b/chrome/browser/ui/views/exclusive_access_bubble_views.cc
@@ -99,8 +99,9 @@ view_->SetBounds(0, 0, size.width(), size.height()); popup_->AddObserver(this); - fullscreen_observer_.Add(bubble_view_context_->GetExclusiveAccessManager() - ->fullscreen_controller()); + fullscreen_observation_.Observe( + bubble_view_context_->GetExclusiveAccessManager() + ->fullscreen_controller()); UpdateMouseWatcher(); }
diff --git a/chrome/browser/ui/views/exclusive_access_bubble_views.h b/chrome/browser/ui/views/exclusive_access_bubble_views.h index 3a32ecb..afdd750 100644 --- a/chrome/browser/ui/views/exclusive_access_bubble_views.h +++ b/chrome/browser/ui/views/exclusive_access_bubble_views.h
@@ -9,7 +9,7 @@ #include "base/compiler_specific.h" #include "base/macros.h" -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "chrome/browser/ui/exclusive_access/exclusive_access_bubble.h" #include "chrome/browser/ui/exclusive_access/exclusive_access_bubble_hide_callback.h" #include "chrome/browser/ui/exclusive_access/fullscreen_controller.h" @@ -115,8 +115,8 @@ SubtleNotificationView* view_; base::string16 browser_fullscreen_exit_accelerator_; - ScopedObserver<FullscreenController, FullscreenObserver> fullscreen_observer_{ - this}; + base::ScopedObservation<FullscreenController, FullscreenObserver> + fullscreen_observation_{this}; DISALLOW_COPY_AND_ASSIGN(ExclusiveAccessBubbleViews); };
diff --git a/chrome/browser/ui/views/flying_indicator.cc b/chrome/browser/ui/views/flying_indicator.cc index d999804..f45f93d 100644 --- a/chrome/browser/ui/views/flying_indicator.cc +++ b/chrome/browser/ui/views/flying_indicator.cc
@@ -91,7 +91,7 @@ views::BubbleDialogDelegateView* const bubble_view_ptr = bubble_view.get(); widget_ = views::BubbleDialogDelegateView::CreateBubble(std::move(bubble_view)); - scoped_observer_.Add(widget_); + scoped_observation_.Observe(widget_); // Set required frame properties. views::BubbleFrameView* const frame_view = @@ -111,7 +111,8 @@ FlyingIndicator::~FlyingIndicator() { // Kill the callback before deleting the widget so we don't call it. done_callback_.Reset(); - scoped_observer_.RemoveAll(); + if (scoped_observation_.IsObserving()) + scoped_observation_.RemoveObservation(); if (widget_) widget_->Close(); } @@ -119,7 +120,7 @@ void FlyingIndicator::OnWidgetDestroyed(views::Widget* widget) { if (widget != widget_) return; - scoped_observer_.Remove(widget_); + scoped_observation_.RemoveObservation(); widget_ = nullptr; animation_.Stop(); if (done_callback_) @@ -182,7 +183,7 @@ if (done_callback_) std::move(done_callback_).Run(); if (widget_) { - scoped_observer_.Remove(widget_); + scoped_observation_.RemoveObservation(); widget_->Close(); widget_ = nullptr; }
diff --git a/chrome/browser/ui/views/flying_indicator.h b/chrome/browser/ui/views/flying_indicator.h index 9574d278..5d6908f 100644 --- a/chrome/browser/ui/views/flying_indicator.h +++ b/chrome/browser/ui/views/flying_indicator.h
@@ -6,7 +6,7 @@ #define CHROME_BROWSER_UI_VIEWS_FLYING_INDICATOR_H_ #include "base/callback.h" -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "ui/gfx/animation/animation_delegate.h" #include "ui/gfx/animation/multi_animation.h" #include "ui/gfx/geometry/point.h" @@ -74,7 +74,8 @@ gfx::MultiAnimation animation_; base::OnceClosure done_callback_; views::Widget* widget_ = nullptr; - ScopedObserver<views::Widget, views::WidgetObserver> scoped_observer_{this}; + base::ScopedObservation<views::Widget, views::WidgetObserver> + scoped_observation_{this}; }; #endif // CHROME_BROWSER_UI_VIEWS_FLYING_INDICATOR_H_
diff --git a/chrome/browser/ui/views/global_media_controls/media_dialog_view.cc b/chrome/browser/ui/views/global_media_controls/media_dialog_view.cc index d8c02c0..b8d8c0f 100644 --- a/chrome/browser/ui/views/global_media_controls/media_dialog_view.cc +++ b/chrome/browser/ui/views/global_media_controls/media_dialog_view.cc
@@ -308,6 +308,8 @@ void MediaDialogView::LiveCaptionButtonPressed(const ui::Event& event) { bool enabled = !profile_->GetPrefs()->GetBoolean(prefs::kLiveCaptionEnabled); ToggleLiveCaption(enabled); + base::UmaHistogramBoolean( + "Accessibility.LiveCaption.EnableFromGlobalMediaControls", enabled); } void MediaDialogView::ToggleLiveCaption(bool enabled) {
diff --git a/chrome/browser/ui/views/hover_button.cc b/chrome/browser/ui/views/hover_button.cc index f40eac8..fc19f577 100644 --- a/chrome/browser/ui/views/hover_button.cc +++ b/chrome/browser/ui/views/hover_button.cc
@@ -162,7 +162,7 @@ label_wrapper_ = AddChildView(std::move(label_wrapper)); // Observe |label_wrapper_| bounds changes to ensure the HoverButton tooltip // is kept in sync with the size. - observed_label_.Add(label_wrapper_); + label_observation_.Observe(label_wrapper_); if (secondary_view) { secondary_view->SetCanProcessEventsWithinSubtree(
diff --git a/chrome/browser/ui/views/hover_button.h b/chrome/browser/ui/views/hover_button.h index a238ad4b..3e157e3 100644 --- a/chrome/browser/ui/views/hover_button.h +++ b/chrome/browser/ui/views/hover_button.h
@@ -7,7 +7,7 @@ #include "base/gtest_prod_util.h" #include "base/optional.h" -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "base/strings/string16.h" #include "ui/views/controls/button/button.h" #include "ui/views/controls/button/menu_button.h" @@ -107,7 +107,8 @@ views::View* icon_view_ = nullptr; views::View* secondary_view_ = nullptr; - ScopedObserver<views::View, views::ViewObserver> observed_label_{this}; + base::ScopedObservation<views::View, views::ViewObserver> label_observation_{ + this}; DISALLOW_COPY_AND_ASSIGN(HoverButton); };
diff --git a/chrome/browser/ui/views/hung_plugin_tab_helper_unittest.cc b/chrome/browser/ui/views/hung_plugin_tab_helper_unittest.cc index 148b845..26968e9 100644 --- a/chrome/browser/ui/views/hung_plugin_tab_helper_unittest.cc +++ b/chrome/browser/ui/views/hung_plugin_tab_helper_unittest.cc
@@ -5,7 +5,7 @@ #include "chrome/browser/ui/hung_plugin_tab_helper.h" #include "base/memory/ptr_util.h" -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "chrome/browser/infobars/infobar_service.h" #include "chrome/browser/ui/views/infobars/confirm_infobar.h" #include "chrome/test/base/chrome_render_view_host_test_harness.h" @@ -26,13 +26,14 @@ private: bool seen_removal_ = false; - ScopedObserver<infobars::InfoBarManager, infobars::InfoBarManager::Observer> - infobar_observer_{this}; + base::ScopedObservation<infobars::InfoBarManager, + infobars::InfoBarManager::Observer> + infobar_observation_{this}; }; HungPluginInfoBarObserver::HungPluginInfoBarObserver( infobars::InfoBarManager* manager) { - infobar_observer_.Add(manager); + infobar_observation_.Observe(manager); } void HungPluginInfoBarObserver::OnInfoBarRemoved(infobars::InfoBar* infobar,
diff --git a/chrome/browser/ui/views/hung_renderer_view.cc b/chrome/browser/ui/views/hung_renderer_view.cc index 5829db2..5cb4f0d 100644 --- a/chrome/browser/ui/views/hung_renderer_view.cc +++ b/chrome/browser/ui/views/hung_renderer_view.cc
@@ -80,8 +80,8 @@ DCHECK(!hang_monitor_restarter.is_null()); DCHECK(!render_widget_host_); - DCHECK(!process_observer_.IsObservingSources()); - DCHECK(!widget_observer_.IsObservingSources()); + DCHECK(!process_observation_.IsObserving()); + DCHECK(!widget_observation_.IsObserving()); DCHECK(tab_observers_.empty()); render_widget_host_ = render_widget_host; @@ -93,8 +93,8 @@ std::make_unique<WebContentsObserverImpl>(this, hung_contents)); } - process_observer_.Add(render_widget_host_->GetProcess()); - widget_observer_.Add(render_widget_host_); + process_observation_.Observe(render_widget_host_->GetProcess()); + widget_observation_.Observe(render_widget_host_); // The world is different. if (observer_) @@ -102,8 +102,8 @@ } void HungPagesTableModel::Reset() { - process_observer_.RemoveAll(); - widget_observer_.RemoveAll(); + process_observation_.RemoveObservation(); + widget_observation_.RemoveObservation(); tab_observers_.clear(); render_widget_host_ = nullptr;
diff --git a/chrome/browser/ui/views/hung_renderer_view.h b/chrome/browser/ui/views/hung_renderer_view.h index 1d487ae..3665588 100644 --- a/chrome/browser/ui/views/hung_renderer_view.h +++ b/chrome/browser/ui/views/hung_renderer_view.h
@@ -10,7 +10,7 @@ #include "base/callback.h" #include "base/macros.h" -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "components/favicon/content/content_favicon_driver.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_process_host_observer.h" @@ -124,11 +124,13 @@ // some more until the renderer process responds). base::RepeatingClosure hang_monitor_restarter_; - ScopedObserver<content::RenderProcessHost, content::RenderProcessHostObserver> - process_observer_{this}; + base::ScopedObservation<content::RenderProcessHost, + content::RenderProcessHostObserver> + process_observation_{this}; - ScopedObserver<content::RenderWidgetHost, content::RenderWidgetHostObserver> - widget_observer_{this}; + base::ScopedObservation<content::RenderWidgetHost, + content::RenderWidgetHostObserver> + widget_observation_{this}; DISALLOW_COPY_AND_ASSIGN(HungPagesTableModel); };
diff --git a/chrome/browser/ui/views/keyboard_access_browsertest.cc b/chrome/browser/ui/views/keyboard_access_browsertest.cc index 6b09563..f064f95 100644 --- a/chrome/browser/ui/views/keyboard_access_browsertest.cc +++ b/chrome/browser/ui/views/keyboard_access_browsertest.cc
@@ -89,7 +89,7 @@ : browser_(browser), menu_open_count_(0), test_dismiss_menu_(test_dismiss_menu) { - observer_.Add(app_menu_button); + observation_.Observe(app_menu_button); } ~SendKeysMenuListener() override = default; @@ -103,7 +103,7 @@ FROM_HERE, base::RunLoop::QuitCurrentWhenIdleClosureDeprecated(), base::TimeDelta::FromMilliseconds(200)); } else { - observer_.RemoveAll(); + observation_.RemoveObservation(); // Press DOWN to select the first item, then RETURN to select it. SendKeyPress(browser_, ui::VKEY_DOWN); SendKeyPress(browser_, ui::VKEY_RETURN); @@ -120,7 +120,8 @@ // we dismiss it by sending the ESC key. bool test_dismiss_menu_; - ScopedObserver<AppMenuButton, AppMenuButtonObserver> observer_{this}; + base::ScopedObservation<AppMenuButton, AppMenuButtonObserver> observation_{ + this}; DISALLOW_COPY_AND_ASSIGN(SendKeysMenuListener); };
diff --git a/chrome/browser/ui/views/menu_view_drag_and_drop_test.cc b/chrome/browser/ui/views/menu_view_drag_and_drop_test.cc index c4a0650..46a64db 100644 --- a/chrome/browser/ui/views/menu_view_drag_and_drop_test.cc +++ b/chrome/browser/ui/views/menu_view_drag_and_drop_test.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "base/macros.h" +#include "base/scoped_observation.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" #include "chrome/browser/ui/views/menu_test_base.h" @@ -189,8 +190,8 @@ // in separate child views). bool performed_in_menu_drop_ = false; - ScopedObserver<views::Widget, views::WidgetObserver> widget_observer_{this}; - + base::ScopedObservation<views::Widget, views::WidgetObserver> + widget_observation_{this}; DISALLOW_COPY_AND_ASSIGN(MenuViewDragAndDropTest); }; @@ -220,7 +221,7 @@ EXPECT_EQ(child_view, target_view_); // The menu is showing, so it has a widget we can observe now. - widget_observer_.Add(submenu->GetWidget()); + widget_observation_.Observe(submenu->GetWidget()); // We do this here (instead of in BuildMenu()) so that the menu is already // built and the bounds are correct. @@ -228,7 +229,8 @@ } void MenuViewDragAndDropTest::TearDown() { - widget_observer_.RemoveAll(); + if (widget_observation_.IsObserving()) + widget_observation_.RemoveObservation(); MenuTestBase::TearDown(); }
diff --git a/chrome/browser/ui/views/page_info/page_info_bubble_view_browsertest.cc b/chrome/browser/ui/views/page_info/page_info_bubble_view_browsertest.cc index 0a91e7c..ff4aeab6 100644 --- a/chrome/browser/ui/views/page_info/page_info_bubble_view_browsertest.cc +++ b/chrome/browser/ui/views/page_info/page_info_bubble_view_browsertest.cc
@@ -5,7 +5,7 @@ #include "chrome/browser/ui/views/page_info/page_info_bubble_view.h" #include "base/run_loop.h" -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "base/test/metrics/histogram_tester.h" #include "build/build_config.h" #include "chrome/browser/safe_browsing/chrome_password_protection_service.h" @@ -945,7 +945,7 @@ public: explicit ViewFocusTracker(views::View* view) : FocusTracker(view->HasFocus()) { - scoped_observer_.Add(view); + scoped_observation_.Observe(view); } void OnViewFocused(views::View* observed_view) override { OnFocused(); } @@ -953,7 +953,8 @@ void OnViewBlurred(views::View* observed_view) override { OnBlurred(); } private: - ScopedObserver<views::View, views::ViewObserver> scoped_observer_{this}; + base::ScopedObservation<views::View, views::ViewObserver> scoped_observation_{ + this}; }; } // namespace
diff --git a/chrome/browser/ui/views/passwords/password_auto_sign_in_view.h b/chrome/browser/ui/views/passwords/password_auto_sign_in_view.h index e72a1252..30064717 100644 --- a/chrome/browser/ui/views/passwords/password_auto_sign_in_view.h +++ b/chrome/browser/ui/views/passwords/password_auto_sign_in_view.h
@@ -5,7 +5,6 @@ #ifndef CHROME_BROWSER_UI_VIEWS_PASSWORDS_PASSWORD_AUTO_SIGN_IN_VIEW_H_ #define CHROME_BROWSER_UI_VIEWS_PASSWORDS_PASSWORD_AUTO_SIGN_IN_VIEW_H_ -#include "base/scoped_observer.h" #include "base/timer/timer.h" #include "chrome/browser/ui/passwords/bubble_controllers/auto_sign_in_bubble_controller.h" #include "chrome/browser/ui/views/passwords/password_bubble_view_base.h"
diff --git a/chrome/browser/ui/views/passwords/password_save_update_with_account_store_view.cc b/chrome/browser/ui/views/passwords/password_save_update_with_account_store_view.cc index dc47da1..c0a07a4 100644 --- a/chrome/browser/ui/views/passwords/password_save_update_with_account_store_view.cc +++ b/chrome/browser/ui/views/passwords/password_save_update_with_account_store_view.cc
@@ -464,12 +464,13 @@ // The |username_dropdown_| should observe the animating layout manager to // close the dropdown menu when the animation starts. - observed_animating_layout_for_username_dropdown_ = std::make_unique< - ScopedObserver<views::AnimatingLayoutManager, - views::AnimatingLayoutManager::Observer>>( + animating_layout_for_username_dropdown_observation_ = std::make_unique< + base::ScopedObservation<views::AnimatingLayoutManager, + views::AnimatingLayoutManager::Observer>>( username_dropdown_); - observed_animating_layout_for_username_dropdown_->Add(animating_layout); - observed_animating_layout_for_iph_.Add(animating_layout); + animating_layout_for_username_dropdown_observation_->Observe( + animating_layout); + animating_layout_for_iph_observation_.Observe(animating_layout); // The account picker is only visible in Save bubbble, not Update bubble. if (destination_dropdown_)
diff --git a/chrome/browser/ui/views/passwords/password_save_update_with_account_store_view.h b/chrome/browser/ui/views/passwords/password_save_update_with_account_store_view.h index 74437a7f..1d0bf82 100644 --- a/chrome/browser/ui/views/passwords/password_save_update_with_account_store_view.h +++ b/chrome/browser/ui/views/passwords/password_save_update_with_account_store_view.h
@@ -6,6 +6,7 @@ #define CHROME_BROWSER_UI_VIEWS_PASSWORDS_PASSWORD_SAVE_UPDATE_WITH_ACCOUNT_STORE_VIEW_H_ #include "base/optional.h" +#include "base/scoped_observation.h" #include "base/token.h" #include "chrome/browser/ui/passwords/bubble_controllers/save_update_with_account_store_bubble_controller.h" #include "chrome/browser/ui/views/passwords/password_bubble_view_base.h" @@ -124,15 +125,16 @@ // Used to add |username_dropdown_| as an observer to the // AnimatingLayoutManager. This is needed such that the |username_dropdown_| // keeps the dropdown menu closed while the layout is animating. - std::unique_ptr<ScopedObserver<views::AnimatingLayoutManager, - views::AnimatingLayoutManager::Observer>> - observed_animating_layout_for_username_dropdown_; + std::unique_ptr< + base::ScopedObservation<views::AnimatingLayoutManager, + views::AnimatingLayoutManager::Observer>> + animating_layout_for_username_dropdown_observation_; // Used to observe the bubble animation when transitions between Save/Update // states. If appropriate, IPH bubble is is shown st end of the animation. - ScopedObserver<views::AnimatingLayoutManager, - views::AnimatingLayoutManager::Observer> - observed_animating_layout_for_iph_{this}; + base::ScopedObservation<views::AnimatingLayoutManager, + views::AnimatingLayoutManager::Observer> + animating_layout_for_iph_observation_{this}; }; #endif // CHROME_BROWSER_UI_VIEWS_PASSWORDS_PASSWORD_SAVE_UPDATE_WITH_ACCOUNT_STORE_VIEW_H_
diff --git a/chrome/browser/ui/views/renderer_context_menu/render_view_context_menu_views.cc b/chrome/browser/ui/views/renderer_context_menu/render_view_context_menu_views.cc index 234cb7a..5f26798 100644 --- a/chrome/browser/ui/views/renderer_context_menu/render_view_context_menu_views.cc +++ b/chrome/browser/ui/views/renderer_context_menu/render_view_context_menu_views.cc
@@ -8,6 +8,7 @@ #include "base/command_line.h" #include "base/logging.h" +#include "base/scoped_observation.h" #include "base/strings/string16.h" #include "base/task/current_thread.h" #include "build/build_config.h" @@ -43,10 +44,10 @@ SubmenuViewObserver(RenderViewContextMenuViews* parent, views::SubmenuView* submenu_view) : parent_(parent), submenu_view_(submenu_view) { - observed_submenu_view_.Add(submenu_view); + submenu_view_observation_.Observe(submenu_view); auto* widget = submenu_view_->host(); if (widget) - observed_submenu_widget_.Add(widget); + submenu_widget_observation_.Observe(widget); } SubmenuViewObserver(const SubmenuViewObserver&) = delete; @@ -72,7 +73,7 @@ DCHECK_EQ(submenu_view_, observed_view); auto* widget = submenu_view_->host(); if (widget) - observed_submenu_widget_.Add(widget); + submenu_widget_observation_.Observe(widget); } // WidgetObserver: @@ -92,9 +93,10 @@ private: RenderViewContextMenuViews* const parent_; views::SubmenuView* const submenu_view_; - ScopedObserver<views::View, views::ViewObserver> observed_submenu_view_{this}; - ScopedObserver<views::Widget, views::WidgetObserver> observed_submenu_widget_{ - this}; + base::ScopedObservation<views::View, views::ViewObserver> + submenu_view_observation_{this}; + base::ScopedObservation<views::Widget, views::WidgetObserver> + submenu_widget_observation_{this}; }; ////////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/ui/views/screen_capture_notification_ui_views.cc b/chrome/browser/ui/views/screen_capture_notification_ui_views.cc index 0bb507da..e1d1f24 100644 --- a/chrome/browser/ui/views/screen_capture_notification_ui_views.cc +++ b/chrome/browser/ui/views/screen_capture_notification_ui_views.cc
@@ -5,7 +5,7 @@ #include "chrome/browser/ui/screen_capture_notification_ui.h" #include "base/macros.h" -#include "base/scoped_observer.h" +#include "base/scoped_multi_source_observation.h" #include "build/build_config.h" #include "chrome/browser/ui/views/chrome_views_export.h" #include "chrome/grit/generated_resources.h" @@ -102,7 +102,8 @@ base::OnceClosure stop_callback_; content::MediaStreamUI::SourceCallback source_callback_; - ScopedObserver<views::View, views::ViewObserver> bounds_observer_{this}; + base::ScopedMultiSourceObservation<views::View, views::ViewObserver> + bounds_observations_{this}; NotificationBarClientView* client_view_ = nullptr; views::ImageView* gripper_ = nullptr; views::Label* label_ = nullptr; @@ -157,9 +158,9 @@ // The client rect for NotificationBarClientView uses the bounds for the // following views. - bounds_observer_.Add(source_button_); - bounds_observer_.Add(stop_button_); - bounds_observer_.Add(hide_link_); + bounds_observations_.AddObservation(source_button_); + bounds_observations_.AddObservation(stop_button_); + bounds_observations_.AddObservation(hide_link_); } ScreenCaptureNotificationUIViews::~ScreenCaptureNotificationUIViews() {
diff --git a/chrome/browser/ui/views/tabs/new_tab_button.h b/chrome/browser/ui/views/tabs/new_tab_button.h index 0a9554f6..d041c36 100644 --- a/chrome/browser/ui/views/tabs/new_tab_button.h +++ b/chrome/browser/ui/views/tabs/new_tab_button.h
@@ -5,7 +5,7 @@ #ifndef CHROME_BROWSER_UI_VIEWS_TABS_NEW_TAB_BUTTON_H_ #define CHROME_BROWSER_UI_VIEWS_TABS_NEW_TAB_BUTTON_H_ -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/tabs/tab_strip.h" #include "ui/views/controls/button/image_button.h"
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc index 31de207..d593e00 100644 --- a/chrome/browser/ui/views/tabs/tab.cc +++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -17,7 +17,7 @@ #include "base/metrics/user_metrics.h" #include "base/numerics/ranges.h" #include "base/numerics/safe_conversions.h" -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "base/strings/utf_string_conversions.h" #include "base/time/time.h" #include "build/build_config.h" @@ -146,13 +146,13 @@ TabController* controller) : tab_(tab), close_button_(close_button), controller_(controller) { DCHECK(close_button_); - tab_close_button_observer_.Add(close_button_); + tab_close_button_observation_.Observe(close_button_); } TabCloseButtonObserver(const TabCloseButtonObserver&) = delete; TabCloseButtonObserver& operator=(const TabCloseButtonObserver&) = delete; ~TabCloseButtonObserver() override { - tab_close_button_observer_.Remove(close_button_); + tab_close_button_observation_.RemoveObservation(); } private: @@ -166,8 +166,8 @@ controller_->UpdateHoverCard(nullptr); } - ScopedObserver<views::View, views::ViewObserver> tab_close_button_observer_{ - this}; + base::ScopedObservation<views::View, views::ViewObserver> + tab_close_button_observation_{this}; Tab* tab_; views::View* close_button_;
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.cc b/chrome/browser/ui/views/tabs/tab_drag_controller.cc index 17baa7b..3355b104 100644 --- a/chrome/browser/ui/views/tabs/tab_drag_controller.cc +++ b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
@@ -412,7 +412,8 @@ if (g_tab_drag_controller == this) g_tab_drag_controller = nullptr; - widget_observer_.RemoveAll(); + if (widget_observation_.IsObserving()) + widget_observation_.RemoveObservation(); if (is_dragging_window()) GetAttachedBrowserWidget()->EndMoveLoop(); @@ -688,7 +689,8 @@ } void TabDragController::OnWidgetDestroyed(views::Widget* widget) { - widget_observer_.Remove(widget); + DCHECK(widget_observation_.IsObservingSource(widget)); + widget_observation_.RemoveObservation(); } void TabDragController::OnSourceTabStripEmpty() { @@ -880,8 +882,8 @@ // results in a move). That'll cause all sorts of problems. Reset the // observer so we don't get notified and process the event. #if defined(OS_CHROMEOS) - if (widget_observer_.IsObserving(move_loop_widget_)) - widget_observer_.Remove(move_loop_widget_); + if (widget_observation_.IsObservingSource(move_loop_widget_)) + widget_observation_.RemoveObservation(); move_loop_widget_ = nullptr; #endif // OS_CHROMEOS views::Widget* browser_widget = GetAttachedBrowserWidget(); @@ -1398,7 +1400,7 @@ move_loop_widget_ = GetAttachedBrowserWidget(); DCHECK(move_loop_widget_); - widget_observer_.Add(move_loop_widget_); + widget_observation_.Observe(move_loop_widget_); current_state_ = DragState::kDraggingWindow; base::WeakPtr<TabDragController> ref(weak_factory_.GetWeakPtr()); if (can_release_capture_) { @@ -1415,8 +1417,8 @@ : views::Widget::MoveLoopSource::kTouch; const views::Widget::MoveLoopEscapeBehavior escape_behavior = is_dragging_new_browser_ - ? views::Widget::MOVE_LOOP_ESCAPE_BEHAVIOR_HIDE - : views::Widget::MOVE_LOOP_ESCAPE_BEHAVIOR_DONT_HIDE; + ? views::Widget::MoveLoopEscapeBehavior::kHide + : views::Widget::MoveLoopEscapeBehavior::kDontHide; views::Widget::MoveLoopResult result = move_loop_widget_->RunMoveLoop( drag_offset, move_loop_source, escape_behavior); content::NotificationService::current()->Notify( @@ -1427,8 +1429,10 @@ if (!ref) return; - if (widget_observer_.IsObserving(move_loop_widget_)) - widget_observer_.Remove(move_loop_widget_); + if (move_loop_widget_ && + widget_observation_.IsObservingSource(move_loop_widget_)) { + widget_observation_.RemoveObservation(); + } move_loop_widget_ = nullptr; if (current_state_ == DragState::kDraggingWindow) {
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.h b/chrome/browser/ui/views/tabs/tab_drag_controller.h index 7af113f..bed51f2e 100644 --- a/chrome/browser/ui/views/tabs/tab_drag_controller.h +++ b/chrome/browser/ui/views/tabs/tab_drag_controller.h
@@ -11,7 +11,7 @@ #include <vector> #include "base/memory/weak_ptr.h" -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "base/timer/timer.h" #include "chrome/browser/ui/tabs/tab_strip_model_observer.h" #include "chrome/browser/ui/views/tabs/tab_drag_context.h" @@ -693,7 +693,8 @@ std::unique_ptr<WindowFinder> window_finder_; - ScopedObserver<views::Widget, views::WidgetObserver> widget_observer_{this}; + base::ScopedObservation<views::Widget, views::WidgetObserver> + widget_observation_{this}; base::WeakPtrFactory<TabDragController> weak_factory_{this}; };
diff --git a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc index 4c0bcc66..cba52641 100644 --- a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc +++ b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc
@@ -410,11 +410,12 @@ if (current_image_ == thumbnail_image) return; - scoped_observer_.RemoveAll(); + if (scoped_observation_.IsObserving()) + scoped_observation_.RemoveObservation(); current_image_ = std::move(thumbnail_image); if (current_image_) { - scoped_observer_.Add(current_image_.get()); + scoped_observation_.Observe(current_image_.get()); current_image_->RequestThumbnailImage(); } } @@ -434,8 +435,8 @@ scoped_refptr<ThumbnailImage> current_image_; TabHoverCardBubbleView* const hover_card_; - ScopedObserver<ThumbnailImage, ThumbnailImage::Observer> scoped_observer_{ - this}; + base::ScopedObservation<ThumbnailImage, ThumbnailImage::Observer> + scoped_observation_{this}; }; TabHoverCardBubbleView::TabHoverCardBubbleView(Tab* tab) @@ -547,7 +548,7 @@ std::make_unique<WidgetSlideAnimationDelegate>(this); fade_animation_delegate_ = std::make_unique<WidgetFadeAnimationDelegate>(GetWidget()); - thumbnail_observer_ = std::make_unique<ThumbnailObserver>(this); + thumbnail_observation_ = std::make_unique<ThumbnailObserver>(this); constexpr int kFootnoteVerticalMargin = 8; GetBubbleFrameView()->set_footnote_margins( @@ -648,7 +649,7 @@ delayed_show_timer_.Stop(); if (!GetWidget()->IsVisible()) return; - thumbnail_observer_->Observe(nullptr); + thumbnail_observation_->Observe(nullptr); slide_animation_delegate_->StopAnimation(); last_visible_timestamp_ = base::TimeTicks::Now(); if (disable_animations_for_testing_) { @@ -804,12 +805,12 @@ auto thumbnail = tab->data().thumbnail; if (!thumbnail) { ClearPreviewImage(); - } else if (thumbnail != thumbnail_observer_->current_image()) { + } else if (thumbnail != thumbnail_observation_->current_image()) { waiting_for_decompress_ = true; - thumbnail_observer_->Observe(thumbnail); + thumbnail_observation_->Observe(thumbnail); } } else { - thumbnail_observer_->Observe(nullptr); + thumbnail_observation_->Observe(nullptr); } } }
diff --git a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.h b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.h index fa08a2b..cf92c20 100644 --- a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.h +++ b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.h
@@ -7,7 +7,7 @@ #include <memory> -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "base/time/time.h" #include "base/timer/timer.h" #include "chrome/browser/ui/tabs/tab_utils.h" @@ -99,7 +99,7 @@ std::unique_ptr<WidgetFadeAnimationDelegate> fade_animation_delegate_; // Used to animate the tab hover card's movement between tabs. std::unique_ptr<WidgetSlideAnimationDelegate> slide_animation_delegate_; - std::unique_ptr<ThumbnailObserver> thumbnail_observer_; + std::unique_ptr<ThumbnailObserver> thumbnail_observation_; // Timestamp of the last time a hover card was visible, recorded before it is // hidden. This is used for metrics.
diff --git a/chrome/browser/ui/views/tabs/tab_search_button.cc b/chrome/browser/ui/views/tabs/tab_search_button.cc index ac49af0b..be6ee8f 100644 --- a/chrome/browser/ui/views/tabs/tab_search_button.cc +++ b/chrome/browser/ui/views/tabs/tab_search_button.cc
@@ -96,7 +96,9 @@ void TabSearchButton::OnWidgetDestroying(views::Widget* widget) { DCHECK_EQ(webui_bubble_manager_.GetBubbleWidget(), widget); - observed_bubble_widget_.Remove(webui_bubble_manager_.GetBubbleWidget()); + DCHECK(bubble_widget_observation_.IsObservingSource( + webui_bubble_manager_.GetBubbleWidget())); + bubble_widget_observation_.RemoveObservation(); pressed_lock_.reset(); } @@ -114,8 +116,8 @@ // There should only ever be a single bubble widget active for the // TabSearchButton. - DCHECK(!observed_bubble_widget_.IsObservingSources()); - observed_bubble_widget_.Add(webui_bubble_manager_.GetBubbleWidget()); + DCHECK(!bubble_widget_observation_.IsObserving()); + bubble_widget_observation_.Observe(webui_bubble_manager_.GetBubbleWidget()); widget_open_timer_.Reset(webui_bubble_manager_.GetBubbleWidget()); // Hold the pressed lock while the |bubble_| is active.
diff --git a/chrome/browser/ui/views/tabs/tab_search_button.h b/chrome/browser/ui/views/tabs/tab_search_button.h index 34079db..6942475 100644 --- a/chrome/browser/ui/views/tabs/tab_search_button.h +++ b/chrome/browser/ui/views/tabs/tab_search_button.h
@@ -80,8 +80,8 @@ // in the process of being shown. std::unique_ptr<views::MenuButtonController::PressedLock> pressed_lock_; - ScopedObserver<views::Widget, views::WidgetObserver> observed_bubble_widget_{ - this}; + base::ScopedObservation<views::Widget, views::WidgetObserver> + bubble_widget_observation_{this}; }; #endif // CHROME_BROWSER_UI_VIEWS_TABS_TAB_SEARCH_BUTTON_H_
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc index 15c42f1c..caf4768 100644 --- a/chrome/browser/ui/views/tabs/tab_strip.cc +++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -1029,7 +1029,8 @@ // but before moving the mouse. RemoveMessageLoopObserver(); - hover_card_observer_.RemoveAll(); + if (hover_card_observation_.IsObserving()) + hover_card_observation_.RemoveObservation(); // Since TabGroupViews expects be able to remove the views it creates, clear // |group_views_| before removing the remaining children below. @@ -1937,7 +1938,7 @@ if (!tab) return; hover_card_ = new TabHoverCardBubbleView(tab); - hover_card_observer_.Add(hover_card_); + hover_card_observation_.Observe(hover_card_); if (GetWidget()) { hover_card_event_sniffer_ = std::make_unique<TabHoverCardEventSniffer>(hover_card_, this); @@ -3257,7 +3258,7 @@ arrow_view_ = arrow_window_->SetContentsView(std::make_unique<views::ImageView>()); arrow_view_->SetImage(GetDropArrowImage(point_down_)); - scoped_observer_.Add(arrow_window_); + scoped_observation_.Observe(arrow_window_); arrow_window_->Show(); } @@ -3281,7 +3282,8 @@ } void TabStrip::DropArrow::OnWidgetDestroying(views::Widget* widget) { - scoped_observer_.Remove(arrow_window_); + DCHECK(scoped_observation_.IsObservingSource(arrow_window_)); + scoped_observation_.RemoveObservation(); arrow_window_ = nullptr; } @@ -3621,7 +3623,8 @@ void TabStrip::OnViewIsDeleting(views::View* observed_view) { if (observed_view == hover_card_) { - hover_card_observer_.Remove(hover_card_); + DCHECK(hover_card_observation_.IsObservingSource(hover_card_)); + hover_card_observation_.RemoveObservation(); hover_card_event_sniffer_.reset(); hover_card_ = nullptr; }
diff --git a/chrome/browser/ui/views/tabs/tab_strip.h b/chrome/browser/ui/views/tabs/tab_strip.h index f58a92b3..fefa4089 100644 --- a/chrome/browser/ui/views/tabs/tab_strip.h +++ b/chrome/browser/ui/views/tabs/tab_strip.h
@@ -15,7 +15,7 @@ #include "base/memory/ref_counted.h" #include "base/observer_list.h" #include "base/optional.h" -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "base/timer/timer.h" #include "build/build_config.h" #include "chrome/browser/ui/tabs/tab_types.h" @@ -410,7 +410,8 @@ views::ImageView* arrow_view_ = nullptr; - ScopedObserver<views::Widget, views::WidgetObserver> scoped_observer_{this}; + base::ScopedObservation<views::Widget, views::WidgetObserver> + scoped_observation_{this}; }; void Init(); @@ -665,7 +666,8 @@ // The view tracker is used to keep track of if the hover card has been // destroyed by its widget. TabHoverCardBubbleView* hover_card_ = nullptr; - ScopedObserver<views::View, views::ViewObserver> hover_card_observer_{this}; + base::ScopedObservation<views::View, views::ViewObserver> + hover_card_observation_{this}; std::unique_ptr<ui::EventHandler> hover_card_event_sniffer_; std::unique_ptr<TabStripController> controller_;
diff --git a/chrome/browser/ui/views/toolbar/app_menu.cc b/chrome/browser/ui/views/toolbar/app_menu.cc index 44301f3..7e2f8324 100644 --- a/chrome/browser/ui/views/toolbar/app_menu.cc +++ b/chrome/browser/ui/views/toolbar/app_menu.cc
@@ -315,8 +315,7 @@ DCHECK(menu_); InMenuButton* button = new InMenuButton( std::move(callback), - gfx::RemoveAcceleratorChar(l10n_util::GetStringUTF16(string_id), '&', - nullptr, nullptr)); + gfx::RemoveAccelerator(l10n_util::GetStringUTF16(string_id))); button->Init(type); button->SetAccessibleName(GetAccessibleNameForAppMenuItem( menu_model_, index, acc_string_id, add_accelerator_text)); @@ -719,7 +718,7 @@ : browser_(browser), run_types_(run_types), alert_reopen_tab_items_(alert_reopen_tab_items) { - global_error_observer_.Add( + global_error_observation_.Observe( GlobalErrorServiceFactory::GetForProfile(browser->profile())); }
diff --git a/chrome/browser/ui/views/toolbar/app_menu.h b/chrome/browser/ui/views/toolbar/app_menu.h index 59fea848..7cebd77 100644 --- a/chrome/browser/ui/views/toolbar/app_menu.h +++ b/chrome/browser/ui/views/toolbar/app_menu.h
@@ -10,7 +10,7 @@ #include <utility> #include "base/memory/weak_ptr.h" -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "base/time/time.h" #include "base/timer/elapsed_timer.h" #include "chrome/browser/ui/global_error/global_error_observer.h" @@ -182,8 +182,8 @@ // Used for managing "Recent tabs" menu items. std::unique_ptr<RecentTabsMenuModelDelegate> recent_tabs_menu_model_delegate_; - ScopedObserver<GlobalErrorService, GlobalErrorObserver> - global_error_observer_{this}; + base::ScopedObservation<GlobalErrorService, GlobalErrorObserver> + global_error_observation_{this}; // The bit mask of views::MenuRunner::RunTypes. const int run_types_;
diff --git a/chrome/browser/ui/views/toolbar/browser_app_menu_button.h b/chrome/browser/ui/views/toolbar/browser_app_menu_button.h index c9ee5444..c7b78327 100644 --- a/chrome/browser/ui/views/toolbar/browser_app_menu_button.h +++ b/chrome/browser/ui/views/toolbar/browser_app_menu_button.h
@@ -10,7 +10,7 @@ #include "base/memory/weak_ptr.h" #include "base/optional.h" -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "chrome/browser/ui/toolbar/app_menu_icon_controller.h" #include "chrome/browser/ui/user_education/feature_promo_controller.h" #include "chrome/browser/ui/views/frame/app_menu_button.h"
diff --git a/chrome/browser/ui/views/toolbar/extension_toolbar_menu_view.cc b/chrome/browser/ui/views/toolbar/extension_toolbar_menu_view.cc index f48295a6..c633c0e6 100644 --- a/chrome/browser/ui/views/toolbar/extension_toolbar_menu_view.cc +++ b/chrome/browser/ui/views/toolbar/extension_toolbar_menu_view.cc
@@ -46,10 +46,10 @@ container_ = SetContents(std::move(container)); // Listen for the drop to finish so we can close the app menu, if necessary. - toolbar_actions_bar_observer_.Add(main->toolbar_actions_bar()); + toolbar_actions_bar_observation_.Observe(main->toolbar_actions_bar()); // Observe app menu so we know when RunMenu() is called. - app_menu_button_observer_.Add(app_menu_button); + app_menu_button_observation_.Observe(app_menu_button); // In *very* extreme cases, it's possible that there are so many overflowed // actions, we won't be able to show them all. Cap the height so that the @@ -83,7 +83,8 @@ } void ExtensionToolbarMenuView::OnToolbarActionsBarDestroyed() { - toolbar_actions_bar_observer_.RemoveAll(); + DCHECK(toolbar_actions_bar_observation_.IsObserving()); + toolbar_actions_bar_observation_.RemoveObservation(); } void ExtensionToolbarMenuView::OnToolbarActionDragDone() {
diff --git a/chrome/browser/ui/views/toolbar/extension_toolbar_menu_view.h b/chrome/browser/ui/views/toolbar/extension_toolbar_menu_view.h index 31f8626..201d00e 100644 --- a/chrome/browser/ui/views/toolbar/extension_toolbar_menu_view.h +++ b/chrome/browser/ui/views/toolbar/extension_toolbar_menu_view.h
@@ -6,7 +6,7 @@ #define CHROME_BROWSER_UI_VIEWS_TOOLBAR_EXTENSION_TOOLBAR_MENU_VIEW_H_ #include "base/memory/weak_ptr.h" -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "chrome/browser/ui/toolbar/toolbar_actions_bar.h" #include "chrome/browser/ui/toolbar/toolbar_actions_bar_observer.h" #include "chrome/browser/ui/views/frame/app_menu_button.h" @@ -81,10 +81,10 @@ // The maximum allowed height for the view. int max_height_ = 0; - ScopedObserver<ToolbarActionsBar, ToolbarActionsBarObserver> - toolbar_actions_bar_observer_{this}; - ScopedObserver<AppMenuButton, AppMenuButtonObserver> - app_menu_button_observer_{this}; + base::ScopedObservation<ToolbarActionsBar, ToolbarActionsBarObserver> + toolbar_actions_bar_observation_{this}; + base::ScopedObservation<AppMenuButton, AppMenuButtonObserver> + app_menu_button_observation_{this}; base::WeakPtrFactory<ExtensionToolbarMenuView> weak_factory_{this}; };
diff --git a/chrome/browser/ui/views/toolbar/toolbar_action_view_interactive_uitest.cc b/chrome/browser/ui/views/toolbar/toolbar_action_view_interactive_uitest.cc index 3e63e222..de1e3da 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_action_view_interactive_uitest.cc +++ b/chrome/browser/ui/views/toolbar/toolbar_action_view_interactive_uitest.cc
@@ -58,14 +58,15 @@ private: bool observed_ = false; base::RunLoop run_loop_; - ScopedObserver<AppMenuButton, AppMenuButtonObserver> observer_{this}; + base::ScopedObservation<AppMenuButton, AppMenuButtonObserver> observation_{ + this}; }; AppMenuShowingWaiter::AppMenuShowingWaiter(AppMenuButton* button) { DCHECK(button); if (button->IsMenuShowing()) observed_ = true; - observer_.Add(button); + observation_.Observe(button); } void AppMenuShowingWaiter::AppMenuShown() {
diff --git a/chrome/browser/ui/views/toolbar/toolbar_icon_container_view.cc b/chrome/browser/ui/views/toolbar/toolbar_icon_container_view.cc index 3350faa..2e36d1b 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_icon_container_view.cc +++ b/chrome/browser/ui/views/toolbar/toolbar_icon_container_view.cc
@@ -6,6 +6,7 @@ #include <memory> +#include "base/scoped_observation.h" #include "base/stl_util.h" #include "chrome/browser/themes/theme_properties.h" #include "chrome/browser/ui/layout_constants.h" @@ -48,7 +49,7 @@ explicit WidgetRestoreObserver( ToolbarIconContainerView* toolbar_icon_container_view) : toolbar_icon_container_view_(toolbar_icon_container_view) { - scoped_observer_.Add( + scoped_observation_.Observe( toolbar_icon_container_view->GetWidget()->GetRootView()); } @@ -64,7 +65,8 @@ private: bool was_collapsed_ = true; ToolbarIconContainerView* const toolbar_icon_container_view_; - ScopedObserver<views::View, views::ViewObserver> scoped_observer_{this}; + base::ScopedObservation<views::View, views::ViewObserver> scoped_observation_{ + this}; }; ToolbarIconContainerView::ToolbarIconContainerView(bool uses_highlight)
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.h b/chrome/browser/ui/views/toolbar/toolbar_view.h index 1fd8c2ce..78c615c 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_view.h +++ b/chrome/browser/ui/views/toolbar/toolbar_view.h
@@ -11,7 +11,7 @@ #include "base/macros.h" #include "base/observer_list.h" #include "base/optional.h" -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "chrome/browser/command_observer.h" #include "chrome/browser/ui/page_action/page_action_icon_type.h" #include "chrome/browser/ui/toolbar/app_menu_icon_controller.h"
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view_interactive_uitest.cc b/chrome/browser/ui/views/toolbar/toolbar_view_interactive_uitest.cc index 03b43e1..48535ca 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_view_interactive_uitest.cc +++ b/chrome/browser/ui/views/toolbar/toolbar_view_interactive_uitest.cc
@@ -168,11 +168,13 @@ // Set up observers that will drive the test along. AppMenuButton* const app_menu_button = GetAppMenuButton(); EXPECT_FALSE(app_menu_button->IsMenuShowing()); - ScopedObserver<views::Widget, views::WidgetObserver> widget_observer(this); - widget_observer.Add( + base::ScopedObservation<views::Widget, views::WidgetObserver> + widget_observation(this); + widget_observation.Observe( BrowserView::GetBrowserViewForBrowser(browser())->GetWidget()); - ScopedObserver<AppMenuButton, AppMenuButtonObserver> button_observer(this); - button_observer.Add(app_menu_button); + base::ScopedObservation<AppMenuButton, AppMenuButtonObserver> + button_observation(this); + button_observation.Observe(app_menu_button); // Set up the task runner to use for posting drag actions. // TODO(devlin): This is basically ViewEventTestBase::GetDragTaskRunner(). In
diff --git a/chrome/browser/ui/views/toolbar/webui_tab_counter_button.cc b/chrome/browser/ui/views/toolbar/webui_tab_counter_button.cc index 858f42450..ef598ba 100644 --- a/chrome/browser/ui/views/toolbar/webui_tab_counter_button.cc +++ b/chrome/browser/ui/views/toolbar/webui_tab_counter_button.cc
@@ -125,7 +125,7 @@ : native_window_(widget->GetNativeWindow()) { if (native_window_) native_window_->AddPreTargetHandler(this); - scoped_widget_observer_.Add(widget); + scoped_widget_observation_.Observe(widget); } InteractionTracker(const InteractionTracker& other) = delete; @@ -160,7 +160,8 @@ void OnWidgetDestroying(views::Widget* widget) override { // Clean up all of our observers and event handlers before the native window // disappears. - scoped_widget_observer_.Remove(widget); + DCHECK(scoped_widget_observation_.IsObservingSource(widget)); + scoped_widget_observation_.RemoveObservation(); if (widget->GetNativeWindow()) { widget->GetNativeWindow()->RemovePreTargetHandler(this); native_window_ = nullptr; @@ -169,8 +170,8 @@ base::Optional<gfx::Point> last_interaction_location_; gfx::NativeWindow native_window_; - ScopedObserver<views::Widget, views::WidgetObserver> scoped_widget_observer_{ - this}; + base::ScopedObservation<views::Widget, views::WidgetObserver> + scoped_widget_observation_{this}; }; //------------------------------------------------------------------------
diff --git a/chrome/build/OWNERS b/chrome/build/OWNERS index 15b2025e..56289de 100644 --- a/chrome/build/OWNERS +++ b/chrome/build/OWNERS
@@ -1,5 +1,2 @@ -hans@chromium.org -thakis@chromium.org - -per-file *.pgo.txt=liaoyuke@chromium.org -per-file *.pgo.txt=sebmarchand@chromium.org +liaoyuke@chromium.org +sebmarchand@chromium.org
diff --git a/chrome/build/README b/chrome/build/README deleted file mode 100644 index 999e1de..0000000 --- a/chrome/build/README +++ /dev/null
@@ -1,3 +0,0 @@ -See -https://chromium.googlesource.com/chromium/src/+/master/docs/win_order_files.md -for how to update the order files.
diff --git a/chrome/build/chrome.x64.orderfile.sha1 b/chrome/build/chrome.x64.orderfile.sha1 deleted file mode 100644 index 0ba7024..0000000 --- a/chrome/build/chrome.x64.orderfile.sha1 +++ /dev/null
@@ -1 +0,0 @@ -d5482a02f41670416a7302b49e5e3f9dede25e61 \ No newline at end of file
diff --git a/chrome/build/chrome.x86.orderfile.sha1 b/chrome/build/chrome.x86.orderfile.sha1 deleted file mode 100644 index 39e3a12..0000000 --- a/chrome/build/chrome.x86.orderfile.sha1 +++ /dev/null
@@ -1 +0,0 @@ -d00f8f154ccdf38ef8a3018ea5bb165e8b279c22 \ No newline at end of file
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt index b80daae1b..bd46895 100644 --- a/chrome/build/linux.pgo.txt +++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@ -chrome-linux-master-1605765502-afac6c1491dbda42eb7f9fa994b3ce280c680afd.profdata +chrome-linux-master-1605786790-1f9152a71727d792e23874dce2b7f267f3ebd366.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index 24da8365..2659110 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-master-1605765502-3ccba7e07e5cf94b5756f4641a727d60a578a62b.profdata +chrome-win64-master-1605776317-40958ff5156f07254d2cc2984d12fc2fc0f55b26.profdata
diff --git a/chrome/credential_provider/DEPS b/chrome/credential_provider/DEPS index 704784b..2d05e6b 100644 --- a/chrome/credential_provider/DEPS +++ b/chrome/credential_provider/DEPS
@@ -6,6 +6,7 @@ "+components/crash", "+components/policy/proto", "+google_apis", + "+net", "+third_party/boringssl/src/include", "+third_party/re2", ]
diff --git a/chrome/credential_provider/extension/BUILD.gn b/chrome/credential_provider/extension/BUILD.gn index 60bb635..ef7e63a 100644 --- a/chrome/credential_provider/extension/BUILD.gn +++ b/chrome/credential_provider/extension/BUILD.gn
@@ -59,6 +59,7 @@ ":common", "../gaiacp:util", "//base:base", + "//net:net", ] configs += [ "//build/config/win:windowed" ] }
diff --git a/chrome/credential_provider/extension/extension_main.cc b/chrome/credential_provider/extension/extension_main.cc index 3858456..af11aeb 100644 --- a/chrome/credential_provider/extension/extension_main.cc +++ b/chrome/credential_provider/extension/extension_main.cc
@@ -14,6 +14,8 @@ #include "chrome/credential_provider/extension/os_service_manager.h" #include "chrome/credential_provider/extension/service.h" #include "chrome/credential_provider/extension/task_manager.h" +#include "chrome/credential_provider/gaiacp/experiments_fetcher.h" +#include "chrome/credential_provider/gaiacp/experiments_manager.h" #include "chrome/credential_provider/gaiacp/gem_device_details_manager.h" #include "chrome/credential_provider/gaiacp/logging.h" #include "chrome/credential_provider/gaiacp/reg_utils.h" @@ -38,6 +40,13 @@ "UploadDeviceDetails", credential_provider::GemDeviceDetailsManager:: UploadDeviceDetailsTaskCreator()); } + + // Task to fetch experiments for all GCPW users. + if (credential_provider::ExperimentsManager::Get()->ExperimentsEnabled()) { + credential_provider::extension::TaskManager::Get()->RegisterTask( + "FetchExperiments", credential_provider::ExperimentsFetcher:: + GetFetchExperimentsTaskCreator()); + } } int APIENTRY wWinMain(HINSTANCE hInstance,
diff --git a/chrome/credential_provider/extension/extension_strings.cc b/chrome/credential_provider/extension/extension_strings.cc index 2ed214a3..cc4472a 100644 --- a/chrome/credential_provider/extension/extension_strings.cc +++ b/chrome/credential_provider/extension/extension_strings.cc
@@ -13,7 +13,5 @@ const wchar_t kEnableGCPWExtension[] = L"enable_gcpw_extension"; -const wchar_t kLastPeriodicSyncTimeRegKey[] = L"extension_last_periodic_sync"; - } // namespace extension } // namespace credential_provider
diff --git a/chrome/credential_provider/extension/extension_strings.h b/chrome/credential_provider/extension/extension_strings.h index 597f0f9..75e3b2f 100644 --- a/chrome/credential_provider/extension/extension_strings.h +++ b/chrome/credential_provider/extension/extension_strings.h
@@ -17,9 +17,6 @@ // Registry which controls whether to install GCPW Extension. extern const wchar_t kEnableGCPWExtension[]; -// Registry which keeps track of last time periodic sync was performed. -extern const wchar_t kLastPeriodicSyncTimeRegKey[]; - } // namespace extension } // namespace credential_provider
diff --git a/chrome/credential_provider/extension/extension_utils.cc b/chrome/credential_provider/extension/extension_utils.cc index 06033fc..50d15ae 100644 --- a/chrome/credential_provider/extension/extension_utils.cc +++ b/chrome/credential_provider/extension/extension_utils.cc
@@ -4,6 +4,7 @@ #include "chrome/credential_provider/extension/extension_utils.h" +#include "base/strings/string_util.h" #include "chrome/credential_provider/extension/extension_strings.h" #include "chrome/credential_provider/extension/os_service_manager.h" #include "chrome/credential_provider/extension/scoped_handle.h" @@ -147,5 +148,9 @@ return GetGlobalFlagOrDefault(extension::kEnableGCPWExtension, 1); } +base::string16 GetLastSyncRegNameForTask(const base::string16& task_name) { + return base::ToLowerASCII(task_name) + L"_last_sync_time"; +} + } // namespace extension } // namespace credential_provider
diff --git a/chrome/credential_provider/extension/extension_utils.h b/chrome/credential_provider/extension/extension_utils.h index 4d951b6..3889865 100644 --- a/chrome/credential_provider/extension/extension_utils.h +++ b/chrome/credential_provider/extension/extension_utils.h
@@ -31,6 +31,10 @@ // Returns true if installation of GCPW extension is enabled. bool IsGCPWExtensionEnabled(); +// Returns the registry name from the provided |task_name| which is provided +// when registering the task with GCPW extension. +base::string16 GetLastSyncRegNameForTask(const base::string16& task_name); + } // namespace extension } // namespace credential_provider
diff --git a/chrome/credential_provider/extension/service.cc b/chrome/credential_provider/extension/service.cc index bce545ff..d053cf4 100644 --- a/chrome/credential_provider/extension/service.cc +++ b/chrome/credential_provider/extension/service.cc
@@ -4,7 +4,6 @@ #include "chrome/credential_provider/extension/service.h" -#include "base/logging.h" #include "base/run_loop.h" #include "base/task/single_thread_task_executor.h" #include "chrome/credential_provider/extension/os_service_manager.h" @@ -89,8 +88,6 @@ run_loop.Run(); - TaskManager::Get()->Quit(); - service_status_.dwCurrentState = SERVICE_STOPPED; service_status_.dwControlsAccepted = 0;
diff --git a/chrome/credential_provider/extension/task.h b/chrome/credential_provider/extension/task.h index 014173f..05dc22f 100644 --- a/chrome/credential_provider/extension/task.h +++ b/chrome/credential_provider/extension/task.h
@@ -5,12 +5,24 @@ #ifndef CHROME_CREDENTIAL_PROVIDER_EXTENSION_TASK_H_ #define CHROME_CREDENTIAL_PROVIDER_EXTENSION_TASK_H_ +#include "base/time/time.h" #include "base/win/windows_types.h" #include "chrome/credential_provider/extension/user_device_context.h" namespace credential_provider { namespace extension { +// Configuration the task needs to run on. A way to tell task manager on how +// to run the task. +struct Config { + // Set a default execution period in case it isn't defined by individual + // tasks. + Config() : execution_period(base::TimeDelta::FromHours(1)) {} + + // The period that the task will be executed on. + base::TimeDelta execution_period; +}; + // An interface that can be implemented by individual GCPW tasks to be executed // during periodic polling by GCPW extension service. Methods are called in the // order they are defined. So, initially task runner gets the configuration of @@ -33,6 +45,7 @@ // ESA calls execute function to perform the actual task. virtual HRESULT Execute() = 0; }; + } // namespace extension } // namespace credential_provider
diff --git a/chrome/credential_provider/extension/task_manager.cc b/chrome/credential_provider/extension/task_manager.cc index a50dbc35..66ebfb4 100644 --- a/chrome/credential_provider/extension/task_manager.cc +++ b/chrome/credential_provider/extension/task_manager.cc
@@ -4,13 +4,11 @@ #include "chrome/credential_provider/extension/task_manager.h" -#include <memory> +#include <windows.h> -#include "base/logging.h" #include "base/strings/string_number_conversions.h" -#include "base/timer/timer.h" -#include "chrome/credential_provider/extension/extension_strings.h" -#include "chrome/credential_provider/extension/task.h" +#include "base/strings/utf_string_conversions.h" +#include "chrome/credential_provider/extension/extension_utils.h" #include "chrome/credential_provider/extension/user_context_enumerator.h" #include "chrome/credential_provider/gaiacp/logging.h" #include "chrome/credential_provider/gaiacp/reg_utils.h" @@ -19,24 +17,57 @@ namespace extension { namespace { -// Specifies the period of executing tasks. -constexpr auto kPollingInterval = base::TimeDelta::FromHours(1); + +// Backoff policy for errors returned by performing task operation. +const net::BackoffEntry::Policy kRetryLaterPolicy = { + // Number of initial errors to ignore before starting to back off. + 0, + + // Initial delay in ms: 1 minute. + 1000 * 60, + + // Factor by which the waiting time is multiplied. + 2, + + // Fuzzing percentage; this spreads delays randomly between 80% and 100% + // of the calculated time. + 0.20, + + // Maximum delay in ms: 3 hours. However this field of back off policy is + // overridden by individual task's execution period when actually backing + // off. + 1000 * 60 * 60 * 3, + + // When to discard an entry: never. + -1, + + // |always_use_initial_delay|; false means that the initial delay is + // applied after the first error, and starts backing off from there. + true, +}; + +// Returns the elapsed time delta since the last time the periodic sync were +// successfully performed for the given task registry. +base::TimeDelta GetTimeDeltaSinceLastPeriodicSync( + const base::string16& task_reg_name) { + wchar_t last_sync_millis[512]; + ULONG last_sync_size = base::size(last_sync_millis); + HRESULT hr = GetGlobalFlag(task_reg_name, last_sync_millis, &last_sync_size); + + if (FAILED(hr)) { + // The periodic sync has never happened before. + return base::TimeDelta::Max(); + } + + int64_t last_sync_millis_int64; + base::StringToInt64(last_sync_millis, &last_sync_millis_int64); + const auto last_sync = base::Time::FromDeltaSinceWindowsEpoch( + base::TimeDelta::FromMilliseconds(last_sync_millis_int64)); + return base::Time::Now() - last_sync; +} + } // namespace -LastPeriodicSyncUpdater::LastPeriodicSyncUpdater() {} - -LastPeriodicSyncUpdater::~LastPeriodicSyncUpdater() { - UpdateLastRunTimestamp(); -} - -void LastPeriodicSyncUpdater::UpdateLastRunTimestamp() { - const base::Time sync_time = base::Time::Now(); - const base::string16 sync_time_millis = base::NumberToString16( - sync_time.ToDeltaSinceWindowsEpoch().InMilliseconds()); - - SetGlobalFlag(kLastPeriodicSyncTimeRegKey, sync_time_millis); -} - // static TaskManager** TaskManager::GetInstanceStorage() { static TaskManager* instance = new TaskManager(); @@ -50,74 +81,108 @@ } TaskManager::TaskManager() {} + TaskManager::~TaskManager() {} -void TaskManager::ScheduleTasks() { - timer_.Start(FROM_HERE, kPollingInterval, this, - &TaskManager::RunTasksInternal); +void TaskManager::ExecuteTask( + scoped_refptr<base::SingleThreadTaskRunner> task_runner, + const std::string& task_name) { + LOGFN(VERBOSE); + + // Get an instance of the task and execute it. + std::unique_ptr<Task> task((task_list_[task_name]).Run()); + if (task == nullptr) { + LOGFN(ERROR) << task_name << " task is null"; + return; + } + + HRESULT hr = + UserContextEnumerator::Get()->PerformTask(task_name, *task.get()); + + // Calculate next time the task should be executed. + base::TimeDelta next_run; + + if (FAILED(hr)) { + LOGFN(ERROR) << task_name << " failed hr=" << putHR(hr); + + // Check whether a backoff entry exists for the task. If so, consider the + // backoff period when calculating next run. + if (task_execution_backoffs_.find(task_name) == + task_execution_backoffs_.end()) { + // First set the template backoff policy for the task. + task_execution_policies_[task_name] = + std::make_unique<net::BackoffEntry::Policy>(); + *task_execution_policies_[task_name] = kRetryLaterPolicy; + + // Max backoff time shouldn't be more than task execution period. + task_execution_policies_[task_name]->maximum_backoff_ms = + task->GetConfig().execution_period.InMilliseconds(); + + const net::BackoffEntry::Policy* policy = + task_execution_policies_.find(task_name)->second.get(); + + // Create backoff entry as this is the first failure after a success. + task_execution_backoffs_[task_name].reset(new net::BackoffEntry(policy)); + } + + task_execution_backoffs_[task_name]->InformOfRequest(false); + + // Get backoff time for the next request. + next_run = task_execution_backoffs_[task_name]->GetTimeUntilRelease(); + + } else { + // Clear the back off entry as the task succeeded. An alternative was to + // keep it and report success. + task_execution_backoffs_.erase(task_name); + next_run = task->GetConfig().execution_period; + + LOGFN(INFO) << task_name << " was executed successfully!"; + const base::Time sync_time = base::Time::Now(); + const base::string16 sync_time_millis = base::NumberToString16( + sync_time.ToDeltaSinceWindowsEpoch().InMilliseconds()); + + SetGlobalFlag(GetLastSyncRegNameForTask(base::UTF8ToUTF16(task_name)), + sync_time_millis); + } + + // Schedule next task execution. + task_runner->PostDelayedTask( + FROM_HERE, + base::BindOnce(&TaskManager::ExecuteTask, base::Unretained(this), + task_runner, task_name), + next_run); } -void TaskManager::RunTasksInternal() { - LOGFN(VERBOSE); - LastPeriodicSyncUpdater last_periodic_sync_updater; - +void TaskManager::RunTasks( + scoped_refptr<base::SingleThreadTaskRunner> task_runner) { + // Enumerate registered tasks and kick-off the periodic execution. for (auto it = task_list_.begin(); it != task_list_.end(); ++it) { - LOGFN(VERBOSE) << "Executing " << it->first; - + // Get an instance of registered Task. std::unique_ptr<Task> task((it->second).Run()); if (task == nullptr) { LOGFN(ERROR) << it->first << " task is null"; continue; } - UserContextEnumerator::Get()->PerformTask(it->first, *task.get()); + // Calculate the next run so that periodic polling happens within + // proper time intervals. When the tasks are scheduled, we don't want to + // immediately start executing to allow some warm-up. + base::TimeDelta next_run = base::TimeDelta::FromSeconds(10); + const base::TimeDelta time_since_last_run = + GetTimeDeltaSinceLastPeriodicSync( + GetLastSyncRegNameForTask(base::UTF8ToUTF16(it->first))); + + if (time_since_last_run < task->GetConfig().execution_period) + next_run = task->GetConfig().execution_period - time_since_last_run; + + task_runner->PostDelayedTask( + FROM_HERE, + base::BindOnce(&TaskManager::ExecuteTask, base::Unretained(this), + task_runner, it->first), + next_run); } } -void TaskManager::RunTasks( - scoped_refptr<base::SingleThreadTaskRunner> task_runner) { - LOGFN(VERBOSE); - - // Calculate the next run so that periodic polling happens within - // proper time intervals. When the tasks are scheduled, we don't want to - // immediately start executing periodic tasks to allow some warm-up. - base::TimeDelta next_run = base::TimeDelta::FromSeconds(10); - const base::TimeDelta time_since_last_run = - GetTimeDeltaSinceLastPeriodicSync(); - if (time_since_last_run < kPollingInterval) - next_run = kPollingInterval - time_since_last_run; - - // Post an individual task that runs after completing a polling period. - task_runner->PostDelayedTask( - FROM_HERE, - base::BindOnce(&TaskManager::RunTasksInternal, base::Unretained(this)), - next_run); - - // Schedule a repeating task to run after running the task above. - task_runner->PostDelayedTask( - FROM_HERE, - base::BindOnce(&TaskManager::ScheduleTasks, base::Unretained(this)), - next_run); -} - -base::TimeDelta TaskManager::GetTimeDeltaSinceLastPeriodicSync() { - wchar_t last_sync_millis[512]; - ULONG last_sync_size = base::size(last_sync_millis); - HRESULT hr = GetGlobalFlag(kLastPeriodicSyncTimeRegKey, last_sync_millis, - &last_sync_size); - - if (FAILED(hr)) { - // The periodic sync has never happened before. - return base::TimeDelta::Max(); - } - - int64_t last_sync_millis_int64; - base::StringToInt64(last_sync_millis, &last_sync_millis_int64); - const auto last_sync = base::Time::FromDeltaSinceWindowsEpoch( - base::TimeDelta::FromMilliseconds(last_sync_millis_int64)); - return base::Time::Now() - last_sync; -} - void TaskManager::RegisterTask(const std::string& task_name, TaskCreator task_creator) { LOGFN(VERBOSE); @@ -125,11 +190,5 @@ task_list_.emplace(task_name, std::move(task_creator)); } -void TaskManager::Quit() { - LOGFN(VERBOSE); - - timer_.AbandonAndStop(); -} - } // namespace extension } // namespace credential_provider
diff --git a/chrome/credential_provider/extension/task_manager.h b/chrome/credential_provider/extension/task_manager.h index 214e199c..3cf836d 100644 --- a/chrome/credential_provider/extension/task_manager.h +++ b/chrome/credential_provider/extension/task_manager.h
@@ -5,7 +5,6 @@ #ifndef CHROME_CREDENTIAL_PROVIDER_EXTENSION_TASK_MANAGER_H_ #define CHROME_CREDENTIAL_PROVIDER_EXTENSION_TASK_MANAGER_H_ -#include "chrome/credential_provider/extension/task.h" #include <map> #include <memory> @@ -13,37 +12,22 @@ #include "base/callback.h" #include "base/single_thread_task_runner.h" -#include "base/timer/timer.h" +#include "chrome/credential_provider/extension/task.h" +#include "net/base/backoff_entry.h" namespace credential_provider { namespace extension { using TaskCreator = base::RepeatingCallback<std::unique_ptr<Task>()>; -// Utility to make sure the registry is updated with the last periodic sync. -class LastPeriodicSyncUpdater { - public: - LastPeriodicSyncUpdater(); - virtual ~LastPeriodicSyncUpdater(); - - private: - // Update the registry with the last time the periodic tasks are executed. - virtual void UpdateLastRunTimestamp(); -}; - +// Manager for all the tasks that are supposed to be executed by GCPW +// extension. Tasks are registered and execution is triggered via TaskManager. class TaskManager { public: // Used to retrieve singleton instance of the TaskManager. static TaskManager* Get(); - TaskManager(); - - virtual ~TaskManager(); - - // Returns the storage used for the instance pointer. - static TaskManager** GetInstanceStorage(); - - // This function schedules periodic tasks using PostTask interface. It + // This function schedules periodic tasks using PostDelayedTask interface. It // schedules the tasks on the provided |task_runner|. virtual void RunTasks( scoped_refptr<base::SingleThreadTaskRunner> task_runner); @@ -53,27 +37,32 @@ virtual void RegisterTask(const std::string& task_name, TaskCreator task_creator); - // Can be called to end the periodically running tasks. - virtual void Quit(); - protected: - // Actual method which goes through registered tasks and runs them. - virtual void RunTasksInternal(); + TaskManager(); + + virtual ~TaskManager(); + + // Returns the storage used for the instance pointer. + static TaskManager** GetInstanceStorage(); + + // Executes the task with the name |task_name| and re-schedules it for the + // next execution. + virtual void ExecuteTask( + scoped_refptr<base::SingleThreadTaskRunner> task_runner, + const std::string& task_name); private: - // Schedules a RepeatingTimer with the period specified in TaskManagerConfig. - virtual void ScheduleTasks(); - - // Returns the elapsed time delta since the last time the periodic sync were - // successfully performed. - base::TimeDelta GetTimeDeltaSinceLastPeriodicSync(); - // List of tasks registered to be executed at every periodic run. std::map<std::string, TaskCreator> task_list_; - // The timer that controls posting task to be executed every time the period - // elapses. - base::RepeatingTimer timer_; + // If a task fails, the next execution time is calculated based on the backoff + // entry created and kept as long as task fails. + std::map<std::string, std::unique_ptr<net::BackoffEntry>> + task_execution_backoffs_; + + // Set of backoff policies for the tasks where there is a backoff entry. + std::map<std::string, std::unique_ptr<net::BackoffEntry::Policy>> + task_execution_policies_; }; } // namespace extension
diff --git a/chrome/credential_provider/extension/task_manager_unittests.cc b/chrome/credential_provider/extension/task_manager_unittests.cc index 3442bc4..5331e13 100644 --- a/chrome/credential_provider/extension/task_manager_unittests.cc +++ b/chrome/credential_provider/extension/task_manager_unittests.cc
@@ -7,18 +7,15 @@ #include <atlcomcli.h> #include <windows.h> +#include "base/bind.h" #include "base/guid.h" -#include "base/run_loop.h" +#include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" -#include "base/test/scoped_run_loop_timeout.h" #include "base/test/task_environment.h" -#include "base/test/test_mock_time_task_runner.h" -#include "base/threading/thread.h" -#include "chrome/credential_provider/extension/extension_strings.h" +#include "chrome/credential_provider/extension/extension_utils.h" #include "chrome/credential_provider/extension/task.h" #include "chrome/credential_provider/extension/task_manager.h" #include "chrome/credential_provider/gaiacp/gcp_utils.h" -#include "chrome/credential_provider/gaiacp/logging.h" #include "chrome/credential_provider/gaiacp/reg_utils.h" #include "chrome/credential_provider/test/gcp_fakes.h" #include "testing/gtest/include/gtest/gtest.h" @@ -41,8 +38,6 @@ registry_override.OverrideRegistry(HKEY_LOCAL_MACHINE); } - void TearDown() override { fake_task_manager_.Quit(); } - FakeTaskManager* fake_task_manager() { return &fake_task_manager_; } FakeOSUserManager* fake_os_user_manager() { return &fake_os_user_manager_; } @@ -59,29 +54,10 @@ base::test::SingleThreadTaskEnvironment::TimeSource::MOCK_TIME}; }; -TEST_F(TaskManagerTest, PeriodicExecution) { - ASSERT_EQ( - GetGlobalFlagOrDefault( - credential_provider::extension::kLastPeriodicSyncTimeRegKey, L""), - L""); - - RunTasks(); - - task_environment()->FastForwardBy(base::TimeDelta::FromHours(5)); - - ASSERT_EQ(fake_task_manager()->NumOfTimesExecuted(), 5); - - ASSERT_NE( - GetGlobalFlagOrDefault( - credential_provider::extension::kLastPeriodicSyncTimeRegKey, L""), - L""); - task_environment()->FastForwardBy(base::TimeDelta::FromHours(2)); - - ASSERT_EQ(fake_task_manager()->NumOfTimesExecuted(), 7); -} - class FakeTask : public extension::Task { public: + explicit FakeTask(base::TimeDelta period); + ~FakeTask() override; extension::Config GetConfig() override; @@ -91,17 +67,25 @@ HRESULT Execute() override; - static int number_of_times_executed_; static std::vector<extension::UserDeviceContext> user_device_context_; + static int num_fails_; + + private: + base::TimeDelta period_; }; -int FakeTask::number_of_times_executed_ = 0; std::vector<extension::UserDeviceContext> FakeTask::user_device_context_; +int FakeTask::num_fails_ = 0; + +FakeTask::FakeTask(base::TimeDelta period) : period_(period) {} + FakeTask::~FakeTask() {} extension::Config FakeTask::GetConfig() { - return {}; + extension::Config config; + config.execution_period = period_; + return config; } HRESULT FakeTask::SetContext( @@ -111,25 +95,84 @@ } HRESULT FakeTask::Execute() { - ++number_of_times_executed_; + if (num_fails_ != 0) { + num_fails_--; + return E_FAIL; + } return S_OK; } -std::unique_ptr<extension::Task> FakeTaskCreator() { - auto task = std::make_unique<FakeTask>(); +std::unique_ptr<extension::Task> AuxTaskCreator(base::TimeDelta period) { + auto task = std::make_unique<FakeTask>(period); return std::move(task); } +extension::TaskCreator GenerateTaskCreator(base::TimeDelta period) { + return base::BindRepeating(&AuxTaskCreator, period); +} + +TEST_F(TaskManagerTest, PeriodicDelay) { + std::string fake_task_name = "fake_task"; + + // Registers a task which has a config to run every 3 hours. + fake_task_manager()->RegisterTask( + fake_task_name, GenerateTaskCreator(base::TimeDelta::FromHours(3))); + + // Starts running registered tasks for all associated GCPW users. + RunTasks(); + + task_environment()->FastForwardBy(base::TimeDelta::FromHours(5)); + ASSERT_EQ(fake_task_manager()->NumOfTimesExecuted(fake_task_name), 2); + + base::string16 fake_task_reg_name = + extension::GetLastSyncRegNameForTask(base::UTF8ToUTF16(fake_task_name)); + ASSERT_NE(GetGlobalFlagOrDefault(fake_task_reg_name, L""), L""); + + task_environment()->FastForwardBy(base::TimeDelta::FromHours(2)); + ASSERT_EQ(fake_task_manager()->NumOfTimesExecuted(fake_task_name), 3); +} + +TEST_F(TaskManagerTest, PreviouslyExecuted) { + std::string fake_task_name = "fake_task"; + + base::string16 fake_task_reg_name = + extension::GetLastSyncRegNameForTask(base::UTF8ToUTF16(fake_task_name)); + + const base::Time sync_time = base::Time::Now(); + const base::string16 sync_time_millis = base::NumberToString16( + (sync_time.ToDeltaSinceWindowsEpoch() - base::TimeDelta::FromHours(1)) + .InMilliseconds()); + + SetGlobalFlag(fake_task_reg_name, sync_time_millis); + + // Registers a task which has a config to run every 3 hours. + fake_task_manager()->RegisterTask( + fake_task_name, GenerateTaskCreator(base::TimeDelta::FromHours(5))); + + // Starts running registered tasks for all associated GCPW users. + RunTasks(); + + // First execution should happen after 4 hours as the registry says it was + // executed an hour ago. + task_environment()->FastForwardBy(base::TimeDelta::FromHours(3) + + base::TimeDelta::FromMinutes(59)); + ASSERT_EQ(fake_task_manager()->NumOfTimesExecuted(fake_task_name), 0); + + task_environment()->FastForwardBy(base::TimeDelta::FromMinutes(1)); + ASSERT_EQ(fake_task_manager()->NumOfTimesExecuted(fake_task_name), 1); + + ASSERT_NE(GetGlobalFlagOrDefault(fake_task_reg_name, L""), L""); + + task_environment()->FastForwardBy(base::TimeDelta::FromHours(5)); + ASSERT_EQ(fake_task_manager()->NumOfTimesExecuted(fake_task_name), 2); +} + TEST_F(TaskManagerTest, TaskExecuted) { base::string16 serial_number = L"1234"; GoogleRegistrationDataForTesting g_registration_data(serial_number); base::string16 machine_guid = L"machine_guid"; SetMachineGuidForTesting(machine_guid); - FakeTokenGenerator fake_token_generator; - fake_token_generator.SetTokensForTesting( - {base::GenerateGUID(), base::GenerateGUID()}); - // Create a fake user associated to a gaia id. CComBSTR sid1; ASSERT_EQ(S_OK, fake_os_user_manager()->CreateTestOSUser( @@ -140,33 +183,33 @@ ASSERT_EQ(S_OK, SetUserProperty(OLE2W(sid1), L"device_resource_id", device_resource_id1)); + FakeTokenGenerator fake_token_generator; + fake_token_generator.SetTokensForTesting( + {base::GenerateGUID(), base::GenerateGUID()}); // IN-TEST + ASSERT_EQ(S_OK, GenerateGCPWDmToken((BSTR)sid1)); base::string16 dm_token1; ASSERT_EQ(S_OK, GetGCPWDmToken((BSTR)sid1, &dm_token1)); - ASSERT_EQ( - GetGlobalFlagOrDefault( - credential_provider::extension::kLastPeriodicSyncTimeRegKey, L""), - L""); + std::string fake_task_name = "fake_task"; - fake_task_manager()->RegisterTask("fake_task", - base::BindRepeating(&FakeTaskCreator)); + fake_task_manager()->RegisterTask( + fake_task_name, GenerateTaskCreator(base::TimeDelta::FromHours(3))); RunTasks(); task_environment()->FastForwardBy(base::TimeDelta::FromHours(5)); + ASSERT_EQ(fake_task_manager()->NumOfTimesExecuted(fake_task_name), 2); - ASSERT_EQ(FakeTask::number_of_times_executed_, 5); ASSERT_EQ(FakeTask::user_device_context_.size(), (size_t)1); extension::UserDeviceContext c1 = {device_resource_id1, serial_number, machine_guid, OLE2W(sid1), dm_token1}; ASSERT_TRUE(FakeTask::user_device_context_[0] == c1); - ASSERT_NE( - GetGlobalFlagOrDefault( - credential_provider::extension::kLastPeriodicSyncTimeRegKey, L""), - L""); + base::string16 fake_task_reg_name = + extension::GetLastSyncRegNameForTask(base::UTF8ToUTF16(fake_task_name)); + ASSERT_NE(GetGlobalFlagOrDefault(fake_task_reg_name, L""), L""); // Create another user associated to a gaia id. CComBSTR sid2; @@ -184,7 +227,7 @@ task_environment()->FastForwardBy(base::TimeDelta::FromHours(2)); - ASSERT_EQ(FakeTask::number_of_times_executed_, 7); + ASSERT_EQ(fake_task_manager()->NumOfTimesExecuted(fake_task_name), 3); ASSERT_EQ(FakeTask::user_device_context_.size(), (size_t)2); extension::UserDeviceContext c2 = {device_resource_id2, serial_number, @@ -193,5 +236,100 @@ ASSERT_TRUE(FakeTask::user_device_context_[1] == c2); } +TEST_F(TaskManagerTest, TasksWithDifferentPeriods) { + std::string fake_task_name = "fake_task"; + std::string another_fake_task_name = "another_fake_task"; + + fake_task_manager()->RegisterTask( + fake_task_name, GenerateTaskCreator(base::TimeDelta::FromHours(3))); + + fake_task_manager()->RegisterTask( + another_fake_task_name, + GenerateTaskCreator(base::TimeDelta::FromHours(1))); + + // Starts running registered tasks for all associated GCPW users. + RunTasks(); + + task_environment()->FastForwardBy(base::TimeDelta::FromHours(5)); + ASSERT_EQ(fake_task_manager()->NumOfTimesExecuted(fake_task_name), 2); + ASSERT_EQ(fake_task_manager()->NumOfTimesExecuted(another_fake_task_name), 5); + + base::string16 fake_task_reg_name = + extension::GetLastSyncRegNameForTask(base::UTF8ToUTF16(fake_task_name)); + ASSERT_NE(GetGlobalFlagOrDefault(fake_task_reg_name, L""), L""); + + base::string16 another_fake_task_reg_name = + extension::GetLastSyncRegNameForTask( + base::UTF8ToUTF16(another_fake_task_name)); + ASSERT_NE(GetGlobalFlagOrDefault(another_fake_task_reg_name, L""), L""); + + task_environment()->FastForwardBy(base::TimeDelta::FromHours(2)); + ASSERT_EQ(fake_task_manager()->NumOfTimesExecuted(fake_task_name), 3); + ASSERT_EQ(fake_task_manager()->NumOfTimesExecuted(another_fake_task_name), 7); +} + +TEST_F(TaskManagerTest, BackOff) { + base::string16 serial_number = L"1234"; + GoogleRegistrationDataForTesting g_registration_data(serial_number); + base::string16 machine_guid = L"machine_guid"; + SetMachineGuidForTesting(machine_guid); // IN-TEST + + // Create a fake user associated to a gaia id. + CComBSTR sid1; + ASSERT_EQ(S_OK, fake_os_user_manager()->CreateTestOSUser( + L"foo@gmail.com", L"password", L"Full Name", L"comment", + L"test-gaia-id", base::string16(), L"domain", &sid1)); + + base::string16 device_resource_id1 = L"foo_resource_id"; + ASSERT_EQ(S_OK, SetUserProperty(OLE2W(sid1), L"device_resource_id", + device_resource_id1)); + + FakeTokenGenerator fake_token_generator; + fake_token_generator.SetTokensForTesting( + {base::GenerateGUID(), base::GenerateGUID()}); // IN-TEST + + ASSERT_EQ(S_OK, GenerateGCPWDmToken((BSTR)sid1)); + + std::string fake_task_name = "fake_task"; + + // Task::Execute returns failure 3 times and backoff mechanism kicks in. + // 1st backoff is 1 min. 2nd backoff ins 3 mins. 3rd backoff is 6 mins. + FakeTask::num_fails_ = 3; + + fake_task_manager()->RegisterTask( + fake_task_name, GenerateTaskCreator(base::TimeDelta::FromMinutes(30))); + + // Starts running registered tasks for all associated GCPW users. + RunTasks(); + + base::string16 fake_task_reg_name = + extension::GetLastSyncRegNameForTask(base::UTF8ToUTF16(fake_task_name)); + + // Seconds 10 - 1st execution failure + task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(10)); + ASSERT_EQ(fake_task_manager()->NumOfTimesExecuted(fake_task_name), 1); + ASSERT_EQ(GetGlobalFlagOrDefault(fake_task_reg_name, L""), L""); + + // Minutes 2:10 - 2nd execution failure + task_environment()->FastForwardBy(base::TimeDelta::FromMinutes(2)); + ASSERT_EQ(fake_task_manager()->NumOfTimesExecuted(fake_task_name), 2); + ASSERT_EQ(GetGlobalFlagOrDefault(fake_task_reg_name, L""), L""); + + // Minutes 6:10 - 3rd execution failure + task_environment()->FastForwardBy(base::TimeDelta::FromMinutes(4)); + ASSERT_EQ(fake_task_manager()->NumOfTimesExecuted(fake_task_name), 3); + ASSERT_EQ(GetGlobalFlagOrDefault(fake_task_reg_name, L""), L""); + + // Minutes 14:10 - success + task_environment()->FastForwardBy(base::TimeDelta::FromMinutes(8)); + ASSERT_EQ(fake_task_manager()->NumOfTimesExecuted(fake_task_name), 4); + ASSERT_NE(GetGlobalFlagOrDefault(fake_task_reg_name, L""), L""); + + // Minutes 13:10 - 3 more success + task_environment()->FastForwardBy(base::TimeDelta::FromHours(2)); + ASSERT_EQ(fake_task_manager()->NumOfTimesExecuted(fake_task_name), 8); + ASSERT_NE(GetGlobalFlagOrDefault(fake_task_reg_name, L""), L""); +} + } // namespace testing } // namespace credential_provider
diff --git a/chrome/credential_provider/extension/user_context_enumerator.cc b/chrome/credential_provider/extension/user_context_enumerator.cc index e377e58..39a49613 100644 --- a/chrome/credential_provider/extension/user_context_enumerator.cc +++ b/chrome/credential_provider/extension/user_context_enumerator.cc
@@ -4,6 +4,8 @@ #include "chrome/credential_provider/extension/user_context_enumerator.h" +#include <windows.h> + #include <map> #include <vector> @@ -32,19 +34,26 @@ UserContextEnumerator::UserContextEnumerator() {} UserContextEnumerator::~UserContextEnumerator() {} -void UserContextEnumerator::PerformTask(const std::string& task_name, - Task& task) { +HRESULT UserContextEnumerator::PerformTask(const std::string& task_name, + Task& task) { base::string16 serial_number = GetSerialNumber(); base::string16 machine_guid = L""; HRESULT hr = GetMachineGuid(&machine_guid); if (FAILED(hr)) - LOGFN(ERROR) << "GetMachineGuid failed hr=" << putHR(hr); + LOGFN(WARNING) << "GetMachineGuid failed hr=" << putHR(hr); std::map<base::string16, UserTokenHandleInfo> sid_to_gaia_id; hr = GetUserTokenHandles(&sid_to_gaia_id); - if (FAILED(hr)) + if (FAILED(hr)) { LOGFN(ERROR) << "GetUserTokenHandles failed hr=" << putHR(hr); + return hr; + } + + if (sid_to_gaia_id.empty()) { + LOGFN(VERBOSE) << "No GCPW user exists on the device!"; + return S_OK; + } std::vector<UserDeviceContext> context_info; for (auto const& entry : sid_to_gaia_id) { @@ -59,15 +68,17 @@ hr = task.SetContext(context_info); if (FAILED(hr)) { - LOGFN(ERROR) << task_name << ":SetContext hr=" << putHR(hr); - return; + LOGFN(ERROR) << task_name << "SetContext hr=" << putHR(hr); + return hr; } hr = task.Execute(); if (FAILED(hr)) { - LOGFN(ERROR) << task_name << ":Execute task hr=" << putHR(hr); - return; + LOGFN(ERROR) << task_name << "Execute task hr=" << putHR(hr); + return hr; } + + return S_OK; } } // namespace extension
diff --git a/chrome/credential_provider/extension/user_context_enumerator.h b/chrome/credential_provider/extension/user_context_enumerator.h index 3fbedfd..470ed64 100644 --- a/chrome/credential_provider/extension/user_context_enumerator.h +++ b/chrome/credential_provider/extension/user_context_enumerator.h
@@ -5,6 +5,7 @@ #ifndef CHROME_CREDENTIAL_PROVIDER_EXTENSION_USER_CONTEXT_ENUMERATOR_H_ #define CHROME_CREDENTIAL_PROVIDER_EXTENSION_USER_CONTEXT_ENUMERATOR_H_ +#include "base/win/windows_types.h" #include "chrome/credential_provider/extension/task.h" namespace credential_provider { @@ -17,7 +18,7 @@ static UserContextEnumerator* Get(); // Performs the given |task| for every GCPW users on the device. - void PerformTask(const std::string& task_name, Task& task); + HRESULT PerformTask(const std::string& task_name, Task& task); private: UserContextEnumerator();
diff --git a/chrome/credential_provider/extension/user_device_context.h b/chrome/credential_provider/extension/user_device_context.h index dc01e7b..1dfd8226e 100644 --- a/chrome/credential_provider/extension/user_device_context.h +++ b/chrome/credential_provider/extension/user_device_context.h
@@ -12,10 +12,6 @@ namespace credential_provider { namespace extension { -// The configuration the task needs to run on. A way to tell task manager on how -// to run the task. -struct Config {}; - // The user, device and authentication details for task to be able to perform // its action. struct UserDeviceContext {
diff --git a/chrome/credential_provider/gaiacp/BUILD.gn b/chrome/credential_provider/gaiacp/BUILD.gn index b883d6b..357d461 100644 --- a/chrome/credential_provider/gaiacp/BUILD.gn +++ b/chrome/credential_provider/gaiacp/BUILD.gn
@@ -16,6 +16,10 @@ # This static library is shared with the setup program. source_set("common") { sources = [ + "experiments_fetcher.cc", + "experiments_fetcher.h", + "experiments_manager.cc", + "experiments_manager.h", "gcp_crash_reporter_client.cc", "gcp_crash_reporter_client.h", "gcp_crash_reporting_utils.cc",
diff --git a/chrome/credential_provider/gaiacp/experiments_fetcher.cc b/chrome/credential_provider/gaiacp/experiments_fetcher.cc new file mode 100644 index 0000000..f2cf0fb0 --- /dev/null +++ b/chrome/credential_provider/gaiacp/experiments_fetcher.cc
@@ -0,0 +1,239 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/credential_provider/gaiacp/experiments_fetcher.h" + +#include <windows.h> + +#include "base/bind.h" +#include "base/files/file.h" +#include "base/json/json_writer.h" +#include "base/strings/string_number_conversions.h" +#include "base/time/time.h" +#include "chrome/common/chrome_version.h" +#include "chrome/credential_provider/gaiacp/experiments_manager.h" +#include "chrome/credential_provider/gaiacp/gcp_utils.h" +#include "chrome/credential_provider/gaiacp/logging.h" +#include "chrome/credential_provider/gaiacp/reg_utils.h" + +namespace credential_provider { +namespace { + +// HTTP endpoint on the GCPW service to fetch experiments. +const wchar_t kGcpwServiceFetchExperimentsPath[] = L"/v1/experiments"; + +// Default timeout when trying to make requests to the GCPW service. +const base::TimeDelta kDefaultFetchExperimentsRequestTimeout = + base::TimeDelta::FromMilliseconds(5000); + +// The period of refreshing experiments. +const base::TimeDelta kExperimentsRefreshExecutionPeriod = + base::TimeDelta::FromHours(3); + +// Maximum number of retries if a HTTP call to the backend fails. +constexpr unsigned int kMaxNumHttpRetries = 1; + +// HTTP query parameters for fetch experiments RPC. +const char kObfuscatedUserIdKey[] = "obfuscated_gaia_id"; +const char kGcpwVersionKey[] = "gcpw_version"; +const char kDmTokenKey[] = "dm_token"; +const char kDeviceResourceIdKey[] = "device_resource_id"; +const char kFeaturesKey[] = "feature"; + +// Defines a task that is called by the ESA to perform the experiments fetch +// operation. +class ExperimentsFetchTask : public extension::Task { + public: + static std::unique_ptr<extension::Task> Create() { + std::unique_ptr<extension::Task> esa_task(new ExperimentsFetchTask()); + return esa_task; + } + + // ESA calls this to retrieve a configuration for the task execution. Return + // a default config for now. + extension::Config GetConfig() final { + extension::Config config; + config.execution_period = kExperimentsRefreshExecutionPeriod; + return config; + } + + // ESA calls this to set all the user-device contexts for the execution of the + // task. + HRESULT SetContext(const std::vector<extension::UserDeviceContext>& c) final { + context_ = c; + return S_OK; + } + + // ESA calls execute function to perform the actual task. + HRESULT Execute() final { + HRESULT task_status = S_OK; + for (const auto& c : context_) { + HRESULT hr = ExperimentsFetcher::Get()->FetchAndStoreExperiments(c); + if (FAILED(hr)) { + LOGFN(ERROR) << "Failed fetching experiments for " << c.user_sid + << ". hr=" << putHR(hr); + task_status = hr; + } + } + + return task_status; + } + + private: + std::vector<extension::UserDeviceContext> context_; +}; + +// Builds the request dictionary to fetch experiments from the backend. If +// |dm_token| is empty, it isn't added into request. If user id isn't found for +// the given |sid|, returns an empty dictionary. +std::unique_ptr<base::DictionaryValue> GetExperimentsRequestDict( + const base::string16& sid, + const base::string16& device_resource_id, + const base::string16& dm_token) { + std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue); + + base::string16 user_id; + + HRESULT status = GetIdFromSid(sid.c_str(), &user_id); + if (FAILED(status)) { + LOGFN(ERROR) << "Could not get user id from sid " << sid; + return nullptr; + } + + dict->SetString(kObfuscatedUserIdKey, user_id); + + if (!dm_token.empty()) { + dict->SetString(kDmTokenKey, dm_token); + } + dict->SetString(kDeviceResourceIdKey, device_resource_id); + + dict->SetString(kGcpwVersionKey, TEXT(CHROME_VERSION_STRING)); + + auto keys = std::make_unique<base::ListValue>(); + for (auto& experiment : ExperimentsManager::Get()->GetExperimentsList()) + keys->AppendString(experiment); + + dict->Set(kFeaturesKey, std::move(keys)); + + return dict; +} + +} // namespace + +GURL ExperimentsFetcher::GetExperimentsUrl() { + GURL gcpw_service_url = GetGcpwServiceUrl(); + return gcpw_service_url.Resolve(kGcpwServiceFetchExperimentsPath); +} + +// static +ExperimentsFetcher* ExperimentsFetcher::Get() { + return *GetInstanceStorage(); +} + +// static +ExperimentsFetcher** ExperimentsFetcher::GetInstanceStorage() { + static ExperimentsFetcher instance; + static ExperimentsFetcher* instance_storage = &instance; + return &instance_storage; +} + +// static +extension::TaskCreator ExperimentsFetcher::GetFetchExperimentsTaskCreator() { + return base::BindRepeating(&ExperimentsFetchTask::Create); +} + +ExperimentsFetcher::ExperimentsFetcher() {} + +ExperimentsFetcher::~ExperimentsFetcher() = default; + +HRESULT ExperimentsFetcher::FetchAndStoreExperiments( + const extension::UserDeviceContext& context) { + return FetchAndStoreExperimentsInternal( + context.user_sid, /* access_token= */ "", + GetExperimentsRequestDict(context.user_sid, context.device_resource_id, + context.dm_token)); +} + +HRESULT ExperimentsFetcher::FetchAndStoreExperiments( + const base::string16& sid, + const std::string& access_token) { + HRESULT hr = FetchAndStoreExperimentsInternal( + sid, access_token, + GetExperimentsRequestDict(sid, GetUserDeviceResourceId(sid), + /* dm_token= */ L"")); + return hr; +} + +HRESULT ExperimentsFetcher::FetchAndStoreExperimentsInternal( + const base::string16& sid, + const std::string& access_token, + std::unique_ptr<base::DictionaryValue> request_dict) { + if (!request_dict) { + LOGFN(ERROR) << "Request dictionary is null"; + return E_FAIL; + } + + // Make the fetch experiments HTTP request. + base::Optional<base::Value> request_result; + HRESULT hr = WinHttpUrlFetcher::BuildRequestAndFetchResultFromHttpService( + GetExperimentsUrl(), access_token, {}, *request_dict.get(), + kDefaultFetchExperimentsRequestTimeout, kMaxNumHttpRetries, + &request_result); + + if (FAILED(hr)) { + LOGFN(ERROR) << "BuildRequestAndFetchResultFromHttpService hr=" + << putHR(hr); + return hr; + } + + std::string experiments_data; + if (request_result && request_result->is_dict()) { + if (!base::JSONWriter::Write(*request_result, &experiments_data)) { + LOGFN(ERROR) << "base::JSONWriter::Write failed"; + return E_FAIL; + } + } else { + LOGFN(ERROR) << "Failed to parse experiments response!"; + return E_FAIL; + } + + uint32_t open_flags = base::File::FLAG_CREATE_ALWAYS | + base::File::FLAG_WRITE | + base::File::FLAG_EXCLUSIVE_WRITE; + std::unique_ptr<base::File> experiments_file = GetOpenedFileForUser( + sid, open_flags, kGcpwExperimentsDirectory, kGcpwUserExperimentsFileName); + if (!experiments_file) { + LOGFN(ERROR) << "Failed to open " << kGcpwUserExperimentsFileName + << " file."; + return E_FAIL; + } + + int num_bytes_written = experiments_file->Write(0, experiments_data.c_str(), + experiments_data.size()); + + experiments_file.reset(); + + if (size_t(num_bytes_written) != experiments_data.size()) { + LOGFN(ERROR) << "Failed writing experiments data to file! Only " + << num_bytes_written << " bytes written out of " + << experiments_data.size(); + return E_FAIL; + } + + base::Time fetch_time = base::Time::Now(); + base::string16 fetch_time_millis = base::NumberToString16( + fetch_time.ToDeltaSinceWindowsEpoch().InMilliseconds()); + + if (!ExperimentsManager::Get()->ReloadExperiments(sid)) { + LOGFN(ERROR) << "Error when loading experiments for user with sid " << sid; + } + + // Store the fetch time so we know whether a refresh is needed. + SetUserProperty(sid, kLastUserExperimentsRefreshTimeRegKey, + fetch_time_millis); + + return S_OK; +} + +} // namespace credential_provider
diff --git a/chrome/credential_provider/gaiacp/experiments_fetcher.h b/chrome/credential_provider/gaiacp/experiments_fetcher.h new file mode 100644 index 0000000..3c8187d --- /dev/null +++ b/chrome/credential_provider/gaiacp/experiments_fetcher.h
@@ -0,0 +1,58 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_CREDENTIAL_PROVIDER_GAIACP_EXPERIMENTS_FETCHER_H_ +#define CHROME_CREDENTIAL_PROVIDER_GAIACP_EXPERIMENTS_FETCHER_H_ + +#include "base/values.h" +#include "base/win/windows_types.h" +#include "chrome/credential_provider/extension/task_manager.h" +#include "url/gurl.h" + +namespace credential_provider { + +// Fetcher used to fetch experiments from GCPW backends. +class ExperimentsFetcher { + public: + // Gets the singleton instance. + static ExperimentsFetcher* Get(); + + // Provides the GCPW extension with a TaskCreator which can be used to create + // a task for fetching experiments. + static extension::TaskCreator GetFetchExperimentsTaskCreator(); + + // Fetches the experiments for the user implied with the |access_token| from + // the GCPW backend and saves it in file storage replacing any previously + // fetched versions. + HRESULT FetchAndStoreExperiments(const base::string16& sid, + const std::string& access_token); + + // Fetches the experiments for the user-device |context| provided by the GCPW + // extension service from the GCPW backend and saves it in file storage + // replacing any previously fetched versions. + HRESULT FetchAndStoreExperiments(const extension::UserDeviceContext& context); + + // Returns the experiments fetch endpoint. + GURL GetExperimentsUrl(); + + private: + // Returns the storage used for the instance pointer. + static ExperimentsFetcher** GetInstanceStorage(); + + ExperimentsFetcher(); + virtual ~ExperimentsFetcher(); + + // Fetches experiments with the provided |request_dict|. |access_token| needs + // to be present if the experiments are being fetched in the presence of an + // oauth token. Otherwise |request_dict| should be carrying the obfuscated + // user id as well as DM token. + HRESULT FetchAndStoreExperimentsInternal( + const base::string16& sid, + const std::string& access_token, + std::unique_ptr<base::DictionaryValue> request_dict); +}; + +} // namespace credential_provider + +#endif // CHROME_CREDENTIAL_PROVIDER_GAIACP_EXPERIMENTS_FETCHER_H_
diff --git a/chrome/credential_provider/gaiacp/experiments_manager.cc b/chrome/credential_provider/gaiacp/experiments_manager.cc new file mode 100644 index 0000000..98edc36 --- /dev/null +++ b/chrome/credential_provider/gaiacp/experiments_manager.cc
@@ -0,0 +1,159 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/credential_provider/gaiacp/experiments_manager.h" + +#include <vector> + +#include "base/files/file.h" +#include "base/json/json_reader.h" +#include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" +#include "chrome/credential_provider/gaiacp/gcp_utils.h" +#include "chrome/credential_provider/gaiacp/logging.h" +#include "chrome/credential_provider/gaiacp/reg_utils.h" + +namespace credential_provider { +namespace { + +// Registry key to control whether experiments feature is enabled. +const wchar_t kExperimentsEnabledRegKey[] = L"experiments_enabled"; + +// Name of the keys found in the experiments server response. +const char kResponseExperimentsKeyName[] = "experiments"; +const char kResponseFeatureKeyName[] = "feature"; +const char kResponseValueKeyName[] = "value"; + +} // namespace + +// static +ExperimentsManager* ExperimentsManager::Get() { + return *GetInstanceStorage(); +} + +// static +ExperimentsManager** ExperimentsManager::GetInstanceStorage() { + static ExperimentsManager instance; + static ExperimentsManager* instance_storage = &instance; + return &instance_storage; +} + +ExperimentsManager::ExperimentsManager() { + if (ExperimentsEnabled()) { + RegisterExperiments(); + ReloadAllExperiments(); + } +} + +ExperimentsManager::~ExperimentsManager() = default; + +void ExperimentsManager::RegisterExperiments() { + experiments_to_values_.clear(); + for (ExperimentMetadata em : experiments) { + // Experiment name to default value mapping is created prior to reading + // experiments file. + experiments_to_values_[em.name].first = em.default_value; + } +} + +// Reloads the experiment values from fetched experiments file for the given +// |sid|. Loads the fetched experiments values into |experiments_to_values_|. +bool ExperimentsManager::ReloadExperiments(const base::string16& sid) { + uint32_t open_flags = base::File::FLAG_OPEN | base::File::FLAG_READ; + std::unique_ptr<base::File> experiments_file = GetOpenedFileForUser( + sid, open_flags, kGcpwExperimentsDirectory, kGcpwUserExperimentsFileName); + if (!experiments_file) { + return false; + } + + std::vector<char> buffer(experiments_file->GetLength()); + experiments_file->Read(0, buffer.data(), buffer.size()); + experiments_file.reset(); + + base::Optional<base::Value> experiments_data = + base::JSONReader::Read(base::StringPiece(buffer.data(), buffer.size()), + base::JSON_ALLOW_TRAILING_COMMAS); + if (!experiments_data || !experiments_data->is_dict()) { + LOGFN(ERROR) << "Failed to read experiments data from file!"; + return false; + } + + const base::Value* experiments = + experiments_data->FindListKey(kResponseExperimentsKeyName); + if (!experiments) { + LOGFN(ERROR) << "User experiments not found!"; + return false; + } + + if (experiments->is_list()) { + for (const auto& item : experiments->GetList()) { + auto* f = item.FindStringKey(kResponseFeatureKeyName); + auto* v = item.FindStringKey(kResponseValueKeyName); + if (!f || !v) { + LOGFN(WARNING) << "Either feature or value are not found!"; + } + + experiments_to_values_[*f].second[base::UTF16ToUTF8(sid)] = *v; + } + } + return true; +} + +// TODO(crbug.com/1143829): Reload experiments if they were fetched by ESA. +void ExperimentsManager::ReloadAllExperiments() { + std::map<base::string16, UserTokenHandleInfo> sid_to_gaia_id; + HRESULT hr = GetUserTokenHandles(&sid_to_gaia_id); + + if (FAILED(hr)) { + LOGFN(ERROR) << "Unable to get the list of associated users"; + return; + } + + for (auto& sid : sid_to_gaia_id) { + if (!ReloadExperiments(sid.first)) { + LOGFN(ERROR) << "Error when loading experiments for user with sid " + << sid.first; + } + } +} + +std::string ExperimentsManager::GetExperimentForUser(const std::string& sid, + Experiment experiment) { + std::string experiment_name = experiments[experiment].name; + + // There shouldn't be a case where a registered experiment can't be found, but + // just in case we return an empty string. + if (experiments_to_values_.find(experiment_name) == + experiments_to_values_.end()) + return ""; + + auto& sid_to_experiment_values = + experiments_to_values_[experiment_name].second; + + // If the experiment value doesn't exist for the given sid, return the default + // value. + if (sid_to_experiment_values.find(sid) == sid_to_experiment_values.end()) { + return experiments_to_values_[experiment_name].first; + } + + return sid_to_experiment_values[sid]; +} + +bool ExperimentsManager::GetExperimentForUserAsBool(const std::string& sid, + Experiment experiment) { + return base::ToLowerASCII(GetExperimentForUser(sid, experiment)) == "true"; +} + +bool ExperimentsManager::ExperimentsEnabled() const { + return GetGlobalFlagOrDefault(kExperimentsEnabledRegKey, 0); +} + +std::vector<std::string> ExperimentsManager::GetExperimentsList() const { + std::vector<std::string> experiment_names; + for (auto& experiment : experiments) + experiment_names.push_back(experiment.name); + return experiment_names; +} + +} // namespace credential_provider
diff --git a/chrome/credential_provider/gaiacp/experiments_manager.h b/chrome/credential_provider/gaiacp/experiments_manager.h new file mode 100644 index 0000000..f9b18fa --- /dev/null +++ b/chrome/credential_provider/gaiacp/experiments_manager.h
@@ -0,0 +1,84 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_CREDENTIAL_PROVIDER_GAIACP_EXPERIMENTS_MANAGER_H_ +#define CHROME_CREDENTIAL_PROVIDER_GAIACP_EXPERIMENTS_MANAGER_H_ + +#include <map> +#include <vector> + +#include "base/strings/string16.h" + +namespace credential_provider { + +// List of experiments which must be kept in sync with the metadata for the +// experiment below. +enum Experiment { TEST_CLIENT_FLAG, TEST_CLIENT_FLAG2 }; + +class ExperimentsManager { + public: + // Gets the singleton instance. + static ExperimentsManager* Get(); + + // Called as the first thing when ExperimentsManager is getting constructed. + // Registers all the experiments used in GCPW and ESA with their default + // values. If fetching experiments happen to fail, defaults set by this + // function are used. + void RegisterExperiments(); + + // Reloads the experiments for the given |sid|. + bool ReloadExperiments(const base::string16& sid); + + // Returns the experiment value for the provided |sid| and |experiment|. + std::string GetExperimentForUser(const std::string& sid, + Experiment experiment); + + // Returns the experiment value as a boolean for the provided |sid| and + // |experiment|. + bool GetExperimentForUserAsBool(const std::string& sid, + Experiment experiment); + + // Return true if experiments feature is enabled. + bool ExperimentsEnabled() const; + + // Returns the list of experiments to fetch from the backend. + std::vector<std::string> GetExperimentsList() const; + + private: + // Returns the storage used for the instance pointer. + static ExperimentsManager** GetInstanceStorage(); + + ExperimentsManager(); + virtual ~ExperimentsManager(); + + // Updates the cached values of experiments with the recent fetch. + void ReloadAllExperiments(); + + // sid to experiment value mapping. + typedef std::map<std::string, std::string> PerUserValues; + + // default value and per user experiment value pair. + typedef std::pair<std::string, PerUserValues> ExperimentValue; + + // Map of features to <default value, per user value mapping> + std::map<std::string, ExperimentValue> experiments_to_values_; + + // Struct which contains an individual experiment name and default value. + struct ExperimentMetadata { + Experiment experiment; + std::string name; + std::string default_value; + }; + + // Metadata for list of supported experiments. + std::vector<ExperimentMetadata> experiments = { + // TODO(crbug.com/1147522): Clean up the test experiments when actual + // experiments are introduced. These were added for e2e testing. + {TEST_CLIENT_FLAG, "test_client_flag", "false"}, + {TEST_CLIENT_FLAG2, "test_client_flag2", "false"}}; +}; + +} // namespace credential_provider + +#endif // CHROME_CREDENTIAL_PROVIDER_GAIACP_EXPERIMENTS_MANAGER_H_
diff --git a/chrome/credential_provider/gaiacp/experiments_manager_unittests.cc b/chrome/credential_provider/gaiacp/experiments_manager_unittests.cc new file mode 100644 index 0000000..8f20860 --- /dev/null +++ b/chrome/credential_provider/gaiacp/experiments_manager_unittests.cc
@@ -0,0 +1,201 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/strings/utf_string_conversions.h" +#include "chrome/credential_provider/extension/task.h" +#include "chrome/credential_provider/gaiacp/experiments_fetcher.h" +#include "chrome/credential_provider/gaiacp/experiments_manager.h" +#include "chrome/credential_provider/gaiacp/gcp_utils.h" +#include "chrome/credential_provider/gaiacp/reg_utils.h" +#include "chrome/credential_provider/test/gcp_fakes.h" +#include "chrome/credential_provider/test/gls_runner_test_base.h" +#include "chrome/credential_provider/test/test_credential.h" +#include "google_apis/gaia/gaia_urls.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace credential_provider { + +namespace testing { + +class ExperimentsManagerTest : public GlsRunnerTestBase { + protected: + void SetUp() override; +}; + +void ExperimentsManagerTest::SetUp() { + GlsRunnerTestBase::SetUp(); + + ASSERT_EQ(S_OK, + SetGlobalFlagForTesting(L"experiments_enabled", 1)); // IN-TEST + FakesForTesting fakes; + fakes.fake_win_http_url_fetcher_creator = + fake_http_url_fetcher_factory()->GetCreatorCallback(); + WinHttpUrlFetcher::SetCreatorForTesting( + fakes.fake_win_http_url_fetcher_creator); + + // Set token result a valid access token. + fake_http_url_fetcher_factory()->SetFakeResponse( + GURL(GaiaUrls::GetInstance()->oauth2_token_url().spec().c_str()), + FakeWinHttpUrlFetcher::Headers(), "{\"access_token\": \"dummy_token\"}"); +} + +TEST_F(ExperimentsManagerTest, DefaultValues) { + EXPECT_EQ("false", ExperimentsManager::Get()->GetExperimentForUser( + "test_sid", Experiment::TEST_CLIENT_FLAG)); + EXPECT_EQ("false", ExperimentsManager::Get()->GetExperimentForUser( + "test_sid", Experiment::TEST_CLIENT_FLAG2)); + + EXPECT_FALSE(ExperimentsManager::Get()->GetExperimentForUserAsBool( + "test_sid", Experiment::TEST_CLIENT_FLAG)); + EXPECT_FALSE(ExperimentsManager::Get()->GetExperimentForUserAsBool( + "test_sid", Experiment::TEST_CLIENT_FLAG2)); +} + +// Tests different outcomes of fetching experiments through GCPW: +// 0 - Experiments are fetched successfully. +// 1 - Failed fetching experiments. +// 2 - Response in fetching experiments contains malformed payload. +class ExperimentsManagerGcpwE2ETest + : public ExperimentsManagerTest, + public ::testing::WithParamInterface<int> {}; + +TEST_P(ExperimentsManagerGcpwE2ETest, FetchingExperiments) { + int experiment_fetch_status = GetParam(); + + // Create a fake user that has the same gaia id as the test gaia id. + CComBSTR sid; + ASSERT_EQ(S_OK, + fake_os_user_manager()->CreateTestOSUser( + L"foo", L"password", L"Full Name", L"comment", + base::UTF8ToUTF16(kDefaultGaiaId), L"user@company.com", &sid)); + + base::string16 device_resource_id = L"foo_resource_id"; + ASSERT_EQ(S_OK, SetUserProperty(OLE2W(sid), L"device_resource_id", + device_resource_id)); + + // Re-registering effectively clears the experiment values from the previous + // fetches. + ExperimentsManager::Get()->RegisterExperiments(); + + GURL url = ExperimentsFetcher::Get()->GetExperimentsUrl(); + + if (experiment_fetch_status == 0) { + fake_http_url_fetcher_factory()->SetFakeResponse( + url, FakeWinHttpUrlFetcher::Headers(), + "{\"experiments\": [{\"feature\": \"test_client_flag\", \"value\": " + "\"abc\"}, {\"feature\": \"test_client_flag2\", \"value\": \"def\"} ] " + "}"); + } else if (experiment_fetch_status == 1) { + fake_http_url_fetcher_factory()->SetFakeFailedResponse(url, E_FAIL); + } else { + fake_http_url_fetcher_factory()->SetFakeResponse( + url, FakeWinHttpUrlFetcher::Headers(), "{\"bad_experiments\": [ ] }"); + } + + // Create provider and start logon. + Microsoft::WRL::ComPtr<ICredentialProviderCredential> cred; + + ASSERT_EQ(S_OK, InitializeProviderAndGetCredential(0, &cred)); + + Microsoft::WRL::ComPtr<ITestCredential> test; + ASSERT_EQ(S_OK, cred.As(&test)); + + ASSERT_EQ(S_OK, StartLogonProcessAndWait()); + + // Email should be the same as the default one. + EXPECT_EQ(test->GetFinalEmail(), kDefaultEmail); + + std::string experiment1_value = "false"; + std::string experiment2_value = "false"; + + if (experiment_fetch_status == 0) { + experiment1_value = "abc"; + experiment2_value = "def"; + } + + EXPECT_EQ(experiment1_value, + ExperimentsManager::Get()->GetExperimentForUser( + base::UTF16ToUTF8(OLE2W(sid)), Experiment::TEST_CLIENT_FLAG)); + EXPECT_EQ(experiment2_value, + ExperimentsManager::Get()->GetExperimentForUser( + base::UTF16ToUTF8(OLE2W(sid)), Experiment::TEST_CLIENT_FLAG2)); +} + +INSTANTIATE_TEST_SUITE_P(All, + ExperimentsManagerGcpwE2ETest, + ::testing::Values(0, 1, 2)); + +// Tests different outcomes of fetching experiments through ESA: +// 0 - Experiments are fetched successfully. +// 1 - Failed fetching experiments. +// 2 - Response in fetching experiments contains malformed payload. +class ExperimentsManagerESAE2ETest : public ExperimentsManagerTest, + public ::testing::WithParamInterface<int> { +}; + +TEST_P(ExperimentsManagerESAE2ETest, FetchingExperiments) { + int experiment_fetch_status = GetParam(); + + // Create a fake user that has the same gaia id as the test gaia id. + CComBSTR sid; + ASSERT_EQ(S_OK, + fake_os_user_manager()->CreateTestOSUser( + L"foo", L"password", L"Full Name", L"comment", + base::UTF8ToUTF16(kDefaultGaiaId), L"user@company.com", &sid)); + + ASSERT_EQ(S_OK, GenerateGCPWDmToken((BSTR)sid)); + + base::string16 device_resource_id = L"foo_resource_id"; + ASSERT_EQ(S_OK, SetUserProperty(OLE2W(sid), L"device_resource_id", + device_resource_id)); + + // Re-registering effectively clears the experiment values from the previous + // fetches. + ExperimentsManager::Get()->RegisterExperiments(); + + GURL url = ExperimentsFetcher::Get()->GetExperimentsUrl(); + + if (experiment_fetch_status == 0) { + fake_http_url_fetcher_factory()->SetFakeResponse( + url, FakeWinHttpUrlFetcher::Headers(), + "{\"experiments\": [{\"feature\": \"test_client_flag\", \"value\": " + "\"abc\"}, {\"feature\": \"test_client_flag2\", \"value\": \"def\"} ] " + "}"); + } else if (experiment_fetch_status == 1) { + fake_http_url_fetcher_factory()->SetFakeFailedResponse(url, E_FAIL); + } else { + fake_http_url_fetcher_factory()->SetFakeResponse( + url, FakeWinHttpUrlFetcher::Headers(), "{\"bad_experiments\": [ ] }"); + } + + base::string16 dm_token; + ASSERT_EQ(S_OK, GetGCPWDmToken((BSTR)sid, &dm_token)); + + std::unique_ptr<extension::Task> task( + ExperimentsFetcher::GetFetchExperimentsTaskCreator().Run()); + task->SetContext({{device_resource_id, L"", L"", OLE2W(sid), dm_token}}); + task->Execute(); + + std::string experiment1_value = "false"; + std::string experiment2_value = "false"; + + if (experiment_fetch_status == 0) { + experiment1_value = "abc"; + experiment2_value = "def"; + } + + EXPECT_EQ(experiment1_value, + ExperimentsManager::Get()->GetExperimentForUser( + base::UTF16ToUTF8(OLE2W(sid)), Experiment::TEST_CLIENT_FLAG)); + EXPECT_EQ(experiment2_value, + ExperimentsManager::Get()->GetExperimentForUser( + base::UTF16ToUTF8(OLE2W(sid)), Experiment::TEST_CLIENT_FLAG2)); +} + +INSTANTIATE_TEST_SUITE_P(All, + ExperimentsManagerESAE2ETest, + ::testing::Values(0, 1, 2)); + +} // namespace testing +} // namespace credential_provider
diff --git a/chrome/credential_provider/gaiacp/gaia_credential_base.cc b/chrome/credential_provider/gaiacp/gaia_credential_base.cc index 1e72b9c6..db57f206 100644 --- a/chrome/credential_provider/gaiacp/gaia_credential_base.cc +++ b/chrome/credential_provider/gaiacp/gaia_credential_base.cc
@@ -40,6 +40,8 @@ #include "chrome/credential_provider/gaiacp/auth_utils.h" #include "chrome/credential_provider/gaiacp/device_policies_manager.h" #include "chrome/credential_provider/gaiacp/event_logs_upload_manager.h" +#include "chrome/credential_provider/gaiacp/experiments_fetcher.h" +#include "chrome/credential_provider/gaiacp/experiments_manager.h" #include "chrome/credential_provider/gaiacp/gaia_credential_provider.h" #include "chrome/credential_provider/gaiacp/gaia_credential_provider_i.h" #include "chrome/credential_provider/gaiacp/gaia_resources.h" @@ -810,6 +812,44 @@ return HRESULT_FROM_WIN32(NERR_UserExists); } +// If GCPW user policies or experiments are stale, make sure to fetch them +// before proceeding with the login. +void GetUserConfigsIfStale(const base::string16& sid, + const base::string16& gaia_id, + const base::string16& access_token) { + if (UserPoliciesManager::Get()->CloudPoliciesEnabled() && + UserPoliciesManager::Get()->IsUserPolicyStaleOrMissing(sid)) { + // Save gaia id since it is needed for the cloud policies server request. + HRESULT hr = SetUserProperty(sid, kUserId, gaia_id); + if (FAILED(hr)) { + LOGFN(ERROR) << "SetUserProperty(id) hr=" << putHR(hr); + } + + hr = UserPoliciesManager::Get()->FetchAndStoreCloudUserPolicies( + sid, base::UTF16ToUTF8(access_token)); + if (FAILED(hr)) { + LOGFN(ERROR) << "Failed fetching user policies for user " << sid + << " Error: " << putHR(hr); + } + } + + if (ExperimentsManager::Get()->ExperimentsEnabled() && + GetTimeDeltaSinceLastFetch(sid, kLastUserExperimentsRefreshTimeRegKey) > + kMaxTimeDeltaSinceLastExperimentsFetch) { + HRESULT hr = SetUserProperty(sid, kUserId, gaia_id); + if (FAILED(hr)) { + LOGFN(ERROR) << "SetUserProperty(id) hr=" << putHR(hr); + } + + hr = ExperimentsFetcher::Get()->FetchAndStoreExperiments( + sid, base::UTF16ToUTF8(access_token)); + if (FAILED(hr)) { + LOGFN(ERROR) << "Failed fetching experiments for user " << sid + << " Error: " << putHR(hr); + } + } +} + } // namespace CGaiaCredentialBase::UIProcessInfo::UIProcessInfo() {} @@ -2492,27 +2532,12 @@ : "false")); } - base::string16 sid = OLE2CW(user_sid_); - if (UserPoliciesManager::Get()->CloudPoliciesEnabled() && - UserPoliciesManager::Get()->IsUserPolicyStaleOrMissing(sid)) { - // Save gaia id since it is needed for the cloud policies server request. - base::string16 gaia_id = GetDictString(*authentication_results_, kKeyId); - HRESULT hr = SetUserProperty(sid, kUserId, gaia_id); - if (FAILED(hr)) { - LOGFN(ERROR) << "SetUserProperty(id) hr=" << putHR(hr); - } - - // TODO(crbug.com/976744) Use downscoped token here. - base::string16 access_token = - GetDictString(*authentication_results_, kKeyAccessToken); - hr = UserPoliciesManager::Get()->FetchAndStoreCloudUserPolicies( - sid, base::UTF16ToUTF8(access_token)); - SecurelyClearString(access_token); - if (FAILED(hr)) { - LOGFN(ERROR) << "Failed fetching user policies for user " << sid - << " Error: " << putHR(hr); - } - } + base::string16 gaia_id = GetDictString(*authentication_results_, kKeyId); + // TODO(crbug.com/976744) Use downscoped token here. + base::string16 access_token = + GetDictString(*authentication_results_, kKeyAccessToken); + GetUserConfigsIfStale(OLE2CW(user_sid_), gaia_id, access_token); + SecurelyClearString(access_token); base::string16 local_password = GetDictString(*authentication_results_, kKeyPassword);
diff --git a/chrome/credential_provider/gaiacp/gaia_credential_base_unittests.cc b/chrome/credential_provider/gaiacp/gaia_credential_base_unittests.cc index 59dd0c1..beedba1d 100644 --- a/chrome/credential_provider/gaiacp/gaia_credential_base_unittests.cc +++ b/chrome/credential_provider/gaiacp/gaia_credential_base_unittests.cc
@@ -3596,7 +3596,7 @@ ASSERT_EQ(S_OK, FinishLogonProcess(true, true, 0)); base::TimeDelta time_since_last_fetch = - UserPoliciesManager::Get()->GetTimeDeltaSinceLastPolicyFetch(sid); + GetTimeDeltaSinceLastFetch(sid, kLastUserPolicyRefreshTimeRegKey); if (cloud_policies_enabled && !policy_refreshed_recently) { ASSERT_EQ(1, fake_user_policies_manager.GetNumTimesFetchAndStoreCalled());
diff --git a/chrome/credential_provider/gaiacp/gcp_utils.cc b/chrome/credential_provider/gaiacp/gcp_utils.cc index eb870b5..e90b7ce7 100644 --- a/chrome/credential_provider/gaiacp/gcp_utils.cc +++ b/chrome/credential_provider/gaiacp/gcp_utils.cc
@@ -92,6 +92,12 @@ constexpr int kMaxNumConsecutiveUploadDeviceFailures = 3; const base::TimeDelta kMaxTimeDeltaSinceLastUserPolicyRefresh = base::TimeDelta::FromDays(1); +const base::TimeDelta kMaxTimeDeltaSinceLastExperimentsFetch = + base::TimeDelta::FromDays(1); + +// Path elements for the path where the experiments are stored on disk. +const wchar_t kGcpwExperimentsDirectory[] = L"Experiments"; +const wchar_t kGcpwUserExperimentsFileName[] = L"ExperimentsFetchResponse"; namespace { @@ -109,6 +115,7 @@ #define HANDLE_LANGUAGE(l_, o_) {L## #l_, o_}, DO_LANGUAGES #undef HANDLE_LANGUAGE + }; base::FilePath GetStartupSentinelLocation(const base::string16& version) { @@ -233,6 +240,23 @@ return S_OK; } +// Get the path to the directory under DIR_COMMON_APP_DATA with the given |sid| +// and |file_dir|. +base::FilePath GetDirectoryFilePath(const base::string16& sid, + const base::string16& file_dir) { + base::FilePath path; + if (!base::PathService::Get(base::DIR_COMMON_APP_DATA, &path)) { + HRESULT hr = HRESULT_FROM_WIN32(::GetLastError()); + LOGFN(ERROR) << "PathService::Get(DIR_COMMON_APP_DATA) hr=" << putHR(hr); + return base::FilePath(); + } + path = path.Append(GetInstallParentDirectoryName()) + .Append(kCredentialProviderFolder) + .Append(file_dir) + .Append(sid); + return path; +} + } // namespace // GoogleRegistrationDataForTesting ////////////////////////////////////////// @@ -1255,4 +1279,62 @@ return url; } +std::unique_ptr<base::File> GetOpenedFileForUser( + const base::string16& sid, + uint32_t open_flags, + const base::string16& file_dir, + const base::string16& file_name) { + base::FilePath experiments_dir = GetDirectoryFilePath(sid, file_dir); + if (!base::DirectoryExists(experiments_dir)) { + base::File::Error error; + if (!CreateDirectoryAndGetError(experiments_dir, &error)) { + LOGFN(ERROR) << "Experiments data directory could not be created for " + << sid << " Error: " << error; + return nullptr; + } + } + + base::FilePath experiments_file_path = experiments_dir.Append(file_name); + std::unique_ptr<base::File> experiments_file( + new base::File(experiments_file_path, open_flags)); + + if (!experiments_file->IsValid()) { + LOGFN(ERROR) << "Error opening experiments file for user " << sid + << " with flags " << open_flags + << " Error: " << experiments_file->error_details(); + return nullptr; + } + + base::File::Error lock_error = + experiments_file->Lock(base::File::LockMode::kExclusive); + if (lock_error != base::File::FILE_OK) { + LOGFN(ERROR) + << "Failed to obtain exclusive lock on experiments file! Error: " + << lock_error; + return nullptr; + } + + return experiments_file; +} + +base::TimeDelta GetTimeDeltaSinceLastFetch(const base::string16& sid, + const base::string16& flag) { + wchar_t last_fetch_millis[512]; + ULONG last_fetch_size = base::size(last_fetch_millis); + HRESULT hr = GetUserProperty(sid, flag, last_fetch_millis, &last_fetch_size); + + if (FAILED(hr)) { + return base::TimeDelta::Max(); + } + + int64_t last_fetch_millis_int64; + base::StringToInt64(last_fetch_millis, &last_fetch_millis_int64); + + int64_t time_delta_from_last_fetch_ms = + base::Time::Now().ToDeltaSinceWindowsEpoch().InMilliseconds() - + last_fetch_millis_int64; + + return base::TimeDelta::FromMilliseconds(time_delta_from_last_fetch_ms); +} + } // namespace credential_provider
diff --git a/chrome/credential_provider/gaiacp/gcp_utils.h b/chrome/credential_provider/gaiacp/gcp_utils.h index b9cb3a4..2a932412 100644 --- a/chrome/credential_provider/gaiacp/gcp_utils.h +++ b/chrome/credential_provider/gaiacp/gcp_utils.h
@@ -10,6 +10,7 @@ #include <string> #include "base/callback.h" +#include "base/files/file.h" #include "base/files/file_path.h" #include "base/strings/string16.h" #include "base/values.h" @@ -75,6 +76,14 @@ // again. extern const base::TimeDelta kMaxTimeDeltaSinceLastUserPolicyRefresh; +// Maximum allowed time delta after which experiments should be fetched +// again. +extern const base::TimeDelta kMaxTimeDeltaSinceLastExperimentsFetch; + +// Path elements for the path where the experiments are stored on disk. +extern const wchar_t kGcpwExperimentsDirectory[]; +extern const wchar_t kGcpwUserExperimentsFileName[]; + // Because of some strange dependency problems with windows header files, // define STATUS_SUCCESS here instead of including ntstatus.h or SubAuth.h #define STATUS_SUCCESS ((NTSTATUS)0x00000000L) @@ -404,6 +413,20 @@ base::string16 GetDevelopmentUrl(const base::string16& url, const base::string16& dev); +// Returns a handle to a file which is stored under DIR_COMMON_APP_DATA > |sid| +// > |file_dir| > |file_name|. The file is opened with the provided +// |open_flags|. +std::unique_ptr<base::File> GetOpenedFileForUser( + const base::string16& sid, + uint32_t open_flags, + const base::string16& file_dir, + const base::string16& file_name); + +// Returns the time delta since the last fetch for the given |sid|. |flag| +// stores the last fetch time. +base::TimeDelta GetTimeDeltaSinceLastFetch(const base::string16& sid, + const base::string16& flag); + } // namespace credential_provider #endif // CHROME_CREDENTIAL_PROVIDER_GAIACP_GCP_UTILS_H_
diff --git a/chrome/credential_provider/gaiacp/gem_device_details_manager.cc b/chrome/credential_provider/gaiacp/gem_device_details_manager.cc index 5e60d6d..4a2fdfb 100644 --- a/chrome/credential_provider/gaiacp/gem_device_details_manager.cc +++ b/chrome/credential_provider/gaiacp/gem_device_details_manager.cc
@@ -59,6 +59,10 @@ const wchar_t kUploadDeviceDetailsFromEsaEnabledRegKey[] = L"upload_device_details_from_esa"; +// The period of uploading device details to the backend. +const base::TimeDelta kUploadDeviceDetailsExecutionPeriod = + base::TimeDelta::FromHours(3); + // True when upload device details from ESA feature is enabled. bool g_upload_device_details_from_esa_enabled = false; @@ -74,8 +78,12 @@ } // ESA calls this to retrieve a configuration for the task execution. Return - // a default config for now. - extension::Config GetConfig() final { return extension::Config(); } + // 3 hours period for uploading device details. + extension::Config GetConfig() final { + extension::Config config; + config.execution_period = kUploadDeviceDetailsExecutionPeriod; + return config; + } // ESA calls this to set all the user-device contexts for the execution of the // task.
diff --git a/chrome/credential_provider/gaiacp/reg_utils.cc b/chrome/credential_provider/gaiacp/reg_utils.cc index bf14a8e..9bb0af64 100644 --- a/chrome/credential_provider/gaiacp/reg_utils.cc +++ b/chrome/credential_provider/gaiacp/reg_utils.cc
@@ -65,6 +65,10 @@ constexpr wchar_t kEmailDomainsKey[] = L"ed"; // deprecated. constexpr wchar_t kEmailDomainsKeyNew[] = L"domains_allowed_to_login"; +const wchar_t kLastUserPolicyRefreshTimeRegKey[] = L"last_policy_refresh_time"; +const wchar_t kLastUserExperimentsRefreshTimeRegKey[] = + L"last_experiments_refresh_time"; + namespace { constexpr wchar_t kAccountPicturesRootRegKey[] =
diff --git a/chrome/credential_provider/gaiacp/reg_utils.h b/chrome/credential_provider/gaiacp/reg_utils.h index f9b7cea..f7f2407 100644 --- a/chrome/credential_provider/gaiacp/reg_utils.h +++ b/chrome/credential_provider/gaiacp/reg_utils.h
@@ -83,6 +83,14 @@ extern const wchar_t kEmailDomainsKey[]; // Older deprecated key. extern const wchar_t kEmailDomainsKeyNew[]; +// Registry key where the the last time the policy is refreshed for the user is +// stored. +extern const wchar_t kLastUserPolicyRefreshTimeRegKey[]; + +// Registry key where the the last time the experiments is refreshed for the +// user is stored. +extern const wchar_t kLastUserExperimentsRefreshTimeRegKey[]; + // Gets any HKLM registry key on the system. HRESULT GetMachineRegDWORD(const base::string16& key_name, const base::string16& name,
diff --git a/chrome/credential_provider/gaiacp/user_policies_manager.cc b/chrome/credential_provider/gaiacp/user_policies_manager.cc index c21236b..a52c705b 100644 --- a/chrome/credential_provider/gaiacp/user_policies_manager.cc +++ b/chrome/credential_provider/gaiacp/user_policies_manager.cc
@@ -41,13 +41,8 @@ base::TimeDelta::FromMilliseconds(5000); // Path elements for the path where the policies are stored on disk. -constexpr base::FilePath::CharType kGcpwPoliciesDirectory[] = L"Policies"; -constexpr base::FilePath::CharType kGcpwUserPolicyFileName[] = - L"PolicyFetchResponse"; - -// Registry key where the the last time the policy is refreshed for the user is -// stored. -const wchar_t kLastUserPolicyRefreshTimeRegKey[] = L"last_policy_refresh_time"; +constexpr wchar_t kGcpwPoliciesDirectory[] = L"Policies"; +constexpr wchar_t kGcpwUserPolicyFileName[] = L"PolicyFetchResponse"; // Maximum number of retries if a HTTP call to the backend fails. constexpr unsigned int kMaxNumHttpRetries = 1; @@ -59,60 +54,13 @@ // policies. const char kPolicyFetchResponseKeyName[] = "policies"; +// The period of refreshing cloud policies. +const base::TimeDelta kCloudPoliciesExecutionPeriod = + base::TimeDelta::FromHours(1); + // True when cloud policies feature is enabled. bool g_cloud_policies_enabled = false; -// Get the path to the directory where the policies will be stored for the user -// with |sid|. -base::FilePath GetUserPolicyDirectoryFilePath(const base::string16& sid) { - base::FilePath path; - if (!base::PathService::Get(base::DIR_COMMON_APP_DATA, &path)) { - HRESULT hr = HRESULT_FROM_WIN32(::GetLastError()); - LOGFN(ERROR) << "PathService::Get(DIR_COMMON_APP_DATA) hr=" << putHR(hr); - return base::FilePath(); - } - path = path.Append(GetInstallParentDirectoryName()) - .Append(kCredentialProviderFolder) - .Append(kGcpwPoliciesDirectory) - .Append(sid); - return path; -} - -std::unique_ptr<base::File> GetOpenedPolicyFileForUser( - const base::string16& sid, - uint32_t open_flags) { - base::FilePath policy_dir = GetUserPolicyDirectoryFilePath(sid); - if (!base::DirectoryExists(policy_dir)) { - base::File::Error error; - if (!CreateDirectoryAndGetError(policy_dir, &error)) { - LOGFN(ERROR) << "Policy data directory could not be created for " << sid - << " Error: " << error; - return nullptr; - } - } - - base::FilePath policy_file_path = policy_dir.Append(kGcpwUserPolicyFileName); - std::unique_ptr<base::File> policy_file( - new base::File(policy_file_path, open_flags)); - - if (!policy_file->IsValid()) { - LOGFN(ERROR) << "Error opening policy file for user " << sid - << " with flags " << open_flags - << " Error: " << policy_file->error_details(); - return nullptr; - } - - base::File::Error lock_error = - policy_file->Lock(base::File::LockMode::kExclusive); - if (lock_error != base::File::FILE_OK) { - LOGFN(ERROR) << "Failed to obtain exclusive lock on policy file! Error: " - << lock_error; - return nullptr; - } - - return policy_file; -} - // Creates the URL used to fetch the policies from the backend based on the // credential present (OAuth vs DM token) for authentication. GURL GetFetchUserPoliciesUrl(const base::string16& sid, @@ -163,8 +111,12 @@ } // ESA calls this to retrieve a configuration for the task execution. Return - // a default config for now. - extension::Config GetConfig() final { return extension::Config(); } + // the 1 hour period for the user policies fetch. + extension::Config GetConfig() final { + extension::Config config; + config.execution_period = kCloudPoliciesExecutionPeriod; + return config; + } // ESA calls this to set all the user-device contexts for the execution of the // task. @@ -294,8 +246,8 @@ uint32_t open_flags = base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE | base::File::FLAG_EXCLUSIVE_WRITE; - std::unique_ptr<base::File> policy_file = - GetOpenedPolicyFileForUser(sid, open_flags); + std::unique_ptr<base::File> policy_file = GetOpenedFileForUser( + sid, open_flags, kGcpwPoliciesDirectory, kGcpwUserPolicyFileName); if (!policy_file) { return (fetch_status_ = E_FAIL); } @@ -322,35 +274,14 @@ return (fetch_status_ = S_OK); } -base::TimeDelta UserPoliciesManager::GetTimeDeltaSinceLastPolicyFetch( - const base::string16& sid) const { - wchar_t last_fetch_millis[512]; - ULONG last_fetch_size = base::size(last_fetch_millis); - HRESULT hr = GetUserProperty(sid, kLastUserPolicyRefreshTimeRegKey, - last_fetch_millis, &last_fetch_size); - - if (FAILED(hr)) { - // The policy was never fetched before. - return base::TimeDelta::Max(); - } - - int64_t last_fetch_millis_int64; - base::StringToInt64(last_fetch_millis, &last_fetch_millis_int64); - - int64_t time_delta_from_last_fetch_ms = - base::Time::Now().ToDeltaSinceWindowsEpoch().InMilliseconds() - - last_fetch_millis_int64; - - return base::TimeDelta::FromMilliseconds(time_delta_from_last_fetch_ms); -} bool UserPoliciesManager::GetUserPolicies(const base::string16& sid, UserPolicies* user_policies) const { DCHECK(user_policies); uint32_t open_flags = base::File::FLAG_OPEN | base::File::FLAG_READ; - std::unique_ptr<base::File> policy_file = - GetOpenedPolicyFileForUser(sid, open_flags); + std::unique_ptr<base::File> policy_file = GetOpenedFileForUser( + sid, open_flags, kGcpwPoliciesDirectory, kGcpwUserPolicyFileName); if (!policy_file) { return false; } @@ -387,7 +318,7 @@ return true; } - if (GetTimeDeltaSinceLastPolicyFetch(sid) > + if (GetTimeDeltaSinceLastFetch(sid, kLastUserPolicyRefreshTimeRegKey) > kMaxTimeDeltaSinceLastUserPolicyRefresh) { return true; }
diff --git a/chrome/credential_provider/gaiacp/user_policies_manager.h b/chrome/credential_provider/gaiacp/user_policies_manager.h index e8d7ef3..e1dac38 100644 --- a/chrome/credential_provider/gaiacp/user_policies_manager.h +++ b/chrome/credential_provider/gaiacp/user_policies_manager.h
@@ -42,11 +42,6 @@ virtual HRESULT FetchAndStoreCloudUserPolicies( const extension::UserDeviceContext& context); - // Return the elapsed time delta since the last time the policies were - // successfully fetched for the user with |sid|. - base::TimeDelta GetTimeDeltaSinceLastPolicyFetch( - const base::string16& sid) const; - // Get the URL of GCPW service for HTTP request for fetching user policies // when the caller has a valid OAuth token for authentication. GURL GetGcpwServiceUserPoliciesUrl(const base::string16& sid);
diff --git a/chrome/credential_provider/test/BUILD.gn b/chrome/credential_provider/test/BUILD.gn index e540efa4..b4fd8be 100644 --- a/chrome/credential_provider/test/BUILD.gn +++ b/chrome/credential_provider/test/BUILD.gn
@@ -11,6 +11,7 @@ "../extension/task_manager_unittests.cc", "../gaiacp/associated_user_validator_unittests.cc", "../gaiacp/device_policies_manager_unittests.cc", + "../gaiacp/experiments_manager_unittests.cc", "../gaiacp/gaia_credential_base_unittests.cc", "../gaiacp/gaia_credential_other_user_unittests.cc", "../gaiacp/gaia_credential_provider_unittests.cc",
diff --git a/chrome/credential_provider/test/gcp_fakes.cc b/chrome/credential_provider/test/gcp_fakes.cc index 9a724e2..3e3c998 100644 --- a/chrome/credential_provider/test/gcp_fakes.cc +++ b/chrome/credential_provider/test/gcp_fakes.cc
@@ -1399,8 +1399,7 @@ /////////////////////////////////////////////////////////////////////////////// -FakeTaskManager::FakeTaskManager() - : task_manager_(*GetInstanceStorage()), num_of_times_executed_(0) { +FakeTaskManager::FakeTaskManager() : task_manager_(*GetInstanceStorage()) { *GetInstanceStorage() = this; } @@ -1408,20 +1407,12 @@ *GetInstanceStorage() = task_manager_; } -void FakeTaskManager::RunTasksInternal() { - if (start_time_.is_null()) { - start_time_ = base::Time::Now(); - } +void FakeTaskManager::ExecuteTask( + scoped_refptr<base::SingleThreadTaskRunner> task_runner, + const std::string& task_name) { + num_of_times_executed_[task_name]++; - int64_t start_hour = start_time_.ToDeltaSinceWindowsEpoch().InHours(); - num_of_times_executed_++; - - int64_t current = base::Time::Now().ToDeltaSinceWindowsEpoch().InHours(); - - ASSERT_EQ(current - start_hour, (num_of_times_executed_ - 1) * 1) - << (current - start_hour) << " hours since first run"; - - TaskManager::RunTasksInternal(); + TaskManager::ExecuteTask(task_runner, task_name); } ///////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/credential_provider/test/gcp_fakes.h b/chrome/credential_provider/test/gcp_fakes.h index 575e86e..64afb92 100644 --- a/chrome/credential_provider/test/gcp_fakes.h +++ b/chrome/credential_provider/test/gcp_fakes.h
@@ -17,6 +17,7 @@ #include "base/synchronization/waitable_event.h" #include "base/test/test_reg_util_win.h" #include "base/win/scoped_handle.h" +#include "chrome/credential_provider/extension/extension_utils.h" #include "chrome/credential_provider/extension/os_service_manager.h" #include "chrome/credential_provider/extension/task_manager.h" #include "chrome/credential_provider/gaiacp/associated_user_validator.h" @@ -733,16 +734,19 @@ FakeTaskManager(); ~FakeTaskManager() override; - int NumOfTimesExecuted() { return num_of_times_executed_; } + int NumOfTimesExecuted(const std::string& task_name) { + return num_of_times_executed_[task_name]; + } private: - void RunTasksInternal() override; + void ExecuteTask(scoped_refptr<base::SingleThreadTaskRunner> task_runner, + const std::string& task_name) override; // Original instance of TaskManager. extension::TaskManager* task_manager_ = nullptr; - int num_of_times_executed_; - base::Time start_time_; + // Counts the number of execution per task. + std::map<std::string, int> num_of_times_executed_; }; ///////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 6cec255..01348211 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -1223,6 +1223,7 @@ "../browser/policy/content_settings_policy_browsertest.cc", "../browser/policy/default_search_provider_policy_browsertest.cc", "../browser/policy/developer_tools_policy_browsertest.cc", + "../browser/policy/download_directory_browsertest.cc", "../browser/policy/force_google_safe_search_policy_browsertest.cc", "../browser/policy/hide_webstore_icon_policy_browsertest.cc", "../browser/policy/hsts_policy_browsertest.cc",
diff --git a/chrome/test/DIR_METADATA b/chrome/test/DIR_METADATA new file mode 100644 index 0000000..9d880f7 --- /dev/null +++ b/chrome/test/DIR_METADATA
@@ -0,0 +1,3 @@ +monorail { + component: "Tests" +}
diff --git a/chrome/test/OWNERS b/chrome/test/OWNERS index 879ea43..eb982b0 100644 --- a/chrome/test/OWNERS +++ b/chrome/test/OWNERS
@@ -1,3 +1,2 @@ # If you're doing structural changes get a review from one of the OWNERS. -per-file BUILD.gn=* -# COMPONENT: Tests +per-file BUILD.gn=* \ No newline at end of file
diff --git a/chrome/test/android/DIR_METADATA b/chrome/test/android/DIR_METADATA new file mode 100644 index 0000000..a0d027c --- /dev/null +++ b/chrome/test/android/DIR_METADATA
@@ -0,0 +1,4 @@ +monorail { + component: "Test>Android" +} +os: ANDROID
diff --git a/chrome/test/android/OWNERS b/chrome/test/android/OWNERS index 0dda74c3..d6813a6 100644 --- a/chrome/test/android/OWNERS +++ b/chrome/test/android/OWNERS
@@ -1,6 +1,3 @@ file://chrome/android/OWNERS per-file BUILD.gn=* - -# COMPONENT: Test>Android -# OS: Android
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/sync/DIR_METADATA b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/sync/DIR_METADATA new file mode 100644 index 0000000..1a6d7ee6 --- /dev/null +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/sync/DIR_METADATA
@@ -0,0 +1,3 @@ +monorail { + component: "Services>Sync" +}
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/sync/OWNERS b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/sync/OWNERS index 68a2d2e..653d59b 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/sync/OWNERS +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/sync/OWNERS
@@ -2,5 +2,3 @@ nyquist@chromium.org yfriedman@chromium.org - -# COMPONENT: Services>Sync
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/webapps/DIR_METADATA b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/webapps/DIR_METADATA new file mode 100644 index 0000000..320129e --- /dev/null +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/webapps/DIR_METADATA
@@ -0,0 +1,3 @@ +monorail { + component: "UI>Browser>WebAppInstalls" +}
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/webapps/OWNERS b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/webapps/OWNERS index 23ff013..7b6517c 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/webapps/OWNERS +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/webapps/OWNERS
@@ -1,3 +1 @@ file://chrome/android/java/src/org/chromium/chrome/browser/webapps/OWNERS - -# COMPONENT: UI>Browser>WebAppInstalls
diff --git a/chrome/test/android/test_trusted_web_activity/DIR_METADATA b/chrome/test/android/test_trusted_web_activity/DIR_METADATA new file mode 100644 index 0000000..e83fdb9 --- /dev/null +++ b/chrome/test/android/test_trusted_web_activity/DIR_METADATA
@@ -0,0 +1,4 @@ +monorail { + component: "UI>Browser>Mobile>TrustedWebActivities" +} +os: ANDROID
diff --git a/chrome/test/android/test_trusted_web_activity/OWNERS b/chrome/test/android/test_trusted_web_activity/OWNERS index 928f320..f5d6db69 100644 --- a/chrome/test/android/test_trusted_web_activity/OWNERS +++ b/chrome/test/android/test_trusted_web_activity/OWNERS
@@ -1,4 +1 @@ peconn@chromium.org - -# COMPONENT: UI>Browser>Mobile>TrustedWebActivities -# OS: Android
diff --git a/chrome/test/base/android/DIR_METADATA b/chrome/test/base/android/DIR_METADATA new file mode 100644 index 0000000..a0d027c --- /dev/null +++ b/chrome/test/base/android/DIR_METADATA
@@ -0,0 +1,4 @@ +monorail { + component: "Test>Android" +} +os: ANDROID
diff --git a/chrome/test/base/android/OWNERS b/chrome/test/base/android/OWNERS index 9a5ecc6..fa6e7ab 100644 --- a/chrome/test/base/android/OWNERS +++ b/chrome/test/base/android/OWNERS
@@ -1,4 +1 @@ file://chrome/test/android/OWNERS - -# COMPONENT: Test>Android -# OS: Android
diff --git a/chrome/test/chromedriver/DIR_METADATA b/chrome/test/chromedriver/DIR_METADATA new file mode 100644 index 0000000..c073cf0c --- /dev/null +++ b/chrome/test/chromedriver/DIR_METADATA
@@ -0,0 +1,3 @@ +monorail { + component: "Test>WebDriver" +}
diff --git a/chrome/test/chromedriver/OWNERS b/chrome/test/chromedriver/OWNERS index 99fdd6e..d24dd3f 100644 --- a/chrome/test/chromedriver/OWNERS +++ b/chrome/test/chromedriver/OWNERS
@@ -3,5 +3,3 @@ # secondary reviewer johnchen@chromium.org - -# COMPONENT: Test>WebDriver
diff --git a/chrome/test/data/DIR_METADATA b/chrome/test/data/DIR_METADATA new file mode 100644 index 0000000..7779236 --- /dev/null +++ b/chrome/test/data/DIR_METADATA
@@ -0,0 +1,3 @@ +monorail { + component: "Test" +}
diff --git a/chrome/test/data/OWNERS b/chrome/test/data/OWNERS index 177e36d..f59ec20 100644 --- a/chrome/test/data/OWNERS +++ b/chrome/test/data/OWNERS
@@ -1,2 +1 @@ -* -# COMPONENT: Test +* \ No newline at end of file
diff --git a/chrome/test/data/extensions/api_test/certificate_provider/DIR_METADATA b/chrome/test/data/extensions/api_test/certificate_provider/DIR_METADATA new file mode 100644 index 0000000..3ecb477 --- /dev/null +++ b/chrome/test/data/extensions/api_test/certificate_provider/DIR_METADATA
@@ -0,0 +1,3 @@ +monorail { + component: "Enterprise" +}
diff --git a/chrome/test/data/extensions/api_test/certificate_provider/OWNERS b/chrome/test/data/extensions/api_test/certificate_provider/OWNERS index 6835e98..325f7c3 100644 --- a/chrome/test/data/extensions/api_test/certificate_provider/OWNERS +++ b/chrome/test/data/extensions/api_test/certificate_provider/OWNERS
@@ -1,3 +1 @@ emaxx@chromium.org - -# COMPONENT: Enterprise
diff --git a/chrome/test/data/extensions/api_test/enterprise_device_attributes/DIR_METADATA b/chrome/test/data/extensions/api_test/enterprise_device_attributes/DIR_METADATA new file mode 100644 index 0000000..3ecb477 --- /dev/null +++ b/chrome/test/data/extensions/api_test/enterprise_device_attributes/DIR_METADATA
@@ -0,0 +1,3 @@ +monorail { + component: "Enterprise" +}
diff --git a/chrome/test/data/extensions/api_test/enterprise_device_attributes/OWNERS b/chrome/test/data/extensions/api_test/enterprise_device_attributes/OWNERS index 10a65a81..eca9776 100644 --- a/chrome/test/data/extensions/api_test/enterprise_device_attributes/OWNERS +++ b/chrome/test/data/extensions/api_test/enterprise_device_attributes/OWNERS
@@ -1,4 +1,2 @@ emaxx@chromium.org pbond@chromium.org - -# COMPONENT: Enterprise
diff --git a/chrome/test/data/extensions/api_test/enterprise_networking_attributes/DIR_METADATA b/chrome/test/data/extensions/api_test/enterprise_networking_attributes/DIR_METADATA new file mode 100644 index 0000000..3ecb477 --- /dev/null +++ b/chrome/test/data/extensions/api_test/enterprise_networking_attributes/DIR_METADATA
@@ -0,0 +1,3 @@ +monorail { + component: "Enterprise" +}
diff --git a/chrome/test/data/extensions/api_test/enterprise_networking_attributes/OWNERS b/chrome/test/data/extensions/api_test/enterprise_networking_attributes/OWNERS index d11193d..aef9c2c4 100644 --- a/chrome/test/data/extensions/api_test/enterprise_networking_attributes/OWNERS +++ b/chrome/test/data/extensions/api_test/enterprise_networking_attributes/OWNERS
@@ -1,3 +1 @@ hendrich@chromium.org - -# COMPONENT: Enterprise
diff --git a/chrome/test/data/extensions/api_test/enterprise_platform_keys/DIR_METADATA b/chrome/test/data/extensions/api_test/enterprise_platform_keys/DIR_METADATA new file mode 100644 index 0000000..3ecb477 --- /dev/null +++ b/chrome/test/data/extensions/api_test/enterprise_platform_keys/DIR_METADATA
@@ -0,0 +1,3 @@ +monorail { + component: "Enterprise" +}
diff --git a/chrome/test/data/extensions/api_test/enterprise_platform_keys/OWNERS b/chrome/test/data/extensions/api_test/enterprise_platform_keys/OWNERS index 6835e98..325f7c3 100644 --- a/chrome/test/data/extensions/api_test/enterprise_platform_keys/OWNERS +++ b/chrome/test/data/extensions/api_test/enterprise_platform_keys/OWNERS
@@ -1,3 +1 @@ emaxx@chromium.org - -# COMPONENT: Enterprise
diff --git a/chrome/test/data/extensions/api_test/platform_keys/DIR_METADATA b/chrome/test/data/extensions/api_test/platform_keys/DIR_METADATA new file mode 100644 index 0000000..3ecb477 --- /dev/null +++ b/chrome/test/data/extensions/api_test/platform_keys/DIR_METADATA
@@ -0,0 +1,3 @@ +monorail { + component: "Enterprise" +}
diff --git a/chrome/test/data/extensions/api_test/platform_keys/OWNERS b/chrome/test/data/extensions/api_test/platform_keys/OWNERS index d95b35b6..ea64ac8a 100644 --- a/chrome/test/data/extensions/api_test/platform_keys/OWNERS +++ b/chrome/test/data/extensions/api_test/platform_keys/OWNERS
@@ -1,5 +1,3 @@ emaxx@chromium.org omorsi@google.com pmarko@chromium.org - -# COMPONENT: Enterprise
diff --git a/chrome/test/data/extensions/api_test/tts/pause_speak_no_enqueue/test.js b/chrome/test/data/extensions/api_test/tts/pause_speak_no_enqueue/test.js index 6762b1e..af5f8b2d 100644 --- a/chrome/test/data/extensions/api_test/tts/pause_speak_no_enqueue/test.js +++ b/chrome/test/data/extensions/api_test/tts/pause_speak_no_enqueue/test.js
@@ -5,38 +5,12 @@ // TTS api test for Chrome. // browser_tests.exe --gtest_filter="TtsApiTest.*" -chrome.test.runTests([ - function testPauseCancel() { - var callbacks = 0; - chrome.tts.pause(); - chrome.tts.speak( - 'text 1', - { - 'enqueue': true, - 'onEvent': function(event) { - chrome.test.assertEq('cancelled', event.type); - callbacks++; - } - }, - function() { - chrome.test.assertNoLastError(); - callbacks++; - }); - chrome.tts.speak( - 'text 2', - { - 'enqueue': false, - 'onEvent': function(event) { - chrome.test.assertEq('cancelled', event.type); - callbacks++; - if (callbacks == 4) { - chrome.test.succeed(); - } - } - }, - function() { - chrome.test.assertNoLastError(); - callbacks++; - }); - } -]); +chrome.test.runTests([function testPauseCancel() { + chrome.tts.pause(); + chrome.tts.speak('text 1', {'enqueue': true}); + chrome.tts.speak('text 2', {'enqueue': false}, function() { + chrome.test.assertNoLastError(); + chrome.test.succeed(); + }); + chrome.tts.resume(); +}]);
diff --git a/chrome/test/data/extensions/api_test/vpn_provider/DIR_METADATA b/chrome/test/data/extensions/api_test/vpn_provider/DIR_METADATA new file mode 100644 index 0000000..3ecb477 --- /dev/null +++ b/chrome/test/data/extensions/api_test/vpn_provider/DIR_METADATA
@@ -0,0 +1,3 @@ +monorail { + component: "Enterprise" +}
diff --git a/chrome/test/data/extensions/api_test/vpn_provider/OWNERS b/chrome/test/data/extensions/api_test/vpn_provider/OWNERS index e1cacf4d..a913a05 100644 --- a/chrome/test/data/extensions/api_test/vpn_provider/OWNERS +++ b/chrome/test/data/extensions/api_test/vpn_provider/OWNERS
@@ -1,4 +1,2 @@ bartfab@chromium.org emaxx@chromium.org - -# COMPONENT: Enterprise
diff --git a/chrome/test/data/extensions/platform_apps/web_view/DIR_METADATA b/chrome/test/data/extensions/platform_apps/web_view/DIR_METADATA new file mode 100644 index 0000000..22d44120c --- /dev/null +++ b/chrome/test/data/extensions/platform_apps/web_view/DIR_METADATA
@@ -0,0 +1,3 @@ +monorail { + component: "Platform>Apps>BrowserTag" +}
diff --git a/chrome/test/data/extensions/platform_apps/web_view/OWNERS b/chrome/test/data/extensions/platform_apps/web_view/OWNERS index 74d34105..4da9c54 100644 --- a/chrome/test/data/extensions/platform_apps/web_view/OWNERS +++ b/chrome/test/data/extensions/platform_apps/web_view/OWNERS
@@ -1,3 +1 @@ file://components/guest_view/OWNERS - -# COMPONENT: Platform>Apps>BrowserTag
diff --git a/chrome/test/data/extensions/signin_screen_manual_test_app/DIR_METADATA b/chrome/test/data/extensions/signin_screen_manual_test_app/DIR_METADATA new file mode 100644 index 0000000..3ecb477 --- /dev/null +++ b/chrome/test/data/extensions/signin_screen_manual_test_app/DIR_METADATA
@@ -0,0 +1,3 @@ +monorail { + component: "Enterprise" +}
diff --git a/chrome/test/data/extensions/signin_screen_manual_test_app/OWNERS b/chrome/test/data/extensions/signin_screen_manual_test_app/OWNERS index fdcf3459..593f4a2 100644 --- a/chrome/test/data/extensions/signin_screen_manual_test_app/OWNERS +++ b/chrome/test/data/extensions/signin_screen_manual_test_app/OWNERS
@@ -1,4 +1,2 @@ emaxx@chromium.org achuith@chromium.org - -# COMPONENT: Enterprise
diff --git a/chrome/test/data/media/engagement/DIR_METADATA b/chrome/test/data/media/engagement/DIR_METADATA new file mode 100644 index 0000000..6667e7f --- /dev/null +++ b/chrome/test/data/media/engagement/DIR_METADATA
@@ -0,0 +1,3 @@ +monorail { + component: "Internals>Media" +}
diff --git a/chrome/test/data/media/engagement/OWNERS b/chrome/test/data/media/engagement/OWNERS index 2b1712e..bc09da7 100644 --- a/chrome/test/data/media/engagement/OWNERS +++ b/chrome/test/data/media/engagement/OWNERS
@@ -1,4 +1,2 @@ mlamouri@chromium.org beccahughes@chromium.org - -# COMPONENT: Internals>Media
diff --git a/chrome/test/data/nacl/DIR_METADATA b/chrome/test/data/nacl/DIR_METADATA new file mode 100644 index 0000000..096cb71 --- /dev/null +++ b/chrome/test/data/nacl/DIR_METADATA
@@ -0,0 +1,3 @@ +monorail { + component: "Platform>NaCl" +}
diff --git a/chrome/test/data/nacl/OWNERS b/chrome/test/data/nacl/OWNERS index cb02b14..8e3867c 100644 --- a/chrome/test/data/nacl/OWNERS +++ b/chrome/test/data/nacl/OWNERS
@@ -1,4 +1,2 @@ bradnelson@chromium.org mseaborn@chromium.org - -# COMPONENT: Platform>NaCl
diff --git a/chrome/test/data/webui/BUILD.gn b/chrome/test/data/webui/BUILD.gn index ce09dbf9..c28bd70 100644 --- a/chrome/test/data/webui/BUILD.gn +++ b/chrome/test/data/webui/BUILD.gn
@@ -128,6 +128,7 @@ if (is_chromeos) { sources += [ + "../../../browser/resources/chromeos/login/components/oobe_types.js", "../../../browser/resources/chromeos/login/security_token_pin_browsertest.js", "../../../browser/ui/webui/chromeos/bluetooth_pairing_dialog_browsertest.js", "../../../browser/ui/webui/chromeos/certificate_manager_dialog_browsertest.js",
diff --git a/chrome/test/data/webui/DIR_METADATA b/chrome/test/data/webui/DIR_METADATA new file mode 100644 index 0000000..8325efa --- /dev/null +++ b/chrome/test/data/webui/DIR_METADATA
@@ -0,0 +1,3 @@ +monorail { + component: "UI>Browser>WebUI" +}
diff --git a/chrome/test/data/webui/OWNERS b/chrome/test/data/webui/OWNERS index 556d58a5..6ca9856 100644 --- a/chrome/test/data/webui/OWNERS +++ b/chrome/test/data/webui/OWNERS
@@ -2,5 +2,3 @@ per-file *.mojom=set noparent per-file *.mojom=file://ipc/SECURITY_OWNERS - -# COMPONENT: UI>Browser>WebUI
diff --git a/chrome/test/data/webui/chromeos/diagnostics/battery_status_card_test.js b/chrome/test/data/webui/chromeos/diagnostics/battery_status_card_test.js index 5d429d3..8bbc135 100644 --- a/chrome/test/data/webui/chromeos/diagnostics/battery_status_card_test.js +++ b/chrome/test/data/webui/chromeos/diagnostics/battery_status_card_test.js
@@ -64,6 +64,35 @@ return flushTasks(); } + /** + * Returns the routine-section from the card. + * @return {!RoutineSectionElement} + */ + function getRoutineSection() { + const routineSection = /** @type {!RoutineSectionElement} */ ( + batteryStatusElement.$$('routine-section')); + assertTrue(!!routineSection); + return routineSection; + } + + /** + * Returns the Run Tests button from inside the routine-section. + * @return {!CrButtonElement} + */ + function getRunTestsButton() { + const button = dx_utils.getRunTestsButtonFromSection(getRoutineSection()); + assertTrue(!!button); + return button; + } + + /** + * Returns whether the run tests button is disabled. + * @return {boolean} + */ + function isRunTestsButtonDisabled() { + return getRunTestsButton().disabled; + } + test('BatteryStatusCardPopulated', () => { return initializeBatteryStatusCard( fakeBatteryInfo, fakeBatteryChargeStatus, fakeBatteryHealth) @@ -93,6 +122,11 @@ const diagnosticsCard = dx_utils.getDiagnosticsCard(batteryStatusElement); assertTrue(isChildVisible(diagnosticsCard, '.data-points')); + + // Verify the routine section is in the card. + assertTrue(!!getRoutineSection()); + assertTrue(!!getRunTestsButton()); + assertFalse(isRunTestsButtonDisabled()); }); }); }
diff --git a/chrome/test/data/webui/chromeos/diagnostics/fake_system_routine_controller_test.js b/chrome/test/data/webui/chromeos/diagnostics/fake_system_routine_controller_test.js index b26a0c1c..5f26ec92 100644 --- a/chrome/test/data/webui/chromeos/diagnostics/fake_system_routine_controller_test.js +++ b/chrome/test/data/webui/chromeos/diagnostics/fake_system_routine_controller_test.js
@@ -35,7 +35,22 @@ const routineRunnerRemote = { onRoutineResult: (resultInfo) => { assertEquals(expectedName, resultInfo.name); - assertEquals(expectedResult, resultInfo.result.simpleResult); + + if (resultInfo.result.hasOwnProperty('simpleResult')) { + assertEquals(expectedResult, resultInfo.result.simpleResult); + + // Can't have both simpleResult and batteryRateResult + assertFalse(resultInfo.result.hasOwnProperty('batteryRateResult')); + } + + if (resultInfo.result.hasOwnProperty('batteryRateResult')) { + assertEquals( + expectedResult, resultInfo.result.batteryRateResult.result); + + // Can't have both simpleResult and batteryRateResult + assertFalse(resultInfo.result.hasOwnProperty('simpleResult')); + } + resolver.resolve(); } }; @@ -119,6 +134,22 @@ return runRoutineAndAssertStandardResult(routineName, expectedResult); }); + test('ExpectedBatteryRateResultPass', () => { + const routineName = RoutineName.kCharge; + const expectedResult = StandardRoutineResult.kTestPassed; + controller.setFakeStandardRoutineResult(routineName, expectedResult); + + return runRoutineAndAssertStandardResult(routineName, expectedResult); + }); + + test('ExpectedBatteryRateResultFail', () => { + const routineName = RoutineName.kCharge; + const expectedResult = StandardRoutineResult.kTestFailed; + controller.setFakeStandardRoutineResult(routineName, expectedResult); + + return runRoutineAndAssertStandardResult(routineName, expectedResult); + }); + test('ExpectedResultPassManualResolve', () => { const routineName = RoutineName.kCpuStress; const expectedResult = StandardRoutineResult.kTestPassed;
diff --git a/chrome/test/data/webui/chromeos/diagnostics/routine_list_executor_test.js b/chrome/test/data/webui/chromeos/diagnostics/routine_list_executor_test.js index 4fd8c465..0ddae8b 100644 --- a/chrome/test/data/webui/chromeos/diagnostics/routine_list_executor_test.js +++ b/chrome/test/data/webui/chromeos/diagnostics/routine_list_executor_test.js
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import {RoutineName, RoutineResultInfo, StandardRoutineResult} from 'chrome://diagnostics/diagnostics_types.js'; +import {BatteryRateRoutineResult, RoutineName, RoutineResultInfo, StandardRoutineResult} from 'chrome://diagnostics/diagnostics_types.js'; import {FakeSystemRoutineController} from 'chrome://diagnostics/fake_system_routine_controller.js'; import {ExecutionProgress, ResultStatusItem, RoutineListExecutor} from 'chrome://diagnostics/routine_list_executor.js'; @@ -38,9 +38,22 @@ // Set the result into the fake. assertNotEquals(undefined, routine); assertNotEquals(undefined, routine.result); - assertNotEquals(undefined, routine.result.simpleResult); - controller.setFakeStandardRoutineResult( - routine.name, routine.result.simpleResult); + + // simpleResult or batteryRateResult must exist. + assertTrue( + routine.result.hasOwnProperty('simpleResult') || + routine.result.hasOwnProperty('batteryRateResult')); + + if (routine.result.hasOwnProperty('simpleResult')) { + controller.setFakeStandardRoutineResult( + routine.name, /** @type {!StandardRoutineResult} */ + (routine.result.simpleResult)); + } else { + assertTrue(routine.result.batteryRateResult.hasOwnProperty('result')); + controller.setFakeBatteryRateRoutineResult( + routine.name, /** @type {!BatteryRateRoutineResult} */ + (routine.result.batteryRateResult)); + } // Build the list of routines to run. routineNames.push(routine.name); @@ -109,7 +122,18 @@ { name: RoutineName.kPrimeSearch, result: {simpleResult: StandardRoutineResult.kTestFailed} - } + }, + { + name: RoutineName.kCharge, + result: { + batteryRateResult: { + result: StandardRoutineResult.kTestFailed, + isCharging: true, + percentDelta: 10, + timeDeltaSeconds: 10 + } + } + }, ]; return runRoutinesAndAssertResults(routines);
diff --git a/chrome/test/data/webui/chromeos/diagnostics/routine_result_entry_test.js b/chrome/test/data/webui/chromeos/diagnostics/routine_result_entry_test.js index 014b5115..ec77bca 100644 --- a/chrome/test/data/webui/chromeos/diagnostics/routine_result_entry_test.js +++ b/chrome/test/data/webui/chromeos/diagnostics/routine_result_entry_test.js
@@ -140,8 +140,9 @@ test('PassedTest', () => { const item = createCompletedStatus( - RoutineName.kCpuStress, - {simpleResult: StandardRoutineResult.kTestPassed}); + RoutineName.kCpuStress, /** @type {!RoutineResult} */ ({ + simpleResult: StandardRoutineResult.kTestPassed + })); return initializeEntryWithItem(item).then(() => { // TODO(zentaro): Localize the test. assertEquals(getNameText(), 'kCpuStress'); @@ -154,8 +155,9 @@ test('FailedTest', () => { const item = createCompletedStatus( - RoutineName.kCpuStress, - {simpleResult: StandardRoutineResult.kTestFailed}); + RoutineName.kCpuStress, /** @type {!RoutineResult} */ ({ + simpleResult: StandardRoutineResult.kTestFailed + })); return initializeEntryWithItem(item).then(() => { // TODO(zentaro): Localize the test. assertEquals(getNameText(), 'kCpuStress'); @@ -165,4 +167,24 @@ assertEquals(getStatusBadge().badgeType, BadgeType.ERROR); }); }); + + test('BatteryTest', () => { + const item = createCompletedStatus( + RoutineName.kCharge, /** @type {!RoutineResult} */ ({ + batteryRateResult: { + result: StandardRoutineResult.kTestPassed, + isCharging: true, + percentDelta: 10, + timeDeltaSeconds: 10 + } + })); + return initializeEntryWithItem(item).then(() => { + // TODO(joonbug): Localize the test. + assertEquals(getNameText(), 'kCharge'); + + // Status should show the passed result. + assertEquals(getStatusBadge().value, 'SUCCESS'); + assertEquals(getStatusBadge().badgeType, BadgeType.SUCCESS); + }); + }); }
diff --git a/chrome/test/data/webui/chromeos/diagnostics/routine_result_list_test.js b/chrome/test/data/webui/chromeos/diagnostics/routine_result_list_test.js index 950d44b..95ff047 100644 --- a/chrome/test/data/webui/chromeos/diagnostics/routine_result_list_test.js +++ b/chrome/test/data/webui/chromeos/diagnostics/routine_result_list_test.js
@@ -4,7 +4,7 @@ import 'chrome://diagnostics/routine_result_list.js'; -import {RoutineName, StandardRoutineResult} from 'chrome://diagnostics/diagnostics_types.js'; +import {RoutineName, RoutineResult, StandardRoutineResult} from 'chrome://diagnostics/diagnostics_types.js'; import {ExecutionProgress, ResultStatusItem} from 'chrome://diagnostics/routine_list_executor.js'; import {assertDeepEquals, assertEquals, assertFalse, assertNotEquals, assertTrue} from '../../chai_assert.js'; @@ -160,7 +160,8 @@ // Move the first routine to completed state. status = new ResultStatusItem(routines[0]); status.progress = ExecutionProgress.kCompleted; - status.result = {simpleResult: StandardRoutineResult.kTestPassed}; + status.result = /** @type {!RoutineResult} */ ( + {simpleResult: StandardRoutineResult.kTestPassed}); routineResultListElement.onStatusUpdate(status); return flushTasks(); @@ -189,7 +190,8 @@ // Move the second routine to completed state. status = new ResultStatusItem(routines[1]); status.progress = ExecutionProgress.kCompleted; - status.result = {simpleResult: StandardRoutineResult.kTestPassed}; + status.result = /** @type {!RoutineResult} */ ( + {simpleResult: StandardRoutineResult.kTestPassed}); routineResultListElement.onStatusUpdate(status); return flushTasks();
diff --git a/chrome/test/data/webui/multidevice_setup/DIR_METADATA b/chrome/test/data/webui/multidevice_setup/DIR_METADATA new file mode 100644 index 0000000..ea7ecb0 --- /dev/null +++ b/chrome/test/data/webui/multidevice_setup/DIR_METADATA
@@ -0,0 +1,3 @@ +monorail { + component: "OS>Systems>Multidevice" +}
diff --git a/chrome/test/data/webui/multidevice_setup/OWNERS b/chrome/test/data/webui/multidevice_setup/OWNERS index 8eaf92b2..7027ab73 100644 --- a/chrome/test/data/webui/multidevice_setup/OWNERS +++ b/chrome/test/data/webui/multidevice_setup/OWNERS
@@ -1,3 +1 @@ file://chromeos/components/multidevice/OWNERS - -# COMPONENT: OS>Systems>Multidevice
diff --git a/chrome/test/data/webui/nearby_share/DIR_METADATA b/chrome/test/data/webui/nearby_share/DIR_METADATA new file mode 100644 index 0000000..7ed7d6b --- /dev/null +++ b/chrome/test/data/webui/nearby_share/DIR_METADATA
@@ -0,0 +1,3 @@ +monorail { + component: "UI>Browser>Sharing>Nearby" +}
diff --git a/chrome/test/data/webui/nearby_share/OWNERS b/chrome/test/data/webui/nearby_share/OWNERS index 72feb28..46b5a73 100644 --- a/chrome/test/data/webui/nearby_share/OWNERS +++ b/chrome/test/data/webui/nearby_share/OWNERS
@@ -1,3 +1 @@ file://chrome/browser/nearby_sharing/OWNERS - -# COMPONENT: UI>Browser>Sharing>Nearby
diff --git a/chrome/test/data/webui/settings/DIR_METADATA b/chrome/test/data/webui/settings/DIR_METADATA new file mode 100644 index 0000000..f4b2e0ae --- /dev/null +++ b/chrome/test/data/webui/settings/DIR_METADATA
@@ -0,0 +1,3 @@ +monorail { + component: "UI>Settings" +}
diff --git a/chrome/test/data/webui/settings/OWNERS b/chrome/test/data/webui/settings/OWNERS index 07f23c7..01ccda0 100644 --- a/chrome/test/data/webui/settings/OWNERS +++ b/chrome/test/data/webui/settings/OWNERS
@@ -22,5 +22,3 @@ per-file site_settings_page_test.js=sauski@google.com per-file test_privacy_page_browser_proxy.js=sauski@google.com per-file test_site_settings_prefs_browser_proxy.js=sauski@google.com - -# COMPONENT: UI>Settings
diff --git a/chrome/test/data/webui/settings/chromeos/DIR_METADATA b/chrome/test/data/webui/settings/chromeos/DIR_METADATA new file mode 100644 index 0000000..2d34b2f4 --- /dev/null +++ b/chrome/test/data/webui/settings/chromeos/DIR_METADATA
@@ -0,0 +1,3 @@ +monorail { + component: "OS>Systems>Settings" +}
diff --git a/chrome/test/data/webui/settings/chromeos/OWNERS b/chrome/test/data/webui/settings/chromeos/OWNERS index cb914ac..da5a446 100644 --- a/chrome/test/data/webui/settings/chromeos/OWNERS +++ b/chrome/test/data/webui/settings/chromeos/OWNERS
@@ -2,5 +2,3 @@ per-file *internet*=azeemarshad@chromium.org per-file *internet*=jonmann@chromium.org - -# COMPONENT: OS>Systems>Settings
diff --git a/chrome/test/data/webui/settings/chromeos/manage_accessibility_page_tests.js b/chrome/test/data/webui/settings/chromeos/manage_accessibility_page_tests.js index 21094221..4cde486 100644 --- a/chrome/test/data/webui/settings/chromeos/manage_accessibility_page_tests.js +++ b/chrome/test/data/webui/settings/chromeos/manage_accessibility_page_tests.js
@@ -48,11 +48,31 @@ } } - function initPage() { + function initPage(opt_prefs) { page = document.createElement('settings-manage-a11y-page'); + page.prefs = opt_prefs || getDefaultPrefs(); document.body.appendChild(page); } + function getDefaultPrefs() { + return { + 'settings': { + 'a11y': { + 'tablet_mode_shelf_nav_buttons_enabled': { + key: 'settings.a11y.tablet_mode_shelf_nav_buttons_enabled', + type: chrome.settingsPrivate.PrefType.BOOLEAN, + value: false, + } + }, + 'accessibility': { + key: 'settings.accessibility', + type: chrome.settingsPrivate.PrefType.BOOLEAN, + value: false, + } + } + }; + } + setup(function() { deviceBrowserProxy = new TestDevicePageBrowserProxy(); settings.DevicePageBrowserProxyImpl.instance_ = deviceBrowserProxy; @@ -100,6 +120,87 @@ assertTrue(isVisible(page.$$('#shelfNavigationButtonsEnabledControl'))); }); + test('toggle tablet mode buttons', function() { + loadTimeData.overrideValues({ + isKioskModeActive: false, + showTabletModeShelfNavigationButtonsSettings: true, + }); + initPage(); + Polymer.dom.flush(); + + const navButtonsToggle = page.$$('#shelfNavigationButtonsEnabledControl'); + assertTrue(isVisible(navButtonsToggle)); + // The default pref value is false. + assertFalse(navButtonsToggle.checked); + + // Clicking the toggle should update the toggle checked value, and the + // backing preference. + navButtonsToggle.click(); + Polymer.dom.flush(); + + assertTrue(navButtonsToggle.checked); + assertFalse(navButtonsToggle.disabled); + assertTrue( + page.prefs.settings.a11y.tablet_mode_shelf_nav_buttons_enabled.value); + + navButtonsToggle.click(); + Polymer.dom.flush(); + + assertFalse(navButtonsToggle.checked); + assertFalse(navButtonsToggle.disabled); + assertFalse( + page.prefs.settings.a11y.tablet_mode_shelf_nav_buttons_enabled.value); + }); + + test('tablet mode buttons toggle disabled with spoken feedback', function() { + loadTimeData.overrideValues({ + isKioskModeActive: false, + showTabletModeShelfNavigationButtonsSettings: true, + }); + + prefs = getDefaultPrefs(); + // Enable spoken feedback. + prefs.settings.accessibility.value = true; + + initPage(prefs); + Polymer.dom.flush(); + + const navButtonsToggle = page.$$('#shelfNavigationButtonsEnabledControl'); + assertTrue(isVisible(navButtonsToggle)); + + // If spoken feedback is enabled, the shelf nav buttons toggle should be + // disabled and checked. + assertTrue(navButtonsToggle.disabled); + assertTrue(navButtonsToggle.checked); + + // Clicking the toggle should have no effect. + navButtonsToggle.click(); + Polymer.dom.flush(); + + assertTrue(navButtonsToggle.disabled); + assertTrue(navButtonsToggle.checked); + assertFalse( + page.prefs.settings.a11y.tablet_mode_shelf_nav_buttons_enabled.value); + + // The toggle should be enabled if the spoken feedback gets disabled. + page.set('prefs.settings.accessibility.value', false); + Polymer.dom.flush(); + + assertFalse(!!navButtonsToggle.disabled); + assertFalse(navButtonsToggle.checked); + assertFalse( + page.prefs.settings.a11y.tablet_mode_shelf_nav_buttons_enabled.value); + + // Clicking the toggle should update the backing pref. + navButtonsToggle.click(); + Polymer.dom.flush(); + + assertFalse(!!navButtonsToggle.disabled); + assertTrue(navButtonsToggle.checked); + assertTrue( + page.prefs.settings.a11y.tablet_mode_shelf_nav_buttons_enabled.value); + }); + test('some parts are hidden in kiosk mode', function() { loadTimeData.overrideValues({ isKioskModeActive: true,
diff --git a/chrome/test/data/xr/DIR_METADATA b/chrome/test/data/xr/DIR_METADATA new file mode 100644 index 0000000..4c269b7f --- /dev/null +++ b/chrome/test/data/xr/DIR_METADATA
@@ -0,0 +1,4 @@ +monorail { + component: "Internals>XR" +} +team_email: "xr-dev@chromium.org"
diff --git a/chrome/test/data/xr/OWNERS b/chrome/test/data/xr/OWNERS index b2cefae..428f610 100644 --- a/chrome/test/data/xr/OWNERS +++ b/chrome/test/data/xr/OWNERS
@@ -1,4 +1 @@ bsheedy@chromium.org - -# TEAM: xr-dev@chromium.org -# COMPONENT: Internals>XR
diff --git a/chrome/test/enterprise/DIR_METADATA b/chrome/test/enterprise/DIR_METADATA new file mode 100644 index 0000000..3ecb477 --- /dev/null +++ b/chrome/test/enterprise/DIR_METADATA
@@ -0,0 +1,3 @@ +monorail { + component: "Enterprise" +}
diff --git a/chrome/test/enterprise/OWNERS b/chrome/test/enterprise/OWNERS index 4fc3dd6d..3465889 100644 --- a/chrome/test/enterprise/OWNERS +++ b/chrome/test/enterprise/OWNERS
@@ -1,5 +1,3 @@ jxiang@google.com asanka@chromium.org uwyiming@google.com - -# COMPONENT: Enterprise
diff --git a/chrome/test/enterprise/e2e/DIR_METADATA b/chrome/test/enterprise/e2e/DIR_METADATA new file mode 100644 index 0000000..3ecb477 --- /dev/null +++ b/chrome/test/enterprise/e2e/DIR_METADATA
@@ -0,0 +1,3 @@ +monorail { + component: "Enterprise" +}
diff --git a/chrome/test/enterprise/e2e/OWNERS b/chrome/test/enterprise/e2e/OWNERS index 0211fa8..d0490d2 100644 --- a/chrome/test/enterprise/e2e/OWNERS +++ b/chrome/test/enterprise/e2e/OWNERS
@@ -1,4 +1,2 @@ jxiang@google.com uwyiming@google.com - -# COMPONENT: Enterprise
diff --git a/chrome/test/media_router/DIR_METADATA b/chrome/test/media_router/DIR_METADATA new file mode 100644 index 0000000..0139d4a --- /dev/null +++ b/chrome/test/media_router/DIR_METADATA
@@ -0,0 +1,3 @@ +monorail { + component: "Internals>Cast" +}
diff --git a/chrome/test/media_router/OWNERS b/chrome/test/media_router/OWNERS index 6f39617..9e513784 100644 --- a/chrome/test/media_router/OWNERS +++ b/chrome/test/media_router/OWNERS
@@ -2,5 +2,3 @@ # Additional members without committer privileges, for potential FYI reviews. leilei@chromium.org - -# COMPONENT: Internals>Cast
diff --git a/chrome/test/mini_installer/DIR_METADATA b/chrome/test/mini_installer/DIR_METADATA new file mode 100644 index 0000000..9123604d --- /dev/null +++ b/chrome/test/mini_installer/DIR_METADATA
@@ -0,0 +1,3 @@ +monorail { + component: "Internals>Installer" +}
diff --git a/chrome/test/mini_installer/OWNERS b/chrome/test/mini_installer/OWNERS index 7f0beeb..7fb73525 100644 --- a/chrome/test/mini_installer/OWNERS +++ b/chrome/test/mini_installer/OWNERS
@@ -1,5 +1,3 @@ gab@chromium.org grt@chromium.org robertshield@chromium.org - -# COMPONENT: Internals>Installer
diff --git a/chrome/test/nacl/DIR_METADATA b/chrome/test/nacl/DIR_METADATA new file mode 100644 index 0000000..096cb71 --- /dev/null +++ b/chrome/test/nacl/DIR_METADATA
@@ -0,0 +1,3 @@ +monorail { + component: "Platform>NaCl" +}
diff --git a/chrome/test/nacl/OWNERS b/chrome/test/nacl/OWNERS index cb02b14..8e3867c 100644 --- a/chrome/test/nacl/OWNERS +++ b/chrome/test/nacl/OWNERS
@@ -1,4 +1,2 @@ bradnelson@chromium.org mseaborn@chromium.org - -# COMPONENT: Platform>NaCl
diff --git a/chrome/test/origin_policy/DIR_METADATA b/chrome/test/origin_policy/DIR_METADATA new file mode 100644 index 0000000..8674903 --- /dev/null +++ b/chrome/test/origin_policy/DIR_METADATA
@@ -0,0 +1,3 @@ +monorail { + component: "Blink>SecurityFeature" +}
diff --git a/chrome/test/origin_policy/OWNERS b/chrome/test/origin_policy/OWNERS index 9f5e5e7..c99c800 100644 --- a/chrome/test/origin_policy/OWNERS +++ b/chrome/test/origin_policy/OWNERS
@@ -1,2 +1 @@ -file://services/network/origin_policy/OWNERS -# COMPONENT: Blink>SecurityFeature +file://services/network/origin_policy/OWNERS \ No newline at end of file
diff --git a/chrome/test/perf/DIR_METADATA b/chrome/test/perf/DIR_METADATA new file mode 100644 index 0000000..31b87f5 --- /dev/null +++ b/chrome/test/perf/DIR_METADATA
@@ -0,0 +1,3 @@ +monorail { + component: "Speed>Benchmarks>Waterfall" +}
diff --git a/chrome/test/perf/OWNERS b/chrome/test/perf/OWNERS index 0269bda..ec11be82 100644 --- a/chrome/test/perf/OWNERS +++ b/chrome/test/perf/OWNERS
@@ -1,5 +1,4 @@ cmp@chromium.org miu@chromium.org nduca@chromium.org -zmo@chromium.org -# COMPONENT: Speed>Benchmarks>Waterfall +zmo@chromium.org \ No newline at end of file
diff --git a/chrome/test/pixel/DIR_METADATA b/chrome/test/pixel/DIR_METADATA new file mode 100644 index 0000000..5256a7c --- /dev/null +++ b/chrome/test/pixel/DIR_METADATA
@@ -0,0 +1,3 @@ +monorail { + component: "Test>Pixel" +}
diff --git a/chrome/test/pixel/OWNERS b/chrome/test/pixel/OWNERS index a427d9ca2..4837f02 100644 --- a/chrome/test/pixel/OWNERS +++ b/chrome/test/pixel/OWNERS
@@ -1,5 +1,3 @@ svenzheng@chromium.org bsheedy@chromium.org -# COMPONENT: Test>Pixel -
diff --git a/chrome/test/ppapi/DIR_METADATA b/chrome/test/ppapi/DIR_METADATA new file mode 100644 index 0000000..9173b1c --- /dev/null +++ b/chrome/test/ppapi/DIR_METADATA
@@ -0,0 +1,4 @@ +monorail { + component: "Internals>Plugins>Pepper" +} +team_email: "pepper-dev@chromium.org"
diff --git a/chrome/test/ppapi/OWNERS b/chrome/test/ppapi/OWNERS index 20cf61c..f129781 100644 --- a/chrome/test/ppapi/OWNERS +++ b/chrome/test/ppapi/OWNERS
@@ -1,5 +1,2 @@ bbudge@chromium.org raymes@chromium.org - -# COMPONENT: Internals>Plugins>Pepper -# TEAM: pepper-dev@chromium.org
diff --git a/chrome/test/views/DIR_METADATA b/chrome/test/views/DIR_METADATA new file mode 100644 index 0000000..64ab044 --- /dev/null +++ b/chrome/test/views/DIR_METADATA
@@ -0,0 +1,3 @@ +monorail { + component: "UI>Accessibility" +}
diff --git a/chrome/test/views/OWNERS b/chrome/test/views/OWNERS index 3944c1c..6f9137626 100644 --- a/chrome/test/views/OWNERS +++ b/chrome/test/views/OWNERS
@@ -1,5 +1,3 @@ file://ui/views/OWNERS per-file accessibility*=file://ui/views/accessibility/OWNERS - -# COMPONENT: UI>Accessibility
diff --git a/chrome/updater/control_service_impl.cc b/chrome/updater/control_service_impl.cc index c87a5e9..b84666b7 100644 --- a/chrome/updater/control_service_impl.cc +++ b/chrome/updater/control_service_impl.cc
@@ -107,7 +107,8 @@ base::BindOnce(std::move(callback_)), config_)); } -void ControlServiceImpl::UnregisterMissingApps(std::vector<AppInfo> apps) { +void ControlServiceImpl::UnregisterMissingApps( + const std::vector<AppInfo>& apps) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); base::ThreadPool::PostTaskAndReplyWithResult( @@ -123,7 +124,7 @@ } std::vector<ControlServiceImpl::PingInfo> ControlServiceImpl::GetAppIDsToRemove( - std::vector<AppInfo> apps) { + const std::vector<AppInfo>& apps) { std::vector<PingInfo> app_ids_to_remove; for (const auto& app : apps) { // Skip if app_id is equal to updater app id. @@ -143,7 +144,7 @@ } void ControlServiceImpl::RemoveAppIDsAndSendUninstallPings( - std::vector<PingInfo> app_ids_to_remove) { + const std::vector<PingInfo>& app_ids_to_remove) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (app_ids_to_remove.empty()) { @@ -151,10 +152,10 @@ return; } - for (const auto& app_id_to_remove : app_ids_to_remove) { - const auto app_id = app_id_to_remove.app_id_; + for (const PingInfo& app_id_to_remove : app_ids_to_remove) { + const std::string& app_id = app_id_to_remove.app_id_; const int ping_reason = app_id_to_remove.ping_reason_; - const base::Version app_version = app_id_to_remove.app_version_; + const base::Version& app_version = app_id_to_remove.app_version_; if (persisted_data_->RemoveApp(app_id)) { VLOG(1) << "Uninstall ping for app id: " << app_id
diff --git a/chrome/updater/control_service_impl.h b/chrome/updater/control_service_impl.h index a4d263e..6bd9326 100644 --- a/chrome/updater/control_service_impl.h +++ b/chrome/updater/control_service_impl.h
@@ -75,7 +75,7 @@ // Provides a way to remove apps from the persisted data if the app is no // longer installed on the machine. - void UnregisterMissingApps(std::vector<AppInfo> apps); + void UnregisterMissingApps(const std::vector<AppInfo>& apps); // After an uninstall ping has been processed, reduces the number of pings // that we need to wait on before checking for updates. @@ -87,12 +87,12 @@ // Returns a list of apps that need to be unregistered. std::vector<ControlServiceImpl::PingInfo> GetAppIDsToRemove( - std::vector<AppInfo> apps); + const std::vector<AppInfo>& apps); // Unregisters the apps in |app_ids_to_remove| and starts an update check // if necessary. void RemoveAppIDsAndSendUninstallPings( - std::vector<PingInfo> app_ids_to_remove); + const std::vector<PingInfo>& app_ids_to_remove); scoped_refptr<updater::Configurator> config_; scoped_refptr<updater::PersistedData> persisted_data_;
diff --git a/chromecast/browser/webview/web_content_controller.cc b/chromecast/browser/webview/web_content_controller.cc index b6b46fcf..38df6f5 100644 --- a/chromecast/browser/webview/web_content_controller.cc +++ b/chromecast/browser/webview/web_content_controller.cc
@@ -206,7 +206,12 @@ void WebContentController::OnVisible(aura::Window* window) { // Acquire initial focus. - GetWebContents()->SetInitialFocus(); + auto* contents = GetWebContents(); + if (contents) contents->SetInitialFocus(); + else { + LOG(WARNING) + << "Webview unable to acquire initial focus due to missing webcontents"; + } // Register for IME events input_method_observer_ = std::make_unique<WebviewInputMethodObserver>(
diff --git a/chromeos/components/diagnostics_ui/resources/BUILD.gn b/chromeos/components/diagnostics_ui/resources/BUILD.gn index 8efe204..f2e9ff71 100644 --- a/chromeos/components/diagnostics_ui/resources/BUILD.gn +++ b/chromeos/components/diagnostics_ui/resources/BUILD.gn
@@ -38,8 +38,11 @@ js_library("battery_status_card") { deps = [ ":data_point", + ":diagnostics_types", ":mojo_interface_provider", ":mojo_utils", + ":percent_bar_chart", + ":routine_section", "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", "//ui/webui/resources/js:i18n_behavior.m", "//ui/webui/resources/js:load_time_data.m",
diff --git a/chromeos/components/diagnostics_ui/resources/battery_status_card.html b/chromeos/components/diagnostics_ui/resources/battery_status_card.html index 7ba47ac..1be2b01 100644 --- a/chromeos/components/diagnostics_ui/resources/battery_status_card.html +++ b/chromeos/components/diagnostics_ui/resources/battery_status_card.html
@@ -23,4 +23,6 @@ <data-point slot="body" id="currentNow" header="[[i18n('currentNowLabel')]]" value="[[getCurrentNow_(batteryChargeStatus_.currentNowMilliamps)]]"> </data-point> + + <routine-section slot="routines" routines="[[routines_]]"></routine-section> </diagnostics-card>
diff --git a/chromeos/components/diagnostics_ui/resources/battery_status_card.js b/chromeos/components/diagnostics_ui/resources/battery_status_card.js index 5ea7dcf..6e676045 100644 --- a/chromeos/components/diagnostics_ui/resources/battery_status_card.js +++ b/chromeos/components/diagnostics_ui/resources/battery_status_card.js
@@ -8,13 +8,14 @@ import './diagnostics_card.js'; import './diagnostics_shared_css.js'; import './percent_bar_chart.js'; +import './routine_section.js'; import './strings.m.js'; import {I18nBehavior} from 'chrome://resources/js/i18n_behavior.m.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js'; import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; -import {BatteryChargeStatus, BatteryHealth, BatteryInfo, SystemDataProviderInterface} from './diagnostics_types.js' +import {BatteryChargeStatus, BatteryHealth, BatteryInfo, RoutineName, SystemDataProviderInterface} from './diagnostics_types.js' import {getSystemDataProvider} from './mojo_interface_provider.js'; import {mojoString16ToString} from './mojo_utils.js'; @@ -64,6 +65,17 @@ type: Object, }, + /** @private {!Array<!RoutineName>} */ + routines_: { + type: Array, + value: () => { + return [ + RoutineName.kCharge, + RoutineName.kDischarge, + ]; + } + }, + /** @protected {string} */ powerTimeString_: { type: String, @@ -87,16 +99,17 @@ /** @private */ fetchBatteryInfo_() { - this.systemDataProvider_.getBatteryInfo().then( - this.onBatteryInfoReceived_.bind(this)); + this.systemDataProvider_.getBatteryInfo().then((result) => { + this.onBatteryInfoReceived_(result.batteryInfo); + }); }, /** - * @param {!{batteryInfo: !BatteryInfo}} result + * @param {!BatteryInfo} batteryInfo * @private */ - onBatteryInfoReceived_(result) { - this.batteryInfo_ = result.batteryInfo; + onBatteryInfoReceived_(batteryInfo) { + this.batteryInfo_ = batteryInfo; }, /** @private */
diff --git a/chromeos/components/diagnostics_ui/resources/diagnostics_app.js b/chromeos/components/diagnostics_ui/resources/diagnostics_app.js index bd23760..2ff9e95 100644 --- a/chromeos/components/diagnostics_ui/resources/diagnostics_app.js +++ b/chromeos/components/diagnostics_ui/resources/diagnostics_app.js
@@ -50,17 +50,17 @@ /** @private */ fetchSystemInfo_() { - this.systemDataProvider_.getSystemInfo().then( - this.onSystemInfoReceived_.bind(this)); + this.systemDataProvider_.getSystemInfo().then((result) => { + this.onSystemInfoReceived_(result.systemInfo); + }); }, /** - * @param {{systemInfo: !SystemInfo}} result + * @param {!SystemInfo} systemInfo * @private */ - onSystemInfoReceived_(result) { - this.showBatteryStatusCard_ = - result.systemInfo.deviceCapabilities.hasBattery; + onSystemInfoReceived_(systemInfo) { + this.showBatteryStatusCard_ = systemInfo.deviceCapabilities.hasBattery; }, }); \ No newline at end of file
diff --git a/chromeos/components/diagnostics_ui/resources/diagnostics_types.js b/chromeos/components/diagnostics_ui/resources/diagnostics_types.js index 7348ef2..c2a6c30 100644 --- a/chromeos/components/diagnostics_ui/resources/diagnostics_types.js +++ b/chromeos/components/diagnostics_ui/resources/diagnostics_types.js
@@ -127,10 +127,21 @@ }; /** - * Type alias for RoutineResult. - * TODO(zentaro): Currently only includes simple result type. + * Type alias for BatteryRateRoutineResult. * @typedef {{ - * simpleResult: !StandardRoutineResult + * result: !StandardRoutineResult, + * isCharging: boolean, + * percentDelta: number, + * timeDeltaSeconds: number, + * }} + */ +export let BatteryRateRoutineResult; + +/** + * Type alias for RoutineResult. + * @typedef {{ + * simpleResult: (!StandardRoutineResult|undefined), + * batteryRateResult: (!BatteryRateRoutineResult|undefined), * }} */ export let RoutineResult;
diff --git a/chromeos/components/diagnostics_ui/resources/fake_data.js b/chromeos/components/diagnostics_ui/resources/fake_data.js index fc626dc..c728a67 100644 --- a/chromeos/components/diagnostics_ui/resources/fake_data.js +++ b/chromeos/components/diagnostics_ui/resources/fake_data.js
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import {BatteryChargeStatus, BatteryInfo, BatteryHealth, CpuUsage, ExternalPowerSource, MemoryUsage, RoutineName, StandardRoutineResult, SystemInfo} from './diagnostics_types.js' +import {BatteryChargeStatus, BatteryHealth, BatteryInfo, BatteryRateRoutineResult, CpuUsage, ExternalPowerSource, MemoryUsage, RoutineName, StandardRoutineResult, SystemInfo} from './diagnostics_types.js' import {stringToMojoString16} from './mojo_utils.js'; /** @type {!Array<!BatteryChargeStatus>} */ @@ -152,4 +152,24 @@ [RoutineName.kFloatingPoint, StandardRoutineResult.kTestFailed], [RoutineName.kPrimeSearch, StandardRoutineResult.kErrorExecuting], [RoutineName.kMemory, StandardRoutineResult.kTestPassed], +]); + +/** @type {!Map<!RoutineName, !BatteryRateRoutineResult>} */ +export const fakeBatteryRoutineResults = new Map([ + [ + RoutineName.kCharge, { + result: StandardRoutineResult.kTestPassed, + is_charging: true, + percent_delta: 5, + time_delta_seconds: 10 + } + ], + [ + RoutineName.kDischarge, { + result: StandardRoutineResult.kUnableToRun, + is_charging: false, + percent_delta: 0, + time_delta_seconds: 0 + } + ], ]); \ No newline at end of file
diff --git a/chromeos/components/diagnostics_ui/resources/fake_system_routine_controller.js b/chromeos/components/diagnostics_ui/resources/fake_system_routine_controller.js index e499a2a9..4aedb737 100644 --- a/chromeos/components/diagnostics_ui/resources/fake_system_routine_controller.js +++ b/chromeos/components/diagnostics_ui/resources/fake_system_routine_controller.js
@@ -4,18 +4,17 @@ import {assert} from 'chrome://resources/js/assert.m.js'; import {PromiseResolver} from 'chrome://resources/js/promise_resolver.m.js'; -import {RoutineName, RoutineResult, RoutineResultInfo, RoutineRunner, StandardRoutineResult} from './diagnostics_types.js'; + +import {BatteryRateRoutineResult, RoutineName, RoutineResult, RoutineResultInfo, RoutineRunner, StandardRoutineResult} from './diagnostics_types.js'; /** * @fileoverview * Implements a fake version of the SystemRoutineController mojo interface. - * - * TODO(zentaro): Add support for complex routine results. */ export class FakeSystemRoutineController { constructor() { - /** private !Map<!RoutineName, !StandardRoutineResult> */ + /** private !Map<!RoutineName, !RoutineResult> */ this.routineResults_ = new Map(); /** @@ -73,7 +72,16 @@ * @param {!StandardRoutineResult} routineResult */ setFakeStandardRoutineResult(routineName, routineResult) { - this.routineResults_.set(routineName, routineResult); + this.routineResults_.set(routineName, {simpleResult: routineResult}); + } + + /** + * + * @param {!RoutineName} routineName + * @param {!BatteryRateRoutineResult} routineResult + */ + setFakeBatteryRateRoutineResult(routineName, routineResult) { + this.routineResults_.set(routineName, {batteryRateResult: routineResult}); } /** @@ -125,18 +133,13 @@ assert(this.routineName_ != null); let result = this.routineResults_.get(this.routineName_); if (result == undefined) { - result = StandardRoutineResult.kErrorExecuting; + result = {simpleResult: StandardRoutineResult.kErrorExecuting}; } - /** @type {!RoutineResult} */ - const fullResult = { - simpleResult: result, - }; - /** @type {!RoutineResultInfo} */ const resultInfo = { name: this.routineName_, - result: fullResult, + result: result, }; return resultInfo;
diff --git a/chromeos/components/diagnostics_ui/resources/mojo_interface_provider.js b/chromeos/components/diagnostics_ui/resources/mojo_interface_provider.js index cefa9311..d6d39b9f 100644 --- a/chromeos/components/diagnostics_ui/resources/mojo_interface_provider.js +++ b/chromeos/components/diagnostics_ui/resources/mojo_interface_provider.js
@@ -10,8 +10,8 @@ import {assert} from 'chrome://resources/js/assert.m.js'; -import {RoutineName, StandardRoutineResult, SystemDataProviderInterface, SystemInfo, SystemRoutineControllerInterface} from './diagnostics_types.js'; -import {fakeBatteryChargeStatus, fakeBatteryHealth, fakeBatteryInfo, fakeCpuUsage, fakeMemoryUsage, fakeRoutineResults, fakeSystemInfo} from './fake_data.js'; +import {BatteryRateRoutineResult, RoutineName, StandardRoutineResult, SystemDataProviderInterface, SystemInfo, SystemRoutineControllerInterface} from './diagnostics_types.js'; +import {fakeBatteryChargeStatus, fakeBatteryHealth, fakeBatteryInfo, fakeBatteryRoutineResults, fakeCpuUsage, fakeMemoryUsage, fakeRoutineResults, fakeSystemInfo} from './fake_data.js'; import {FakeSystemDataProvider} from './fake_system_data_provider.js'; import {FakeSystemRoutineController} from './fake_system_routine_controller.js'; @@ -62,6 +62,13 @@ /** @type{!StandardRoutineResult} */ (result)); } + // Add fake battery routine results. + for (const [routine, result] of fakeBatteryRoutineResults.entries()) { + controller.setFakeBatteryRateRoutineResult( + /** @type {!RoutineName} */ (routine), + /** @type {!BatteryRateRoutineResult} */ (result)); + } + // Set the fake controller. setSystemRoutineControllerForTesting(controller); }
diff --git a/chromeos/components/diagnostics_ui/resources/overview_card.js b/chromeos/components/diagnostics_ui/resources/overview_card.js index 8b52a2c..0c4e15e 100644 --- a/chromeos/components/diagnostics_ui/resources/overview_card.js +++ b/chromeos/components/diagnostics_ui/resources/overview_card.js
@@ -41,16 +41,16 @@ /** @private */ fetchSystemInfo_() { - this.systemDataProvider_.getSystemInfo().then( - this.onSystemInfoReceived_.bind(this)); + this.systemDataProvider_.getSystemInfo().then((result) => { + this.onSystemInfoReceived_(result.systemInfo); + }); }, /** - * @param {!{systemInfo: !SystemInfo}} result + * @param {!SystemInfo} systemInfo * @private */ - onSystemInfoReceived_(result) { - this.systemInfo_ = result.systemInfo; + onSystemInfoReceived_(systemInfo) { + this.systemInfo_ = systemInfo; }, - });
diff --git a/chromeos/components/diagnostics_ui/resources/routine_result_entry.js b/chromeos/components/diagnostics_ui/resources/routine_result_entry.js index 829616e..ce14462c 100644 --- a/chromeos/components/diagnostics_ui/resources/routine_result_entry.js +++ b/chromeos/components/diagnostics_ui/resources/routine_result_entry.js
@@ -6,7 +6,7 @@ import './diagnostics_shared_css.js'; import './text_badge.js'; -import {assert} from 'chrome://resources/js/assert.m.js'; +import {assert, assertNotReached} from 'chrome://resources/js/assert.m.js'; import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {RoutineName, RoutineResult, StandardRoutineResult} from './diagnostics_types.js'; import {ExecutionProgress, ResultStatusItem} from './routine_list_executor.js'; @@ -67,6 +67,27 @@ }, /** + * @param {!RoutineResult} result + * @return {!StandardRoutineResult} + */ + getSimpleResult_(result) { + assert(result); + + if (result.hasOwnProperty('simpleResult')) { + // Ideally we would just return assert(result.simpleResult) but enum + // value 0 fails assert. + return /** @type {!StandardRoutineResult} */ (result.simpleResult); + } + + if (result.hasOwnProperty('batteryRateResult')) { + return /** @type {!StandardRoutineResult} */ ( + result.batteryRateResult.result); + } + + assertNotReached(); + }, + + /** * @protected */ getBadgeText_() { @@ -76,7 +97,8 @@ } if (this.item.result && - this.item.result.simpleResult === StandardRoutineResult.kTestPassed) { + this.getSimpleResult_(this.item.result) === + StandardRoutineResult.kTestPassed) { return 'SUCCESS'; } @@ -93,7 +115,8 @@ } if (this.item.result && - this.item.result.simpleResult === StandardRoutineResult.kTestPassed) { + this.getSimpleResult_(this.item.result) === + StandardRoutineResult.kTestPassed) { return BadgeType.SUCCESS; } return BadgeType.ERROR;
diff --git a/chromeos/components/media_app_ui/resources/js/receiver.js b/chromeos/components/media_app_ui/resources/js/receiver.js index faf40edd..dff8896 100644 --- a/chromeos/components/media_app_ui/resources/js/receiver.js +++ b/chromeos/components/media_app_ui/resources/js/receiver.js
@@ -303,6 +303,7 @@ // Note: go/bbsrc/flags.ts processes this, `window.features` variable. /** @type{{features: Object<string, boolean>}} */ (window).features = { imageAnnotation: loadTimeData.getBoolean('imageAnnotation'), + pdfInInk: loadTimeData.getBoolean('pdfInInk'), flagsMenu: loadTimeData.getBoolean('flagsMenu'), isDevChannel: loadTimeData.getBoolean('isDevChannel'), };
diff --git a/chromeos/constants/chromeos_features.cc b/chromeos/constants/chromeos_features.cc index 15b03a8..12fdd83 100644 --- a/chromeos/constants/chromeos_features.cc +++ b/chromeos/constants/chromeos_features.cc
@@ -157,7 +157,7 @@ // Enable or disables running the Camera App as a System Web App. const base::Feature kCameraSystemWebApp{"CameraSystemWebApp", - base::FEATURE_DISABLED_BY_DEFAULT}; + base::FEATURE_ENABLED_BY_DEFAULT}; // If enabled, will use the CDM in the Chrome OS daemon rather than loading the // CDM using the library CDM interface. @@ -445,6 +445,10 @@ const base::Feature kMediaAppHandlesRaw{"MediaAppHandlesRaw", base::FEATURE_ENABLED_BY_DEFAULT}; +// Whether Pdf files loading ink is enabled in the ChromeOS media app. +const base::Feature kMediaAppPdfInInk{"MediaAppPdfInInk", + base::FEATURE_DISABLED_BY_DEFAULT}; + // Enables a unique URL for each path in CrOS settings. // This allows deep linking to individual settings, i.e. in settings search. const base::Feature kOsSettingsDeepLinking{"OsSettingsDeepLinking",
diff --git a/chromeos/constants/chromeos_features.h b/chromeos/constants/chromeos_features.h index 9a50e6d3..834d1ee4 100644 --- a/chromeos/constants/chromeos_features.h +++ b/chromeos/constants/chromeos_features.h
@@ -196,6 +196,8 @@ COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const base::Feature kMediaAppHandlesRaw; COMPONENT_EXPORT(CHROMEOS_CONSTANTS) +extern const base::Feature kMediaAppPdfInInk; +COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const base::Feature kMinimumChromeVersion; COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const base::Feature kOsSettingsDeepLinking;
diff --git a/chromeos/process_proxy/process_proxy.cc b/chromeos/process_proxy/process_proxy.cc index 75ac4f2..b6afe90 100644 --- a/chromeos/process_proxy/process_proxy.cc +++ b/chromeos/process_proxy/process_proxy.cc
@@ -282,8 +282,8 @@ pipe[PT_SLAVE_FD] = base::kInvalidFd; } -base::ProcessHandle ProcessProxy::GetProcessHandleForTesting() { - return process_.IsValid() ? process_.Handle() : base::kNullProcessHandle; +const base::Process* ProcessProxy::GetProcessForTesting() { + return &process_; } } // namespace chromeos
diff --git a/chromeos/process_proxy/process_proxy.h b/chromeos/process_proxy/process_proxy.h index d48073a..b6e527cd 100644 --- a/chromeos/process_proxy/process_proxy.h +++ b/chromeos/process_proxy/process_proxy.h
@@ -66,7 +66,7 @@ void AckOutput(); // Get the process handle for testing purposes. - base::ProcessHandle GetProcessHandleForTesting(); + const base::Process* GetProcessForTesting(); private: friend class base::RefCountedThreadSafe<ProcessProxy>;
diff --git a/chromeos/process_proxy/process_proxy_registry.cc b/chromeos/process_proxy/process_proxy_registry.cc index 1f34ca2a..66e7f8b 100644 --- a/chromeos/process_proxy/process_proxy_registry.cc +++ b/chromeos/process_proxy/process_proxy_registry.cc
@@ -199,14 +199,14 @@ base::Thread::Options(base::MessagePumpType::IO, 0)); } -base::ProcessHandle ProcessProxyRegistry::GetProcessHandleForTesting( +const base::Process* ProcessProxyRegistry::GetProcessForTesting( const std::string& id) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); std::map<std::string, ProcessProxyInfo>::iterator it = proxy_map_.find(id); if (it == proxy_map_.end()) - return base::kNullProcessHandle; + return nullptr; - return it->second.proxy->GetProcessHandleForTesting(); + return it->second.proxy->GetProcessForTesting(); // IN-TEST } } // namespace chromeos
diff --git a/chromeos/process_proxy/process_proxy_registry.h b/chromeos/process_proxy/process_proxy_registry.h index 0a88b68..5e5edb2f 100644 --- a/chromeos/process_proxy/process_proxy_registry.h +++ b/chromeos/process_proxy/process_proxy_registry.h
@@ -71,8 +71,8 @@ // Shuts down registry, closing all associated processed. void ShutDown(); - // Get the process handle for testing purposes. - base::ProcessHandle GetProcessHandleForTesting(const std::string& id); + // Get the process for testing purposes. + const base::Process* GetProcessForTesting(const std::string& id); private: friend struct ::base::LazyInstanceTraitsBase<ProcessProxyRegistry>;
diff --git a/chromeos/process_proxy/process_proxy_unittest.cc b/chromeos/process_proxy/process_proxy_unittest.cc index aa72071..02f6f4a5 100644 --- a/chromeos/process_proxy/process_proxy_unittest.cc +++ b/chromeos/process_proxy/process_proxy_unittest.cc
@@ -48,7 +48,7 @@ TestRunner() = default; virtual ~TestRunner() = default; virtual void SetupExpectations(const std::string& id, - base::ProcessHandle handle) = 0; + const base::Process* process) = 0; virtual void OnSomeRead(const std::string& id, const std::string& type, const std::string& output) = 0; @@ -60,7 +60,7 @@ protected: std::string id_; - base::ProcessHandle handle_; + const base::Process* process_; base::OnceClosure done_read_closure_; }; @@ -70,9 +70,9 @@ ~RegistryTestRunner() override = default; void SetupExpectations(const std::string& id, - base::ProcessHandle handle) override { + const base::Process* process) override { id_ = id; - handle_ = handle; + process_ = process; left_to_check_index_[0] = 0; left_to_check_index_[1] = 0; // We consider that a line processing has started if a value in @@ -150,10 +150,10 @@ ~RegistryNotifiedOnProcessExitTestRunner() override = default; void SetupExpectations(const std::string& id, - base::ProcessHandle handle) override { + const base::Process* process) override { output_received_ = false; id_ = id; - handle_ = handle; + process_ = process; } void OnSomeRead(const std::string& id, @@ -165,9 +165,7 @@ output_received_ = true; EXPECT_EQ(type, "stdout"); EXPECT_EQ(output, "p"); - base::Process process = - base::Process::DeprecatedGetProcessFromHandle(handle_); - process.Terminate(0, true); + process_->Terminate(0, true); return; } EXPECT_EQ("exit", type); @@ -200,11 +198,11 @@ base::BindRepeating(&ProcessProxyTest::HandleRead, base::Unretained(this)), &id_); - handle_ = registry_->GetProcessHandleForTesting(id_); + process_ = registry_->GetProcessForTesting(id_); EXPECT_TRUE(success); test_runner_->set_done_read_closure(std::move(done_closure)); - test_runner_->SetupExpectations(id_, handle_); + test_runner_->SetupExpectations(id_, process_); test_runner_->StartRegistryTest(registry_); } @@ -222,12 +220,10 @@ int unused_exit_code = 0; base::TerminationStatus status = - base::GetTerminationStatus(handle_, &unused_exit_code); + base::GetTerminationStatus(process_->Handle(), &unused_exit_code); EXPECT_NE(base::TERMINATION_STATUS_STILL_RUNNING, status); if (status == base::TERMINATION_STATUS_STILL_RUNNING) { - base::Process process = - base::Process::DeprecatedGetProcessFromHandle(handle_); - process.Terminate(0, true); + process_->Terminate(0, true); } registry_->ShutDown(); @@ -266,7 +262,7 @@ ProcessProxyRegistry* registry_; std::string id_; - base::ProcessHandle handle_; + const base::Process* process_ = nullptr; base::test::TaskEnvironment task_environment_; };
diff --git a/components/autofill_assistant/browser/metrics.h b/components/autofill_assistant/browser/metrics.h index 0b897258..9185e903 100644 --- a/components/autofill_assistant/browser/metrics.h +++ b/components/autofill_assistant/browser/metrics.h
@@ -256,6 +256,10 @@ // Since Chrome M-88. The RPC to fetch the trigger scripts returned with an // empty response. LITE_SCRIPT_NO_TRIGGER_SCRIPT_AVAILABLE = 21, + // Since Chrome M-88. The trigger script failed to show. This can happen, + // for example, if the activity was changed after triggering (e.g., + // switching from CCT to regular tab). + LITE_SCRIPT_FAILED_TO_SHOW = 22, // NOTE: All values in this block are DEPRECATED and will only be sent by // Chrome M-86 and M-87. @@ -286,7 +290,7 @@ // Since Chrome M-88. The bottom sheet was swipe-dismissed by the user. LITE_SCRIPT_PROMPT_SWIPE_DISMISSED = 16, - kMaxValue = LITE_SCRIPT_NO_TRIGGER_SCRIPT_AVAILABLE + kMaxValue = LITE_SCRIPT_FAILED_TO_SHOW }; // The different ways a user who has successfully completed a light script may
diff --git a/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.cc b/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.cc index 9977c4a..f938ec53 100644 --- a/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.cc +++ b/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.cc
@@ -210,6 +210,13 @@ RunOutOfScheduleTriggerConditionCheck(); } +void TriggerScriptCoordinator::OnTriggerScriptShown(bool success) { + if (!success) { + Stop(Metrics::LiteScriptFinishedState::LITE_SCRIPT_FAILED_TO_SHOW); + return; + } +} + void TriggerScriptCoordinator::Stop(Metrics::LiteScriptFinishedState state) { HideTriggerScript(); StopCheckingTriggerConditions();
diff --git a/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.h b/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.h index 661bba3..773d5bb1 100644 --- a/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.h +++ b/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.h
@@ -82,6 +82,11 @@ // Called when the keyboard was shown or hidden. void OnKeyboardVisibilityChanged(bool visible); + // Called when a trigger script was attempted to be shown on screen. This may + // have failed, for example when trying to show a trigger script after + // switching from CCT to regular tab. + void OnTriggerScriptShown(bool success); + void AddObserver(Observer* observer); void RemoveObserver(const Observer* observer);
diff --git a/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator_unittest.cc b/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator_unittest.cc index 139a83e..397d669 100644 --- a/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator_unittest.cc +++ b/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator_unittest.cc
@@ -755,4 +755,31 @@ Metrics::LiteScriptFinishedState::LITE_SCRIPT_TRIGGER_CONDITION_TIMEOUT); } +TEST_F(TriggerScriptCoordinatorTest, OnTriggerScriptFailedToShow) { + GetTriggerScriptsResponseProto response; + response.add_trigger_scripts(); + std::string serialized_response; + response.SerializeToString(&serialized_response); + + EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _)) + .WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response)); + EXPECT_CALL(*mock_static_trigger_conditions_, Init) + .WillOnce(RunOnceCallback<3>()); + EXPECT_CALL(*mock_dynamic_trigger_conditions_, + OnUpdate(mock_web_controller_, _)) + .WillRepeatedly(RunOnceCallback<1>()); + + EXPECT_CALL(mock_observer_, OnTriggerScriptShown).WillOnce([&]() { + coordinator_->OnTriggerScriptShown(/* success = */ false); + }); + EXPECT_CALL( + mock_observer_, + OnTriggerScriptFinished( + Metrics::LiteScriptFinishedState::LITE_SCRIPT_FAILED_TO_SHOW)); + coordinator_->Start(GURL(kFakeDeepLink), + std::make_unique<TriggerContextImpl>()); + AssertRecordedFinishedState( + Metrics::LiteScriptFinishedState::LITE_SCRIPT_FAILED_TO_SHOW); +} + } // namespace autofill_assistant
diff --git a/components/browser_ui/photo_picker/android/java/src/org/chromium/components/browser_ui/photo_picker/PickerBitmapView.java b/components/browser_ui/photo_picker/android/java/src/org/chromium/components/browser_ui/photo_picker/PickerBitmapView.java index 4be36a5..0ba961d 100644 --- a/components/browser_ui/photo_picker/android/java/src/org/chromium/components/browser_ui/photo_picker/PickerBitmapView.java +++ b/components/browser_ui/photo_picker/android/java/src/org/chromium/components/browser_ui/photo_picker/PickerBitmapView.java
@@ -493,11 +493,13 @@ setBackgroundColor(mCategoryView.isZoomSwitchingInEffect() && !special ? Color.TRANSPARENT : mBackgroundColor); - // The visibility of the unselected toggle for multi-selection mode is a little more complex - // because we don't want to show it when nothing is selected and also not on a blank canvas. boolean isSelected = mSelectionDelegate.isItemSelected(mBitmapDetails); mSelectedView.setVisibility(!special && isSelected ? View.VISIBLE : View.GONE); - boolean showUnselectedToggle = !special && !isSelected && anySelection && mImageLoaded + // The visibility of the unselected toggle for multi-selection mode is a little more complex + // because we don't want to show it when nothing is selected (unless in magnifying mode) and + // also not on a blank canvas. + boolean showUnselectedToggle = !special && !isSelected && mImageLoaded + && (anySelection || mCategoryView.isInMagnifyingMode()) && mCategoryView.isMultiSelectAllowed(); mUnselectedView.setVisibility(showUnselectedToggle ? View.VISIBLE : View.GONE); mScrim.setVisibility(showUnselectedToggle ? View.VISIBLE : View.GONE);
diff --git a/components/content_settings/core/browser/content_settings_policy_provider.cc b/components/content_settings/core/browser/content_settings_policy_provider.cc index 6b210067..d14878c 100644 --- a/components/content_settings/core/browser/content_settings_policy_provider.cc +++ b/components/content_settings/core/browser/content_settings_policy_provider.cc
@@ -20,7 +20,6 @@ #include "components/content_settings/core/browser/website_settings_info.h" #include "components/content_settings/core/browser/website_settings_registry.h" #include "components/content_settings/core/common/content_settings_pattern.h" -#include "components/content_settings/core/common/features.h" #include "components/content_settings/core/common/pref_names.h" #include "components/pref_registry/pref_registry_syncable.h" #include "components/prefs/pref_service.h" @@ -33,8 +32,6 @@ const char* pref_name; ContentSettingsType content_type; ContentSetting setting; - content_settings::WildcardsInPrimaryPattern wildcards_in_primary_pattern = - content_settings::WildcardsInPrimaryPattern::ALLOWED; }; const PrefsForManagedContentSettingsMapEntry @@ -395,18 +392,6 @@ continue; } - if (base::FeatureList::IsEnabled( - content_settings::kDisallowWildcardsInPluginContentSettings) && - kPrefsForManagedContentSettingsMap[i].wildcards_in_primary_pattern == - WildcardsInPrimaryPattern::NOT_ALLOWED && - pattern_pair.first.HasHostWildcards()) { - discarded_rules_value_map_[content_type].push_back( - Rule(pattern_pair.first, secondary_pattern, - base::Value(kPrefsForManagedContentSettingsMap[i].setting), - base::Time(), content_settings::SessionModel::Durable)); - continue; - } - // Don't set a timestamp for policy settings. value_map->SetValue( pattern_pair.first, secondary_pattern, content_type, base::Time(),
diff --git a/components/content_settings/core/common/content_settings_pattern.cc b/components/content_settings/core/common/content_settings_pattern.cc index 2693e1c..1f0afca 100644 --- a/components/content_settings/core/common/content_settings_pattern.cc +++ b/components/content_settings/core/common/content_settings_pattern.cc
@@ -616,10 +616,6 @@ return path_relation; } -bool ContentSettingsPattern::HasHostWildcards() const { - return parts_.has_domain_wildcard; -} - bool ContentSettingsPattern::operator==( const ContentSettingsPattern& other) const { return Compare(other) == IDENTITY;
diff --git a/components/content_settings/core/common/content_settings_pattern.h b/components/content_settings/core/common/content_settings_pattern.h index 9cd4988..90bb7c8 100644 --- a/components/content_settings/core/common/content_settings_pattern.h +++ b/components/content_settings/core/common/content_settings_pattern.h
@@ -22,11 +22,6 @@ namespace mojom { class ContentSettingsPatternDataView; } - -enum class WildcardsInPrimaryPattern { - NOT_ALLOWED, - ALLOWED, -}; } // A pattern used in content setting rules. See |IsValid| for a description of @@ -224,9 +219,6 @@ // |Relation| of the two patterns. Relation Compare(const ContentSettingsPattern& other) const; - // True if the host in the pattern has a wildcard. - bool HasHostWildcards() const; - // Returns true if the pattern and the |other| pattern are identical. bool operator==(const ContentSettingsPattern& other) const;
diff --git a/components/content_settings/core/common/content_settings_pattern_unittest.cc b/components/content_settings/core/common/content_settings_pattern_unittest.cc index e5c0f25f..547d902 100644 --- a/components/content_settings/core/common/content_settings_pattern_unittest.cc +++ b/components/content_settings/core/common/content_settings_pattern_unittest.cc
@@ -845,22 +845,3 @@ EXPECT_TRUE(Pattern("file:///foo/bar/").HasPath()); EXPECT_TRUE(Pattern("file:///foo/bar/test.html").HasPath()); } - -TEST(ContentSettingsPatternTest, PatternHasWildcards) { - // scheme wildcard are allowed - EXPECT_FALSE(Pattern("mail.google.com:443/home").HasHostWildcards()); - EXPECT_FALSE(Pattern("*://mail.google.com:443/home").HasHostWildcards()); - // domain wildcard - EXPECT_TRUE(Pattern("https://[*.]google.com:443/home").HasHostWildcards()); - // path wildcard are allowed - EXPECT_FALSE(Pattern("https://mail.google.com:443/*").HasHostWildcards()); - // port wildcards are allowed - EXPECT_FALSE(Pattern("https://mail.google.com/home").HasHostWildcards()); - EXPECT_FALSE(Pattern("https://mail.google.com:*/home").HasHostWildcards()); - // full wildcard pattern - EXPECT_TRUE(Pattern("*").HasHostWildcards()); - // full wildcard pattern - EXPECT_TRUE(ContentSettingsPattern::Wildcard().HasHostWildcards()); - // no wildcards - EXPECT_FALSE(Pattern("https://mail.google.com:443/home").HasHostWildcards()); -}
diff --git a/components/content_settings/core/common/features.cc b/components/content_settings/core/common/features.cc index 19d9ab9..d80d34fb 100644 --- a/components/content_settings/core/common/features.cc +++ b/components/content_settings/core/common/features.cc
@@ -15,8 +15,4 @@ base::FEATURE_DISABLED_BY_DEFAULT}; #endif // defined(OS_IOS) -const base::Feature kDisallowWildcardsInPluginContentSettings{ - "DisallowWildcardsInPluginContentSettings", - base::FEATURE_ENABLED_BY_DEFAULT}; - } // namespace content_settings
diff --git a/components/content_settings/core/common/features.h b/components/content_settings/core/common/features.h index 10ef3666..9342f03 100644 --- a/components/content_settings/core/common/features.h +++ b/components/content_settings/core/common/features.h
@@ -20,10 +20,6 @@ extern const base::Feature kImprovedCookieControls; #endif -// Feature to disallow wildcard pattern matching for plugin content settings -COMPONENT_EXPORT(CONTENT_SETTINGS_FEATURES) -extern const base::Feature kDisallowWildcardsInPluginContentSettings; - } // namespace content_settings #endif // COMPONENTS_CONTENT_SETTINGS_CORE_COMMON_FEATURES_H_
diff --git a/components/guest_view/DIR_METADATA b/components/guest_view/DIR_METADATA new file mode 100644 index 0000000..68dca923 --- /dev/null +++ b/components/guest_view/DIR_METADATA
@@ -0,0 +1,3 @@ +monorail { + component: "Platform>Apps>BrowserTag" +} \ No newline at end of file
diff --git a/components/guest_view/OWNERS b/components/guest_view/OWNERS index b788969..1ba9222 100644 --- a/components/guest_view/OWNERS +++ b/components/guest_view/OWNERS
@@ -4,9 +4,8 @@ wjmaclean@chromium.org mcnee@chromium.org -# COMPONENT: Platform>Apps>BrowserTag # Emeritus: # fsamuel@chromium.org # paulmeyer@chromium.org -# ekaramad@chromium.org +# ekaramad@chromium.org \ No newline at end of file
diff --git a/components/guest_view/common/DIR_METADATA b/components/guest_view/common/DIR_METADATA new file mode 100644 index 0000000..68dca923 --- /dev/null +++ b/components/guest_view/common/DIR_METADATA
@@ -0,0 +1,3 @@ +monorail { + component: "Platform>Apps>BrowserTag" +} \ No newline at end of file
diff --git a/components/guest_view/common/OWNERS b/components/guest_view/common/OWNERS index fad6e24f..42444bc 100644 --- a/components/guest_view/common/OWNERS +++ b/components/guest_view/common/OWNERS
@@ -1,4 +1,2 @@ per-file *_messages*.h=set noparent per-file *_messages*.h=file://ipc/SECURITY_OWNERS - -# COMPONENT: Platform>Apps>BrowserTag
diff --git a/components/nacl/browser/nacl_process_host.cc b/components/nacl/browser/nacl_process_host.cc index b68e922..a3bc2a3 100644 --- a/components/nacl/browser/nacl_process_host.cc +++ b/components/nacl/browser/nacl_process_host.cc
@@ -900,7 +900,7 @@ // browser process. ppapi_host_.reset(content::BrowserPpapiHost::CreateExternalPluginProcess( ipc_proxy_channel_.get(), // sender - permissions_, process_->GetData().GetProcess().Handle(), + permissions_, process_->GetData().GetProcess().Duplicate(), ipc_proxy_channel_.get(), nacl_host_message_filter_->render_process_id(), render_view_id_, profile_directory_));
diff --git a/components/password_manager/DIR_METADATA b/components/password_manager/DIR_METADATA new file mode 100644 index 0000000..484c599 --- /dev/null +++ b/components/password_manager/DIR_METADATA
@@ -0,0 +1,4 @@ +monorail { + component: "UI>Browser>Passwords" +} +team_email: "chromium-dev@chromium.org" \ No newline at end of file
diff --git a/components/password_manager/OWNERS b/components/password_manager/OWNERS index 5b8680ef..73bb597 100644 --- a/components/password_manager/OWNERS +++ b/components/password_manager/OWNERS
@@ -3,6 +3,3 @@ kolos@chromium.org mamir@chromium.org vasilii@chromium.org - -# COMPONENT: UI>Browser>Passwords -# TEAM: chromium-dev@chromium.org
diff --git a/components/password_manager/core/browser/android_affiliation/DIR_METADATA b/components/password_manager/core/browser/android_affiliation/DIR_METADATA new file mode 100644 index 0000000..518e435 --- /dev/null +++ b/components/password_manager/core/browser/android_affiliation/DIR_METADATA
@@ -0,0 +1,3 @@ +monorail { + component: "UI>Browser>Passwords" +} \ No newline at end of file
diff --git a/components/password_manager/core/browser/android_affiliation/OWNERS b/components/password_manager/core/browser/android_affiliation/OWNERS index 992fe26..b0a71151 100644 --- a/components/password_manager/core/browser/android_affiliation/OWNERS +++ b/components/password_manager/core/browser/android_affiliation/OWNERS
@@ -1,3 +1 @@ engedy@chromium.org - -# COMPONENT: UI>Browser>Passwords
diff --git a/components/password_manager/core/browser/export/DIR_METADATA b/components/password_manager/core/browser/export/DIR_METADATA new file mode 100644 index 0000000..484c599 --- /dev/null +++ b/components/password_manager/core/browser/export/DIR_METADATA
@@ -0,0 +1,4 @@ +monorail { + component: "UI>Browser>Passwords" +} +team_email: "chromium-dev@chromium.org" \ No newline at end of file
diff --git a/components/password_manager/core/browser/export/OWNERS b/components/password_manager/core/browser/export/OWNERS index 1d447d6..d6e23bb5 100644 --- a/components/password_manager/core/browser/export/OWNERS +++ b/components/password_manager/core/browser/export/OWNERS
@@ -1,4 +1 @@ cfroussios@chromium.org - -# COMPONENT: UI>Browser>Passwords -# TEAM: chromium-dev@chromium.org
diff --git a/components/policy/core/common/cloud/enterprise_metrics.cc b/components/policy/core/common/cloud/enterprise_metrics.cc index a8ced39..e56b98d 100644 --- a/components/policy/core/common/cloud/enterprise_metrics.cc +++ b/components/policy/core/common/cloud/enterprise_metrics.cc
@@ -186,4 +186,11 @@ const char kMetricCBCMUnsignedRemoteCommandExecutedTemplate[] = "Enterprise.CBCMRemoteCommand.Executed.Unsigned.%s"; +const char kUMAPrivateSetMembershipHashDanceComparison[] = + "Enterprise.AutoEnrollmentPrivateSetMembershipHashDanceComparison"; +const char kUMAPrivateSetMembershipSuccessTime[] = + "Enterprise.AutoEnrollmentPrivateSetMembershipSuccessTime"; +const char kUMAPrivateSetMembershipRequestStatus[] = + "Enterprise.AutoEnrollmentPrivateSetMembershipRequestStatus"; + } // namespace policy
diff --git a/components/policy/core/common/cloud/enterprise_metrics.h b/components/policy/core/common/cloud/enterprise_metrics.h index 3dc7c006..a790c9d 100644 --- a/components/policy/core/common/cloud/enterprise_metrics.h +++ b/components/policy/core/common/cloud/enterprise_metrics.h
@@ -283,6 +283,11 @@ POLICY_EXPORT extern const char kMetricCBCMUnsignedRemoteCommandExecutedTemplate[]; +// Private set membership UMA histogram names. +POLICY_EXPORT extern const char kUMAPrivateSetMembershipHashDanceComparison[]; +POLICY_EXPORT extern const char kUMAPrivateSetMembershipSuccessTime[]; +POLICY_EXPORT extern const char kUMAPrivateSetMembershipRequestStatus[]; + } // namespace policy #endif // COMPONENTS_POLICY_CORE_COMMON_CLOUD_ENTERPRISE_METRICS_H_
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json index da5189fa..a98ed70 100644 --- a/components/policy/resources/policy_templates.json +++ b/components/policy/resources/policy_templates.json
@@ -6052,7 +6052,7 @@ URL patterns must not conflict with <ph name="WEB_USB_ASK_FOR_URLS_POLICY_NAME">WebUsbAskForUrls</ph>. Neither policy takes precedence if a URL matches with both. - For detailed information on valid <ph name="URL_LABEL">url</ph> patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns.''', + For detailed information on valid <ph name="URL_LABEL">url</ph> patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns. <ph name="WILDCARD_VALUE">*</ph> is not an accepted value for this policy.''', }, { 'name': 'WebUsbBlockedForUrls', @@ -6077,7 +6077,7 @@ URL patterns can't conflict with <ph name="WEB_USB_ASK_FOR_URLS_POLICY_NAME">WebUsbAskForUrls</ph>. Neither policy takes precedence if a URL matches with both. - For detailed information on valid <ph name="URL_LABEL">url</ph> patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns.''', + For detailed information on valid <ph name="URL_LABEL">url</ph> patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns. <ph name="WILDCARD_VALUE">*</ph> is not an accepted value for this policy.''', }, { 'name': 'DefaultSerialGuardSetting', @@ -6138,7 +6138,7 @@ URL patterns must not conflict with <ph name="SERIAL_BLOCKED_FOR_URLS_POLICY_NAME">SerialBlockedForUrls</ph>. Neither policy takes precedence if a URL matches with both. - For detailed information on valid <ph name="URL_LABEL">url</ph> patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns.''', + For detailed information on valid <ph name="URL_LABEL">url</ph> patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns. <ph name="WILDCARD_VALUE">*</ph> is not an accepted value for this policy.''', }, { 'name': 'SerialBlockedForUrls', @@ -6165,7 +6165,7 @@ URL patterns can't conflict with <ph name="SERIAL_ASK_FOR_URLS_POLICY_NAME">SerialAskForUrls</ph>. Neither policy takes precedence if a URL matches with both. - For detailed information on valid <ph name="URL_LABEL">url</ph> patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns.''', + For detailed information on valid <ph name="URL_LABEL">url</ph> patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns. <ph name="WILDCARD_VALUE">*</ph> is not an accepted value for this policy.''', }, { 'name': 'DefaultFileSystemReadGuardSetting', @@ -6258,7 +6258,7 @@ URL patterns must not conflict with <ph name="FILE_SYSTEM_READ_BLOCKED_FOR_URLS_POLICY_NAME">FileSystemReadBlockedForUrls</ph>. Neither policy takes precedence if a URL matches with both. - For detailed information on valid <ph name="URL_LABEL">url</ph> patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns.''', + For detailed information on valid <ph name="URL_LABEL">url</ph> patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns. <ph name="WILDCARD_VALUE">*</ph> is not an accepted value for this policy.''', }, { 'name': 'FileSystemReadBlockedForUrls', @@ -6283,7 +6283,7 @@ URL patterns can't conflict with <ph name="FILE_SYSTEM_READ_ASK_FOR_URLS_POLICY_NAME">FileSystemReadAskForUrls</ph>. Neither policy takes precedence if a URL matches with both. - For detailed information on valid <ph name="URL_LABEL">url</ph> patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns.''', + For detailed information on valid <ph name="URL_LABEL">url</ph> patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns. <ph name="WILDCARD_VALUE">*</ph> is not an accepted value for this policy.''', }, { 'name': 'FileSystemWriteAskForUrls', @@ -6308,7 +6308,7 @@ URL patterns must not conflict with <ph name="FILE_SYSTEM_WRITE_BLOCKED_FOR_URLS_POLICY_NAME">FileSystemWriteBlockedForUrls</ph>. Neither policy takes precedence if a URL matches with both. - For detailed information on valid <ph name="URL_LABEL">url</ph> patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns.''', + For detailed information on valid <ph name="URL_LABEL">url</ph> patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns. <ph name="WILDCARD_VALUE">*</ph> is not an accepted value for this policy.''', }, { 'name': 'FileSystemWriteBlockedForUrls', @@ -6333,7 +6333,7 @@ URL patterns can't conflict with <ph name="FILE_SYSTEM_WRITE_ASK_FOR_URLS_POLICY_NAME">FileSystemWriteAskForUrls</ph>. Neither policy takes precedence if a URL matches with both. - For detailed information on valid <ph name="URL_LABEL">url</ph> patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns.''', + For detailed information on valid <ph name="URL_LABEL">url</ph> patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns. <ph name="WILDCARD_VALUE">*</ph> is not an accepted value for this policy.''', }, { 'name': 'AutoSelectCertificateForUrls', @@ -6477,11 +6477,11 @@ 'tags': [], 'desc': '''Allows you to set a list of url patterns that specify sites which are allowed to set cookies. - If this policy is left not set the global default value will be used for all sites either from the 'DefaultCookiesSetting' policy if it is set, or the user's personal configuration otherwise. + If this policy is left not set the global default value will be used for all sites either from the <ph name="DEFAULT_COOKIES_SETTINGS_POLICY_NAME">DefaultCookiesSetting</ph> policy if it is set, or the user's personal configuration otherwise. - See also policies 'CookiesBlockedForUrls' and 'CookiesSessionOnlyForUrls'. Note that there must be no conflicting URL patterns between these three policies - it is unspecified which policy takes precedence. + See also policies <ph name="COOKIES_BLOCKED_FOR_URLS_POLICY_NAME">CookiesBlockedForUrls</ph> and <ph name="COOKIES_SESSIONS_ONLY_FOR_URLS">CookiesSessionOnlyForUrls</ph>. Note that there must be no conflicting URL patterns between these three policies - it is unspecified which policy takes precedence. - For detailed information on valid url patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns.''', + For detailed information on valid url patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns. <ph name="WILDCARD_VALUE">*</ph> is not an accepted value for this policy.''', }, { 'name': 'CookiesBlockedForUrls', @@ -6508,9 +6508,9 @@ Leaving the policy unset results in the use of <ph name="DEFAULT_COOKIES_SETTINGS_POLICY_NAME">DefaultCookiesSetting</ph> for all sites, if it's set. If not, the user's personal setting applies. - While no specific policy takes precedence, see <ph name="COOKIES_BLOCKED_FOR_URLS_POLICY_NAME">CookiesBlockedForUrls</ph> and <ph name="COOKIES_SESSION_ONLY_FOR_URLS_POLICY_NAME">CookiesSessionOnlyForUrls</ph>. URL patterns among these 3 policies must not conflict. + While no specific policy takes precedence, see <ph name="COOKIES_ALLOWED_FOR_URLS_POLICY_NAME">CookiesAllowedForUrls</ph> and <ph name="COOKIES_SESSION_ONLY_FOR_URLS_POLICY_NAME">CookiesSessionOnlyForUrls</ph>. URL patterns among these 3 policies must not conflict. - For detailed information on valid <ph name="URL_LABEL">url</ph> patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns.''', + For detailed information on valid <ph name="URL_LABEL">url</ph> patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns. <ph name="WILDCARD_VALUE">*</ph> is not an accepted value for this policy.''', }, { 'name': 'CookiesSessionOnlyForUrls', @@ -6541,7 +6541,7 @@ While no specific policy takes precedence, see <ph name="COOKIES_BLOCKED_FOR_URLS_POLICY_NAME">CookiesBlockedForUrls</ph> and <ph name="COOKIES_ALLOWED_FOR_URLS_POLICY_NAME">CookiesAllowedForUrls</ph>. URL patterns among these 3 policies must not conflict. - For detailed information on valid <ph name="URL_LABEL">url</ph> patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns.''', + For detailed information on valid <ph name="URL_LABEL">url</ph> patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns. <ph name="WILDCARD_VALUE">*</ph> is not an accepted value for this policy.''', }, { 'name': 'ImagesAllowedForUrls', @@ -6564,7 +6564,7 @@ Leaving the policy unset means <ph name="DEFAULT_IMAGES_SETTING_ENABLED_POLICY_NAME">DefaultImagesSetting</ph> applies for all sites, if it's set. If not, the user's personal setting applies. - For detailed information on valid <ph name="URL_LABEL">url</ph> patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns. + For detailed information on valid <ph name="URL_LABEL">url</ph> patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns. <ph name="WILDCARD_VALUE">*</ph> is not an accepted value for this policy. Note that previously this policy was erroneously enabled on Android, but this functionality has never been fully supported on Android.''', }, @@ -6589,7 +6589,7 @@ Leaving the policy unset means <ph name="DEFAULT_IMAGE_SETTING_ENABLED_POLICY_NAME">DefaultImagesSetting</ph> applies for all sites, if it's set. If not, the user's personal setting applies. - For detailed information on valid <ph name="URL_LABEL">url</ph> patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns. + For detailed information on valid <ph name="URL_LABEL">url</ph> patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns. <ph name="WILDCARD_VALUE">*</ph> is not an accepted value for this policy. Note that previously this policy was erroneously enabled on Android, but this functionality has never been fully supported on Android.''', }, @@ -6614,7 +6614,7 @@ Leaving the policy unset means <ph name="DEFAULT_JAVA_SCRIPT_SETTING_POLICY_NAME">DefaultJavaScriptSetting</ph> applies for all sites, if it's set. If not, the user's personal setting applies. - For detailed information on valid <ph name="URL_LABEL">url</ph> patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns.''', + For detailed information on valid <ph name="URL_LABEL">url</ph> patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns. <ph name="WILDCARD_VALUE">*</ph> is not an accepted value for this policy.''', }, { 'name': 'JavaScriptBlockedForUrls', @@ -6637,7 +6637,7 @@ Leaving the policy unset means <ph name="DEFAULT_JAVA_SCRIPT_SETTING_POLICY_NAME">DefaultJavaScriptSetting</ph> applies for all sites, if it's set. If not, the user's personal setting applies. - For detailed information on valid <ph name="URL_LABEL">url</ph> patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns.''', + For detailed information on valid <ph name="URL_LABEL">url</ph> patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns. <ph name="WILDCARD_VALUE">*</ph> is not an accepted value for this policy.''', }, { 'name': 'KeygenAllowedForUrls', @@ -6661,7 +6661,7 @@ If this policy is left not set the global default value will be used for all sites either from the 'DefaultKeygenSetting' policy if it is set, or the user's personal configuration otherwise. - For detailed information on valid url patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns.''', + For detailed information on valid url patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns. <ph name="WILDCARD_VALUE">*</ph> is not an accepted value for this policy.''', }, { 'name': 'KeygenBlockedForUrls', @@ -6685,7 +6685,7 @@ If this policy is left not set the global default value will be used for all sites either from the 'DefaultKeygenSetting' policy if it is set, or the user's personal configuration otherwise. - For detailed information on valid url patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns.''', + For detailed information on valid url patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns. <ph name="WILDCARD_VALUE">*</ph> is not an accepted value for this policy.''', }, { 'name': 'LegacySameSiteCookieBehaviorEnabled', @@ -6899,7 +6899,7 @@ Leaving the policy unset means <ph name="DEFAULT_POPUPS_SETTING_POLICY_NAME">DefaultPopupsSetting</ph> applies for all sites, if it's set. If not, the user's personal setting applies. - For detailed information on valid <ph name="URL_LABEL">url</ph> patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns.''', + For detailed information on valid <ph name="URL_LABEL">url</ph> patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns. <ph name="WILDCARD_VALUE">*</ph> is not an accepted value for this policy.''', }, { 'name': 'RegisteredProtocolHandlers', @@ -6968,7 +6968,7 @@ Leaving the policy unset means <ph name="DEFAULT_POPUPS_SETTING_POLICY_NAME">DefaultPopupsSetting</ph> applies for all sites, if it's set. If not, the user's personal setting applies. - For detailed information on valid <ph name="URL_LABEL">url</ph> patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns.''', + For detailed information on valid <ph name="URL_LABEL">url</ph> patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns. <ph name="WILDCARD_VALUE">*</ph> is not an accepted value for this policy.''', }, { 'name': 'NotificationsAllowedForUrls', @@ -6991,7 +6991,7 @@ Leaving the policy unset means <ph name="DEFAULT_JAVA_SCRIPT_SETTING_POLICY_NAME">DefaultJavaScriptSetting</ph> applies for all sites, if it's set. If not, the user's personal setting applies. - For detailed information on valid <ph name="URL_LABEL">url</ph> patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns.''', + For detailed information on valid <ph name="URL_LABEL">url</ph> patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns. <ph name="WILDCARD_VALUE">*</ph> is not an accepted value for this policy.''', }, { 'name': 'NotificationsBlockedForUrls', @@ -7014,7 +7014,7 @@ Leaving the policy unset means <ph name="DEFAULT_JAVA_SCRIPT_SETTING_POLICY_NAME">DefaultJavaScriptSetting</ph> applies for all sites, if it's set. If not, the user's personal setting applies. - For detailed information on valid <ph name="URL_LABEL">url</ph> patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns.''', + For detailed information on valid <ph name="URL_LABEL">url</ph> patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns. <ph name="WILDCARD_VALUE">*</ph> is not an accepted value for this policy.''', }, { 'name': 'SensorsAllowedForUrls', @@ -7039,7 +7039,7 @@ If the same URL pattern exists in both this policy and the <ph name="SENSORS_BLOCKED_FOR_URLS_POLICY_NAME">SensorsBlockedForUrls</ph> policy, the latter is prioritized and access to motion or light sensors will be blocked. - For detailed information on valid <ph name="URL_LABEL">url</ph> patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns.''', + For detailed information on valid <ph name="URL_LABEL">url</ph> patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns. <ph name="WILDCARD_VALUE">*</ph> is not an accepted value for this policy.''', }, { 'name': 'SensorsBlockedForUrls', @@ -7064,7 +7064,7 @@ If the same URL pattern exists in both this policy and the <ph name="SENSORS_ALLOWED_FOR_URLS_POLICY_NAME">SensorsAllowedForUrls</ph> policy, this policy is prioritized and access to motion or light sensors will be blocked. - For detailed information on valid <ph name="URL_LABEL">url</ph> patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns.''', + For detailed information on valid <ph name="URL_LABEL">url</ph> patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns. <ph name="WILDCARD_VALUE">*</ph> is not an accepted value for this policy.''', }, { 'name': 'NativeMessagingBlacklist', @@ -22091,7 +22091,7 @@ If this policy is left not set blockable mixed content will be blocked and optionally blockable mixed content will be upgraded, and users will be allowed to set exceptions to allow it for specific sites. - For detailed information on valid url patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns.''', + For detailed information on valid url patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns. <ph name="WILDCARD_VALUE">*</ph> is not an accepted value for this policy.''', }, { 'name': 'InsecureContentBlockedForUrls', @@ -22114,7 +22114,7 @@ If this policy is left not set blockable mixed content will be blocked and optionally blockable mixed content will be upgraded, but users will be allowed to set exceptions to allow it for specific sites. - For detailed information on valid url patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns.''', + For detailed information on valid url patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns. <ph name="WILDCARD_VALUE">*</ph> is not an accepted value for this policy.''', }, { 'name': 'DeviceWebBasedAttestationAllowedUrls',
diff --git a/components/search/repeatable_queries/repeatable_queries_service_unittest.cc b/components/search/repeatable_queries/repeatable_queries_service_unittest.cc index d1b08ed..4e0e81f 100644 --- a/components/search/repeatable_queries/repeatable_queries_service_unittest.cc +++ b/components/search/repeatable_queries/repeatable_queries_service_unittest.cc
@@ -14,6 +14,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/task_environment.h" +#include "build/build_config.h" #include "components/bookmarks/browser/bookmark_model.h" #include "components/bookmarks/test/test_bookmark_client.h" #include "components/history/core/browser/history_service.h" @@ -548,7 +549,16 @@ EXPECT_EQ(expected_server_queries, service()->repeatable_queries()); } -TEST_F(RepeatableQueriesServiceTest, SignedOut_DefaultSearchProviderChanged) { +// TODO(crbug.com/1150909) Test fails on iOS simulators +#if defined(OS_IOS) +#define MAYBE_SignedOut_DefaultSearchProviderChanged \ + DISABLED_SignedOut_DefaultSearchProviderChanged +#else +#define MAYBE_SignedOut_DefaultSearchProviderChanged \ + SignedOut_DefaultSearchProviderChanged +#endif +TEST_F(RepeatableQueriesServiceTest, + MAYBE_SignedOut_DefaultSearchProviderChanged) { int original_query_age = history::kAutocompleteDuplicateVisitIntervalThreshold.InSeconds() + 3; FillURLDatabase({
diff --git a/components/upload_list/text_log_upload_list.cc b/components/upload_list/text_log_upload_list.cc index 5bbadd3..776229b 100644 --- a/components/upload_list/text_log_upload_list.cc +++ b/components/upload_list/text_log_upload_list.cc
@@ -240,7 +240,7 @@ std::unique_ptr<UploadInfo> info = nullptr; base::Optional<base::Value> json = base::JSONReader::Read(line); - if (json.has_value()) + if (json.has_value() && json->is_dict()) info = TryParseJsonLogEntry(json.value()); else info = TryParseCsvLogEntry(line);
diff --git a/components/upload_list/text_log_upload_list_unittest.cc b/components/upload_list/text_log_upload_list_unittest.cc index 29434b4..996fd4a 100644 --- a/components/upload_list/text_log_upload_list_unittest.cc +++ b/components/upload_list/text_log_upload_list_unittest.cc
@@ -596,6 +596,34 @@ EXPECT_EQ(1u, uploads.size()); } +// Test log entry string with only single column. +// Such kind of lines are considered as invalid CSV entry. They should be +// skipped in parsing the log file. +TEST_F(TextLogUploadListTest, SkipBlankOrCorruptedEntry) { + std::string test_entry; + + // Add an empty line. + test_entry += "\n"; + + // Add a line with only single column. + test_entry.append(kTestUploadTime); + test_entry += "\n"; + + WriteUploadLog(test_entry); + + scoped_refptr<TextLogUploadList> upload_list = + new TextLogUploadList(log_path()); + + base::RunLoop run_loop; + upload_list->Load(run_loop.QuitClosure()); + run_loop.Run(); + + std::vector<UploadList::UploadInfo> uploads; + upload_list->GetUploads(999, &uploads); + + EXPECT_EQ(0u, uploads.size()); +} + TEST_F(TextLogUploadListTest, ClearUsingUploadTime) { constexpr time_t kTestTime = 1234u; constexpr char kOtherEntry[] = "4567,def\n";
diff --git a/components/viz/common/display/overlay_strategy.h b/components/viz/common/display/overlay_strategy.h index bd8d68af..3fa5ede 100644 --- a/components/viz/common/display/overlay_strategy.h +++ b/components/viz/common/display/overlay_strategy.h
@@ -21,7 +21,8 @@ kSingleOnTop = 3, kUnderlay = 4, kUnderlayCast = 5, - kMaxValue = kUnderlayCast, + kNoStrategyAllFail = 6, + kMaxValue = kNoStrategyAllFail, }; // Parses a comma separated list of overlay strategy types and returns a list
diff --git a/components/viz/common/features.cc b/components/viz/common/features.cc index e8a259cb..c4ff6bf 100644 --- a/components/viz/common/features.cc +++ b/components/viz/common/features.cc
@@ -18,6 +18,9 @@ namespace features { +const base::Feature kEnableOverlayPrioritization{ + "EnableOverlayPrioritization", base::FEATURE_DISABLED_BY_DEFAULT}; + const base::Feature kForcePreferredIntervalForVideo{ "ForcePreferredIntervalForVideo", base::FEATURE_DISABLED_BY_DEFAULT}; @@ -92,6 +95,10 @@ base::FEATURE_DISABLED_BY_DEFAULT}; #endif // OS_WIN +bool IsOverlayPrioritizationEnabled() { + return base::FeatureList::IsEnabled(kEnableOverlayPrioritization); +} + bool IsForcePreferredIntervalForVideoEnabled() { return base::FeatureList::IsEnabled(kForcePreferredIntervalForVideo); }
diff --git a/components/viz/common/features.h b/components/viz/common/features.h index b7c7376..1fee7c1 100644 --- a/components/viz/common/features.h +++ b/components/viz/common/features.h
@@ -13,6 +13,7 @@ namespace features { +VIZ_COMMON_EXPORT extern const base::Feature kEnableOverlayPrioritization; VIZ_COMMON_EXPORT extern const base::Feature kForcePreferredIntervalForVideo; VIZ_COMMON_EXPORT extern const base::Feature kUseSkiaRenderer; VIZ_COMMON_EXPORT extern const base::Feature kRecordSkPicture; @@ -39,6 +40,7 @@ #if defined(OS_ANDROID) VIZ_COMMON_EXPORT bool IsDynamicColorGamutEnabled(); #endif +VIZ_COMMON_EXPORT bool IsOverlayPrioritizationEnabled(); VIZ_COMMON_EXPORT bool IsUsingFastPathForSolidColorQuad(); VIZ_COMMON_EXPORT bool IsUsingVizForWebView(); VIZ_COMMON_EXPORT bool IsUsingVizFrameSubmissionForWebView();
diff --git a/components/viz/service/display/display.cc b/components/viz/service/display/display.cc index 94877489..6415782 100644 --- a/components/viz/service/display/display.cc +++ b/components/viz/service/display/display.cc
@@ -770,6 +770,7 @@ draw_timer.emplace(); renderer_->DecideRenderPassAllocationsForFrame(frame.render_pass_list); + overlay_processor_->SetFrameSequenceNumber(frame_sequence_number_); renderer_->DrawFrame(&frame.render_pass_list, device_scale_factor_, current_surface_size, display_color_spaces_, &frame.surface_damage_rect_list_); @@ -868,7 +869,6 @@ } client_->DisplayDidDrawAndSwap(); - // Garbage collection can lead to sync IPCs to the GPU service to verify sync // tokens. We defer garbage collection until the end of DrawAndSwap to avoid // stalling the critical path for compositing. @@ -1009,6 +1009,8 @@ !renderer_->GetDelegatedInkTrailDamageRect().IsEmpty()) { scheduler_->SetNeedsOneBeginFrame(true); } + + frame_sequence_number_ = ack.frame_id.sequence_number; } const SurfaceId& Display::CurrentSurfaceId() {
diff --git a/components/viz/service/display/display.h b/components/viz/service/display/display.h index a98ab0ff..525b0f08 100644 --- a/components/viz/service/display/display.h +++ b/components/viz/service/display/display.h
@@ -294,6 +294,7 @@ int64_t last_presented_trace_id_ = 0; int pending_swaps_ = 0; + uint64_t frame_sequence_number_ = 0; // The height of the top-controls in the previously drawn frame. float last_top_controls_visible_height_ = 0.f;
diff --git a/components/viz/service/display/gl_renderer_unittest.cc b/components/viz/service/display/gl_renderer_unittest.cc index a5d550ae..1f1f4924 100644 --- a/components/viz/service/display/gl_renderer_unittest.cc +++ b/components/viz/service/display/gl_renderer_unittest.cc
@@ -2603,6 +2603,32 @@ primary_surface, OverlayCandidateList* candidates, std::vector<gfx::Rect>* content_bounds)); + + void ProposePrioritized( + const SkMatrix44& output_color_matrix, + const FilterOperationsMap& render_pass_backdrop_filters, + DisplayResourceProvider* resource_provider, + AggregatedRenderPassList* render_pass_list, + SurfaceDamageRectList* surface_damage_rect_list, + const PrimaryPlane* primary_plane, + OverlayProposedCandidateList* candidates, + std::vector<gfx::Rect>* content_bounds) override { + auto* render_pass = render_pass_list->back().get(); + QuadList& quad_list = render_pass->quad_list; + OverlayCandidate candidate; + candidates->push_back({quad_list.end(), candidate, this}); + } + + MOCK_METHOD9(AttemptPrioritized, + bool(const SkMatrix44& output_color_matrix, + const FilterOperationsMap& render_pass_backdrop_filters, + DisplayResourceProvider* resource_provider, + AggregatedRenderPassList* render_pass_list, + SurfaceDamageRectList* surface_damage_rect_list, + const PrimaryPlane* primary_plane, + OverlayCandidateList* candidates, + std::vector<gfx::Rect>* content_bounds, + OverlayProposedCandidate* proposed_candidate)); }; bool IsOverlaySupported() const override { return true; } @@ -2626,6 +2652,8 @@ explicit TestOverlayProcessor(OutputSurface* output_surface) : OverlayProcessorUsingStrategy() { strategies_.push_back(std::make_unique<Strategy>()); + prioritization_config_.changing_threshold = false; + prioritization_config_.damage_rate_threshold = false; } ~TestOverlayProcessor() override = default; }; @@ -2734,7 +2762,14 @@ // any attempt to overlay, which there shouldn't be. We can't use the quad // list because the render pass is cleaned up by DrawFrame. #if defined(USE_OZONE) || defined(OS_ANDROID) - EXPECT_CALL(processor->strategy(), Attempt(_, _, _, _, _, _, _, _)).Times(0); + if (features::IsOverlayPrioritizationEnabled()) { + EXPECT_CALL(processor->strategy(), + AttemptPrioritized(_, _, _, _, _, _, _, _, _)) + .Times(0); + } else { + EXPECT_CALL(processor->strategy(), Attempt(_, _, _, _, _, _, _, _)) + .Times(0); + } #elif defined(OS_APPLE) EXPECT_CALL(*mock_ca_processor, ProcessForCALayerOverlays(_, _, _, _, _, _)) .Times(0); @@ -2766,7 +2801,14 @@ SK_ColorTRANSPARENT, vertex_opacity, flipped, nearest_neighbor, /*secure_output_only=*/false, gfx::ProtectedVideoType::kClear); #if defined(USE_OZONE) || defined(OS_ANDROID) - EXPECT_CALL(processor->strategy(), Attempt(_, _, _, _, _, _, _, _)).Times(1); + if (features::IsOverlayPrioritizationEnabled()) { + EXPECT_CALL(processor->strategy(), + AttemptPrioritized(_, _, _, _, _, _, _, _, _)) + .Times(1); + } else { + EXPECT_CALL(processor->strategy(), Attempt(_, _, _, _, _, _, _, _)) + .Times(1); + } #elif defined(OS_APPLE) EXPECT_CALL(*mock_ca_processor, ProcessForCALayerOverlays(_, _, _, _, _, _)) .Times(1); @@ -2790,6 +2832,8 @@ SingleOverlayOnTopProcessor() : OverlayProcessorUsingStrategy() { strategies_.push_back(std::make_unique<OverlayStrategySingleOnTop>(this)); strategies_.push_back(std::make_unique<OverlayStrategyUnderlay>(this)); + prioritization_config_.changing_threshold = false; + prioritization_config_.damage_rate_threshold = false; } bool NeedsSurfaceDamageRectList() const override { return true; } @@ -3815,6 +3859,38 @@ return true; } + void ProposePrioritized( + const SkMatrix44& output_color_matrix, + const FilterOperationsMap& render_pass_backdrop_filters, + DisplayResourceProvider* resource_provider, + AggregatedRenderPassList* render_pass_list, + SurfaceDamageRectList* surface_damage_rect_list, + const PrimaryPlane* primary_plane, + OverlayProposedCandidateList* candidates, + std::vector<gfx::Rect>* content_bounds) override { + auto* render_pass = render_pass_list->back().get(); + QuadList& quad_list = render_pass->quad_list; + OverlayCandidate candidate; + // Adding a mock candidate to the propose list so that + // 'AttemptPrioritized' will be called. + candidates->push_back({quad_list.end(), candidate, this}); + } + + bool AttemptPrioritized( + const SkMatrix44& output_color_matrix, + const FilterOperationsMap& render_pass_backdrop_filters, + DisplayResourceProvider* resource_provider, + AggregatedRenderPassList* render_pass_list, + SurfaceDamageRectList* surface_damage_rect_list, + const PrimaryPlane* primary_plane, + OverlayCandidateList* candidates, + std::vector<gfx::Rect>* content_bounds, + OverlayProposedCandidate* proposed_candidate) override { + content_bounds->insert(content_bounds->end(), content_bounds_.begin(), + content_bounds_.end()); + return true; + } + private: const std::vector<gfx::Rect> content_bounds_; }; @@ -3824,6 +3900,8 @@ : OverlayProcessorUsingStrategy(), content_bounds_(content_bounds) { strategies_.push_back( std::make_unique<Strategy>(std::move(content_bounds_))); + prioritization_config_.changing_threshold = false; + prioritization_config_.damage_rate_threshold = false; } Strategy& strategy() { return static_cast<Strategy&>(*strategies_.back()); }
diff --git a/components/viz/service/display/overlay_candidate.cc b/components/viz/service/display/overlay_candidate.cc index 05e7922..0bfb7b0 100644 --- a/components/viz/service/display/overlay_candidate.cc +++ b/components/viz/service/display/overlay_candidate.cc
@@ -101,15 +101,33 @@ return true; // A damaged surface on top is found. } - return false; // No occluding damges + return false; // No occluding damages } -gfx::Rect GetDamageRect(const SharedQuadState* shared_quad_state, +gfx::Rect GetDamageRect(const DrawQuad* quad, SurfaceDamageRectList* surface_damage_rect_list) { - if (!shared_quad_state->overlay_damage_index.has_value()) - return gfx::Rect(); + const SharedQuadState* sqs = quad->shared_quad_state; + auto& transform = sqs->quad_to_target_transform; + gfx::RectF display_rect = gfx::RectF(quad->rect); + transform.TransformRect(&display_rect); + if (!sqs->overlay_damage_index.has_value()) { + gfx::Rect display_rect_int = gfx::ToRoundedRect(display_rect); + // This is a special case where an overlay candidate may have damage but it + // does not have a damage index since it was not the only quad in the + // original surface. Here the union of all |surface_damage_rect_list| will + // be in effect the full damage for this display. + auto full_display_damage = gfx::Rect(); + for (auto& each : *surface_damage_rect_list) { + full_display_damage.Union(each); + } - size_t overlay_damage_index = shared_quad_state->overlay_damage_index.value(); + // We limit the damage to the candidates quad rect in question. + gfx::Rect intersection = display_rect_int; + intersection.Intersect(full_display_damage); + return intersection; + } + + size_t overlay_damage_index = sqs->overlay_damage_index.value(); // Invalid index. if (overlay_damage_index >= surface_damage_rect_list->size()) { DCHECK(false); @@ -228,8 +246,7 @@ SurfaceDamageRectList* surface_damage_rect_list, QuadList::ConstIterator quad_list_begin, QuadList::ConstIterator quad_list_end) { - gfx::Rect quad_damage = - GetDamageRect(quad->shared_quad_state, surface_damage_rect_list); + gfx::Rect quad_damage = GetDamageRect(quad, surface_damage_rect_list); int occluded_damage_estimate_total = 0; for (auto overlap_iter = quad_list_begin; overlap_iter != quad_list_end; ++overlap_iter) { @@ -327,9 +344,7 @@ // |damage_area_estimate| to more accurately reflect the actual visible // damage. candidate->damage_area_estimate = - GetDamageRect(quad->shared_quad_state, surface_damage_rect_list) - .size() - .GetArea(); + GetDamageRect(quad, surface_damage_rect_list).size().GetArea(); candidate->resource_id = resource_id; candidate->transform = overlay_transform; candidate->mailbox = resource_provider->GetMailbox(resource_id); @@ -360,9 +375,7 @@ // |damage_area_estimate| to more accurately reflect the actual visible // damage. candidate->damage_area_estimate = - GetDamageRect(quad->shared_quad_state, surface_damage_rect_list) - .size() - .GetArea(); + GetDamageRect(quad, surface_damage_rect_list).size().GetArea(); candidate->requires_overlay = OverlayCandidate::RequiresOverlay(quad); return true; }
diff --git a/components/viz/service/display/overlay_candidate_temporal_tracker.cc b/components/viz/service/display/overlay_candidate_temporal_tracker.cc index 9e5328e6..ba81334f 100644 --- a/components/viz/service/display/overlay_candidate_temporal_tracker.cc +++ b/components/viz/service/display/overlay_candidate_temporal_tracker.cc
@@ -7,121 +7,89 @@ namespace viz { void OverlayCandidateTemporalTracker::Reset() { - fps_category = kFrameRateLow; - damage_category = kDamageLow; - for (int i = 0; i < kNumRecords; i++) { - damage_record[i] = 0.0f; - tick_record[i] = base::TimeTicks(); - } + ratio_rate_category = 0; } -void OverlayCandidateTemporalTracker::CategorizeDamageRatio( +int OverlayCandidateTemporalTracker::GetModeledPowerGain( + uint64_t curr_frame, + const OverlayCandidateTemporalTracker::Config& config, + int display_area) { + // Model of proportional power gained by hw overlay promotion. + return static_cast<int>((ratio_rate_category - config.damage_rate_threshold) * + display_area); +} + +void OverlayCandidateTemporalTracker::CategorizeDamageRatioRate( + uint64_t curr_frame, const OverlayCandidateTemporalTracker::Config& config) { - // This function uses member state to provide a hysteresis effect. - if (damage_category == DamageCategory::kDamageHigh) { - if (MeanDamageAreaRatio() < config.damage_low_threshold) { - damage_category = DamageCategory::kDamageLow; - } - } else { - if (MeanDamageAreaRatio() > config.damage_high_threshold) { - damage_category = DamageCategory::kDamageHigh; - } - } -} - -void OverlayCandidateTemporalTracker::CategorizeFrameRate( - base::TimeTicks curr_tick) { - // This function uses member state to provide a hysteresis effect. - static constexpr int64_t kEpsilonMs = 2; - static constexpr int64_t k60FPSMs = 16; - static constexpr int64_t k30FPSMs = 33; - static constexpr int64_t k15FPSMs = 66; - // Visual depiction of the hysteresis of this function: - // * - Go into kFrameRateLow state. - // # - Go into kFrameRate30fps state. - // & - Go into kFrameRate60fps state. - // - // Current fps_category: - // - // kFrameRateLow --&&&&&&&&#################******** - // kFrameRate30fps --&&&&&&&&####################***** - // kFrameRate60fps --&&&&&&&&&&&&&&&&&&&&&&######***** - // mean_frame_time |^^^^^^^^^|^^^^^^^^^|^^^ ... ^^^| - // 10 20 30 60 - // - auto mean_frame_time = MeanFrameMs(); - if (fps_category == FrameRateCategory::kFrameRate60fps) { - if (mean_frame_time > (k15FPSMs - kEpsilonMs)) { - fps_category = FrameRateCategory::kFrameRateLow; - } else if (mean_frame_time > (k30FPSMs - kEpsilonMs)) { - fps_category = FrameRateCategory::kFrameRate30fps; - } - } else if (fps_category == FrameRateCategory::kFrameRate30fps) { - if (mean_frame_time < (k60FPSMs + kEpsilonMs)) { - fps_category = FrameRateCategory::kFrameRate60fps; - } else if (mean_frame_time > (k15FPSMs - kEpsilonMs)) { - fps_category = FrameRateCategory::kFrameRateLow; - } - } else { - if (mean_frame_time < (k60FPSMs + kEpsilonMs)) { - fps_category = FrameRateCategory::kFrameRate60fps; - } else if (mean_frame_time < (k30FPSMs + kEpsilonMs)) { - fps_category = FrameRateCategory::kFrameRate30fps; - } + float mean_ratio_rate = MeanFrameRatioRate(config); + // Simple implementation of hysteresis. If the value is far enough away from + // the stored value it will be updated. + if (std::abs(mean_ratio_rate - ratio_rate_category) >= + config.damage_rate_hysteresis_range) { + ratio_rate_category = mean_ratio_rate; } } bool OverlayCandidateTemporalTracker::IsActivelyChanging( - base::TimeTicks curr_tick, - const OverlayCandidateTemporalTracker::Config& config) { - return LastChangeMs(curr_tick) < config.max_ms_active; + uint64_t curr_frame, + const OverlayCandidateTemporalTracker::Config& config) const { + return LastChangeFrameCount(curr_frame) < config.max_frames_inactive; } void OverlayCandidateTemporalTracker::AddRecord( - base::TimeTicks curr_tick, + uint64_t curr_frame, float damage_area_ratio, unsigned resource_id, const OverlayCandidateTemporalTracker::Config& config) { if (prev_resource_id != resource_id && - tick_record[(next_index + kNumRecords - 1) % kNumRecords] != curr_tick) { - tick_record[next_index] = curr_tick; + frame_record[(next_index + kNumRecords - 1) % kNumRecords] != + curr_frame) { + frame_record[next_index] = curr_frame; damage_record[next_index] = damage_area_ratio; next_index = (next_index + 1) % kNumRecords; prev_resource_id = resource_id; - CategorizeFrameRate(curr_tick); - CategorizeDamageRatio(config); + CategorizeDamageRatioRate(curr_frame, config); } absent = false; } -float OverlayCandidateTemporalTracker::MeanDamageAreaRatio() const { - float sum = 0.0f; - for (auto& damage : damage_record) { - sum += damage; - } - return sum / kNumRecords; -} - -int64_t OverlayCandidateTemporalTracker::LastChangeMs( - base::TimeTicks curr_tick) const { - int64_t diff_now_prev = - (curr_tick - tick_record[((next_index - 1) + kNumRecords) % kNumRecords]) - .InMilliseconds(); +uint64_t OverlayCandidateTemporalTracker::LastChangeFrameCount( + uint64_t curr_frame) const { + uint64_t diff_now_prev = + (curr_frame - + frame_record[((next_index - 1) + kNumRecords) % kNumRecords]); return diff_now_prev; } -int64_t OverlayCandidateTemporalTracker::MeanFrameMs() const { - int64_t mean_time = 0; +float OverlayCandidateTemporalTracker::MeanFrameRatioRate( + const OverlayCandidateTemporalTracker::Config& config) const { + float mean_ratio_rate = 0.f; + int num_records = (kNumRecords - 1); + // We are concerned with the steady state of damage ratio rate. + // A specific interruption (paused video, stopped accelerated ink) is + // categorized by 'IsActivelyChanging' and is intentionally excluded here by + // |skip_single_interruption|. + bool skip_single_interruption = true; for (int i = 0; i < kNumRecords; i++) { if (i != next_index) { - mean_time += - (tick_record[i] - tick_record[((i - 1) + kNumRecords) % kNumRecords]) - .InMilliseconds(); + uint64_t diff_frames = + (frame_record[i] - + frame_record[((i - 1) + kNumRecords) % kNumRecords]); + if (skip_single_interruption && + diff_frames > config.max_frames_inactive) { + skip_single_interruption = false; + num_records--; + } else if (diff_frames != 0) { + float damage_ratio = damage_record[i]; + mean_ratio_rate += damage_ratio / diff_frames; + } } } - return mean_time / (kNumRecords - 1); + + return mean_ratio_rate / num_records; } bool OverlayCandidateTemporalTracker::IsAbsent() {
diff --git a/components/viz/service/display/overlay_candidate_temporal_tracker.h b/components/viz/service/display/overlay_candidate_temporal_tracker.h index 6da011e..42afda5 100644 --- a/components/viz/service/display/overlay_candidate_temporal_tracker.h +++ b/components/viz/service/display/overlay_candidate_temporal_tracker.h
@@ -26,28 +26,36 @@ // experiments. class VIZ_SERVICE_EXPORT Config { public: - // Mean damage above |kDamageHighThreshold| is considered significant. An - // example of this is a youtube video. - float damage_high_threshold = 0.3f; - // Mean damage below |kDamageLowThreshold| is considered insignificant. An - // example of this is a blinking cursor. - float damage_low_threshold = 0.1f; + // This is the only heuristic input constant to our power model. It + // effectively determines the threshold for positive power gain. + float damage_rate_threshold = 0.3f; - // |sMaxMsActive| is a millisecond the cutoff for when an unchanging + // The hysteresis value for damage rate is kept constant within the range of + // |damage_rate_hysteresis_range| + float damage_rate_hysteresis_range = 0.15f; + + // |max_frames_inactive| is the frame count cutoff for when an unchanging // candidate is considered to be inactive. see 'IsActivelyChanging()' - int64_t max_ms_active = 100; + uint64_t max_frames_inactive = 6; }; - enum FrameRateCategory { kFrameRate60fps, kFrameRate30fps, kFrameRateLow }; - enum DamageCategory { kDamageHigh, kDamageLow }; + // This function returns an opaque but comparable value representing the + // power improvement by promoting the tracked candidate to an overlay. + // Negative values indicate that the model suggests a power degradation if the + // candidate is promoted to overlay. + int GetModeledPowerGain(uint64_t curr_frame, + const OverlayCandidateTemporalTracker::Config& config, + int display_area); // This function returns true when the time since the |resource_id| changed // exceeds a specific threshold. - bool IsActivelyChanging(base::TimeTicks curr_tick, const Config& config); + bool IsActivelyChanging(uint64_t curr_frame, const Config& config) const; + + void Reset(); // This function adds a new record to the tracker if the |resource_id| has // changed since last update. - void AddRecord(base::TimeTicks curr_tick, + void AddRecord(uint64_t curr_frame, float damage_area_ratio, unsigned resource_id, const Config& config); @@ -57,29 +65,21 @@ // overlay candidate is no longer present since we are tracking across frames. bool IsAbsent(); - void Reset(); - - FrameRateCategory GetFPSCategory() const { return fps_category; } - bool HasSignificantDamage() { return damage_category == kDamageHigh; } - // The functions and data below are used internally but also can be used for // diagnosis and testing. - int64_t MeanFrameMs() const; - float MeanDamageAreaRatio() const; - int64_t LastChangeMs(base::TimeTicks curr_tick) const; - + float MeanFrameRatioRate(const Config& config) const; + float GetDamageRatioRate() const { return ratio_rate_category; } + uint64_t LastChangeFrameCount(uint64_t curr_frame) const; // Categorization can happen over a series of |KNumRecords| frames. // The more records the smoother the categorization but the worse the latency. static constexpr int kNumRecords = 6; private: - void CategorizeFrameRate(base::TimeTicks curr_tick); - void CategorizeDamageRatio(const Config& config); - + void CategorizeDamageRatioRate(uint64_t curr_frame, const Config& config); unsigned prev_resource_id = kInvalidResourceId; - FrameRateCategory fps_category = kFrameRateLow; - DamageCategory damage_category = kDamageLow; - // Next empty slot index + + float ratio_rate_category = 0.0f; + // Next empty slot index. Used for circular samples buffer. int next_index = 0; // The state of this absent bool is as follows: @@ -90,7 +90,7 @@ // 'IsAbsent()' returns true because |absent| was never reset to false. This // indicating this tracker should be removed. bool absent = false; - base::TimeTicks tick_record[kNumRecords] = {}; + uint64_t frame_record[kNumRecords] = {}; float damage_record[kNumRecords] = {}; };
diff --git a/components/viz/service/display/overlay_processor_interface.h b/components/viz/service/display/overlay_processor_interface.h index 2c7514b..68132d98 100644 --- a/components/viz/service/display/overlay_processor_interface.h +++ b/components/viz/service/display/overlay_processor_interface.h
@@ -165,6 +165,10 @@ virtual void SetDisplayTransformHint(gfx::OverlayTransform transform) {} virtual void SetViewportSize(const gfx::Size& size) {} + // Overlay processor uses a frame counter to determine the potential power + // benefits of individual overlay candidates. + virtual void SetFrameSequenceNumber(uint64_t frame_sequence_number) {} + protected: OverlayProcessorInterface() {}
diff --git a/components/viz/service/display/overlay_processor_using_strategy.cc b/components/viz/service/display/overlay_processor_using_strategy.cc index 02a15ef..945fb3a 100644 --- a/components/viz/service/display/overlay_processor_using_strategy.cc +++ b/components/viz/service/display/overlay_processor_using_strategy.cc
@@ -6,10 +6,12 @@ #include <vector> +#include "base/feature_list.h" #include "base/memory/ptr_util.h" #include "base/metrics/histogram_macros.h" #include "base/trace_event/trace_event.h" #include "build/build_config.h" +#include "components/viz/common/features.h" #include "components/viz/common/quads/solid_color_draw_quad.h" #include "components/viz/service/display/display_resource_provider.h" #include "components/viz/service/display/output_surface.h" @@ -18,8 +20,22 @@ #include "ui/gfx/geometry/rect_conversions.h" #include "ui/gfx/transform.h" +#include "components/viz/common/quads/texture_draw_quad.h" + namespace viz { +static void LogStrategyEnumUMA(OverlayStrategy strategy) { + UMA_HISTOGRAM_ENUMERATION("Viz.DisplayCompositor.OverlayStrategy", strategy); +} + +OverlayProcessorUsingStrategy::ProposedCandidateKey +OverlayProcessorUsingStrategy::ToProposeKey( + const OverlayProcessorUsingStrategy::Strategy::OverlayProposedCandidate& + proposed) { + return {gfx::ToRoundedRect(proposed.candidate.display_rect), + proposed.strategy->GetUMAEnum()}; +} + // Default implementation of whether a strategy would remove the output surface // as overlay plane. bool OverlayProcessorUsingStrategy::Strategy::RemoveOutputSurfaceAsOverlay() { @@ -53,6 +69,11 @@ const CandidateList& candidates, const QuadList& quad_list) {} +void OverlayProcessorUsingStrategy::SetFrameSequenceNumber( + uint64_t frame_sequence_number) { + frame_sequence_number_ = frame_sequence_number; +} + void OverlayProcessorUsingStrategy::ProcessForOverlays( DisplayResourceProvider* resource_provider, AggregatedRenderPassList* render_passes, @@ -67,7 +88,6 @@ std::vector<gfx::Rect>* content_bounds) { TRACE_EVENT0("viz", "OverlayProcessorUsingStrategy::ProcessForOverlays"); DCHECK(candidates->empty()); - auto* render_pass = render_passes->back().get(); // If we have any copy requests, we can't remove any quads for overlays or @@ -76,6 +96,9 @@ if (!render_pass->copy_requests.empty()) { // Reset |previous_frame_underlay_rect_| in case UpdateDamageRect() not // being invoked. Also reset |previous_frame_underlay_was_unoccluded_|. + if (!previous_frame_underlay_rect_.IsEmpty()) + damage_rect->Union(previous_frame_underlay_rect_); + previous_frame_underlay_rect_ = gfx::Rect(); previous_frame_underlay_was_unoccluded_ = false; NotifyOverlayPromotion(resource_provider, *candidates, @@ -84,10 +107,19 @@ } // Only if that fails, attempt hardware overlay strategies. - bool success = AttemptWithStrategies( - output_color_matrix, render_pass_backdrop_filters, resource_provider, - render_passes, surface_damage_rect_list, output_surface_plane, candidates, - content_bounds); + bool success = false; + + if (features::IsOverlayPrioritizationEnabled()) { + success = AttemptWithStrategiesPrioritized( + output_color_matrix, render_pass_backdrop_filters, resource_provider, + render_passes, surface_damage_rect_list, output_surface_plane, + candidates, content_bounds, damage_rect); + } else { + success = AttemptWithStrategies( + output_color_matrix, render_pass_backdrop_filters, resource_provider, + render_passes, surface_damage_rect_list, output_surface_plane, + candidates, content_bounds); + } if (success) { UpdateDamageRect(candidates, previous_frame_underlay_rect_, @@ -105,6 +137,7 @@ NotifyOverlayPromotion(resource_provider, *candidates, render_pass->quad_list); + TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("viz.debug.overlay_planes"), "Scheduled overlay planes", candidates->size()); } @@ -154,6 +187,7 @@ bool same_underlay_rect = this_frame_underlay_rect == previous_frame_underlay_rect; + bool transition_from_occluded_to_unoccluded = overlay.is_unoccluded && !previous_frame_underlay_was_unoccluded; bool always_unoccluded = @@ -219,14 +253,145 @@ // This function is used by underlay strategy to mark the primary plane as // enable_blending. strategy->AdjustOutputSurfaceOverlay(primary_plane); - UMA_HISTOGRAM_ENUMERATION("Viz.DisplayCompositor.OverlayStrategy", - strategy->GetUMAEnum()); + LogStrategyEnumUMA(strategy->GetUMAEnum()); last_successful_strategy_ = strategy.get(); return true; } } - UMA_HISTOGRAM_ENUMERATION("Viz.DisplayCompositor.OverlayStrategy", - OverlayStrategy::kNoStrategyUsed); + + LogStrategyEnumUMA(OverlayStrategy::kNoStrategyUsed); + return false; +} + +void OverlayProcessorUsingStrategy::SortProposedOverlayCandidatesPrioritized( + Strategy::OverlayProposedCandidateList* proposed_candidates) { + // Removes trackers for candidates that are no longer being rendered. + for (auto it = tracked_candidates.begin(); it != tracked_candidates.end();) { + if (it->second.IsAbsent()) { + it = tracked_candidates.erase(it); + } else { + ++it; + } + } + + // This loop fills in data for the heuristic sort and thresholds candidates. + for (auto it = proposed_candidates->begin(); + it != proposed_candidates->end();) { + auto key = ToProposeKey(*it); + // If no tracking exists we create a new one here. + auto& track_data = tracked_candidates[key]; + auto display_area = it->candidate.display_rect.size().GetArea(); + track_data.AddRecord( + frame_sequence_number_, + static_cast<float>(it->candidate.damage_area_estimate) / display_area, + it->candidate.resource_id, tracker_config_); + + // Here a series of criteria are considered for wholesale rejection of a + // candidate. The rational for rejection is usually power improvements but + // this can indirectly reallocate limited overlay resources to another + // candidate. + bool passes_min_threshold = + ((track_data.IsActivelyChanging(frame_sequence_number_, + tracker_config_) || + !prioritization_config_.changing_threshold) && + (track_data.GetModeledPowerGain(frame_sequence_number_, + tracker_config_, display_area) > 0 || + !prioritization_config_.damage_rate_threshold)); + + if (it->candidate.requires_overlay || passes_min_threshold) { + it->relative_power_gain = track_data.GetModeledPowerGain( + frame_sequence_number_, tracker_config_, display_area); + ++it; + } else { + // We 'Reset' rather than delete the |track_data| because this candidate + // will still be present next frame. + track_data.Reset(); + it = proposed_candidates->erase(it); + } + } + + // Heuristic sorting: + // The stable sort of proposed candidates will not change the prioritized + // order of candidates that have equal sort. What this means is that in a + // situation where there are multiple candidates with identical rects we will + // output a sort that respects the original strategies order. An example of + // this would be the single_on_top strategy coming before the underlay + // strategy for a overlay candidate that has zero occlusion. This sort + // function must provide weak ordering. + auto prio_config = prioritization_config_; + std::stable_sort( + proposed_candidates->begin(), proposed_candidates->end(), + [prio_config](const auto& a, const auto& b) { + // DRM/CDM HW overlay required: + // This comparison is for correctness over performance reasons. Some + // candidates must be an HW overlay to function. If both require an HW + // overlay we sort on the remaining criteria below. + if (a.candidate.requires_overlay ^ b.candidate.requires_overlay) { + return a.candidate.requires_overlay; + } + + // Opaque Power Metric: + // |relative_power_gain| is computed in the tracker for each overlay + // candidate and being proportional to power saved is directly + // comparable. + if (prio_config.power_gain_sort) { + if (a.relative_power_gain != b.relative_power_gain) { + return a.relative_power_gain > b.relative_power_gain; + } + } + + return false; + }); +} + +bool OverlayProcessorUsingStrategy::AttemptWithStrategiesPrioritized( + const SkMatrix44& output_color_matrix, + const OverlayProcessorInterface::FilterOperationsMap& + render_pass_backdrop_filters, + DisplayResourceProvider* resource_provider, + AggregatedRenderPassList* render_pass_list, + SurfaceDamageRectList* surface_damage_rect_list, + OverlayProcessorInterface::OutputSurfaceOverlayPlane* primary_plane, + OverlayCandidateList* candidates, + std::vector<gfx::Rect>* content_bounds, + gfx::Rect* incoming_damage) { + last_successful_strategy_ = nullptr; + + Strategy::OverlayProposedCandidateList proposed_candidates; + for (const auto& strategy : strategies_) { + strategy->ProposePrioritized( + output_color_matrix, render_pass_backdrop_filters, resource_provider, + render_pass_list, surface_damage_rect_list, primary_plane, + &proposed_candidates, content_bounds); + } + + UMA_HISTOGRAM_COUNTS_1000( + "Viz.DisplayCompositor.OverlayNumProposedCandidates", + proposed_candidates.size()); + + SortProposedOverlayCandidatesPrioritized(&proposed_candidates); + + for (auto&& candidate : proposed_candidates) { + if (candidate.strategy->AttemptPrioritized( + output_color_matrix, render_pass_backdrop_filters, + resource_provider, render_pass_list, surface_damage_rect_list, + primary_plane, candidates, content_bounds, &candidate)) { + // This function is used by underlay strategy to mark the primary plane as + // enable_blending. + candidate.strategy->AdjustOutputSurfaceOverlay(primary_plane); + LogStrategyEnumUMA(candidate.strategy->GetUMAEnum()); + last_successful_strategy_ = candidate.strategy; + OnOverlaySwitchUMA(ToProposeKey(candidate)); + return true; + } + } + + if (proposed_candidates.size() == 0) { + LogStrategyEnumUMA(OverlayStrategy::kNoStrategyUsed); + } else { + LogStrategyEnumUMA(OverlayStrategy::kNoStrategyAllFail); + } + OnOverlaySwitchUMA(ProposedCandidateKey()); return false; } @@ -234,4 +399,16 @@ const OverlayCandidate& overlay) const { return ToEnclosedRect(overlay.display_rect); } + +void OverlayProcessorUsingStrategy::OnOverlaySwitchUMA( + OverlayProcessorUsingStrategy::ProposedCandidateKey overlay_tracking_id) { + auto curr_tick = base::TimeTicks::Now(); + if (!(prev_overlay_tracking_id_ == overlay_tracking_id)) { + prev_overlay_tracking_id_ = overlay_tracking_id; + UMA_HISTOGRAM_TIMES("Viz.DisplayCompositor.OverlaySwitchInterval", + curr_tick - last_time_interval_switch_overlay_tick_); + last_time_interval_switch_overlay_tick_ = curr_tick; + } +} + } // namespace viz
diff --git a/components/viz/service/display/overlay_processor_using_strategy.h b/components/viz/service/display/overlay_processor_using_strategy.h index c4821f5a..f90aeb7 100644 --- a/components/viz/service/display/overlay_processor_using_strategy.h +++ b/components/viz/service/display/overlay_processor_using_strategy.h
@@ -6,6 +6,7 @@ #define COMPONENTS_VIZ_SERVICE_DISPLAY_OVERLAY_PROCESSOR_USING_STRATEGY_H_ #include <memory> +#include <unordered_map> #include <vector> #include "base/containers/flat_map.h" @@ -15,6 +16,7 @@ #include "components/viz/common/quads/aggregated_render_pass.h" #include "components/viz/service/display/output_surface.h" #include "components/viz/service/display/overlay_candidate.h" +#include "components/viz/service/display/overlay_candidate_temporal_tracker.h" #include "components/viz/service/display/overlay_processor_interface.h" #include "components/viz/service/viz_service_export.h" #include "gpu/ipc/common/surface_handle.h" @@ -30,12 +32,32 @@ : public OverlayProcessorInterface { public: using CandidateList = OverlayCandidateList; - // TODO(weiliangc): Move it to an external class. class VIZ_SERVICE_EXPORT Strategy { public: - virtual ~Strategy() {} + class VIZ_SERVICE_EXPORT OverlayProposedCandidate { + public: + OverlayProposedCandidate(QuadList::Iterator it, + OverlayCandidate overlay_candidate, + Strategy* overlay_strategy) + : quad_iter(it), + candidate(overlay_candidate), + strategy(overlay_strategy) {} + + // A iterator in the vector of quads. + QuadList::Iterator quad_iter; + OverlayCandidate candidate; + Strategy* strategy = nullptr; + + // heuristic sort element + int relative_power_gain = 0; + }; + + using OverlayProposedCandidateList = std::vector<OverlayProposedCandidate>; + + virtual ~Strategy() = default; using PrimaryPlane = OverlayProcessorInterface::OutputSurfaceOverlayPlane; + // Returns false if the strategy cannot be made to work with the // current set of render passes. Returns true if the strategy was successful // and adds any additional passes necessary to represent overlays to @@ -51,6 +73,36 @@ OverlayCandidateList* candidates, std::vector<gfx::Rect>* content_bounds) = 0; + // Appends all legitimate overlay candidates to the list |candidates| + // for this strategy. It is very important to note that this function + // should not attempt a specific candidate it should merely identify them + // and save the necessary data required to for a later attempt. + virtual void ProposePrioritized( + const SkMatrix44& output_color_matrix, + const FilterOperationsMap& render_pass_backdrop_filters, + DisplayResourceProvider* resource_provider, + AggregatedRenderPassList* render_pass_list, + SurfaceDamageRectList* surface_damage_rect_list, + const PrimaryPlane* primary_plane, + OverlayProposedCandidateList* candidates, + std::vector<gfx::Rect>* content_bounds) = 0; + + // Returns false if the specific |proposed_candidate| cannot be made to work + // for this strategy with the current set of render passes. Returns true if + // the strategy was successful and adds any additional passes necessary to + // represent overlays to |render_pass_list|. Most strategies should look at + // the primary RenderPass, the last element. + virtual bool AttemptPrioritized( + const SkMatrix44& output_color_matrix, + const FilterOperationsMap& render_pass_backdrop_filters, + DisplayResourceProvider* resource_provider, + AggregatedRenderPassList* render_pass_list, + SurfaceDamageRectList* surface_damage_rect_list, + const PrimaryPlane* primary_plane, + OverlayCandidateList* candidates, + std::vector<gfx::Rect>* content_bounds, + OverlayProposedCandidate* proposed_candidate) = 0; + // Currently this is only overridden by the Underlay strategy: the underlay // strategy needs to enable blending for the primary plane in order to show // content underneath. @@ -74,7 +126,7 @@ // Override OverlayProcessor. void SetDisplayTransformHint(gfx::OverlayTransform transform) override {} void SetViewportSize(const gfx::Size& size) override {} - + void SetFrameSequenceNumber(uint64_t frame_sequence_number_) override; // Attempt to replace quads from the specified root render pass with overlays. // This must be called every frame. void ProcessForOverlays( @@ -121,6 +173,20 @@ gfx::Rect previous_frame_underlay_rect_; bool previous_frame_underlay_was_unoccluded_ = false; + struct OverlayPrioritizationConfig { + // Threshold criteria required for a proposed candidate to be considered for + // overlay promotion + bool changing_threshold = true; + bool damage_rate_threshold = true; + + // Sorting criteria that determines the relative order of consideration for + // a overlay candidate. + bool power_gain_sort = true; + }; + + OverlayPrioritizationConfig prioritization_config_; + OverlayCandidateTemporalTracker::Config tracker_config_; + private: // Update |damage_rect| by removing damage caused by |candidates|. void UpdateDamageRect(OverlayCandidateList* candidates, @@ -133,8 +199,8 @@ // Returns true if one of the attempts is successful. Has to be called after // InitializeStrategies(). A |primary_plane| represents the output surface's // buffer that comes from |BufferQueue|. It is passed in here so it could be - // pass through to hardware through CheckOverlaySupport. It is not passed in - // as a const member because the underlay strategy changes the + // pass through to hardware through CheckOverlaySupport. It is not passed + // through as a const member because the underlay strategy changes the // |primary_plane|'s blending setting. bool AttemptWithStrategies( const SkMatrix44& output_color_matrix, @@ -147,12 +213,67 @@ OverlayCandidateList* candidates, std::vector<gfx::Rect>* content_bounds); + // Iterate through a list of strategies and attempt to overlay with each. + // Returns true if one of the attempts is successful. Has to be called after + // InitializeStrategies(). A |primary_plane| represents the output surface's + // buffer that comes from |BufferQueue|. It is passed in here so it could be + // pass through to hardware through CheckOverlaySupport. It is not passed + // through as a const member because the underlay strategy changes the + // |primary_plane|'s blending setting. + bool AttemptWithStrategiesPrioritized( + const SkMatrix44& output_color_matrix, + const OverlayProcessorInterface::FilterOperationsMap& + render_pass_backdrop_filters, + DisplayResourceProvider* resource_provider, + AggregatedRenderPassList* render_pass_list, + SurfaceDamageRectList* surface_damage_rect_list, + OverlayProcessorInterface::OutputSurfaceOverlayPlane* primary_plane, + OverlayCandidateList* candidates, + std::vector<gfx::Rect>* content_bounds, + gfx::Rect* incoming_damage); + + // This function reorders and removes |proposed_candidates| based on a + // heuristic designed to maximize the effectiveness of the limited number + // of Hardware overlays. Effectiveness here is primarily about power and + // secondarily about of performance. + void SortProposedOverlayCandidatesPrioritized( + Strategy::OverlayProposedCandidateList* proposed_candidates); + // Used by Android pre-SurfaceControl to notify promotion hints. virtual void NotifyOverlayPromotion( DisplayResourceProvider* display_resource_provider, const OverlayCandidateList& candidate_list, const QuadList& quad_list); + struct ProposedCandidateKey { + gfx::Rect rect; + OverlayStrategy strategy_id = OverlayStrategy::kUnknown; + + bool operator==(const ProposedCandidateKey& other) const { + return (rect == other.rect && strategy_id == other.strategy_id); + } + }; + + struct ProposedCandidateKeyHasher { + std::size_t operator()(const ProposedCandidateKey& k) const { + return base::Hash(&k, sizeof(k)); + } + }; + + static ProposedCandidateKey ToProposeKey( + const Strategy::OverlayProposedCandidate& proposed); + + std::unordered_map<ProposedCandidateKey, + OverlayCandidateTemporalTracker, + ProposedCandidateKeyHasher> + tracked_candidates; + + // These variables are used only for UMA purposes. + void OnOverlaySwitchUMA(ProposedCandidateKey overlay_tracking_key); + base::TimeTicks last_time_interval_switch_overlay_tick_; + ProposedCandidateKey prev_overlay_tracking_id_; + uint64_t frame_sequence_number_ = 0; + DISALLOW_COPY_AND_ASSIGN(OverlayProcessorUsingStrategy); };
diff --git a/components/viz/service/display/overlay_strategy_fullscreen.cc b/components/viz/service/display/overlay_strategy_fullscreen.cc index 11d6b34..98358d6 100644 --- a/components/viz/service/display/overlay_strategy_fullscreen.cc +++ b/components/viz/service/display/overlay_strategy_fullscreen.cc
@@ -76,6 +76,77 @@ return true; } +void OverlayStrategyFullscreen::ProposePrioritized( + const SkMatrix44& output_color_matrix, + const OverlayProcessorInterface::FilterOperationsMap& + render_pass_backdrop_filters, + DisplayResourceProvider* resource_provider, + AggregatedRenderPassList* render_pass_list, + SurfaceDamageRectList* surface_damage_rect_list, + const PrimaryPlane* primary_plane, + OverlayProposedCandidateList* candidates, + std::vector<gfx::Rect>* content_bounds) { + auto* render_pass = render_pass_list->back().get(); + QuadList* quad_list = &render_pass->quad_list; + + // First non invisible quad of quad_list is the top most quad. + auto front = quad_list->begin(); + while (front != quad_list->end()) { + if (!OverlayCandidate::IsInvisibleQuad(*front)) + break; + ++front; + } + + if (front == quad_list->end()) + return; + + const DrawQuad* quad = *front; + if (quad->ShouldDrawWithBlending()) + return; + + OverlayCandidate candidate; + if (!OverlayCandidate::FromDrawQuad(resource_provider, + surface_damage_rect_list, + output_color_matrix, quad, &candidate)) { + return; + } + + if (!candidate.display_rect.origin().IsOrigin() || + gfx::ToRoundedSize(candidate.display_rect.size()) != + render_pass->output_rect.size()) { + return; + } + candidate.is_opaque = true; + candidate.plane_z_order = 0; + candidates->push_back({front, candidate, this}); +} + +bool OverlayStrategyFullscreen::AttemptPrioritized( + const SkMatrix44& output_color_matrix, + const OverlayProcessorInterface::FilterOperationsMap& + render_pass_backdrop_filters, + DisplayResourceProvider* resource_provider, + AggregatedRenderPassList* render_pass_list, + SurfaceDamageRectList* surface_damage_rect_list, + const PrimaryPlane* primary_plane, + OverlayCandidateList* candidate_list, + std::vector<gfx::Rect>* content_bounds, + OverlayProposedCandidate* proposed_candidate) { + // Before we attempt an overlay strategy, the candidate list should be empty. + DCHECK(candidate_list->empty()); + + OverlayCandidateList new_candidate_list; + new_candidate_list.push_back(proposed_candidate->candidate); + capability_checker_->CheckOverlaySupport(primary_plane, &new_candidate_list); + if (!new_candidate_list.front().overlay_handled) + return false; + + candidate_list->swap(new_candidate_list); + auto* render_pass = render_pass_list->back().get(); + render_pass->quad_list = QuadList(); // Remove all the quads + return true; +} + OverlayStrategy OverlayStrategyFullscreen::GetUMAEnum() const { return OverlayStrategy::kFullscreen; }
diff --git a/components/viz/service/display/overlay_strategy_fullscreen.h b/components/viz/service/display/overlay_strategy_fullscreen.h index 958b6da..a7588b3 100644 --- a/components/viz/service/display/overlay_strategy_fullscreen.h +++ b/components/viz/service/display/overlay_strategy_fullscreen.h
@@ -32,6 +32,28 @@ OverlayCandidateList* candidate_list, std::vector<gfx::Rect>* content_bounds) override; + void ProposePrioritized(const SkMatrix44& output_color_matrix, + const OverlayProcessorInterface::FilterOperationsMap& + render_pass_backdrop_filters, + DisplayResourceProvider* resource_provider, + AggregatedRenderPassList* render_pass_list, + SurfaceDamageRectList* surface_damage_rect_list, + const PrimaryPlane* primary_plane, + OverlayProposedCandidateList* candidates, + std::vector<gfx::Rect>* content_bounds) override; + + bool AttemptPrioritized( + const SkMatrix44& output_color_matrix, + const OverlayProcessorInterface::FilterOperationsMap& + render_pass_backdrop_filters, + DisplayResourceProvider* resource_provider, + AggregatedRenderPassList* render_pass_list, + SurfaceDamageRectList* surface_damage_rect_list, + const PrimaryPlane* primary_plane, + OverlayCandidateList* candidates, + std::vector<gfx::Rect>* content_bounds, + OverlayProposedCandidate* proposed_candidate) override; + bool RemoveOutputSurfaceAsOverlay() override; OverlayStrategy GetUMAEnum() const override;
diff --git a/components/viz/service/display/overlay_strategy_single_on_top.cc b/components/viz/service/display/overlay_strategy_single_on_top.cc index dfbdfb5..0a5b383 100644 --- a/components/viz/service/display/overlay_strategy_single_on_top.cc +++ b/components/viz/service/display/overlay_strategy_single_on_top.cc
@@ -75,6 +75,52 @@ } } +void OverlayStrategySingleOnTop::ProposePrioritized( + const SkMatrix44& output_color_matrix, + const OverlayProcessorInterface::FilterOperationsMap& + render_pass_backdrop_filters, + DisplayResourceProvider* resource_provider, + AggregatedRenderPassList* render_pass_list, + SurfaceDamageRectList* surface_damage_rect_list, + const PrimaryPlane* primary_plane, + OverlayProposedCandidateList* candidates, + std::vector<gfx::Rect>* content_bounds) { + auto* render_pass = render_pass_list->back().get(); + QuadList* quad_list = &render_pass->quad_list; + // Build a list of candidates with the associated quad. + OverlayCandidate best_candidate; + auto best_quad_it = quad_list->end(); + for (auto it = quad_list->begin(); it != quad_list->end(); ++it) { + OverlayCandidate candidate; + if (OverlayCandidate::FromDrawQuad(resource_provider, + surface_damage_rect_list, + output_color_matrix, *it, &candidate) && + !OverlayCandidate::IsOccluded(candidate, quad_list->cbegin(), it)) { + candidates->push_back({it, candidate, this}); + } + } +} + +bool OverlayStrategySingleOnTop::AttemptPrioritized( + const SkMatrix44& output_color_matrix, + const OverlayProcessorInterface::FilterOperationsMap& + render_pass_backdrop_filters, + DisplayResourceProvider* resource_provider, + AggregatedRenderPassList* render_pass_list, + SurfaceDamageRectList* surface_damage_rect_list, + const PrimaryPlane* primary_plane, + OverlayCandidateList* candidate_list, + std::vector<gfx::Rect>* content_bounds, + OverlayProposedCandidate* proposed_candidate) { + // Before we attempt an overlay strategy, we shouldn't have a candidate. + DCHECK(candidate_list->empty()); + auto* render_pass = render_pass_list->back().get(); + QuadList* quad_list = &render_pass->quad_list; + return TryOverlay(quad_list, primary_plane, candidate_list, + proposed_candidate->candidate, + proposed_candidate->quad_iter); +} + bool OverlayStrategySingleOnTop::TryOverlay( QuadList* quad_list, const PrimaryPlane* primary_plane,
diff --git a/components/viz/service/display/overlay_strategy_single_on_top.h b/components/viz/service/display/overlay_strategy_single_on_top.h index 133faa2..5839aa6 100644 --- a/components/viz/service/display/overlay_strategy_single_on_top.h +++ b/components/viz/service/display/overlay_strategy_single_on_top.h
@@ -31,6 +31,28 @@ OverlayCandidateList* candidate_list, std::vector<gfx::Rect>* content_bounds) override; + void ProposePrioritized(const SkMatrix44& output_color_matrix, + const OverlayProcessorInterface::FilterOperationsMap& + render_pass_backdrop_filters, + DisplayResourceProvider* resource_provider, + AggregatedRenderPassList* render_pass_list, + SurfaceDamageRectList* surface_damage_rect_list, + const PrimaryPlane* primary_plane, + OverlayProposedCandidateList* candidates, + std::vector<gfx::Rect>* content_bounds) override; + + bool AttemptPrioritized( + const SkMatrix44& output_color_matrix, + const OverlayProcessorInterface::FilterOperationsMap& + render_pass_backdrop_filters, + DisplayResourceProvider* resource_provider, + AggregatedRenderPassList* render_pass_list, + SurfaceDamageRectList* surface_damage_rect_list, + const PrimaryPlane* primary_plane, + OverlayCandidateList* candidates, + std::vector<gfx::Rect>* content_bounds, + OverlayProposedCandidate* proposed_candidate) override; + OverlayStrategy GetUMAEnum() const override; private:
diff --git a/components/viz/service/display/overlay_strategy_underlay.cc b/components/viz/service/display/overlay_strategy_underlay.cc index 3efb304..b1e48b65 100644 --- a/components/viz/service/display/overlay_strategy_underlay.cc +++ b/components/viz/service/display/overlay_strategy_underlay.cc
@@ -90,6 +90,97 @@ return false; } +void OverlayStrategyUnderlay::ProposePrioritized( + const SkMatrix44& output_color_matrix, + const OverlayProcessorInterface::FilterOperationsMap& + render_pass_backdrop_filters, + DisplayResourceProvider* resource_provider, + AggregatedRenderPassList* render_pass_list, + SurfaceDamageRectList* surface_damage_rect_list, + const PrimaryPlane* primary_plane, + OverlayProposedCandidateList* candidates, + std::vector<gfx::Rect>* content_bounds) { + auto* render_pass = render_pass_list->back().get(); + QuadList& quad_list = render_pass->quad_list; + + for (auto it = quad_list.begin(); it != quad_list.end(); ++it) { + OverlayCandidate candidate; + + if (!OverlayCandidate::FromDrawQuad(resource_provider, + surface_damage_rect_list, + output_color_matrix, *it, &candidate) || + (opaque_mode_ == OpaqueMode::RequireOpaqueCandidates && + !candidate.is_opaque)) { + continue; + } + + // Filters read back the framebuffer to get the pixel values that need to + // be filtered. This is a problem when there are hardware planes because + // the planes are not composited until they are on the display controller. + if (OverlayCandidate::IsOccludedByFilteredQuad( + candidate, quad_list.begin(), it, render_pass_backdrop_filters)) { + continue; + } + + candidate.damage_area_estimate = OverlayCandidate::EstimateVisibleDamage( + *it, surface_damage_rect_list, quad_list.begin(), it); + + candidates->push_back({it, candidate, this}); + } +} + +bool OverlayStrategyUnderlay::AttemptPrioritized( + const SkMatrix44& output_color_matrix, + const OverlayProcessorInterface::FilterOperationsMap& + render_pass_backdrop_filters, + DisplayResourceProvider* resource_provider, + AggregatedRenderPassList* render_pass_list, + SurfaceDamageRectList* surface_damage_rect_list, + const PrimaryPlane* primary_plane, + OverlayCandidateList* candidate_list, + std::vector<gfx::Rect>* content_bounds, + OverlayProposedCandidate* proposed_candidate) { + // Before we attempt an overlay strategy, the candidate list should be empty. + DCHECK(candidate_list->empty()); + auto* render_pass = render_pass_list->back().get(); + QuadList& quad_list = render_pass->quad_list; + // Add the overlay. + OverlayCandidateList new_candidate_list = *candidate_list; + new_candidate_list.push_back(proposed_candidate->candidate); + new_candidate_list.back().plane_z_order = -1; + + if (primary_plane) { + // Since there is a list of strategies to go through, each strategy should + // not change the input parameters. In this case, we need to keep the + // |primary_plane| unchanged. The underlay strategy only works when the + // |primary_plane| supports blending. In order to check the hardware + // support, make a copy of the |primary_plane| with blending enabled. + PrimaryPlane new_plane_candidate(*primary_plane); + new_plane_candidate.enable_blending = true; + // Check for support. + capability_checker_->CheckOverlaySupport(&new_plane_candidate, + &new_candidate_list); + } else { + capability_checker_->CheckOverlaySupport(nullptr, &new_candidate_list); + } + + // If the candidate can be handled by an overlay, create a pass for it. We + // need to switch out the video quad with a black transparent one. + if (new_candidate_list.back().overlay_handled) { + new_candidate_list.back().is_unoccluded = !OverlayCandidate::IsOccluded( + proposed_candidate->candidate, quad_list.cbegin(), + proposed_candidate->quad_iter); + + render_pass->ReplaceExistingQuadWithOpaqueTransparentSolidColor( + proposed_candidate->quad_iter); + candidate_list->swap(new_candidate_list); + + return true; + } + + return false; +} + // Turn on blending for the output surface plane so the underlay could show // through. void OverlayStrategyUnderlay::AdjustOutputSurfaceOverlay(
diff --git a/components/viz/service/display/overlay_strategy_underlay.h b/components/viz/service/display/overlay_strategy_underlay.h index ac046ee..7e02e95 100644 --- a/components/viz/service/display/overlay_strategy_underlay.h +++ b/components/viz/service/display/overlay_strategy_underlay.h
@@ -46,6 +46,28 @@ OverlayCandidateList* candidate_list, std::vector<gfx::Rect>* content_bounds) override; + void ProposePrioritized(const SkMatrix44& output_color_matrix, + const OverlayProcessorInterface::FilterOperationsMap& + render_pass_backdrop_filters, + DisplayResourceProvider* resource_provider, + AggregatedRenderPassList* render_pass_list, + SurfaceDamageRectList* surface_damage_rect_list, + const PrimaryPlane* primary_plane, + OverlayProposedCandidateList* candidates, + std::vector<gfx::Rect>* content_bounds) override; + + bool AttemptPrioritized( + const SkMatrix44& output_color_matrix, + const OverlayProcessorInterface::FilterOperationsMap& + render_pass_backdrop_filters, + DisplayResourceProvider* resource_provider, + AggregatedRenderPassList* render_pass_list, + SurfaceDamageRectList* surface_damage_rect_list, + const PrimaryPlane* primary_plane, + OverlayCandidateList* candidates, + std::vector<gfx::Rect>* content_bounds, + OverlayProposedCandidate* proposed_candidate) override; + void AdjustOutputSurfaceOverlay( OverlayProcessorInterface::OutputSurfaceOverlayPlane* output_surface_plane) override;
diff --git a/components/viz/service/display/overlay_strategy_underlay_cast.cc b/components/viz/service/display/overlay_strategy_underlay_cast.cc index 93c0743..dcf6461 100644 --- a/components/viz/service/display/overlay_strategy_underlay_cast.cc +++ b/components/viz/service/display/overlay_strategy_underlay_cast.cc
@@ -145,6 +145,145 @@ return found_underlay; } +void OverlayStrategyUnderlayCast::ProposePrioritized( + const SkMatrix44& output_color_matrix, + const OverlayProcessorInterface::FilterOperationsMap& + render_pass_backdrop_filters, + DisplayResourceProvider* resource_provider, + AggregatedRenderPassList* render_pass_list, + SurfaceDamageRectList* surface_damage_rect_list, + const PrimaryPlane* primary_plane, + OverlayProposedCandidateList* candidates, + std::vector<gfx::Rect>* content_bounds) { + auto* render_pass = render_pass_list->back().get(); + QuadList& quad_list = render_pass->quad_list; + OverlayCandidate candidate; + auto overlay_iter = quad_list.end(); + // Original code did reverse iteration. + // Here we do forward but find the last one. which should be the same thing. + for (auto it = quad_list.begin(); it != quad_list.end(); ++it) { + if (OverlayCandidate::IsInvisibleQuad(*it)) + continue; + + // Look for quads that are overlayable and require an overlay. Chromecast + // only supports a video underlay so this can't promote all quads that are + // overlayable, it needs to ensure that the quad requires overlays since + // that quad is side-channeled through a secure path into an overlay + // sitting underneath the primary plane. This is only looking at where the + // quad is supposed to be to replace it with a transparent quad to allow + // the underlay to be visible. + // VIDEO_HOLE implies it requires overlay. + if (it->material == DrawQuad::Material::kVideoHole && + OverlayCandidate::FromDrawQuad(resource_provider, + surface_damage_rect_list, + output_color_matrix, *it, &candidate)) { + overlay_iter = it; + } + } + + if (overlay_iter != quad_list.end()) { + candidates->push_back({overlay_iter, candidate, this}); + } +} + +bool OverlayStrategyUnderlayCast::AttemptPrioritized( + const SkMatrix44& output_color_matrix, + const OverlayProcessorInterface::FilterOperationsMap& + render_pass_backdrop_filters, + DisplayResourceProvider* resource_provider, + AggregatedRenderPassList* render_pass_list, + SurfaceDamageRectList* surface_damage_rect_list, + const PrimaryPlane* primary_plane, + OverlayCandidateList* candidate_list, + std::vector<gfx::Rect>* content_bounds, + OverlayProposedCandidate* proposed_candidate) { + // Before we attempt an overlay strategy, the candidate list should be empty. + DCHECK(candidate_list->empty()); + auto* render_pass = render_pass_list->back().get(); + QuadList& quad_list = render_pass->quad_list; + bool found_underlay = false; + gfx::Rect content_rect; + for (const auto* quad : base::Reversed(quad_list)) { + if (OverlayCandidate::IsInvisibleQuad(quad)) + continue; + + const auto& transform = quad->shared_quad_state->quad_to_target_transform; + gfx::RectF quad_rect = gfx::RectF(quad->rect); + transform.TransformRect(&quad_rect); + + bool is_underlay = false; + if (!found_underlay) { + OverlayCandidate candidate; + // Look for quads that are overlayable and require an overlay. Chromecast + // only supports a video underlay so this can't promote all quads that are + // overlayable, it needs to ensure that the quad requires overlays since + // that quad is side-channeled through a secure path into an overlay + // sitting underneath the primary plane. This is only looking at where the + // quad is supposed to be to replace it with a transparent quad to allow + // the underlay to be visible. + // VIDEO_HOLE implies it requires overlay. + is_underlay = quad->material == DrawQuad::Material::kVideoHole && + OverlayCandidate::FromDrawQuad( + resource_provider, surface_damage_rect_list, + output_color_matrix, quad, &candidate); + found_underlay = is_underlay; + } + + if (!found_underlay && quad->material == DrawQuad::Material::kSolidColor) { + const SolidColorDrawQuad* solid = SolidColorDrawQuad::MaterialCast(quad); + if (solid->color == SK_ColorBLACK) + continue; + } + + if (is_underlay) { + content_rect.Subtract(gfx::ToEnclosedRect(quad_rect)); + } else { + content_rect.Union(gfx::ToEnclosingRect(quad_rect)); + } + } + + if (is_using_overlay_ != found_underlay) { + is_using_overlay_ = found_underlay; + VLOG(1) << (found_underlay ? "Overlay activated" : "Overlay deactivated"); + } + + if (found_underlay) { + for (auto it = quad_list.begin(); it != quad_list.end(); ++it) { + OverlayCandidate candidate; + if (it->material != DrawQuad::Material::kVideoHole || + !OverlayCandidate::FromDrawQuad( + resource_provider, surface_damage_rect_list, output_color_matrix, + *it, &candidate)) { + continue; + } + + // TODO(guohuideng): when migration to GPU process complete, remove + // the code that's for the browser process compositor. +#if BUILDFLAG(IS_CHROMECAST) + if (g_overlay_composited_callback.Get().is_null()) { + DCHECK(GetVideoGeometrySetter()); + GetVideoGeometrySetter()->SetVideoGeometry( + candidate.display_rect, candidate.transform, + VideoHoleDrawQuad::MaterialCast(*it)->overlay_plane_id); + } else { + g_overlay_composited_callback.Get().Run(candidate.display_rect, + candidate.transform); + } +#endif + + render_pass->ReplaceExistingQuadWithOpaqueTransparentSolidColor(it); + + break; + } + } + + DCHECK(content_bounds && content_bounds->empty()); + if (found_underlay) { + content_bounds->push_back(content_rect); + } + return found_underlay; +} + OverlayStrategy OverlayStrategyUnderlayCast::GetUMAEnum() const { return OverlayStrategy::kUnderlayCast; }
diff --git a/components/viz/service/display/overlay_strategy_underlay_cast.h b/components/viz/service/display/overlay_strategy_underlay_cast.h index dfdbffd..53b40ed 100644 --- a/components/viz/service/display/overlay_strategy_underlay_cast.h +++ b/components/viz/service/display/overlay_strategy_underlay_cast.h
@@ -39,6 +39,28 @@ OverlayCandidateList* candidate_list, std::vector<gfx::Rect>* content_bounds) override; + void ProposePrioritized(const SkMatrix44& output_color_matrix, + const OverlayProcessorInterface::FilterOperationsMap& + render_pass_backdrop_filters, + DisplayResourceProvider* resource_provider, + AggregatedRenderPassList* render_pass_list, + SurfaceDamageRectList* surface_damage_rect_list, + const PrimaryPlane* primary_plane, + OverlayProposedCandidateList* candidates, + std::vector<gfx::Rect>* content_bounds) override; + + bool AttemptPrioritized( + const SkMatrix44& output_color_matrix, + const OverlayProcessorInterface::FilterOperationsMap& + render_pass_backdrop_filters, + DisplayResourceProvider* resource_provider, + AggregatedRenderPassList* render_pass_list, + SurfaceDamageRectList* surface_damage_rect_list, + const PrimaryPlane* primary_plane, + OverlayCandidateList* candidates, + std::vector<gfx::Rect>* content_bounds, + OverlayProposedCandidate* proposed_candidate) override; + // Callback that's made whenever an overlay quad is processed in the // compositor. Used to allow hardware video plane to be positioned to match // compositor hole.
diff --git a/components/viz/service/display/overlay_unittest.cc b/components/viz/service/display/overlay_unittest.cc index 1af80bf1..fb3af582 100644 --- a/components/viz/service/display/overlay_unittest.cc +++ b/components/viz/service/display/overlay_unittest.cc
@@ -17,6 +17,7 @@ #include "cc/test/geometry_test_utils.h" #include "cc/test/resource_provider_test_utils.h" #include "components/viz/client/client_resource_provider.h" +#include "components/viz/common/features.h" #include "components/viz/common/quads/compositor_render_pass.h" #include "components/viz/common/quads/compositor_render_pass_draw_quad.h" #include "components/viz/common/quads/solid_color_draw_quad.h" @@ -77,7 +78,12 @@ class TestOverlayProcessor : public OverlayProcessorUsingStrategy { public: using PrimaryPlane = OverlayProcessorInterface::OutputSurfaceOverlayPlane; - TestOverlayProcessor() : OverlayProcessorUsingStrategy() {} + TestOverlayProcessor() { + // By default the prioritization thresholding features are disabled for all + // tests. + prioritization_config_.changing_threshold = false; + prioritization_config_.damage_rate_threshold = false; + } ~TestOverlayProcessor() override = default; bool IsOverlaySupported() const override { return true; } @@ -89,7 +95,7 @@ class FullscreenOverlayProcessor : public TestOverlayProcessor { public: - FullscreenOverlayProcessor() : TestOverlayProcessor() { + FullscreenOverlayProcessor() { strategies_.push_back(std::make_unique<OverlayStrategyFullscreen>(this)); } bool NeedsSurfaceDamageRectList() const override { return true; } @@ -101,8 +107,7 @@ class DefaultOverlayProcessor : public TestOverlayProcessor { public: - DefaultOverlayProcessor() - : TestOverlayProcessor(), expected_rects_(1, gfx::RectF(kOverlayRect)) {} + DefaultOverlayProcessor() : expected_rects_(1, gfx::RectF(kOverlayRect)) {} bool NeedsSurfaceDamageRectList() const override { return true; } void CheckOverlaySupport(const PrimaryPlane* primary_plane, @@ -154,6 +159,9 @@ public: SingleOnTopOverlayProcessor() : DefaultOverlayProcessor() { strategies_.push_back(std::make_unique<OverlayStrategySingleOnTop>(this)); + // To reduce the complexity of this test for the prioritization feature the + // |damage_rate_threshold| is set to zero to make all opaque power positive. + tracker_config_.damage_rate_threshold = 0.f; } }; @@ -161,6 +169,9 @@ public: UnderlayOverlayProcessor() : DefaultOverlayProcessor() { strategies_.push_back(std::make_unique<OverlayStrategyUnderlay>(this)); + prioritization_config_.changing_threshold = false; + prioritization_config_.damage_rate_threshold = false; + prioritization_config_.power_gain_sort = false; } }; @@ -179,6 +190,32 @@ } }; +class ChangeThresholdOnTopOverlayProcessor : public DefaultOverlayProcessor { + public: + ChangeThresholdOnTopOverlayProcessor() { + strategies_.push_back(std::make_unique<OverlayStrategySingleOnTop>(this)); + prioritization_config_.damage_rate_threshold = false; + prioritization_config_.changing_threshold = true; + } + + // To keep this test consistent we need to expose the config for how long it + // takes for the system to threshold a unchanging candidate. + const OverlayCandidateTemporalTracker::Config& TrackerConfigAccessor() { + return tracker_config_; + } +}; + +class FullThresholdUnderlayOverlayProcessor : public DefaultOverlayProcessor { + public: + FullThresholdUnderlayOverlayProcessor() { + strategies_.push_back(std::make_unique<OverlayStrategyUnderlay>(this)); + // Disable this feature as it is tested in + // |ChangeThresholdOnTopOverlayProcessor|. + prioritization_config_.changing_threshold = false; + prioritization_config_.damage_rate_threshold = true; + } +}; + class OverlayOutputSurface : public OutputSurface { public: explicit OverlayOutputSurface( @@ -520,6 +557,8 @@ using FullscreenOverlayTest = OverlayTest<FullscreenOverlayProcessor>; using SingleOverlayOnTopTest = OverlayTest<SingleOnTopOverlayProcessor>; +using ChangeSingleOnTopTest = OverlayTest<ChangeThresholdOnTopOverlayProcessor>; +using FullThresholdTest = OverlayTest<FullThresholdUnderlayOverlayProcessor>; using UnderlayTest = OverlayTest<UnderlayOverlayProcessor>; using TransparentUnderlayTest = OverlayTest<TransparentUnderlayOverlayProcessor>; @@ -839,9 +878,11 @@ OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters; AggregatedRenderPassList pass_list; AggregatedRenderPass* main_pass = pass.get(); - pass_list.push_back(std::move(pass)); SurfaceDamageRectList surface_damage_rect_list; - + // Simplify by adding full root damage. + surface_damage_rect_list.push_back(pass->output_rect); + pass_list.push_back(std::move(pass)); + overlay_processor_->SetFrameSequenceNumber(1); overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, @@ -1627,12 +1668,21 @@ EXPECT_EQ(0U, candidate_list.size()); } -TEST_F(SingleOverlayOnTopTest, DoNotPromoteIfContentsDontChange) { +TEST_F(ChangeSingleOnTopTest, DoNotPromoteIfContentsDontChange) { // Resource ID for the repeated quads. Value should be equivalent to // OverlayStrategySingleOnTop::kMaxFrameCandidateWithSameResourceId. - constexpr size_t kFramesSkippedBeforeNotPromoting = 3; - ResourceId previous_resource_id; + size_t kFramesSkippedBeforeNotPromoting = 3; + // The overlay prioritization feature supports overlay demotion for unchanging + // overlays however the timing is slightly different as prioritization is + // frame counter based. + if (features::IsOverlayPrioritizationEnabled()) { + kFramesSkippedBeforeNotPromoting = + overlay_processor_->TrackerConfigAccessor().max_frames_inactive; + } + + ResourceId previous_resource_id; + int64_t frame_counter = 0; for (size_t i = 0; i < 3 + kFramesSkippedBeforeNotPromoting; ++i) { auto pass = CreateRenderPass(); AggregatedRenderPass* main_pass = pass.get(); @@ -1675,21 +1725,110 @@ pass_list.push_back(std::move(pass)); SurfaceDamageRectList surface_damage_rect_list; + overlay_processor_->SetFrameSequenceNumber(frame_counter); + overlay_processor_->ProcessForOverlays( + resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), + render_pass_filters, render_pass_backdrop_filters, + &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, + &content_bounds_); + frame_counter++; + if (i <= kFramesSkippedBeforeNotPromoting) { + EXPECT_EQ(1U, candidate_list.size()); + if (candidate_list.size()) { + // Check that the right resource id got extracted. + EXPECT_EQ(resource_id, candidate_list.back().resource_id); + } + // Check that the quad is gone. + EXPECT_EQ(1U, main_pass->quad_list.size()); + } else { + // Check nothing has been promoted. + EXPECT_EQ(2U, main_pass->quad_list.size()); + } + } +} + +TEST_F(FullThresholdTest, ThresholdTestForPrioritization) { + // This test is specific to the prioritized version of the overlay strategies. + // The thresholds of damage and frame rate are only features of + // prioritization. + if (!features::IsOverlayPrioritizationEnabled()) { + return; + } + + int64_t frame_counter = 0; + // This is a helper function to simulate framerates. + + auto wait_1_frame = [&]() { frame_counter++; }; + + auto wait_4_frames = [&]() { frame_counter += 4; }; + + // This test uses many iterations to test prioritization threshold features + // due to frame averaging over samples. + constexpr size_t kDamageFrameTestStart = + OverlayCandidateTemporalTracker::kNumRecords; + constexpr size_t kDamageFrameTestEnd = + kDamageFrameTestStart + OverlayCandidateTemporalTracker::kNumRecords; + constexpr size_t kSlowFrameTestStart = + kDamageFrameTestEnd + OverlayCandidateTemporalTracker::kNumRecords; + constexpr size_t kSlowFrameTestEnd = + kSlowFrameTestStart + OverlayCandidateTemporalTracker::kNumRecords; + + // This quad is used to occlude the damage of the overlay candidate to the + // point that the damage is no longer considered significant. + auto nearly_occluding_quad = kOverlayRect; + nearly_occluding_quad.Inset(1, 1); + + for (size_t i = 0; i < kSlowFrameTestEnd; ++i) { + if (i >= kSlowFrameTestStart && i < kSlowFrameTestEnd) { + wait_4_frames(); + } else { + wait_1_frame(); + } + + auto pass = CreateRenderPass(); + AggregatedRenderPass* main_pass = pass.get(); + + bool nearly_occluded = + i >= kDamageFrameTestStart && i < kDamageFrameTestEnd; + CreateSolidColorQuadAt( + pass->shared_quad_state_list.back(), SK_ColorBLACK, pass.get(), + nearly_occluded ? nearly_occluding_quad : kOverlayTopLeftRect); + + // Create a quad with the resource ID selected above. + TextureDrawQuad* quad_candidate = CreateCandidateQuadAt( + resource_provider_.get(), child_resource_provider_.get(), + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get(), + kOverlayRect); + + quad_candidate->set_resource_size_in_pixels(pass->output_rect.size()); + + // Add something behind it. + CreateFullscreenOpaqueQuad(resource_provider_.get(), + pass->shared_quad_state_list.back(), main_pass); + + // Check for potential candidates. + OverlayCandidateList candidate_list; + OverlayProcessorInterface::FilterOperationsMap render_pass_filters; + OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters; + AggregatedRenderPassList pass_list; + pass_list.push_back(std::move(pass)); + SurfaceDamageRectList surface_damage_rect_list; + surface_damage_rect_list.push_back(kOverlayRect); + overlay_processor_->SetFrameSequenceNumber(frame_counter); overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, &content_bounds_); - if (i <= kFramesSkippedBeforeNotPromoting) { + EXPECT_EQ(3u, main_pass->quad_list.size()); + + if (i == kDamageFrameTestStart - 1 || i == kSlowFrameTestStart - 1) { + // Test to make sure an overlay was promoted. EXPECT_EQ(1U, candidate_list.size()); - // Check that the right resource id got extracted. - EXPECT_EQ(resource_id, candidate_list.back().resource_id); - // Check that the quad is gone. - EXPECT_EQ(1U, main_pass->quad_list.size()); - } else { - // Check nothing has been promoted. - EXPECT_EQ(2U, main_pass->quad_list.size()); + } else if (i == kDamageFrameTestEnd - 1 || i == kSlowFrameTestEnd - 1) { + // Test to make sure no overlay was promoted + EXPECT_EQ(0u, candidate_list.size()); } } } @@ -2068,122 +2207,137 @@ TEST_F(UnderlayTest, OverlayCandidateTemporalTracker) { unsigned id_counter = 0; + uint64_t frame_counter = 0; // Function to fake unique resource ids so the system sees them as changing. auto get_id = [&] { return ++id_counter; }; // Test the default configuration. OverlayCandidateTemporalTracker::Config config; - constexpr float kEpsilon = 0.01f; - float kBelowLowDamage = config.damage_low_threshold - kEpsilon; - float kAboveHighDamage = config.damage_high_threshold + kEpsilon; - - base::TimeTicks tick_start = base::TimeTicks::Now(); + float kDamageEpsilon = config.damage_rate_hysteresis_range; + float kBelowLowDamage = config.damage_rate_threshold - kDamageEpsilon; + float kAboveHighDamage = config.damage_rate_threshold + kDamageEpsilon; + float kFullDamage = 1.0f; // This is a helper function to simulate framerates. - auto wait_17ms = [&]() { - while ((base::TimeTicks::Now() - tick_start).InMilliseconds() < 17) { - } - tick_start = base::TimeTicks::Now(); + auto wait_1_frame = [&]() { frame_counter++; }; + + auto wait_inactive_frames = [&]() { + frame_counter += config.max_frames_inactive + 1; }; - auto wait_66ms = [&]() { - while ((base::TimeTicks::Now() - tick_start).InMilliseconds() < 66) { - } - tick_start = base::TimeTicks::Now(); - }; OverlayCandidateTemporalTracker tracker; - + int fake_display_area = 256 * 256; // We test internal hysteresis state by running this test twice. for (int j = 0; j < 2; j++) { // First setup a 60fps high damage candidate. for (int i = 0; i < OverlayCandidateTemporalTracker::kNumRecords; i++) { - tracker.AddRecord(base::TimeTicks::Now(), kAboveHighDamage, get_id(), - config); - wait_17ms(); + wait_1_frame(); + tracker.AddRecord(frame_counter, kFullDamage, get_id(), config); } - OverlayCandidateTemporalTracker tracker_not_active_changing = tracker; + EXPECT_TRUE(tracker.IsActivelyChanging(frame_counter, config)); + auto opaque_power_gain_60_full = + tracker.GetModeledPowerGain(frame_counter, config, fake_display_area); - EXPECT_TRUE(tracker.HasSignificantDamage()); - ASSERT_EQ(tracker.GetFPSCategory(), - OverlayCandidateTemporalTracker::kFrameRate60fps); + EXPECT_FLOAT_EQ(tracker.MeanFrameRatioRate(config), 1.0f); + EXPECT_GT(opaque_power_gain_60_full, 0); - // Test the hysteresis by checking that a few 30fps low damage updates do - // not change the categorization state. - wait_17ms(); - wait_17ms(); - tracker.AddRecord(base::TimeTicks::Now(), kBelowLowDamage, get_id(), - config); - wait_17ms(); - wait_17ms(); - tracker.AddRecord(base::TimeTicks::Now(), kBelowLowDamage, get_id(), - config); - EXPECT_TRUE(tracker.HasSignificantDamage()); - ASSERT_EQ(tracker.GetFPSCategory(), - OverlayCandidateTemporalTracker::kFrameRate60fps); + // Test our hysteresis categorization of power by ensuring a single frame + // drop does not change the end power categorization. + wait_1_frame(); + wait_1_frame(); + tracker.AddRecord(frame_counter, kFullDamage, get_id(), config); - // Now simulate a overaly candidate with 30fps and low damage. + auto opaque_power_gain_60_stutter = + tracker.GetModeledPowerGain(frame_counter, config, fake_display_area); + + // A single frame drop even at 60fps should not change our power + // categorization. + ASSERT_EQ(opaque_power_gain_60_full, opaque_power_gain_60_stutter); + + wait_inactive_frames(); + EXPECT_FALSE(tracker.IsActivelyChanging(frame_counter, config)); + tracker.AddRecord(frame_counter, kFullDamage, get_id(), config); + + auto opaque_power_gain_60_inactive = + tracker.GetModeledPowerGain(frame_counter, config, fake_display_area); + // Simple test to make sure that power categorization is not completely + // invalidated when candidate becomes inactive. + EXPECT_GT(opaque_power_gain_60_inactive, 0); + + // Now simulate a overlay candidate with 30fps full damage. for (int i = 0; i < OverlayCandidateTemporalTracker::kNumRecords; i++) { - wait_17ms(); - wait_17ms(); - tracker.AddRecord(base::TimeTicks::Now(), kBelowLowDamage, get_id(), - config); + wait_1_frame(); + wait_1_frame(); + tracker.AddRecord(frame_counter, kFullDamage, get_id(), config); } - // Check that it has reached the applied state. - EXPECT_FALSE(tracker.HasSignificantDamage()); - ASSERT_EQ(tracker.GetFPSCategory(), - OverlayCandidateTemporalTracker::kFrameRate30fps); - OverlayCandidateTemporalTracker tracker_saved_30fps = tracker; + auto opaque_power_gain_30_full = + tracker.GetModeledPowerGain(frame_counter, config, fake_display_area); - // Test hysteresis for this new state by adding in a few high damage 60fps - // frames. - wait_17ms(); - tracker.AddRecord(base::TimeTicks::Now(), kAboveHighDamage, get_id(), - config); - wait_17ms(); - tracker.AddRecord(base::TimeTicks::Now(), kAboveHighDamage, get_id(), - config); - EXPECT_FALSE(tracker.HasSignificantDamage()); - ASSERT_EQ(tracker.GetFPSCategory(), - OverlayCandidateTemporalTracker::kFrameRate30fps); + EXPECT_FLOAT_EQ(tracker.MeanFrameRatioRate(config), 0.5f); + EXPECT_GT(opaque_power_gain_30_full, 0); + EXPECT_GT(opaque_power_gain_60_full, opaque_power_gain_30_full); - EXPECT_TRUE(tracker.IsActivelyChanging(base::TimeTicks::Now(), config)); + // Test the hysteresis by checking that a stuttering frame will not change + // power categorization. + wait_1_frame(); + wait_1_frame(); + wait_1_frame(); + tracker.AddRecord(frame_counter, kFullDamage, get_id(), config); - // Test hysteresis for 30fps to lowfps state by inserting lowfps frames and - // asserting that the tracker is still in the 30fps state. - wait_66ms(); - tracker_saved_30fps.AddRecord(base::TimeTicks::Now(), kAboveHighDamage, - get_id(), config); - wait_66ms(); - tracker_saved_30fps.AddRecord(base::TimeTicks::Now(), kAboveHighDamage, - get_id(), config); - ASSERT_EQ(tracker.GetFPSCategory(), - OverlayCandidateTemporalTracker::kFrameRate30fps); + EXPECT_TRUE(tracker.IsActivelyChanging(frame_counter, config)); + auto opaque_power_gain_30_stutter = + tracker.GetModeledPowerGain(frame_counter, config, fake_display_area); + + EXPECT_TRUE(opaque_power_gain_30_stutter == opaque_power_gain_30_full); + + wait_inactive_frames(); + EXPECT_FALSE(tracker.IsActivelyChanging(frame_counter, config)); + tracker.AddRecord(frame_counter, kFullDamage, get_id(), config); + + auto opaque_power_gain_30_inactive = + tracker.GetModeledPowerGain(frame_counter, config, fake_display_area); + // Simple test to make sure that power categorization is not completely + // invalidated when candidate becomes inactive. + EXPECT_GT(opaque_power_gain_30_inactive, 0); + + // Test low and high damage thresholds. + for (int i = 0; i < OverlayCandidateTemporalTracker::kNumRecords; i++) { + wait_1_frame(); + tracker.AddRecord(frame_counter, kAboveHighDamage, get_id(), config); + } + + auto opaque_power_gain_high_damage = + tracker.GetModeledPowerGain(frame_counter, config, fake_display_area); + + EXPECT_GT(opaque_power_gain_high_damage, 0); + EXPECT_GE(opaque_power_gain_60_full, opaque_power_gain_high_damage); for (int i = 0; i < OverlayCandidateTemporalTracker::kNumRecords; i++) { - wait_66ms(); - tracker_saved_30fps.AddRecord(base::TimeTicks::Now(), kBelowLowDamage, - get_id(), config); + wait_1_frame(); + tracker.AddRecord(frame_counter, kBelowLowDamage, get_id(), config); } - // make sure our we have moved into the |kFrameRateLow| category. - ASSERT_EQ(tracker_saved_30fps.GetFPSCategory(), - OverlayCandidateTemporalTracker::kFrameRateLow); - // The current design only updates frame rate categorization on record - // insertion ('AddRecord()'). We test this assumption by asserting that a - // tracker that is not actively changing still has its original 60fps - // category. - EXPECT_FALSE(tracker_not_active_changing.IsActivelyChanging( - base::TimeTicks::Now(), config)); + auto opaque_power_gain_low_damage = + tracker.GetModeledPowerGain(frame_counter, config, fake_display_area); + EXPECT_LT(opaque_power_gain_low_damage, 0); - ASSERT_EQ(tracker_not_active_changing.GetFPSCategory(), - OverlayCandidateTemporalTracker::kFrameRate60fps); - // Finally we test that the categorization changes on the addition of a new - // record of very large time interval. - tracker_not_active_changing.AddRecord(base::TimeTicks::Now(), - kAboveHighDamage, get_id(), config); - ASSERT_EQ(tracker_not_active_changing.GetFPSCategory(), - OverlayCandidateTemporalTracker::kFrameRateLow); + // Test our mean damage ratio computations for our tacker. + float expected_mean = 0.0f; + for (int i = 0; i < OverlayCandidateTemporalTracker::kNumRecords; i++) { + wait_1_frame(); + // Please note that this first iter frame damage will not get included in + // the mean as the mean is computed between timing intervals. This means 6 + // timing intervals only gives 5 values. + float dynamic_damage_ratio = static_cast<float>(i); + expected_mean += dynamic_damage_ratio; + tracker.AddRecord(frame_counter, dynamic_damage_ratio, get_id(), config); + } + + expected_mean = + expected_mean / (OverlayCandidateTemporalTracker::kNumRecords - 1); + + EXPECT_FLOAT_EQ(expected_mean, tracker.MeanFrameRatioRate(config)); } EXPECT_FALSE(tracker.IsAbsent()); @@ -2191,8 +2345,8 @@ // return true; indicating this tracker is no longer active. EXPECT_TRUE(tracker.IsAbsent()); - wait_17ms(); - tracker.AddRecord(base::TimeTicks::Now(), 0.0f, get_id(), config); + wait_1_frame(); + tracker.AddRecord(frame_counter, 0.0f, get_id(), config); EXPECT_FALSE(tracker.IsAbsent()); } @@ -3493,29 +3647,49 @@ AddQuad(gfx::Rect(150, 150, kOccluderWidth, kOccluderWidth), identity, pass.get()); - const int kCandidateSmallWidth = 50; - const int kCandidateLargeWidth = 100; + const int kCandidateSmall = 50; + const int kCandidateLarge = 100; const gfx::Rect kCandidateRects[] = { - gfx::Rect(0, 0, kCandidateSmallWidth, kCandidateSmallWidth), - gfx::Rect(100, 100, kCandidateSmallWidth, kCandidateSmallWidth), - gfx::Rect(100, 100, kCandidateLargeWidth, kCandidateLargeWidth)}; + gfx::Rect(0, 0, kCandidateSmall, kCandidateSmall), + gfx::Rect(100, 100, kCandidateSmall, kCandidateSmall), + gfx::Rect(100, 100, kCandidateLarge, kCandidateLarge), kOverlayRect}; - const int kExpectedDamages[] = {kCandidateSmallWidth * kCandidateSmallWidth, - kCandidateSmallWidth * kCandidateSmallWidth - - kOccluderWidth * kOccluderWidth, - kCandidateLargeWidth * kCandidateLargeWidth - - kOccluderWidth * kOccluderWidth * 2}; + const bool kCandidateUseSurfaceIndex[] = {true, true, true, false}; + + const int kExpectedDamages[] = { + kCandidateSmall * kCandidateSmall, + kCandidateSmall * kCandidateSmall - kOccluderWidth * kOccluderWidth, + kCandidateLarge * kCandidateLarge - kOccluderWidth * kOccluderWidth * 2, + kCandidateLarge * kCandidateLarge * 4 - + kOccluderWidth * kOccluderWidth * 2}; + + static_assert( + base::size(kCandidateRects) == base::size(kCandidateUseSurfaceIndex), + "Number of elements in each list should be the identical."); + static_assert(base::size(kCandidateRects) == base::size(kExpectedDamages), + "Number of elements in each list should be the identical."); + QuadList& quad_list = pass->quad_list; auto occluder_iter_count = quad_list.size(); + SurfaceDamageRectList surface_damage_rect_list; for (size_t i = 0; i < base::size(kCandidateRects); ++i) { - SurfaceDamageRectList surface_damage_rect_list; // Create fake surface damage for this candidate. SharedQuadState* damaged_shared_quad_state = pass->shared_quad_state_list.AllocateAndCopyFrom( pass->shared_quad_state_list.back()); - damaged_shared_quad_state->overlay_damage_index = 0; - surface_damage_rect_list.emplace_back(kCandidateRects[i]); + // We want to test what happens when an overlay candidate does not have an + // associated damage index. An estimate damage for this candidate will still + // be computed but it will be derived from a union of all surface damages. + // TODO(petermcneeley): Update this code when surface damage is made more + // reliable. + if (kCandidateUseSurfaceIndex[i]) { + damaged_shared_quad_state->overlay_damage_index = + surface_damage_rect_list.size(); + surface_damage_rect_list.emplace_back(kCandidateRects[i]); + } else { + damaged_shared_quad_state->overlay_damage_index.reset(); + } auto* quad_candidate = CreateCandidateQuadAt( resource_provider_.get(), child_resource_provider_.get(), @@ -3530,8 +3704,15 @@ // Before the 'EstimateOccludedDamage' function is called the damage area // will just be whatever comes from the |surface_damage_rect_list|. - ASSERT_EQ(kCandidateRects[i].size().GetArea(), - candidate.damage_area_estimate); + if (kCandidateUseSurfaceIndex[i]) { + ASSERT_EQ(kCandidateRects[i].size().GetArea(), + candidate.damage_area_estimate); + } else { + // In the special case where we have no surface damage index the candidate + // area will not simply be the |damage_area_estimate|. + ASSERT_FALSE( + quad_candidate->shared_quad_state->overlay_damage_index.has_value()); + } // We have to find the occluder end of our list as it changes each // iteration. @@ -3545,6 +3726,7 @@ candidate.damage_area_estimate = OverlayCandidate::EstimateVisibleDamage( quad_candidate, &surface_damage_rect_list, quad_list.begin(), iter_occluder_end); + ASSERT_EQ(kExpectedDamages[i], candidate.damage_area_estimate); } }
diff --git a/content/browser/accessibility/browser_accessibility_android.cc b/content/browser/accessibility/browser_accessibility_android.cc index b62285f..38908bea 100644 --- a/content/browser/accessibility/browser_accessibility_android.cc +++ b/content/browser/accessibility/browser_accessibility_android.cc
@@ -1305,9 +1305,6 @@ case ax::mojom::Role::kSlider: message_id = IDS_AX_ROLE_SLIDER; break; - case ax::mojom::Role::kSliderThumb: - // No role description. - break; case ax::mojom::Role::kSpinButton: message_id = IDS_AX_ROLE_SPIN_BUTTON; break;
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.mm b/content/browser/accessibility/browser_accessibility_cocoa.mm index e83627b4..d9d756a 100644 --- a/content/browser/accessibility/browser_accessibility_cocoa.mm +++ b/content/browser/accessibility/browser_accessibility_cocoa.mm
@@ -3558,10 +3558,11 @@ // Position in set and Set size. // Only add these attributes for roles that use posinset and setsize. if (ui::IsItemLike(_owner->node()->data().role)) - [ret addObjectsFromArray:@[ NSAccessibilityARIAPosInSetAttribute ]]; - if (ui::IsSetLike(_owner->node()->data().role) || - ui::IsItemLike(_owner->node()->data().role)) - [ret addObjectsFromArray:@[ NSAccessibilityARIASetSizeAttribute ]]; + [ret addObjectsFromArray:@[ + NSAccessibilityARIAPosInSetAttribute, NSAccessibilityARIASetSizeAttribute + ]]; + if (ui::IsSetLike(_owner->node()->data().role)) + [ret addObject:NSAccessibilityARIASetSizeAttribute]; // Live regions. if (_owner->HasStringAttribute(ax::mojom::StringAttribute::kLiveStatus)) {
diff --git a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc index f286fafd..e857381 100644 --- a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc +++ b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
@@ -398,15 +398,11 @@ ScreenshotEncoding encoding, bool from_surface, const gfx::RectF& clip = gfx::RectF(), - float clip_scale = 0, - bool capture_beyond_viewport = false) { + float clip_scale = 0) { std::unique_ptr<base::DictionaryValue> params(new base::DictionaryValue()); params->SetString("format", encoding == ENCODING_PNG ? "png" : "jpeg"); params->SetInteger("quality", 100); params->SetBoolean("fromSurface", from_surface); - if (capture_beyond_viewport) { - params->SetBoolean("captureBeyondViewport", true); - } if (clip_scale) { std::unique_ptr<base::DictionaryValue> clip_value( new base::DictionaryValue()); @@ -437,10 +433,9 @@ bool from_surface, float device_scale_factor = 0, const gfx::RectF& clip = gfx::RectF(), - float clip_scale = 0, - bool capture_beyond_viewport = false) { - std::unique_ptr<SkBitmap> result_bitmap = CaptureScreenshot( - encoding, from_surface, clip, clip_scale, capture_beyond_viewport); + float clip_scale = 0) { + std::unique_ptr<SkBitmap> result_bitmap = + CaptureScreenshot(encoding, from_surface, clip, clip_scale); gfx::Rect matching_mask(gfx::SkIRectToRect(expected_bitmap.bounds())); #if defined(OS_MAC) @@ -536,97 +531,6 @@ #endif }; -IN_PROC_BROWSER_TEST_F(CaptureScreenshotTest, - CaptureScreenshotBeyondViewport_OutOfView) { - // This test fails consistently on low-end Android devices. - // See crbug.com/653637. - // TODO(eseckler): Reenable with error limit if necessary. - if (base::SysInfo::IsLowEndDevice()) - return; - - // Load dummy page before getting the window size. - shell()->LoadURL(GURL("data:text/html,<body></body>")); - gfx::Size window_size = - static_cast<RenderWidgetHostViewBase*>( - shell()->web_contents()->GetRenderWidgetHostView()) - ->GetCompositorViewportPixelSize(); - - // Make a page a bit bigger then the view to force scrollbar to be shown. - float content_height = window_size.height() + 10; - float content_width = window_size.width() + 10; - - shell()->LoadURL( - GURL("data:text/html,<body " - "style='background:%23123456;height:" + - base::NumberToString(content_height) + - "px;width:" + base::NumberToString(content_width) + "px'></body>")); - - EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); - Attach(); - - // Generate expected screenshot without any scrollbars. - SkBitmap expected_bitmap; - expected_bitmap.allocN32Pixels(content_width, content_height); - expected_bitmap.eraseColor(SkColorSetRGB(0x12, 0x34, 0x56)); - - float device_scale_factor = - display::Screen::GetScreen()->GetPrimaryDisplay().device_scale_factor(); - - // Verify there are no scrollbars on the screenshot. - CaptureScreenshotAndCompareTo( - expected_bitmap, ENCODING_PNG, true, device_scale_factor, - gfx::RectF(0, 0, content_width, content_height), 1, true); -} - -// ChromeOS and Android has fading out scrollbars, which makes the test flacky. -// Android has a problem with changing scale: crbug.com/1150059. -// Android Lollipop has a problem with capturing screenshot: crbug.com/1147911. -#if defined(OS_ANDROID) || defined(OS_CHROMEOS) -#define MAYBE_CaptureScreenshotBeyondViewport_InnerScrollbarsAreShown \ - DISABLED_CaptureScreenshotBeyondViewport_InnerScrollbarsAreShown -#else -#define MAYBE_CaptureScreenshotBeyondViewport_InnerScrollbarsAreShown \ - CaptureScreenshotBeyondViewport_InnerScrollbarsAreShown -#endif -IN_PROC_BROWSER_TEST_F( - CaptureScreenshotTest, - MAYBE_CaptureScreenshotBeyondViewport_InnerScrollbarsAreShown) { - // This test fails consistently on low-end Android devices. - // See crbug.com/653637. - // TODO(eseckler): Reenable with error limit if necessary. - if (base::SysInfo::IsLowEndDevice()) - return; - - shell()->LoadURL(GURL( - "data:text/html,<body><div style='width: 50px; height: 50px; overflow: " - "scroll;'><h3>test</h3><h3>test</h3><h3>test</h3></div></body>")); - - EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); - Attach(); - - // We compare against the actual physical backing size rather than the - // view size, because the view size is stored adjusted for DPI and only in - // integer precision. - gfx::Size view_size = static_cast<RenderWidgetHostViewBase*>( - shell()->web_contents()->GetRenderWidgetHostView()) - ->GetCompositorViewportPixelSize(); - - // Capture a screenshot not "form surface", meaning without emulation and - // without changing preferences, as-is. - std::unique_ptr<SkBitmap> expected_bitmap = - CaptureScreenshot(ENCODING_PNG, false); - - float device_scale_factor = - display::Screen::GetScreen()->GetPrimaryDisplay().device_scale_factor(); - - // Compare the captured screenshot with one made "from_surface", where actual - // scrollbar magic happened, and verify it looks the same, meaning the - // internal scrollbars are rendered. - CaptureScreenshotAndCompareTo( - *expected_bitmap, ENCODING_PNG, true, device_scale_factor, - gfx::RectF(0, 0, view_size.width(), view_size.height()), 1, true); -} - IN_PROC_BROWSER_TEST_F(CaptureScreenshotTest, CaptureScreenshot) { // This test fails consistently on low-end Android devices. // See crbug.com/653637.
diff --git a/content/browser/devtools/protocol/page_handler.cc b/content/browser/devtools/protocol/page_handler.cc index 9a31a0d6..0e719ed 100644 --- a/content/browser/devtools/protocol/page_handler.cc +++ b/content/browser/devtools/protocol/page_handler.cc
@@ -15,7 +15,6 @@ #include "base/memory/ref_counted.h" #include "base/memory/ref_counted_memory.h" #include "base/numerics/safe_conversions.h" -#include "base/optional.h" #include "base/process/process_handle.h" #include "base/single_thread_task_runner.h" #include "base/strings/string16.h" @@ -682,7 +681,6 @@ Maybe<int> quality, Maybe<Page::Viewport> clip, Maybe<bool> from_surface, - Maybe<bool> capture_beyond_viewport, std::unique_ptr<CaptureScreenshotCallback> callback) { if (!host_ || !host_->GetRenderWidgetHost() || !host_->GetRenderWidgetHost()->GetView()) { @@ -714,8 +712,7 @@ base::BindOnce(&PageHandler::ScreenshotCaptured, weak_factory_.GetWeakPtr(), std::move(callback), screenshot_format, screenshot_quality, gfx::Size(), - gfx::Size(), blink::DeviceEmulationParams(), - base::nullopt), + gfx::Size(), blink::DeviceEmulationParams()), false); return; } @@ -778,30 +775,6 @@ } } - base::Optional<blink::web_pref::WebPreferences> original_web_prefs_if_needed; - if (capture_beyond_viewport.fromMaybe(false)) { - blink::web_pref::WebPreferences original_web_prefs = - host_->GetRenderViewHost()->GetDelegate()->GetOrCreateWebPreferences(); - original_web_prefs_if_needed = original_web_prefs; - - blink::web_pref::WebPreferences modified_web_prefs = original_web_prefs; - // Hiding scrollbar is needed to avoid scrollbar artefacts on the - // screenshot. Details: https://crbug.com/1003629. - modified_web_prefs.hide_scrollbars = true; - modified_web_prefs.record_whole_document = true; - host_->GetRenderViewHost()->GetDelegate()->SetWebPreferences( - modified_web_prefs); - - { - // TODO(crbug.com/1141835): Remove the bug is fixed. - // Walkaround for the bug. Emulated `view_size` has to be set twice, - // otherwise the scrollbar will be on the screenshot present. - blink::DeviceEmulationParams tmp_params = modified_params; - tmp_params.view_size = gfx::Size(1, 1); - emulation_handler_->SetDeviceEmulationParams(tmp_params); - } - } - // We use DeviceEmulationParams to either emulate, set viewport or both. emulation_handler_->SetDeviceEmulationParams(modified_params); @@ -834,8 +807,7 @@ base::BindOnce(&PageHandler::ScreenshotCaptured, weak_factory_.GetWeakPtr(), std::move(callback), screenshot_format, screenshot_quality, original_view_size, - requested_image_size, original_params, - original_web_prefs_if_needed), + requested_image_size, original_params), true); } @@ -1138,8 +1110,6 @@ const gfx::Size& original_view_size, const gfx::Size& requested_image_size, const blink::DeviceEmulationParams& original_emulation_params, - const base::Optional<blink::web_pref::WebPreferences>& - maybe_original_web_prefs, const gfx::Image& image) { if (original_view_size.width()) { RenderWidgetHostImpl* widget_host = host_->GetRenderWidgetHost(); @@ -1147,11 +1117,6 @@ emulation_handler_->SetDeviceEmulationParams(original_emulation_params); } - if (maybe_original_web_prefs) { - host_->GetRenderViewHost()->GetDelegate()->SetWebPreferences( - maybe_original_web_prefs.value()); - } - if (image.IsEmpty()) { callback->sendFailure( Response::ServerError("Unable to capture screenshot"));
diff --git a/content/browser/devtools/protocol/page_handler.h b/content/browser/devtools/protocol/page_handler.h index 6a616bf..9f8eb66 100644 --- a/content/browser/devtools/protocol/page_handler.h +++ b/content/browser/devtools/protocol/page_handler.h
@@ -126,7 +126,6 @@ Maybe<int> quality, Maybe<Page::Viewport> clip, Maybe<bool> from_surface, - Maybe<bool> capture_beyond_viewport, std::unique_ptr<CaptureScreenshotCallback> callback) override; void CaptureSnapshot( Maybe<std::string> format, @@ -188,15 +187,13 @@ std::unique_ptr<Page::ScreencastFrameMetadata> metadata, const protocol::Binary& data); - void ScreenshotCaptured( - std::unique_ptr<CaptureScreenshotCallback> callback, - const std::string& format, - int quality, - const gfx::Size& original_view_size, - const gfx::Size& requested_image_size, - const blink::DeviceEmulationParams& original_params, - const base::Optional<blink::web_pref::WebPreferences>& original_web_prefs, - const gfx::Image& image); + void ScreenshotCaptured(std::unique_ptr<CaptureScreenshotCallback> callback, + const std::string& format, + int quality, + const gfx::Size& original_view_size, + const gfx::Size& requested_image_size, + const blink::DeviceEmulationParams& original_params, + const gfx::Image& image); void GotManifest(std::unique_ptr<GetAppManifestCallback> callback, const GURL& manifest_url,
diff --git a/content/browser/gpu/gpu_data_manager_impl_private.cc b/content/browser/gpu/gpu_data_manager_impl_private.cc index 95e8e5d0..82c3b38 100644 --- a/content/browser/gpu/gpu_data_manager_impl_private.cc +++ b/content/browser/gpu/gpu_data_manager_impl_private.cc
@@ -241,7 +241,7 @@ // was recorded in this histogram in order to have a convenient // denominator to compute blocklist percentages for the rest of the // entries. - UMA_HISTOGRAM_EXACT_LINEAR("GPU.BlacklistTestResultsPerEntry", 0, + UMA_HISTOGRAM_EXACT_LINEAR("GPU.BlocklistTestResultsPerEntry", 0, max_entry_id + 1); if (!gpu_feature_info.applied_gpu_blocklist_entries.empty()) { std::vector<uint32_t> entry_ids = blocklist->GetEntryIDsFromIndices( @@ -250,7 +250,7 @@ entry_ids.size()); for (auto id : entry_ids) { DCHECK_GE(max_entry_id, id); - UMA_HISTOGRAM_EXACT_LINEAR("GPU.BlacklistTestResultsPerEntry", id, + UMA_HISTOGRAM_EXACT_LINEAR("GPU.BlocklistTestResultsPerEntry", id, max_entry_id + 1); } } @@ -266,12 +266,12 @@ gpu::GPU_FEATURE_TYPE_ACCELERATED_WEBGL, gpu::GPU_FEATURE_TYPE_ACCELERATED_WEBGL2}; const std::string kGpuBlocklistFeatureHistogramNames[] = { - "GPU.BlacklistFeatureTestResults.Accelerated2dCanvas", - "GPU.BlacklistFeatureTestResults.GpuCompositing", - "GPU.BlacklistFeatureTestResults.GpuRasterization", - "GPU.BlacklistFeatureTestResults.OopRasterization", - "GPU.BlacklistFeatureTestResults.Webgl", - "GPU.BlacklistFeatureTestResults.Webgl2"}; + "GPU.BlocklistFeatureTestResults.Accelerated2dCanvas", + "GPU.BlocklistFeatureTestResults.GpuCompositing", + "GPU.BlocklistFeatureTestResults.GpuRasterization", + "GPU.BlocklistFeatureTestResults.OopRasterization", + "GPU.BlocklistFeatureTestResults.Webgl", + "GPU.BlocklistFeatureTestResults.Webgl2"}; const bool kGpuFeatureUserFlags[] = { command_line.HasSwitch(switches::kDisableAccelerated2dCanvas), command_line.HasSwitch(switches::kDisableGpu),
diff --git a/content/browser/loader/prefetch_url_loader_service.cc b/content/browser/loader/prefetch_url_loader_service.cc index b3d7b76f..3817309 100644 --- a/content/browser/loader/prefetch_url_loader_service.cc +++ b/content/browser/loader/prefetch_url_loader_service.cc
@@ -5,6 +5,7 @@ #include "content/browser/loader/prefetch_url_loader_service.h" #include "base/bind.h" +#include "base/debug/crash_logging.h" #include "base/debug/dump_without_crashing.h" #include "base/feature_list.h" #include "base/time/default_tick_clock.h" @@ -31,8 +32,10 @@ namespace { void DumpWithoutCrashing(const network::ResourceRequest& request) { - DEBUG_ALIAS_FOR_GURL(prefetch_buf, request.url); - DEBUG_ALIAS_FOR_GURL(initiator_buf, request.request_initiator->GetURL()); + std::string prefetch_url = request.url.spec(); + std::string initiator_url = request.request_initiator->GetURL().spec(); + SCOPED_CRASH_KEY_STRING256(Crbug1132770, PrefetchURL, prefetch_url); + SCOPED_CRASH_KEY_STRING256(Crbug1132770, InitiatorURL, initiator_url); base::debug::DumpWithoutCrashing(); } } // namespace
diff --git a/content/browser/prerender/prerender_processor_unittest.cc b/content/browser/prerender/prerender_processor_unittest.cc new file mode 100644 index 0000000..4a12422 --- /dev/null +++ b/content/browser/prerender/prerender_processor_unittest.cc
@@ -0,0 +1,235 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/prerender/prerender_processor.h" + +#include "base/run_loop.h" +#include "base/test/bind.h" +#include "base/test/scoped_feature_list.h" +#include "content/browser/site_instance_impl.h" +#include "content/browser/storage_partition_impl.h" +#include "content/public/browser/storage_partition.h" +#include "content/public/test/test_browser_context.h" +#include "content/test/test_render_view_host.h" +#include "content/test/test_web_contents.h" +#include "mojo/public/cpp/system/functions.h" +#include "third_party/blink/public/common/features.h" + +namespace content { +namespace { + +// TODO(https://crbug.com/839030): Remove this implementation along with +// deprecating the prefixed prerender events. +class PrerenderProcessorClient final + : public blink::mojom::PrerenderProcessorClient { + public: + // blink::mojom::PrerenderProcessorClient: + void OnPrerenderStart() override {} + void OnPrerenderStopLoading() override {} + void OnPrerenderDomContentLoaded() override {} + void OnPrerenderStop() override {} + + mojo::PendingRemote<blink::mojom::PrerenderProcessorClient> + BindNewPipeAndPassRemote() { + return receiver_.BindNewPipeAndPassRemote(); + } + + private: + mojo::Receiver<blink::mojom::PrerenderProcessorClient> receiver_{this}; +}; + +class PrerenderProcessorTest : public RenderViewHostImplTestHarness { + public: + void SetUp() override { + RenderViewHostImplTestHarness::SetUp(); + + scoped_feature_list_.InitAndEnableFeature(blink::features::kPrerender2); + browser_context_ = std::make_unique<TestBrowserContext>(); + + web_contents_ = TestWebContents::Create( + browser_context_.get(), + SiteInstanceImpl::Create(browser_context_.get())); + web_contents_->NavigateAndCommit(GURL("https://example.com")); + } + + void TearDown() override { + web_contents_.reset(); + browser_context_.reset(); + RenderViewHostImplTestHarness::TearDown(); + } + + void DestroyPrerenderProcessors() { + // Resetting the web contents destroys render frame hosts, which in turn + // destroy `RenderFrameHostImpl::prerender_processor_receivers_`. + web_contents_.reset(); + } + + RenderFrameHostImpl* GetRenderFrameHost() { + DCHECK(web_contents_); + return web_contents_->GetMainFrame(); + } + + PrerenderHostRegistry* GetPrerenderHostRegistry() const { + return static_cast<StoragePartitionImpl*>( + BrowserContext::GetDefaultStoragePartition( + browser_context_.get())) + ->GetPrerenderHostRegistry(); + } + + private: + base::test::ScopedFeatureList scoped_feature_list_; + + std::unique_ptr<TestBrowserContext> browser_context_; + std::unique_ptr<TestWebContents> web_contents_; +}; + +TEST_F(PrerenderProcessorTest, StartCancel) { + RenderFrameHostImpl* render_frame_host = GetRenderFrameHost(); + PrerenderHostRegistry* registry = GetPrerenderHostRegistry(); + + mojo::Remote<blink::mojom::PrerenderProcessor> remote; + render_frame_host->BindPrerenderProcessor( + render_frame_host, remote.BindNewPipeAndPassReceiver()); + + const GURL kPrerenderingUrl("https://example.com/next"); + auto attributes = blink::mojom::PrerenderAttributes::New(); + attributes->url = kPrerenderingUrl; + attributes->referrer = blink::mojom::Referrer::New(); + PrerenderProcessorClient client; + + // Start() call should register a new prerender host. + EXPECT_FALSE(registry->FindHostByUrlForTesting(kPrerenderingUrl)); + remote->Start(std::move(attributes), client.BindNewPipeAndPassRemote()); + remote.FlushForTesting(); + EXPECT_TRUE(registry->FindHostByUrlForTesting(kPrerenderingUrl)); + + // Cancel() call should abandon the prerender host. + remote->Cancel(); + remote.FlushForTesting(); + EXPECT_FALSE(registry->FindHostByUrlForTesting(kPrerenderingUrl)); +} + +TEST_F(PrerenderProcessorTest, StartDisconnect) { + RenderFrameHostImpl* render_frame_host = GetRenderFrameHost(); + PrerenderHostRegistry* registry = GetPrerenderHostRegistry(); + + mojo::Remote<blink::mojom::PrerenderProcessor> remote; + render_frame_host->BindPrerenderProcessor( + render_frame_host, remote.BindNewPipeAndPassReceiver()); + + const GURL kPrerenderingUrl("https://example.com/next"); + auto attributes = blink::mojom::PrerenderAttributes::New(); + attributes->url = kPrerenderingUrl; + attributes->referrer = blink::mojom::Referrer::New(); + PrerenderProcessorClient client; + + // Start() call should register a new prerender host. + EXPECT_FALSE(registry->FindHostByUrlForTesting(kPrerenderingUrl)); + remote->Start(std::move(attributes), client.BindNewPipeAndPassRemote()); + remote.FlushForTesting(); + EXPECT_TRUE(registry->FindHostByUrlForTesting(kPrerenderingUrl)); + + // Connection lost should abandon the prerender host. + remote.reset(); + // FlushForTesting() is no longer available. Instead, use base::RunLoop. + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(registry->FindHostByUrlForTesting(kPrerenderingUrl)); +} + +TEST_F(PrerenderProcessorTest, CancelOnDestruction) { + RenderFrameHostImpl* render_frame_host = GetRenderFrameHost(); + PrerenderHostRegistry* registry = GetPrerenderHostRegistry(); + + mojo::Remote<blink::mojom::PrerenderProcessor> remote; + render_frame_host->BindPrerenderProcessor( + render_frame_host, remote.BindNewPipeAndPassReceiver()); + + const GURL kPrerenderingUrl("https://example.com/next"); + auto attributes = blink::mojom::PrerenderAttributes::New(); + attributes->url = kPrerenderingUrl; + attributes->referrer = blink::mojom::Referrer::New(); + PrerenderProcessorClient client; + + // Start() call should register a new prerender host. + EXPECT_FALSE(registry->FindHostByUrlForTesting(kPrerenderingUrl)); + remote->Start(std::move(attributes), client.BindNewPipeAndPassRemote()); + remote.FlushForTesting(); + EXPECT_TRUE(registry->FindHostByUrlForTesting(kPrerenderingUrl)); + + // The destructor of PrerenderProcessor should abandon the prerender host. + DestroyPrerenderProcessors(); + EXPECT_FALSE(registry->FindHostByUrlForTesting(kPrerenderingUrl)); +} + +TEST_F(PrerenderProcessorTest, StartTwice) { + RenderFrameHostImpl* render_frame_host = GetRenderFrameHost(); + PrerenderHostRegistry* registry = GetPrerenderHostRegistry(); + + mojo::Remote<blink::mojom::PrerenderProcessor> remote; + render_frame_host->BindPrerenderProcessor( + render_frame_host, remote.BindNewPipeAndPassReceiver()); + + // Set up the error handler for bad mojo messages. + std::string bad_message_error; + mojo::SetDefaultProcessErrorHandler( + base::BindLambdaForTesting([&](const std::string& error) { + EXPECT_TRUE(bad_message_error.empty()); + bad_message_error = error; + })); + + const GURL kPrerenderingUrl("https://example.com/next"); + auto attributes1 = blink::mojom::PrerenderAttributes::New(); + attributes1->url = kPrerenderingUrl; + attributes1->referrer = blink::mojom::Referrer::New(); + PrerenderProcessorClient client1; + + // Start() call should register a new prerender host. + EXPECT_FALSE(registry->FindHostByUrlForTesting(kPrerenderingUrl)); + remote->Start(std::move(attributes1), client1.BindNewPipeAndPassRemote()); + remote.FlushForTesting(); + EXPECT_TRUE(registry->FindHostByUrlForTesting(kPrerenderingUrl)); + + auto attributes2 = blink::mojom::PrerenderAttributes::New(); + attributes2->url = kPrerenderingUrl; + attributes2->referrer = blink::mojom::Referrer::New(); + PrerenderProcessorClient client2; + + // Call Start() again. This should be reported as a bad mojo message. + ASSERT_TRUE(bad_message_error.empty()); + remote->Start(std::move(attributes2), client2.BindNewPipeAndPassRemote()); + remote.FlushForTesting(); + EXPECT_EQ(bad_message_error, "PP_START_TWICE"); +} + +TEST_F(PrerenderProcessorTest, CancelBeforeStart) { + RenderFrameHostImpl* render_frame_host = GetRenderFrameHost(); + + mojo::Remote<blink::mojom::PrerenderProcessor> remote; + render_frame_host->BindPrerenderProcessor( + render_frame_host, remote.BindNewPipeAndPassReceiver()); + + // Set up the error handler for bad mojo messages. + std::string bad_message_error; + mojo::SetDefaultProcessErrorHandler( + base::BindLambdaForTesting([&](const std::string& error) { + EXPECT_TRUE(bad_message_error.empty()); + bad_message_error = error; + })); + + const GURL kPrerenderingUrl("https://example.com/next"); + auto attributes1 = blink::mojom::PrerenderAttributes::New(); + attributes1->url = kPrerenderingUrl; + attributes1->referrer = blink::mojom::Referrer::New(); + PrerenderProcessorClient client1; + + // Call Cancel() before Start(). This should be reported as a bad mojo + // message. + ASSERT_TRUE(bad_message_error.empty()); + remote->Cancel(); + remote.FlushForTesting(); + EXPECT_EQ(bad_message_error, "PP_CANCEL_BEFORE_START"); +} + +} // namespace +} // namespace content
diff --git a/content/browser/renderer_host/navigation_controller_impl.cc b/content/browser/renderer_host/navigation_controller_impl.cc index 71ede49..9eb91c2 100644 --- a/content/browser/renderer_host/navigation_controller_impl.cc +++ b/content/browser/renderer_host/navigation_controller_impl.cc
@@ -319,7 +319,7 @@ break; // Fall through to rest of function. } - if (entry->restore_type() == RestoreType::LAST_SESSION_EXITED_CLEANLY) { + if (entry->restore_type() != RestoreType::NONE) { return entry->GetHasPostData() ? mojom::NavigationType::RESTORE_WITH_POST : mojom::NavigationType::RESTORE; }
diff --git a/content/browser/renderer_host/pepper/browser_ppapi_host_impl.cc b/content/browser/renderer_host/pepper/browser_ppapi_host_impl.cc index 803c8a3..8a959928 100644 --- a/content/browser/renderer_host/pepper/browser_ppapi_host_impl.cc +++ b/content/browser/renderer_host/pepper/browser_ppapi_host_impl.cc
@@ -17,7 +17,7 @@ BrowserPpapiHost* BrowserPpapiHost::CreateExternalPluginProcess( IPC::Sender* sender, ppapi::PpapiPermissions permissions, - base::ProcessHandle plugin_child_process, + base::Process plugin_child_process, IPC::ChannelProxy* channel, int render_process_id, int render_view_id, @@ -31,8 +31,7 @@ profile_directory, false /* in_process */, true /* external_plugin */); - browser_ppapi_host->set_plugin_process( - base::Process::DeprecatedGetProcessFromHandle(plugin_child_process)); + browser_ppapi_host->set_plugin_process(std::move(plugin_child_process)); scoped_refptr<PepperMessageFilter> pepper_message_filter( new PepperMessageFilter());
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc index dd1340d..af1607c 100644 --- a/content/browser/renderer_host/render_widget_host_impl.cc +++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -1106,6 +1106,8 @@ } void RenderWidgetHostImpl::Focus() { + // TODO(crbug.com/689777): This sends it to the main frame RenderWidgetHost + // should it be going to the local root instead? RenderWidgetHostImpl* focused_widget = delegate_ ? delegate_->GetRenderWidgetHostWithPageFocus() : nullptr; @@ -1115,6 +1117,8 @@ } void RenderWidgetHostImpl::Blur() { + // TODO(crbug.com/689777): This sends it to the main frame RenderWidgetHost + // should it be going to the local root instead? RenderWidgetHostImpl* focused_widget = delegate_ ? delegate_->GetRenderWidgetHostWithPageFocus() : nullptr; @@ -1154,6 +1158,11 @@ // Also send page-level focus state to other SiteInstances involved in // rendering the current FrameTree, if this widget is for a main frame. + // TODO(crbug.com/689777): We should be telling the delegate which + // RenderWidgetHost was focused (if we send it to the focused one instead + // of the main frame in order to order it correctly with other input events), + // so that the delegate can propagate it to all other WebViews based on + // where this RenderWidgetHost lives. if (owner_delegate_ && delegate_) delegate_->ReplicatePageFocus(focused); }
diff --git a/content/browser/speech/tts_controller_impl.cc b/content/browser/speech/tts_controller_impl.cc index 76df378..84967c5 100644 --- a/content/browser/speech/tts_controller_impl.cc +++ b/content/browser/speech/tts_controller_impl.cc
@@ -134,17 +134,19 @@ // specific implementation is loaded to avoid racy behaviors. if (TtsPlatformLoading()) { bool can_enqueue = utterance->GetCanEnqueue(); - utterance_list_.emplace_back(std::move(utterance)); if (!can_enqueue) ClearUtteranceQueue(true); + + utterance_list_.emplace_back(std::move(utterance)); + return; } // If we're paused and we get an utterance that can't be queued, // flush the queue but stay in the paused state. if (paused_ && !utterance->GetCanEnqueue()) { - utterance_list_.emplace_back(std::move(utterance)); Stop(); + utterance_list_.emplace_back(std::move(utterance)); paused_ = true; return; } @@ -539,12 +541,15 @@ } void TtsControllerImpl::FinishCurrentUtterance() { - if (current_utterance_) { - if (!current_utterance_->IsFinished()) - current_utterance_->OnTtsEvent(TTS_EVENT_INTERRUPTED, kInvalidCharIndex, - kInvalidLength, std::string()); - SetCurrentUtterance(nullptr); + if (!current_utterance_) + return; + + if (!current_utterance_->IsFinished()) { + current_utterance_->OnTtsEvent(TTS_EVENT_INTERRUPTED, kInvalidCharIndex, + kInvalidLength, std::string()); } + + SetCurrentUtterance(nullptr); } void TtsControllerImpl::SpeakNextUtterance() {
diff --git a/content/browser/speech/tts_controller_unittest.cc b/content/browser/speech/tts_controller_unittest.cc index 26e31da..b84fe3e0 100644 --- a/content/browser/speech/tts_controller_unittest.cc +++ b/content/browser/speech/tts_controller_unittest.cc
@@ -682,31 +682,35 @@ controller()->Pause(); EXPECT_TRUE(controller()->IsPausedForTesting()); - // Speak an utterance while controller is paused. The utterance cannot be - // queued and should be dropped. + // Speak an utterance while controller is paused. The utterance clears the + // queue and is enqueued itself. controller()->SpeakOrEnqueue(std::move(utterance1)); - EXPECT_TRUE(IsUtteranceListEmpty()); + EXPECT_FALSE(IsUtteranceListEmpty()); + EXPECT_EQ(1, controller()->QueueSize()); EXPECT_FALSE(TtsControllerCurrentUtterance()); // Speak an utterance that can be queued. The controller should stay paused - // and the second utterance must be queued. + // and the second utterance must be queued with the first also queued. std::unique_ptr<TtsUtteranceImpl> utterance2 = CreateUtteranceImpl(web_contents.get()); utterance2->SetCanEnqueue(true); controller()->SpeakOrEnqueue(std::move(utterance2)); EXPECT_TRUE(controller()->IsPausedForTesting()); + EXPECT_EQ(2, controller()->QueueSize()); EXPECT_FALSE(IsUtteranceListEmpty()); EXPECT_FALSE(TtsControllerCurrentUtterance()); - // Speak an utterance that cannot be queued should clear the queue. + // Speak an utterance that cannot be queued should clear the queue, then + // enqueue the new utterance. std::unique_ptr<TtsUtteranceImpl> utterance3 = CreateUtteranceImpl(web_contents.get()); utterance3->SetCanEnqueue(false); controller()->SpeakOrEnqueue(std::move(utterance3)); EXPECT_TRUE(controller()->IsPausedForTesting()); - EXPECT_TRUE(IsUtteranceListEmpty()); + EXPECT_FALSE(IsUtteranceListEmpty()); + EXPECT_EQ(1, controller()->QueueSize()); EXPECT_FALSE(TtsControllerCurrentUtterance()); // Resume the controller.
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc index ebfecf2..0143e0f2 100644 --- a/content/child/runtime_features.cc +++ b/content/child/runtime_features.cc
@@ -360,6 +360,7 @@ {"LayoutNG", blink::features::kLayoutNG}, {"LayoutNGFieldset", blink::features::kLayoutNGFieldset}, {"LayoutNGFragmentItem", blink::features::kFragmentItem}, + {"LayoutNGTextControl", blink::features::kLayoutNGTextControl}, {"LegacyWindowsDWriteFontFallback", features::kLegacyWindowsDWriteFontFallback}, {"LinkDisabledNewSpecBehavior",
diff --git a/content/public/browser/browser_ppapi_host.h b/content/public/browser/browser_ppapi_host.h index 91754a11..ade8ace 100644 --- a/content/public/browser/browser_ppapi_host.h +++ b/content/public/browser/browser_ppapi_host.h
@@ -38,7 +38,7 @@ static BrowserPpapiHost* CreateExternalPluginProcess( IPC::Sender* sender, ppapi::PpapiPermissions permissions, - base::ProcessHandle plugin_child_process, + base::Process plugin_child_process, IPC::ChannelProxy* channel, int render_process_id, int render_view_id,
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index 7d59da8..8f12894a 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -1889,6 +1889,7 @@ "../browser/plugin_list_unittest.cc", "../browser/prerender/prerender_host_registry_unittest.cc", "../browser/prerender/prerender_host_unittest.cc", + "../browser/prerender/prerender_processor_unittest.cc", "../browser/presentation/presentation_service_impl_unittest.cc", "../browser/quota/quota_change_dispatcher_unittest.cc", "../browser/renderer_host/ancestor_throttle_unittest.cc",
diff --git a/content/test/data/accessibility/aria/aria-owns-ignored-expected-blink.txt b/content/test/data/accessibility/aria/aria-owns-ignored-expected-blink.txt index 1ce7785e..265fb3e 100644 --- a/content/test/data/accessibility/aria/aria-owns-ignored-expected-blink.txt +++ b/content/test/data/accessibility/aria/aria-owns-ignored-expected-blink.txt
@@ -23,4 +23,3 @@ ++++++++genericContainer ++++++++++presentational ignored ++++++++++++slider horizontal value='50' valueForRange=50.00 minValueForRange=0.00 maxValueForRange=100.00 -++++++++++++++sliderThumb
diff --git a/content/test/data/accessibility/aria/aria-owns-included-in-tree-expected-blink.txt b/content/test/data/accessibility/aria/aria-owns-included-in-tree-expected-blink.txt index 996b8d8..c025fd2 100644 --- a/content/test/data/accessibility/aria/aria-owns-included-in-tree-expected-blink.txt +++ b/content/test/data/accessibility/aria/aria-owns-included-in-tree-expected-blink.txt
@@ -28,7 +28,6 @@ ++++++++++++++inlineTextBox name='xyz' ++++++++++genericContainer ++++++++++++slider horizontal value='50' valueForRange=50.00 minValueForRange=0.00 maxValueForRange=100.00 -++++++++++++++sliderThumb ++++++none ignored ++++++++genericContainer ignored ++++++genericContainer ignored invisible
diff --git a/content/test/data/accessibility/html/actions-expected-blink.txt b/content/test/data/accessibility/html/actions-expected-blink.txt index 47ad5550..e40c8f6 100644 --- a/content/test/data/accessibility/html/actions-expected-blink.txt +++ b/content/test/data/accessibility/html/actions-expected-blink.txt
@@ -2,6 +2,5 @@ ++genericContainer ignored ++++genericContainer ++++++slider horizontal value='50' valueForRange=50.00 minValueForRange=1.00 maxValueForRange=100.00 actions=setValue -++++++++sliderThumb ++++++textField name='Test textfield' actions=setValue ++++++++genericContainer
diff --git a/content/test/data/accessibility/html/input-range-expected-blink.txt b/content/test/data/accessibility/html/input-range-expected-blink.txt new file mode 100644 index 0000000..6a1ef0a --- /dev/null +++ b/content/test/data/accessibility/html/input-range-expected-blink.txt
@@ -0,0 +1,4 @@ +rootWebArea +++genericContainer ignored +++++genericContainer +++++++slider horizontal inputType='range' value='5' valueForRange=5.00 minValueForRange=1.00 maxValueForRange=10.00
diff --git a/content/test/data/accessibility/html/input-types-expected-blink.txt b/content/test/data/accessibility/html/input-types-expected-blink.txt index 5d3dc83..0cbbb725 100644 --- a/content/test/data/accessibility/html/input-types-expected-blink.txt +++ b/content/test/data/accessibility/html/input-types-expected-blink.txt
@@ -49,7 +49,6 @@ ++++++++staticText name='Range: ' ++++++++++inlineTextBox name='Range: ' ++++++++slider horizontal name='Range:' value='50' valueForRange=50.00 minValueForRange=0.00 maxValueForRange=100.00 -++++++++++sliderThumb ++++++labelText ++++++++staticText name='Reset: ' ++++++++++inlineTextBox name='Reset: '
diff --git a/content/test/data/accessibility/html/no-source-video-expected-blink.txt b/content/test/data/accessibility/html/no-source-video-expected-blink.txt index 14094441..3bcccc0 100644 --- a/content/test/data/accessibility/html/no-source-video-expected-blink.txt +++ b/content/test/data/accessibility/html/no-source-video-expected-blink.txt
@@ -15,4 +15,3 @@ ++++++++++++button name='enter full screen' restriction=disabled ++++++++++++button description='more options' name='show more media controls' descriptionFrom=attribute restriction=disabled ++++++++++slider horizontal description='video time scrubber' value='0:00' descriptionFrom=uninitialized restriction=disabled valueForRange=0.00 minValueForRange=0.00 maxValueForRange=0.00 -++++++++++++sliderThumb \ No newline at end of file
diff --git a/content/test/data/accessibility/html/video-controls-expected-blink.txt b/content/test/data/accessibility/html/video-controls-expected-blink.txt index ae9e018..a9a9ce3 100644 --- a/content/test/data/accessibility/html/video-controls-expected-blink.txt +++ b/content/test/data/accessibility/html/video-controls-expected-blink.txt
@@ -15,4 +15,3 @@ ++++++++++++++button name='enter full screen' restriction=disabled ++++++++++++++button description='more options' name='show more media controls' descriptionFrom=uninitialized restriction=disabled ++++++++++++slider horizontal description='movie time scrubber' value='0:00' descriptionFrom=uninitialized valueForRange=0.00 minValueForRange=0.00 maxValueForRange=0.00 -++++++++++++++sliderThumb
diff --git a/device/fido/fido_authenticator.cc b/device/fido/fido_authenticator.cc index c47c885..afc5974 100644 --- a/device/fido/fido_authenticator.cc +++ b/device/fido/fido_authenticator.cc
@@ -73,18 +73,18 @@ NOTREACHED(); } -FidoAuthenticator::MakeCredentialPINUVDisposition +FidoAuthenticator::PINUVDisposition FidoAuthenticator::PINUVDispositionForMakeCredential( const CtapMakeCredentialRequest& request, const FidoRequestHandlerBase::Observer* observer) { - return MakeCredentialPINUVDisposition::kNoUV; + return PINUVDisposition::kNoUV; } -FidoAuthenticator::GetAssertionPINDisposition -FidoAuthenticator::WillNeedPINToGetAssertion( +FidoAuthenticator::PINUVDisposition +FidoAuthenticator::PINUVDispositionForGetAssertion( const CtapGetAssertionRequest& request, const FidoRequestHandlerBase::Observer* observer) { - return GetAssertionPINDisposition::kNoPIN; + return PINUVDisposition::kNoUV; } void FidoAuthenticator::GetCredentialsMetadata(
diff --git a/device/fido/fido_authenticator.h b/device/fido/fido_authenticator.h index 42b044a78..0576e81 100644 --- a/device/fido/fido_authenticator.h +++ b/device/fido/fido_authenticator.h
@@ -146,9 +146,9 @@ const std::string& new_pin, SetPINCallback callback); - // MakeCredentialPINUVDisposition enumerates the possible options for - // obtaining user verification when making a credential. - enum class MakeCredentialPINUVDisposition { + // PINUVDisposition enumerates the possible options for obtaining user + // verification when making a CTAP2 request. + enum class PINUVDisposition { // No UV (neither clientPIN nor internal) is needed to make this // credential. kNoUV, @@ -165,31 +165,17 @@ // The request cannot be satisfied by this authenticator. kUnsatisfiable, }; - // PINUVDispositionForMakeCredential returns whether and how user verification + + // PINUVDisposition returns whether and how user verification // should be obtained in order to serve the given request on this // authenticator. - virtual MakeCredentialPINUVDisposition PINUVDispositionForMakeCredential( + virtual PINUVDisposition PINUVDispositionForMakeCredential( const CtapMakeCredentialRequest& request, const FidoRequestHandlerBase::Observer* observer); - // GetAssertionPINDisposition enumerates the possible interactions between - // a user-verification level and the PIN support of an authenticator when - // getting an assertion. - enum class GetAssertionPINDisposition { - // kNoPIN means that a PIN will not be needed for this assertion. - kNoPIN, - // kUsePIN means that a PIN must be gathered and used for this assertion. - kUsePIN, - // kUsePINForFallback means that a PIN may be used for fallback if internal - // user verification fails. - kUsePINForFallback, - // kUnsatisfiable means that the request cannot be satisfied by this - // authenticator. - kUnsatisfiable, - }; // WillNeedPINToGetAssertion returns whether a PIN prompt will be needed to // serve the given request on this authenticator. - virtual GetAssertionPINDisposition WillNeedPINToGetAssertion( + virtual PINUVDisposition PINUVDispositionForGetAssertion( const CtapGetAssertionRequest& request, const FidoRequestHandlerBase::Observer* observer);
diff --git a/device/fido/fido_device_authenticator.cc b/device/fido/fido_device_authenticator.cc index e3b61159..b3ee336 100644 --- a/device/fido/fido_device_authenticator.cc +++ b/device/fido/fido_device_authenticator.cc
@@ -349,7 +349,7 @@ std::move(callback), base::BindOnce(&pin::EmptyResponse::Parse)); } -FidoAuthenticator::MakeCredentialPINUVDisposition +FidoAuthenticator::PINUVDisposition FidoDeviceAuthenticator::PINUVDispositionForMakeCredential( const CtapMakeCredentialRequest& request, const FidoRequestHandlerBase::Observer* observer) { @@ -363,9 +363,6 @@ Options()->user_verification_availability == UserVerificationAvailability::kSupportedAndConfigured; - const bool can_get_token = - (can_collect_pin && pin_supported) || CanGetUvToken(); - // CTAP 2.0 requires a PIN for credential creation once a PIN has been set. // Thus, if fallback to U2F isn't possible, a PIN will be needed if set. const bool u2f_fallback_possible = @@ -373,73 +370,74 @@ device()->device_info()->versions.contains(ProtocolVersion::kU2f) && IsConvertibleToU2fRegisterCommand(request) && !ShouldPreferCTAP2EvenIfItNeedsAPIN(request); - const bool uv_required = - request.user_verification == UserVerificationRequirement::kRequired || - (pin_configured && !u2f_fallback_possible); - const bool uv_preferred = - request.user_verification == UserVerificationRequirement::kPreferred; - if (!uv_required && !(uv_preferred && (pin_configured || uv_configured))) { - return MakeCredentialPINUVDisposition::kNoUV; + const UserVerificationRequirement uv_requirement = + (pin_configured && !u2f_fallback_possible) + ? UserVerificationRequirement::kRequired + : request.user_verification; + + if (uv_requirement == UserVerificationRequirement::kDiscouraged || + (uv_requirement == UserVerificationRequirement::kPreferred && + ((!pin_configured || !can_collect_pin) && !uv_configured))) { + return PINUVDisposition::kNoUV; } // Authenticators with built-in UV that don't support UV token should try // sending the request as-is with uv=true first. if (uv_configured && !CanGetUvToken()) { return (can_collect_pin && pin_supported) - ? MakeCredentialPINUVDisposition::kNoTokenInternalUVPINFallback - : MakeCredentialPINUVDisposition::kNoTokenInternalUV; + ? PINUVDisposition::kNoTokenInternalUVPINFallback + : PINUVDisposition::kNoTokenInternalUV; } + const bool can_get_token = + (can_collect_pin && pin_supported) || CanGetUvToken(); + if (can_get_token) { - return MakeCredentialPINUVDisposition::kGetToken; + return PINUVDisposition::kGetToken; } - return MakeCredentialPINUVDisposition::kUnsatisfiable; + return PINUVDisposition::kUnsatisfiable; } -FidoAuthenticator::GetAssertionPINDisposition -FidoDeviceAuthenticator::WillNeedPINToGetAssertion( +FidoAuthenticator::PINUVDisposition +FidoDeviceAuthenticator::PINUVDispositionForGetAssertion( const CtapGetAssertionRequest& request, const FidoRequestHandlerBase::Observer* observer) { - const bool can_use_pin = (Options()->client_pin_availability == - AuthenticatorSupportedOptions:: - ClientPinAvailability::kSupportedAndPinSet) && - // The PIN is effectively unavailable if there's no - // UI support for collecting it. - observer && observer->SupportsPIN(); + // TODO(crbug.com/1149405): GetAssertion requests don't allow in-line UV + // enrollment. Perhaps we should change this and align with MakeCredential + // behavior. + const bool can_collect_pin = observer && observer->SupportsPIN(); + const bool pin_configured = Options()->client_pin_availability == + ClientPinAvailability::kSupportedAndPinSet; - // Authenticators with built-in UV can use that. - if (Options()->user_verification_availability == - UserVerificationAvailability::kSupportedAndConfigured) { - return can_use_pin ? GetAssertionPINDisposition::kUsePINForFallback - : GetAssertionPINDisposition::kNoPIN; + const bool uv_configured = + Options()->user_verification_availability == + UserVerificationAvailability::kSupportedAndConfigured; + + const UserVerificationRequirement uv_requirement = + request.allow_list.empty() ? UserVerificationRequirement::kRequired + : request.user_verification; + + if (uv_requirement == UserVerificationRequirement::kDiscouraged || + (uv_requirement == UserVerificationRequirement::kPreferred && + ((!pin_configured || !can_collect_pin) && !uv_configured))) { + return PINUVDisposition::kNoUV; } - const bool resident_key_request = request.allow_list.empty(); - - if (resident_key_request) { - if (can_use_pin) { - return GetAssertionPINDisposition::kUsePIN; - } - return GetAssertionPINDisposition::kUnsatisfiable; + // Authenticators with built-in UV that don't support UV token should try + // sending the request as-is with uv=true first. + if (uv_configured && !CanGetUvToken()) { + return (can_collect_pin && pin_configured) + ? PINUVDisposition::kNoTokenInternalUVPINFallback + : PINUVDisposition::kNoTokenInternalUV; } - // If UV is required then the PIN must be used if set, or else this request - // cannot be satisfied. - if (request.user_verification == UserVerificationRequirement::kRequired) { - if (can_use_pin) { - return GetAssertionPINDisposition::kUsePIN; - } - return GetAssertionPINDisposition::kUnsatisfiable; + if ((can_collect_pin && pin_configured) || CanGetUvToken()) { + return PINUVDisposition::kGetToken; } - // If UV is preferred and a PIN is set, use it. - if (request.user_verification == UserVerificationRequirement::kPreferred && - can_use_pin) { - return GetAssertionPINDisposition::kUsePIN; - } - return GetAssertionPINDisposition::kNoPIN; + return PINUVDisposition::kUnsatisfiable; } void FidoDeviceAuthenticator::GetCredentialsMetadata(
diff --git a/device/fido/fido_device_authenticator.h b/device/fido/fido_device_authenticator.h index ce9b9163..73e8ea5 100644 --- a/device/fido/fido_device_authenticator.h +++ b/device/fido/fido_device_authenticator.h
@@ -67,13 +67,13 @@ void ChangePIN(const std::string& old_pin, const std::string& new_pin, SetPINCallback callback) override; - MakeCredentialPINUVDisposition PINUVDispositionForMakeCredential( + PINUVDisposition PINUVDispositionForMakeCredential( const CtapMakeCredentialRequest& request, const FidoRequestHandlerBase::Observer* observer) override; // WillNeedPINToGetAssertion returns whether a PIN prompt will be needed to // serve the given request on this authenticator. - GetAssertionPINDisposition WillNeedPINToGetAssertion( + PINUVDisposition PINUVDispositionForGetAssertion( const CtapGetAssertionRequest& request, const FidoRequestHandlerBase::Observer* observer) override;
diff --git a/device/fido/get_assertion_request_handler.cc b/device/fido/get_assertion_request_handler.cc index c8b7a16..393a3a4 100644 --- a/device/fido/get_assertion_request_handler.cc +++ b/device/fido/get_assertion_request_handler.cc
@@ -44,15 +44,15 @@ namespace { -using PINDisposition = FidoAuthenticator::GetAssertionPINDisposition; +using PINUVDisposition = FidoAuthenticator::PINUVDisposition; -const std::vector<pin::Permissions> GetPinTokenPermissionsFor( +const std::set<pin::Permissions> GetPinTokenPermissionsFor( const FidoAuthenticator& authenticator, const CtapGetAssertionRequest& request) { - std::vector<pin::Permissions> permissions = {pin::Permissions::kGetAssertion}; + std::set<pin::Permissions> permissions = {pin::Permissions::kGetAssertion}; if (request.large_blob_write && authenticator.Options() && authenticator.Options()->supports_large_blobs) { - permissions.emplace_back(pin::Permissions::kLargeBlobWrite); + permissions.emplace(pin::Permissions::kLargeBlobWrite); } return permissions; } @@ -75,8 +75,7 @@ return GetAssertionStatus::kUserConsentDenied; // External authenticators may return this error if internal user - // verification fails for a make credential request or if the pin token is - // not valid. + // verification fails or if the pin token is not valid. case CtapDeviceResponseCode::kCtap2ErrPinAuthInvalid: return GetAssertionStatus::kUserConsentDenied; @@ -342,23 +341,20 @@ CtapGetAssertionRequest request = SpecializeRequestForAuthenticator(request_, *authenticator); - switch (authenticator->WillNeedPINToGetAssertion(request, observer())) { - case PINDisposition::kUsePIN: - // Skip asking for touch if this is the only available authenticator. - if (active_authenticators().size() == 1 && allow_skipping_pin_touch_) { - CollectPINThenSendRequest(authenticator); - return; - } - // A PIN will be needed. Just request a touch to let the user select - // this authenticator if they wish. - FIDO_LOG(DEBUG) << "Asking for touch from " - << authenticator->GetDisplayName() - << " because a PIN will be required"; - authenticator->GetTouch( - base::BindOnce(&GetAssertionRequestHandler::CollectPINThenSendRequest, - weak_factory_.GetWeakPtr(), authenticator)); + PINUVDisposition uv_disposition = + authenticator->PINUVDispositionForGetAssertion(request, observer()); + switch (uv_disposition) { + case PINUVDisposition::kNoUV: + case PINUVDisposition::kNoTokenInternalUV: + case PINUVDisposition::kNoTokenInternalUVPINFallback: + // Proceed without a token. + break; + case PINUVDisposition::kGetToken: + ObtainPINUVAuthToken(authenticator, + GetPinTokenPermissionsFor(*authenticator, request), + allow_skipping_pin_touch_); return; - case PINDisposition::kUnsatisfiable: + case PINUVDisposition::kUnsatisfiable: FIDO_LOG(DEBUG) << authenticator->GetDisplayName() << " cannot satisfy assertion request. Requesting " "touch in order to handle error case."; @@ -366,23 +362,10 @@ &GetAssertionRequestHandler::TerminateUnsatisfiableRequestPostTouch, weak_factory_.GetWeakPtr(), authenticator)); return; - case PINDisposition::kNoPIN: - case PINDisposition::kUsePINForFallback: - break; - } - - if (request.user_verification != UserVerificationRequirement::kDiscouraged && - authenticator->CanGetUvToken()) { - authenticator->GetUvRetries( - base::BindOnce(&GetAssertionRequestHandler::OnStartUvTokenOrFallback, - weak_factory_.GetWeakPtr(), authenticator)); - return; } ReportGetAssertionRequestTransport(authenticator); - FIDO_LOG(DEBUG) << "Asking for assertion from " - << authenticator->GetDisplayName(); CtapGetAssertionRequest request_copy(request); authenticator->GetAssertion( std::move(request_copy), options_, @@ -425,12 +408,15 @@ FidoAuthenticator* authenticator) { DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_); + auth_token_requester_map_.erase(authenticator); + FidoRequestHandlerBase::AuthenticatorRemoved(discovery, authenticator); - if (authenticator == authenticator_) { - authenticator_ = nullptr; - if (state_ == State::kWaitingForPIN || - state_ == State::kWaitingForSecondTouch) { + if (authenticator == selected_authenticator_for_pin_uv_auth_token_) { + selected_authenticator_for_pin_uv_auth_token_ = nullptr; + // Authenticator could have been removed during PIN entry or PIN fallback + // after failed internal UV. Bail and show an error. + if (state_ != State::kFinished) { state_ = State::kFinished; std::move(completion_callback_) .Run(GetAssertionStatus::kAuthenticatorRemovedDuringPINEntry, @@ -439,6 +425,107 @@ } } +void GetAssertionRequestHandler::AuthenticatorSelectedForPINUVAuthToken( + FidoAuthenticator* authenticator) { + DCHECK_EQ(state_, State::kWaitingForTouch); + state_ = State::kWaitingForToken; + selected_authenticator_for_pin_uv_auth_token_ = authenticator; + + base::EraseIf(auth_token_requester_map_, [authenticator](auto& entry) { + return entry.first != authenticator; + }); + CancelActiveAuthenticators(authenticator->GetId()); +} + +void GetAssertionRequestHandler::CollectNewPIN( + uint32_t min_pin_length, + ProvidePINCallback provide_pin_cb) { + DCHECK_EQ(state_, State::kWaitingForToken); + observer()->CollectPIN(min_pin_length, /*attempts=*/base::nullopt, + std::move(provide_pin_cb)); +} + +void GetAssertionRequestHandler::CollectExistingPIN( + int attempts, + uint32_t min_pin_length, + ProvidePINCallback provide_pin_cb) { + DCHECK_EQ(state_, State::kWaitingForToken); + observer()->CollectPIN(min_pin_length, attempts, std::move(provide_pin_cb)); +} + +void GetAssertionRequestHandler::PromptForInternalUVRetry(int attempts) { + DCHECK(state_ == State::kWaitingForTouch || + state_ == State::kWaitingForToken); + observer()->OnRetryUserVerification(attempts); +} + +void GetAssertionRequestHandler::InternalUVLockedForAuthToken() { + DCHECK(state_ == State::kWaitingForTouch || + state_ == State::kWaitingForToken); + observer()->OnInternalUserVerificationLocked(); +} + +void GetAssertionRequestHandler::HavePINUVAuthTokenResultForAuthenticator( + FidoAuthenticator* authenticator, + AuthTokenRequester::Result result, + base::Optional<pin::TokenResponse> token_response) { + DCHECK_EQ(state_, State::kWaitingForToken); + DCHECK_EQ(selected_authenticator_for_pin_uv_auth_token_, authenticator); + + base::Optional<GetAssertionStatus> error; + switch (result) { + case AuthTokenRequester::Result::kPreTouchUnsatisfiableRequest: + case AuthTokenRequester::Result::kPreTouchAuthenticatorResponseInvalid: + FIDO_LOG(ERROR) << "Ignoring AuthTokenRequester::Result=" + << static_cast<int>(result) << " from " + << authenticator->GetId(); + return; + case AuthTokenRequester::Result::kPostTouchAuthenticatorInternalUVLock: + error = GetAssertionStatus::kAuthenticatorMissingUserVerification; + break; + case AuthTokenRequester::Result::kPostTouchAuthenticatorResponseInvalid: + error = GetAssertionStatus::kAuthenticatorResponseInvalid; + break; + case AuthTokenRequester::Result::kPostTouchAuthenticatorOperationDenied: + error = GetAssertionStatus::kUserConsentDenied; + break; + case AuthTokenRequester::Result::kPostTouchAuthenticatorPINSoftLock: + error = GetAssertionStatus::kSoftPINBlock; + break; + case AuthTokenRequester::Result::kPostTouchAuthenticatorPINHardLock: + error = GetAssertionStatus::kHardPINBlock; + break; + case AuthTokenRequester::Result::kSuccess: + break; + } + if (error) { + state_ = State::kFinished; + std::move(completion_callback_).Run(*error, base::nullopt, authenticator); + return; + } + + DCHECK_EQ(result, AuthTokenRequester::Result::kSuccess); + + auto request = std::make_unique<CtapGetAssertionRequest>(request_); + SpecializeRequestForAuthenticator(*request, *authenticator); + DispatchRequestWithToken(std::move(*token_response)); +} + +void GetAssertionRequestHandler::ObtainPINUVAuthToken( + FidoAuthenticator* authenticator, + std::set<pin::Permissions> permissions, + bool skip_pin_touch) { + AuthTokenRequester::Options options; + options.token_permissions = std::move(permissions); + options.rp_id = request_.rp_id; + options.skip_pin_touch = skip_pin_touch; + + auth_token_requester_map_.insert( + {authenticator, std::make_unique<AuthTokenRequester>( + this, authenticator, std::move(options))}); + auth_token_requester_map_.at(authenticator)->ObtainPINUVAuthToken(); +} + void GetAssertionRequestHandler::HandleResponse( FidoAuthenticator* authenticator, CtapGetAssertionRequest request, @@ -448,7 +535,7 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_); if (state_ != State::kWaitingForTouch && - state_ != State::kWaitingForSecondTouch) { + state_ != State::kWaitingForResponseWithToken) { FIDO_LOG(DEBUG) << "Ignoring response from " << authenticator->GetDisplayName() << " because no longer waiting for touch"; @@ -483,34 +570,36 @@ } #endif - // Requests that require a PIN should follow the |GetTouch| path initially. - DCHECK(state_ == State::kWaitingForSecondTouch || - authenticator->WillNeedPINToGetAssertion(request, observer()) != - PINDisposition::kUsePIN); - - if ((status == CtapDeviceResponseCode::kCtap2ErrPinRequired || + // If we requested UV from an authentiator without uvToken support, UV failed, + // and the authenticator supports PIN, fall back to that. + if (request.user_verification != UserVerificationRequirement::kDiscouraged && + !request.pin_auth && + (status == CtapDeviceResponseCode::kCtap2ErrPinAuthInvalid || + status == CtapDeviceResponseCode::kCtap2ErrPinRequired || status == CtapDeviceResponseCode::kCtap2ErrOperationDenied) && - authenticator->WillNeedPINToGetAssertion(request, observer()) == - PINDisposition::kUsePINForFallback) { + authenticator->PINUVDispositionForGetAssertion(request, observer()) == + PINUVDisposition::kNoTokenInternalUVPINFallback) { // Authenticators without uvToken support will return this error immediately // without user interaction when internal UV is locked. const base::TimeDelta response_time = request_timer.Elapsed(); if (response_time < kMinExpectedAuthenticatorResponseTime) { FIDO_LOG(DEBUG) << "Authenticator is probably locked, response_time=" << response_time; - authenticator->GetTouch(base::BindOnce( - &GetAssertionRequestHandler::StartPINFallbackForInternalUv, - weak_factory_.GetWeakPtr(), authenticator)); + ObtainPINUVAuthToken(authenticator, + GetPinTokenPermissionsFor(*authenticator, request), + /*skip_pin_touch=*/false); return; } - StartPINFallbackForInternalUv(authenticator); + ObtainPINUVAuthToken(authenticator, + GetPinTokenPermissionsFor(*authenticator, request), + /*skip_pin_touch=*/true); return; } const base::Optional<GetAssertionStatus> maybe_result = ConvertDeviceResponseCode(status); if (!maybe_result) { - if (state_ == State::kWaitingForSecondTouch) { + if (state_ == State::kWaitingForResponseWithToken) { std::move(completion_callback_) .Run(GetAssertionStatus::kAuthenticatorResponseInvalid, base::nullopt, authenticator); @@ -613,34 +702,6 @@ OnGetAssertionSuccess(authenticator, std::move(request)); } -void GetAssertionRequestHandler::CollectPINThenSendRequest( - FidoAuthenticator* authenticator) { - if (state_ != State::kWaitingForTouch) { - return; - } - DCHECK_NE(authenticator->WillNeedPINToGetAssertion( - SpecializeRequestForAuthenticator(request_, *authenticator), - observer()), - PINDisposition::kNoPIN); - DCHECK(observer()); - state_ = State::kGettingRetries; - CancelActiveAuthenticators(authenticator->GetId()); - authenticator_ = authenticator; - authenticator_->GetPinRetries( - base::BindOnce(&GetAssertionRequestHandler::OnPinRetriesResponse, - weak_factory_.GetWeakPtr())); -} - -void GetAssertionRequestHandler::StartPINFallbackForInternalUv( - FidoAuthenticator* authenticator) { - DCHECK_EQ(authenticator->WillNeedPINToGetAssertion( - SpecializeRequestForAuthenticator(request_, *authenticator), - observer()), - PINDisposition::kUsePINForFallback); - observer()->OnInternalUserVerificationLocked(); - CollectPINThenSendRequest(authenticator); -} - void GetAssertionRequestHandler::TerminateUnsatisfiableRequestPostTouch( FidoAuthenticator* authenticator) { // User touched an authenticator that cannot handle this request or internal @@ -653,220 +714,27 @@ base::nullopt, nullptr); } -void GetAssertionRequestHandler::OnPinRetriesResponse( - CtapDeviceResponseCode status, - base::Optional<pin::RetriesResponse> response) { - DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_); - DCHECK_EQ(state_, State::kGettingRetries); - if (status != CtapDeviceResponseCode::kSuccess) { - FIDO_LOG(ERROR) << "OnPinRetriesResponse() failed for " - << authenticator_->GetDisplayName(); - state_ = State::kFinished; - std::move(completion_callback_) - .Run(GetAssertionStatus::kAuthenticatorResponseInvalid, base::nullopt, - nullptr); - return; - } - if (response->retries == 0) { - state_ = State::kFinished; - std::move(completion_callback_) - .Run(GetAssertionStatus::kHardPINBlock, base::nullopt, nullptr); - return; - } - state_ = State::kWaitingForPIN; - observer()->CollectPIN(authenticator_->CurrentMinPINLength(), - response->retries, - base::BindOnce(&GetAssertionRequestHandler::OnHavePIN, - weak_factory_.GetWeakPtr())); -} - -void GetAssertionRequestHandler::OnHavePIN(std::string pin) { - DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_); - DCHECK_EQ(State::kWaitingForPIN, state_); - DCHECK(pin::IsValid(pin)); - - if (authenticator_ == nullptr) { - // Authenticator was detached. The request will already have been canceled - // but this callback may have been waiting in a queue. - return; - } - - state_ = State::kRequestWithPIN; - authenticator_->GetPINToken( - std::move(pin), GetPinTokenPermissionsFor(*authenticator_, request_), - request_.rp_id, - base::BindOnce(&GetAssertionRequestHandler::OnHavePINToken, - weak_factory_.GetWeakPtr())); -} - -void GetAssertionRequestHandler::OnHavePINToken( - CtapDeviceResponseCode status, - base::Optional<pin::TokenResponse> response) { - DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_); - DCHECK_EQ(state_, State::kRequestWithPIN); - - if (status == CtapDeviceResponseCode::kCtap2ErrPinInvalid) { - state_ = State::kGettingRetries; - authenticator_->GetPinRetries( - base::BindOnce(&GetAssertionRequestHandler::OnPinRetriesResponse, - weak_factory_.GetWeakPtr())); - return; - } - - if (status != CtapDeviceResponseCode::kSuccess) { - state_ = State::kFinished; - GetAssertionStatus ret; - switch (status) { - case CtapDeviceResponseCode::kCtap2ErrPinAuthBlocked: - ret = GetAssertionStatus::kSoftPINBlock; - break; - case CtapDeviceResponseCode::kCtap2ErrPinBlocked: - ret = GetAssertionStatus::kHardPINBlock; - break; - default: - ret = GetAssertionStatus::kAuthenticatorResponseInvalid; - break; - } - std::move(completion_callback_).Run(ret, base::nullopt, nullptr); - return; - } - - DispatchRequestWithToken(std::move(*response)); -} - -void GetAssertionRequestHandler::OnStartUvTokenOrFallback( - FidoAuthenticator* authenticator, - CtapDeviceResponseCode status, - base::Optional<pin::RetriesResponse> response) { - size_t retries; - if (status != CtapDeviceResponseCode::kSuccess) { - FIDO_LOG(ERROR) << "OnStartUvTokenOrFallback() failed for " - << authenticator_->GetDisplayName() - << ", assuming authenticator locked."; - retries = 0; - } else { - retries = response->retries; - } - - if (retries == 0) { - CtapGetAssertionRequest request = - SpecializeRequestForAuthenticator(request_, *authenticator); - if (authenticator->WillNeedPINToGetAssertion(request, observer()) == - PINDisposition::kUsePINForFallback) { - authenticator->GetTouch(base::BindOnce( - &GetAssertionRequestHandler::StartPINFallbackForInternalUv, - weak_factory_.GetWeakPtr(), authenticator)); - return; - } - authenticator->GetTouch(base::BindOnce( - &GetAssertionRequestHandler::TerminateUnsatisfiableRequestPostTouch, - weak_factory_.GetWeakPtr(), authenticator)); - } - - authenticator->GetUvToken( - GetPinTokenPermissionsFor(*authenticator, request_), request_.rp_id, - base::BindOnce(&GetAssertionRequestHandler::OnHaveUvToken, - weak_factory_.GetWeakPtr(), authenticator)); -} - -void GetAssertionRequestHandler::OnUvRetriesResponse( - CtapDeviceResponseCode status, - base::Optional<pin::RetriesResponse> response) { - if (status != CtapDeviceResponseCode::kSuccess) { - FIDO_LOG(ERROR) << "OnUvRetriesResponse() failed for " - << authenticator_->GetDisplayName(); - state_ = State::kFinished; - std::move(completion_callback_) - .Run(GetAssertionStatus::kAuthenticatorResponseInvalid, base::nullopt, - nullptr); - return; - } - state_ = State::kWaitingForTouch; - if (response->retries == 0) { - CtapGetAssertionRequest request = - SpecializeRequestForAuthenticator(request_, *authenticator_); - if (authenticator_->WillNeedPINToGetAssertion(request, observer()) == - PINDisposition::kUsePINForFallback) { - // Fall back to PIN. - StartPINFallbackForInternalUv(authenticator_); - return; - } - // Device does not support fallback to PIN, terminate the request instead. - TerminateUnsatisfiableRequestPostTouch(authenticator_); - return; - } - observer()->OnRetryUserVerification(response->retries); - authenticator_->GetUvToken( - GetPinTokenPermissionsFor(*authenticator_, request_), request_.rp_id, - base::BindOnce(&GetAssertionRequestHandler::OnHaveUvToken, - weak_factory_.GetWeakPtr(), authenticator_)); -} - -void GetAssertionRequestHandler::OnHaveUvToken( - FidoAuthenticator* authenticator, - CtapDeviceResponseCode status, - base::Optional<pin::TokenResponse> response) { - DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_); - if (state_ != State::kWaitingForTouch) { - FIDO_LOG(DEBUG) << "Ignoring uv token response from " - << authenticator->GetDisplayName() - << " because no longer waiting for touch"; - return; - } - - if (status == CtapDeviceResponseCode::kCtap2ErrUvInvalid || - status == CtapDeviceResponseCode::kCtap2ErrOperationDenied || - status == CtapDeviceResponseCode::kCtap2ErrUvBlocked) { - if (status == CtapDeviceResponseCode::kCtap2ErrUvBlocked) { - CtapGetAssertionRequest request = - SpecializeRequestForAuthenticator(request_, *authenticator_); - if (authenticator->WillNeedPINToGetAssertion(request, observer()) == - PINDisposition::kUsePINForFallback) { - StartPINFallbackForInternalUv(authenticator); - return; - } - TerminateUnsatisfiableRequestPostTouch(authenticator); - return; - } - DCHECK(status == CtapDeviceResponseCode::kCtap2ErrUvInvalid || - status == CtapDeviceResponseCode::kCtap2ErrOperationDenied); - CancelActiveAuthenticators(authenticator->GetId()); - authenticator_ = authenticator; - state_ = State::kGettingRetries; - authenticator->GetUvRetries( - base::BindOnce(&GetAssertionRequestHandler::OnUvRetriesResponse, - weak_factory_.GetWeakPtr())); - return; - } - - if (status != CtapDeviceResponseCode::kSuccess) { - FIDO_LOG(ERROR) << "Ignoring status " << static_cast<int>(status) - << " from " << authenticator->GetDisplayName(); - return; - } - - CancelActiveAuthenticators(authenticator->GetId()); - authenticator_ = authenticator; - DispatchRequestWithToken(std::move(*response)); -} - void GetAssertionRequestHandler::DispatchRequestWithToken( pin::TokenResponse token) { + DCHECK(selected_authenticator_for_pin_uv_auth_token_); + observer()->FinishCollectToken(); pin_token_ = std::move(token); - state_ = State::kWaitingForSecondTouch; - CtapGetAssertionRequest request = - SpecializeRequestForAuthenticator(request_, *authenticator_); + state_ = State::kWaitingForResponseWithToken; + CtapGetAssertionRequest request = SpecializeRequestForAuthenticator( + request_, *selected_authenticator_for_pin_uv_auth_token_); std::tie(request.pin_protocol, request.pin_auth) = pin_token_->PinAuth(request.client_data_hash); - ReportGetAssertionRequestTransport(authenticator_); + ReportGetAssertionRequestTransport( + selected_authenticator_for_pin_uv_auth_token_); auto request_copy(request); - authenticator_->GetAssertion( + selected_authenticator_for_pin_uv_auth_token_->GetAssertion( std::move(request_copy), options_, base::BindOnce(&GetAssertionRequestHandler::HandleResponse, - weak_factory_.GetWeakPtr(), authenticator_, + weak_factory_.GetWeakPtr(), + selected_authenticator_for_pin_uv_auth_token_, std::move(request), base::ElapsedTimer())); }
diff --git a/device/fido/get_assertion_request_handler.h b/device/fido/get_assertion_request_handler.h index cb0a39e..38800d48 100644 --- a/device/fido/get_assertion_request_handler.h +++ b/device/fido/get_assertion_request_handler.h
@@ -6,6 +6,7 @@ #define DEVICE_FIDO_GET_ASSERTION_REQUEST_HANDLER_H_ #include <memory> +#include <set> #include <string> #include <vector> @@ -13,6 +14,7 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/optional.h" +#include "device/fido/auth_token_requester.h" #include "device/fido/authenticator_get_assertion_response.h" #include "device/fido/ctap_get_assertion_request.h" #include "device/fido/fido_constants.h" @@ -29,7 +31,6 @@ class FidoDiscoveryFactory; namespace pin { -struct RetriesResponse; class TokenResponse; } // namespace pin @@ -51,7 +52,8 @@ }; class COMPONENT_EXPORT(DEVICE_FIDO) GetAssertionRequestHandler - : public FidoRequestHandlerBase { + : public FidoRequestHandlerBase, + public AuthTokenRequester::Delegate { public: using CompletionCallback = base::OnceCallback<void( GetAssertionStatus, @@ -70,10 +72,8 @@ private: enum class State { kWaitingForTouch, - kWaitingForSecondTouch, - kGettingRetries, - kWaitingForPIN, - kRequestWithPIN, + kWaitingForToken, + kWaitingForResponseWithToken, kReadingMultipleResponses, kFinished, }; @@ -89,6 +89,24 @@ void AuthenticatorRemoved(FidoDiscoveryBase* discovery, FidoAuthenticator* authenticator) override; + // AuthTokenRequester::Delegate: + void AuthenticatorSelectedForPINUVAuthToken( + FidoAuthenticator* authenticator) override; + void CollectNewPIN(uint32_t min_pin_length, + ProvidePINCallback provide_pin_cb) override; + void CollectExistingPIN(int attempts, + uint32_t min_pin_length, + ProvidePINCallback provide_pin_cb) override; + void PromptForInternalUVRetry(int attempts) override; + void InternalUVLockedForAuthToken() override; + void HavePINUVAuthTokenResultForAuthenticator( + FidoAuthenticator* authenticator, + AuthTokenRequester::Result result, + base::Optional<pin::TokenResponse> response) override; + + void ObtainPINUVAuthToken(FidoAuthenticator* authenticator, + std::set<pin::Permissions> permissions, + bool skip_pin_touch); void HandleResponse( FidoAuthenticator* authenticator, CtapGetAssertionRequest request, @@ -100,22 +118,7 @@ CtapGetAssertionRequest request, CtapDeviceResponseCode response_code, base::Optional<AuthenticatorGetAssertionResponse> response); - void CollectPINThenSendRequest(FidoAuthenticator* authenticator); - void StartPINFallbackForInternalUv(FidoAuthenticator* authenticator); void TerminateUnsatisfiableRequestPostTouch(FidoAuthenticator* authenticator); - void OnPinRetriesResponse(CtapDeviceResponseCode status, - base::Optional<pin::RetriesResponse> response); - void OnHavePIN(std::string pin); - void OnHavePINToken(CtapDeviceResponseCode status, - base::Optional<pin::TokenResponse> response); - void OnStartUvTokenOrFallback(FidoAuthenticator* authenticator, - CtapDeviceResponseCode status, - base::Optional<pin::RetriesResponse> response); - void OnUvRetriesResponse(CtapDeviceResponseCode status, - base::Optional<pin::RetriesResponse> response); - void OnHaveUvToken(FidoAuthenticator* authenticator, - CtapDeviceResponseCode status, - base::Optional<pin::TokenResponse> response); void DispatchRequestWithToken(pin::TokenResponse token); void OnGetAssertionSuccess(FidoAuthenticator* authenticator, CtapGetAssertionRequest request); @@ -132,23 +135,32 @@ CtapGetAssertionRequest request_; CtapGetAssertionOptions options_; base::Optional<pin::TokenResponse> pin_token_; + // If true, and if at the time the request is dispatched to the first // authenticator no other authenticators are available, the request handler // will skip the initial touch that is usually required to select a PIN // protected authenticator. bool allow_skipping_pin_touch_; - // authenticator_ points to the authenticator that will be used for this - // operation. It's only set after the user touches an authenticator to select - // it, after which point that authenticator will be used exclusively through - // requesting PIN etc. The object is owned by the underlying discovery object - // and this pointer is cleared if it's removed during processing. - FidoAuthenticator* authenticator_ = nullptr; + + // selected_authenticator_for_pin_uv_auth_token_ points to the authenticator + // that was tapped by the user while requesting a pinUvAuthToken from + // connected authenticators. The object is owned by the underlying discovery + // object and this pointer is cleared if it's removed during processing. + FidoAuthenticator* selected_authenticator_for_pin_uv_auth_token_ = nullptr; + // responses_ holds the set of responses while they are incrementally read // from the device. Only used when more than one response is returned. std::vector<AuthenticatorGetAssertionResponse> responses_; + // remaining_responses_ contains the number of responses that remain to be // read when multiple responses are returned. size_t remaining_responses_ = 0; + + // auth_token_requester_map_ holds active AuthTokenRequesters for + // authenticators that need a pinUvAuthToken to service the request. + std::map<FidoAuthenticator*, std::unique_ptr<AuthTokenRequester>> + auth_token_requester_map_; + SEQUENCE_CHECKER(my_sequence_checker_); base::WeakPtrFactory<GetAssertionRequestHandler> weak_factory_{this};
diff --git a/device/fido/make_credential_request_handler.cc b/device/fido/make_credential_request_handler.cc index d6bb9ed..c1a6e65 100644 --- a/device/fido/make_credential_request_handler.cc +++ b/device/fido/make_credential_request_handler.cc
@@ -27,8 +27,7 @@ namespace device { -using MakeCredentialPINUVDisposition = - FidoAuthenticator::MakeCredentialPINUVDisposition; +using PINUVDisposition = FidoAuthenticator::PINUVDisposition; using BioEnrollmentAvailability = AuthenticatorSupportedOptions::BioEnrollmentAvailability; @@ -130,7 +129,7 @@ } if (authenticator->PINUVDispositionForMakeCredential(request, observer) == - MakeCredentialPINUVDisposition::kUnsatisfiable) { + PINUVDisposition::kUnsatisfiable) { return MakeCredentialStatus::kAuthenticatorMissingUserVerification; } @@ -428,14 +427,14 @@ auto uv_disposition = authenticator->PINUVDispositionForMakeCredential( *request.get(), observer()); switch (uv_disposition) { - case MakeCredentialPINUVDisposition::kNoUV: - case MakeCredentialPINUVDisposition::kNoTokenInternalUV: - case MakeCredentialPINUVDisposition::kNoTokenInternalUVPINFallback: + case PINUVDisposition::kNoUV: + case PINUVDisposition::kNoTokenInternalUV: + case PINUVDisposition::kNoTokenInternalUVPINFallback: break; - case MakeCredentialPINUVDisposition::kGetToken: + case PINUVDisposition::kGetToken: ObtainPINUVAuthToken(authenticator, skip_pin_touch); return; - case MakeCredentialPINUVDisposition::kUnsatisfiable: + case PINUVDisposition::kUnsatisfiable: // |IsCandidateAuthenticatorPostTouch| should have handled this case. NOTREACHED(); return; @@ -529,8 +528,8 @@ << authenticator->GetId(); return; case AuthTokenRequester::Result::kPostTouchAuthenticatorInternalUVLock: - HandleInternalUvLocked(authenticator); - return; + error = MakeCredentialStatus::kAuthenticatorMissingUserVerification; + break; case AuthTokenRequester::Result::kPostTouchAuthenticatorResponseInvalid: error = MakeCredentialStatus::kAuthenticatorResponseInvalid; break; @@ -641,7 +640,7 @@ (status == CtapDeviceResponseCode::kCtap2ErrPinAuthInvalid || status == CtapDeviceResponseCode::kCtap2ErrPinRequired) && authenticator->PINUVDispositionForMakeCredential(*request, observer()) == - MakeCredentialPINUVDisposition::kNoTokenInternalUVPINFallback) { + PINUVDisposition::kNoTokenInternalUVPINFallback) { // Authenticators without uvToken support will return this error immediately // without user interaction when internal UV is locked. const base::TimeDelta response_time = request_timer.Elapsed(); @@ -718,15 +717,6 @@ .Run(MakeCredentialStatus::kSuccess, std::move(*response), authenticator); } -void MakeCredentialRequestHandler::HandleInternalUvLocked( - FidoAuthenticator* authenticator) { - state_ = State::kFinished; - CancelActiveAuthenticators(authenticator->GetId()); - std::move(completion_callback_) - .Run(MakeCredentialStatus::kAuthenticatorMissingUserVerification, - base::nullopt, nullptr); -} - void MakeCredentialRequestHandler::HandleInapplicableAuthenticator( FidoAuthenticator* authenticator, std::unique_ptr<CtapMakeCredentialRequest> request) {
diff --git a/device/fido/make_credential_request_handler.h b/device/fido/make_credential_request_handler.h index e4ebfb0..610ec6f91 100644 --- a/device/fido/make_credential_request_handler.h +++ b/device/fido/make_credential_request_handler.h
@@ -178,7 +178,6 @@ base::ElapsedTimer request_timer, CtapDeviceResponseCode response_code, base::Optional<AuthenticatorMakeCredentialResponse> response); - void HandleInternalUvLocked(FidoAuthenticator* authenticator); void HandleInapplicableAuthenticator( FidoAuthenticator* authenticator, std::unique_ptr<CtapMakeCredentialRequest> request);
diff --git a/docs/win_order_files.md b/docs/win_order_files.md index 2366f78a..aa521ed1 100644 --- a/docs/win_order_files.md +++ b/docs/win_order_files.md
@@ -1,86 +1,8 @@ # Updating the Windows .order files -The `chrome/build/*.orderfile` files are used to specify the order in which -the linker should lay out symbols in the binary it's producing. By ordering -functions in the order they're typically executed during start-up, the start-up -time can be reduced slightly. - -The order files are used automatically when building with Clang for Windows with -the gn flag `is_official_build` set to `true`. - -To update the order files: - -1. Build with instrumentation enabled: - - The instrumentation will capture the couple of million function calls - in a binary as it runs and write them to a file in the `\src\tmp` directory. - Make sure this directory exists. - - ```shell - gn gen out\instrument --args="is_debug=false is_official_build=true generate_order_files=true symbol_level=1" - ninja -C out\instrument chrome - ``` - - (If you have access to Goma, add `use_goma=true` to the gn args and `-j500` - to the Ninja invocation.) - - -1. Run the instrumented binaries: - - (Some binaries such as `mksnapshot`, `yasm`, and `protoc` already ran with - instrumentation during the build process. The instrumentation output should - be available under `\src\tmp`.) - - Open the Task Manager's Details tab or - [Process Explorer](https://docs.microsoft.com/en-us/sysinternals/downloads/process-explorer) - to be able to see the Process IDs of running programs. - - Run Chrome: - - ```shell - out\instrument\chrome - ``` - - Note the Process ID of the browser process. - - Check in `\src\tmp\` for instrumentation output from the process, for - example `cygprofile_14652.txt`. The files are only written once a certain - number of function calls have been made, so sometimes you need to browse a - bit for the file to be produced. - -1. If the file appears to have sensible contents (a long list of function names - that eventually seem related to what the browser should - do), copy it into `chrome\build\`: - - ```shell - copy \src\tmp\cygprofile_25392.txt chrome\build\chrome.x64.orderfile - ``` - -1. Re-build the `chrome` target. This will re-link `chrome.dll` - using the new order file and surface any link errors if - the order file is broken. - - ```shell - ninja -C out\instrument chrome - ``` - - -1. Repeat the previous steps with a 32-bit build, i.e. passing - `target_cpu="x86"` to gn and storing the file as `.x86.orderfile`. - - -1. Upload the order files to Google Cloud Storage. They will get downloaded - by a `gclient` hook based on the contents of the `.orderfile.sha1` files. - - You need to have write access to the `chromium-browser-clang` GCS bucket - for this step. - - ```shell - cd chrome\build\ - upload_to_google_storage.py -b chromium-browser-clang/orderfiles -z orderfile chrome.x64.orderfile chrome.x86.orderfile - gsutil.py setacl public-read gs://chromium-browser-clang/orderfiles/* - ``` - - -1. Check in the `.sha1` files corresponding to the orderfiles created by the - previous step. +Since [#824529](https://crrev.com/824529), order files are no longer used for +linking Chromium on Windows. Instead, the linker orders the binary contents +based on profile-guided optimization (PGO) data, using LLD's call graph profile +sort feature. That provides similar benefits and uses use the existing PGO +infrastructure instead of requiring maintenance of the order files. See +[crbug.com/1077279](https://crbug.com/1077279).
diff --git a/extensions/browser/api/declarative_net_request/rules_monitor_service.cc b/extensions/browser/api/declarative_net_request/rules_monitor_service.cc index a4f781c..97da952 100644 --- a/extensions/browser/api/declarative_net_request/rules_monitor_service.cc +++ b/extensions/browser/api/declarative_net_request/rules_monitor_service.cc
@@ -30,6 +30,7 @@ #include "extensions/browser/api/declarative_net_request/ruleset_matcher.h" #include "extensions/browser/api/web_request/permission_helper.h" #include "extensions/browser/api/web_request/web_request_api.h" +#include "extensions/browser/disable_reason.h" #include "extensions/browser/extension_file_task_runner.h" #include "extensions/browser/extension_prefs.h" #include "extensions/browser/extension_prefs_factory.h" @@ -64,6 +65,24 @@ UMA_HISTOGRAM_ENUMERATION(kLoadRulesetResultHistogram, result); } +// Returns whether the extension's allocation should be released. This would +// return true for cases where we expect the extension to be unloaded for a +// while. +bool ShouldReleaseAllocationOnUnload(const ExtensionPrefs* prefs, + const ExtensionId& extension_id, + UnloadedExtensionReason reason) { + if (reason == UnloadedExtensionReason::DISABLE) { + static constexpr int kReleaseAllocationDisableReasons = + disable_reason::DISABLE_BLOCKED_BY_POLICY | + disable_reason::DISABLE_REMOTELY_FOR_MALWARE; + + return (prefs->GetDisableReasons(extension_id) & + kReleaseAllocationDisableReasons) != 0; + } + + return reason == UnloadedExtensionReason::BLOCKLIST; +} + } // namespace // Helper to bridge tasks to FileSequenceHelper. Lives on the UI thread. @@ -352,13 +371,16 @@ UnloadedExtensionReason reason) { DCHECK_EQ(context_, browser_context); - // If the extension is unloaded for any reason other than an update, the - // unused rule allocation should not be kept for this extension the next time - // its rulesets are loaded, as it is no longer "the first load after an - // update". - if (base::FeatureList::IsEnabled(kDeclarativeNetRequestGlobalRules) && - reason != UnloadedExtensionReason::UPDATE) { - prefs_->SetDNRKeepExcessAllocation(extension->id(), false); + if (base::FeatureList::IsEnabled(kDeclarativeNetRequestGlobalRules)) { + // If the extension is unloaded for any reason other than an update, the + // unused rule allocation should not be kept for this extension the next + // time its rulesets are loaded, as it is no longer "the first load after an + // update". + if (reason != UnloadedExtensionReason::UPDATE) + prefs_->SetDNRKeepExcessAllocation(extension->id(), false); + + if (ShouldReleaseAllocationOnUnload(prefs_, extension->id(), reason)) + global_rules_tracker_.ClearExtensionAllocation(extension->id()); } // Return early if the extension does not have an active indexed ruleset.
diff --git a/extensions/browser/extension_action.cc b/extensions/browser/extension_action.cc index 9cee93a..7bf6d84 100644 --- a/extensions/browser/extension_action.cc +++ b/extensions/browser/extension_action.cc
@@ -17,7 +17,6 @@ #include "extensions/common/extension_icon_set.h" #include "extensions/common/manifest_handlers/icons_handler.h" #include "extensions/grit/extensions_browser_resources.h" -#include "skia/ext/skia_utils_base.h" #include "skia/public/mojom/bitmap.mojom.h" #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkCanvas.h" @@ -137,20 +136,12 @@ } else { continue; } - SkBitmap unsafe_bitmap; - if (!skia::mojom::InlineBitmap::Deserialize(bytes, num_bytes, - &unsafe_bitmap)) { - return IconParseResult::kUnpickleFailure; - } - CHECK(!unsafe_bitmap.isNull()); - // On receipt of an arbitrary bitmap from the renderer, we convert to an N32 - // 32bpp bitmap. Other pixel sizes can lead to out-of-bounds mistakes when - // transferring the pixels out of the/ bitmap into other buffers. SkBitmap bitmap; - if (!skia::SkBitmapToN32OpaqueOrPremul(unsafe_bitmap, &bitmap)) { - NOTREACHED() << "Unable to convert bitmap for icon"; + if (!skia::mojom::InlineBitmap::Deserialize(bytes, num_bytes, &bitmap)) { return IconParseResult::kUnpickleFailure; } + // A well-behaved renderer will never send a null bitmap to us here. + CHECK(!bitmap.isNull()); // Chrome helpfully scales the provided icon(s), but let's not go overboard. const int kActionIconMaxSize = 10 * ActionIconSize();
diff --git a/extensions/common/api/automation.idl b/extensions/common/api/automation.idl index cd548e079..4554c20 100644 --- a/extensions/common/api/automation.idl +++ b/extensions/common/api/automation.idl
@@ -301,7 +301,6 @@ searchBox, section, slider, - sliderThumb, spinButton, splitter, staticText,
diff --git a/fuchsia/engine/browser/accessibility_bridge.cc b/fuchsia/engine/browser/accessibility_bridge.cc index 0936993..5a27507a 100644 --- a/fuchsia/engine/browser/accessibility_bridge.cc +++ b/fuchsia/engine/browser/accessibility_bridge.cc
@@ -93,9 +93,7 @@ // Updates to AXTree must be applied first. for (const ui::AXTreeUpdate& update : details.updates) { - if (!update.has_tree_data && - ax_tree_.GetAXTreeID() != ui::AXTreeIDUnknown() && - ax_tree_.GetAXTreeID() != details.ax_tree_id) { + if (web_contents_->GetMainFrame()->GetAXTreeID() != details.ax_tree_id) { // TODO(https://crbug.com/1128954): Add support for combining AXTrees. continue; }
diff --git a/fuchsia/engine/browser/accessibility_bridge_browsertest.cc b/fuchsia/engine/browser/accessibility_bridge_browsertest.cc index f16ae01..96a7935d 100644 --- a/fuchsia/engine/browser/accessibility_bridge_browsertest.cc +++ b/fuchsia/engine/browser/accessibility_bridge_browsertest.cc
@@ -8,6 +8,7 @@ #include "content/public/test/browser_test.h" #include "fuchsia/base/frame_test_util.h" +#include "fuchsia/base/mem_buffer_util.h" #include "fuchsia/base/test_navigation_listener.h" #include "fuchsia/engine/browser/accessibility_bridge.h" #include "fuchsia/engine/browser/fake_semantics_manager.h" @@ -23,8 +24,10 @@ const char kPage1Path[] = "/ax1.html"; const char kPage2Path[] = "/batching.html"; +const char kPageIframePath[] = "/iframe.html"; const char kPage1Title[] = "accessibility 1"; const char kPage2Title[] = "lots of nodes!"; +const char kPageIframeTitle[] = "iframe title"; const char kButtonName1[] = "a button"; const char kButtonName2[] = "another button"; const char kButtonName3[] = "button 3"; @@ -65,10 +68,13 @@ return event; } -// Creates an AXEventNotificationDetails that contains |update|. +// Creates an AXEventNotificationDetails that contains |update| for the tree +// referenced by |tree_id|. content::AXEventNotificationDetails CreateAccessibilityEventWithUpdate( - ui::AXTreeUpdate update) { + ui::AXTreeUpdate update, + ui::AXTreeID tree_id) { content::AXEventNotificationDetails event; + event.ax_tree_id = tree_id; event.updates.push_back(std::move(update)); return event; } @@ -402,6 +408,7 @@ // full semantic tree is sent in the first update when back on. IN_PROC_BROWSER_TEST_F(AccessibilityBridgeTest, TogglesSemanticsUpdates) { LoadPage(kPage1Path, kPage1Title); + semantics_manager_.semantic_tree()->RunUntilCommitCountIs(1); semantics_manager_.semantic_tree()->RunUntilNodeCountAtLeast(kPage1NodeCount); EXPECT_EQ(semantics_manager_.semantic_tree()->num_commit_calls(), 1u); @@ -429,15 +436,34 @@ // valid state. Note that every time that a new tree is sent to Fuchsia, the // FakeSemantiTree checks if the tree is valid. IN_PROC_BROWSER_TEST_F(AccessibilityBridgeTest, TreeModificationsAreForwarded) { + // Loads a page, so a real frame is created for this test. Then, several tree + // operations are applied on top of it, using the AXTreeID that corresponds to + // that frame. + LoadPage(kPage1Path, kPage1Title); + semantics_manager_.semantic_tree()->RunUntilCommitCountIs(1); + + // Fetch the AXTreeID of the main frame (the page just loaded). This ID will + // be used in the operations that follow to simulate new data coming in. + auto tree_id = + frame_impl_->web_contents_for_test()->GetMainFrame()->GetAXTreeID(); + AccessibilityBridge* bridge = frame_impl_->accessibility_bridge_for_test(); size_t tree_size = 5; // The tree has the following form: (1 (2 (3 (4 (5))))) auto tree_accessibility_event = CreateTreeAccessibilityEvent(tree_size); + tree_accessibility_event.ax_tree_id = tree_id; + + // The root of this tree needs to be cleared (because it holds the page just + // loaded, and we are loading something completely new). + tree_accessibility_event.updates[0].node_id_to_clear = + bridge->ax_tree_for_test()->root()->id(); + bridge->AccessibilityEventReceived(tree_accessibility_event); - semantics_manager_.semantic_tree()->RunUntilNodeCountAtLeast(tree_size); - CheckCallsToFakeSemanticTree(/*num_deletes=*/0, /*num_updates=*/1, - /*num_commits=*/1); + + semantics_manager_.semantic_tree()->RunUntilCommitCountIs(2); + CheckCallsToFakeSemanticTree(/*num_deletes=*/1, /*num_updates=*/3, + /*num_commits=*/2); // Adds a new node with ID 6. // (1 (2 (3 (4 (5 6))))) @@ -451,10 +477,10 @@ update.nodes[1].id = 6; bridge->AccessibilityEventReceived( - CreateAccessibilityEventWithUpdate(std::move(update))); - semantics_manager_.semantic_tree()->RunUntilNodeCountAtLeast(tree_size + 1); - CheckCallsToFakeSemanticTree(/*num_deletes=*/0, /*num_updates=*/2, - /*num_commits=*/2); + CreateAccessibilityEventWithUpdate(std::move(update), tree_id)); + semantics_manager_.semantic_tree()->RunUntilCommitCountIs(3); + CheckCallsToFakeSemanticTree(/*num_deletes=*/1, /*num_updates=*/4, + /*num_commits=*/3); } // Removes the added node 6. @@ -470,11 +496,11 @@ update.nodes[1].id = 5; bridge->AccessibilityEventReceived( - CreateAccessibilityEventWithUpdate(std::move(update))); + CreateAccessibilityEventWithUpdate(std::move(update), tree_id)); - semantics_manager_.semantic_tree()->RunUntilCommitCountIs(3); - CheckCallsToFakeSemanticTree(/*num_deletes=*/1, /*num_updates=*/3, - /*num_commits=*/3); + semantics_manager_.semantic_tree()->RunUntilCommitCountIs(4); + CheckCallsToFakeSemanticTree(/*num_deletes=*/2, /*num_updates=*/5, + /*num_commits=*/4); EXPECT_EQ(semantics_manager_.semantic_tree()->tree_size(), tree_size); } @@ -493,11 +519,11 @@ update.nodes[2].id = 5; bridge->AccessibilityEventReceived( - CreateAccessibilityEventWithUpdate(std::move(update))); + CreateAccessibilityEventWithUpdate(std::move(update), tree_id)); - semantics_manager_.semantic_tree()->RunUntilCommitCountIs(4); - CheckCallsToFakeSemanticTree(/*num_deletes=*/1, /*num_updates=*/4, - /*num_commits=*/4); + semantics_manager_.semantic_tree()->RunUntilCommitCountIs(5); + CheckCallsToFakeSemanticTree(/*num_deletes=*/2, /*num_updates=*/6, + /*num_commits=*/5); EXPECT_EQ(semantics_manager_.semantic_tree()->tree_size(), tree_size); } @@ -521,11 +547,11 @@ update.nodes[4].id = 5; bridge->AccessibilityEventReceived( - CreateAccessibilityEventWithUpdate(std::move(update))); + CreateAccessibilityEventWithUpdate(std::move(update), tree_id)); - semantics_manager_.semantic_tree()->RunUntilCommitCountIs(5); - CheckCallsToFakeSemanticTree(/*num_deletes=*/1, /*num_updates=*/5, - /*num_commits=*/5); + semantics_manager_.semantic_tree()->RunUntilCommitCountIs(6); + CheckCallsToFakeSemanticTree(/*num_deletes=*/2, /*num_updates=*/7, + /*num_commits=*/6); EXPECT_EQ(semantics_manager_.semantic_tree()->tree_size(), tree_size); } @@ -542,11 +568,11 @@ update.nodes[1].id = 2; bridge->AccessibilityEventReceived( - CreateAccessibilityEventWithUpdate(std::move(update))); + CreateAccessibilityEventWithUpdate(std::move(update), tree_id)); - semantics_manager_.semantic_tree()->RunUntilCommitCountIs(6); - CheckCallsToFakeSemanticTree(/*num_deletes=*/2, /*num_updates=*/6, - /*num_commits=*/6); + semantics_manager_.semantic_tree()->RunUntilCommitCountIs(7); + CheckCallsToFakeSemanticTree(/*num_deletes=*/3, /*num_updates=*/8, + /*num_commits=*/7); EXPECT_EQ(semantics_manager_.semantic_tree()->tree_size(), 2u); } @@ -563,11 +589,11 @@ update.nodes[1].id = 2; bridge->AccessibilityEventReceived( - CreateAccessibilityEventWithUpdate(std::move(update))); + CreateAccessibilityEventWithUpdate(std::move(update), tree_id)); - semantics_manager_.semantic_tree()->RunUntilCommitCountIs(7); - CheckCallsToFakeSemanticTree(/*num_deletes=*/3, /*num_updates=*/7, - /*num_commits=*/7); + semantics_manager_.semantic_tree()->RunUntilCommitCountIs(8); + CheckCallsToFakeSemanticTree(/*num_deletes=*/4, /*num_updates=*/9, + /*num_commits=*/8); EXPECT_EQ(semantics_manager_.semantic_tree()->tree_size(), 2u); } @@ -581,11 +607,61 @@ update.nodes[0].id = 1; bridge->AccessibilityEventReceived( - CreateAccessibilityEventWithUpdate(std::move(update))); + CreateAccessibilityEventWithUpdate(std::move(update), tree_id)); - semantics_manager_.semantic_tree()->RunUntilCommitCountIs(8); - CheckCallsToFakeSemanticTree(/*num_deletes=*/4, /*num_updates=*/8, - /*num_commits=*/8); + semantics_manager_.semantic_tree()->RunUntilCommitCountIs(9); + CheckCallsToFakeSemanticTree(/*num_deletes=*/5, /*num_updates=*/10, + /*num_commits=*/9); EXPECT_EQ(semantics_manager_.semantic_tree()->tree_size(), 1u); } } + +IN_PROC_BROWSER_TEST_F(AccessibilityBridgeTest, OutOfProcessIframe) { + constexpr int64_t kBindingsId = 1234; + + // Start a different embedded test server, and load a page on it. The URL for + // this page will have a different port and be considered out of process when + // used as the src for an iframe. + net::EmbeddedTestServer second_test_server; + second_test_server.ServeFilesFromSourceDirectory( + base::FilePath(cr_fuchsia::kTestServerRoot)); + ASSERT_TRUE(second_test_server.Start()); + GURL out_of_process_url = second_test_server.GetURL(kPage1Path); + + // Before loading a page on the default embedded test server, set the iframe + // src to be |out_of_process_url|. + frame_ptr_->AddBeforeLoadJavaScript( + kBindingsId, {"*"}, + cr_fuchsia::MemBufferFromString( + base::StringPrintf("iframeSrc = '%s'", + out_of_process_url.spec().c_str()), + "test"), + [](fuchsia::web::Frame_AddBeforeLoadJavaScript_Result result) { + CHECK(result.is_response()); + }); + LoadPage(kPageIframePath, "iframe loaded"); + + semantics_manager_.semantic_tree()->RunUntilCommitCountIs(1); + + // Run message loop for 200ms to ensure that all AX updates from the iframes + // are processed. + base::RunLoop run_loop; + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, run_loop.QuitClosure(), + base::TimeDelta::FromMilliseconds(200)); + run_loop.Run(); + + // Two frames should be present. + int num_frames = frame_impl_->web_contents_for_test()->GetAllFrames().size(); + EXPECT_EQ(num_frames, 2); + + // Check that the iframe node has been loaded. + EXPECT_TRUE( + semantics_manager_.semantic_tree()->GetNodeFromLabel(kPageIframeTitle)); + + // TODO(https://crbug.com/1128954): Add support for combining AXTrees. + // Expect that the contents of the iframe are not available in the semantic + // tree. + EXPECT_FALSE( + semantics_manager_.semantic_tree()->GetNodeFromLabel(kButtonName1)); +}
diff --git a/fuchsia/engine/test/data/iframe.html b/fuchsia/engine/test/data/iframe.html new file mode 100644 index 0000000..36ce8e3 --- /dev/null +++ b/fuchsia/engine/test/data/iframe.html
@@ -0,0 +1,15 @@ +<html> + <head> + <title>this page has an iframe</title> + </head> + <body> + <iframe id="iframeId" name="iframeName" title="iframe title"></iframe> + <script> + var iframe = document.getElementById("iframeId"); + iframe.src = iframeSrc; + iframe.onload = () => { + document.title = "iframe loaded"; + } + </script> + </body> +</html>
diff --git a/fuchsia/runners/cast/cast_runner.cc b/fuchsia/runners/cast/cast_runner.cc index 5487b99..502aec30 100644 --- a/fuchsia/runners/cast/cast_runner.cc +++ b/fuchsia/runners/cast/cast_runner.cc
@@ -13,12 +13,15 @@ #include "base/bind.h" #include "base/files/file_path.h" +#include "base/files/file_util.h" #include "base/fuchsia/file_utils.h" #include "base/fuchsia/filtered_service_directory.h" #include "base/fuchsia/fuchsia_logging.h" #include "base/fuchsia/process_context.h" #include "base/logging.h" +#include "base/values.h" #include "fuchsia/base/agent_manager.h" +#include "fuchsia/base/config_reader.h" #include "fuchsia/runners/cast/cast_streaming.h" #include "fuchsia/runners/cast/pending_cast_component.h" #include "fuchsia/runners/common/web_content_runner.h" @@ -68,9 +71,64 @@ return false; } +// Names used to partition the Runner's persistent storage for different uses. +constexpr char kCdmDataSubdirectoryName[] = "cdm_data"; +constexpr char kProfileSubdirectoryName[] = "web_profile"; + // Ephemeral remote debugging port used by child contexts. const uint16_t kEphemeralRemoteDebuggingPort = 0; +// Application URL for the pseudo-component providing fuchsia.web.FrameHost. +constexpr char kFrameHostComponentName[] = "cast:fuchsia.web.FrameHost"; + +// Populates |params| with web data settings. Web data persistence is only +// enabled if a soft quota is explicitly specified via config-data. +void SetDataParamsForMainContext(fuchsia::web::CreateContextParams* params) { + // Set web and CDM data quotas based on the CastRunner configuration. + const base::Optional<base::Value>& config = cr_fuchsia::LoadPackageConfig(); + constexpr char kDataQuotaBytesSwitch[] = "data-quota-bytes"; + const base::Optional<int> data_quota_bytes = + config && config->FindIntPath(kDataQuotaBytesSwitch); + if (!data_quota_bytes) + return; + + // Allow best-effort persistent of Cast application data. + // TODO(crbug.com/1148334): Remove the need for an explicit quota to be + // configured, once the platform provides storage quotas. + const auto profile_path = + base::FilePath(base::fuchsia::kPersistedCacheDirectoryPath) + .Append(kProfileSubdirectoryName); + CHECK(base::CreateDirectory(profile_path)); + params->set_data_directory(base::fuchsia::OpenDirectory(profile_path)); + CHECK(params->data_directory()); + params->set_data_quota_bytes(*data_quota_bytes); +} + +// Populates |params| with settings to enable Widevine & PlayReady CDMs. +// CDM data persistence is always enabled, with an optional soft quota. +void SetCdmParamsForMainContext(fuchsia::web::CreateContextParams* params) { + const base::Optional<base::Value>& config = cr_fuchsia::LoadPackageConfig(); + constexpr char kCdmDataQuotaBytesSwitch[] = "cdm-data-quota-bytes"; + const base::Optional<int> cdm_data_quota_bytes = + config && config->FindIntPath(kCdmDataQuotaBytesSwitch); + if (cdm_data_quota_bytes) + params->set_cdm_data_quota_bytes(*cdm_data_quota_bytes); + + // TODO(b/154204041): Consider using isolated-persistent-storage for CDM data. + // Create an isolated-cache-storage sub-directory for CDM data. + const auto cdm_data_path = base::FilePath(base::kPersistedCacheDirectoryPath) + .Append(kCdmDataSubdirectoryName); + CHECK(base::CreateDirectory(cdm_data_path)); + params->set_cdm_data_directory(base::OpenDirectoryHandle(cdm_data_path)); + CHECK(params->cdm_data_directory()); + + // Enable the Widevine and Playready CDMs. + *params->mutable_features() |= + fuchsia::web::ContextFeatureFlags::WIDEVINE_CDM; + const char kCastPlayreadyKeySystem[] = "com.chromecast.playready"; + params->set_playready_key_system(kCastPlayreadyKeySystem); +} + // TODO(crbug.com/1120914): Remove this once Component Framework v2 can be // used to route fuchsia.web.FrameHost capabilities cleanly. class FrameHostComponent : public fuchsia::sys::ComponentController { @@ -112,9 +170,6 @@ fidl::Binding<fuchsia::sys::ComponentController> binding_{this}; }; -// Application URL for the pseudo-component providing fuchsia.web.FrameHost. -constexpr char kFrameHostComponentName[] = "cast:fuchsia.web.FrameHost"; - } // namespace CastRunner::CastRunner(bool is_headless) @@ -274,8 +329,7 @@ fuchsia::web::CreateContextParams CastRunner::GetCommonContextParams() { fuchsia::web::CreateContextParams params; - params.set_features(fuchsia::web::ContextFeatureFlags::AUDIO | - fuchsia::web::ContextFeatureFlags::WIDEVINE_CDM); + params.set_features(fuchsia::web::ContextFeatureFlags::AUDIO); if (is_headless_) { LOG(WARNING) << "Running in headless mode."; @@ -288,27 +342,16 @@ fuchsia::web::ContextFeatureFlags::VULKAN; } - // TODO(b/154204041) Migrate to using persistent data, and specifying an - // explicit quota for CDM storage. - params.set_cdm_data_directory(base::OpenDirectoryHandle( - base::FilePath(base::kPersistedCacheDirectoryPath))); - CHECK(params.cdm_data_directory()); - - const char kCastPlayreadyKeySystem[] = "com.chromecast.playready"; - params.set_playready_key_system(kCastPlayreadyKeySystem); - - // See http://b/141956135. + // TODO(b/141956135): Fetch this information from the agent. params.set_user_agent_product("CrKey"); params.set_user_agent_version("1.52.000000"); // When tests require that VULKAN be disabled, DRM must also be disabled. if (disable_vulkan_for_test_) { *params.mutable_features() &= - ~(fuchsia::web::ContextFeatureFlags::WIDEVINE_CDM | - fuchsia::web::ContextFeatureFlags::VULKAN | + ~(fuchsia::web::ContextFeatureFlags::VULKAN | fuchsia::web::ContextFeatureFlags::HARDWARE_VIDEO_DECODER | fuchsia::web::ContextFeatureFlags::HARDWARE_VIDEO_DECODER_ONLY); - params.clear_playready_key_system(); } // If there is a list of headers to exempt from CORS checks, pass the list @@ -329,6 +372,11 @@ main_services_->ConnectClient( params.mutable_service_directory()->NewRequest()); + if (!disable_vulkan_for_test_) + SetCdmParamsForMainContext(¶ms); + + SetDataParamsForMainContext(¶ms); + // TODO(crbug.com/1023514): Remove this switch when it is no longer // necessary. params.set_unsafely_treat_insecure_origins_as_secure(
diff --git a/gpu/ipc/service/pass_through_image_transport_surface.cc b/gpu/ipc/service/pass_through_image_transport_surface.cc index 9f9ac2a..8db6374 100644 --- a/gpu/ipc/service/pass_through_image_transport_surface.cc +++ b/gpu/ipc/service/pass_through_image_transport_surface.cc
@@ -10,6 +10,7 @@ #include "base/callback_helpers.h" #include "base/command_line.h" #include "base/metrics/histogram_macros.h" +#include "base/metrics/histogram_macros_local.h" #include "build/build_config.h" #include "gpu/command_buffer/common/swap_buffers_complete_params.h" #include "ui/gfx/vsync_provider.h" @@ -255,7 +256,7 @@ // Report only if collection is enabled and supported on current platform // See gpu::Scheduler::TakeTotalBlockingTime for details. if (!blocked_time_since_last_swap.is_min()) { - UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES( + LOCAL_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES( "GPU.GpuBlockedBetweenSwapsUs2", blocked_time_since_last_swap, kTimingMetricsHistogramMin, kTimingMetricsHistogramMax, kTimingMetricsHistogramBuckets);
diff --git a/infra/config/subprojects/chromium/try.star b/infra/config/subprojects/chromium/try.star index 4438f8ad..458a0d1 100644 --- a/infra/config/subprojects/chromium/try.star +++ b/infra/config/subprojects/chromium/try.star
@@ -130,7 +130,7 @@ try_.list_view( name = "tryserver.chromium.linux", - branch_selector = branches.STANDARD_MILESTONE, + branch_selector = branches.ALL_BRANCHES, ) try_.list_view( @@ -820,7 +820,7 @@ try_.chromium_linux_builder( name = "chromium_presubmit", - branch_selector = branches.STANDARD_MILESTONE, + branch_selector = branches.ALL_BRANCHES, executable = "recipe:presubmit", goma_backend = None, main_list_view = "try",
diff --git a/ios/chrome/browser/ios_chrome_main_parts.mm b/ios/chrome/browser/ios_chrome_main_parts.mm index 3f49809..82f5393d 100644 --- a/ios/chrome/browser/ios_chrome_main_parts.mm +++ b/ios/chrome/browser/ios_chrome_main_parts.mm
@@ -82,9 +82,12 @@ // Do not install allocator shim on iOS 13.4 due to high crash volume on this // particular version of OS. TODO(crbug.com/1108219): Remove this workaround // when/if the bug gets fixed. +// +// Do not install allocator shim for now, until it's clear why Chrome crashes +// on iOS 14.3+ on startup. +// TODO(crbug.com/1150599): Remove this workaround when/if the bug gets fixed. bool ShouldInstallAllocatorShim() { - return !base::ios::IsRunningOnOrLater(13, 4, 0) || - base::ios::IsRunningOnOrLater(13, 5, 0); + return false; } #endif
diff --git a/media/capture/video/mac/sample_buffer_transformer_mac.cc b/media/capture/video/mac/sample_buffer_transformer_mac.cc index 5e40a90..1a9e5aa 100644 --- a/media/capture/video/mac/sample_buffer_transformer_mac.cc +++ b/media/capture/video/mac/sample_buffer_transformer_mac.cc
@@ -16,7 +16,7 @@ namespace media { const base::Feature kInCaptureConvertToNv12{"InCaptureConvertToNv12", - base::FEATURE_DISABLED_BY_DEFAULT}; + base::FEATURE_ENABLED_BY_DEFAULT}; const base::Feature kInCaptureConvertToNv12WithPixelTransfer{ "InCaptureConvertToNv12WithPixelTransfer", @@ -27,7 +27,7 @@ namespace { -constexpr size_t kDefaultBufferPoolSize = 10; +constexpr size_t kDefaultBufferPoolSize = 5; // NV12 a.k.a. 420v constexpr OSType kPixelFormatNv12 =
diff --git a/media/capture/video/mac/sample_buffer_transformer_mac_unittest.mm b/media/capture/video/mac/sample_buffer_transformer_mac_unittest.mm index 96e9549..0712fca 100644 --- a/media/capture/video/mac/sample_buffer_transformer_mac_unittest.mm +++ b/media/capture/video/mac/sample_buffer_transformer_mac_unittest.mm
@@ -408,8 +408,8 @@ TestParametersOSTypeToString); TEST(SampleBufferTransformerAutoReconfigureTest, - AutoReconfigureIsDisabledByDefault) { - EXPECT_FALSE(SampleBufferTransformer::CreateIfAutoReconfigureEnabled()); + AutoReconfigureIsEnabledByDefault) { + EXPECT_TRUE(SampleBufferTransformer::CreateIfAutoReconfigureEnabled()); } TEST(SampleBufferTransformerAutoReconfigureTest,
diff --git a/media/gpu/android/codec_wrapper.cc b/media/gpu/android/codec_wrapper.cc index a89cc16..128ebad 100644 --- a/media/gpu/android/codec_wrapper.cc +++ b/media/gpu/android/codec_wrapper.cc
@@ -125,7 +125,10 @@ bool CodecOutputBuffer::ReleaseToSurface() { was_rendered_ = true; - return codec_->ReleaseCodecOutputBuffer(id_, true); + auto result = codec_->ReleaseCodecOutputBuffer(id_, true); + if (render_cb_) + std::move(render_cb_).Run(); + return result; } CodecWrapperImpl::CodecWrapperImpl(
diff --git a/media/gpu/android/codec_wrapper.h b/media/gpu/android/codec_wrapper.h index 0716f13d..c4993198 100644 --- a/media/gpu/android/codec_wrapper.h +++ b/media/gpu/android/codec_wrapper.h
@@ -44,6 +44,12 @@ // The size of the image. gfx::Size size() const { return size_; } + // Sets a callback that will be called when we're released to the surface. + // Will not be called if we're dropped. + void set_render_cb(base::OnceClosure render_cb) { + render_cb_ = std::move(render_cb); + } + // Note that you can't use the first ctor, since CodecWrapperImpl isn't // defined here. Use the second, and it'll be nullptr. template <typename... Args> @@ -67,6 +73,7 @@ int64_t id_; bool was_rendered_ = false; gfx::Size size_; + base::OnceClosure render_cb_; DISALLOW_COPY_AND_ASSIGN(CodecOutputBuffer); };
diff --git a/media/gpu/android/codec_wrapper_unittest.cc b/media/gpu/android/codec_wrapper_unittest.cc index 66c48ad7f..5791937 100644 --- a/media/gpu/android/codec_wrapper_unittest.cc +++ b/media/gpu/android/codec_wrapper_unittest.cc
@@ -355,4 +355,22 @@ base::RunLoop().RunUntilIdle(); } +TEST_F(CodecWrapperTest, RenderCallbackCalledIfRendered) { + auto codec_buffer = DequeueCodecOutputBuffer(); + bool flag = false; + codec_buffer->set_render_cb(base::BindOnce([](bool* flag) { *flag = true; }, + base::Unretained(&flag))); + codec_buffer->ReleaseToSurface(); + EXPECT_TRUE(flag); +} + +TEST_F(CodecWrapperTest, RenderCallbackIsNotCalledIfNotRendered) { + auto codec_buffer = DequeueCodecOutputBuffer(); + bool flag = false; + codec_buffer->set_render_cb(base::BindOnce([](bool* flag) { *flag = true; }, + base::Unretained(&flag))); + codec_buffer.reset(); + EXPECT_FALSE(flag); +} + } // namespace media
diff --git a/media/gpu/android/media_codec_video_decoder.cc b/media/gpu/android/media_codec_video_decoder.cc index 686357a8..6176b7e9 100644 --- a/media/gpu/android/media_codec_video_decoder.cc +++ b/media/gpu/android/media_codec_video_decoder.cc
@@ -966,6 +966,16 @@ std::unique_ptr<ScopedAsyncTrace> async_trace = ScopedAsyncTrace::CreateIfEnabled( "MediaCodecVideoDecoder::CreateVideoFrame"); + // Make sure that we're notified when this is rendered. Otherwise, if we're + // waiting for all output buffers to drain so that we can swap the output + // surface, we might not realize that we may continue. If we're using + // SurfaceControl overlays, then this isn't needed; there is never a surface + // transition anyway. + if (!is_surface_control_enabled_) { + output_buffer->set_render_cb(BindToCurrentLoop( + base::BindOnce(&MediaCodecVideoDecoder::StartTimerOrPumpCodec, + weak_factory_.GetWeakPtr()))); + } video_frame_factory_->CreateVideoFrame( std::move(output_buffer), presentation_time, GetNaturalSize(visible_rect, decoder_config_.GetPixelAspectRatio()),
diff --git a/net/cookies/canonical_cookie.cc b/net/cookies/canonical_cookie.cc index 8e5c7f3..5a19499 100644 --- a/net/cookies/canonical_cookie.cc +++ b/net/cookies/canonical_cookie.cc
@@ -257,6 +257,11 @@ } // namespace +CookieAccessParams::CookieAccessParams(CookieAccessSemantics access_semantics, + bool delegate_treats_url_as_trustworthy) + : access_semantics(access_semantics), + delegate_treats_url_as_trustworthy(delegate_treats_url_as_trustworthy) {} + CanonicalCookie::CanonicalCookie() = default; CanonicalCookie::CanonicalCookie(const CanonicalCookie& other) = default;
diff --git a/net/cookies/canonical_cookie.h b/net/cookies/canonical_cookie.h index 294e2b2..fcf34e77 100644 --- a/net/cookies/canonical_cookie.h +++ b/net/cookies/canonical_cookie.h
@@ -35,7 +35,11 @@ std::vector<CookieAndLineWithAccessResult>; using CookieAccessResultList = std::vector<CookieWithAccessResult>; -struct CookieAccessParams { +struct NET_EXPORT CookieAccessParams { + CookieAccessParams() = delete; + CookieAccessParams(CookieAccessSemantics access_semantics, + bool delegate_treats_url_as_trustworthy); + // |access_semantics| is the access mode of the cookie access check. CookieAccessSemantics access_semantics = CookieAccessSemantics::UNKNOWN; // |delegate_treats_url_as_trustworthy| should be true iff the
diff --git a/net/cookies/cookie_inclusion_status.cc b/net/cookies/cookie_inclusion_status.cc index cd213856..fb5f3a5 100644 --- a/net/cookies/cookie_inclusion_status.cc +++ b/net/cookies/cookie_inclusion_status.cc
@@ -254,8 +254,6 @@ base::StrAppend(&out, {"WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE, "}); if (HasWarningReason(WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE)) base::StrAppend(&out, {"WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE, "}); - if (HasWarningReason(WARN_SAMESITE_COMPAT_PAIR)) - base::StrAppend(&out, {"WARN_SAMESITE_COMPAT_PAIR, "}); if (HasWarningReason(WARN_SECURE_ACCESS_GRANTED_NON_CRYPTOGRAPHIC)) base::StrAppend(&out, {"WARN_SECURE_ACCESS_GRANTED_NON_CRYPTOGRAPHIC, "});
diff --git a/net/cookies/cookie_inclusion_status.h b/net/cookies/cookie_inclusion_status.h index 604b92e..59f64971 100644 --- a/net/cookies/cookie_inclusion_status.h +++ b/net/cookies/cookie_inclusion_status.h
@@ -142,30 +142,12 @@ // Lax to Cross-site downgrade for an effective SameSite=Lax cookie. WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE = 7, - // This is applied to a cookie that may be part of a "double cookie" pair - // used for compatibility reasons. These pairs consist of one cookie that - // has "SameSite=None; Secure" and a duplicate cookie that leaves SameSite - // unspecified to maintain compatibility with browsers that do not support - // the "SameSite=None" attribute. This warning is applied to both - // members of the pair. See cookie_util::IsSameSiteCompatPair(). - // - // If computing this for a cookie access attempt from a non-network context - // (i.e. script), this should not be applied if either member of the pair is - // HttpOnly, to avoid leaking information about the name and value of - // HttpOnly cookies to an untrusted renderer. - // - // This is only relevant if WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT is - // present on the same status or a status for a cookie accessed at the same - // time, so it may not be applied at other times (e.g. when the context is - // same-site). - WARN_SAMESITE_COMPAT_PAIR = 8, - // Advisory warning attached when a Secure cookie is accessed from (sent to, // or set by) a non-cryptographic URL. This can happen if the URL is // potentially trustworthy (e.g. a localhost URL, or another URL that // the CookieAccessDelegate is configured to allow). // TODO(chlily): Add metrics for how often and where this occurs. - WARN_SECURE_ACCESS_GRANTED_NON_CRYPTOGRAPHIC = 9, + WARN_SECURE_ACCESS_GRANTED_NON_CRYPTOGRAPHIC = 8, // This should be kept last. NUM_WARNING_REASONS
diff --git a/net/cookies/cookie_util.cc b/net/cookies/cookie_util.cc index 69f25ce8..dd19f28 100644 --- a/net/cookies/cookie_util.cc +++ b/net/cookies/cookie_util.cc
@@ -581,48 +581,6 @@ return CookieOptions::SameSiteCookieContext::MakeInclusive(); } -bool IsSameSiteCompatPair(const CanonicalCookie& c1, - const CanonicalCookie& c2, - const CookieOptions& options) { - if (options.exclude_httponly() && (c1.IsHttpOnly() || c2.IsHttpOnly())) - return false; - - if (c1.IsEquivalent(c2)) - return false; - - // One of them is SameSite=None and Secure; the other one has unspecified - // SameSite. - bool same_site_attributes_ok = - c1.SameSite() == CookieSameSite::NO_RESTRICTION && c1.IsSecure() && - c2.SameSite() == CookieSameSite::UNSPECIFIED; - same_site_attributes_ok = - same_site_attributes_ok || - (c2.SameSite() == CookieSameSite::NO_RESTRICTION && c2.IsSecure() && - c1.SameSite() == CookieSameSite::UNSPECIFIED); - if (!same_site_attributes_ok) - return false; - - if (c1.Domain() != c2.Domain() || c1.Path() != c2.Path() || - c1.Value() != c2.Value()) { - return false; - } - - DCHECK(c1.Name() != c2.Name()); - std::string shorter, longer; - std::tie(shorter, longer) = (c1.Name().length() < c2.Name().length()) - ? std::tie(c1.Name(), c2.Name()) - : std::tie(c2.Name(), c1.Name()); - // One of them has a name that is a prefix or suffix of the other and has - // length at least 3 characters. - if (shorter.length() < kMinCompatPairNameLength) - return false; - if (base::StartsWith(longer, shorter, base::CompareCase::SENSITIVE) || - base::EndsWith(longer, shorter, base::CompareCase::SENSITIVE)) { - return true; - } - return false; -} - bool IsSameSiteByDefaultCookiesEnabled() { return base::FeatureList::IsEnabled(features::kSameSiteByDefaultCookies); }
diff --git a/net/cookies/cookie_util.h b/net/cookies/cookie_util.h index f719304..ebcf07ad 100644 --- a/net/cookies/cookie_util.h +++ b/net/cookies/cookie_util.h
@@ -28,10 +28,6 @@ const int kVlogSetCookies = 7; const int kVlogGarbageCollection = 5; -// Minimum name length for SameSite compatibility pair heuristic (see -// IsSameSiteCompatPair() below.) -const int kMinCompatPairNameLength = 3; - // This enum must match the numbering for StorageAccessResult in // histograms/enums.xml. Do not reorder or remove items, only add new items // at the end. @@ -214,26 +210,6 @@ const SiteForCookies& site_for_cookies, bool force_ignore_site_for_cookies); -// Evaluates a heuristic to determine whether |c1| and |c2| are likely to be a -// "double cookie" pair used for SameSite=None compatibility reasons. -// -// This returns true if all of the following are true: -// 1. The cookies are not equivalent (i.e. same name, domain, and path). -// 2. One of them is SameSite=None and Secure; the other one has unspecified -// SameSite. -// 3. Their domains are equal. -// 4. Their paths are equal. -// 5. Their values are equal. -// 6. One of them has a name that is a prefix or suffix of the other and has -// length at least 3 characters. -// -// |options| is the CookieOptions object used to access (get/set) the cookies. -// If the CookieOptions indicate that HttpOnly cookies are not allowed, this -// will return false if either of |c1| or |c2| is HttpOnly. -NET_EXPORT bool IsSameSiteCompatPair(const CanonicalCookie& c1, - const CanonicalCookie& c2, - const CookieOptions& options); - // Returns whether the respective SameSite feature is enabled. NET_EXPORT bool IsSameSiteByDefaultCookiesEnabled(); NET_EXPORT bool IsCookiesWithoutSameSiteMustBeSecureEnabled();
diff --git a/net/cookies/cookie_util_unittest.cc b/net/cookies/cookie_util_unittest.cc index a4a3f625..4271b0c 100644 --- a/net/cookies/cookie_util_unittest.cc +++ b/net/cookies/cookie_util_unittest.cc
@@ -1267,139 +1267,6 @@ EXPECT_TRUE(result_out); } -TEST(CookieUtilTest, IsSameSiteCompatPair) { - ASSERT_EQ(3, cookie_util::kMinCompatPairNameLength) - << "This test assumes that SameSite compatibility pairs have cookie name " - "length at least 3."; - GURL url("https://www.site.example/path"); - - struct { - const char* cookie_line_1; - const char* cookie_line_2; - bool expected_is_same_site_compat_pair; - } kTestCases[] = { - // Matching cases - {"name=value; SameSite=None; Secure", "name_legacy=value", true}, - {"uid=value; SameSite=None; Secure", "uid_old=value", true}, - {"name=value; SameSite=None; Secure", "name2=value; Secure", true}, - {"name_samesite=value; SameSite=None; Secure", "name=value", true}, - {"__Secure-name=value; SameSite=None; Secure", "name=value", true}, - {"__Secure-3Pname=value; SameSite=None; Secure", "name=value", true}, - {"name=value; SameSite=None; Secure; HttpOnly", "name_legacy=value", - true}, - {"name=value; SameSite=None; Secure; Domain=site.example", - "name_legacy=value; Secure; Domain=site.example", true}, - // Fails because cookies are equivalent - {"name=value; SameSite=None; Secure", "name=value", false}, - // Fails SameSite criterion - {"name=value", "name_legacy=value", false}, - {"name=value; SameSite=None", "name_legacy=value", false}, - {"name=value; SameSite=None; Secure", "name_legacy=value; SameSite=None", - false}, - {"name=value; SameSite=None; Secure", - "name_legacy=value; SameSite=None; Secure", false}, - // Fails Domain criterion - {"name=value; SameSite=None; Secure; Domain=site.example", - "name_legacy=value", false}, - {"name=value; SameSite=None; Secure; Domain=www.site.example", - "name_legacy=value", false}, - {"name=value; SameSite=None; Secure", - "name_legacy=value; Domain=site.example", false}, - {"name=value; SameSite=None; Secure", - "name_legacy=value; Domain=www.site.example", false}, - // Fails Path criterion - {"name=value; SameSite=None; Secure; Path=/path", "name_legacy=value", - false}, - {"name=value; SameSite=None; Secure; Path=/path", - "name_legacy=value; Path=/", false}, - {"name=value; SameSite=None; Secure; Path=/", - "name_legacy=value; Path=/path", false}, - {"name=value; SameSite=None; Secure", "name_legacy=value; Path=/path", - false}, - // Fails value criterion - {"name=value; SameSite=None; Secure", "name_legacy=foobar", false}, - {"name=value; SameSite=None; Secure", "name_legacy=value2", false}, - // Fails name length criterion - {"id=value; SameSite=None; Secure", "id_legacy=value", false}, - {"id_samesite=value; SameSite=None; Secure", "id=value", false}, - {"value; SameSite=None; Secure", "legacy=value", false}, - // Fails suffix/prefix criterion - {"name_samesite=value; SameSite=None; Secure", "name_legacy=value", - false}, - {"name1=value; SameSite=None; Secure", "name2=value", false}, - }; - - for (const auto& test_case : kTestCases) { - auto cookie1 = CanonicalCookie::Create(url, test_case.cookie_line_1, - base::Time::Now(), base::nullopt); - auto cookie2 = CanonicalCookie::Create(url, test_case.cookie_line_2, - base::Time::Now(), base::nullopt); - - ASSERT_TRUE(cookie1); - ASSERT_TRUE(cookie2); - EXPECT_EQ(test_case.expected_is_same_site_compat_pair, - cookie_util::IsSameSiteCompatPair( - *cookie1, *cookie2, CookieOptions::MakeAllInclusive())); - EXPECT_EQ(test_case.expected_is_same_site_compat_pair, - cookie_util::IsSameSiteCompatPair( - *cookie2, *cookie1, CookieOptions::MakeAllInclusive())); - } -} - -TEST(CookieUtilTest, IsSameSiteCompatPair_HttpOnly) { - GURL url("https://www.site.example/path"); - auto new_cookie = - CanonicalCookie::Create(url, "name=value; SameSite=None; Secure", - base::Time::Now(), base::nullopt); - auto legacy_cookie = CanonicalCookie::Create( - url, "name_legacy=value", base::Time::Now(), base::nullopt); - auto http_only_new_cookie = CanonicalCookie::Create( - url, "name=value; SameSite=None; Secure; HttpOnly", base::Time::Now(), - base::nullopt); - auto http_only_legacy_cookie = CanonicalCookie::Create( - url, "name_legacy=value; HttpOnly", base::Time::Now(), base::nullopt); - ASSERT_TRUE(new_cookie); - ASSERT_TRUE(legacy_cookie); - ASSERT_TRUE(http_only_new_cookie); - ASSERT_TRUE(http_only_legacy_cookie); - - // Allows HttpOnly access. - CookieOptions inclusive_options = CookieOptions::MakeAllInclusive(); - // Disallows HttpOnly access. - CookieOptions restrictive_options; - // Allows SameSite but not HttpOnly access. (SameSite shouldn't matter.) - CookieOptions same_site_options; - same_site_options.set_same_site_cookie_context( - CookieOptions::SameSiteCookieContext::MakeInclusive()); - - EXPECT_TRUE(cookie_util::IsSameSiteCompatPair(*new_cookie, *legacy_cookie, - inclusive_options)); - EXPECT_TRUE(cookie_util::IsSameSiteCompatPair( - *http_only_new_cookie, *legacy_cookie, inclusive_options)); - EXPECT_TRUE(cookie_util::IsSameSiteCompatPair( - *new_cookie, *http_only_legacy_cookie, inclusive_options)); - EXPECT_TRUE(cookie_util::IsSameSiteCompatPair( - *http_only_new_cookie, *http_only_legacy_cookie, inclusive_options)); - - EXPECT_TRUE(cookie_util::IsSameSiteCompatPair(*new_cookie, *legacy_cookie, - restrictive_options)); - EXPECT_FALSE(cookie_util::IsSameSiteCompatPair( - *http_only_new_cookie, *legacy_cookie, restrictive_options)); - EXPECT_FALSE(cookie_util::IsSameSiteCompatPair( - *new_cookie, *http_only_legacy_cookie, restrictive_options)); - EXPECT_FALSE(cookie_util::IsSameSiteCompatPair( - *http_only_new_cookie, *http_only_legacy_cookie, restrictive_options)); - - EXPECT_TRUE(cookie_util::IsSameSiteCompatPair(*new_cookie, *legacy_cookie, - same_site_options)); - EXPECT_FALSE(cookie_util::IsSameSiteCompatPair( - *http_only_new_cookie, *legacy_cookie, same_site_options)); - EXPECT_FALSE(cookie_util::IsSameSiteCompatPair( - *new_cookie, *http_only_legacy_cookie, same_site_options)); - EXPECT_FALSE(cookie_util::IsSameSiteCompatPair( - *http_only_new_cookie, *http_only_legacy_cookie, same_site_options)); -} - } // namespace } // namespace net
diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc index dd533f1..2c1daf73 100644 --- a/net/url_request/url_request_http_job.cc +++ b/net/url_request/url_request_http_job.cc
@@ -152,58 +152,6 @@ net::ct::CTPolicyCompliance::CT_POLICY_COUNT); } -template <typename CookieWithMetadata> -bool ShouldMarkSameSiteCompatPairs( - const std::vector<CookieWithMetadata>& cookie_list, - const net::CookieOptions& options) { - // If the context is same-site then there cannot be any SameSite-by-default - // warnings, so the compat pair warning is irrelevant. - if (options.same_site_cookie_context().GetContextForCookieInclusion() > - net::CookieOptions::SameSiteCookieContext::ContextType:: - SAME_SITE_LAX_METHOD_UNSAFE) { - return false; - } - return cookie_list.size() >= 2; -} - -void MarkSameSiteCompatPairs( - std::vector<net::CookieWithAccessResult>& cookie_list, - const net::CookieOptions& options) { - for (size_t i = 0; i < cookie_list.size() - 1; ++i) { - const net::CanonicalCookie& c1 = cookie_list[i].cookie; - for (size_t j = i + 1; j < cookie_list.size(); ++j) { - const net::CanonicalCookie& c2 = cookie_list[j].cookie; - if (net::cookie_util::IsSameSiteCompatPair(c1, c2, options)) { - cookie_list[i].access_result.status.AddWarningReason( - net::CookieInclusionStatus::WARN_SAMESITE_COMPAT_PAIR); - cookie_list[j].access_result.status.AddWarningReason( - net::CookieInclusionStatus::WARN_SAMESITE_COMPAT_PAIR); - } - } - } -} - -void MarkSameSiteCompatPairs( - std::vector<net::CookieAndLineWithAccessResult>& cookie_list, - const net::CookieOptions& options) { - for (size_t i = 0; i < cookie_list.size() - 1; ++i) { - if (!cookie_list[i].cookie.has_value()) - continue; - const net::CanonicalCookie& c1 = cookie_list[i].cookie.value(); - for (size_t j = i + 1; j < cookie_list.size(); ++j) { - if (!cookie_list[j].cookie.has_value()) - continue; - const net::CanonicalCookie& c2 = cookie_list[j].cookie.value(); - if (net::cookie_util::IsSameSiteCompatPair(c1, c2, options)) { - cookie_list[i].access_result.status.AddWarningReason( - net::CookieInclusionStatus::WARN_SAMESITE_COMPAT_PAIR); - cookie_list[j].access_result.status.AddWarningReason( - net::CookieInclusionStatus::WARN_SAMESITE_COMPAT_PAIR); - } - } - } -} - net::CookieOptions CreateCookieOptions( net::CookieOptions::SameSiteCookieContext cookie_context) { net::CookieOptions options; @@ -684,11 +632,6 @@ } } - // Mark the CookieInclusionStatuses of items in |maybe_sent_cookies| if they - // are part of a presumed SameSite compatibility pair. - if (ShouldMarkSameSiteCompatPairs(maybe_sent_cookies, options)) - MarkSameSiteCompatPairs(maybe_sent_cookies, options); - request_->set_maybe_sent_cookies(std::move(maybe_sent_cookies)); StartTransaction(); @@ -785,15 +728,8 @@ // loop has been exited. num_cookie_lines_left_--; - if (num_cookie_lines_left_ == 0) { - // Mark the CookieInclusionStatuses of items in - // |set_cookie_access_result_list_| if they are part of a presumed SameSite - // compatibility pair. - if (ShouldMarkSameSiteCompatPairs(set_cookie_access_result_list_, options)) - MarkSameSiteCompatPairs(set_cookie_access_result_list_, options); - + if (num_cookie_lines_left_ == 0) NotifyHeadersComplete(); - } } void URLRequestHttpJob::OnSetCookieResult( @@ -820,15 +756,8 @@ // If all the cookie lines have been handled, |set_cookie_access_result_list_| // now reflects the result of all Set-Cookie lines, and the request can be // continued. - if (num_cookie_lines_left_ == 0) { - // Mark the CookieInclusionStatuses of items in - // |set_cookie_access_result_list_| if they are part of a presumed SameSite - // compatibility pair. - if (ShouldMarkSameSiteCompatPairs(set_cookie_access_result_list_, options)) - MarkSameSiteCompatPairs(set_cookie_access_result_list_, options); - + if (num_cookie_lines_left_ == 0) NotifyHeadersComplete(); - } } void URLRequestHttpJob::ProcessStrictTransportSecurityHeader() {
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc index 87715a8e..77727d0 100644 --- a/net/url_request/url_request_unittest.cc +++ b/net/url_request/url_request_unittest.cc
@@ -7016,203 +7016,6 @@ } } -// Test that CookieInclusionStatus warnings for SameSite cookie compatibility -// pairs are applied correctly. -TEST_F(URLRequestTest, SameSiteCookieCompatPairWarnings) { - EmbeddedTestServer https_test_server(EmbeddedTestServer::TYPE_HTTPS); - RegisterDefaultHandlers(&https_test_server); - ASSERT_TRUE(https_test_server.Start()); - - GURL set_pair_url = https_test_server.GetURL( - "/set-cookie?name=value;SameSite=None;Secure&" - "name_legacy=value"); - GURL set_httponly_pair_url = https_test_server.GetURL( - "/set-cookie?name=value;SameSite=None;Secure;HttpOnly&" - "name_legacy=value;HttpOnly"); - GURL set_pair_and_other_url = https_test_server.GetURL( - "/set-cookie?name=value;SameSite=None;Secure&" - "name_legacy=value&" - "name2=value;SameSite=None;Secure"); - GURL set_two_pairs_url = https_test_server.GetURL( - "/set-cookie?name=value;SameSite=None;Secure&" - "name_legacy=value&" - "name2=value;SameSite=None;Secure&" - "compat-name2=value"); - GURL get_cookies_url = https_test_server.GetURL("/echoheader?Cookie"); - - struct TestCase { - // URL used to set cookies. - // Note: This test works because each URL uses a superset of the cookies - // used by URLs before it. - GURL set_cookies_url; - // Names of cookies and whether they are expected to be included for a - // cross-site get/set. (All are expected for a same-site request.) - std::map<std::string, bool> expected_cookies; - // Names of cookies expected to have a compat pair warning for a cross-site - // request. - std::set<std::string> expected_compat_warning_cookies; - // Whether all cookies should be HttpOnly. - bool expected_httponly = false; - } kTestCases[] = { - // Basic case with a single compat pair. - {set_pair_url, - {{"name", true}, {"name_legacy", false}}, - {"name", "name_legacy"}}, - // Compat pair with HttpOnly cookies (should not change behavior because - // this is an HTTP request). - {set_httponly_pair_url, - {{"name", true}, {"name_legacy", false}}, - {"name", "name_legacy"}, - true}, - // Pair should be marked, but extra cookie (not part of a pair) should - // not. - {set_pair_and_other_url, - {{"name", true}, {"name_legacy", false}, {"name2", true}}, - {"name", "name_legacy"}}, - // Two separate pairs should all be marked. - {set_two_pairs_url, - {{"name", true}, - {"name_legacy", false}, - {"name2", true}, - {"compat-name2", false}}, - {"name", "name_legacy", "name2", "compat-name2"}}}; - - // For each test case, this exercises: - // 1. Set cookies in a cross-site context to trigger compat pair warnings. - // 2. Set cookies in a same-site context and check that no compat pair - // warnings are applied (and also make sure the cookies are actually - // present for the subsequent tests). - // 3. Get cookies in a same-site context and check that no compat pair - // warnings are applied. - // 4. Get cookies in a cross-site context to trigger compat pair warnings. - for (const auto& test : kTestCases) { - { - // Set cookies in a cross-site context. - TestDelegate d; - std::unique_ptr<URLRequest> req(default_context().CreateRequest( - test.set_cookies_url, DEFAULT_PRIORITY, &d, - TRAFFIC_ANNOTATION_FOR_TESTS)); - req->Start(); - d.RunUntilComplete(); - - ASSERT_EQ(test.expected_cookies.size(), - req->maybe_stored_cookies().size()); - for (const auto& cookie : req->maybe_stored_cookies()) { - ASSERT_TRUE(cookie.cookie.has_value()); - EXPECT_EQ(cookie.cookie->IsHttpOnly(), test.expected_httponly); - - const std::string& cookie_name = cookie.cookie->Name(); - auto it = test.expected_cookies.find(cookie_name); - ASSERT_NE(test.expected_cookies.end(), it); - bool included = cookie.access_result.status.IsInclude(); - EXPECT_EQ(it->second, included); - - std::vector<CookieInclusionStatus::ExclusionReason> exclusions; - std::vector<CookieInclusionStatus::WarningReason> warnings; - if (!included) { - exclusions.push_back(CookieInclusionStatus:: - EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX); - warnings.push_back(CookieInclusionStatus:: - WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT); - } - if (base::Contains(test.expected_compat_warning_cookies, cookie_name)) { - warnings.push_back(CookieInclusionStatus::WARN_SAMESITE_COMPAT_PAIR); - } - EXPECT_TRUE( - cookie.access_result.status.HasExactlyExclusionReasonsForTesting( - exclusions)); - EXPECT_TRUE( - cookie.access_result.status.HasExactlyWarningReasonsForTesting( - warnings)); - } - } - { - // Set cookies in a same-site context. - TestDelegate d; - std::unique_ptr<URLRequest> req(default_context().CreateFirstPartyRequest( - test.set_cookies_url, DEFAULT_PRIORITY, &d, - TRAFFIC_ANNOTATION_FOR_TESTS)); - req->Start(); - d.RunUntilComplete(); - - ASSERT_EQ(test.expected_cookies.size(), - req->maybe_stored_cookies().size()); - for (const auto& cookie : req->maybe_stored_cookies()) { - ASSERT_TRUE(cookie.cookie.has_value()); - EXPECT_EQ(cookie.cookie->IsHttpOnly(), test.expected_httponly); - EXPECT_TRUE( - base::Contains(test.expected_cookies, cookie.cookie->Name())); - // Cookie was included and there are no warnings. - EXPECT_EQ(CookieInclusionStatus(), cookie.access_result.status); - } - } - { - // Get cookies in a same-site context. - TestDelegate d; - std::unique_ptr<URLRequest> req(default_context().CreateFirstPartyRequest( - get_cookies_url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS)); - req->Start(); - d.RunUntilComplete(); - - ASSERT_EQ(test.expected_cookies.size(), req->maybe_sent_cookies().size()); - for (const auto& cookie : req->maybe_sent_cookies()) { - EXPECT_EQ(cookie.cookie.IsHttpOnly(), test.expected_httponly); - EXPECT_TRUE( - base::Contains(test.expected_cookies, cookie.cookie.Name())); - EXPECT_THAT(d.data_received(), - ::testing::HasSubstr(cookie.cookie.Name() + "=value")); - // Cookie was included and there are no warnings. - EXPECT_EQ(CookieInclusionStatus(), cookie.access_result.status); - } - } - { - // Get cookies in a cross-site context. - TestDelegate d; - std::unique_ptr<URLRequest> req(default_context().CreateRequest( - get_cookies_url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS)); - req->Start(); - d.RunUntilComplete(); - - ASSERT_EQ(test.expected_cookies.size(), req->maybe_sent_cookies().size()); - for (const auto& cookie : req->maybe_sent_cookies()) { - EXPECT_EQ(cookie.cookie.IsHttpOnly(), test.expected_httponly); - - const std::string& cookie_name = cookie.cookie.Name(); - auto it = test.expected_cookies.find(cookie_name); - ASSERT_NE(test.expected_cookies.end(), it); - bool included = cookie.access_result.status.IsInclude(); - EXPECT_EQ(it->second, included); - - if (included) { - EXPECT_THAT(d.data_received(), - ::testing::HasSubstr(cookie.cookie.Name() + "=value")); - } else { - EXPECT_THAT(d.data_received(), ::testing::Not(::testing::HasSubstr( - cookie.cookie.Name() + "=value"))); - } - - std::vector<CookieInclusionStatus::ExclusionReason> exclusions; - std::vector<CookieInclusionStatus::WarningReason> warnings; - if (!included) { - exclusions.push_back(CookieInclusionStatus:: - EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX); - warnings.push_back(CookieInclusionStatus:: - WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT); - } - if (base::Contains(test.expected_compat_warning_cookies, cookie_name)) { - warnings.push_back(CookieInclusionStatus::WARN_SAMESITE_COMPAT_PAIR); - } - EXPECT_TRUE( - cookie.access_result.status.HasExactlyExclusionReasonsForTesting( - exclusions)); - EXPECT_TRUE( - cookie.access_result.status.HasExactlyWarningReasonsForTesting( - warnings)); - } - } - } -} - // Test that the SameSite-by-default CookieInclusionStatus warnings do not get // set if the cookie would have been rejected for other reasons. // Regression test for https://crbug.com/1027318.
diff --git a/services/network/restricted_cookie_manager.cc b/services/network/restricted_cookie_manager.cc index f63e626..84104f6 100644 --- a/services/network/restricted_cookie_manager.cc +++ b/services/network/restricted_cookie_manager.cc
@@ -86,32 +86,6 @@ return options; } -void MarkSameSiteCompatPairs( - std::vector<net::CookieWithAccessResult>& cookie_list, - const net::CookieOptions& options) { - // If the context is same-site then there cannot be any SameSite-by-default - // warnings, so the compat pair warning is irrelevant. - if (options.same_site_cookie_context().GetContextForCookieInclusion() > - net::CookieOptions::SameSiteCookieContext::ContextType:: - SAME_SITE_LAX_METHOD_UNSAFE) { - return; - } - if (cookie_list.size() < 2) - return; - for (size_t i = 0; i < cookie_list.size() - 1; ++i) { - const net::CanonicalCookie& c1 = cookie_list[i].cookie; - for (size_t j = i + 1; j < cookie_list.size(); ++j) { - const net::CanonicalCookie& c2 = cookie_list[j].cookie; - if (net::cookie_util::IsSameSiteCompatPair(c1, c2, options)) { - cookie_list[i].access_result.status.AddWarningReason( - net::CookieInclusionStatus::WARN_SAMESITE_COMPAT_PAIR); - cookie_list[j].access_result.status.AddWarningReason( - net::CookieInclusionStatus::WARN_SAMESITE_COMPAT_PAIR); - } - } - } -} - } // namespace class RestrictedCookieManager::Listener : public base::LinkNode<Listener> { @@ -288,11 +262,6 @@ // TODO(https://crbug.com/977040): Remove once samesite tightening up is // rolled out. - // |on_cookies_accessed_result| is populated with excluded cookies here based - // on warnings present before WARN_SAMESITE_COMPAT_PAIR can be applied by - // MarkSameSiteCompatPairs(). This is ok because WARN_SAMESITE_COMPAT_PAIR is - // irrelevant unless WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT is already - // present. for (const auto& cookie_and_access_result : excluded_cookies) { if (cookie_and_access_result.access_result.status.ShouldWarn()) { on_cookies_accessed_result.push_back(cookie_and_access_result); @@ -331,10 +300,6 @@ } if (cookie_observer_) { - // Mark the CookieInclusionStatuses of items in |result_with_access_result| - // if they are part of a presumed SameSite compatibility pair. - MarkSameSiteCompatPairs(on_cookies_accessed_result, net_options); - cookie_observer_->OnCookiesAccessed(mojom::CookieAccessDetails::New( mojom::CookieAccessDetails::Type::kRead, url, site_for_cookies, on_cookies_accessed_result, base::nullopt));
diff --git a/services/network/restricted_cookie_manager_unittest.cc b/services/network/restricted_cookie_manager_unittest.cc index a322cdf0..4fa8fa8 100644 --- a/services/network/restricted_cookie_manager_unittest.cc +++ b/services/network/restricted_cookie_manager_unittest.cc
@@ -216,21 +216,6 @@ return callback.result().status.IsInclude(); } - // Set a canonical cookie directly into the store. - // Uses a cookie options that will succeed at setting any cookie. - bool EnsureSetCanonicalCookie(const net::CanonicalCookie& cookie) { - net::ResultSavingCookieCallback<net::CookieAccessResult> callback; - cookie_monster_.SetCanonicalCookieAsync( - std::make_unique<net::CanonicalCookie>(cookie), - net::cookie_util::SimulatedCookieSource(cookie, "https"), - net::CookieOptions::MakeAllInclusive(), - base::BindOnce( - &net::ResultSavingCookieCallback<net::CookieAccessResult>::Run, - base::Unretained(&callback))); - callback.WaitUntilDone(); - return callback.result().status.IsInclude(); - } - // Simplified helper for SetCanonicalCookie. // // Creates a CanonicalCookie that is secure (unless overriden), not http-only, @@ -876,233 +861,6 @@ EXPECT_THAT(cookies, testing::SizeIs(0)); } -// Test that the WARN_SAMESITE_COMPAT_PAIR warning is applied correctly to -// CookieInclusionStatuses passed to the CookieAccessObserver, -// but does not get into the cookies returned to the renderer. -TEST_P(RestrictedCookieManagerTest, SameSiteCompatPairWarning_AppliedOnGet) { - // Set cookies directly into the store that form a compat pair. - ASSERT_TRUE(EnsureSetCanonicalCookie(net::CanonicalCookie( - "name", "value", "example.com", "/", base::Time(), base::Time(), - base::Time(), /* secure = */ true, - /* httponly = */ false, net::CookieSameSite::NO_RESTRICTION, - net::COOKIE_PRIORITY_DEFAULT, /* same_party = */ false))); - ASSERT_TRUE(EnsureSetCanonicalCookie(net::CanonicalCookie( - "name_legacy", "value", "example.com", "/", base::Time(), base::Time(), - base::Time(), /* secure = */ true, - /* httponly = */ false, net::CookieSameSite::UNSPECIFIED, - net::COOKIE_PRIORITY_DEFAULT, /* same_party = */ false))); - - // Get cookies from the RestrictedCookieManager in a same-site context (should - // not trigger warnings). - { - auto options = mojom::CookieManagerGetOptions::New(); - options->name = "name"; - options->match_type = mojom::CookieMatchType::STARTS_WITH; - - std::vector<net::CookieWithAccessResult> cookies = - sync_service_->GetAllForUrlWithAccessResult( - GURL("https://example.com/test/"), GURL("https://example.com"), - url::Origin::Create(GURL("https://example.com")), - std::move(options)); - - ASSERT_THAT(cookies, testing::SizeIs(2)); - EXPECT_EQ("name", cookies[0].cookie.Name()); - EXPECT_EQ("name_legacy", cookies[1].cookie.Name()); - - // No warning is applied to returned cookies. - EXPECT_EQ(net::CookieInclusionStatus(), cookies[0].access_result.status); - EXPECT_EQ(net::CookieInclusionStatus(), cookies[1].access_result.status); - } - - // No warning is applied to the CookieInclusionStatuses passed to the - // CookieAccessObserver. - ASSERT_EQ(2u, recorded_activity().size()); - EXPECT_EQ(recorded_activity()[0].get, true); - EXPECT_EQ(recorded_activity()[0].url, "https://example.com/test/"); - EXPECT_EQ(recorded_activity()[0].site_for_cookies, "https://example.com/"); - EXPECT_THAT(recorded_activity()[0].cookie, - net::MatchesCookieLine("name=value")); - EXPECT_EQ(net::CookieInclusionStatus(), recorded_activity()[0].status); - EXPECT_EQ(recorded_activity()[1].get, true); - EXPECT_EQ(recorded_activity()[1].url, "https://example.com/test/"); - EXPECT_EQ(recorded_activity()[1].site_for_cookies, "https://example.com/"); - EXPECT_THAT(recorded_activity()[1].cookie, - net::MatchesCookieLine("name_legacy=value")); - EXPECT_EQ(net::CookieInclusionStatus(), recorded_activity()[1].status); - - recorded_activity().clear(); - - // Get cookies from the RestrictedCookieManager in a cross-site context to - // trigger warnings. - service_->OverrideSiteForCookiesForTesting( - net::SiteForCookies::FromUrl(GURL("https://notexample.com"))); - { - auto options = mojom::CookieManagerGetOptions::New(); - options->name = "name"; - options->match_type = mojom::CookieMatchType::STARTS_WITH; - - std::vector<net::CookieWithAccessResult> cookies = - sync_service_->GetAllForUrlWithAccessResult( - GURL("https://example.com/test/"), GURL("https://notexample.com"), - url::Origin::Create(GURL("https://example.com")), - std::move(options)); - - ASSERT_THAT(cookies, testing::SizeIs(1)); - EXPECT_EQ("name", cookies[0].cookie.Name()); - - // The warning is not applied to returned cookies. - EXPECT_EQ(net::CookieInclusionStatus(), cookies[0].access_result.status); - } - - // The warning is applied to the CookieInclusionStatuses passed to the - // CookieAccessObserver. - ASSERT_EQ(2u, recorded_activity().size()); - EXPECT_EQ(recorded_activity()[0].get, true); - EXPECT_EQ(recorded_activity()[0].url, "https://example.com/test/"); - EXPECT_EQ(recorded_activity()[0].site_for_cookies, "https://notexample.com/"); - EXPECT_THAT(recorded_activity()[0].cookie, - net::MatchesCookieLine("name_legacy=value")); - EXPECT_TRUE( - recorded_activity()[0].status.HasExactlyExclusionReasonsForTesting( - {net::CookieInclusionStatus:: - EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX})); - EXPECT_TRUE(recorded_activity()[0].status.HasExactlyWarningReasonsForTesting( - {net::CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT, - net::CookieInclusionStatus::WARN_SAMESITE_COMPAT_PAIR})); - EXPECT_EQ(recorded_activity()[1].get, true); - EXPECT_EQ(recorded_activity()[1].url, "https://example.com/test/"); - EXPECT_EQ(recorded_activity()[1].site_for_cookies, "https://notexample.com/"); - EXPECT_THAT(recorded_activity()[1].cookie, - net::MatchesCookieLine("name=value")); - EXPECT_TRUE(recorded_activity()[1].status.IsInclude()); - EXPECT_TRUE(recorded_activity()[1].status.HasExactlyWarningReasonsForTesting( - {net::CookieInclusionStatus::WARN_SAMESITE_COMPAT_PAIR})); -} - -// Test that the WARN_SAMESITE_COMPAT_PAIR warning is not applied if either of -// the cookies in the pair is HttpOnly and the access is from a script. -TEST_P(RestrictedCookieManagerTest, SameSiteCompatPairWarning_HttpOnly) { - // Use a cross-site context to trigger warnings. - service_->OverrideSiteForCookiesForTesting( - net::SiteForCookies::FromUrl(GURL("https://notexample.com"))); - - // Set cookies directly into the store that form a compat pair. - // One of them is HttpOnly. - ASSERT_TRUE(EnsureSetCanonicalCookie(net::CanonicalCookie( - "name", "value", "example.com", "/", base::Time(), base::Time(), - base::Time(), /* secure = */ true, - /* httponly = */ true, net::CookieSameSite::NO_RESTRICTION, - net::COOKIE_PRIORITY_DEFAULT, /* same_party = */ false))); - ASSERT_TRUE(EnsureSetCanonicalCookie(net::CanonicalCookie( - "name_legacy", "value", "example.com", "/", base::Time(), base::Time(), - base::Time(), /* secure = */ true, - /* httponly = */ false, net::CookieSameSite::UNSPECIFIED, - net::COOKIE_PRIORITY_DEFAULT, /* same_party = */ false))); - - // Get cookies from the RestrictedCookieManager in a cross-site context. - { - auto options = mojom::CookieManagerGetOptions::New(); - options->name = "name"; - options->match_type = mojom::CookieMatchType::STARTS_WITH; - - std::vector<net::CookieWithAccessResult> cookies = - sync_service_->GetAllForUrlWithAccessResult( - GURL("https://example.com/test/"), GURL("https://notexample.com"), - url::Origin::Create(GURL("https://example.com")), - std::move(options)); - - if (GetParam() == mojom::RestrictedCookieManagerRole::SCRIPT) { - ASSERT_THAT(cookies, testing::SizeIs(0)); - } else { // mojom::RestrictedCookieManagerRole::NETWORK - ASSERT_THAT(cookies, testing::SizeIs(1)); - EXPECT_EQ("name", cookies[0].cookie.Name()); - - // The warning is not applied to returned cookies. - EXPECT_EQ(net::CookieInclusionStatus(), cookies[0].access_result.status); - } - } - - ASSERT_EQ(GetParam() == mojom::RestrictedCookieManagerRole::SCRIPT ? 1u : 2u, - recorded_activity().size()); - EXPECT_EQ(recorded_activity()[0].get, true); - EXPECT_EQ(recorded_activity()[0].url, "https://example.com/test/"); - EXPECT_EQ(recorded_activity()[0].site_for_cookies, "https://notexample.com/"); - EXPECT_THAT(recorded_activity()[0].cookie, - net::MatchesCookieLine("name_legacy=value")); - EXPECT_TRUE( - recorded_activity()[0].status.HasExactlyExclusionReasonsForTesting( - {net::CookieInclusionStatus:: - EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX})); - if (GetParam() == mojom::RestrictedCookieManagerRole::SCRIPT) { - // No compat pair warning in script context. - EXPECT_TRUE( - recorded_activity()[0].status.HasExactlyWarningReasonsForTesting( - {net::CookieInclusionStatus:: - WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT})); - return; - } - // Compat pair warning is applied in a network context. - EXPECT_TRUE(recorded_activity()[0].status.HasExactlyWarningReasonsForTesting( - {net::CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT, - net::CookieInclusionStatus::WARN_SAMESITE_COMPAT_PAIR})); - - EXPECT_EQ(recorded_activity()[1].get, true); - EXPECT_EQ(recorded_activity()[1].url, "https://example.com/test/"); - EXPECT_EQ(recorded_activity()[1].site_for_cookies, "https://notexample.com/"); - EXPECT_THAT(recorded_activity()[1].cookie, - net::MatchesCookieLine("name=value")); - EXPECT_TRUE(recorded_activity()[1].status.IsInclude()); - EXPECT_TRUE(recorded_activity()[1].status.HasExactlyWarningReasonsForTesting( - {net::CookieInclusionStatus::WARN_SAMESITE_COMPAT_PAIR})); -} - -// Test that compat pair warning is not applied when RestrictedCookieManager -// sets a cookie. -TEST_P(RestrictedCookieManagerTest, SameSiteCompatPairWarning_NotAppliedOnSet) { - // Even a cross-site context should not apply warnings for setting cookies. - service_->OverrideSiteForCookiesForTesting( - net::SiteForCookies::FromUrl(GURL("https://notexample.com"))); - - { - // SameSite=None cookie is set. - auto cookie = net::CanonicalCookie::Create( - GURL("https://example.com"), "A=B; SameSite=none; Secure", - base::Time::Now(), base::nullopt /* server_time */); - EXPECT_TRUE(sync_service_->SetCanonicalCookie( - *cookie, GURL("https://example.com"), GURL("https://notexample.com"), - url::Origin::Create(GURL("https://example.com")))); - } - ASSERT_EQ(1u, recorded_activity().size()); - EXPECT_EQ(recorded_activity()[0].get, false); - EXPECT_EQ(recorded_activity()[0].url, "https://example.com/"); - EXPECT_EQ(recorded_activity()[0].site_for_cookies, "https://notexample.com/"); - EXPECT_THAT(recorded_activity()[0].cookie, net::MatchesCookieLine("A=B")); - EXPECT_EQ(net::CookieInclusionStatus(), recorded_activity()[0].status); - - { - // Legacy cookie is rejected. - auto cookie = net::CanonicalCookie::Create(GURL("https://example.com"), - "A_compat=B", base::Time::Now(), - base::nullopt /* server_time */); - EXPECT_FALSE(sync_service_->SetCanonicalCookie( - *cookie, GURL("https://example.com"), GURL("https://notexample.com"), - url::Origin::Create(GURL("https://example.com")))); - } - ASSERT_EQ(2u, recorded_activity().size()); - EXPECT_EQ(recorded_activity()[1].get, false); - EXPECT_EQ(recorded_activity()[1].url, "https://example.com/"); - EXPECT_EQ(recorded_activity()[1].site_for_cookies, "https://notexample.com/"); - EXPECT_THAT(recorded_activity()[1].cookie, - net::MatchesCookieLine("A_compat=B")); - EXPECT_TRUE( - recorded_activity()[1].status.HasExactlyExclusionReasonsForTesting( - {net::CookieInclusionStatus:: - EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX})); - EXPECT_TRUE(recorded_activity()[1].status.HasExactlyWarningReasonsForTesting( - {net::CookieInclusionStatus:: - WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT})); -} - namespace { // Stashes the cookie changes it receives, for testing.
diff --git a/skia/public/mojom/BUILD.gn b/skia/public/mojom/BUILD.gn index 64f5b1b..2de0be5 100644 --- a/skia/public/mojom/BUILD.gn +++ b/skia/public/mojom/BUILD.gn
@@ -99,6 +99,10 @@ mojom = "skia.mojom.ImageInfo" cpp = "::SkImageInfo" }, + { + mojom = "skia.mojom.BitmapN32ImageInfo" + cpp = "::SkImageInfo" + }, ] traits_headers = [ "image_info_mojom_traits.h" ] traits_public_deps = [
diff --git a/skia/public/mojom/bitmap.mojom b/skia/public/mojom/bitmap.mojom index 845322a..34250f5 100644 --- a/skia/public/mojom/bitmap.mojom +++ b/skia/public/mojom/bitmap.mojom
@@ -11,7 +11,7 @@ [Stable] struct Bitmap { ImageInfo image_info; - uint64 row_bytes; + uint64 UNUSED_row_bytes; mojo_base.mojom.BigBuffer pixel_data; }; @@ -29,14 +29,19 @@ [Stable, RenamedFrom="skia.mojom.UnsafeBitmap"] struct BitmapMappedFromTrustedProcess { ImageInfo image_info; - uint64 row_bytes; + uint64 UNUSED_row_bytes; mojo_base.mojom.BigBuffer pixel_data; }; -// NOTE: This should only be used when an SkBitmap MUST be serialized as raw -// bytes (i.e. it's not OK for shared memory to be used, as above). +// Encode an N32 SkBitmap for transport without relying on shared memory. +// Normally, it is preferable to use shared memory and this mojom type should +// NOT be used for IPC. +// +// This type is useful, however, for de/serialization to a string (via +// skia::mojom::InlineBitmap::Serialize() and Deserialize()) since it will not +// attempt to use a shared memory handle and will encode the actual pixel +// content always. struct InlineBitmap { - ImageInfo image_info; - uint64 row_bytes; + BitmapN32ImageInfo image_info; array<uint8> pixel_data; };
diff --git a/skia/public/mojom/bitmap_skbitmap_mojom_traits.cc b/skia/public/mojom/bitmap_skbitmap_mojom_traits.cc index 7b3e3b4..78ff48e 100644 --- a/skia/public/mojom/bitmap_skbitmap_mojom_traits.cc +++ b/skia/public/mojom/bitmap_skbitmap_mojom_traits.cc
@@ -31,35 +31,44 @@ mojo_base::BigBuffer buffer_; }; +bool CreateSkBitmapForPixelData(SkBitmap* b, + const SkImageInfo& image_info, + base::span<const uint8_t> pixel_data) { + // Ensure width and height are reasonable. + if (image_info.width() > kMaxWidth || image_info.height() > kMaxHeight) + return false; + + // We require incoming bitmaps to be tightly packed by specifying the + // rowBytes() as minRowBytes(). Then we compare the number of bytes against + // `pixel_data.size()` later to verify the actual data is tightly packed. + if (!b->tryAllocPixels(image_info, image_info.minRowBytes())) + return false; + + // If the image is empty, return success after setting the image info. + if (image_info.width() == 0 || image_info.height() == 0) + return true; + + // If these don't match then the number of bytes sent does not match what the + // rest of the mojom said there should be. + if (pixel_data.size() != b->computeByteSize()) + return false; + + // Implementation note: This copy is important from a security perspective as + // it provides the recipient of the SkBitmap with a stable copy of the data. + // The sender could otherwise continue modifying the shared memory buffer + // underlying the BigBuffer instance. + std::copy(pixel_data.begin(), pixel_data.end(), + static_cast<uint8_t*>(b->getPixels())); + b->notifyPixelsChanged(); + return true; +} + } // namespace // static -bool StructTraits<skia::mojom::BitmapDataView, SkBitmap>::IsNull( - const SkBitmap& b) { - return b.isNull(); -} - -// static -void StructTraits<skia::mojom::BitmapDataView, SkBitmap>::SetToNull( - SkBitmap* b) { - b->reset(); -} - -// static -const SkImageInfo& StructTraits<skia::mojom::BitmapDataView, - SkBitmap>::image_info(const SkBitmap& b) { - return b.info(); -} - -// static -uint64_t StructTraits<skia::mojom::BitmapDataView, SkBitmap>::row_bytes( - const SkBitmap& b) { - return b.rowBytes(); -} - -// static mojo_base::BigBufferView StructTraits<skia::mojom::BitmapDataView, SkBitmap>::pixel_data(const SkBitmap& b) { + CHECK_EQ(b.rowBytes(), b.info().minRowBytes()); return mojo_base::BigBufferView(base::make_span( static_cast<uint8_t*>(b.getPixels()), b.computeByteSize())); } @@ -72,69 +81,19 @@ if (!data.ReadImageInfo(&image_info)) return false; - // Ensure width and height are reasonable. - if (image_info.width() > kMaxWidth || image_info.height() > kMaxHeight) - return false; - - *b = SkBitmap(); - if (!b->tryAllocPixels(image_info, data.row_bytes())) { - return false; - } - - // If the image is empty, return success after setting the image info. - if (image_info.width() == 0 || image_info.height() == 0) - return true; - mojo_base::BigBufferView pixel_data_view; if (!data.ReadPixelData(&pixel_data_view)) return false; - base::span<const uint8_t> pixel_data_bytes = pixel_data_view.data(); - if (b->width() != image_info.width() || b->height() != image_info.height() || - static_cast<uint64_t>(b->rowBytes()) != data.row_bytes() || - b->computeByteSize() != pixel_data_bytes.size() || !b->readyToDraw()) { - return false; - } - - // Implementation note: This copy is important from a security perspective as - // it provides the recipient of the SkBitmap with a stable copy of the data. - // The sender could otherwise continue modifying the shared memory buffer - // underlying the BigBuffer instance. - std::copy(pixel_data_bytes.begin(), pixel_data_bytes.end(), - static_cast<uint8_t*>(b->getPixels())); - b->notifyPixelsChanged(); - return true; -} - -// static -bool StructTraits<skia::mojom::BitmapMappedFromTrustedProcessDataView, - SkBitmap>::IsNull(const SkBitmap& b) { - return b.isNull(); -} - -// static -void StructTraits<skia::mojom::BitmapMappedFromTrustedProcessDataView, - SkBitmap>::SetToNull(SkBitmap* b) { - b->reset(); -} - -// static -const SkImageInfo& -StructTraits<skia::mojom::BitmapMappedFromTrustedProcessDataView, - SkBitmap>::image_info(const SkBitmap& b) { - return b.info(); -} - -// static -uint64_t StructTraits<skia::mojom::BitmapMappedFromTrustedProcessDataView, - SkBitmap>::row_bytes(const SkBitmap& b) { - return b.rowBytes(); + return CreateSkBitmapForPixelData(b, std::move(image_info), + pixel_data_view.data()); } // static mojo_base::BigBufferView StructTraits<skia::mojom::BitmapMappedFromTrustedProcessDataView, SkBitmap>::pixel_data(const SkBitmap& b) { + CHECK_EQ(b.rowBytes(), b.info().minRowBytes()); return mojo_base::BigBufferView(base::make_span( static_cast<uint8_t*>(b.getPixels()), b.computeByteSize())); } @@ -152,11 +111,9 @@ if (image_info.width() > kMaxWidth || image_info.height() > kMaxHeight) return false; - *b = SkBitmap(); - // If the image is empty, return success after setting the image info. if (image_info.width() == 0 || image_info.height() == 0) - return b->tryAllocPixels(image_info, data.row_bytes()); + return b->tryAllocPixels(image_info); // Otherwise, set a custom PixelRef to retain the BigBuffer. This avoids // making another copy of the pixel data. @@ -165,7 +122,16 @@ if (!data.ReadPixelData(&pixel_data_view)) return false; - if (!b->setInfo(image_info, data.row_bytes())) + // We require incoming bitmaps to be tightly packed by specifying the + // rowBytes() as minRowBytes(). Then we compare the number of bytes against + // `pixel_data_view.data().size()` later to verify the actual data is tightly + // packed. + if (!b->setInfo(image_info, image_info.minRowBytes())) + return false; + + // If these don't match then the number of bytes sent does not match what the + // rest of the mojom said there should be. + if (b->computeByteSize() != pixel_data_view.data().size()) return false; // Allow the resultant SkBitmap to refer to the given BigBuffer. Note, the @@ -174,39 +140,16 @@ b->setPixelRef( sk_make_sp<BigBufferPixelRef>( mojo_base::BigBufferView::ToBigBuffer(std::move(pixel_data_view)), - image_info.width(), image_info.height(), data.row_bytes()), + image_info.width(), image_info.height(), image_info.minRowBytes()), 0, 0); return true; } // static -bool StructTraits<skia::mojom::InlineBitmapDataView, SkBitmap>::IsNull( - const SkBitmap& b) { - return b.isNull(); -} - -// static -void StructTraits<skia::mojom::InlineBitmapDataView, SkBitmap>::SetToNull( - SkBitmap* b) { - b->reset(); -} - -// static -const SkImageInfo& StructTraits<skia::mojom::InlineBitmapDataView, - SkBitmap>::image_info(const SkBitmap& b) { - return StructTraits<skia::mojom::BitmapDataView, SkBitmap>::image_info(b); -} - -// static -uint64_t StructTraits<skia::mojom::InlineBitmapDataView, SkBitmap>::row_bytes( - const SkBitmap& b) { - return StructTraits<skia::mojom::BitmapDataView, SkBitmap>::row_bytes(b); -} - -// static base::span<const uint8_t> StructTraits<skia::mojom::InlineBitmapDataView, SkBitmap>::pixel_data( const SkBitmap& b) { + CHECK_EQ(b.rowBytes(), b.info().minRowBytes()); return base::make_span(static_cast<uint8_t*>(b.getPixels()), b.computeByteSize()); } @@ -219,35 +162,14 @@ if (!data.ReadImageInfo(&image_info)) return false; - // Ensure width and height are reasonable. - if (image_info.width() > kMaxWidth || image_info.height() > kMaxHeight) - return false; + mojo::ArrayDataView<uint8_t> pixel_data_view; + data.GetPixelDataDataView(&pixel_data_view); - *b = SkBitmap(); - if (!b->tryAllocPixels(image_info, data.row_bytes())) - return false; + base::span<const uint8_t> pixel_data_bytes(pixel_data_view.data(), + pixel_data_view.size()); - // If the image is empty, return success after setting the image info. - if (image_info.width() == 0 || image_info.height() == 0) - return true; - - mojo::ArrayDataView<uint8_t> data_view; - data.GetPixelDataDataView(&data_view); - if (b->width() != image_info.width() || b->height() != image_info.height() || - static_cast<uint64_t>(b->rowBytes()) != data.row_bytes() || - b->computeByteSize() != data_view.size() || !b->readyToDraw()) { - return false; - } - - auto bitmap_buffer = base::make_span(static_cast<uint8_t*>(b->getPixels()), - b->computeByteSize()); - if (!data.ReadPixelData(&bitmap_buffer) || - bitmap_buffer.size() != b->computeByteSize()) { - return false; - } - - b->notifyPixelsChanged(); - return true; + return CreateSkBitmapForPixelData(b, std::move(image_info), + std::move(pixel_data_bytes)); } } // namespace mojo
diff --git a/skia/public/mojom/bitmap_skbitmap_mojom_traits.h b/skia/public/mojom/bitmap_skbitmap_mojom_traits.h index 7a08576..ca598dc 100644 --- a/skia/public/mojom/bitmap_skbitmap_mojom_traits.h +++ b/skia/public/mojom/bitmap_skbitmap_mojom_traits.h
@@ -20,11 +20,13 @@ template <> struct COMPONENT_EXPORT(SKIA_SHARED_TRAITS) StructTraits<skia::mojom::BitmapDataView, SkBitmap> { - static bool IsNull(const SkBitmap& b); - static void SetToNull(SkBitmap* b); - static const SkImageInfo& image_info(const SkBitmap& b); - static uint64_t row_bytes(const SkBitmap& b); + static bool IsNull(const SkBitmap& b) { return b.isNull(); } + static void SetToNull(SkBitmap* b) { b->reset(); } + + static const SkImageInfo& image_info(const SkBitmap& b) { return b.info(); } + static uint64_t UNUSED_row_bytes(const SkBitmap& b) { return 0; } static mojo_base::BigBufferView pixel_data(const SkBitmap& b); + static bool Read(skia::mojom::BitmapDataView data, SkBitmap* b); }; @@ -32,11 +34,13 @@ struct COMPONENT_EXPORT(SKIA_SHARED_TRAITS) StructTraits<skia::mojom::BitmapMappedFromTrustedProcessDataView, SkBitmap> { - static bool IsNull(const SkBitmap& b); - static void SetToNull(SkBitmap* b); - static const SkImageInfo& image_info(const SkBitmap& b); - static uint64_t row_bytes(const SkBitmap& b); + static bool IsNull(const SkBitmap& b) { return b.isNull(); } + static void SetToNull(SkBitmap* b) { b->reset(); } + + static const SkImageInfo& image_info(const SkBitmap& b) { return b.info(); } + static uint64_t UNUSED_row_bytes(const SkBitmap& b) { return 0; } static mojo_base::BigBufferView pixel_data(const SkBitmap& b); + static bool Read(skia::mojom::BitmapMappedFromTrustedProcessDataView data, SkBitmap* b); }; @@ -44,11 +48,12 @@ template <> struct COMPONENT_EXPORT(SKIA_SHARED_TRAITS) StructTraits<skia::mojom::InlineBitmapDataView, SkBitmap> { - static bool IsNull(const SkBitmap& b); - static void SetToNull(SkBitmap* b); - static const SkImageInfo& image_info(const SkBitmap& b); - static uint64_t row_bytes(const SkBitmap& b); + static bool IsNull(const SkBitmap& b) { return b.isNull(); } + static void SetToNull(SkBitmap* b) { b->reset(); } + + static const SkImageInfo& image_info(const SkBitmap& b) { return b.info(); } static base::span<const uint8_t> pixel_data(const SkBitmap& b); + static bool Read(skia::mojom::InlineBitmapDataView data, SkBitmap* b); };
diff --git a/skia/public/mojom/image_info.mojom b/skia/public/mojom/image_info.mojom index 35d00c2..3d921519 100644 --- a/skia/public/mojom/image_info.mojom +++ b/skia/public/mojom/image_info.mojom
@@ -54,3 +54,25 @@ // no explicit color space. array<float, 9>? color_to_xyz_matrix; }; + +// Similar to ImageInfo, but is used when only N32 ColorType is allowed. As such +// the ColorType is not transmitted over the wire at all. +struct BitmapN32ImageInfo { + AlphaType alpha_type; + uint32 width; + uint32 height; + + // Color transfer function mapping encoded values to linear values, + // represented by this 7-parameter piecewise function: + // linear = sign(encoded) * (c*|encoded| + f) , 0 <= |encoded| < d + // = sign(encoded) * ((a*|encoded| + b)^g + e), d <= |encoded| + // (A simple gamma transfer function sets g to gamma and a to 1.) + // See SkColorSpace and skcms_TransferFunction. Null if the image has no + // explicit color space. Parameters are serialized as: g, a, b, c, d, e, f. + array<float, 7>? color_transfer_function; + + // Color transformation matrix to convert colors to XYZ D50, represented as + // a row-major 3x3 matrix. See SkColorSpace::MakeRGB(). Null if the image has + // no explicit color space. + array<float, 9>? color_to_xyz_matrix; +};
diff --git a/skia/public/mojom/image_info_mojom_traits.cc b/skia/public/mojom/image_info_mojom_traits.cc index 1818def..95df3e9 100644 --- a/skia/public/mojom/image_info_mojom_traits.cc +++ b/skia/public/mojom/image_info_mojom_traits.cc
@@ -11,6 +11,39 @@ namespace mojo { +namespace { + +SkImageInfo MakeSkImageInfo(SkColorType color_type, + SkAlphaType alpha_type, + int width, + int height, + mojo::ArrayDataView<float> color_transfer_function, + mojo::ArrayDataView<float> color_to_xyz_matrix) { + sk_sp<SkColorSpace> color_space; + if (!color_transfer_function.is_null() && !color_to_xyz_matrix.is_null()) { + const float* data = color_transfer_function.data(); + skcms_TransferFunction transfer_function; + CHECK_EQ(7u, color_transfer_function.size()); + transfer_function.g = data[0]; + transfer_function.a = data[1]; + transfer_function.b = data[2]; + transfer_function.c = data[3]; + transfer_function.d = data[4]; + transfer_function.e = data[5]; + transfer_function.f = data[6]; + + skcms_Matrix3x3 to_xyz_matrix; + CHECK_EQ(9u, color_to_xyz_matrix.size()); + memcpy(to_xyz_matrix.vals, color_to_xyz_matrix.data(), 9 * sizeof(float)); + color_space = SkColorSpace::MakeRGB(transfer_function, to_xyz_matrix); + } + + return SkImageInfo::Make(width, height, color_type, alpha_type, + std::move(color_space)); +} + +} // namespace + // static skia::mojom::AlphaType EnumTraits<skia::mojom::AlphaType, SkAlphaType>::ToMojom( SkAlphaType type) { @@ -117,18 +150,6 @@ } // static -SkColorType StructTraits<skia::mojom::ImageInfoDataView, - SkImageInfo>::color_type(const SkImageInfo& info) { - return info.colorType(); -} - -// static -SkAlphaType StructTraits<skia::mojom::ImageInfoDataView, - SkImageInfo>::alpha_type(const SkImageInfo& info) { - return info.alphaType(); -} - -// static uint32_t StructTraits<skia::mojom::ImageInfoDataView, SkImageInfo>::width( const SkImageInfo& info) { // Negative width images are invalid. @@ -186,33 +207,28 @@ mojo::ArrayDataView<float> color_to_xyz_matrix; data.GetColorToXyzMatrixDataView(&color_to_xyz_matrix); - // Sender must supply both color space fields or neither. This approach is - // simpler than having an optional ColorSpace mojo struct, due to BUILD.gn - // complexity with blink variants. - if (color_transfer_function.is_null() != color_to_xyz_matrix.is_null()) + *info = MakeSkImageInfo(color_type, alpha_type, data.width(), data.height(), + std::move(color_transfer_function), + std::move(color_to_xyz_matrix)); + return true; +} + +// static +bool StructTraits<skia::mojom::BitmapN32ImageInfoDataView, SkImageInfo>::Read( + skia::mojom::BitmapN32ImageInfoDataView data, + SkImageInfo* info) { + SkAlphaType alpha_type; + if (!data.ReadAlphaType(&alpha_type)) return false; - sk_sp<SkColorSpace> sk_color_space; - if (!color_transfer_function.is_null() && !color_to_xyz_matrix.is_null()) { - const float* data = color_transfer_function.data(); - skcms_TransferFunction transfer_function; - CHECK_EQ(7u, color_transfer_function.size()); - transfer_function.g = data[0]; - transfer_function.a = data[1]; - transfer_function.b = data[2]; - transfer_function.c = data[3]; - transfer_function.d = data[4]; - transfer_function.e = data[5]; - transfer_function.f = data[6]; + mojo::ArrayDataView<float> color_transfer_function; + data.GetColorTransferFunctionDataView(&color_transfer_function); + mojo::ArrayDataView<float> color_to_xyz_matrix; + data.GetColorToXyzMatrixDataView(&color_to_xyz_matrix); - skcms_Matrix3x3 to_xyz_matrix; - CHECK_EQ(9u, color_to_xyz_matrix.size()); - memcpy(to_xyz_matrix.vals, color_to_xyz_matrix.data(), 9 * sizeof(float)); - sk_color_space = SkColorSpace::MakeRGB(transfer_function, to_xyz_matrix); - } - - *info = SkImageInfo::Make(data.width(), data.height(), color_type, alpha_type, - std::move(sk_color_space)); + *info = MakeSkImageInfo(kN32_SkColorType, alpha_type, data.width(), + data.height(), std::move(color_transfer_function), + std::move(color_to_xyz_matrix)); return true; }
diff --git a/skia/public/mojom/image_info_mojom_traits.h b/skia/public/mojom/image_info_mojom_traits.h index e443ce3b..770382d37 100644 --- a/skia/public/mojom/image_info_mojom_traits.h +++ b/skia/public/mojom/image_info_mojom_traits.h
@@ -31,8 +31,12 @@ template <> struct COMPONENT_EXPORT(SKIA_SHARED_TRAITS) StructTraits<skia::mojom::ImageInfoDataView, SkImageInfo> { - static SkColorType color_type(const SkImageInfo& info); - static SkAlphaType alpha_type(const SkImageInfo& info); + static SkColorType color_type(const SkImageInfo& info) { + return info.colorType(); + } + static SkAlphaType alpha_type(const SkImageInfo& info) { + return info.alphaType(); + } static uint32_t width(const SkImageInfo& info); static uint32_t height(const SkImageInfo& info); static base::Optional<std::vector<float>> color_transfer_function( @@ -43,6 +47,37 @@ static bool Read(skia::mojom::ImageInfoDataView data, SkImageInfo* info); }; +template <> +struct COMPONENT_EXPORT(SKIA_SHARED_TRAITS) + StructTraits<skia::mojom::BitmapN32ImageInfoDataView, SkImageInfo> { + static SkAlphaType alpha_type(const SkImageInfo& info) { + // BitmapN32ImageInfo only allows N32 SkImageInfos. + CHECK_EQ(info.colorType(), kN32_SkColorType); + return info.alphaType(); + } + static uint32_t width(const SkImageInfo& info) { + return ImageInfoStructTraits::width(info); + } + static uint32_t height(const SkImageInfo& info) { + return ImageInfoStructTraits::height(info); + } + static base::Optional<std::vector<float>> color_transfer_function( + const SkImageInfo& info) { + return ImageInfoStructTraits::color_transfer_function(info); + } + static base::Optional<std::vector<float>> color_to_xyz_matrix( + const SkImageInfo& info) { + return ImageInfoStructTraits::color_to_xyz_matrix(info); + } + + static bool Read(skia::mojom::BitmapN32ImageInfoDataView data, + SkImageInfo* info); + + private: + using ImageInfoStructTraits = + StructTraits<skia::mojom::ImageInfoDataView, SkImageInfo>; +}; + } // namespace mojo #endif // SKIA_PUBLIC_MOJOM_IMAGE_INFO_MOJOM_TRAITS_H_
diff --git a/skia/public/mojom/test/mojom_traits_unittest.cc b/skia/public/mojom/test/mojom_traits_unittest.cc index 6f5969d3..b611cbd 100644 --- a/skia/public/mojom/test/mojom_traits_unittest.cc +++ b/skia/public/mojom/test/mojom_traits_unittest.cc
@@ -4,6 +4,7 @@ #include "mojo/public/cpp/test_support/test_utils.h" #include "skia/public/mojom/bitmap.mojom.h" +#include "skia/public/mojom/bitmap_skbitmap_mojom_traits.h" #include "skia/public/mojom/blur_image_filter_tile_mode.mojom.h" #include "skia/public/mojom/blur_image_filter_tile_mode_mojom_traits.h" #include "skia/public/mojom/image_info.mojom.h" @@ -19,9 +20,33 @@ #include "ui/gfx/skia_util.h" namespace skia { - namespace { +// A helper to construct a skia.mojom.Bitmap without using StructTraits +// to bypass checks on the sending/serialization side. +mojo::StructPtr<skia::mojom::Bitmap> ConstructBitmap( + SkImageInfo info, + int row_bytes, + std::vector<unsigned char> pixels) { + auto mojom_bitmap = skia::mojom::Bitmap::New(); + mojom_bitmap->image_info = std::move(info); + mojom_bitmap->UNUSED_row_bytes = row_bytes; + mojom_bitmap->pixel_data = std::move(pixels); + return mojom_bitmap; +} + +// A helper to construct a skia.mojom.InlineBitmap without using StructTraits +// to bypass checks on the sending/serialization side. +mojo::StructPtr<skia::mojom::InlineBitmap> ConstructInlineBitmap( + SkImageInfo info, + std::vector<unsigned char> pixels) { + DCHECK_EQ(info.colorType(), kN32_SkColorType); + auto mojom_bitmap = skia::mojom::InlineBitmap::New(); + mojom_bitmap->image_info = std::move(info); + mojom_bitmap->pixel_data = std::move(pixels); + return mojom_bitmap; +} + // mojo::test::SerializeAndDeserialize() doesn't work for a raw enum, so roll // our own. bool SerializeAndDeserialize(SkBlurImageFilter::TileMode* input, @@ -33,7 +58,20 @@ SkBlurImageFilter::TileMode>::FromMojom(mode, output); } -} // namespace +template <typename MojomType, typename UserType> +bool SerializeAndDeserializeFromMojom(mojo::StructPtr<MojomType>* input, + UserType* output) { + mojo::Message message = MojomType::SerializeAsMessage(input); + + // This accurately simulates full serialization to ensure that all attached + // handles are serialized as well. Necessary for DeserializeFromMessage to + // work properly. + mojo::ScopedMessageHandle handle = message.TakeMojoMessage(); + message = mojo::Message::CreateFromMessageHandle(&handle); + DCHECK(!message.IsNull()); + + return MojomType::DeserializeFromMessage(std::move(message), output); +} TEST(StructTraitsTest, ImageInfo) { SkImageInfo input = SkImageInfo::Make( @@ -85,6 +123,24 @@ EXPECT_TRUE(gfx::BitmapsAreEqual(input, output)); } +TEST(StructTraitsTest, BitmapNull) { + SkBitmap input; + input.setInfo(SkImageInfo::MakeN32Premul( + 10, 5, + SkColorSpace::MakeRGB(SkNamedTransferFn::kLinear, + SkNamedGamut::kRec2020))); + EXPECT_TRUE(input.isNull()); + + // Null input produces a default-initialized SkBitmap. + SkBitmap output; + ASSERT_TRUE(mojo::test::SerializeAndDeserialize<skia::mojom::Bitmap>( + &input, &output)); + EXPECT_EQ(output.info().alphaType(), kUnknown_SkAlphaType); + EXPECT_EQ(output.info().colorType(), kUnknown_SkColorType); + EXPECT_EQ(output.rowBytes(), 0u); + EXPECT_TRUE(output.isNull()); +} + TEST(StructTraitsTest, BitmapTooWideToSerialize) { SkBitmap input; constexpr int kTooWide = 64 * 1024 + 1; @@ -107,23 +163,69 @@ &input, &output)); } -TEST(StructTraitsTest, BitmapWithExtraRowBytes) { +TEST(StructTraitsTest, BitmapSerializeInvalidRowBytes) { SkBitmap input; - // Ensure traits work with bitmaps containing additional bytes between rows. SkImageInfo info = SkImageInfo::MakeN32(8, 5, kPremul_SkAlphaType, SkColorSpace::MakeSRGB()); - // Any extra bytes on each row must be a multiple of the row's pixel size to - // keep every row's pixels aligned. - size_t extra = info.bytesPerPixel(); - input.allocPixels(info, info.minRowBytes() + extra); - input.eraseColor(SK_ColorRED); - input.erase(SK_ColorTRANSPARENT, SkIRect::MakeXYWH(0, 1, 2, 3)); + EXPECT_TRUE( + input.tryAllocPixels(info, info.minRowBytes() + info.bytesPerPixel())); + + // We do not allow sending rowBytes() other than the minRowBytes(). + EXPECT_DEATH(skia::mojom::Bitmap::SerializeAsMessage(&input), ""); +} + +TEST(StructTraitsTest, VerifyBitmapConstruction) { + // Verify that we can manually construct a valid skia.mojom.Bitmap and + // deserialize it successfully. + mojo::StructPtr<skia::mojom::Bitmap> input = + ConstructBitmap(SkImageInfo::MakeN32Premul(1, 1), 0, {1, 2, 3, 4}); + SkBitmap output; - ASSERT_TRUE(mojo::test::SerializeAndDeserialize<skia::mojom::Bitmap>( - &input, &output)); - EXPECT_EQ(input.info(), output.info()); - EXPECT_EQ(input.rowBytes(), output.rowBytes()); - EXPECT_TRUE(gfx::BitmapsAreEqual(input, output)); + bool ok = + SerializeAndDeserializeFromMojom<skia::mojom::Bitmap>(&input, &output); + EXPECT_TRUE(ok); +} + +TEST(StructTraitsTest, BitmapDeserializeIgnoresRowBytes) { + mojo::StructPtr<skia::mojom::Bitmap> input = + ConstructBitmap(SkImageInfo::MakeN32Premul(1, 1), 8, {1, 2, 3, 4}); + + SkBitmap output; + bool ok = + SerializeAndDeserializeFromMojom<skia::mojom::Bitmap>(&input, &output); + EXPECT_TRUE(ok); + // The row_bytes field is ignored, and the minRowBytes() is always used. + EXPECT_EQ(4u, output.rowBytes()); +} + +TEST(StructTraitsTest, BitmapDeserializeMismatchFormatAndPixels) { + mojo::StructPtr<skia::mojom::Bitmap> input = + ConstructBitmap(SkImageInfo::MakeA8(1, 1), 0, {1, 2, 3, 4}); + + SkBitmap output; + bool ok = + SerializeAndDeserializeFromMojom<skia::mojom::Bitmap>(&input, &output); + EXPECT_FALSE(ok); +} + +TEST(StructTraitsTest, BitmapDeserializeTooFewPixels) { + mojo::StructPtr<skia::mojom::Bitmap> input = + ConstructBitmap(SkImageInfo::MakeN32Premul(2, 1), 0, {1, 2, 3, 4}); + + SkBitmap output; + bool ok = + SerializeAndDeserializeFromMojom<skia::mojom::Bitmap>(&input, &output); + EXPECT_FALSE(ok); +} + +TEST(StructTraitsTest, BitmapDeserializeTooManyPixels) { + mojo::StructPtr<skia::mojom::Bitmap> input = ConstructBitmap( + SkImageInfo::MakeN32Premul(1, 1), 0, {1, 2, 3, 4, 5, 6, 7, 8}); + + SkBitmap output; + bool ok = + SerializeAndDeserializeFromMojom<skia::mojom::Bitmap>(&input, &output); + EXPECT_FALSE(ok); } TEST(StructTraitsTest, BlurImageFilterTileMode) { @@ -139,4 +241,102 @@ EXPECT_EQ(input, output); } +TEST(StructTraitsTest, InlineBitmap) { + SkBitmap input; + input.allocPixels(SkImageInfo::MakeN32Premul( + 10, 5, + SkColorSpace::MakeRGB(SkNamedTransferFn::kLinear, + SkNamedGamut::kRec2020))); + input.eraseColor(SK_ColorYELLOW); + input.erase(SK_ColorTRANSPARENT, SkIRect::MakeXYWH(0, 1, 2, 3)); + SkBitmap output; + ASSERT_TRUE(mojo::test::SerializeAndDeserialize<skia::mojom::InlineBitmap>( + &input, &output)); + EXPECT_EQ(input.info(), output.info()); + EXPECT_EQ(input.rowBytes(), output.rowBytes()); + EXPECT_TRUE(gfx::BitmapsAreEqual(input, output)); +} + +TEST(StructTraitsTest, InlineBitmapNull) { + SkBitmap input; + input.setInfo(SkImageInfo::MakeN32Premul( + 10, 5, + SkColorSpace::MakeRGB(SkNamedTransferFn::kLinear, + SkNamedGamut::kRec2020))); + EXPECT_TRUE(input.isNull()); + + // Null input produces a default-initialized SkBitmap. + SkBitmap output; + ASSERT_TRUE(mojo::test::SerializeAndDeserialize<skia::mojom::InlineBitmap>( + &input, &output)); + EXPECT_EQ(output.info().alphaType(), kUnknown_SkAlphaType); + EXPECT_EQ(output.info().colorType(), kUnknown_SkColorType); + EXPECT_EQ(output.rowBytes(), 0u); + EXPECT_TRUE(output.isNull()); +} + +TEST(StructTraitsTest, InlineBitmapSerializeToString) { + SkBitmap input; + input.allocPixels(SkImageInfo::MakeN32Premul(10, 5)); + input.eraseColor(SK_ColorYELLOW); + + // Serialize to string works. + auto serialized = skia::mojom::InlineBitmap::Serialize(&input); + SkBitmap output; + ASSERT_TRUE( + skia::mojom::InlineBitmap::Deserialize(std::move(serialized), &output)); + EXPECT_EQ(input.info(), output.info()); + EXPECT_EQ(input.rowBytes(), output.rowBytes()); + EXPECT_TRUE(gfx::BitmapsAreEqual(input, output)); +} + +TEST(StructTraitsTest, InlineBitmapSerializeInvalidRowBytes) { + SkBitmap input; + input.allocPixels(SkImageInfo::MakeN32Premul(10, 5), 11 * 4); + + // We do not allow sending rowBytes() other than the minRowBytes(). + EXPECT_DEATH(skia::mojom::InlineBitmap::SerializeAsMessage(&input), ""); +} + +TEST(StructTraitsTest, InlineBitmapSerializeInvalidColorType) { + SkBitmap input; + input.allocPixels(SkImageInfo::MakeA8(10, 5)); + + // We do not allow sending colorType() other than the kN32_SkColorType. + EXPECT_DEATH(skia::mojom::InlineBitmap::SerializeAsMessage(&input), ""); +} + +TEST(StructTraitsTest, VerifyInlineBitmapConstruction) { + // Verify that we can manually construct a valid skia.mojom.InlineBitmap and + // deserialize it successfully. + mojo::StructPtr<skia::mojom::InlineBitmap> input = + ConstructInlineBitmap(SkImageInfo::MakeN32Premul(1, 1), {1, 2, 3, 4}); + + SkBitmap output; + bool ok = SerializeAndDeserializeFromMojom<skia::mojom::InlineBitmap>( + &input, &output); + EXPECT_TRUE(ok); +} + +TEST(StructTraitsTest, InlineBitmapDeserializeTooFewBytes) { + mojo::StructPtr<skia::mojom::InlineBitmap> input = + ConstructInlineBitmap(SkImageInfo::MakeN32Premul(2, 1), {1, 2, 3, 4}); + + SkBitmap output; + bool ok = SerializeAndDeserializeFromMojom<skia::mojom::InlineBitmap>( + &input, &output); + EXPECT_FALSE(ok); +} + +TEST(StructTraitsTest, InlineBitmapDeserializeTooManyBytes) { + mojo::StructPtr<skia::mojom::InlineBitmap> input = ConstructInlineBitmap( + SkImageInfo::MakeN32Premul(1, 1), {1, 2, 3, 4, 5, 6, 7, 8}); + + SkBitmap output; + bool ok = SerializeAndDeserializeFromMojom<skia::mojom::InlineBitmap>( + &input, &output); + EXPECT_FALSE(ok); +} + +} // namespace } // namespace skia
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 44dfa14d..cee160d 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -1958,6 +1958,21 @@ ] } ], + "CriticalPersistedTabData": [ + { + "platforms": [ + "android" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "CriticalPersistedTabData" + ] + } + ] + } + ], "CrosSchedulerCore": [ { "platforms": [ @@ -5224,6 +5239,21 @@ ] } ], + "PasswordEditingInSettingsIOS": [ + { + "platforms": [ + "ios" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "EditPasswordsInSettings" + ] + } + ] + } + ], "PasswordScriptsFetching": [ { "platforms": [ @@ -5335,24 +5365,6 @@ ] } ], - "PermissionChip": [ - { - "platforms": [ - "chromeos", - "linux", - "mac", - "windows" - ], - "experiments": [ - { - "name": "Enabled", - "enable_features": [ - "PermissionChip" - ] - } - ] - } - ], "PermissionPromptUICocoa": [ { "platforms": [
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc index 94aca88e..2d8cc77 100644 --- a/third_party/blink/common/features.cc +++ b/third_party/blink/common/features.cc
@@ -84,6 +84,9 @@ const base::Feature kLayoutNGFieldset{"LayoutNGFieldset", base::FEATURE_ENABLED_BY_DEFAULT}; +const base::Feature kLayoutNGTextControl{"LayoutNGTextControl", + base::FEATURE_DISABLED_BY_DEFAULT}; + const base::Feature kFragmentItem{"FragmentItem", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h index d64469f..75f7a27 100644 --- a/third_party/blink/public/common/features.h +++ b/third_party/blink/public/common/features.h
@@ -36,6 +36,7 @@ BLINK_COMMON_EXPORT extern const base::Feature kEditingNG; BLINK_COMMON_EXPORT extern const base::Feature kLayoutNG; BLINK_COMMON_EXPORT extern const base::Feature kLayoutNGFieldset; +BLINK_COMMON_EXPORT extern const base::Feature kLayoutNGTextControl; BLINK_COMMON_EXPORT extern const base::Feature kFragmentItem; BLINK_COMMON_EXPORT extern const base::Feature kMixedContentAutoupgrade; BLINK_COMMON_EXPORT extern const base::Feature kNavigationPredictor;
diff --git a/third_party/blink/public/devtools_protocol/browser_protocol.pdl b/third_party/blink/public/devtools_protocol/browser_protocol.pdl index 442cca5..b6b3ec2 100644 --- a/third_party/blink/public/devtools_protocol/browser_protocol.pdl +++ b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
@@ -6314,8 +6314,6 @@ optional Viewport clip # Capture the screenshot from the surface, rather than the view. Defaults to true. experimental optional boolean fromSurface - # Capture the screenshot beyond the viewport. Defaults to false. - experimental optional boolean captureBeyondViewport returns # Base64-encoded image data. binary data @@ -6823,6 +6821,12 @@ # Frame object. Frame frame + # Fired when opening document to write to. + experimental event documentOpened + parameters + # Frame object. + Frame frame + experimental event frameResized # Fired when a renderer-initiated navigation is requested.
diff --git a/third_party/blink/public/web/web_view.h b/third_party/blink/public/web/web_view.h index 500f7da..537aa00 100644 --- a/third_party/blink/public/web/web_view.h +++ b/third_party/blink/public/web/web_view.h
@@ -119,9 +119,6 @@ // Destroys the WebView. virtual void Close() = 0; - // Sets whether the WebView is focused. - virtual void SetFocus(bool enable) = 0; - // Called to inform WebViewImpl that a local main frame has been attached. // After this call MainFrameImpl() will return a valid frame until it is // detached.
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.cc b/third_party/blink/renderer/core/exported/web_view_impl.cc index ce88fac5..ef3f9af 100644 --- a/third_party/blink/renderer/core/exported/web_view_impl.cc +++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -1787,7 +1787,7 @@ return MainFrameImpl()->GetFrameView()->LayoutViewport()->VerticalScrollbar(); } -void WebViewImpl::SetFocus(bool enable) { +void WebViewImpl::SetPageFocus(bool enable) { if (enable) page_->GetFocusController().SetActive(true); page_->GetFocusController().SetFocused(enable); @@ -1818,15 +1818,7 @@ } else { CancelPagePopup(); - // Clear focus on the currently focused frame if any. - if (!page_) - return; - - LocalFrame* frame = DynamicTo<LocalFrame>(page_->MainFrame()); - if (!frame) - return; - - LocalFrame* focused_frame = FocusedLocalFrameInWidget(); + LocalFrame* focused_frame = page_->GetFocusController().FocusedFrame(); if (focused_frame) { // Finish an ongoing composition to delete the composition node. if (focused_frame->GetInputMethodController().HasComposition()) {
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.h b/third_party/blink/renderer/core/exported/web_view_impl.h index 00b634a8..14ebd013 100644 --- a/third_party/blink/renderer/core/exported/web_view_impl.h +++ b/third_party/blink/renderer/core/exported/web_view_impl.h
@@ -504,6 +504,9 @@ // Indication that the root layer for the main frame widget has changed. void DidChangeRootLayer(bool root_layer_exists); + // Sets the page focus. + void SetPageFocus(bool enable); + // This method is used for testing. // Resizes the unscaled (page scale = 1.0) visual viewport. Normally the // unscaled visual viewport is the same size as the main frame. The passed @@ -535,7 +538,6 @@ // These are temporary methods to allow WebViewFrameWidget to delegate to // WebViewImpl. We expect to eventually move these out. void ThemeChanged(); - void SetFocus(bool enable) override; // Update the target url locally and tell the browser that the target URL has // changed. If |url| is empty, show |fallback_url|.
diff --git a/third_party/blink/renderer/core/exported/web_view_test.cc b/third_party/blink/renderer/core/exported/web_view_test.cc index d5ac55c..8ad2bf3f 100644 --- a/third_party/blink/renderer/core/exported/web_view_test.cc +++ b/third_party/blink/renderer/core/exported/web_view_test.cc
@@ -3154,7 +3154,7 @@ WebString target = WebString::FromUTF8("target"); WebLocalFrameImpl* frame = web_view->MainFrameImpl(); - static_cast<WebView*>(web_view)->SetFocus(true); + web_view->SetPageFocus(true); WebInputMethodController* active_input_method_controller = frame->FrameWidget()->GetActiveWebInputMethodController(); EXPECT_TRUE(TapElementById(WebInputEvent::Type::kGestureTap, target));
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.cc b/third_party/blink/renderer/core/frame/local_frame_view.cc index 8c54148..32217ac 100644 --- a/third_party/blink/renderer/core/frame/local_frame_view.cc +++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -2786,11 +2786,10 @@ // While printing or capturing a paint preview of a document, the paint walk // is done into a special canvas. There is no point doing a normal paint step // (or animations update) when in this mode. - bool is_capturing_layout = - frame_->GetDocument()->IsPrintingOrPaintingPreview(); - bool repainted = false; - if (!is_capturing_layout) - repainted = PaintTree(benchmark_mode); + if (frame_->GetDocument()->IsPrintingOrPaintingPreview()) + return; + + bool repainted = PaintTree(benchmark_mode); if (benchmark_mode == PaintBenchmarkMode::kForcePaintArtifactCompositorUpdate || @@ -2801,79 +2800,74 @@ paint_artifact_compositor_->SetNeedsUpdate(); } - if (!is_capturing_layout) { - bool needed_update = !paint_artifact_compositor_ || - paint_artifact_compositor_->NeedsUpdate(); - PushPaintArtifactToCompositor(repainted); - size_t total_animations_count = 0; - bool current_frame_had_raf = false; - bool next_frame_has_pending_raf = false; - ForAllNonThrottledLocalFrameViews([this, &total_animations_count, - ¤t_frame_had_raf, - &next_frame_has_pending_raf]( - LocalFrameView& frame_view) { - if (auto* scrollable_area = frame_view.GetScrollableArea()) - scrollable_area->UpdateCompositorScrollAnimations(); - if (const auto* animating_scrollable_areas = - frame_view.AnimatingScrollableAreas()) { - for (PaintLayerScrollableArea* area : *animating_scrollable_areas) - area->UpdateCompositorScrollAnimations(); - } - frame_view.GetLayoutView() - ->GetDocument() - .GetDocumentAnimations() - .UpdateAnimations(DocumentLifecycle::kPaintClean, - paint_artifact_compositor_.get()); - Document& document = frame_view.GetLayoutView()->GetDocument(); - total_animations_count += - document.GetDocumentAnimations().GetAnimationsCount(); - current_frame_had_raf |= document.CurrentFrameHadRAF(); - next_frame_has_pending_raf |= document.NextFrameHasPendingRAF(); - }); + bool needed_update = + !paint_artifact_compositor_ || paint_artifact_compositor_->NeedsUpdate(); + PushPaintArtifactToCompositor(repainted); + size_t total_animations_count = 0; + bool current_frame_had_raf = false; + bool next_frame_has_pending_raf = false; + ForAllNonThrottledLocalFrameViews( + [this, &total_animations_count, ¤t_frame_had_raf, + &next_frame_has_pending_raf](LocalFrameView& frame_view) { + if (auto* scrollable_area = frame_view.GetScrollableArea()) + scrollable_area->UpdateCompositorScrollAnimations(); + if (const auto* animating_scrollable_areas = + frame_view.AnimatingScrollableAreas()) { + for (PaintLayerScrollableArea* area : *animating_scrollable_areas) + area->UpdateCompositorScrollAnimations(); + } + frame_view.GetLayoutView() + ->GetDocument() + .GetDocumentAnimations() + .UpdateAnimations(DocumentLifecycle::kPaintClean, + paint_artifact_compositor_.get()); + Document& document = frame_view.GetLayoutView()->GetDocument(); + total_animations_count += + document.GetDocumentAnimations().GetAnimationsCount(); + current_frame_had_raf |= document.CurrentFrameHadRAF(); + next_frame_has_pending_raf |= document.NextFrameHasPendingRAF(); + }); - if (GetLayoutView()->GetDocument().View() && - GetLayoutView()->GetDocument().View()->GetCompositorAnimationHost()) { - GetLayoutView() - ->GetDocument() - .View() - ->GetCompositorAnimationHost() - ->SetAnimationCounts(total_animations_count, current_frame_had_raf, - next_frame_has_pending_raf); - } - - // Initialize animation properties in the newly created paint property - // nodes according to the current animation state. This is mainly for - // the running composited animations which didn't change state during - // above UpdateAnimations() but associated with new paint property nodes. - if (needed_update) { - auto* root_layer = RootCcLayer(); - if (root_layer && root_layer->layer_tree_host()) { - root_layer->layer_tree_host() - ->mutator_host() - ->InitClientAnimationState(); - } - } - - // Notify the controller that the artifact has been pushed and some - // lifecycle state can be freed (such as raster invalidations). - if (paint_controller_) - paint_controller_->FinishCycle(); - - if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) { - auto* root = GetLayoutView()->Compositor()->PaintRootGraphicsLayer(); - if (root) { - ForAllPaintingGraphicsLayers(*root, [](GraphicsLayer& layer) { - // Notify the paint controller that the artifact has been pushed and - // some lifecycle state can be freed (such as raster invalidations). - layer.GetPaintController().FinishCycle(); - }); - } - } - - if (paint_artifact_compositor_) - paint_artifact_compositor_->ClearPropertyTreeChangedState(); + if (GetLayoutView()->GetDocument().View() && + GetLayoutView()->GetDocument().View()->GetCompositorAnimationHost()) { + GetLayoutView() + ->GetDocument() + .View() + ->GetCompositorAnimationHost() + ->SetAnimationCounts(total_animations_count, current_frame_had_raf, + next_frame_has_pending_raf); } + // Initialize animation properties in the newly created paint property + // nodes according to the current animation state. This is mainly for + // the running composited animations which didn't change state during + // above UpdateAnimations() but associated with new paint property nodes. + if (needed_update) { + auto* root_layer = RootCcLayer(); + if (root_layer && root_layer->layer_tree_host()) { + root_layer->layer_tree_host()->mutator_host()->InitClientAnimationState(); + } + } + + // Notify the controller that the artifact has been pushed and some + // lifecycle state can be freed (such as raster invalidations). + if (paint_controller_) + paint_controller_->FinishCycle(); + + if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) { + auto* root = GetLayoutView()->Compositor()->PaintRootGraphicsLayer(); + if (root) { + ForAllPaintingGraphicsLayers(*root, [](GraphicsLayer& layer) { + // Notify the paint controller that the artifact has been pushed and + // some lifecycle state can be freed (such as raster invalidations). + layer.GetPaintController().FinishCycle(); + }); + } + } + + if (paint_artifact_compositor_) + paint_artifact_compositor_->ClearPropertyTreeChangedState(); + if (GetPage()) GetPage()->Animator().ReportFrameAnimations(GetCompositorAnimationHost()); }
diff --git a/third_party/blink/renderer/core/frame/remote_frame.cc b/third_party/blink/renderer/core/frame/remote_frame.cc index 724af9e7..62fd622 100644 --- a/third_party/blink/renderer/core/frame/remote_frame.cc +++ b/third_party/blink/renderer/core/frame/remote_frame.cc
@@ -569,7 +569,8 @@ } void RemoteFrame::SetPageFocus(bool is_focused) { - WebFrame::FromFrame(this)->View()->SetFocus(is_focused); + static_cast<WebViewImpl*>(WebFrame::FromFrame(this)->View()) + ->SetPageFocus(is_focused); } void RemoteFrame::ScrollRectToVisible(
diff --git a/third_party/blink/renderer/core/frame/visual_viewport.cc b/third_party/blink/renderer/core/frame/visual_viewport.cc index 0f5195c..1e01c53b 100644 --- a/third_party/blink/renderer/core/frame/visual_viewport.cc +++ b/third_party/blink/renderer/core/frame/visual_viewport.cc
@@ -599,12 +599,15 @@ needs_paint_property_update_ = true; - scrollbar_layer_horizontal_ = nullptr; - scrollbar_layer_vertical_ = nullptr; if (VisualViewportSuppliesScrollbars() && !GetPage().GetSettings().GetHideScrollbars()) { + DCHECK(!scrollbar_layer_horizontal_); + DCHECK(!scrollbar_layer_vertical_); UpdateScrollbarLayer(kHorizontalScrollbar); UpdateScrollbarLayer(kVerticalScrollbar); + } else { + scrollbar_layer_horizontal_ = nullptr; + scrollbar_layer_vertical_ = nullptr; } // Ensure existing LocalFrameView scrollbars are removed if the visual
diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_base.cc b/third_party/blink/renderer/core/frame/web_frame_widget_base.cc index 76cb295..4a1c508 100644 --- a/third_party/blink/renderer/core/frame/web_frame_widget_base.cc +++ b/third_party/blink/renderer/core/frame/web_frame_widget_base.cc
@@ -1087,6 +1087,14 @@ Client()->ScheduleAnimation(); } +void WebFrameWidgetBase::FocusChanged(bool enable) { + // TODO(crbug.com/689777): FocusChange events are only sent to the MainFrame + // these maybe should goto the local root so that the rest of input messages + // sent to those are preserved in order. + DCHECK(ForMainFrame()); + View()->SetPageFocus(enable); +} + bool WebFrameWidgetBase::ShouldAckSyntheticInputImmediately() { // TODO(bokan): The RequestPresentation API appears not to function in VR. As // a short term workaround for https://crbug.com/940063, ACK input @@ -1195,6 +1203,68 @@ ScrollFocusedEditableElementIntoView(); } +void WebFrameWidgetBase::ApplyVisualPropertiesSizing( + const VisualProperties& visual_properties) { + gfx::Rect new_compositor_viewport_pixel_rect = + visual_properties.compositor_viewport_pixel_rect; + if (ForMainFrame()) { + if (size_ != + widget_base_->DIPsToCeiledBlinkSpace(visual_properties.new_size)) { + // Only hide popups when the size changes. Eg https://crbug.com/761908. + View()->CancelPagePopup(); + } + + if (auto* device_emulator = DeviceEmulator()) { + device_emulator->UpdateVisualProperties(visual_properties); + return; + } + + if (AutoResizeMode()) { + new_compositor_viewport_pixel_rect = gfx::Rect(gfx::ScaleToCeiledSize( + widget_base_->BlinkSpaceToFlooredDIPs(size_.value_or(gfx::Size())), + visual_properties.screen_info.device_scale_factor)); + } + } + + SetWindowSegments(visual_properties.root_widget_window_segments); + + widget_base_->UpdateSurfaceAndScreenInfo( + visual_properties.local_surface_id.value_or(viz::LocalSurfaceId()), + new_compositor_viewport_pixel_rect, visual_properties.screen_info); + + // Store this even when auto-resizing, it is the size of the full viewport + // used for clipping, and this value is propagated down the Widget + // hierarchy via the VisualProperties waterfall. + widget_base_->SetVisibleViewportSizeInDIPs( + visual_properties.visible_viewport_size); + + if (ForMainFrame()) { + if (!AutoResizeMode()) { + size_ = widget_base_->DIPsToCeiledBlinkSpace(visual_properties.new_size); + + View()->ResizeWithBrowserControls( + size_.value(), + widget_base_->DIPsToCeiledBlinkSpace( + widget_base_->VisibleViewportSizeInDIPs()), + visual_properties.browser_controls_params); + } + } else { + // Widgets in a WebView's frame tree without a local main frame + // set the size of the WebView to be the |visible_viewport_size|, in order + // to limit compositing in (out of process) child frames to what is visible. + // + // Note that child frames in the same process/WebView frame tree as the + // main frame do not do this in order to not clobber the source of truth in + // the main frame. + if (!View()->MainFrameImpl()) { + View()->Resize(widget_base_->DIPsToCeiledBlinkSpace( + widget_base_->VisibleViewportSizeInDIPs())); + } + + Resize(widget_base_->DIPsToCeiledBlinkSpace(visual_properties.new_size)); + } +} + void WebFrameWidgetBase::ScheduleAnimationForWebTests() { Client()->ScheduleAnimationForWebTests(); } @@ -2699,6 +2769,21 @@ return HitTestResultAt(point).GetScrollableContainerId(); } +bool WebFrameWidgetBase::ShouldHandleImeEvents() { + if (ForMainFrame()) { + return HasFocus(); + } else { + // TODO(ekaramad): main frame widget returns true only if it has focus. + // We track page focus in all WebViews on the page but the WebFrameWidgets + // corresponding to child local roots do not get the update. For now, this + // method returns true when the WebFrameWidget is for a child local frame, + // i.e., IME events will be processed regardless of page focus. We should + // revisit this after page focus for OOPIFs has been fully resolved + // (https://crbug.com/689777). + return LocalRootImpl(); + } +} + void WebFrameWidgetBase::SetEditCommandsForNextKeyEvent( Vector<mojom::blink::EditCommandPtr> edit_commands) { edit_commands_ = std::move(edit_commands);
diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_base.h b/third_party/blink/renderer/core/frame/web_frame_widget_base.h index 9105317..485423d 100644 --- a/third_party/blink/renderer/core/frame/web_frame_widget_base.h +++ b/third_party/blink/renderer/core/frame/web_frame_widget_base.h
@@ -206,6 +206,7 @@ bool IsProvisional() override; uint64_t GetScrollableContainerIdAt( const gfx::PointF& point_in_dips) override; + bool ShouldHandleImeEvents() override; void SetEditCommandsForNextKeyEvent( Vector<mojom::blink::EditCommandPtr> edit_commands) override; @@ -408,6 +409,7 @@ void SetCursorVisibilityState(bool is_visible) override; blink::FrameWidget* FrameWidget() override { return this; } void ScheduleAnimation() override; + void FocusChanged(bool enable) override; bool ShouldAckSyntheticInputImmediately() override; void UpdateVisualProperties( const VisualProperties& visual_properties) override; @@ -636,10 +638,6 @@ ScreenMetricsEmulator* DeviceEmulator(); - // Called during |UpdateVisualProperties| to apply the new size to the widget. - virtual void ApplyVisualPropertiesSizing( - const VisualProperties& visual_properties) = 0; - // Calculates the selection bounds in the root frame. Returns bounds unchanged // when there is no focused frame or no selection. void CalculateSelectionBounds(gfx::Rect& anchor_in_root_frame, @@ -731,6 +729,9 @@ HitTestResult HitTestResultForRootFramePos( const FloatPoint& pos_in_root_frame); + // Called during |UpdateVisualProperties| to apply the new size to the widget. + void ApplyVisualPropertiesSizing(const VisualProperties& visual_properties); + // Returns the current state of synchronous resize mode for testing. bool SynchronousResizeModeForTestingEnabled();
diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc index 234913d..dcec47b 100644 --- a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc +++ b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
@@ -307,17 +307,6 @@ view->SetLayoutSize(WebSize(layout_size)); } -bool WebFrameWidgetImpl::ShouldHandleImeEvents() { - // TODO(ekaramad): WebViewWidgetImpl returns true only if it has focus. - // We track page focus in all RenderViews on the page but - // the RenderWidgets corresponding to child local roots do not get the - // update. For now, this method returns true when the RenderWidget is for a - // child local frame, i.e., IME events will be processed regardless of page - // focus. We should revisit this after page focus for OOPIFs has been fully - // resolved (https://crbug.com/689777). - return LocalRootImpl(); -} - bool WebFrameWidgetImpl::ScrollFocusedEditableElementIntoView() { Element* element = FocusedElement(); if (!element || !WebElement(element).IsEditable()) @@ -334,52 +323,6 @@ return true; } -void WebFrameWidgetImpl::FocusChanged(bool enable) { - if (enable) - GetPage()->GetFocusController().SetActive(true); - GetPage()->GetFocusController().SetFocused(enable); - if (enable) { - LocalFrame* focused_frame = GetPage()->GetFocusController().FocusedFrame(); - if (focused_frame) { - Element* element = focused_frame->GetDocument()->FocusedElement(); - if (element && focused_frame->Selection() - .ComputeVisibleSelectionInDOMTreeDeprecated() - .IsNone()) { - // If the selection was cleared while the WebView was not - // focused, then the focus element shows with a focus ring but - // no caret and does respond to keyboard inputs. - focused_frame->GetDocument()->UpdateStyleAndLayoutTree(); - if (element->IsTextControl()) { - element->UpdateFocusAppearance(SelectionBehaviorOnFocus::kRestore); - } else if (HasEditableStyle(*element)) { - // updateFocusAppearance() selects all the text of - // contentseditable DIVs. So we set the selection explicitly - // instead. Note that this has the side effect of moving the - // caret back to the beginning of the text. - Position position(element, 0); - focused_frame->Selection().SetSelectionAndEndTyping( - SelectionInDOMTree::Builder().Collapse(position).Build()); - } - } - } - } else { - LocalFrame* focused_frame = FocusedLocalFrameInWidget(); - if (focused_frame) { - // Finish an ongoing composition to delete the composition node. - if (focused_frame->GetInputMethodController().HasComposition()) { - // TODO(editing-dev): The use of - // UpdateStyleAndLayout needs to be audited. - // See http://crbug.com/590369 for more details. - focused_frame->GetDocument()->UpdateStyleAndLayout( - DocumentUpdateReason::kFocus); - - focused_frame->GetInputMethodController().FinishComposingText( - InputMethodController::kKeepSelection); - } - } - } -} - WebInputEventResult WebFrameWidgetImpl::HandleGestureEvent( const WebGestureEvent& event) { DCHECK(Client()); @@ -512,33 +455,4 @@ rect_to_scroll = PhysicalRect(maximal_rect); } -void WebFrameWidgetImpl::ApplyVisualPropertiesSizing( - const VisualProperties& visual_properties) { - SetWindowSegments(visual_properties.root_widget_window_segments); - widget_base_->UpdateSurfaceAndScreenInfo( - visual_properties.local_surface_id.value_or(viz::LocalSurfaceId()), - visual_properties.compositor_viewport_pixel_rect, - visual_properties.screen_info); - - // Store this even when auto-resizing, it is the size of the full viewport - // used for clipping, and this value is propagated down the Widget - // hierarchy via the VisualProperties waterfall. - widget_base_->SetVisibleViewportSizeInDIPs( - visual_properties.visible_viewport_size); - - // Widgets in a WebView's frame tree without a local main frame - // set the size of the WebView to be the |visible_viewport_size|, in order - // to limit compositing in (out of process) child frames to what is visible. - // - // Note that child frames in the same process/WebView frame tree as the - // main frame do not do this in order to not clobber the source of truth in - // the main frame. - if (!View()->MainFrameImpl()) { - View()->Resize(widget_base_->DIPsToCeiledBlinkSpace( - widget_base_->VisibleViewportSizeInDIPs())); - } - - Resize(widget_base_->DIPsToCeiledBlinkSpace(visual_properties.new_size)); -} - } // namespace blink
diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_impl.h b/third_party/blink/renderer/core/frame/web_frame_widget_impl.h index d567219..7fc8b6c6 100644 --- a/third_party/blink/renderer/core/frame/web_frame_widget_impl.h +++ b/third_party/blink/renderer/core/frame/web_frame_widget_impl.h
@@ -93,14 +93,6 @@ // WebFrameWidgetBase overrides: void DidCreateLocalRootView() override; - void ApplyVisualPropertiesSizing( - const VisualProperties& visual_properties) override; - - // FrameWidget overrides: - bool ShouldHandleImeEvents() override; - - // WidgetBaseClient overrides: - void FocusChanged(bool enable) override; void UpdateMainFrameLayoutSize();
diff --git a/third_party/blink/renderer/core/frame/web_view_frame_widget.cc b/third_party/blink/renderer/core/frame/web_view_frame_widget.cc index 47d8837..8e9e17ec 100644 --- a/third_party/blink/renderer/core/frame/web_view_frame_widget.cc +++ b/third_party/blink/renderer/core/frame/web_view_frame_widget.cc
@@ -92,14 +92,6 @@ web_view_->Resize(size); } -void WebViewFrameWidget::FocusChanged(bool enable) { - web_view_->SetFocus(enable); -} - -bool WebViewFrameWidget::ShouldHandleImeEvents() { - return HasFocus(); -} - bool WebViewFrameWidget::ScrollFocusedEditableElementIntoView() { return web_view_->ScrollFocusedEditableElementIntoView(); } @@ -288,69 +280,4 @@ return event_result; } -void WebViewFrameWidget::ApplyVisualPropertiesSizing( - const VisualProperties& visual_properties) { - if (size_ != - widget_base_->DIPsToCeiledBlinkSpace(visual_properties.new_size)) { - // Only hide popups when the size changes. Eg https://crbug.com/761908. - web_view_->CancelPagePopup(); - } - - if (auto* device_emulator = DeviceEmulator()) { - device_emulator->UpdateVisualProperties(visual_properties); - return; - } - - SetWindowSegments(visual_properties.root_widget_window_segments); - - // We can ignore browser-initialized resizing during synchronous - // (renderer-controlled) mode, unless it is switching us to/from - // fullsreen mode or changing the device scale factor. - bool ignore_resize = SynchronousResizeModeForTestingEnabled(); - if (ignore_resize) { - // TODO(danakj): Does the browser actually change DSF inside a web test?? - // TODO(danakj): Isn't the display mode check redundant with the - // fullscreen one? - if (visual_properties.is_fullscreen_granted != IsFullscreenGranted() || - visual_properties.screen_info.device_scale_factor != - widget_base_->GetScreenInfo().device_scale_factor) - ignore_resize = false; - } - - // When controlling the size in the renderer, we should ignore sizes given - // by the browser IPC here. - // TODO(danakj): There are many things also being ignored that aren't the - // widget's size params. It works because tests that use this mode don't - // change those parameters, I guess. But it's more complicated then because - // it looks like they are related to sync resize mode. Let's move them out - // of this block. - gfx::Rect new_compositor_viewport_pixel_rect = - visual_properties.compositor_viewport_pixel_rect; - if (AutoResizeMode()) { - new_compositor_viewport_pixel_rect = gfx::Rect(gfx::ScaleToCeiledSize( - widget_base_->BlinkSpaceToFlooredDIPs(size_.value_or(gfx::Size())), - visual_properties.screen_info.device_scale_factor)); - } - - widget_base_->UpdateSurfaceAndScreenInfo( - visual_properties.local_surface_id.value_or(viz::LocalSurfaceId()), - new_compositor_viewport_pixel_rect, visual_properties.screen_info); - - // Store this even when auto-resizing, it is the size of the full viewport - // used for clipping, and this value is propagated down the Widget - // hierarchy via the VisualProperties waterfall. - widget_base_->SetVisibleViewportSizeInDIPs( - visual_properties.visible_viewport_size); - - if (!AutoResizeMode()) { - size_ = widget_base_->DIPsToCeiledBlinkSpace(visual_properties.new_size); - - View()->ResizeWithBrowserControls( - size_.value(), - widget_base_->DIPsToCeiledBlinkSpace( - widget_base_->VisibleViewportSizeInDIPs()), - visual_properties.browser_controls_params); - } -} - } // namespace blink
diff --git a/third_party/blink/renderer/core/frame/web_view_frame_widget.h b/third_party/blink/renderer/core/frame/web_view_frame_widget.h index 5071f91..1d46f94 100644 --- a/third_party/blink/renderer/core/frame/web_view_frame_widget.h +++ b/third_party/blink/renderer/core/frame/web_view_frame_widget.h
@@ -68,16 +68,6 @@ // WebFrameWidget overrides: bool ScrollFocusedEditableElementIntoView() override; - // WebFrameWidgetBase overrides: - void ApplyVisualPropertiesSizing( - const VisualProperties& visual_properties) override; - - // FrameWidget overrides: - bool ShouldHandleImeEvents() override; - - // WidgetBaseClient overrides: - void FocusChanged(bool enabled) override; - private: // PageWidgetEventHandler overrides: WebInputEventResult HandleGestureEvent(const WebGestureEvent&) override;
diff --git a/third_party/blink/renderer/core/inspector/inspector_page_agent.cc b/third_party/blink/renderer/core/inspector/inspector_page_agent.cc index c245ada..a8042899 100644 --- a/third_party/blink/renderer/core/inspector/inspector_page_agent.cc +++ b/third_party/blink/renderer/core/inspector/inspector_page_agent.cc
@@ -947,6 +947,13 @@ GetFrontend()->frameNavigated(BuildObjectForFrame(loader->GetFrame())); } +void InspectorPageAgent::DidOpenDocument(LocalFrame* frame, + DocumentLoader* loader) { + GetFrontend()->documentOpened(BuildObjectForFrame(loader->GetFrame())); + LifecycleEvent(frame, loader, "init", + base::TimeTicks::Now().since_origin().InSecondsF()); +} + void InspectorPageAgent::FrameAttachedToParent(LocalFrame* frame) { Frame* parent_frame = frame->Tree().Parent(); std::unique_ptr<SourceLocation> location =
diff --git a/third_party/blink/renderer/core/inspector/inspector_page_agent.h b/third_party/blink/renderer/core/inspector/inspector_page_agent.h index faeb95d4..2d4d6ae 100644 --- a/third_party/blink/renderer/core/inspector/inspector_page_agent.h +++ b/third_party/blink/renderer/core/inspector/inspector_page_agent.h
@@ -175,6 +175,7 @@ void DomContentLoadedEventFired(LocalFrame*); void LoadEventFired(LocalFrame*); void WillCommitLoad(LocalFrame*, DocumentLoader*); + void DidOpenDocument(LocalFrame*, DocumentLoader*); void FrameAttachedToParent(LocalFrame*); void FrameDetachedFromParent(LocalFrame*, FrameDetachType); void FrameStartedLoading(LocalFrame*);
diff --git a/third_party/blink/renderer/core/layout/layout_object.cc b/third_party/blink/renderer/core/layout/layout_object.cc index daed77a..df934163 100644 --- a/third_party/blink/renderer/core/layout/layout_object.cc +++ b/third_party/blink/renderer/core/layout/layout_object.cc
@@ -148,6 +148,26 @@ return nullptr; } +// Returns the parent LayoutObject, or nullptr. If this LayoutObject is a +// LayoutView, it will return the owning LayoutObject in the containing frame, +// with the exception that it will not traverse from the LayoutView in a frame +// which would be throttled during a full lifecycle update, to the owning +// LayoutObject in the containing frame. This is an optimization to avoid +// propagating paint invalidation flags into the parent frame; it's unnecessary +// because the to-be-throttled frame won't paint. +LayoutObject* ParentCrossingFramesForPaintInvalidation( + const LayoutObject* object) { + if (IsA<LayoutView>(object)) { + LocalFrameView* frame_view = object->GetFrameView(); + if (frame_view->CanThrottleRendering()) { + frame_view->SetPrePaintSkippedWhileThrottled(); + return nullptr; + } + return object->GetFrame()->OwnerLayoutObject(); + } + return object->Parent(); +} + } // namespace static int g_allow_destroying_layout_object_in_finalizer = 0; @@ -817,14 +837,15 @@ auto FindContainer = [](const LayoutObject& object) -> const LayoutObject* { if (object.IsRenderedLegend()) return LayoutFieldset::FindLegendContainingBlock(To<LayoutBox>(object)); - // Use ContainingBlock() instead of ParentCrossingFrames() for floating - // objects to omit any self-painting layers of inline objects that don't - // paint the floating object. This is only needed for inline-level floats - // not managed by LayoutNG. LayoutNG floats are painted by the correct - // painting layer. + // Use ContainingBlock() instead of Parent() for floating objects to omit + // any self-painting layers of inline objects that don't paint the floating + // object. This is only needed for inline-level floats not managed by + // LayoutNG. LayoutNG floats are painted by the correct painting layer. if (object.IsFloating() && !object.IsInLayoutNGInlineFormattingContext()) return object.ContainingBlock(); - return object.ParentCrossingFrames(); + if (IsA<LayoutView>(object)) + return object.GetFrame()->OwnerLayoutObject(); + return object.Parent(); }; for (const LayoutObject* current = this; current; @@ -3406,13 +3427,6 @@ return Parent(); } -inline LayoutObject* LayoutObject::ParentCrossingFrames() const { - NOT_DESTROYED(); - if (IsA<LayoutView>(this)) - return GetFrame()->OwnerLayoutObject(); - return Parent(); -} - inline void LayoutObject::ClearLayoutRootIfNeeded() const { NOT_DESTROYED(); if (LocalFrameView* view = GetFrameView()) { @@ -3615,7 +3629,7 @@ GetFrameView()->SetIntersectionObservationState(LocalFrameView::kDesired); bitfields_.SetNeedsPaintPropertyUpdate(true); - if (auto* ancestor = ParentCrossingFrames()) + if (auto* ancestor = ParentCrossingFramesForPaintInvalidation(this)) ancestor->SetDescendantNeedsPaintPropertyUpdate(); } @@ -3623,17 +3637,17 @@ NOT_DESTROYED(); for (auto* ancestor = this; ancestor && !ancestor->DescendantNeedsPaintPropertyUpdate(); - ancestor = ancestor->ParentCrossingFrames()) { + ancestor = ParentCrossingFramesForPaintInvalidation(ancestor)) { ancestor->bitfields_.SetDescendantNeedsPaintPropertyUpdate(true); } } void LayoutObject::SetAncestorsNeedPaintPropertyUpdateForMainThreadScrolling() { NOT_DESTROYED(); - LayoutObject* ancestor = ParentCrossingFrames(); + LayoutObject* ancestor = ParentCrossingFramesForPaintInvalidation(this); while (ancestor) { ancestor->SetNeedsPaintPropertyUpdate(); - ancestor = ancestor->ParentCrossingFrames(); + ancestor = ParentCrossingFramesForPaintInvalidation(ancestor); } } @@ -4274,10 +4288,10 @@ NOT_DESTROYED(); DCHECK(ShouldCheckForPaintInvalidation()); bitfields_.SetShouldCheckGeometryForPaintInvalidation(true); - for (auto* ancestor = ParentCrossingFrames(); + for (auto* ancestor = ParentCrossingFramesForPaintInvalidation(this); ancestor && !ancestor->DescendantShouldCheckGeometryForPaintInvalidation(); - ancestor = ancestor->ParentCrossingFrames()) { + ancestor = ParentCrossingFramesForPaintInvalidation(ancestor)) { ancestor->bitfields_.SetDescendantShouldCheckGeometryForPaintInvalidation( true); } @@ -4343,9 +4357,9 @@ GetFrameView()->ScheduleVisualUpdateForPaintInvalidationIfNeeded(); bitfields_.SetShouldCheckForPaintInvalidation(true); - for (LayoutObject* parent = ParentCrossingFrames(); + for (LayoutObject* parent = ParentCrossingFramesForPaintInvalidation(this); parent && !parent->ShouldCheckForPaintInvalidation(); - parent = parent->ParentCrossingFrames()) { + parent = ParentCrossingFramesForPaintInvalidation(parent)) { parent->bitfields_.SetShouldCheckForPaintInvalidation(true); } } @@ -4521,13 +4535,13 @@ return; } - LayoutObject* obj = ParentCrossingFrames(); + LayoutObject* obj = ParentCrossingFramesForPaintInvalidation(this); while (obj && !obj->DescendantEffectiveAllowedTouchActionChanged()) { obj->bitfields_.SetDescendantEffectiveAllowedTouchActionChanged(true); if (obj->ChildPrePaintBlockedByDisplayLock()) break; - obj = obj->ParentCrossingFrames(); + obj = ParentCrossingFramesForPaintInvalidation(obj); } } @@ -4542,13 +4556,13 @@ return; } - LayoutObject* obj = ParentCrossingFrames(); + LayoutObject* obj = ParentCrossingFramesForPaintInvalidation(this); while (obj && !obj->DescendantBlockingWheelEventHandlerChanged()) { obj->bitfields_.SetDescendantBlockingWheelEventHandlerChanged(true); if (obj->ChildPrePaintBlockedByDisplayLock()) break; - obj = obj->ParentCrossingFrames(); + obj = ParentCrossingFramesForPaintInvalidation(obj); } }
diff --git a/third_party/blink/renderer/core/layout/layout_object.h b/third_party/blink/renderer/core/layout/layout_object.h index 65eef32..39baae8c 100644 --- a/third_party/blink/renderer/core/layout/layout_object.h +++ b/third_party/blink/renderer/core/layout/layout_object.h
@@ -3599,10 +3599,6 @@ static bool IsAllowedToModifyLayoutTreeStructure(Document&); - // Returns the parent LayoutObject, or nullptr. This has a special case for - // LayoutView to return the owning LayoutObject in the containing frame. - inline LayoutObject* ParentCrossingFrames() const; - void UpdateImageObservers(const ComputedStyle* old_style, const ComputedStyle* new_style); void UpdateFirstLineImageObservers(const ComputedStyle* new_style);
diff --git a/third_party/blink/renderer/core/loader/frame_loader.cc b/third_party/blink/renderer/core/loader/frame_loader.cc index 8c117e4fb..0c4725a 100644 --- a/third_party/blink/renderer/core/loader/frame_loader.cc +++ b/third_party/blink/renderer/core/loader/frame_loader.cc
@@ -350,8 +350,7 @@ } void FrameLoader::DidExplicitOpen() { - probe::LifecycleEvent(frame_, GetDocumentLoader(), "init", - base::TimeTicks::Now().since_origin().InSecondsF()); + probe::DidOpenDocument(frame_, GetDocumentLoader()); if (empty_document_status_ == EmptyDocumentStatus::kOnlyEmpty) empty_document_status_ = EmptyDocumentStatus::kOnlyEmptyButExplicitlyOpened;
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc b/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc index c61e07f..0eaa2e2 100644 --- a/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc +++ b/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc
@@ -411,14 +411,15 @@ auto* iframe_transform = ChildDocument().getElementById("iframeTransform")->GetLayoutObject(); - // Invalidate properties in the iframe; invalidations will be propagated from - // the throttled frame into the embedding document. + // Invalidate properties in the iframe; invalidations will not be propagated + // into the embedding document while the iframe is throttle-able. iframe_transform->SetNeedsPaintPropertyUpdate(); iframe_transform->SetShouldCheckForPaintInvalidation(); EXPECT_FALSE(GetDocument().GetLayoutView()->NeedsPaintPropertyUpdate()); - EXPECT_TRUE( + EXPECT_FALSE( GetDocument().GetLayoutView()->DescendantNeedsPaintPropertyUpdate()); - EXPECT_TRUE(GetDocument().GetLayoutView()->ShouldCheckForPaintInvalidation()); + EXPECT_FALSE( + GetDocument().GetLayoutView()->ShouldCheckForPaintInvalidation()); EXPECT_FALSE(transform->NeedsPaintPropertyUpdate()); EXPECT_FALSE(transform->DescendantNeedsPaintPropertyUpdate()); EXPECT_FALSE(transform->ShouldCheckForPaintInvalidation()); @@ -438,16 +439,14 @@ EXPECT_FALSE(transform->DescendantNeedsPaintPropertyUpdate()); // A full lifecycle update with the iframe throttled will clear flags in the - // top document, but not in the throttled iframe. The iframe's LayoutView - // will be marked for paint property update because it was skipped while - // paint properties were updated in the embedding document. + // top document, but not in the throttled iframe. UpdateAllLifecyclePhasesForTest(); EXPECT_FALSE(GetDocument().GetLayoutView()->NeedsPaintPropertyUpdate()); EXPECT_FALSE( GetDocument().GetLayoutView()->DescendantNeedsPaintPropertyUpdate()); EXPECT_FALSE(transform->NeedsPaintPropertyUpdate()); EXPECT_FALSE(transform->DescendantNeedsPaintPropertyUpdate()); - EXPECT_TRUE(iframe_layout_view->NeedsPaintPropertyUpdate()); + EXPECT_FALSE(iframe_layout_view->NeedsPaintPropertyUpdate()); EXPECT_TRUE(iframe_layout_view->DescendantNeedsPaintPropertyUpdate()); EXPECT_TRUE(iframe_layout_view->ShouldCheckForPaintInvalidation()); EXPECT_TRUE(iframe_transform->NeedsPaintPropertyUpdate());
diff --git a/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc b/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc index cae05e9..46b2910 100644 --- a/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc +++ b/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc
@@ -248,7 +248,6 @@ if (frame_view.ShouldThrottleRendering()) { // Skip the throttled frame, and set dirty bits that will be applied when it // becomes unthrottled. - frame_view.SetPrePaintSkippedWhileThrottled(); if (LayoutView* layout_view = frame_view.GetLayoutView()) { if (needs_tree_builder_context_update) { layout_view->AddSubtreePaintPropertyUpdateReason(
diff --git a/third_party/blink/renderer/core/probe/core_probes.json5 b/third_party/blink/renderer/core/probe/core_probes.json5 index 277a2f6..f15a5dc7 100644 --- a/third_party/blink/renderer/core/probe/core_probes.json5 +++ b/third_party/blink/renderer/core/probe/core_probes.json5
@@ -191,6 +191,7 @@ "DidResizeMainFrame", "DidRunJavaScriptDialog", "DomContentLoadedEventFired", + "DidOpenDocument", "FileChooserOpened", "FrameAttachedToParent", "FrameClearedScheduledNavigation",
diff --git a/third_party/blink/renderer/core/probe/core_probes.pidl b/third_party/blink/renderer/core/probe/core_probes.pidl index 8d5721dc..2c6c58cc 100644 --- a/third_party/blink/renderer/core/probe/core_probes.pidl +++ b/third_party/blink/renderer/core/probe/core_probes.pidl
@@ -118,6 +118,7 @@ void WillCommitLoad([Keep] LocalFrame*, DocumentLoader*); void DidCommitLoad([Keep] LocalFrame*, DocumentLoader*); void DidNavigateWithinDocument([Keep] LocalFrame*); + void DidOpenDocument([Keep] LocalFrame*, DocumentLoader*); void FrameDocumentUpdated([Keep] LocalFrame*); void FrameOwnerContentUpdated([Keep] LocalFrame*, HTMLFrameOwnerElement*); void FrameStartedLoading([Keep] LocalFrame*);
diff --git a/third_party/blink/renderer/core/svg/graphics/svg_image.cc b/third_party/blink/renderer/core/svg/graphics/svg_image.cc index 83c8c45..30e7914 100644 --- a/third_party/blink/renderer/core/svg/graphics/svg_image.cc +++ b/third_party/blink/renderer/core/svg/graphics/svg_image.cc
@@ -406,8 +406,7 @@ adjusted_src_size.Scale(residual_scale.Width(), residual_scale.Height()); scaled_src.SetSize(adjusted_src_size); - DrawInternal(canvas, flags, dst_rect, scaled_src, kRespectImageOrientation, - kClampImageToSourceRect, url); + DrawInternal(canvas, flags, dst_rect, scaled_src, url); }); } @@ -549,19 +548,16 @@ return result; } -void SVGImage::Draw( - cc::PaintCanvas* canvas, - const PaintFlags& flags, - const FloatRect& dst_rect, - const FloatRect& src_rect, - RespectImageOrientationEnum should_respect_image_orientation, - ImageClampingMode clamp_mode, - ImageDecodingMode) { +void SVGImage::Draw(cc::PaintCanvas* canvas, + const PaintFlags& flags, + const FloatRect& dst_rect, + const FloatRect& src_rect, + RespectImageOrientationEnum, + ImageClampingMode, + ImageDecodingMode) { if (!page_) return; - - DrawInternal(canvas, flags, dst_rect, src_rect, - should_respect_image_orientation, clamp_mode, NullURL()); + DrawInternal(canvas, flags, dst_rect, src_rect, NullURL()); } sk_sp<PaintRecord> SVGImage::PaintRecordForCurrentFrame(const KURL& url) { @@ -597,8 +593,6 @@ const PaintFlags& flags, const FloatRect& dst_rect, const FloatRect& src_rect, - RespectImageOrientationEnum, - ImageClampingMode, const KURL& url) { { PaintCanvasAutoRestore ar(canvas, false);
diff --git a/third_party/blink/renderer/core/svg/graphics/svg_image.h b/third_party/blink/renderer/core/svg/graphics/svg_image.h index 8ca57ef..92855c4 100644 --- a/third_party/blink/renderer/core/svg/graphics/svg_image.h +++ b/third_party/blink/renderer/core/svg/graphics/svg_image.h
@@ -146,8 +146,8 @@ void Draw(cc::PaintCanvas*, const cc::PaintFlags&, - const FloatRect& from_rect, - const FloatRect& to_rect, + const FloatRect& dst_rect, + const FloatRect& src_rect, RespectImageOrientationEnum, ImageClampingMode, ImageDecodingMode) override; @@ -179,10 +179,8 @@ void DrawInternal(cc::PaintCanvas*, const cc::PaintFlags&, - const FloatRect& from_rect, - const FloatRect& to_rect, - RespectImageOrientationEnum, - ImageClampingMode, + const FloatRect& dst_rect, + const FloatRect& src_rect, const KURL&); template <typename Func>
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object.cc b/third_party/blink/renderer/modules/accessibility/ax_object.cc index 11742bb..cdd294e 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_object.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_object.cc
@@ -422,7 +422,6 @@ {ax::mojom::blink::Role::kSearch, "Search"}, {ax::mojom::blink::Role::kSearchBox, "SearchBox"}, {ax::mojom::blink::Role::kSlider, "Slider"}, - {ax::mojom::blink::Role::kSliderThumb, "SliderThumb"}, {ax::mojom::blink::Role::kSpinButton, "SpinButton"}, {ax::mojom::blink::Role::kSplitter, "Splitter"}, {ax::mojom::blink::Role::kStaticText, "StaticText"}, @@ -4469,7 +4468,6 @@ case ax::mojom::blink::Role::kSlider: case ax::mojom::blink::Role::kSpinButton: case ax::mojom::blink::Role::kStatus: - case ax::mojom::blink::Role::kSliderThumb: case ax::mojom::blink::Role::kSuggestion: case ax::mojom::blink::Role::kSvgRoot: case ax::mojom::blink::Role::kTable:
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc index 24a26387..a3ccdd4 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
@@ -669,9 +669,6 @@ AXObject* obj = nullptr; switch (role) { - case ax::mojom::Role::kSliderThumb: - obj = MakeGarbageCollected<AXSliderThumb>(*this); - break; case ax::mojom::Role::kMenuListPopup: DCHECK(use_ax_menu_list_); obj = MakeGarbageCollected<AXMenuListPopup>(*this);
diff --git a/third_party/blink/renderer/modules/accessibility/ax_slider.cc b/third_party/blink/renderer/modules/accessibility/ax_slider.cc index fd3eab74..2290318 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_slider.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_slider.cc
@@ -75,36 +75,6 @@ } } -void AXSlider::AddChildren() { - DCHECK(!IsDetached()); - DCHECK(!have_children_); - have_children_ = true; - - AXObjectCacheImpl& cache = AXObjectCache(); - AXObject* thumb = cache.GetOrCreate(ax::mojom::Role::kSliderThumb); - DCHECK(thumb); - thumb->SetParent(this); - - // Before actually adding the value indicator to the hierarchy, - // allow the platform to make a final decision about it. - if (!thumb->AccessibilityIsIncludedInTree()) { - cache.Remove(thumb->AXObjectID()); - return; - } - - children_.push_back(thumb); -} - -AXObject* AXSlider::ElementAccessibilityHitTest(const IntPoint& point) const { - if (HasChildren()) { - DCHECK(children_.size() == 1); - if (children_[0]->GetBoundsInFrameCoordinates().Contains(point)) - return children_[0].Get(); - } - - return AXObjectCache().GetOrCreate(layout_object_); -} - bool AXSlider::OnNativeSetValueAction(const String& value) { HTMLInputElement* input = GetInputElement(); @@ -131,27 +101,4 @@ return To<HTMLInputElement>(layout_object_->GetNode()); } -AXSliderThumb::AXSliderThumb(AXObjectCacheImpl& ax_object_cache) - : AXMockObject(ax_object_cache) {} - -LayoutObject* AXSliderThumb::LayoutObjectForRelativeBounds() const { - if (!parent_) - return nullptr; - - LayoutObject* slider_layout_object = parent_->GetLayoutObject(); - if (!slider_layout_object) - return nullptr; - Element* thumb_element = - To<Element>(slider_layout_object->GetNode()) - ->UserAgentShadowRoot() - ->getElementById(shadow_element_names::kIdSliderThumb); - DCHECK(thumb_element); - return thumb_element->GetLayoutObject(); -} - -bool AXSliderThumb::ComputeAccessibilityIsIgnored( - IgnoredReasons* ignored_reasons) const { - return AccessibilityIsIgnoredByDefault(ignored_reasons); -} - } // namespace blink
diff --git a/third_party/blink/renderer/modules/accessibility/ax_slider.h b/third_party/blink/renderer/modules/accessibility/ax_slider.h index 1dd6000..982bbbe 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_slider.h +++ b/third_party/blink/renderer/modules/accessibility/ax_slider.h
@@ -45,36 +45,17 @@ private: HTMLInputElement* GetInputElement() const; - AXObject* ElementAccessibilityHitTest(const IntPoint&) const final; ax::mojom::Role DetermineAccessibilityRole() final; bool IsSlider() const final { return true; } bool IsControl() const final { return true; } - void AddChildren() final; - bool OnNativeSetValueAction(const String&) final; AccessibilityOrientation Orientation() const final; DISALLOW_COPY_AND_ASSIGN(AXSlider); }; -class AXSliderThumb final : public AXMockObject { - public: - explicit AXSliderThumb(AXObjectCacheImpl&); - ~AXSliderThumb() override = default; - - ax::mojom::Role RoleValue() const override { - return ax::mojom::Role::kSliderThumb; - } - - private: - bool ComputeAccessibilityIsIgnored(IgnoredReasons* = nullptr) const override; - LayoutObject* LayoutObjectForRelativeBounds() const override; - - DISALLOW_COPY_AND_ASSIGN(AXSliderThumb); -}; - } // namespace blink #endif // THIRD_PARTY_BLINK_RENDERER_MODULES_ACCESSIBILITY_AX_SLIDER_H_
diff --git a/third_party/blink/renderer/modules/content_index/content_index.cc b/third_party/blink/renderer/modules/content_index/content_index.cc index 30be307..ef52fa5 100644 --- a/third_party/blink/renderer/modules/content_index/content_index.cc +++ b/third_party/blink/renderer/modules/content_index/content_index.cc
@@ -118,14 +118,22 @@ ScriptPromiseResolver* resolver, mojom::blink::ContentDescriptionPtr description, const Vector<gfx::Size>& icon_sizes) { + ScriptState* script_state = resolver->GetScriptState(); + ScriptState::Scope scope(script_state); + if (!icon_sizes.IsEmpty() && description->icons.IsEmpty()) { - ScriptState* script_state = resolver->GetScriptState(); - ScriptState::Scope scope(script_state); resolver->Reject(V8ThrowException::CreateTypeError( script_state->GetIsolate(), "icons must be provided")); return; } + if (!registration_->GetExecutionContext()) { + // The SW execution context is not valid for some reason. Bail out. + resolver->Reject(V8ThrowException::CreateTypeError( + script_state->GetIsolate(), "Service worker is no longer valid.")); + return; + } + if (icon_sizes.IsEmpty()) { DidGetIcons(resolver, std::move(description), /* icons= */ {}); return; @@ -152,6 +160,13 @@ } } + if (!registration_->GetExecutionContext()) { + // The SW execution context is not valid for some reason. Bail out. + resolver->Reject(V8ThrowException::CreateTypeError( + script_state->GetIsolate(), "Service worker is no longer valid.")); + return; + } + KURL launch_url = registration_->GetExecutionContext()->CompleteURL( description->launch_url);
diff --git a/third_party/blink/renderer/modules/locks/BUILD.gn b/third_party/blink/renderer/modules/locks/BUILD.gn index b8af64f..74524fa 100644 --- a/third_party/blink/renderer/modules/locks/BUILD.gn +++ b/third_party/blink/renderer/modules/locks/BUILD.gn
@@ -10,7 +10,5 @@ "lock.h", "lock_manager.cc", "lock_manager.h", - "navigator_locks.cc", - "navigator_locks.h", ] }
diff --git a/third_party/blink/renderer/modules/locks/lock_manager.cc b/third_party/blink/renderer/modules/locks/lock_manager.cc index 1bd532ef..ca66a6c 100644 --- a/third_party/blink/renderer/modules/locks/lock_manager.cc +++ b/third_party/blink/renderer/modules/locks/lock_manager.cc
@@ -202,10 +202,23 @@ DISALLOW_COPY_AND_ASSIGN(LockRequestImpl); }; -LockManager::LockManager(ExecutionContext* context) - : ExecutionContextLifecycleObserver(context), - service_(context), - observer_(context) {} +const char LockManager::kSupplementName[] = "LockManager"; + +// static +LockManager* LockManager::locks(NavigatorBase& navigator) { + auto* supplement = Supplement<NavigatorBase>::From<LockManager>(navigator); + if (!supplement) { + supplement = MakeGarbageCollected<LockManager>(navigator); + Supplement<NavigatorBase>::ProvideTo(navigator, supplement); + } + return supplement; +} + +LockManager::LockManager(NavigatorBase& navigator) + : Supplement<NavigatorBase>(navigator), + ExecutionContextLifecycleObserver(navigator.GetExecutionContext()), + service_(navigator.GetExecutionContext()), + observer_(navigator.GetExecutionContext()) {} ScriptPromise LockManager::request(ScriptState* script_state, const String& name, @@ -416,6 +429,7 @@ void LockManager::Trace(Visitor* visitor) const { ScriptWrappable::Trace(visitor); + Supplement<NavigatorBase>::Trace(visitor); ExecutionContextLifecycleObserver::Trace(visitor); visitor->Trace(pending_requests_); visitor->Trace(held_locks_);
diff --git a/third_party/blink/renderer/modules/locks/lock_manager.h b/third_party/blink/renderer/modules/locks/lock_manager.h index 8353c9a..94e3f15 100644 --- a/third_party/blink/renderer/modules/locks/lock_manager.h +++ b/third_party/blink/renderer/modules/locks/lock_manager.h
@@ -17,19 +17,27 @@ #include "third_party/blink/renderer/platform/heap/heap_allocator.h" #include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h" #include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h" +#include "third_party/blink/renderer/platform/supplementable.h" namespace blink { +class NavigatorBase; class ScriptPromise; class ScriptState; class V8LockGrantedCallback; class LockManager final : public ScriptWrappable, + public Supplement<NavigatorBase>, public ExecutionContextLifecycleObserver { DEFINE_WRAPPERTYPEINFO(); public: - explicit LockManager(ExecutionContext*); + static const char kSupplementName[]; + + // Web-exposed as navigator.locks + static LockManager* locks(NavigatorBase&); + + explicit LockManager(NavigatorBase&); ScriptPromise request(ScriptState*, const String& name,
diff --git a/third_party/blink/renderer/modules/locks/navigator_locks.cc b/third_party/blink/renderer/modules/locks/navigator_locks.cc deleted file mode 100644 index 802d8829..0000000 --- a/third_party/blink/renderer/modules/locks/navigator_locks.cc +++ /dev/null
@@ -1,75 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "third_party/blink/renderer/modules/locks/navigator_locks.h" - -#include "third_party/blink/renderer/core/frame/navigator.h" -#include "third_party/blink/renderer/core/workers/worker_navigator.h" -#include "third_party/blink/renderer/modules/locks/lock_manager.h" -#include "third_party/blink/renderer/platform/bindings/name_client.h" -#include "third_party/blink/renderer/platform/bindings/script_state.h" -#include "third_party/blink/renderer/platform/supplementable.h" - -namespace blink { - -namespace { - -template <typename T> -class NavigatorLocksImpl final : public GarbageCollected<NavigatorLocksImpl<T>>, - public Supplement<T>, - public NameClient { - public: - static const char kSupplementName[]; - - static NavigatorLocksImpl& From(T& navigator) { - NavigatorLocksImpl* supplement = static_cast<NavigatorLocksImpl*>( - Supplement<T>::template From<NavigatorLocksImpl>(navigator)); - if (!supplement) { - supplement = MakeGarbageCollected<NavigatorLocksImpl>(navigator); - Supplement<T>::ProvideTo(navigator, supplement); - } - return *supplement; - } - - explicit NavigatorLocksImpl(T& navigator) : Supplement<T>(navigator) {} - - LockManager* GetLockManager(ExecutionContext* context) const { - if (!lock_manager_ && context) { - lock_manager_ = MakeGarbageCollected<LockManager>(context); - } - return lock_manager_.Get(); - } - - void Trace(Visitor* visitor) const override { - visitor->Trace(lock_manager_); - Supplement<T>::Trace(visitor); - } - - const char* NameInHeapSnapshot() const override { - return "NavigatorLocksImpl"; - } - - private: - mutable Member<LockManager> lock_manager_; -}; - -// static -template <typename T> -const char NavigatorLocksImpl<T>::kSupplementName[] = "NavigatorLocksImpl"; - -} // namespace - -LockManager* NavigatorLocks::locks(ScriptState* script_state, - Navigator& navigator) { - return NavigatorLocksImpl<Navigator>::From(navigator).GetLockManager( - ExecutionContext::From(script_state)); -} - -LockManager* NavigatorLocks::locks(ScriptState* script_state, - WorkerNavigator& navigator) { - return NavigatorLocksImpl<WorkerNavigator>::From(navigator).GetLockManager( - ExecutionContext::From(script_state)); -} - -} // namespace blink
diff --git a/third_party/blink/renderer/modules/locks/navigator_locks.h b/third_party/blink/renderer/modules/locks/navigator_locks.h deleted file mode 100644 index 600a0fd..0000000 --- a/third_party/blink/renderer/modules/locks/navigator_locks.h +++ /dev/null
@@ -1,27 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_LOCKS_NAVIGATOR_LOCKS_H_ -#define THIRD_PARTY_BLINK_RENDERER_MODULES_LOCKS_NAVIGATOR_LOCKS_H_ - -#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" - -namespace blink { - -class LockManager; -class Navigator; -class ScriptState; -class WorkerNavigator; - -class NavigatorLocks final { - STATIC_ONLY(NavigatorLocks); - - public: - static LockManager* locks(ScriptState*, Navigator&); - static LockManager* locks(ScriptState*, WorkerNavigator&); -}; - -} // namespace blink - -#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_LOCKS_NAVIGATOR_LOCKS_H_
diff --git a/third_party/blink/renderer/modules/locks/navigator_locks.idl b/third_party/blink/renderer/modules/locks/navigator_locks.idl index 79d2709..87389ef 100644 --- a/third_party/blink/renderer/modules/locks/navigator_locks.idl +++ b/third_party/blink/renderer/modules/locks/navigator_locks.idl
@@ -6,7 +6,7 @@ [ SecureContext, Exposed=Window, - ImplementedAs=NavigatorLocks + ImplementedAs=LockManager ] partial interface Navigator { - [CallWith=ScriptState] readonly attribute LockManager locks; + readonly attribute LockManager locks; };
diff --git a/third_party/blink/renderer/modules/locks/worker_navigator_locks.idl b/third_party/blink/renderer/modules/locks/worker_navigator_locks.idl index cbbccdf..4dfdd5e 100644 --- a/third_party/blink/renderer/modules/locks/worker_navigator_locks.idl +++ b/third_party/blink/renderer/modules/locks/worker_navigator_locks.idl
@@ -6,7 +6,7 @@ [ SecureContext, Exposed=Worker, - ImplementedAs=NavigatorLocks + ImplementedAs=LockManager ] partial interface WorkerNavigator { - [CallWith=ScriptState] readonly attribute LockManager locks; + readonly attribute LockManager locks; };
diff --git a/third_party/blink/renderer/modules/quota/BUILD.gn b/third_party/blink/renderer/modules/quota/BUILD.gn index f4bc0a0..388a9ee3 100644 --- a/third_party/blink/renderer/modules/quota/BUILD.gn +++ b/third_party/blink/renderer/modules/quota/BUILD.gn
@@ -20,8 +20,6 @@ "quota_utils.h", "storage_manager.cc", "storage_manager.h", - "worker_navigator_storage_quota.cc", - "worker_navigator_storage_quota.h", ] deps = [ "//third_party/blink/renderer/modules/permissions" ] }
diff --git a/third_party/blink/renderer/modules/quota/navigator_storage_quota.cc b/third_party/blink/renderer/modules/quota/navigator_storage_quota.cc index fbbe9cb..5a66552e 100644 --- a/third_party/blink/renderer/modules/quota/navigator_storage_quota.cc +++ b/third_party/blink/renderer/modules/quota/navigator_storage_quota.cc
@@ -38,14 +38,14 @@ namespace blink { -NavigatorStorageQuota::NavigatorStorageQuota(Navigator& navigator) - : Supplement<Navigator>(navigator) {} +NavigatorStorageQuota::NavigatorStorageQuota(NavigatorBase& navigator) + : Supplement<NavigatorBase>(navigator) {} const char NavigatorStorageQuota::kSupplementName[] = "NavigatorStorageQuota"; -NavigatorStorageQuota& NavigatorStorageQuota::From(Navigator& navigator) { +NavigatorStorageQuota& NavigatorStorageQuota::From(NavigatorBase& navigator) { NavigatorStorageQuota* supplement = - Supplement<Navigator>::From<NavigatorStorageQuota>(navigator); + Supplement<NavigatorBase>::From<NavigatorStorageQuota>(navigator); if (!supplement) { supplement = MakeGarbageCollected<NavigatorStorageQuota>(navigator); ProvideTo(navigator, supplement); @@ -55,59 +55,40 @@ DeprecatedStorageQuota* NavigatorStorageQuota::webkitTemporaryStorage( Navigator& navigator) { - return NavigatorStorageQuota::From(navigator).webkitTemporaryStorage(); + NavigatorStorageQuota& navigator_storage = From(navigator); + if (!navigator_storage.temporary_storage_) { + navigator_storage.temporary_storage_ = + MakeGarbageCollected<DeprecatedStorageQuota>( + DeprecatedStorageQuota::kTemporary, navigator.DomWindow()); + } + return navigator_storage.temporary_storage_.Get(); } DeprecatedStorageQuota* NavigatorStorageQuota::webkitPersistentStorage( Navigator& navigator) { - return NavigatorStorageQuota::From(navigator).webkitPersistentStorage(); -} - -StorageManager* NavigatorStorageQuota::storage(Navigator& navigator) { - return NavigatorStorageQuota::From(navigator).storage(); -} - -DeprecatedStorageQuota* NavigatorStorageQuota::webkitTemporaryStorage() const { - if (!temporary_storage_) { - temporary_storage_ = MakeGarbageCollected<DeprecatedStorageQuota>( - DeprecatedStorageQuota::kTemporary, GetSupplementable()->DomWindow()); + NavigatorStorageQuota& navigator_storage = From(navigator); + if (!navigator_storage.persistent_storage_) { + navigator_storage.persistent_storage_ = + MakeGarbageCollected<DeprecatedStorageQuota>( + DeprecatedStorageQuota::kPersistent, navigator.DomWindow()); } - return temporary_storage_.Get(); + return navigator_storage.persistent_storage_.Get(); } -DeprecatedStorageQuota* NavigatorStorageQuota::webkitPersistentStorage() const { - if (!persistent_storage_) { - persistent_storage_ = MakeGarbageCollected<DeprecatedStorageQuota>( - DeprecatedStorageQuota::kPersistent, GetSupplementable()->DomWindow()); +StorageManager* NavigatorStorageQuota::storage(NavigatorBase& navigator) { + NavigatorStorageQuota& navigator_storage = From(navigator); + if (!navigator_storage.storage_manager_) { + navigator_storage.storage_manager_ = + MakeGarbageCollected<StorageManager>(navigator.GetExecutionContext()); } - return persistent_storage_.Get(); -} - -StorageManager* NavigatorStorageQuota::storage() const { - if (!storage_manager_) { - mojo::Remote<mojom::blink::QuotaManagerHost> backend; - - auto* supplementable = GetSupplementable(); - auto* execution_context = - supplementable ? supplementable->GetExecutionContext() : nullptr; - if (execution_context) { - if (&execution_context->GetBrowserInterfaceBroker() != - &GetEmptyBrowserInterfaceBroker()) { - execution_context->GetBrowserInterfaceBroker().GetInterface( - backend.BindNewPipeAndPassReceiver()); - } - } - storage_manager_ = MakeGarbageCollected<StorageManager>(execution_context, - std::move(backend)); - } - return storage_manager_.Get(); + return navigator_storage.storage_manager_.Get(); } void NavigatorStorageQuota::Trace(Visitor* visitor) const { visitor->Trace(temporary_storage_); visitor->Trace(persistent_storage_); visitor->Trace(storage_manager_); - Supplement<Navigator>::Trace(visitor); + Supplement<NavigatorBase>::Trace(visitor); } } // namespace blink
diff --git a/third_party/blink/renderer/modules/quota/navigator_storage_quota.h b/third_party/blink/renderer/modules/quota/navigator_storage_quota.h index 21324f1..6693abd 100644 --- a/third_party/blink/renderer/modules/quota/navigator_storage_quota.h +++ b/third_party/blink/renderer/modules/quota/navigator_storage_quota.h
@@ -31,7 +31,6 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_QUOTA_NAVIGATOR_STORAGE_QUOTA_H_ #define THIRD_PARTY_BLINK_RENDERER_MODULES_QUOTA_NAVIGATOR_STORAGE_QUOTA_H_ -#include "third_party/blink/renderer/core/frame/navigator.h" #include "third_party/blink/renderer/modules/quota/deprecated_storage_quota.h" #include "third_party/blink/renderer/platform/heap/handle.h" #include "third_party/blink/renderer/platform/supplementable.h" @@ -39,28 +38,29 @@ namespace blink { class Navigator; +class NavigatorBase; class StorageManager; class NavigatorStorageQuota final : public GarbageCollected<NavigatorStorageQuota>, - public Supplement<Navigator> { + public Supplement<NavigatorBase> { public: static const char kSupplementName[]; - static NavigatorStorageQuota& From(Navigator&); + // Web-exposed on window only. static DeprecatedStorageQuota* webkitTemporaryStorage(Navigator&); static DeprecatedStorageQuota* webkitPersistentStorage(Navigator&); - static StorageManager* storage(Navigator&); - DeprecatedStorageQuota* webkitTemporaryStorage() const; - DeprecatedStorageQuota* webkitPersistentStorage() const; - StorageManager* storage() const; + // Web-exposed on both window and worker. + static StorageManager* storage(NavigatorBase&); - explicit NavigatorStorageQuota(Navigator&); + explicit NavigatorStorageQuota(NavigatorBase&); void Trace(Visitor*) const override; private: + static NavigatorStorageQuota& From(NavigatorBase&); + mutable Member<DeprecatedStorageQuota> temporary_storage_; mutable Member<DeprecatedStorageQuota> persistent_storage_; mutable Member<StorageManager> storage_manager_;
diff --git a/third_party/blink/renderer/modules/quota/storage_manager.cc b/third_party/blink/renderer/modules/quota/storage_manager.cc index c1f055e..c26a88c 100644 --- a/third_party/blink/renderer/modules/quota/storage_manager.cc +++ b/third_party/blink/renderer/modules/quota/storage_manager.cc
@@ -85,9 +85,7 @@ } // namespace -StorageManager::StorageManager( - ExecutionContext* execution_context, - mojo::Remote<mojom::blink::QuotaManagerHost> backend) +StorageManager::StorageManager(ExecutionContext* execution_context) : ExecutionContextClient(execution_context), permission_service_(execution_context), quota_host_(execution_context),
diff --git a/third_party/blink/renderer/modules/quota/storage_manager.h b/third_party/blink/renderer/modules/quota/storage_manager.h index 51a7fc76..b0c02c1 100644 --- a/third_party/blink/renderer/modules/quota/storage_manager.h +++ b/third_party/blink/renderer/modules/quota/storage_manager.h
@@ -29,8 +29,7 @@ DEFINE_WRAPPERTYPEINFO(); public: - explicit StorageManager(ExecutionContext*, - mojo::Remote<mojom::blink::QuotaManagerHost> backend); + explicit StorageManager(ExecutionContext*); ~StorageManager() override; ScriptPromise persisted(ScriptState*);
diff --git a/third_party/blink/renderer/modules/quota/worker_navigator_storage_quota.cc b/third_party/blink/renderer/modules/quota/worker_navigator_storage_quota.cc deleted file mode 100644 index 1c6bf14e..0000000 --- a/third_party/blink/renderer/modules/quota/worker_navigator_storage_quota.cc +++ /dev/null
@@ -1,85 +0,0 @@ -/* - * Copyright (C) 2013 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "third_party/blink/renderer/modules/quota/worker_navigator_storage_quota.h" - -#include "third_party/blink/public/common/browser_interface_broker_proxy.h" -#include "third_party/blink/renderer/modules/quota/deprecated_storage_quota.h" -#include "third_party/blink/renderer/modules/quota/storage_manager.h" - -namespace blink { - -WorkerNavigatorStorageQuota::WorkerNavigatorStorageQuota() = default; - -const char WorkerNavigatorStorageQuota::kSupplementName[] = - "WorkerNavigatorStorageQuota"; - -WorkerNavigatorStorageQuota& WorkerNavigatorStorageQuota::From( - WorkerNavigator& navigator) { - WorkerNavigatorStorageQuota* supplement = - Supplement<WorkerNavigator>::From<WorkerNavigatorStorageQuota>(navigator); - if (!supplement) { - supplement = MakeGarbageCollected<WorkerNavigatorStorageQuota>(); - ProvideTo(navigator, supplement); - } - return *supplement; -} - -StorageManager* WorkerNavigatorStorageQuota::storage( - WorkerNavigator& navigator) { - return WorkerNavigatorStorageQuota::From(navigator).storage(); -} - -StorageManager* WorkerNavigatorStorageQuota::storage() const { - if (!storage_manager_) { - mojo::Remote<mojom::blink::QuotaManagerHost> backend; - - auto* supplementable = GetSupplementable(); - auto* execution_context = - supplementable ? supplementable->GetExecutionContext() : nullptr; - if (execution_context) { - if (&execution_context->GetBrowserInterfaceBroker() != - &GetEmptyBrowserInterfaceBroker()) { - execution_context->GetBrowserInterfaceBroker().GetInterface( - backend.BindNewPipeAndPassReceiver()); - } - } - storage_manager_ = MakeGarbageCollected<StorageManager>(execution_context, - std::move(backend)); - } - return storage_manager_.Get(); -} - -void WorkerNavigatorStorageQuota::Trace(Visitor* visitor) const { - visitor->Trace(storage_manager_); - Supplement<WorkerNavigator>::Trace(visitor); -} - -} // namespace blink
diff --git a/third_party/blink/renderer/modules/quota/worker_navigator_storage_quota.h b/third_party/blink/renderer/modules/quota/worker_navigator_storage_quota.h deleted file mode 100644 index 84700a9..0000000 --- a/third_party/blink/renderer/modules/quota/worker_navigator_storage_quota.h +++ /dev/null
@@ -1,65 +0,0 @@ -/* - * Copyright (C) 2013 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_QUOTA_WORKER_NAVIGATOR_STORAGE_QUOTA_H_ -#define THIRD_PARTY_BLINK_RENDERER_MODULES_QUOTA_WORKER_NAVIGATOR_STORAGE_QUOTA_H_ - -#include "third_party/blink/renderer/core/workers/worker_navigator.h" -#include "third_party/blink/renderer/modules/quota/deprecated_storage_quota.h" -#include "third_party/blink/renderer/platform/heap/handle.h" -#include "third_party/blink/renderer/platform/supplementable.h" - -namespace blink { - -class StorageManager; - -class WorkerNavigatorStorageQuota final - : public GarbageCollected<WorkerNavigatorStorageQuota>, - public Supplement<WorkerNavigator> { - public: - static const char kSupplementName[]; - - static WorkerNavigatorStorageQuota& From(WorkerNavigator&); - - static StorageManager* storage(WorkerNavigator&); - - StorageManager* storage() const; - - explicit WorkerNavigatorStorageQuota(); - - void Trace(Visitor*) const override; - - private: - mutable Member<StorageManager> storage_manager_; -}; - -} // namespace blink - -#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_QUOTA_WORKER_NAVIGATOR_STORAGE_QUOTA_H_
diff --git a/third_party/blink/renderer/modules/quota/worker_navigator_storage_quota.idl b/third_party/blink/renderer/modules/quota/worker_navigator_storage_quota.idl index 0acd78e..8888189 100644 --- a/third_party/blink/renderer/modules/quota/worker_navigator_storage_quota.idl +++ b/third_party/blink/renderer/modules/quota/worker_navigator_storage_quota.idl
@@ -18,7 +18,7 @@ */ [ - ImplementedAs=WorkerNavigatorStorageQuota + ImplementedAs=NavigatorStorageQuota ] partial interface WorkerNavigator { // https://storage.spec.whatwg.org/#api [SecureContext] readonly attribute StorageManager storage;
diff --git a/third_party/blink/renderer/modules/sanitizer_api/sanitizer_api_fuzzer.cc b/third_party/blink/renderer/modules/sanitizer_api/sanitizer_api_fuzzer.cc index 51aa7086..65d9acb1 100644 --- a/third_party/blink/renderer/modules/sanitizer_api/sanitizer_api_fuzzer.cc +++ b/third_party/blink/renderer/modules/sanitizer_api/sanitizer_api_fuzzer.cc
@@ -22,6 +22,12 @@ namespace blink { +ScriptState* Initialization() { + static BlinkFuzzerTestSupport test_support = BlinkFuzzerTestSupport(); + static DummyPageHolder* g_page_holder = new DummyPageHolder(); + return ToScriptStateForMainWorld(&g_page_holder->GetFrame()); +} + Vector<String> ToVector( const google::protobuf::RepeatedPtrField<std::string>& inputs) { Vector<String> elements; @@ -60,35 +66,26 @@ } } -DEFINE_TEXT_PROTO_FUZZER(const SanitizerConfigProto& proto) { - static BlinkFuzzerTestSupport test_support = BlinkFuzzerTestSupport(); - // Scope cannot be created before BlinkFuzzerTestSupport because it requires - // that Oilpan be initialized to access blink::ThreadState::Current. - LEAK_SANITIZER_DISABLED_SCOPE; - static DummyPageHolder* g_page_holder = new DummyPageHolder(); - - ScriptState* script_state = - ToScriptStateForMainWorld(&g_page_holder->GetFrame()); - +void TextProtoFuzzer(const SanitizerConfigProto& proto, + ScriptState* script_state) { // Create random Sanitizer. auto* sanitizer_config = MakeGarbageCollected<SanitizerConfig>(); MakeConfiguration(sanitizer_config, proto); auto* sanitizer = MakeGarbageCollected<Sanitizer>(sanitizer_config); // Sanitize random strings. + String str = proto.html_string().c_str(); StringOrTrustedHTMLOrDocumentFragmentOrDocument str1 = - StringOrTrustedHTMLOrDocumentFragmentOrDocument::FromString( - proto.html_string().c_str()); + StringOrTrustedHTMLOrDocumentFragmentOrDocument::FromString(str); sanitizer->sanitize(script_state, str1, IGNORE_EXCEPTION_FOR_TESTING); - StringOrDocumentFragmentOrDocument str2 = - StringOrDocumentFragmentOrDocument::FromString( - proto.html_string().c_str()); + StringOrDocumentFragmentOrDocument::FromString(str); sanitizer->sanitizeToString(script_state, str2, IGNORE_EXCEPTION_FOR_TESTING); - - // Request a garbage collection. - ThreadState::Current()->CollectAllGarbageForTesting( - BlinkGC::kNoHeapPointersOnStack); } } // namespace blink + +DEFINE_TEXT_PROTO_FUZZER(const SanitizerConfigProto& proto) { + static blink::ScriptState* script_state = blink::Initialization(); + blink::TextProtoFuzzer(proto, script_state); +}
diff --git a/third_party/blink/renderer/platform/fonts/mac/font_matcher_mac.mm b/third_party/blink/renderer/platform/fonts/mac/font_matcher_mac.mm index aafddac..b9bd84e 100644 --- a/third_party/blink/renderer/platform/fonts/mac/font_matcher_mac.mm +++ b/third_party/blink/renderer/platform/fonts/mac/font_matcher_mac.mm
@@ -42,10 +42,6 @@ #import "third_party/blink/renderer/platform/wtf/hash_set.h" #import "third_party/blink/renderer/platform/wtf/text/atomic_string_hash.h" -@interface NSFont (YosemiteAdditions) -+ (NSFont*)systemFontOfSize:(CGFloat)size weight:(CGFloat)weight; -@end - namespace { static CGFloat toFontWeight(blink::FontSelectionValue font_weight) { @@ -176,15 +172,9 @@ if (desired_family_string == font_family_names::kSystemUi) { NSFont* font = nil; -// Normally we'd use an availability macro here, but -// systemFontOfSize:weight: is available but not visible on macOS 10.10, -// so it's been forward declared earlier in this file. -// On OSX 10.10+, the default system font has more weights. -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunguarded-availability" - font = [NSFont systemFontOfSize:size weight:toFontWeight(desired_weight)]; -#pragma clang diagnostic pop - + if (@available(macOS 10.11, *)) { + font = [NSFont systemFontOfSize:size weight:toFontWeight(desired_weight)]; + } if (desired_traits & IMPORTANT_FONT_TRAITS) font = [[NSFontManager sharedFontManager] convertFont:font toHaveTrait:desired_traits];
diff --git a/third_party/blink/renderer/platform/heap/impl/heap_allocator.h b/third_party/blink/renderer/platform/heap/impl/heap_allocator.h index a9b3bae..850551b 100644 --- a/third_party/blink/renderer/platform/heap/impl/heap_allocator.h +++ b/third_party/blink/renderer/platform/heap/impl/heap_allocator.h
@@ -31,6 +31,17 @@ namespace blink { +class HeapListHashSetAllocator; +template <typename ValueArg> +class HeapListHashSetNode; + +namespace internal { + +template <typename T> +constexpr bool IsMember = WTF::IsSubclassOfTemplate<T, Member>::value; + +} // namespace internal + #define DISALLOW_IN_CONTAINER() \ public: \ using IsDisallowedInContainerMarker = int; \ @@ -108,12 +119,6 @@ MarkingVisitor::WriteBarrier(slot); } - template <typename Return, typename Metadata> - static Return Malloc(size_t size, const char* type_name) { - return reinterpret_cast<Return>( - MarkAsConstructed(ThreadHeap::Allocate<Metadata>(size))); - } - static bool IsAllocationAllowed() { return ThreadState::Current()->IsAllocationAllowed(); } @@ -235,103 +240,13 @@ } private: - static Address MarkAsConstructed(Address address) { - HeapObjectHeader::FromPayload(reinterpret_cast<void*>(address)) - ->MarkFullyConstructed<HeapObjectHeader::AccessMode::kAtomic>(); - return address; - } - static void BackingFree(void*); static bool BackingExpand(void*, size_t); static bool BackingShrink(void*, size_t quantized_current_size, size_t quantized_shrunk_size); - - template <typename T, wtf_size_t u, typename V> - friend class WTF::Vector; - template <typename T, typename U, typename V, typename W> - friend class WTF::HashSet; - template <typename T, - typename U, - typename V, - typename W, - typename X, - typename Y> - friend class WTF::HashMap; }; -template <typename VisitorDispatcher, typename Value> -static void TraceListHashSetValue(VisitorDispatcher visitor, - const Value& value) { - // We use the default hash traits for the value in the node, because - // ListHashSet does not let you specify any specific ones. - // We don't allow ListHashSet of WeakMember, so we set that one false - // (there's an assert elsewhere), but we have to specify some value for the - // strongify template argument, so we specify WTF::WeakPointersActWeak, - // arbitrarily. - TraceCollectionIfEnabled<WTF::kNoWeakHandling, Value, - WTF::HashTraits<Value>>::Trace(visitor, &value); -} - -// The inline capacity is just a dummy template argument to match the off-heap -// allocator. -// This inherits from the static-only HeapAllocator trait class, but we do -// declare pointers to instances. These pointers are always null, and no -// objects are instantiated. -template <typename ValueArg, wtf_size_t inlineCapacity> -class HeapListHashSetAllocator : public HeapAllocator { - DISALLOW_NEW(); - - public: - using TableAllocator = HeapAllocator; - using Node = WTF::ListHashSetNode<ValueArg, HeapListHashSetAllocator>; - - class AllocatorProvider { - DISALLOW_NEW(); - - public: - // For the heap allocation we don't need an actual allocator object, so - // we just return null. - HeapListHashSetAllocator* Get() const { return nullptr; } - - // No allocator object is needed. - void CreateAllocatorIfNeeded() {} - void ReleaseAllocator() {} - - // There is no allocator object in the HeapListHashSet (unlike in the - // regular ListHashSet) so there is nothing to swap. - void Swap(AllocatorProvider& other) {} - }; - - void Deallocate(void* dummy) {} - - // This is not a static method even though it could be, because it needs to - // match the one that the (off-heap) ListHashSetAllocator has. The 'this' - // pointer will always be null. - void* AllocateNode() { - // Consider using a LinkedHashSet instead if this compile-time assert fails: - static_assert(!WTF::IsWeak<ValueArg>::value, - "weak pointers in a ListHashSet will result in null entries " - "in the set"); - - return Malloc<void*, Node>( - sizeof(Node), - nullptr /* Oilpan does not use the heap profiler at the moment. */); - } - - template <typename VisitorDispatcher> - static void TraceValue(VisitorDispatcher visitor, const Node* node) { - TraceListHashSetValue(visitor, node->value_); - } -}; - -namespace internal { - -template <typename T> -constexpr bool IsMember = WTF::IsSubclassOfTemplate<T, Member>::value; - -} // namespace internal - template <typename KeyArg, typename MappedArg, typename HashArg = typename DefaultHash<KeyArg>::Hash, @@ -452,6 +367,77 @@ HeapLinkedHashSet() { CheckType(); } }; +} // namespace blink + +namespace WTF { + +template <typename Value, wtf_size_t inlineCapacity> +struct ListHashSetTraits<Value, inlineCapacity, blink::HeapListHashSetAllocator> + : public HashTraits<blink::Member<blink::HeapListHashSetNode<Value>>> { + using Allocator = blink::HeapListHashSetAllocator; + using Node = blink::HeapListHashSetNode<Value>; + + static constexpr bool kCanTraceConcurrently = + HashTraits<Value>::kCanTraceConcurrently; +}; + +} // namespace WTF + +namespace blink { + +template <typename ValueArg> +class HeapListHashSetNode final + : public GarbageCollected<HeapListHashSetNode<ValueArg>> { + public: + using NodeAllocator = HeapListHashSetAllocator; + using PointerType = Member<HeapListHashSetNode>; + using Value = ValueArg; + + template <typename U> + static HeapListHashSetNode* Create(NodeAllocator* allocator, U&& value) { + return MakeGarbageCollected<HeapListHashSetNode>(std::forward<U>(value)); + } + + template <typename U> + explicit HeapListHashSetNode(U&& value) : value_(std::forward<U>(value)) { + static_assert(std::is_trivially_destructible<Value>::value, + "Garbage collected types used in ListHashSet must be " + "trivially destructible"); + } + + void Destroy(NodeAllocator* allocator) {} + + HeapListHashSetNode* Next() const { return next_; } + HeapListHashSetNode* Prev() const { return prev_; } + + void Trace(Visitor* visitor) const { + visitor->Trace(prev_); + visitor->Trace(next_); + visitor->Trace(value_); + } + + ValueArg value_; + PointerType prev_; + PointerType next_; +}; + +// Empty allocator as HeapListHashSetNode directly allocates using +// MakeGarbageCollected(). +class HeapListHashSetAllocator { + DISALLOW_NEW(); + + public: + using TableAllocator = HeapAllocator; + + static constexpr bool kIsGarbageCollected = true; + + struct AllocatorProvider final { + void CreateAllocatorIfNeeded() {} + HeapListHashSetAllocator* Get() { return nullptr; } + void Swap(AllocatorProvider& other) {} + }; +}; + template <typename T, typename U> struct GCInfoTrait<HeapLinkedHashSet<T, U>> : public GCInfoTrait<LinkedHashSet<T, U, HeapAllocator>> {}; @@ -460,11 +446,10 @@ wtf_size_t inlineCapacity = 0, // The inlineCapacity is just a dummy // to match ListHashSet (off-heap). typename HashArg = typename DefaultHash<ValueArg>::Hash> -class HeapListHashSet - : public ListHashSet<ValueArg, - inlineCapacity, - HashArg, - HeapListHashSetAllocator<ValueArg, inlineCapacity>> { +class HeapListHashSet : public ListHashSet<ValueArg, + inlineCapacity, + HashArg, + HeapListHashSetAllocator> { IS_GARBAGE_COLLECTED_CONTAINER_TYPE(); DISALLOW_NEW(); @@ -494,10 +479,7 @@ template <typename T, wtf_size_t inlineCapacity, typename U> struct GCInfoTrait<HeapListHashSet<T, inlineCapacity, U>> : public GCInfoTrait< - ListHashSet<T, - inlineCapacity, - U, - HeapListHashSetAllocator<T, inlineCapacity>>> {}; + ListHashSet<T, inlineCapacity, U, HeapListHashSetAllocator>> {}; template <typename Value, typename HashFunctions = typename DefaultHash<Value>::Hash, @@ -815,43 +797,6 @@ } }; -template <typename T, wtf_size_t inlineCapacity> -struct IsTraceable< - ListHashSetNode<T, blink::HeapListHashSetAllocator<T, inlineCapacity>>*> { - STATIC_ONLY(IsTraceable); - static_assert(sizeof(T), "T must be fully defined"); - // All heap allocated node pointers need visiting to keep the nodes alive, - // regardless of whether they contain pointers to other heap allocated - // objects. - static const bool value = true; -}; - -template <typename T, wtf_size_t inlineCapacity> -struct IsGarbageCollectedType< - ListHashSetNode<T, blink::HeapListHashSetAllocator<T, inlineCapacity>>> { - static const bool value = true; -}; - -template <typename Set> -struct IsGarbageCollectedType<ListHashSetIterator<Set>> { - static const bool value = IsGarbageCollectedType<Set>::value; -}; - -template <typename Set> -struct IsGarbageCollectedType<ListHashSetConstIterator<Set>> { - static const bool value = IsGarbageCollectedType<Set>::value; -}; - -template <typename Set> -struct IsGarbageCollectedType<ListHashSetReverseIterator<Set>> { - static const bool value = IsGarbageCollectedType<Set>::value; -}; - -template <typename Set> -struct IsGarbageCollectedType<ListHashSetConstReverseIterator<Set>> { - static const bool value = IsGarbageCollectedType<Set>::value; -}; - template <typename T, typename H> struct HandleHashTraits : SimpleClassHashTraits<H> { STATIC_ONLY(HandleHashTraits);
diff --git a/third_party/blink/renderer/platform/heap/impl/trace_traits.h b/third_party/blink/renderer/platform/heap/impl/trace_traits.h index 668da56..44ae3c94 100644 --- a/third_party/blink/renderer/platform/heap/impl/trace_traits.h +++ b/third_party/blink/renderer/platform/heap/impl/trace_traits.h
@@ -22,10 +22,6 @@ namespace blink { -template <typename Table> -class HeapHashTableBacking; -template <typename ValueArg, wtf_size_t inlineCapacity> -class HeapListHashSetAllocator; template <typename T> struct TraceTrait; template <typename T> @@ -300,82 +296,6 @@ } }; -// This specialization of TraceInCollectionTrait is for the backing of -// HeapListHashSet. This is for the case that we find a reference to the -// backing from the stack. That probably means we have a GC while we are in a -// ListHashSet method since normal API use does not put pointers to the backing -// on the stack. -template <typename NodeContents, - size_t inlineCapacity, - typename T, - typename U, - typename V, - typename W, - typename X, - typename Y> -struct TraceInCollectionTrait< - kNoWeakHandling, - blink::HeapHashTableBacking<HashTable< - ListHashSetNode<NodeContents, - blink::HeapListHashSetAllocator<T, inlineCapacity>>*, - U, - V, - W, - X, - Y, - blink::HeapAllocator>>, - void> { - using Node = - ListHashSetNode<NodeContents, - blink::HeapListHashSetAllocator<T, inlineCapacity>>; - using Table = HashTable<Node*, U, V, W, X, Y, blink::HeapAllocator>; - - static void Trace(blink::Visitor* visitor, const void* self) { - const Node* const* array = reinterpret_cast<const Node* const*>(self); - blink::HeapObjectHeader* header = - blink::HeapObjectHeader::FromPayload(self); - size_t length = header->PayloadSize() / sizeof(Node*); - const bool is_concurrent = visitor->IsConcurrent(); - for (size_t i = 0; i < length; ++i) { - const Node* node; - if (is_concurrent) { - // If tracing concurrently, IsEmptyOrDeletedBucket can cause data - // races. Loading array[i] atomically prevents possible data races. - // array[i] is of type Node* so can directly loaded atomically. - node = AsAtomicPtr(&array[i])->load(std::memory_order_relaxed); - } else { - node = array[i]; - } - if (!HashTableHelper< - const Node*, typename Table::ExtractorType, - typename Table::KeyTraitsType>::IsEmptyOrDeletedBucket(node)) { - visitor->Trace(node); - } - } - } -}; - -// ListHashSetNode pointers (a ListHashSet is implemented as a hash table of -// these pointers). -template <typename Value, size_t inlineCapacity, typename Traits> -struct TraceInCollectionTrait< - kNoWeakHandling, - ListHashSetNode<Value, - blink::HeapListHashSetAllocator<Value, inlineCapacity>>*, - Traits> { - using Node = - ListHashSetNode<Value, - blink::HeapListHashSetAllocator<Value, inlineCapacity>>; - - static void Trace(blink::Visitor* visitor, const Node* node) { - static_assert(!IsWeak<Node>::value, - "ListHashSet does not support weakness"); - static_assert(IsTraceableInCollectionTrait<Traits>::value, - "T should be traceable"); - visitor->Trace(node); - } -}; - } // namespace WTF #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_TRACE_TRAITS_H_
diff --git a/third_party/blink/renderer/platform/loader/cors/cors.cc b/third_party/blink/renderer/platform/loader/cors/cors.cc index f759b9a..05912d2 100644 --- a/third_party/blink/renderer/platform/loader/cors/cors.cc +++ b/third_party/blink/renderer/platform/loader/cors/cors.cc
@@ -4,79 +4,20 @@ #include "third_party/blink/renderer/platform/loader/cors/cors.h" -#include <memory> #include <string> -#include <utility> #include "net/http/http_util.h" #include "services/network/public/cpp/cors/cors.h" -#include "services/network/public/cpp/cors/preflight_cache.h" -#include "services/network/public/cpp/request_mode.h" #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h" #include "third_party/blink/public/platform/web_string.h" -#include "third_party/blink/renderer/platform/loader/cors/cors_error_string.h" #include "third_party/blink/renderer/platform/loader/fetch/resource_response.h" -#include "third_party/blink/renderer/platform/network/http_header_map.h" #include "third_party/blink/renderer/platform/network/http_names.h" -#include "third_party/blink/renderer/platform/runtime_enabled_features.h" -#include "third_party/blink/renderer/platform/weborigin/kurl.h" -#include "third_party/blink/renderer/platform/weborigin/scheme_registry.h" #include "third_party/blink/renderer/platform/weborigin/security_origin.h" -#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h" -#include "third_party/blink/renderer/platform/wtf/thread_specific.h" -#include "url/gurl.h" -#include "url/origin.h" namespace blink { namespace { -base::Optional<std::string> GetHeaderValue(const HTTPHeaderMap& header_map, - const AtomicString& header_name) { - if (header_map.Contains(header_name)) { - return header_map.Get(header_name).Latin1(); - } - return base::nullopt; -} - -network::cors::PreflightCache& GetPerThreadPreflightCache() { - DEFINE_THREAD_SAFE_STATIC_LOCAL(ThreadSpecific<network::cors::PreflightCache>, - cache, ()); - return *cache; -} - -base::Optional<std::string> GetOptionalHeaderValue( - const HTTPHeaderMap& header_map, - const AtomicString& header_name) { - const AtomicString& result = header_map.Get(header_name); - if (result.IsNull()) - return base::nullopt; - - return result.Ascii(); -} - -std::unique_ptr<net::HttpRequestHeaders> CreateNetHttpRequestHeaders( - const HTTPHeaderMap& header_map) { - std::unique_ptr<net::HttpRequestHeaders> request_headers = - std::make_unique<net::HttpRequestHeaders>(); - for (HTTPHeaderMap::const_iterator i = header_map.begin(), - end = header_map.end(); - i != end; ++i) { - DCHECK(!i->key.IsNull()); - DCHECK(!i->value.IsNull()); - request_headers->SetHeader(i->key.Ascii(), i->value.Ascii()); - } - return request_headers; -} - -url::Origin AsUrlOrigin(const SecurityOrigin& origin) { - // "file:" origin is treated like an opaque unique origin when - // allow-file-access-from-files is not specified. Such origin is not - // opaque (i.e., IsOpaque() returns false) but still serializes to - // "null". - return origin.ToString() == "null" ? url::Origin() : origin.ToUrlOrigin(); -} - // A parser for the value of the Access-Control-Expose-Headers header. class HTTPHeaderNameListParser { STACK_ALLOCATED(); @@ -159,165 +100,10 @@ namespace cors { -base::Optional<network::CorsErrorStatus> CheckAccess( - const KURL& response_url, - const HTTPHeaderMap& response_header, - network::mojom::CredentialsMode credentials_mode, - const SecurityOrigin& origin) { - return network::cors::CheckAccess( - response_url, - GetHeaderValue(response_header, http_names::kAccessControlAllowOrigin), - GetHeaderValue(response_header, - http_names::kAccessControlAllowCredentials), - credentials_mode, AsUrlOrigin(origin)); -} - -base::Optional<network::CorsErrorStatus> CheckPreflightAccess( - const KURL& response_url, - const int response_status_code, - const HTTPHeaderMap& response_header, - network::mojom::CredentialsMode actual_credentials_mode, - const SecurityOrigin& origin) { - return network::cors::CheckPreflightAccess( - response_url, response_status_code, - GetHeaderValue(response_header, http_names::kAccessControlAllowOrigin), - GetHeaderValue(response_header, - http_names::kAccessControlAllowCredentials), - actual_credentials_mode, AsUrlOrigin(origin)); -} - -base::Optional<network::CorsErrorStatus> CheckRedirectLocation( - const KURL& url, - network::mojom::RequestMode request_mode, - const SecurityOrigin* origin, - CorsFlag cors_flag) { - base::Optional<url::Origin> origin_to_pass; - if (origin) - origin_to_pass = AsUrlOrigin(*origin); - - // Blink-side implementations rewrite the origin instead of setting the - // tainted flag. - return network::cors::CheckRedirectLocation( - url, request_mode, origin_to_pass, cors_flag == CorsFlag::Set, false); -} - -base::Optional<network::CorsErrorStatus> CheckExternalPreflight( - const HTTPHeaderMap& response_header) { - return network::cors::CheckExternalPreflight( - GetHeaderValue(response_header, http_names::kAccessControlAllowExternal)); -} - bool IsCorsEnabledRequestMode(network::mojom::RequestMode request_mode) { return network::cors::IsCorsEnabledRequestMode(request_mode); } -base::Optional<network::CorsErrorStatus> EnsurePreflightResultAndCacheOnSuccess( - const HTTPHeaderMap& response_header_map, - const String& origin, - const KURL& request_url, - const String& request_method, - const HTTPHeaderMap& request_header_map, - network::mojom::CredentialsMode request_credentials_mode) { - DCHECK(!origin.IsNull()); - DCHECK(!request_method.IsNull()); - - base::Optional<network::mojom::CorsError> error; - - std::unique_ptr<network::cors::PreflightResult> result = - network::cors::PreflightResult::Create( - request_credentials_mode, - GetOptionalHeaderValue(response_header_map, - http_names::kAccessControlAllowMethods), - GetOptionalHeaderValue(response_header_map, - http_names::kAccessControlAllowHeaders), - GetOptionalHeaderValue(response_header_map, - http_names::kAccessControlMaxAge), - &error); - if (error) - return network::CorsErrorStatus(*error); - - base::Optional<network::CorsErrorStatus> status; - status = result->EnsureAllowedCrossOriginMethod(request_method.Ascii()); - if (status) - return status; - - // |is_revalidating| is not needed for blink-side CORS. - constexpr bool is_revalidating = false; - status = result->EnsureAllowedCrossOriginHeaders( - *CreateNetHttpRequestHeaders(request_header_map), is_revalidating); - if (status) - return status; - - GetPerThreadPreflightCache().AppendEntry( - url::Origin::Create(GURL(origin.Ascii())), request_url, - net::NetworkIsolationKey(), std::move(result)); - return base::nullopt; -} - -bool CheckIfRequestCanSkipPreflight( - const String& origin, - const KURL& url, - network::mojom::CredentialsMode credentials_mode, - const String& method, - const HTTPHeaderMap& request_header_map) { - DCHECK(!origin.IsNull()); - DCHECK(!method.IsNull()); - - // |is_revalidating| is not needed for blink-side CORS. - constexpr bool is_revalidating = false; - return GetPerThreadPreflightCache().CheckIfRequestCanSkipPreflight( - url::Origin::Create(GURL(origin.Ascii())), url, - net::NetworkIsolationKey(), credentials_mode, method.Ascii(), - *CreateNetHttpRequestHeaders(request_header_map), is_revalidating); -} - -// Keep this in sync with the identical function -// network::cors::CorsURLLoader::CalculateResponseTainting. -// -// This is the same as that function except using KURL and SecurityOrigin -// instead of GURL and url::Origin. We can't combine them because converting -// SecurityOrigin to url::Origin loses information about origins that are -// allowed by SecurityPolicy. -// -// This function also doesn't use a |tainted_origin| flag because Blink loaders -// mutate the origin instead of using such a flag. -network::mojom::FetchResponseType CalculateResponseTainting( - const KURL& url, - network::mojom::RequestMode request_mode, - const SecurityOrigin* origin, - const SecurityOrigin* isolated_world_origin, - CorsFlag cors_flag) { - if (url.ProtocolIsData()) - return network::mojom::FetchResponseType::kBasic; - - if (cors_flag == CorsFlag::Set) { - DCHECK(IsCorsEnabledRequestMode(request_mode)); - return network::mojom::FetchResponseType::kCors; - } - - if (!origin) { - // This is actually not defined in the fetch spec, but in this case CORS - // is disabled so no one should care this value. - return network::mojom::FetchResponseType::kBasic; - } - - if (request_mode == network::mojom::RequestMode::kNoCors) { - bool can_request = origin->CanRequest(url); - if (!can_request && isolated_world_origin) - can_request = isolated_world_origin->CanRequest(url); - if (!can_request) - return network::mojom::FetchResponseType::kOpaque; - } - return network::mojom::FetchResponseType::kBasic; -} - -bool CalculateCredentialsFlag( - network::mojom::CredentialsMode credentials_mode, - network::mojom::FetchResponseType response_tainting) { - return network::cors::CalculateCredentialsFlag(credentials_mode, - response_tainting); -} - bool IsCorsSafelistedMethod(const String& method) { DCHECK(!method.IsNull()); return network::cors::IsCorsSafelistedMethod(method.Latin1()); @@ -327,9 +113,10 @@ return network::cors::IsCorsSafelistedContentType(media_type.Latin1()); } -bool IsNoCorsSafelistedHeaderName(const String& name) { +bool IsNoCorsSafelistedHeader(const String& name, const String& value) { DCHECK(!name.IsNull()); - return network::cors::IsNoCorsSafelistedHeaderName(name.Latin1()); + DCHECK(!value.IsNull()); + return network::cors::IsNoCorsSafelistedHeader(name.Latin1(), value.Latin1()); } bool IsPrivilegedNoCorsHeaderName(const String& name) { @@ -337,23 +124,9 @@ return network::cors::IsPrivilegedNoCorsHeaderName(name.Latin1()); } -bool IsNoCorsSafelistedHeader(const String& name, const String& value) { +bool IsNoCorsSafelistedHeaderName(const String& name) { DCHECK(!name.IsNull()); - DCHECK(!value.IsNull()); - return network::cors::IsNoCorsSafelistedHeader(name.Latin1(), value.Latin1()); -} - -Vector<String> CorsUnsafeRequestHeaderNames(const HTTPHeaderMap& headers) { - net::HttpRequestHeaders::HeaderVector in; - for (const auto& entry : headers) { - in.push_back(net::HttpRequestHeaders::HeaderKeyValuePair( - entry.key.Latin1(), entry.value.Latin1())); - } - - Vector<String> header_names; - for (const auto& name : network::cors::CorsUnsafeRequestHeaderNames(in)) - header_names.push_back(WebString::FromLatin1(name)); - return header_names; + return network::cors::IsNoCorsSafelistedHeaderName(name.Latin1()); } PLATFORM_EXPORT Vector<String> PrivilegedNoCorsHeaderNames() { @@ -368,8 +141,13 @@ } bool ContainsOnlyCorsSafelistedHeaders(const HTTPHeaderMap& header_map) { - Vector<String> header_names = CorsUnsafeRequestHeaderNames(header_map); - return header_names.IsEmpty(); + net::HttpRequestHeaders::HeaderVector in; + for (const auto& entry : header_map) { + in.push_back(net::HttpRequestHeaders::HeaderKeyValuePair( + entry.key.Latin1(), entry.value.Latin1())); + } + + return network::cors::CorsUnsafeRequestHeaderNames(in).empty(); } bool ContainsOnlyCorsSafelistedOrForbiddenHeaders(
diff --git a/third_party/blink/renderer/platform/loader/cors/cors.h b/third_party/blink/renderer/platform/loader/cors/cors.h index e76d68a..f3886e79 100644 --- a/third_party/blink/renderer/platform/loader/cors/cors.h +++ b/third_party/blink/renderer/platform/loader/cors/cors.h
@@ -31,78 +31,17 @@ namespace cors { // Thin wrapper functions below are for calling ::network::cors functions from -// Blink core. Once Out-of-renderer CORS is enabled, following functions will -// be removed. -PLATFORM_EXPORT base::Optional<network::CorsErrorStatus> CheckAccess( - const KURL&, - const HTTPHeaderMap&, - network::mojom::CredentialsMode, - const SecurityOrigin&); - -PLATFORM_EXPORT base::Optional<network::CorsErrorStatus> CheckPreflightAccess( - const KURL&, - const int response_status_code, - const HTTPHeaderMap&, - network::mojom::CredentialsMode, - const SecurityOrigin&); - -PLATFORM_EXPORT base::Optional<network::CorsErrorStatus> CheckRedirectLocation( - const KURL&, - network::mojom::RequestMode, - const SecurityOrigin*, - CorsFlag); - -PLATFORM_EXPORT base::Optional<network::CorsErrorStatus> CheckExternalPreflight( - const HTTPHeaderMap&); - +// Blink core. PLATFORM_EXPORT bool IsCorsEnabledRequestMode(network::mojom::RequestMode); - -PLATFORM_EXPORT base::Optional<network::CorsErrorStatus> -EnsurePreflightResultAndCacheOnSuccess( - const HTTPHeaderMap& response_header_map, - const String& origin, - const KURL& request_url, - const String& request_method, - const HTTPHeaderMap& request_header_map, - network::mojom::CredentialsMode request_credentials_mode); - -PLATFORM_EXPORT bool CheckIfRequestCanSkipPreflight( - const String& origin, - const KURL&, - network::mojom::CredentialsMode, - const String& method, - const HTTPHeaderMap& request_header_map); - -// Returns the response tainting value -// (https://fetch.spec.whatwg.org/#concept-request-response-tainting) for a -// request and the CORS flag, as specified in -// https://fetch.spec.whatwg.org/#main-fetch. -PLATFORM_EXPORT network::mojom::FetchResponseType CalculateResponseTainting( - const KURL& url, - network::mojom::RequestMode request_mode, - const SecurityOrigin* origin, - const SecurityOrigin* isolated_world_origin, - CorsFlag cors_flag); - -PLATFORM_EXPORT bool CalculateCredentialsFlag( - network::mojom::CredentialsMode credentials_mode, - network::mojom::FetchResponseType response_tainting); - -// Thin wrapper functions that will not be removed even after out-of-renderer -// CORS is enabled. PLATFORM_EXPORT bool IsCorsSafelistedMethod(const String& method); PLATFORM_EXPORT bool IsCorsSafelistedContentType(const String&); PLATFORM_EXPORT bool IsNoCorsSafelistedHeader(const String& name, const String& value); PLATFORM_EXPORT bool IsPrivilegedNoCorsHeaderName(const String& name); PLATFORM_EXPORT bool IsNoCorsSafelistedHeaderName(const String& name); -PLATFORM_EXPORT Vector<String> CorsUnsafeRequestHeaderNames( - const HTTPHeaderMap& headers); PLATFORM_EXPORT Vector<String> PrivilegedNoCorsHeaderNames(); PLATFORM_EXPORT bool IsForbiddenHeaderName(const String& name); PLATFORM_EXPORT bool ContainsOnlyCorsSafelistedHeaders(const HTTPHeaderMap&); -PLATFORM_EXPORT bool ContainsOnlyCorsSafelistedOrForbiddenHeaders( - const HTTPHeaderMap&); PLATFORM_EXPORT bool IsOkStatus(int status); @@ -114,7 +53,6 @@ // |kNavigate|. // This should be identical to CalculateCorsFlag defined in // //services/network/cors/cors_url_loader.cc. -// This function will be removed when out-of-renderer CORS is enabled. PLATFORM_EXPORT bool CalculateCorsFlag( const KURL& url, const SecurityOrigin* initiator_origin,
diff --git a/third_party/blink/renderer/platform/loader/cors/cors_test.cc b/third_party/blink/renderer/platform/loader/cors/cors_test.cc index 173f852..33a8264 100644 --- a/third_party/blink/renderer/platform/loader/cors/cors_test.cc +++ b/third_party/blink/renderer/platform/loader/cors/cors_test.cc
@@ -7,7 +7,6 @@ #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h" #include "third_party/blink/renderer/platform/loader/fetch/resource_response.h" -#include "third_party/blink/renderer/platform/weborigin/security_origin.h" namespace blink { @@ -101,87 +100,6 @@ HTTPHeaderSet({"a", "b", "*"})); } -// Keep this in sync with the CalculateResponseTainting test in -// services/network/cors/cors_url_loader_unittest.cc. -TEST(CorsTest, CalculateResponseTainting) { - using network::mojom::FetchResponseType; - using network::mojom::RequestMode; - - const KURL same_origin_url("https://example.com/"); - const KURL cross_origin_url("https://example2.com/"); - scoped_refptr<SecurityOrigin> origin_refptr = - SecurityOrigin::Create(same_origin_url); - const SecurityOrigin* origin = origin_refptr.get(); - const SecurityOrigin* no_origin = nullptr; - - // CORS flag is false, same-origin request - EXPECT_EQ( - FetchResponseType::kBasic, - cors::CalculateResponseTainting(same_origin_url, RequestMode::kSameOrigin, - origin, nullptr, CorsFlag::Unset)); - EXPECT_EQ( - FetchResponseType::kBasic, - cors::CalculateResponseTainting(same_origin_url, RequestMode::kNoCors, - origin, nullptr, CorsFlag::Unset)); - EXPECT_EQ(FetchResponseType::kBasic, - cors::CalculateResponseTainting(same_origin_url, RequestMode::kCors, - origin, nullptr, CorsFlag::Unset)); - EXPECT_EQ(FetchResponseType::kBasic, - cors::CalculateResponseTainting( - same_origin_url, RequestMode::kCorsWithForcedPreflight, origin, - nullptr, CorsFlag::Unset)); - EXPECT_EQ( - FetchResponseType::kBasic, - cors::CalculateResponseTainting(same_origin_url, RequestMode::kNavigate, - origin, nullptr, CorsFlag::Unset)); - - // CORS flag is false, cross-origin request - EXPECT_EQ( - FetchResponseType::kOpaque, - cors::CalculateResponseTainting(cross_origin_url, RequestMode::kNoCors, - origin, nullptr, CorsFlag::Unset)); - EXPECT_EQ( - FetchResponseType::kBasic, - cors::CalculateResponseTainting(cross_origin_url, RequestMode::kNavigate, - origin, nullptr, CorsFlag::Unset)); - - // CORS flag is true, same-origin request - EXPECT_EQ(FetchResponseType::kCors, - cors::CalculateResponseTainting(same_origin_url, RequestMode::kCors, - origin, nullptr, CorsFlag::Set)); - EXPECT_EQ(FetchResponseType::kCors, - cors::CalculateResponseTainting( - same_origin_url, RequestMode::kCorsWithForcedPreflight, origin, - nullptr, CorsFlag::Set)); - - // CORS flag is true, cross-origin request - EXPECT_EQ(FetchResponseType::kCors, cors::CalculateResponseTainting( - cross_origin_url, RequestMode::kCors, - origin, nullptr, CorsFlag::Set)); - EXPECT_EQ(FetchResponseType::kCors, - cors::CalculateResponseTainting( - cross_origin_url, RequestMode::kCorsWithForcedPreflight, origin, - nullptr, CorsFlag::Set)); - - // Origin is not provided. - EXPECT_EQ( - FetchResponseType::kBasic, - cors::CalculateResponseTainting(same_origin_url, RequestMode::kNoCors, - no_origin, nullptr, CorsFlag::Unset)); - EXPECT_EQ( - FetchResponseType::kBasic, - cors::CalculateResponseTainting(same_origin_url, RequestMode::kNavigate, - no_origin, nullptr, CorsFlag::Unset)); - EXPECT_EQ( - FetchResponseType::kBasic, - cors::CalculateResponseTainting(cross_origin_url, RequestMode::kNoCors, - no_origin, nullptr, CorsFlag::Unset)); - EXPECT_EQ( - FetchResponseType::kBasic, - cors::CalculateResponseTainting(cross_origin_url, RequestMode::kNavigate, - no_origin, nullptr, CorsFlag::Unset)); -} - } // namespace } // namespace blink
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc index f9350633..900b1ce 100644 --- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc +++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
@@ -800,11 +800,13 @@ } } -void ResourceFetcher::UpdateMemoryCacheStats(Resource* resource, - RevalidationPolicy policy, - const FetchParameters& params, - const ResourceFactory& factory, - bool is_static_data) const { +void ResourceFetcher::UpdateMemoryCacheStats( + Resource* resource, + RevalidationPolicy policy, + const FetchParameters& params, + const ResourceFactory& factory, + bool is_static_data, + bool in_cached_resources_map) const { if (is_static_data) return; @@ -822,6 +824,11 @@ DEFINE_RESOURCE_HISTOGRAM("Dead."); } + // Log metrics to evaluate effectiveness of the memory cache if it were scoped + // to the document. + if (in_cached_resources_map) + DEFINE_RESOURCE_HISTOGRAM("PerDocument."); + // Async (and defer) scripts may have more cache misses, track them // separately. See https://crbug.com/1043679 for context. if (params.Defer() != FetchParameters::DeferOption::kNoDefer && @@ -1084,7 +1091,11 @@ } } - UpdateMemoryCacheStats(resource, policy, params, factory, is_static_data); + bool in_cached_resources_map = cached_resources_map_.Contains( + MemoryCache::RemoveFragmentIdentifierIfNeeded(params.Url())); + + UpdateMemoryCacheStats(resource, policy, params, factory, is_static_data, + in_cached_resources_map); switch (policy) { case RevalidationPolicy::kReload: @@ -1132,8 +1143,7 @@ DCHECK(EqualIgnoringFragmentIdentifier(resource->Url(), params.Url())); if (policy == RevalidationPolicy::kUse && resource->GetStatus() == ResourceStatus::kCached && - !cached_resources_map_.Contains( - MemoryCache::RemoveFragmentIdentifierIfNeeded(params.Url()))) { + !in_cached_resources_map) { // Loaded from MemoryCache. DidLoadResourceFromMemoryCache(resource, resource_request, is_static_data); }
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h index c90b94f..981c18e 100644 --- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h +++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h
@@ -404,7 +404,8 @@ RevalidationPolicy, const FetchParameters&, const ResourceFactory&, - bool is_static_data) const; + bool is_static_data, + bool in_cached_resources_map) const; void ScheduleStaleRevalidate(Resource* stale_resource); void RevalidateStaleResource(Resource* stale_resource);
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc index e4392e7..edbd8c3 100644 --- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc +++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc
@@ -65,6 +65,7 @@ #include "third_party/blink/renderer/platform/loader/testing/mock_resource_client.h" #include "third_party/blink/renderer/platform/loader/testing/test_loader_factory.h" #include "third_party/blink/renderer/platform/loader/testing/test_resource_fetcher_properties.h" +#include "third_party/blink/renderer/platform/testing/histogram_tester.h" #include "third_party/blink/renderer/platform/testing/mock_context_lifecycle_notifier.h" #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h" #include "third_party/blink/renderer/platform/testing/scoped_mocked_url.h" @@ -228,6 +229,7 @@ } TEST_F(ResourceFetcherTest, UseExistingResource) { + blink::HistogramTester histogram_tester; auto* fetcher = CreateFetcher(); KURL url("http://127.0.0.1:8000/foo.html"); @@ -248,6 +250,33 @@ Resource* new_resource = MockResource::Fetch(fetch_params, fetcher, nullptr); EXPECT_EQ(resource, new_resource); + + // Test histograms. + histogram_tester.ExpectTotalCount( + "Blink.MemoryCache.RevalidationPolicy.PerDocument.Mock", 1); + histogram_tester.ExpectBucketCount( + "Blink.MemoryCache.RevalidationPolicy.PerDocument.Mock", + 0 /* RevalidationPolicy::kUse */, 1); + + histogram_tester.ExpectTotalCount("Blink.MemoryCache.RevalidationPolicy.Mock", + 2); + histogram_tester.ExpectBucketCount( + "Blink.MemoryCache.RevalidationPolicy.Mock", + 3 /* RevalidationPolicy::kLoad */, 1); + histogram_tester.ExpectBucketCount( + "Blink.MemoryCache.RevalidationPolicy.Mock", + 0 /* RevalidationPolicy::kUse */, 1); + + // Create a new fetcher and load the same resource. The PerDocument histogram + // should not be incremented. + auto* new_fetcher = CreateFetcher(); + Resource* new_fetcher_resource = + MockResource::Fetch(fetch_params, new_fetcher, nullptr); + EXPECT_EQ(resource, new_fetcher_resource); + histogram_tester.ExpectTotalCount( + "Blink.MemoryCache.RevalidationPolicy.PerDocument.Mock", 1); + histogram_tester.ExpectTotalCount("Blink.MemoryCache.RevalidationPolicy.Mock", + 3); } // Verify that the ad bit is copied to WillSendRequest's request when the
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index a88b1c96..0e8650a 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -1093,7 +1093,8 @@ { name: "LayoutNGTextControl", depends_on: ["EditingNG"], - status: "experimental", + // In Chrome, the flag is managed by Finch. + status: "test", }, { name: "LayoutNGWebkitBox",
diff --git a/third_party/blink/renderer/platform/wtf/DEPS b/third_party/blink/renderer/platform/wtf/DEPS index 962b2909..f42e6ba 100644 --- a/third_party/blink/renderer/platform/wtf/DEPS +++ b/third_party/blink/renderer/platform/wtf/DEPS
@@ -1,6 +1,7 @@ include_rules = [ # To only allow a subset of base/ in Blink, we explicitly list all # directories and files instead of writing 'base/'. + "+base/allocator/buildflags.h", "+base/allocator/partition_allocator", "+base/atomic_ref_count.h", "+base/auto_reset.h",
diff --git a/third_party/blink/renderer/platform/wtf/allocator/allocator.h b/third_party/blink/renderer/platform/wtf/allocator/allocator.h index b135f37..c6b35283 100644 --- a/third_party/blink/renderer/platform/wtf/allocator/allocator.h +++ b/third_party/blink/renderer/platform/wtf/allocator/allocator.h
@@ -7,6 +7,7 @@ #include <atomic> +#include "base/allocator/partition_allocator/partition_alloc.h" #include "base/check_op.h" #include "build/build_config.h" #include "third_party/blink/renderer/platform/wtf/allocator/partitions.h" @@ -108,6 +109,58 @@ // }; // +// In official builds, do not include type info string literals to avoid +// bloating the binary. +#if defined(OFFICIAL_BUILD) +#define WTF_HEAP_PROFILER_TYPE_NAME(T) nullptr +#else +#define WTF_HEAP_PROFILER_TYPE_NAME(T) ::WTF::GetStringWithTypeName<T>() +#endif + +// Both of these macros enable fast malloc and provide type info to the heap +// profiler. The regular macro does not provide type info in official builds, +// to avoid bloating the binary with type name strings. The |WITH_TYPE_NAME| +// variant provides type info unconditionally, so it should be used sparingly. +// Furthermore, the |WITH_TYPE_NAME| variant does not work if |type| is a +// template argument; |USING_FAST_MALLOC| does. +#define USING_FAST_MALLOC(type) \ + USING_FAST_MALLOC_INTERNAL(type, WTF_HEAP_PROFILER_TYPE_NAME(type)) +#define USING_FAST_MALLOC_WITH_TYPE_NAME(type) \ + USING_FAST_MALLOC_INTERNAL(type, #type) + +// FastMalloc doesn't provide isolation, only a (hopefully fast) malloc(). When +// PartitionAlloc is already the malloc() implementation, there is nothing to +// do. +// +// Note that we could keep the two heaps separate, but each PartitionAlloc's +// root has a cost, both in used memory and in virtual address space. Don't pay +// it when we don't have to. +#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) + +// Still using operator overaloading to be closer to the other case, and not +// require code changes to DISALLOW_NEW() objects. +#define USING_FAST_MALLOC_INTERNAL(type, typeName) \ + public: \ + void* operator new(size_t, void* p) { return p; } \ + void* operator new[](size_t, void* p) { return p; } \ + \ + void* operator new(size_t size) { return malloc(size); } \ + \ + void operator delete(void* p) { free(p); } \ + \ + void* operator new[](size_t size) { return malloc(size); } \ + \ + void operator delete[](void* p) { free(p); } \ + void* operator new(size_t, NotNullTag, void* location) { \ + DCHECK(location); \ + return location; \ + } \ + \ + private: \ + friend class ::WTF::internal::__thisIsHereToForceASemicolonAfterThisMacro + +#else + #define USING_FAST_MALLOC_INTERNAL(type, typeName) \ public: \ void* operator new(size_t, void* p) { return p; } \ @@ -132,24 +185,7 @@ private: \ friend class ::WTF::internal::__thisIsHereToForceASemicolonAfterThisMacro -// In official builds, do not include type info string literals to avoid -// bloating the binary. -#if defined(OFFICIAL_BUILD) -#define WTF_HEAP_PROFILER_TYPE_NAME(T) nullptr -#else -#define WTF_HEAP_PROFILER_TYPE_NAME(T) ::WTF::GetStringWithTypeName<T>() -#endif - -// Both of these macros enable fast malloc and provide type info to the heap -// profiler. The regular macro does not provide type info in official builds, -// to avoid bloating the binary with type name strings. The |WITH_TYPE_NAME| -// variant provides type info unconditionally, so it should be used sparingly. -// Furthermore, the |WITH_TYPE_NAME| variant does not work if |type| is a -// template argument; |USING_FAST_MALLOC| does. -#define USING_FAST_MALLOC(type) \ - USING_FAST_MALLOC_INTERNAL(type, WTF_HEAP_PROFILER_TYPE_NAME(type)) -#define USING_FAST_MALLOC_WITH_TYPE_NAME(type) \ - USING_FAST_MALLOC_INTERNAL(type, #type) +#endif // !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) // TOOD(omerkatz): replace these casts with std::atomic_ref (C++20) once it // becomes available @@ -359,4 +395,4 @@ return location; } -#endif /* WTF_Allocator_h */ +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_ALLOCATOR_ALLOCATOR_H_
diff --git a/third_party/blink/renderer/platform/wtf/allocator/partitions.cc b/third_party/blink/renderer/platform/wtf/allocator/partitions.cc index ae48cea..edb18ec 100644 --- a/third_party/blink/renderer/platform/wtf/allocator/partitions.cc +++ b/third_party/blink/renderer/platform/wtf/allocator/partitions.cc
@@ -54,7 +54,9 @@ // These statics are inlined, so cannot be LazyInstances. We create the values, // and then set the pointers correctly in Initialize(). +#if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) base::ThreadSafePartitionRoot* Partitions::fast_malloc_root_ = nullptr; +#endif base::ThreadSafePartitionRoot* Partitions::array_buffer_root_ = nullptr; base::ThreadSafePartitionRoot* Partitions::buffer_root_ = nullptr; base::ThreadUnsafePartitionRoot* Partitions::layout_root_ = nullptr; @@ -67,26 +69,22 @@ // static bool Partitions::InitializeOnce() { +#if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) static base::PartitionAllocator fast_malloc_allocator{}; + fast_malloc_allocator.init( + {base::PartitionOptions::Alignment::kRegular, + base::PartitionOptions::ThreadCache::kEnabled, + base::PartitionOptions::PCScan::kDisabledByDefault}); + + fast_malloc_root_ = fast_malloc_allocator.root(); +#endif // !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) + static base::PartitionAllocator array_buffer_allocator{}; static base::PartitionAllocator buffer_allocator{}; static base::ThreadUnsafePartitionAllocator layout_allocator{}; base::PartitionAllocGlobalInit(&Partitions::HandleOutOfMemory); - // Only one thread cache at a time is supported, in this case it is already - // claimed by malloc(). -#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) - fast_malloc_allocator.init( - {base::PartitionOptions::Alignment::kRegular, - base::PartitionOptions::ThreadCache::kDisabled, - base::PartitionOptions::PCScan::kDisabledByDefault}); -#else - fast_malloc_allocator.init( - {base::PartitionOptions::Alignment::kRegular, - base::PartitionOptions::ThreadCache::kEnabled, - base::PartitionOptions::PCScan::kDisabledByDefault}); -#endif array_buffer_allocator.init( {base::PartitionOptions::Alignment::kRegular, base::PartitionOptions::ThreadCache::kDisabled, @@ -98,14 +96,15 @@ base::PartitionOptions::ThreadCache::kDisabled, base::PartitionOptions::PCScan::kAlwaysDisabled}); - fast_malloc_root_ = fast_malloc_allocator.root(); array_buffer_root_ = array_buffer_allocator.root(); buffer_root_ = buffer_allocator.root(); layout_root_ = layout_allocator.root(); if (base::features::IsPartitionAllocPCScanEnabled() || base::FeatureList::IsEnabled(kPCScanBlinkPartitions)) { +#if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) fast_malloc_root_->EnablePCScan(); +#endif buffer_root_->EnablePCScan(); } @@ -130,8 +129,10 @@ // accessed only on the main thread. DCHECK(IsMainThread()); +#if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) FastMallocPartition()->DumpStats("fast_malloc", is_light_dump, partition_stats_dumper); +#endif ArrayBufferPartition()->DumpStats("array_buffer", is_light_dump, partition_stats_dumper); BufferPartition()->DumpStats("buffer", is_light_dump, partition_stats_dumper); @@ -167,8 +168,10 @@ DCHECK(initialized_); size_t total_size = 0; // Racy reads below: this is fine to collect statistics. +#if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) total_size += TS_UNCHECKED_READ(FastMallocPartition()->total_size_of_committed_pages); +#endif total_size += TS_UNCHECKED_READ(ArrayBufferPartition()->total_size_of_committed_pages); total_size += @@ -261,20 +264,36 @@ return BufferPartition()->ActualSize(n); } +// Ideally this would be removed when PartitionAlloc is malloc(), but there are +// quite a few callers. Just forward to the C functions instead. Most of the +// usual callers will never reach here though, as USING_FAST_MALLOC() becomes a +// no-op. // static void* Partitions::FastMalloc(size_t n, const char* type_name) { +#if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) return FastMallocPartition()->Alloc(n, type_name); +#else + return malloc(n); +#endif } // static void* Partitions::FastZeroedMalloc(size_t n, const char* type_name) { +#if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) return FastMallocPartition()->AllocFlags(base::PartitionAllocZeroFill, n, type_name); +#else + return calloc(n, 1); +#endif } // static void Partitions::FastFree(void* p) { +#if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) FastMallocPartition()->Free(p); +#else + free(p); +#endif } // static
diff --git a/third_party/blink/renderer/platform/wtf/allocator/partitions.h b/third_party/blink/renderer/platform/wtf/allocator/partitions.h index b8b89b1..6d949c79 100644 --- a/third_party/blink/renderer/platform/wtf/allocator/partitions.h +++ b/third_party/blink/renderer/platform/wtf/allocator/partitions.h
@@ -89,16 +89,20 @@ static void HandleOutOfMemory(size_t size); private: +#if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) ALWAYS_INLINE static base::ThreadSafePartitionRoot* FastMallocPartition() { DCHECK(initialized_); return fast_malloc_root_; } +#endif // !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) static bool InitializeOnce(); static bool initialized_; // See Allocator.md for a description of these partitions. +#if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) static base::ThreadSafePartitionRoot* fast_malloc_root_; +#endif static base::ThreadSafePartitionRoot* array_buffer_root_; static base::ThreadSafePartitionRoot* buffer_root_; static base::ThreadUnsafePartitionRoot* layout_root_;
diff --git a/third_party/blink/renderer/platform/wtf/assertions.h b/third_party/blink/renderer/platform/wtf/assertions.h index 41ace57..8830e38 100644 --- a/third_party/blink/renderer/platform/wtf/assertions.h +++ b/third_party/blink/renderer/platform/wtf/assertions.h
@@ -77,83 +77,6 @@ inline bool operator!=(const Type& a, const Type* b) { return !(a == b); } \ inline bool operator!=(const Type* a, const Type& b) { return !(a == b); } -// DEFINE_TYPE_CASTS -// -// ToType() functions are static_cast<> wrappers with SECURITY_DCHECK. It's -// helpful to find bad casts. -// -// ToTypeOrNull() functions are similar to dynamic_cast<>. They return -// type-casted values if the specified predicate is true, and return -// nullptr otherwise. -// -// ToTypeOrDie() has a runtime type check, and it crashes if the specified -// object is not an instance of the destination type. It is used if -// * it's hard to prevent from passing unexpected objects, -// * proceeding with the following code doesn't make sense, and -// * cost of runtime type check is acceptable. -#define DEFINE_TYPE_CASTS(Type, ArgType, argument, pointerPredicate, \ - referencePredicate) \ - inline Type* To##Type(ArgType* argument) { \ - SECURITY_DCHECK(!argument || (pointerPredicate)); \ - return static_cast<Type*>(argument); \ - } \ - inline const Type* To##Type(const ArgType* argument) { \ - SECURITY_DCHECK(!argument || (pointerPredicate)); \ - return static_cast<const Type*>(argument); \ - } \ - inline Type& To##Type(ArgType& argument) { \ - SECURITY_DCHECK(referencePredicate); \ - return static_cast<Type&>(argument); \ - } \ - inline const Type& To##Type(const ArgType& argument) { \ - SECURITY_DCHECK(referencePredicate); \ - return static_cast<const Type&>(argument); \ - } \ - void To##Type(const Type*); \ - void To##Type(const Type&); \ - \ - inline Type* To##Type##OrNull(ArgType* argument) { \ - if (!(argument) || !(pointerPredicate)) \ - return nullptr; \ - return static_cast<Type*>(argument); \ - } \ - inline const Type* To##Type##OrNull(const ArgType* argument) { \ - if (!(argument) || !(pointerPredicate)) \ - return nullptr; \ - return static_cast<const Type*>(argument); \ - } \ - inline Type* To##Type##OrNull(ArgType& argument) { \ - if (!(referencePredicate)) \ - return nullptr; \ - return static_cast<Type*>(&argument); \ - } \ - inline const Type* To##Type##OrNull(const ArgType& argument) { \ - if (!(referencePredicate)) \ - return nullptr; \ - return static_cast<const Type*>(&argument); \ - } \ - void To##Type##OrNull(const Type*); \ - void To##Type##OrNull(const Type&); \ - \ - inline Type* To##Type##OrDie(ArgType* argument) { \ - CHECK(!argument || (pointerPredicate)); \ - return static_cast<Type*>(argument); \ - } \ - inline const Type* To##Type##OrDie(const ArgType* argument) { \ - CHECK(!argument || (pointerPredicate)); \ - return static_cast<const Type*>(argument); \ - } \ - inline Type& To##Type##OrDie(ArgType& argument) { \ - CHECK(referencePredicate); \ - return static_cast<Type&>(argument); \ - } \ - inline const Type& To##Type##OrDie(const ArgType& argument) { \ - CHECK(referencePredicate); \ - return static_cast<const Type&>(argument); \ - } \ - void To##Type##OrDie(const Type*); \ - void To##Type##OrDie(const Type&) - // Check at compile time that related enums stay in sync. #define STATIC_ASSERT_ENUM(a, b) \ static_assert(static_cast<int>(a) == static_cast<int>(b), \
diff --git a/third_party/blink/renderer/platform/wtf/list_hash_set.h b/third_party/blink/renderer/platform/wtf/list_hash_set.h index bfa0975d..6e8a3cb 100644 --- a/third_party/blink/renderer/platform/wtf/list_hash_set.h +++ b/third_party/blink/renderer/platform/wtf/list_hash_set.h
@@ -59,30 +59,167 @@ template <typename Set> class ListHashSetConstReverseIterator; -template <typename ValueArg> -class ListHashSetNodeBase; template <typename ValueArg, typename Allocator> -class ListHashSetNode; -template <typename ValueArg, size_t inlineCapacity> -struct ListHashSetAllocator; +class MallocedListHashSetNode; +template <typename ValueArg, wtf_size_t inlineCapacity> +struct MallocedListHashSetAllocator; template <typename HashArg> struct ListHashSetNodeHashFunctions; -template <typename HashArg> +template <typename HashArg, typename NodeArg> struct ListHashSetTranslator; +template <typename Value, wtf_size_t inlineCapacity, typename Allocator> +struct ListHashSetTraits; -template <typename Value, typename Allocator> -struct ListHashSetTraits - : public HashTraits<ListHashSetNode<Value, Allocator>*> { - using Node = ListHashSetNode<Value, Allocator>; +template <typename Value, wtf_size_t inlineCapacity> +struct ListHashSetTraits<Value, + inlineCapacity, + MallocedListHashSetAllocator<Value, inlineCapacity>> + : public HashTraits<MallocedListHashSetNode< + Value, + MallocedListHashSetAllocator<Value, inlineCapacity>>*> { + using Allocator = MallocedListHashSetAllocator<Value, inlineCapacity>; + using Node = MallocedListHashSetNode<Value, Allocator>; +}; - static void ConstructDeletedValue(Node*& slot, bool) { - AsAtomicPtr(&slot)->store(reinterpret_cast<Node*>(-1), - std::memory_order_relaxed); +template <typename ValueArg, typename AllocatorArg> +class MallocedListHashSetNode { + DISALLOW_NEW(); + + public: + using NodeAllocator = AllocatorArg; + using PointerType = MallocedListHashSetNode*; + using Value = ValueArg; + + template <typename U> + static MallocedListHashSetNode* Create(NodeAllocator* allocator, U&& value) { + return new (allocator->AllocateNode()) + MallocedListHashSetNode(std::forward<U>(value)); } - static constexpr bool kCanTraceConcurrently = - HashTraits<Value>::kCanTraceConcurrently; + template <typename U> + explicit MallocedListHashSetNode(U&& value) + : value_(std::forward<U>(value)) {} + + void Destroy(NodeAllocator* allocator) { + this->~MallocedListHashSetNode(); + allocator->Deallocate(this); + } + + MallocedListHashSetNode* Next() const { return next_; } + MallocedListHashSetNode* Prev() const { return prev_; } + + ValueArg value_; + PointerType prev_ = nullptr; + PointerType next_ = nullptr; +#if DCHECK_IS_ON() + bool is_allocated_ = true; +#endif +}; + +// This allocator is only used for non-Heap ListHashSets. +template <typename ValueArg, wtf_size_t inlineCapacity> +struct MallocedListHashSetAllocator : public PartitionAllocator { + using TableAllocator = PartitionAllocator; + using Node = MallocedListHashSetNode<ValueArg, MallocedListHashSetAllocator>; + + class AllocatorProvider { + DISALLOW_NEW(); + + public: + AllocatorProvider() = default; + void CreateAllocatorIfNeeded() { + if (!allocator_) + allocator_ = new MallocedListHashSetAllocator; + } + + void ReleaseAllocator() { + delete allocator_; + allocator_ = nullptr; + } + + void Swap(AllocatorProvider& other) { + std::swap(allocator_, other.allocator_); + } + + MallocedListHashSetAllocator* Get() const { + DCHECK(allocator_); + return allocator_; + } + + private: + // Not using std::unique_ptr as this pointer should be deleted at + // releaseAllocator() method rather than at destructor. + MallocedListHashSetAllocator* allocator_ = nullptr; + }; + + MallocedListHashSetAllocator() : free_list_(Pool()) { + memset(pool_, 0, sizeof(pool_)); + } + + Node* AllocateNode() { + Node* result = free_list_; + + if (!result) { + return static_cast<Node*>(WTF::Partitions::FastMalloc( + sizeof(Node), WTF_HEAP_PROFILER_TYPE_NAME(Node))); + } + +#if DCHECK_IS_ON() + DCHECK(!result->is_allocated_); +#endif + + Node* next = result->Next(); +#if DCHECK_IS_ON() + DCHECK(!next || !next->is_allocated_); +#endif + if (!next && !is_done_with_initial_free_list_) { + next = result + 1; + if (next == PastPool()) { + is_done_with_initial_free_list_ = true; + next = nullptr; + } else { + DCHECK(InPool(next)); +#if DCHECK_IS_ON() + DCHECK(!next->is_allocated_); +#endif + } + } + free_list_ = next; + + return result; + } + + void Deallocate(Node* node) { + if (InPool(node)) { +#if DCHECK_IS_ON() + node->is_allocated_ = false; +#endif + node->next_ = free_list_; + free_list_ = node; + return; + } + + WTF::Partitions::FastFree(node); + } + + bool InPool(Node* node) { return node >= Pool() && node < PastPool(); } + + private: + Node* Pool() { return reinterpret_cast_ptr<Node*>(pool_); } + Node* PastPool() { return Pool() + kPoolSize; } + + Node* free_list_; + bool is_done_with_initial_free_list_ = false; +#if defined(MEMORY_TOOL_REPLACES_ALLOCATOR) + // The allocation pool for nodes is one big chunk that ASAN has no insight + // into, so it can cloak errors. Make it as small as possible to force nodes + // to be allocated individually where ASAN can see them. + static const size_t kPoolSize = 1; +#else + static const size_t kPoolSize = inlineCapacity; +#endif + alignas(Node) char pool_[sizeof(Node) * kPoolSize]; }; // Note that for a ListHashSet you cannot specify the HashTraits as a template @@ -91,37 +228,37 @@ size_t inlineCapacity = 256, typename HashArg = typename DefaultHash<ValueArg>::Hash, typename AllocatorArg = - ListHashSetAllocator<ValueArg, inlineCapacity>> + MallocedListHashSetAllocator<ValueArg, inlineCapacity>> class ListHashSet : public ConditionalDestructor< ListHashSet<ValueArg, inlineCapacity, HashArg, AllocatorArg>, AllocatorArg::kIsGarbageCollected> { - typedef AllocatorArg Allocator; + using Allocator = AllocatorArg; USE_ALLOCATOR(ListHashSet, Allocator); - typedef ListHashSetNode<ValueArg, Allocator> Node; - typedef ListHashSetTraits<ValueArg, Allocator> NodeTraits; - typedef ListHashSetNodeHashFunctions<HashArg> NodeHash; - typedef ListHashSetTranslator<HashArg> BaseTranslator; + using NodeTraits = ListHashSetTraits<ValueArg, inlineCapacity, Allocator>; + using Node = typename NodeTraits::Node; + using NodeHash = ListHashSetNodeHashFunctions<HashArg>; + using BaseTranslator = ListHashSetTranslator<HashArg, Node>; - typedef HashTable<Node*, - Node*, + typedef HashTable<typename Node::PointerType, + typename Node::PointerType, IdentityExtractor, NodeHash, NodeTraits, NodeTraits, typename Allocator::TableAllocator> ImplType; - typedef HashTableIterator<Node*, - Node*, + typedef HashTableIterator<typename Node::PointerType, + typename Node::PointerType, IdentityExtractor, NodeHash, NodeTraits, NodeTraits, typename Allocator::TableAllocator> ImplTypeIterator; - typedef HashTableConstIterator<Node*, - Node*, + typedef HashTableConstIterator<typename Node::PointerType, + typename Node::PointerType, IdentityExtractor, NodeHash, NodeTraits, @@ -254,7 +391,7 @@ void PrependNode(Node*); void InsertNodeBefore(Node* before_node, Node* new_node); void DeleteAllNodes(); - Allocator* GetAllocator() const { return allocator_provider_.Get(); } + Allocator* GetAllocator() { return allocator_provider_.Get(); } void CreateAllocatorIfNeeded() { allocator_provider_.CreateAllocatorIfNeeded(); } @@ -271,190 +408,11 @@ } ImplType impl_; - Node* head_; - Node* tail_; + typename Node::PointerType head_; + typename Node::PointerType tail_; typename Allocator::AllocatorProvider allocator_provider_; }; -// ListHashSetNode has this base class to hold the members because the MSVC -// compiler otherwise gets into circular template dependencies when trying to do -// sizeof on a node. -template <typename ValueArg> -class ListHashSetNodeBase { - DISALLOW_NEW(); - - protected: - template <typename U> - explicit ListHashSetNodeBase(U&& value) : value_(std::forward<U>(value)) {} - - public: - ValueArg value_; - ListHashSetNodeBase* prev_ = nullptr; - ListHashSetNodeBase* next_ = nullptr; -#if DCHECK_IS_ON() - bool is_allocated_ = true; -#endif -}; - -// This allocator is only used for non-Heap ListHashSets. -template <typename ValueArg, size_t inlineCapacity> -struct ListHashSetAllocator : public PartitionAllocator { - typedef PartitionAllocator TableAllocator; - typedef ListHashSetNode<ValueArg, ListHashSetAllocator> Node; - typedef ListHashSetNodeBase<ValueArg> NodeBase; - - class AllocatorProvider { - DISALLOW_NEW(); - - public: - AllocatorProvider() : allocator_(nullptr) {} - void CreateAllocatorIfNeeded() { - if (!allocator_) - allocator_ = new ListHashSetAllocator; - } - - void ReleaseAllocator() { - delete allocator_; - allocator_ = nullptr; - } - - void Swap(AllocatorProvider& other) { - std::swap(allocator_, other.allocator_); - } - - ListHashSetAllocator* Get() const { - DCHECK(allocator_); - return allocator_; - } - - private: - // Not using std::unique_ptr as this pointer should be deleted at - // releaseAllocator() method rather than at destructor. - ListHashSetAllocator* allocator_; - }; - - ListHashSetAllocator() - : free_list_(Pool()), is_done_with_initial_free_list_(false) { - memset(pool_, 0, sizeof(pool_)); - } - - Node* AllocateNode() { - Node* result = free_list_; - - if (!result) - return static_cast<Node*>(WTF::Partitions::FastMalloc( - sizeof(NodeBase), WTF_HEAP_PROFILER_TYPE_NAME(Node))); - -#if DCHECK_IS_ON() - DCHECK(!result->is_allocated_); -#endif - - Node* next = result->Next(); -#if DCHECK_IS_ON() - DCHECK(!next || !next->is_allocated_); -#endif - if (!next && !is_done_with_initial_free_list_) { - next = result + 1; - if (next == PastPool()) { - is_done_with_initial_free_list_ = true; - next = nullptr; - } else { - DCHECK(InPool(next)); -#if DCHECK_IS_ON() - DCHECK(!next->is_allocated_); -#endif - } - } - free_list_ = next; - - return result; - } - - void Deallocate(Node* node) { - if (InPool(node)) { -#if DCHECK_IS_ON() - node->is_allocated_ = false; -#endif - node->next_ = free_list_; - free_list_ = node; - return; - } - - WTF::Partitions::FastFree(node); - } - - bool InPool(Node* node) { return node >= Pool() && node < PastPool(); } - - template <typename VisitorDispatcher> - static void TraceValue(VisitorDispatcher, const Node*) {} - - private: - Node* Pool() { return reinterpret_cast_ptr<Node*>(pool_); } - Node* PastPool() { return Pool() + kPoolSize; } - - Node* free_list_; - bool is_done_with_initial_free_list_; -#if defined(MEMORY_TOOL_REPLACES_ALLOCATOR) - // The allocation pool for nodes is one big chunk that ASAN has no insight - // into, so it can cloak errors. Make it as small as possible to force nodes - // to be allocated individually where ASAN can see them. - static const size_t kPoolSize = 1; -#else - static const size_t kPoolSize = inlineCapacity; -#endif - alignas(NodeBase) char pool_[sizeof(NodeBase) * kPoolSize]; -}; - -template <typename ValueArg, typename AllocatorArg> -class ListHashSetNode : public ListHashSetNodeBase<ValueArg> { - public: - typedef AllocatorArg NodeAllocator; - typedef ValueArg Value; - - template <typename U> - explicit ListHashSetNode(U&& value) - : ListHashSetNodeBase<ValueArg>(std::forward<U>(value)) { - static_assert(!NodeAllocator::kIsGarbageCollected || - std::is_trivially_destructible<Value>::value, - "Garbage collected types used in ListHashSet should be " - "trivially destructible"); - } - - void* operator new(size_t, NodeAllocator* allocator) { - static_assert( - sizeof(ListHashSetNode) == sizeof(ListHashSetNodeBase<ValueArg>), - "please add any fields to the base"); - return allocator->AllocateNode(); - } - - void Destroy(NodeAllocator* allocator) { - if (NodeAllocator::kIsGarbageCollected) - return; - this->~ListHashSetNode(); - allocator->Deallocate(this); - } - - template <typename VisitorDispatcher, typename A = NodeAllocator> - std::enable_if_t<A::kIsGarbageCollected> Trace( - VisitorDispatcher visitor) const { - NodeAllocator::TraceValue(visitor, this); - } - - ListHashSetNode* Next() const { - return reinterpret_cast<ListHashSetNode*>(this->next_); - } - ListHashSetNode* Prev() const { - return reinterpret_cast<ListHashSetNode*>(this->prev_); - } - - // Don't add fields here, the ListHashSetNodeBase and this should have the - // same size. - - static constexpr ListHashSetNode* UnlinkedNodePointer() { - return reinterpret_cast<ListHashSetNode*>(-1); - } -}; - template <typename HashArg> struct ListHashSetNodeHashFunctions { STATIC_ONLY(ListHashSetNodeHashFunctions); @@ -462,8 +420,8 @@ static unsigned GetHash(const T& key) { return HashArg::GetHash(key->value_); } - template <typename T> - static bool Equal(const T& a, const T& b) { + template <typename U, typename V> + static bool Equal(const U& a, const V& b) { return HashArg::Equal(a->value_, b->value_); } static const bool safe_to_compare_to_empty_or_deleted = false; @@ -513,11 +471,6 @@ operator const_iterator() const { return iterator_; } - template <typename VisitorDispatcher> - void Trace(VisitorDispatcher visitor) const { - iterator_.Trace(visitor); - } - private: Node* GetNode() { return iterator_.GetNode(); } @@ -575,12 +528,6 @@ return position_ != other.position_; } - template <typename VisitorDispatcher> - void Trace(VisitorDispatcher visitor) const { - visitor->Trace(*set_); - visitor->Trace(position_); - } - private: Node* GetNode() { return position_; } @@ -635,11 +582,6 @@ operator const_reverse_iterator() const { return iterator_; } - template <typename VisitorDispatcher> - void Trace(VisitorDispatcher visitor) const { - iterator_.trace(visitor); - } - private: Node* GetNode() { return iterator_.node(); } @@ -697,12 +639,6 @@ return position_ != other.position_; } - template <typename VisitorDispatcher> - void Trace(VisitorDispatcher visitor) const { - visitor->Trace(*set_); - visitor->Trace(position_); - } - private: Node* GetNode() { return position_; } @@ -713,9 +649,12 @@ friend class ListHashSet; }; -template <typename HashFunctions> +template <typename HashFunctions, typename NodeArg> struct ListHashSetTranslator { STATIC_ONLY(ListHashSetTranslator); + + using Node = NodeArg; + template <typename T> static unsigned GetHash(const T& key) { return HashFunctions::GetHash(key); @@ -724,11 +663,15 @@ static bool Equal(const T& a, const U& b) { return HashFunctions::Equal(a->value_, b); } - template <typename T, typename U, typename V> - static void Translate(T*& location, U&& key, const V& allocator) { - AsAtomicPtr(&location)->store(new (const_cast<V*>(&allocator)) - T(std::forward<U>(key)), - std::memory_order_relaxed); + template <typename Key, typename Allocator> + static void Translate(typename Node::PointerType& location, + Key&& key, + Allocator& allocator) { + // PointerType is + // - Member<Node> for the Heap version, supporting concurrency using + // atomics; + // - Node* for the PA version; + location = Node::Create(&allocator, std::forward<Key>(key)); } }; @@ -1095,10 +1038,9 @@ static_assert(!IsWeak<T>::value, "HeapListHashSet does not support weakness, consider using " "HeapLinkedHashSet instead."); - // This marks all the nodes and their contents live that can be accessed - // through the HashTable. That includes m_head and m_tail so we do not have - // to explicitly trace them here. impl_.Trace(visitor); + visitor->Trace(head_); + visitor->Trace(tail_); } } // namespace WTF
diff --git a/third_party/blink/web_tests/FlagExpectations/disable-layout-ng b/third_party/blink/web_tests/FlagExpectations/disable-layout-ng index 7972aae..b2f34de 100644 --- a/third_party/blink/web_tests/FlagExpectations/disable-layout-ng +++ b/third_party/blink/web_tests/FlagExpectations/disable-layout-ng
@@ -387,6 +387,8 @@ crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/sizing/vert-block-size-small-or-larger-than-container-with-min-or-max-content-2b.html [ Failure ] ### external/wpt/quirks/ +crbug.com/591099 external/wpt/quirks/body-fills-html-quirk-vertical.html [ Failure ] +crbug.com/591099 external/wpt/quirks/body-fills-html-quirk.html [ Failure ] crbug.com/591099 external/wpt/quirks/line-height-trailing-collapsable-whitespace.html [ Failure ] ### fast/box-decoration-break/ @@ -426,6 +428,8 @@ crbug.com/639223 virtual/text-antialias/line-break-between-text-nodes-latin1.html [ Failure ] ### http/tests/ +crbug.com/1139949 http/tests/devtools/elements/highlight/highlight-css-flex-multiline.js [ Failure ] +crbug.com/1139949 http/tests/devtools/elements/highlight/highlight-css-flex.js [ Failure ] crbug.com/591099 http/tests/devtools/elements/highlight/highlight-node-vertical-rl.js [ Failure ] ### http/tests/images/ @@ -508,8 +512,8 @@ # White space, absolute position and paint timing failures from June 5, 2020 crbug.com/591099 external/wpt/paint-timing/fcp-only/fcp-pseudo-element-visibility.html [ Failure ] -crbug.com/591099 external/wpt/css/css-position/position-absolute-center-001.tentative.html [ Failure ] -crbug.com/591099 external/wpt/css/css-position/position-absolute-center-002.tentative.html [ Failure ] +crbug.com/591099 external/wpt/css/css-position/position-absolute-center-001.html [ Failure ] +crbug.com/591099 external/wpt/css/css-position/position-absolute-center-002.html [ Failure ] crbug.com/591099 external/wpt/css/css-text/white-space/break-spaces-051.html [ Failure ] crbug.com/591099 external/wpt/css/css-text/white-space/break-spaces-052.html [ Failure ] crbug.com/591099 external/wpt/css/css-text/white-space/pre-wrap-051.html [ Failure ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index bb3c3e6..7269f22 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -6006,3 +6006,6 @@ crbug.com/1149987 external/wpt/websockets/Create-blocked-port.any.worker.html [ Pass Timeout ] crbug.com/1150518 [ Win ] virtual/gpu/fast/canvas/canvas-composite-shadow.html [ Pass Timeout ] crbug.com/1150475 fast/dom/open-and-close-by-DOM.html [ Pass Failure ] + +# Skip to land change in frontend (https://crrev.com/c/2550061) before this layout test can be updated +crbug.com/1150854 http/tests/devtools/unit/soft-context-menu.js [ Skip ]
diff --git a/third_party/blink/web_tests/accessibility/role-attribute-expected.txt b/third_party/blink/web_tests/accessibility/role-attribute-expected.txt index 8e8c3d20..33e10b95 100644 --- a/third_party/blink/web_tests/accessibility/role-attribute-expected.txt +++ b/third_party/blink/web_tests/accessibility/role-attribute-expected.txt
@@ -63,9 +63,7 @@ AXRole: AXStatus AXRole: AXProgressIndicator AXRole: AXStatus - AXRole: AXSliderThumb AXRole: AXSlider - AXRole: AXSliderThumb PASS successfullyParsed is true
diff --git a/third_party/blink/web_tests/accessibility/slider-thumb-bounds.html b/third_party/blink/web_tests/accessibility/slider-thumb-bounds.html deleted file mode 100644 index 262520e..0000000 --- a/third_party/blink/web_tests/accessibility/slider-thumb-bounds.html +++ /dev/null
@@ -1,26 +0,0 @@ -<!DOCTYPE HTML> -<script src="../resources/testharness.js"></script> -<script src="../resources/testharnessreport.js"></script> - -<input id="slider" type="range" min=0 max=10 value=0 style="position: absolute; left: 100px; top: 50px; width: 300px; height: 20px;"> - -<script> -test(function(t) { - var axSlider = accessibilityController.accessibleElementById("slider"); - assert_equals(axSlider.role, "AXRole: AXSlider"); - - var axSliderThumb = axSlider.childAtIndex(0); - assert_equals(axSliderThumb.role, "AXRole: AXSliderThumb"); - - // The slider thumb should be near the beginning of the slider - assert_true(Math.abs(axSliderThumb.x - axSlider.x) < 5); - assert_true(Math.abs(axSliderThumb.y - axSlider.y) < 5); - - // The slider should be wide but the thumb should not be - assert_true(axSlider.width > 250); - assert_true(axSliderThumb.width < 30); -}, "Test bounds of slider thumb"); -</script> - -</body> -</html>
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json index e3ecdaaa..2f4d21a 100644 --- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json +++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -233642,7 +233642,7 @@ ] }, "lint.ignore": [ - "07c6fb7b85cbe5e2892b247032addc23b20f97e1", + "b457f02d14790794883a641f5c3a00fbc386ab9d", [] ], "loading": { @@ -404154,7 +404154,7 @@ ] ], "animation-timeline-computed.html": [ - "02836d714b59081b3a14c2bd124d2ac254d23d58", + "8d539789cf8a775f35b57fb1572a04734a4242fa", [ null, {} @@ -427903,7 +427903,7 @@ ] ], "video-decoder.html": [ - "f653ba03b09a51b9e25b90173b4d7002242e05e7", + "ff48625dc8c2a8718895831e6dd0c82b9c17d7c2", [ null, {}
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/css-flexbox-row-ref.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/css-flexbox-row-ref.html index 91eb06c..21e7a01 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-flexbox/css-flexbox-row-ref.html +++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/css-flexbox-row-ref.html
@@ -4,27 +4,21 @@ <meta charset="utf-8" /> <title>CSS Reftest Reference</title> <link rel="author" title="Tsutomu ogaoga Ogasawara" href="mailto:info@ogaoga.org"> - <style type="text/css"> - .container { - color: white; - } + + <style> .item { - writing-mode: vertical-rl; - background: green; - height: 3em; - width: 3em; - line-height: 1.5em; + width: 15px; + height: 45px; + float: left; } </style> </head> -<body> - <p>The test passes if you see a tall green box with pairs of the 1-9 and a-i listed top to bottom in two columns.</p> - <div class="container"> - <div class="item">123<br />abc</div> - <div class="item">456<br />def</div> - <div class="item">789<br />ghi</div> - </div> +<p>Pass condition: 4 rectangles, with colors in clockwise order starting from top-left: grey, orange, blue, yellow. -</body> -</html> +<div style="height: 90px; width: 30px; border: 2px solid black;"> + <div class="item" style="background: grey"></div> + <div class="item" style="background: orange"></div> + <div class="item" style="background: yellow"></div> + <div class="item" style="background: blue"></div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/css-flexbox-row-reverse-wrap-reverse.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/css-flexbox-row-reverse-wrap-reverse.html index 3d0d6a5..4aa864b8 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-flexbox/css-flexbox-row-reverse-wrap-reverse.html +++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/css-flexbox-row-reverse-wrap-reverse.html
@@ -18,39 +18,26 @@ display: flex; flex-flow: row-reverse wrap-reverse; writing-mode: vertical-rl; - color: white; - - height: 9em; + border: 2px solid black; + height: 90px; } .item { - background: green; - height: 3em; - width: 1.5em; - line-height: 1.5em; + width: 15px; + height: 45px; /* make sure UA that doesn't support writing mode and flexbox fails. */ float: right; } - .error { - position: absolute; - background: red; - height: 9em; - width: 3em; - z-index: -1; - } </style> </head> <body> - <p>The test passes if you see a tall green box with pairs of the 1-9 and a-i listed top to bottom in two columns.</p> +<p>Pass condition: 4 rectangles, with colors in clockwise order starting from top-left: grey, orange, blue, yellow. - <div class="error"></div> <div class="container"> - <div class="item">ghi</div> - <div class="item">def</div> - <div class="item">abc</div> - <div class="item">789</div> - <div class="item">456</div> - <div class="item">123</div> + <div class="item" style="background: yellow"></div> + <div class="item" style="background: grey"></div> + <div class="item" style="background: blue"></div> + <div class="item" style="background: orange"></div> </div> </body> </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/css-flexbox-row-reverse-wrap.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/css-flexbox-row-reverse-wrap.html index 8242f22..41550e0d 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-flexbox/css-flexbox-row-reverse-wrap.html +++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/css-flexbox-row-reverse-wrap.html
@@ -18,39 +18,26 @@ display: flex; flex-flow: row-reverse wrap; writing-mode: vertical-rl; - color: white; - - height: 9em; + border: 2px solid black; + height: 90px; } .item { - background: green; - height: 3em; - width: 1.5em; - line-height: 1.5em; + width: 15px; + height: 45px; /* make sure UA that doesn't support writing mode and flexbox fails. */ float: right; } - .error { - position: absolute; - background: red; - height: 9em; - width: 3em; - z-index: -1; - } </style> </head> <body> - <p>The test passes if you see a tall green box with pairs of the 1-9 and a-i listed top to bottom in two columns.</p> +<p>Pass condition: 4 rectangles, with colors in clockwise order starting from top-left: grey, orange, blue, yellow. - <div class="error"></div> <div class="container"> - <div class="item">789</div> - <div class="item">456</div> - <div class="item">123</div> - <div class="item">ghi</div> - <div class="item">def</div> - <div class="item">abc</div> + <div class="item" style="background: blue"></div> + <div class="item" style="background: orange"></div> + <div class="item" style="background: yellow"></div> + <div class="item" style="background: grey"></div> </div> </body> </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/css-flexbox-row-reverse.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/css-flexbox-row-reverse.html index d5a857ea..1b36e7e 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-flexbox/css-flexbox-row-reverse.html +++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/css-flexbox-row-reverse.html
@@ -18,34 +18,35 @@ display: flex; flex-flow: row-reverse; writing-mode: vertical-rl; - color: white; + border: 2px solid black; + height: 90px; } .item { - background: green; - height: 3em; - width: 3em; - line-height: 1.5em; + line-height: 0; /* make sure UA that doesn't support writing mode and flexbox fails. */ float: right; } - .error { - position: absolute; - background: red; - height: 9em; - width: 3em; - z-index: -1; + .color-block { + display: inline-block; + width: 15px; + height: 45px; } </style> </head> <body> - <p>The test passes if you see a tall green box with pairs of the 1-9 and a-i listed top to bottom in two columns.</p> - - <div class="error"></div> + <p>Pass condition: 4 rectangles, with colors in clockwise order starting from top-left: grey, orange, blue, yellow. <div class="container"> - <div class="item">789<br />ghi</div> - <div class="item">456<br />def</div> - <div class="item">123<br />abc</div> + <div class="item"> + <span class=color-block style="background: blue;"></span> + <br /> + <span class=color-block style="background: yellow;"></span> + </div> + <div class="item"> + <span class=color-block style="background: orange;"></span> + <br /> + <span class=color-block style="background: grey;"></span> + </div> </div> </body> </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/css-flexbox-row-wrap-reverse.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/css-flexbox-row-wrap-reverse.html index 94d4346b..0104856 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-flexbox/css-flexbox-row-wrap-reverse.html +++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/css-flexbox-row-wrap-reverse.html
@@ -18,39 +18,25 @@ display: flex; flex-flow: row wrap-reverse; writing-mode: vertical-rl; - color: white; - - height: 9em; + border: 2px solid black; + height: 90px; } .item { - background: green; - height: 3em; - width: 1.5em; - line-height: 1.5em; + width: 15px; + height: 45px; /* make sure UA that doesn't support writing mode and flexbox fails. */ float: right; } - .error { - position: absolute; - background: red; - height: 9em; - width: 3em; - z-index: -1; - } </style> </head> <body> - <p>The test passes if you see a tall green box with pairs of the 1-9 and a-i listed top to bottom in two columns.</p> - - <div class="error"></div> +<p>Pass condition: 4 rectangles, with colors in clockwise order starting from top-left: grey, orange, blue, yellow. <div class="container"> - <div class="item">abc</div> - <div class="item">def</div> - <div class="item">ghi</div> - <div class="item">123</div> - <div class="item">456</div> - <div class="item">789</div> + <div class="item" style="background: grey"></div> + <div class="item" style="background: yellow"></div> + <div class="item" style="background: orange"></div> + <div class="item" style="background: blue"></div> </div> </body> </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/css-flexbox-row-wrap.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/css-flexbox-row-wrap.html index 22ed901..0cbc469c 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-flexbox/css-flexbox-row-wrap.html +++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/css-flexbox-row-wrap.html
@@ -18,39 +18,26 @@ display: flex; flex-flow: row wrap; writing-mode: vertical-rl; - color: white; - - height: 9em; + border: 2px solid black; + height: 90px; } .item { - background: green; - height: 3em; - width: 1.5em; - line-height: 1.5em; + width: 15px; + height: 45px; /* make sure UA that doesn't support writing mode and flexbox fails. */ float: right; } - .error { - position: absolute; - background: red; - height: 9em; - width: 3em; - z-index: -1; - } </style> </head> <body> - <p>The test passes if you see a tall green box with pairs of the 1-9 and a-i listed top to bottom in two columns.</p> +<p>Pass condition: 4 rectangles, with colors in clockwise order starting from top-left: grey, orange, blue, yellow. - <div class="error"></div> <div class="container"> - <div class="item">123</div> - <div class="item">456</div> - <div class="item">789</div> - <div class="item">abc</div> - <div class="item">def</div> - <div class="item">ghi</div> + <div class="item" style="background: orange"></div> + <div class="item" style="background: blue"></div> + <div class="item" style="background: grey"></div> + <div class="item" style="background: yellow"></div> </div> </body> </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/css-flexbox-row.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/css-flexbox-row.html index 15f4f69..f34b7aa 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-flexbox/css-flexbox-row.html +++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/css-flexbox-row.html
@@ -18,35 +18,35 @@ display: flex; flex-flow: row; writing-mode: vertical-rl; - color: white; + border: 2px solid black; + height: 90px; } .item { - background: green; - height: 3em; - width: 3em; - line-height: 1.5em; + line-height: 0; /* make sure UA that doesn't support writing mode and flexbox fails. */ float: right; } - .error { - position: absolute; - background: red; - height: 9em; - width: 3em; - z-index: -1; + .color-block { + display: inline-block; + width: 15px; + height: 45px; } </style> </head> <body> - - <p>The test passes if you see a tall green box with pairs of the 1-9 and a-i listed top to bottom in two columns.</p> - - <div class="error"></div> + <p>Pass condition: 4 rectangles, with colors in clockwise order starting from top-left: grey, orange, blue, yellow. <div class="container"> - <div class="item">123<br />abc</div> - <div class="item">456<br />def</div> - <div class="item">789<br />ghi</div> + <div class="item"> + <span class=color-block style="background: orange;"></span> + <br /> + <span class=color-block style="background: grey;"></span> + </div> + <div class="item"> + <span class=color-block style="background: blue;"></span> + <br /> + <span class=color-block style="background: yellow;"></span> + </div> </div> </body> </html>
diff --git a/third_party/blink/web_tests/external/wpt/lint.ignore b/third_party/blink/web_tests/external/wpt/lint.ignore index 07c6fb7..b457f02 100644 --- a/third_party/blink/web_tests/external/wpt/lint.ignore +++ b/third_party/blink/web_tests/external/wpt/lint.ignore
@@ -619,6 +619,8 @@ CSS-COLLIDING-SUPPORT-NAME: css/vendor-imports/mozilla/mozilla-central-reftests/ui3/support/replaced-min-max-1.png CSS-COLLIDING-REF-NAME: css/css-multicol/baseline-001-ref.html CSS-COLLIDING-REF-NAME: css/css-grid/subgrid/baseline-001-ref.html +CSS-COLLIDING-REF-NAME: css/css-backgrounds/simple-bg-color-ref.html +CSS-COLLIDING-REF-NAME: css/css-backgrounds/hidpi/simple-bg-color-ref.html CSS-COLLIDING-TEST-NAME: css/css-contain/inheritance.html CSS-COLLIDING-TEST-NAME: css/css-contain/content-visibility/inheritance.html
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/accessibility/element-role-mapping-normal-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/accessibility/element-role-mapping-normal-expected.txt index b26a991..e524bc1 100644 --- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/accessibility/element-role-mapping-normal-expected.txt +++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/accessibility/element-role-mapping-normal-expected.txt
@@ -172,13 +172,14 @@ AXRole: AXCaption AXRole: AXStaticText "Caption" AXRole: AXInlineTextBox "Caption" - AXRole: AXRow - AXRole: AXCell "Cell1" - AXRole: AXStaticText "Cell1" - AXRole: AXInlineTextBox "Cell1" - AXRole: AXCell "Cell2" - AXRole: AXStaticText "Cell2" - AXRole: AXInlineTextBox "Cell2" + AXRole: AXRowGroup + AXRole: AXRow + AXRole: AXCell "Cell1" + AXRole: AXStaticText "Cell1" + AXRole: AXInlineTextBox "Cell1" + AXRole: AXCell "Cell2" + AXRole: AXStaticText "Cell2" + AXRole: AXInlineTextBox "Cell2" AXRole: AXFigure "Fig1. - Blue Box" AXRole: AXImage "blue" AXRole: AXFigcaption
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-log-linkify-links.js b/third_party/blink/web_tests/http/tests/devtools/console/console-log-linkify-links.js index 36bc26a28..fcfa938 100644 --- a/third_party/blink/web_tests/http/tests/devtools/console/console-log-linkify-links.js +++ b/third_party/blink/web_tests/http/tests/devtools/console/console-log-linkify-links.js
@@ -46,7 +46,7 @@ TestRunner.addResult('\nText: ' + element.deepTextContent()); var links = element.querySelectorAll('.devtools-link'); for (var link of links) { - var info = Components.Linkifier._linkInfo(link); + var info = Components.Linkifier.linkInfo(link); if (info && info.url) { TestRunner.addResult('Linked url: ' + info.url); if (info.lineNumber !== null || info.columnNumber !== null)
diff --git a/third_party/blink/web_tests/http/tests/devtools/jump-to-previous-editing-location.js b/third_party/blink/web_tests/http/tests/devtools/jump-to-previous-editing-location.js index 881bbec..951796d 100644 --- a/third_party/blink/web_tests/http/tests/devtools/jump-to-previous-editing-location.js +++ b/third_party/blink/web_tests/http/tests/devtools/jump-to-previous-editing-location.js
@@ -207,7 +207,7 @@ var linkifier = new Components.Linkifier(); var anchorURI = uiSourceCode.url(); var anchor = linkifier.linkifyScriptLocation(SDK.targetManager.mainTarget(), null, anchorURI, 10, {columnNumber: 1}); - var info = Components.Linkifier._linkInfo(anchor); + var info = Components.Linkifier.linkInfo(anchor); Common.Revealer.reveal(info.uiLocation).then(function() { TestRunner.addResult('Selection: ' + panel.visibleView.textEditor.selection().toString()); dumpSelection('Showed anchor in ' + anchorURI.split('/').pop() + ' with line 333 column 3');
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/page/iframe-src-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/page/iframe-src-expected.txt new file mode 100644 index 0000000..883168b --- /dev/null +++ b/third_party/blink/web_tests/http/tests/inspector-protocol/page/iframe-src-expected.txt
@@ -0,0 +1,5 @@ +Tests sending of info for iframe with src +Frame navigated to http://devtools.test:8000/inspector-protocol/page/resources/iframe-src.html +Frame navigated to http://devtools.test:8000/inspector-protocol/resources/empty.html +Received information about 2 frame(s). +
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/page/iframe-src-write-delay-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/page/iframe-src-write-delay-expected.txt new file mode 100644 index 0000000..ef11f44 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/inspector-protocol/page/iframe-src-write-delay-expected.txt
@@ -0,0 +1,6 @@ +Tests sending of info for iframe with src which is being written to after a delay +Frame navigated to http://devtools.test:8000/inspector-protocol/page/resources/iframe-src.html +Frame navigated to http://devtools.test:8000/inspector-protocol/resources/empty.html +Document opened, new url: http://devtools.test:8000/inspector-protocol/page/resources/iframe-src.html +Received information about 2 frame(s). +
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/page/iframe-src-write-delay.js b/third_party/blink/web_tests/http/tests/inspector-protocol/page/iframe-src-write-delay.js new file mode 100644 index 0000000..9a35a85 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/inspector-protocol/page/iframe-src-write-delay.js
@@ -0,0 +1,31 @@ +(async function(testRunner) { + const {page, session, dp} = await testRunner.startBlank( + `Tests sending of info for iframe with src which is being written to after a delay`); + + await dp.Page.enable(); + const frameIDs = new Set(); + + page.navigate('http://devtools.test:8000/inspector-protocol/page/resources/iframe-src.html'); + + let frame = (await dp.Page.onceFrameNavigated()).params.frame; + testRunner.log(`Frame navigated to ${frame.url}`); + frameIDs.add(frame.id); + + frame = (await dp.Page.onceFrameNavigated()).params.frame; + testRunner.log(`Frame navigated to ${frame.url}`); + frameIDs.add(frame.id); + + session.evaluate(` + const doc = document.getElementById('frame').contentDocument; + doc.open(); + doc.write("<h1>Hello world!</h1>"); + doc.close(); + `); + + frame = (await dp.Page.onceDocumentOpened()).params.frame; + testRunner.log(`Document opened, new url: ${frame.url}`); + frameIDs.add(frame.id); + + testRunner.log(`Received information about ${frameIDs.size} frame(s).`); + testRunner.completeTest(); +})
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/page/iframe-src-write-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/page/iframe-src-write-expected.txt new file mode 100644 index 0000000..adea53d --- /dev/null +++ b/third_party/blink/web_tests/http/tests/inspector-protocol/page/iframe-src-write-expected.txt
@@ -0,0 +1,5 @@ +Tests sending of info for iframe with src which is being written to +Frame navigated to http://devtools.test:8000/inspector-protocol/page/resources/iframe-src-write.html +Document opened, new url: http://devtools.test:8000/inspector-protocol/page/resources/iframe-src-write.html +Received information about 2 frame(s). +
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/page/iframe-src-write.js b/third_party/blink/web_tests/http/tests/inspector-protocol/page/iframe-src-write.js new file mode 100644 index 0000000..2f6f940 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/inspector-protocol/page/iframe-src-write.js
@@ -0,0 +1,20 @@ +(async function(testRunner) { + const {page, dp} = await testRunner.startBlank( + `Tests sending of info for iframe with src which is being written to`); + + await dp.Page.enable(); + const frameIDs = new Set(); + + dp.Page.onFrameNavigated((event) => { + testRunner.log(`Frame navigated to ${event.params.frame.url}`); + frameIDs.add(event.params.frame.id); + }); + dp.Page.onDocumentOpened((event) => { + testRunner.log(`Document opened, new url: ${event.params.frame.url}`); + frameIDs.add(event.params.frame.id); + }); + + await page.navigate('http://devtools.test:8000/inspector-protocol/page/resources/iframe-src-write.html'); + testRunner.log(`Received information about ${frameIDs.size} frame(s).`); + testRunner.completeTest(); +})
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/page/iframe-src.js b/third_party/blink/web_tests/http/tests/inspector-protocol/page/iframe-src.js new file mode 100644 index 0000000..70c2e9b --- /dev/null +++ b/third_party/blink/web_tests/http/tests/inspector-protocol/page/iframe-src.js
@@ -0,0 +1,20 @@ +(async function(testRunner) { + const {page, dp} = await testRunner.startBlank( + `Tests sending of info for iframe with src`); + + await dp.Page.enable(); + const frameIDs = new Set(); + + dp.Page.onFrameNavigated((event) => { + testRunner.log(`Frame navigated to ${event.params.frame.url}`); + frameIDs.add(event.params.frame.id); + }); + dp.Page.onDocumentOpened((event) => { + testRunner.log(`Document opened, new url: ${event.params.frame.url}`); + frameIDs.add(event.params.frame.id); + }); + + await page.navigate('http://devtools.test:8000/inspector-protocol/page/resources/iframe-src.html'); + testRunner.log(`Received information about ${frameIDs.size} frame(s).`); + testRunner.completeTest(); +})
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/page/iframe-srcdoc-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/page/iframe-srcdoc-expected.txt new file mode 100644 index 0000000..3c5e2e7 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/inspector-protocol/page/iframe-srcdoc-expected.txt
@@ -0,0 +1,5 @@ +Tests sending of info for iframe with srcdoc +Frame navigated to http://devtools.test:8000/inspector-protocol/page/resources/iframe-srcdoc.html +Frame navigated to about:srcdoc +Received information about 2 frame(s). +
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/page/iframe-srcdoc-write-delay-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/page/iframe-srcdoc-write-delay-expected.txt new file mode 100644 index 0000000..4386a40 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/inspector-protocol/page/iframe-srcdoc-write-delay-expected.txt
@@ -0,0 +1,6 @@ +Tests sending of info for iframe with srcdoc which is being written to after a delay +Frame navigated to http://devtools.test:8000/inspector-protocol/page/resources/iframe-srcdoc.html +Frame navigated to about:srcdoc +Document opened, new url: http://devtools.test:8000/inspector-protocol/page/resources/iframe-srcdoc.html +Received information about 2 frame(s). +
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/page/iframe-srcdoc-write-delay.js b/third_party/blink/web_tests/http/tests/inspector-protocol/page/iframe-srcdoc-write-delay.js new file mode 100644 index 0000000..1278ff0b --- /dev/null +++ b/third_party/blink/web_tests/http/tests/inspector-protocol/page/iframe-srcdoc-write-delay.js
@@ -0,0 +1,32 @@ +(async function(testRunner) { + const {page, session, dp} = await testRunner.startBlank( + `Tests sending of info for iframe with srcdoc which is being written to after a delay`); + + await dp.Page.enable(); + const frameIDs = new Set(); + + page.navigate('http://devtools.test:8000/inspector-protocol/page/resources/iframe-srcdoc.html'); + + let frame = (await dp.Page.onceFrameNavigated()).params.frame; + testRunner.log(`Frame navigated to ${frame.url}`); + frameIDs.add(frame.id); + + frame = (await dp.Page.onceFrameNavigated()).params.frame; + testRunner.log(`Frame navigated to ${frame.url}`); + frameIDs.add(frame.id); + + session.evaluate(` + const doc = document.getElementById('frame').contentDocument; + doc.open(); + doc.write("<h1>Hello world!</h1>"); + doc.close(); +`); + + frame = (await dp.Page.onceDocumentOpened()).params.frame; + testRunner.log(`Document opened, new url: ${frame.url}`); + frameIDs.add(frame.id); + + testRunner.log(`Received information about ${frameIDs.size} frame(s).`); + testRunner.completeTest(); +}) +
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/page/iframe-srcdoc-write-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/page/iframe-srcdoc-write-expected.txt new file mode 100644 index 0000000..972abc1 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/inspector-protocol/page/iframe-srcdoc-write-expected.txt
@@ -0,0 +1,5 @@ +Tests sending of info for iframe with srcdoc which is being written to +Frame navigated to http://devtools.test:8000/inspector-protocol/page/resources/iframe-srcdoc-write.html +Document opened, new url: http://devtools.test:8000/inspector-protocol/page/resources/iframe-srcdoc-write.html +Received information about 2 frame(s). +
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/page/iframe-srcdoc-write.js b/third_party/blink/web_tests/http/tests/inspector-protocol/page/iframe-srcdoc-write.js new file mode 100644 index 0000000..f03d75a41 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/inspector-protocol/page/iframe-srcdoc-write.js
@@ -0,0 +1,20 @@ +(async function(testRunner) { + const {page, dp} = await testRunner.startBlank( + `Tests sending of info for iframe with srcdoc which is being written to`); + + await dp.Page.enable(); + const frameIDs = new Set(); + + dp.Page.onFrameNavigated((event) => { + testRunner.log(`Frame navigated to ${event.params.frame.url}`); + frameIDs.add(event.params.frame.id); + }); + dp.Page.onDocumentOpened((event) => { + testRunner.log(`Document opened, new url: ${event.params.frame.url}`); + frameIDs.add(event.params.frame.id); + }); + + await page.navigate('http://devtools.test:8000/inspector-protocol/page/resources/iframe-srcdoc-write.html'); + testRunner.log(`Received information about ${frameIDs.size} frame(s).`); + testRunner.completeTest(); +})
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/page/iframe-srcdoc.js b/third_party/blink/web_tests/http/tests/inspector-protocol/page/iframe-srcdoc.js new file mode 100644 index 0000000..7ba63fa --- /dev/null +++ b/third_party/blink/web_tests/http/tests/inspector-protocol/page/iframe-srcdoc.js
@@ -0,0 +1,20 @@ +(async function(testRunner) { + const {page, dp} = await testRunner.startBlank( + `Tests sending of info for iframe with srcdoc`); + + await dp.Page.enable(); + const frameIDs = new Set(); + + dp.Page.onFrameNavigated((event) => { + testRunner.log(`Frame navigated to ${event.params.frame.url}`); + frameIDs.add(event.params.frame.id); + }); + dp.Page.onDocumentOpened((event) => { + testRunner.log(`Document opened, new url: ${event.params.frame.url}`); + frameIDs.add(event.params.frame.id); + }); + + await page.navigate('http://devtools.test:8000/inspector-protocol/page/resources/iframe-srcdoc.html'); + testRunner.log(`Received information about ${frameIDs.size} frame(s).`); + testRunner.completeTest(); +})
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/page/resources/iframe-src-write.html b/third_party/blink/web_tests/http/tests/inspector-protocol/page/resources/iframe-src-write.html new file mode 100644 index 0000000..526d6a64 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/inspector-protocol/page/resources/iframe-src-write.html
@@ -0,0 +1,7 @@ +<iframe id="frame" src="http://devtools.test:8000/inspector-protocol/resources/empty.html"></iframe> +<script> + const doc = document.getElementById('frame').contentDocument; + doc.open(); + doc.write("<h1>Hello world!</h1>"); + doc.close(); +</script>
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/page/resources/iframe-src.html b/third_party/blink/web_tests/http/tests/inspector-protocol/page/resources/iframe-src.html new file mode 100644 index 0000000..9d95a02 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/inspector-protocol/page/resources/iframe-src.html
@@ -0,0 +1 @@ +<iframe id="frame" src="http://devtools.test:8000/inspector-protocol/resources/empty.html"></iframe>
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/page/resources/iframe-srcdoc-write.html b/third_party/blink/web_tests/http/tests/inspector-protocol/page/resources/iframe-srcdoc-write.html new file mode 100644 index 0000000..59f6731 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/inspector-protocol/page/resources/iframe-srcdoc-write.html
@@ -0,0 +1,9 @@ + +<iframe srcdoc id="frame"></iframe> + +<script> + const doc = document.getElementById('frame').contentDocument; + doc.open(); + doc.write("<h1>Hello world!</h1>"); + doc.close(); +</script>
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/page/resources/iframe-srcdoc.html b/third_party/blink/web_tests/http/tests/inspector-protocol/page/resources/iframe-srcdoc.html new file mode 100644 index 0000000..0c61e6b9 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/inspector-protocol/page/resources/iframe-srcdoc.html
@@ -0,0 +1,2 @@ + +<iframe srcdoc id="frame"></iframe>
diff --git a/third_party/closure_compiler/externs/automation.js b/third_party/closure_compiler/externs/automation.js index 9abae7e..b0ab87fd 100644 --- a/third_party/closure_compiler/externs/automation.js +++ b/third_party/closure_compiler/externs/automation.js
@@ -300,7 +300,6 @@ SEARCH_BOX: 'searchBox', SECTION: 'section', SLIDER: 'slider', - SLIDER_THUMB: 'sliderThumb', SPIN_BUTTON: 'spinButton', SPLITTER: 'splitter', STATIC_TEXT: 'staticText',
diff --git a/tools/cygprofile_win/BUILD.gn b/tools/cygprofile_win/BUILD.gn deleted file mode 100644 index 99b23c5..0000000 --- a/tools/cygprofile_win/BUILD.gn +++ /dev/null
@@ -1,10 +0,0 @@ -# Copyright 2017 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -static_library("cygprofile_win") { - sources = [ "cygprofile.cc" ] - - # Don't instrument this library. - configs -= [ "//build/config/win:default_cygprofile_instrumentation" ] -}
diff --git a/tools/cygprofile_win/OWNERS b/tools/cygprofile_win/OWNERS deleted file mode 100644 index 8d8029ea..0000000 --- a/tools/cygprofile_win/OWNERS +++ /dev/null
@@ -1 +0,0 @@ -hans@chromium.org
diff --git a/tools/cygprofile_win/cygprofile.cc b/tools/cygprofile_win/cygprofile.cc deleted file mode 100644 index 87045a75..0000000 --- a/tools/cygprofile_win/cygprofile.cc +++ /dev/null
@@ -1,103 +0,0 @@ -// Copyright (c) 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include <stdio.h> -#include <atomic> -#include <string> -#include <unordered_set> - -#include <windows.h> // Needs to be included before the others. - -#include <dbghelp.h> -#include <process.h> - -namespace { - -// The main purpose of the order file is to optimize startup time, -// so capturing the first N function calls is enough. -static constexpr int kSamplesCapacity = 25 * 1024 * 1024; - -void* samples[kSamplesCapacity]; -std::atomic_int num_samples; -std::atomic_int done; - -// Path to the dump file. %lu will be substituted by the process id. -static const char kDumpFile[] = "/src/tmp/cygprofile_%lu.txt"; - -// Symbolize the samples and write them to disk. -void dump(void*) { - HMODULE dbghelp = LoadLibraryA("dbghelp.dll"); - auto sym_from_addr = reinterpret_cast<decltype(::SymFromAddr)*>( - ::GetProcAddress(dbghelp, "SymFromAddr")); - auto sym_initialize = reinterpret_cast<decltype(::SymInitialize)*>( - ::GetProcAddress(dbghelp, "SymInitialize")); - auto sym_set_options = reinterpret_cast<decltype(::SymSetOptions)*>( - ::GetProcAddress(dbghelp, "SymSetOptions")); - - char filename[MAX_PATH]; - snprintf(filename, sizeof(filename), kDumpFile, ::GetCurrentProcessId()); - FILE* f = fopen(filename, "w"); - if (!f) - return; - - sym_initialize(::GetCurrentProcess(), NULL, TRUE); - sym_set_options(SYMOPT_DEFERRED_LOADS | SYMOPT_PUBLICS_ONLY); - char sym_buf[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)]; - - std::unordered_set<void*> seen; - std::unordered_set<std::string> seen_names; - - for (void* sample : samples) { - // Only print the first call of a function. - if (seen.count(sample)) - continue; - seen.insert(sample); - - SYMBOL_INFO* symbol = reinterpret_cast<SYMBOL_INFO*>(sym_buf); - symbol->SizeOfStruct = sizeof(SYMBOL_INFO); - symbol->MaxNameLen = MAX_SYM_NAME; - DWORD64 offset = 0; - - if (sym_from_addr(::GetCurrentProcess(), reinterpret_cast<DWORD64>(sample), - &offset, symbol)) { - const char* name = symbol->Name; - if (name[0] == '_') - name++; - if (seen_names.count(name)) - continue; - seen_names.insert(name); - - fprintf(f, "%s\n", name); - } - } - - fclose(f); -} - -} // namespace - -extern "C" { - -void __cyg_profile_func_enter(void* this_fn, void* call_site_unused) { - if (done) - return; - - // Get our index for the samples array atomically. - int n = num_samples++; - - if (n < kSamplesCapacity) { - samples[n] = this_fn; - - if (n + 1 == kSamplesCapacity) { - // This is the final sample; start dumping the samples to a file (on a - // separate thread so as not to disturb the main program). - done = 1; - _beginthread(dump, 0, nullptr); - } - } -} - -void __cyg_profile_func_exit(void* this_fn, void* call_site) {} - -} // extern "C"
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl index b491156..4202d1e 100644 --- a/tools/mb/mb_config.pyl +++ b/tools/mb/mb_config.pyl
@@ -699,7 +699,6 @@ 'internal.chrome.fyi': { 'chromeos-amd64-generic-lacros-internal-rel': 'chromeos_amd64-generic_lacros_rel', - 'chromeos-betty-pi-arc-chrome-dchecks': 'chromeos_betty-pi-arc_dchecks', 'linux-autofill-captured-sites-rel': 'release_bot', 'linux-password-manager-captured-sites-rel': 'release_bot', 'lorenz-graph-dbg': 'android_debug_static_external_bot', @@ -711,6 +710,7 @@ 'internal.chromeos.fyi': { 'chromeos-betty-arc-r-chrome': 'chromeos_betty-arc-r_include_unwind_tables_official_use_fake_dbus_clients', + 'chromeos-betty-pi-arc-chrome-dchecks': 'chromeos_betty-pi-arc_dchecks', 'chromeos-eve-arc-r-chrome': 'chromeos_eve-arc-r_include_unwind_tables_official', },
diff --git a/tools/mb/mb_config_expectations/internal.chrome.fyi.json b/tools/mb/mb_config_expectations/internal.chrome.fyi.json index 3636e8d..5e73395 100644 --- a/tools/mb/mb_config_expectations/internal.chrome.fyi.json +++ b/tools/mb/mb_config_expectations/internal.chrome.fyi.json
@@ -27,19 +27,6 @@ "use_vaapi": false } }, - "chromeos-betty-pi-arc-chrome-dchecks": { - "args_file": "//build/args/chromeos/betty-pi-arc.gni", - "gn_args": { - "dcheck_always_on": true, - "exclude_unwind_tables": false, - "is_chrome_branded": true, - "is_chromeos_device": true, - "is_official_build": true, - "ozone_platform_headless": true, - "use_goma": true, - "use_real_dbus_clients": false - } - }, "linux-autofill-captured-sites-rel": { "gn_args": { "is_component_build": false,
diff --git a/tools/mb/mb_config_expectations/internal.chromeos.fyi.json b/tools/mb/mb_config_expectations/internal.chromeos.fyi.json index 66f34d8..677c9366 100644 --- a/tools/mb/mb_config_expectations/internal.chromeos.fyi.json +++ b/tools/mb/mb_config_expectations/internal.chromeos.fyi.json
@@ -11,6 +11,19 @@ "use_real_dbus_clients": false } }, + "chromeos-betty-pi-arc-chrome-dchecks": { + "args_file": "//build/args/chromeos/betty-pi-arc.gni", + "gn_args": { + "dcheck_always_on": true, + "exclude_unwind_tables": false, + "is_chrome_branded": true, + "is_chromeos_device": true, + "is_official_build": true, + "ozone_platform_headless": true, + "use_goma": true, + "use_real_dbus_clients": false + } + }, "chromeos-eve-arc-r-chrome": { "args_file": "//build/args/chromeos/eve-arc-r.gni", "gn_args": {
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 68b1c59..c8e61c92 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -3691,6 +3691,16 @@ <int value="8" label="Bottom right"/> </enum> +<enum name="AssistantActionPerformed"> +<!-- This must be kept in sync with VoiceInteraction.QueryDuration.Android in +others/histograms.xml --> + + <int value="0" label="Unknown"/> + <int value="1" label="Transcription"/> + <int value="2" label="Translate"/> + <int value="3" label="Readout"/> +</enum> + <enum name="AssistantBetterOnboardingMode"> <int value="0" label="kDefault"/> <int value="1" label="kEdu"/> @@ -4577,6 +4587,7 @@ <int value="19" label="Tab was closed while prompt was visible"/> <int value="20" label="Tab was closed while prompt was invisible"/> <int value="21" label="No trigger script available"/> + <int value="22" label="Failed to show"/> </enum> <enum name="AutofillAssistantLiteScriptOnboarding"> @@ -34928,147 +34939,147 @@ <int value="2" label="Disabled Force"/> </enum> -<enum name="GPUBlacklistFeatureTestResults"> +<enum name="GPUBlocklistFeatureTestResults"> <summary> - Results of testing against a GPU feature being allowed/blacklisted/disabled. + Results of testing against a GPU feature being allowed/blocklisted/disabled. </summary> <int value="0" label="Allowed"/> - <int value="1" label="Blacklisted"/> + <int value="1" label="Blocklisted"/> <int value="2" label="User-disabled"/> </enum> -<enum name="GPUBlacklistFeatureTestResultsWin"> +<enum name="GPUBlocklistFeatureTestResultsWin"> <summary> - Results of testing against a GPU feature being blacklisted or not in various + Results of testing against a GPU feature being blocklisted or not in various Windows sub-versions. </summary> <int value="0" label="Allowed Others"/> - <int value="1" label="Blacklisted Others"/> + <int value="1" label="Blocklisted Others"/> <int value="2" label="Allowed XP"/> - <int value="3" label="Blacklisted XP"/> + <int value="3" label="Blocklisted XP"/> <int value="4" label="Allowed Vista"/> - <int value="5" label="Blacklisted Vista"/> + <int value="5" label="Blocklisted Vista"/> <int value="6" label="Allowed Win7"/> - <int value="7" label="Blacklisted Win7"/> + <int value="7" label="Blocklisted Win7"/> </enum> -<enum name="GPUBlacklistFeatureTestResultsWindows"> +<enum name="GPUBlocklistFeatureTestResultsWindows"> <obsolete> - Replaced by GPUBlacklistFeatureTestResultsWindows2 in M67. + Replaced by GPUBlocklistFeatureTestResultsWindows2 in M67. </obsolete> <summary> - Results of testing against a GPU feature being allowed/blacklisted/disabled + Results of testing against a GPU feature being allowed/blocklisted/disabled in various Windows sub-versions. </summary> <int value="0" label="Allowed Others"/> - <int value="1" label="Blacklisted Others"/> + <int value="1" label="Blocklisted Others"/> <int value="2" label="User-disabled Others"/> <int value="3" label="Allowed XP"/> - <int value="4" label="Blacklisted XP"/> + <int value="4" label="Blocklisted XP"/> <int value="5" label="User-disabled XP"/> <int value="6" label="Allowed Vista"/> - <int value="7" label="Blacklisted Vista"/> + <int value="7" label="Blocklisted Vista"/> <int value="8" label="User-disabled Vista"/> <int value="9" label="Allowed Win7"/> - <int value="10" label="Blacklisted Win7"/> + <int value="10" label="Blocklisted Win7"/> <int value="11" label="User-disabled Win7"/> <int value="12" label="Allowed Win8"/> - <int value="13" label="Blacklisted Win8"/> + <int value="13" label="Blocklisted Win8"/> <int value="14" label="User-disabled Win8"/> </enum> -<enum name="GPUBlacklistFeatureTestResultsWindows2"> +<enum name="GPUBlocklistFeatureTestResultsWindows2"> <obsolete> Removed in Oct 2020. </obsolete> <summary> - Results of testing against a GPU feature being allowed, blacklisted, + Results of testing against a GPU feature being allowed, blocklisted, disabled, fallback to software, or undefined in various Windows sub-versions. </summary> <int value="0" label="Enabled PRE_XP"/> - <int value="1" label="Blacklisted PRE_XP"/> + <int value="1" label="Blocklisted PRE_XP"/> <int value="2" label="User Disabled PRE_XP"/> <int value="3" label="Fallback to Software PRE_XP"/> <int value="4" label="Status Unknown PRE_XP"/> <int value="5" label="Enabled XP"/> - <int value="6" label="Blacklisted XP"/> + <int value="6" label="Blocklisted XP"/> <int value="7" label="User Disabled XP"/> <int value="8" label="Fallback to Software XP"/> <int value="9" label="Status Unknown XP"/> <int value="10" label="Enabled SERVER_2003"/> - <int value="11" label="Blacklisted SERVER_2003"/> + <int value="11" label="Blocklisted SERVER_2003"/> <int value="12" label="User Disabled SERVER_2003"/> <int value="13" label="Fallback to Software SERVER_2003"/> <int value="14" label="Status Unknown SERVER_2003"/> <int value="15" label="Enabled VISTA"/> - <int value="16" label="Blacklisted VISTA"/> + <int value="16" label="Blocklisted VISTA"/> <int value="17" label="User Disabled VISTA"/> <int value="18" label="Fallback to Software VISTA"/> <int value="19" label="Status Unknown VISTA"/> <int value="20" label="Enabled WIN7"/> - <int value="21" label="Blacklisted WIN7"/> + <int value="21" label="Blocklisted WIN7"/> <int value="22" label="User Disabled WIN7"/> <int value="23" label="Fallback to Software WIN7"/> <int value="24" label="Status Unknown WIN7"/> <int value="25" label="Enabled WIN8"/> - <int value="26" label="Blacklisted WIN8"/> + <int value="26" label="Blocklisted WIN8"/> <int value="27" label="User Disabled WIN8"/> <int value="28" label="Fallback to Software WIN8"/> <int value="29" label="Status Unknown WIN8"/> <int value="30" label="Enabled WIN8_1"/> - <int value="31" label="Blacklisted WIN8_1"/> + <int value="31" label="Blocklisted WIN8_1"/> <int value="32" label="User Disabled WIN8_1"/> <int value="33" label="Fallback to Software WIN8_1"/> <int value="34" label="Status Unknown WIN8_1"/> <int value="35" label="Enabled WIN10"/> - <int value="36" label="Blacklisted WIN10"/> + <int value="36" label="Blocklisted WIN10"/> <int value="37" label="User Disabled WIN10"/> <int value="38" label="Fallback to Software WIN10"/> <int value="39" label="Status Unknown WIN10"/> <int value="40" label="Enabled WIN10_TH2"/> - <int value="41" label="Blacklisted WIN10_TH2"/> + <int value="41" label="Blocklisted WIN10_TH2"/> <int value="42" label="User Disabled WIN10_TH2"/> <int value="43" label="Fallback to Software WIN10_TH2"/> <int value="44" label="Status Unknown WIN10_TH2"/> <int value="45" label="Enabled WIN10_RS1"/> - <int value="46" label="Blacklisted WIN10_RS1"/> + <int value="46" label="Blocklisted WIN10_RS1"/> <int value="47" label="User Disabled WIN10_RS1"/> <int value="48" label="Fallback to Software WIN10_RS1"/> <int value="49" label="Status Unknown WIN10_RS1"/> <int value="50" label="Enabled WIN10_RS2"/> - <int value="51" label="Blacklisted WIN10_RS2"/> + <int value="51" label="Blocklisted WIN10_RS2"/> <int value="52" label="User Disabled WIN10_RS2"/> <int value="53" label="Fallback to Software WIN10_RS2"/> <int value="54" label="Status Unknown WIN10_RS2"/> <int value="55" label="Enabled WIN10_RS3"/> - <int value="56" label="Blacklisted WIN10_RS3"/> + <int value="56" label="Blocklisted WIN10_RS3"/> <int value="57" label="User Disabled WIN10_RS3"/> <int value="58" label="Fallback to Software WIN10_RS3"/> <int value="59" label="Status Unknown WIN10_RS3"/> <int value="60" label="Enabled WIN10_RS4"/> - <int value="61" label="Blacklisted WIN10_RS4"/> + <int value="61" label="Blocklisted WIN10_RS4"/> <int value="62" label="User Disabled WIN10_RS4"/> <int value="63" label="Fallback to Software WIN10_RS4"/> <int value="64" label="Status Unknown WIN10_RS4"/> <int value="65" label="Enabled WIN10_RS5"/> - <int value="66" label="Blacklisted WIN10_RS5"/> + <int value="66" label="Blocklisted WIN10_RS5"/> <int value="67" label="User Disabled WIN10_RS5"/> <int value="68" label="Fallback to Software WIN10_RS5"/> <int value="69" label="Status Unknown WIN10_RS5"/> <int value="70" label="Enabled WIN10_19H1"/> - <int value="71" label="Blacklisted WIN10_19H1"/> + <int value="71" label="Blocklisted WIN10_19H1"/> <int value="72" label="User Disabled WIN10_19H1"/> <int value="73" label="Fallback to Software WIN10_19H1"/> <int value="74" label="Status Unknown WIN10_19H1"/> <int value="75" label="Enabled WIN10_20H1"/> - <int value="76" label="Blacklisted WIN10_20H1"/> + <int value="76" label="Blocklisted WIN10_20H1"/> <int value="77" label="User Disabled WIN10_20H1"/> <int value="78" label="Fallback to Software WIN10_20H1"/> <int value="79" label="Status Unknown WIN10_20H1"/> </enum> -<enum name="GPUBlacklistTestResultPerEntry"> +<enum name="GPUBlocklistTestResultPerEntry"> <summary>Results of testing against the GPU blacklist entries.</summary> <int value="0" label="TotalCount"/> <int value="1" label="Mac/ATI/Radeon X1900"/> @@ -41612,6 +41623,11 @@ <int value="2" label="Throttled but stopped due to rebuffer"/> </enum> +<enum name="LiveCaptionExpandBubbleEvent"> + <int value="0" label="Bubble collapsed"/> + <int value="1" label="Bubble expanded"/> +</enum> + <enum name="LiveCaptionSessionEvent"> <int value="0" label="Stream started"/> <int value="1" label="Stream finished"/> @@ -42478,6 +42494,7 @@ <int value="-1614912400" label="enable-link-disambiguation-popup"/> <int value="-1613583483" label="UseNewAcceptLanguageHeader:enabled"/> <int value="-1611758030" label="AndroidWebContentsDarkMode:disabled"/> + <int value="-1611357520" label="MediaAppPdfInInk:enabled"/> <int value="-1611305202" label="KeepPrefetchedContentSuggestions:disabled"/> <int value="-1607953813" label="AndroidPartnerCustomizationPhenotype:enabled"/> @@ -42620,6 +42637,7 @@ <int value="-1481918315" label="SmsReceiverCrossDevice:enabled"/> <int value="-1480926949" label="MaterialDesignBookmarks:enabled"/> <int value="-1480866718" label="ash-disable-login-dim-and-blur"/> + <int value="-1480606359" label="AssistantIntentPageUrl:enabled"/> <int value="-1478876902" label="disable-permission-action-reporting"/> <int value="-1478137998" label="lite-video-default-downlink-bandwidth-kbps"/> <int value="-1477686864" label="OmniboxRichAutocompletion:enabled"/> @@ -44582,6 +44600,7 @@ <int value="413081240" label="enable-new-md-input-view"/> <int value="413695227" label="NTPSuggestionsStandaloneUI:enabled"/> <int value="414114078" label="LitePageServerPreviews:disabled"/> + <int value="414342153" label="AssistantIntentPageUrl:disabled"/> <int value="414937629" label="MediaNotificationsCounter:enabled"/> <int value="415154056" label="enable-physical-keyboard-autocorrect"/> <int value="415395210" label="TrimOnMemoryPressure:enabled"/> @@ -45387,6 +45406,7 @@ <int value="1211284676" label="V8NoTurbo:enabled"/> <int value="1211756417" label="SessionRestorePrioritizesBackgroundUseCases:disabled"/> + <int value="1212526465" label="MediaAppPdfInInk:disabled"/> <int value="1214219155" label="gamepad-polling-interval"/> <int value="1214455758" label="VideoRotateToFullscreen:disabled"/> <int value="1215531732" label="OmniboxUIExperiments:disabled"/> @@ -55661,6 +55681,7 @@ <int value="3" label="SingleOnTop"/> <int value="4" label="Underlay"/> <int value="5" label="Underlay Cast"/> + <int value="6" label="All overlays failed"/> </enum> <enum name="OverlaySupportFlag"> @@ -58310,14 +58331,15 @@ <enum name="PhoneHubScreen"> <int value="0" label="BluetoothOrWifiDisabled"/> - <int value="1" label="ConnectionError"/> - <int value="2" label="InitialConnecting"/> - <int value="3" label="Reconnecting"/> + <int value="1" label="PhoneDisconnected"/> + <int value="2" label="InitialConnecting (Deprecated)"/> + <int value="3" label="Reconnecting (Deprecated)"/> <int value="4" label="Onboarding.ExistingMultideviceUser"/> <int value="5" label="Onboarding.NewMultideviceUser"/> <int value="6" label="PhoneConnected"/> <int value="7" label="OnboardingDismissPrompt"/> <int value="8" label="Invalid"/> + <int value="9" label="PhoneConnecting"/> </enum> <enum name="PhoneNumberRegexVariantResult"> @@ -76037,6 +76059,9 @@ </enum> <enum name="VoiceInteractionEventSource"> +<!-- This must be kept in sync with VoiceInteraction.AssistantActionPerformed in +others/histograms.xml --> + <int value="0" label="Omnibox"/> <int value="1" label="NTP"/> <int value="2" label="Search widget"/>
diff --git a/tools/metrics/histograms/histograms_xml/accessibility/histograms.xml b/tools/metrics/histograms/histograms_xml/accessibility/histograms.xml index 33f450a..8bcdbb47 100644 --- a/tools/metrics/histograms/histograms_xml/accessibility/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/accessibility/histograms.xml
@@ -592,6 +592,34 @@ </summary> </histogram> +<histogram name="Accessibility.LiveCaption.EnableFrom{Entrypoint}" + enum="BooleanEnabled" expires_after="2021-04-30"> + <owner>katie@chromium.org</owner> + <owner>abigailbklein@google.com</owner> + <owner>evliu@google.com</owner> + <owner>chrome-a11y-core@google.com</owner> + <summary> + Records when a user enables or disables the Live Caption feature from + {Entrypoint}. + </summary> + <token key="Entrypoint"> + <variant name="GlobalMediaControls" + summary="global media controls (Zenith)"/> + <variant name="Settings" summary="chrome://settings"/> + </token> +</histogram> + +<histogram name="Accessibility.LiveCaption.ExpandBubble" + enum="LiveCaptionExpandBubbleEvent" expires_after="2021-04-30"> + <owner>katie@chromium.org</owner> + <owner>abigailbklein@google.com</owner> + <owner>evliu@google.com</owner> + <owner>chrome-a11y-core@google.com</owner> + <summary> + Records when a user expands or collapses the Live Caption bubble. + </summary> +</histogram> + <histogram name="Accessibility.LiveCaption.FeatureEnabled" enum="BooleanEnabled" expires_after="2021-04-30"> <owner>katie@chromium.org</owner> @@ -618,18 +646,6 @@ </summary> </histogram> -<histogram name="Accessibility.LiveCaption.ToggleEnabled" enum="BooleanEnabled" - expires_after="2021-04-30"> - <owner>katie@chromium.org</owner> - <owner>abigailbklein@google.com</owner> - <owner>evliu@google.com</owner> - <owner>chrome-a11y-core@google.com</owner> - <summary> - Records when a user enables or disables the Live Caption feature from - chrome://settings. - </summary> -</histogram> - <histogram name="Accessibility.LiveCaption.WebsiteBlocked" enum="BooleanEnabled" expires_after="2021-04-30"> <owner>katie@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/ash/histograms.xml b/tools/metrics/histograms/histograms_xml/ash/histograms.xml index d3ce84c..11ce469 100644 --- a/tools/metrics/histograms/histograms_xml/ash/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/ash/histograms.xml
@@ -1171,17 +1171,33 @@ enum="PhoneHubInterstitialScreenEvent" expires_after="2021-10-31"> <owner>tengs@chromium.org</owner> <owner>khorimoto@chromium.org</owner> - <summary>Events for the given PhoneHub interstitial screen.</summary> + <summary> + Events logged when the given PhoneHub interstitial screen is shown. + </summary> <!-- The entries below should be a subset of the PhoneHubScreen enum --> <token key="Screen"> <variant name="BluetoothOrWifiDisabled"/> - <variant name="ConnectionError"/> - <variant name="InitialConnecting"/> + <variant name="ConnectionError"> + <obsolete> + Renamed to PhoneDisconnected on Nov 2020. + </obsolete> + </variant> + <variant name="InitialConnecting"> + <obsolete> + Combined into PhoneConnecting on Nov 2020. + </obsolete> + </variant> <variant name="Onboarding.ExistingMultideviceUser"/> <variant name="Onboarding.NewMultideviceUser"/> <variant name="OnboardingDismissPrompt"/> - <variant name="Reconnecting"/> + <variant name="PhoneConnecting"/> + <variant name="PhoneDisconnected"/> + <variant name="Reconnecting"> + <obsolete> + Combined into PhoneConnecting on Nov 2020. + </obsolete> + </variant> </token> </histogram>
diff --git a/tools/metrics/histograms/histograms_xml/blink/histograms.xml b/tools/metrics/histograms/histograms_xml/blink/histograms.xml index b0f9c22..ba11ca8 100644 --- a/tools/metrics/histograms/histograms_xml/blink/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/blink/histograms.xml
@@ -1468,6 +1468,17 @@ </summary> </histogram> +<histogram name="Blink.MemoryCache.RevalidationPolicy.PerDocument" + enum="RevalidationPolicy" expires_after="2021-04-21"> + <owner>shivanisha@chromium.org</owner> + <owner>privacy-sandbox-dev@chromium.org</owner> + <summary> + RevalidationPolicy used for requests for each resource type. Logged only if + the resource is found in the memory cache and if the same document had + loaded this resource earlier. + </summary> +</histogram> + <histogram name="Blink.MemoryCache.RevalidationPolicy.Preload" enum="RevalidationPolicy" expires_after="2021-04-21"> <owner>hiroshige@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/browser/histograms.xml b/tools/metrics/histograms/histograms_xml/browser/histograms.xml index 9a61c07..1d4283d 100644 --- a/tools/metrics/histograms/histograms_xml/browser/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/browser/histograms.xml
@@ -117,6 +117,10 @@ <histogram name="Browser.PaintPreview.CaptureExperiment.CompressedOnDiskSize" units="KB" expires_after="2020-12-20"> + <obsolete> + Obsoleted on 2020-11-17 as corresponding experiment code was removed and the + experiment wrapped up. + </obsolete> <owner>ckitagawa@chromium.org</owner> <owner>mahmoudi@chromium.org</owner> <owner>fredmello@chromium.org</owner> @@ -128,6 +132,10 @@ <histogram name="Browser.PaintPreview.CaptureExperiment.Success" enum="BooleanSuccess" expires_after="2020-12-20"> + <obsolete> + Obsoleted on 2020-11-17 as corresponding experiment code was removed and the + experiment wrapped up. + </obsolete> <owner>ckitagawa@chromium.org</owner> <owner>mahmoudi@chromium.org</owner> <owner>fredmello@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/gpu/histograms.xml b/tools/metrics/histograms/histograms_xml/gpu/histograms.xml index daec34f..5fea9a8 100644 --- a/tools/metrics/histograms/histograms_xml/gpu/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/gpu/histograms.xml
@@ -200,7 +200,10 @@ </histogram> <histogram name="GPU.BlacklistFeatureTestResults" - enum="GPUBlacklistFeatureTestResults" expires_after="2021-03-21"> + enum="GPUBlocklistFeatureTestResults" expires_after="M89"> + <obsolete> + Replaced by GPU.BlocklistFeatureTestResults in M89. + </obsolete> <owner>vmiura@chromium.org</owner> <summary> Counts number of browser invocations for which a GPU feature is @@ -209,7 +212,7 @@ </histogram> <histogram name="GPU.BlacklistFeatureTestResultsWindows2" - enum="GPUBlacklistFeatureTestResultsWindows2" expires_after="2020-05-10"> + enum="GPUBlocklistFeatureTestResultsWindows2" expires_after="M89"> <obsolete> Removed in Oct 2020. </obsolete> @@ -221,7 +224,10 @@ </histogram> <histogram name="GPU.BlacklistTestResultsPerDisabledEntry" - enum="GPUBlacklistTestResultPerEntry" expires_after="M85"> + enum="GPUBlocklistTestResultPerEntry" expires_after="M85"> + <obsolete> + Removed before M86. + </obsolete> <owner>vmiura@chromium.org</owner> <summary> Counts number of browser invocations for which a disabled blacklist entry is @@ -230,11 +236,34 @@ </histogram> <histogram name="GPU.BlacklistTestResultsPerEntry" - enum="GPUBlacklistTestResultPerEntry" expires_after="2020-04-26"> + enum="GPUBlocklistTestResultPerEntry" expires_after="M89"> + <obsolete> + Replaced by GPU.BlocklistTestResultsPerEntry in M89. + </obsolete> <owner>vmiura@chromium.org</owner> <summary> Counts number of browser invocations for which the GPU process is blocked - due to a blacklist entry match. + due to a blocklist entry match. + </summary> +</histogram> + +<histogram name="GPU.BlocklistFeatureTestResults" + enum="GPUBlocklistFeatureTestResults" expires_after="2021-03-21"> + <owner>vmiura@chromium.org</owner> + <owner>graphics-dev@chromium.org</owner> + <summary> + Counts number of browser invocations for which a GPU feature is + allowed/blocklisted/disabled. + </summary> +</histogram> + +<histogram name="GPU.BlocklistTestResultsPerEntry" + enum="GPUBlocklistTestResultPerEntry" expires_after="2021-03-21"> + <owner>vmiura@chromium.org</owner> + <owner>graphics-dev@chromium.org</owner> + <summary> + Counts number of browser invocations for which the GPU process is blocked + due to a blocklist entry match. </summary> </histogram> @@ -627,6 +656,9 @@ <histogram name="GPU.GpuBlockedBetweenSwapsUs2" units="microseconds" expires_after="2020-12-01"> + <obsolete> + Removed in Nov 2020 (available as local histogram for telemetry runs). + </obsolete> <owner>vasilyt@chromium.org</owner> <owner>backer@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml b/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml index 7b965bc..5963664 100644 --- a/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml +++ b/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml
@@ -6915,8 +6915,7 @@ </affected-histogram> </histogram_suffixes> -<histogram_suffixes name="GPUBlacklistPerFeature" separator="."> - <owner>vmiura@chromium.org</owner> +<histogram_suffixes name="GPUBlocklistPerFeature" separator="."> <suffix name="Accelerated2dCanvas" label="Accelerated2dCanvas"/> <suffix name="GpuCompositing" label="GpuCompositing"/> <suffix name="GpuRasterization" label="GpuRasterization"/> @@ -6925,6 +6924,7 @@ <affected-histogram name="GPU.BlacklistFeatureTestResults"/> <affected-histogram name="GPU.BlacklistFeatureTestResultsWindows"/> <affected-histogram name="GPU.BlacklistFeatureTestResultsWindows2"/> + <affected-histogram name="GPU.BlocklistFeatureTestResults"/> </histogram_suffixes> <histogram_suffixes name="GpuChannelManagerPressureHandlerDurationDetails" @@ -15848,6 +15848,7 @@ <suffix name="XSLStyleSheet" label=""/> <affected-histogram name="Blink.MemoryCache.RevalidationPolicy"/> <affected-histogram name="Blink.MemoryCache.RevalidationPolicy.Dead"/> + <affected-histogram name="Blink.MemoryCache.RevalidationPolicy.PerDocument"/> <affected-histogram name="Blink.MemoryCache.RevalidationPolicy.Preload"/> <affected-histogram name="PreloadScanner.Counts"/> <affected-histogram name="PreloadScanner.Counts.Miss"/>
diff --git a/tools/metrics/histograms/histograms_xml/obsolete_histograms.xml b/tools/metrics/histograms/histograms_xml/obsolete_histograms.xml index 2dbae87..4cb320fb 100644 --- a/tools/metrics/histograms/histograms_xml/obsolete_histograms.xml +++ b/tools/metrics/histograms/histograms_xml/obsolete_histograms.xml
@@ -25690,7 +25690,7 @@ </histogram> <histogram name="GPU.BlacklistFeatureTestResultsWindows" - enum="GPUBlacklistFeatureTestResultsWindows" expires_after="2018-02-28"> + enum="GPUBlocklistFeatureTestResultsWindows" expires_after="2018-02-28"> <obsolete> Replaced by GPU.BlacklistFeatureTestResultsWindows2 in M67. </obsolete>
diff --git a/tools/metrics/histograms/histograms_xml/others/histograms.xml b/tools/metrics/histograms/histograms_xml/others/histograms.xml index f16cd7597..3d2b94c 100644 --- a/tools/metrics/histograms/histograms_xml/others/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/others/histograms.xml
@@ -8897,14 +8897,19 @@ expires_after="M87"> <owner>zentaro@chromium.org</owner> <owner>cros-peripherals@chromium.org</owner> - <summary>Tracks mouse acceleration setting changes by the user.</summary> + <summary> + Tracks mouse acceleration setting changes by the user. Only reported on + Chrome OS. + </summary> </histogram> <histogram name="Mouse.Acceleration.Started" enum="BooleanEnabled" expires_after="M87"> <owner>zentaro@chromium.org</owner> <owner>cros-peripherals@chromium.org</owner> - <summary>Tracks mouse acceleration setting on startup.</summary> + <summary> + Tracks mouse acceleration setting on startup. Only reported on Chrome OS. + </summary> </histogram> <histogram name="Mouse.PointerSensitivity.Changed" enum="PointerSensitivity" @@ -8913,7 +8918,7 @@ <owner>cros-peripherals@google.com</owner> <summary> Tracks mouse sensitivity setting changes by the user. This replaces the old - Mouse.Sensitivity.Changed metric. + Mouse.Sensitivity.Changed metric. Only reported on Chrome OS. </summary> </histogram> @@ -8923,20 +8928,25 @@ <owner>cros-peripherals@google.com</owner> <summary> Tracks mouse sensitivity setting on startup. This replaces the old - Mouse.Sensitivity.Started metric. + Mouse.Sensitivity.Started metric. Only reported on Chrome OS. </summary> </histogram> <histogram name="Mouse.ReverseScroll.Changed" enum="BooleanEnabled" expires_after="M77"> <owner>lannm@chromium.org</owner> - <summary>Tracks mouse reverse scroll setting changes by the user.</summary> + <summary> + Tracks mouse reverse scroll setting changes by the user. Only reported on + Chrome OS. + </summary> </histogram> <histogram name="Mouse.ReverseScroll.Started" enum="BooleanEnabled" expires_after="M85"> <owner>lannm@chromium.org</owner> - <summary>Tracks mouse reverse scroll setting on startup.</summary> + <summary> + Tracks mouse reverse scroll setting on startup. Only reported on Chrome OS. + </summary> </histogram> <histogram base="true" name="Mouse.ScrollAcceleration" enum="BooleanEnabled" @@ -8945,7 +8955,9 @@ <owner>khorimoto@chromium.org</owner> <owner>zentaro@chromium.org</owner> - <summary>Whether mouse scroll acceleration is enabled.</summary> + <summary> + Whether mouse scroll acceleration is enabled. Only reported on Chrome OS. + </summary> </histogram> <histogram base="true" name="Mouse.ScrollSensitivity" enum="PointerSensitivity" @@ -8954,7 +8966,7 @@ <owner>khorimoto@chromium.org</owner> <owner>zentaro@chromium.org</owner> - <summary>Mouse scroll sensitivity value.</summary> + <summary>Mouse scroll sensitivity value. Only reported on Chrome OS.</summary> </histogram> <histogram name="MPArch.ChildProcessLaunchFirst" units="units" @@ -15353,14 +15365,19 @@ expires_after="M87"> <owner>zentaro@chromium.org</owner> <owner>cros-peripherals@chromium.org</owner> - <summary>Tracks touchpad acceleration setting changes by the user.</summary> + <summary> + Tracks touchpad acceleration setting changes by the user. Only reported on + Chrome OS. + </summary> </histogram> <histogram name="Touchpad.Acceleration.Started" enum="BooleanEnabled" expires_after="M87"> <owner>zentaro@chromium.org</owner> <owner>cros-peripherals@chromium.org</owner> - <summary>Tracks touchpad acceleration setting on startup.</summary> + <summary> + Tracks touchpad acceleration setting on startup. Only reported on Chrome OS. + </summary> </histogram> <histogram name="Touchpad.Device" enum="TouchpadDeviceState" @@ -15373,14 +15390,20 @@ expires_after="2021-07-15"> <owner>zentaro@chromium.org</owner> <owner>cros-peripherals@google.com</owner> - <summary>Tracks touchpad natural scroll setting changes by the user.</summary> + <summary> + Tracks touchpad natural scroll setting changes by the user. Only reported on + Chrome OS. + </summary> </histogram> <histogram name="Touchpad.NaturalScroll.Started" enum="BooleanEnabled" expires_after="2021-07-15"> <owner>zentaro@chromium.org</owner> <owner>cros-peripherals@google.com</owner> - <summary>Tracks touchpad natural scroll setting on startup.</summary> + <summary> + Tracks touchpad natural scroll setting on startup. Only reported on Chrome + OS. + </summary> </histogram> <histogram name="Touchpad.PointerSensitivity.Changed" enum="PointerSensitivity" @@ -15389,7 +15412,7 @@ <owner>cros-peripherals@google.com</owner> <summary> Tracks touchpad sensitivity setting changes by the user. This replaces the - old Touchpad.Sensitivity.Changed metric. + old Touchpad.Sensitivity.Changed metric. Only reported on Chrome OS. </summary> </histogram> @@ -15399,7 +15422,7 @@ <owner>cros-peripherals@google.com</owner> <summary> Tracks touchpad sensitivity setting on startup. This replaces the old - Touchpad.Sensitivity.Started metric. + Touchpad.Sensitivity.Started metric. Only reported on Chrome OS. </summary> </histogram> @@ -15409,7 +15432,9 @@ <owner>khorimoto@chromium.org</owner> <owner>zentaro@chromium.org</owner> - <summary>Whether touchpad scroll acceleration is enabled.</summary> + <summary> + Whether touchpad scroll acceleration is enabled. Only reported on Chrome OS. + </summary> </histogram> <histogram base="true" name="Touchpad.ScrollSensitivity" @@ -15418,35 +15443,48 @@ <owner>khorimoto@chromium.org</owner> <owner>zentaro@chromium.org</owner> - <summary>Touchpad scroll sensitivity value.</summary> + <summary> + Touchpad scroll sensitivity value. Only reported on Chrome OS. + </summary> </histogram> <histogram name="Touchpad.TapDragging.Changed" enum="BooleanEnabled" expires_after="2021-07-15"> <owner>zentaro@chromium.org</owner> <owner>cros-peripherals@google.com</owner> - <summary>Tracks touchpad TapDragging setting changes by the user.</summary> + <summary> + Tracks touchpad TapDragging setting changes by the user. Only reported on + Chrome OS. + </summary> </histogram> <histogram name="Touchpad.TapDragging.Started" enum="BooleanEnabled" expires_after="2021-07-15"> <owner>zentaro@chromium.org</owner> <owner>cros-peripherals@google.com</owner> - <summary>Tracks touchpad TapDragging setting on startup.</summary> + <summary> + Tracks touchpad TapDragging setting on startup. Only reported on Chrome OS. + </summary> </histogram> <histogram name="Touchpad.TapToClick.Changed" enum="BooleanEnabled" expires_after="2021-07-15"> <owner>zentaro@chromium.org</owner> <owner>cros-peripherals@google.com</owner> - <summary>Tracks touchpad TapToClick setting changes by the user.</summary> + <summary> + Tracks touchpad TapToClick setting changes by the user. Only reported on + Chrome OS. + </summary> </histogram> <histogram name="Touchpad.TapToClick.Started" enum="BooleanEnabled" expires_after="2021-07-15"> <owner>zentaro@chromium.org</owner> <owner>cros-peripherals@google.com</owner> - <summary>Tracks touchpad TapToClick setting changes by the user.</summary> + <summary> + Tracks touchpad TapToClick setting changes by the user. Only reported on + Chrome OS. + </summary> </histogram> <histogram name="TouchScreen.MissedTOUCHEVENTF_UP" enum="BooleanHit" @@ -16093,6 +16131,17 @@ </summary> </histogram> +<histogram name="Viz.DisplayCompositor.OverlayNumProposedCandidates" + units="units" expires_after="2021-07-01"> + <owner>petermcneeley@chromium.org</owner> + <owner>dcastagna@chromium.org</owner> + <summary> + A count of the number of proposed overlay candidates available for overlay + selection. Recorded every time a frame is rendered by the display + compositor. + </summary> +</histogram> + <histogram name="Viz.DisplayCompositor.OverlayStrategy" enum="OverlayStrategies" expires_after="2021-07-01"> <owner>dcastagna@chromium.org</owner> @@ -16103,6 +16152,16 @@ </summary> </histogram> +<histogram name="Viz.DisplayCompositor.OverlaySwitchInterval" units="ms" + expires_after="2021-07-01"> + <owner>petermcneeley@chromium.org</owner> + <owner>dcastagna@chromium.org</owner> + <summary> + The time, in milliseconds, since the change in overlay selection. Recorded + every time a frame is rendered by the display compositor. + </summary> +</histogram> + <histogram name="Viz.DisplayCompositor.RootDamageRect.Overlay" enum="BooleanOverlayDamageRect" expires_after="2021-12-01"> <owner>magchen@chromium.org</owner> @@ -16165,6 +16224,27 @@ </summary> </histogram> +<histogram name="VoiceInteraction.AssistantActionPerformed{Source}" + enum="AssistantActionPerformed" expires_after="2021-04-04"> + <owner>jds@chromium.org</owner> + <owner>chrome-language@google.com</owner> + <summary> + Android: The action performed by Assistant upon being invoked during a voice + search initiated via the {Source}, such as transcription of a voice search + query or translation of the current page. This is recorded after an + Assistant intent has completed successfully. + </summary> + <token key="Source"> +<!-- Must be kept in sync with VoiceInteractionEventSource in enums.xml. --> + + <variant name=".NTP" summary="NTP"/> + <variant name=".Omnibox" summary="Omnibox"/> + <variant name=".SearchWidget" summary="Search widget"/> + <variant name=".TasksSurface" summary="Tasks surface"/> + <variant name=".Toolbar" summary="Toolbar"/> + </token> +</histogram> + <histogram name="VoiceInteraction.DismissedEventSource" enum="VoiceInteractionEventSource" expires_after="2021-03-28"> <owner>wylieb@chromium.org</owner> @@ -16205,15 +16285,38 @@ </histogram> <histogram name="VoiceInteraction.QueryDuration.Android" units="ms" - expires_after="2021-01-24"> + expires_after="2021-04-04"> <owner>wylieb@chromium.org</owner> <owner>tedchoc@chromium.org</owner> <summary> Records the time it takes between the user clicking the mic and chrome - recieving the transcribed voice query. + receiving the transcribed voice query. This is recorded after an Assistant + intent has completed successfully. </summary> </histogram> +<histogram name="VoiceInteraction.QueryDuration.Android{Action}" units="ms" + expires_after="2021-04-04"> + <owner>wylieb@chromium.org</owner> + <owner>tedchoc@chromium.org</owner> + <summary> + Records the time it takes between the user clicking the mic and chrome + receiving the intent response for {Action} actions. This is recorded after + an Assistant intent has completed successfully. These per-action variants + are recorded only when non-transcription actions are enabled. See + VoiceInteraction.QueryDuration.Android for the total count that includes + clients with non-transcription actions disabled. + </summary> + <token key="Action"> +<!-- Must be kept in sync with AssistantActionPerformed in enums.xml. --> + + <variant name=".Readout" summary="Readout"/> + <variant name=".Transcription" summary="Transcription"/> + <variant name=".Translate" summary="Translate"/> + <variant name=".Unknown" summary="Unknown"/> + </token> +</histogram> + <histogram name="VoiceInteraction.StartEventSource" enum="VoiceInteractionEventSource" expires_after="2021-03-28"> <owner>wylieb@chromium.org</owner>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json index bcedc5f..568a1c7 100644 --- a/tools/perf/core/perfetto_binary_roller/binary_deps.json +++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -2,7 +2,7 @@ "trace_processor_shell": { "win": { "hash": "bfdb6057bef6817a2dde5a68acd2e3852a05ff62", - "remote_path": "perfetto_binaries/trace_processor_shell/win/3a578ae352335947ee862d0a9ebc0a70e71902b0/trace_processor_shell.exe" + "remote_path": "perfetto_binaries/trace_processor_shell/win/16973d613fed5c24d63bc4bf6cc9ffe267708ea5/trace_processor_shell.exe" }, "mac": { "hash": "fc50aba2bda1b92a35ddce6e7cfa0fcba40b010d",
diff --git a/tools/privacy_budget/font_indexer/font_indexer.cc b/tools/privacy_budget/font_indexer/font_indexer.cc index e1f983b..68a20550 100644 --- a/tools/privacy_budget/font_indexer/font_indexer.cc +++ b/tools/privacy_budget/font_indexer/font_indexer.cc
@@ -11,8 +11,10 @@ #include "base/logging.h" #include "base/run_loop.h" #include "content/public/browser/font_list_async.h" +#include "third_party/blink/public/common/privacy_budget/identifiable_token_builder.h" #include "third_party/blink/renderer/platform/fonts/font_global_context.h" #include "third_party/blink/renderer/platform/fonts/simple_font_data.h" +#include "third_party/blink/renderer/platform/privacy_budget/identifiability_digest_helpers.h" #include "third_party/blink/renderer/platform/wtf/hash_set.h" namespace privacy_budget { @@ -80,8 +82,9 @@ }; const char kOutputHeader[] = - "Family name\tPostScript name\tweight\twidth\tslope\tdigest " - "(int64_t)\tdigest (uint64_t)"; + "Family name\tPostScript name\tweight\twidth\tslope\ttypeface " + "digest\tdefault family name lookup digest\tdefault PostScript name lookup " + "digest"; const char kOutputSeparator[] = "\t"; FontIndexer::FontIndexer() : font_cache_(blink::FontCache::GetFontCache()) {} @@ -234,18 +237,47 @@ if (scoped_refptr<blink::SimpleFontData> font_data = font_cache_->GetFontData(font_description, name)) { - int64_t digest = + uint64_t typeface_digest = blink::FontGlobalContext::Get() ->GetOrComputeTypefaceDigest(font_data->PlatformData()) .ToUkmMetricValue(); - if (set_of_digests.insert(digest).is_new_entry) { + if (set_of_digests.insert(typeface_digest).is_new_entry) { + WTF::String postscript_name = + font_data->PlatformData().GetPostScriptName(); + + // Matches behavior in FontMatchingMetrics for lookups using the + // family name and the PostScript name, respectively, with default + // FontSelectionRequests. + uint64_t default_family_name_lookup_digest; + { + blink::IdentifiableTokenBuilder builder; + builder.AddValue( + blink::FontDescription().GetFontSelectionRequest().GetHash()); + builder.AddToken( + blink::IdentifiabilityBenignCaseFoldingStringToken(name)); + default_family_name_lookup_digest = + builder.GetToken().ToUkmMetricValue(); + } + uint64_t default_postscript_name_lookup_digest; + { + blink::IdentifiableTokenBuilder builder; + builder.AddValue( + blink::FontDescription().GetFontSelectionRequest().GetHash()); + builder.AddToken( + blink::IdentifiabilityBenignCaseFoldingStringToken( + postscript_name)); + default_postscript_name_lookup_digest = + builder.GetToken().ToUkmMetricValue(); + } + std::cout << name.Ascii() << kOutputSeparator - << font_data->PlatformData().GetPostScriptName().Ascii() - << kOutputSeparator << weight_pair.second - << kOutputSeparator << width_pair.second - << kOutputSeparator << slope_pair.second - << kOutputSeparator << digest << kOutputSeparator - << static_cast<uint64_t>(digest) << std::endl; + << postscript_name.Ascii() << kOutputSeparator + << weight_pair.second << kOutputSeparator + << width_pair.second << kOutputSeparator + << slope_pair.second << kOutputSeparator + << typeface_digest << kOutputSeparator + << default_family_name_lookup_digest << kOutputSeparator + << default_postscript_name_lookup_digest << std::endl; } } }
diff --git a/tools/traffic_annotation/summary/annotations.xml b/tools/traffic_annotation/summary/annotations.xml index 1ec703f..b458e81 100644 --- a/tools/traffic_annotation/summary/annotations.xml +++ b/tools/traffic_annotation/summary/annotations.xml
@@ -308,7 +308,7 @@ <item id="save_file_manager" added_in_milestone="62" hash_code="56275203" type="0" content_hash_code="56692339" os_list="linux,windows" file_path="content/browser/download/save_file_manager.cc"/> <item id="sct_auditing" added_in_milestone="87" hash_code="48603483" type="0" content_hash_code="43567503" os_list="linux,windows" file_path="chrome/browser/ssl/sct_reporting_service.cc"/> <item id="sdch_dictionary_fetch" added_in_milestone="62" hash_code="47152935" type="0" deprecated="2017-09-16" content_hash_code="16764294" file_path=""/> - <item id="search_prefetch_service" added_in_milestone="88" hash_code="108986091" type="0" content_hash_code="125257414" os_list="linux,windows" file_path="chrome/browser/prefetch/search_prefetch/search_prefetch_service.cc"/> + <item id="search_prefetch_service" added_in_milestone="88" hash_code="108986091" type="0" content_hash_code="125257414" os_list="windows,linux" file_path="chrome/browser/prefetch/search_prefetch/base_search_prefetch_request.cc"/> <item id="search_suggest_service" added_in_milestone="73" hash_code="57785193" type="0" content_hash_code="132247652" os_list="linux,windows" file_path="chrome/browser/search/search_suggest/search_suggest_loader_impl.cc"/> <item id="security_key_socket" added_in_milestone="66" hash_code="31074955" type="0" content_hash_code="13741232" os_list="linux,windows" file_path="remoting/host/security_key/security_key_socket.cc"/> <item id="send_message_express" added_in_milestone="85" hash_code="23527666" type="0" deprecated="2020-09-21" content_hash_code="96850228" file_path=""/>
diff --git a/ui/accessibility/ax_enum_util.cc b/ui/accessibility/ax_enum_util.cc index cf2dd9dc..2d97da80 100644 --- a/ui/accessibility/ax_enum_util.cc +++ b/ui/accessibility/ax_enum_util.cc
@@ -462,8 +462,6 @@ return "searchBox"; case ax::mojom::Role::kSlider: return "slider"; - case ax::mojom::Role::kSliderThumb: - return "sliderThumb"; case ax::mojom::Role::kSpinButton: return "spinButton"; case ax::mojom::Role::kSplitter:
diff --git a/ui/accessibility/ax_enums.mojom b/ui/accessibility/ax_enums.mojom index faf5746..80bcb665 100644 --- a/ui/accessibility/ax_enums.mojom +++ b/ui/accessibility/ax_enums.mojom
@@ -274,7 +274,6 @@ kSearchBox, kSection, kSlider, - kSliderThumb, kSpinButton, kSplitter, kStaticText,
diff --git a/ui/accessibility/ax_role_properties.cc b/ui/accessibility/ax_role_properties.cc index 4712489..8a4c27c 100644 --- a/ui/accessibility/ax_role_properties.cc +++ b/ui/accessibility/ax_role_properties.cc
@@ -303,6 +303,7 @@ case ax::mojom::Role::kRadioButton: case ax::mojom::Role::kDescriptionListTerm: case ax::mojom::Role::kTerm: + DCHECK(!IsSetLike(role)) << "Role cannot be both item-like and set-like."; return true; default: return false;
diff --git a/ui/accessibility/ax_role_properties.h b/ui/accessibility/ax_role_properties.h index c9819bd..c4207f55 100644 --- a/ui/accessibility/ax_role_properties.h +++ b/ui/accessibility/ax_role_properties.h
@@ -86,7 +86,7 @@ AX_BASE_EXPORT bool IsImageOrVideo(const ax::mojom::Role role); // Returns true if the provided role is item-like, specifically if it can hold -// pos_in_set and set_size values. +// pos_in_set and set_size values. Roles that are item-like are not set-like. AX_BASE_EXPORT bool IsItemLike(const ax::mojom::Role role); // Returns true if the role is a subclass of the ARIA Landmark abstract role. @@ -145,7 +145,7 @@ AX_BASE_EXPORT bool IsSelectElement(const ax::mojom::Role role); // Returns true if the provided role is ordered-set like, specifically if it -// can hold set_size values. +// can hold set_size values. Roles that are set-like are not item-like. AX_BASE_EXPORT bool IsSetLike(const ax::mojom::Role role); // Returns true if the provided role belongs to a non-interactive list.
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux.cc b/ui/accessibility/platform/ax_platform_node_auralinux.cc index 0788061..ec590e2 100644 --- a/ui/accessibility/platform/ax_platform_node_auralinux.cc +++ b/ui/accessibility/platform/ax_platform_node_auralinux.cc
@@ -2932,7 +2932,6 @@ case ax::mojom::Role::kSearch: return ATK_ROLE_LANDMARK; case ax::mojom::Role::kSlider: - case ax::mojom::Role::kSliderThumb: return ATK_ROLE_SLIDER; case ax::mojom::Role::kSpinButton: return ATK_ROLE_SPIN_BUTTON;
diff --git a/ui/accessibility/platform/ax_platform_node_base.h b/ui/accessibility/platform/ax_platform_node_base.h index 2da228c..5ccdfa6 100644 --- a/ui/accessibility/platform/ax_platform_node_base.h +++ b/ui/accessibility/platform/ax_platform_node_base.h
@@ -366,6 +366,12 @@ // AXPlatformNodeDelegate* delegate_ = nullptr; + // Uses the delegate to calculate this node's PosInSet. + base::Optional<int> GetPosInSet() const; + + // Uses the delegate to calculate this node's SetSize. + base::Optional<int> GetSetSize() const; + bool IsDocument() const; protected: @@ -493,9 +499,6 @@ size_t* old_len, size_t* new_len); - base::Optional<int> GetPosInSet() const; - base::Optional<int> GetSetSize() const; - std::string GetInvalidValue() const; // Based on the characteristics of this object, such as its role and the
diff --git a/ui/accessibility/platform/ax_platform_node_mac.mm b/ui/accessibility/platform/ax_platform_node_mac.mm index 094535d..33e621a 100644 --- a/ui/accessibility/platform/ax_platform_node_mac.mm +++ b/ui/accessibility/platform/ax_platform_node_mac.mm
@@ -195,7 +195,6 @@ {ax::mojom::Role::kSearchBox, NSAccessibilityTextFieldRole}, {ax::mojom::Role::kSection, NSAccessibilityGroupRole}, {ax::mojom::Role::kSlider, NSAccessibilitySliderRole}, - {ax::mojom::Role::kSliderThumb, NSAccessibilityValueIndicatorRole}, {ax::mojom::Role::kSpinButton, NSAccessibilityIncrementorRole}, {ax::mojom::Role::kSplitter, NSAccessibilitySplitterRole}, {ax::mojom::Role::kStaticText, NSAccessibilityStaticTextRole}, @@ -629,7 +628,6 @@ case ax::mojom::Role::kRadioButton: case ax::mojom::Role::kSearchBox: case ax::mojom::Role::kSlider: - case ax::mojom::Role::kSliderThumb: case ax::mojom::Role::kToggleButton: [axAttributes addObjectsFromArray:kValueAttributes]; break; @@ -637,12 +635,14 @@ default: break; } - if (_node->GetData().HasBoolAttribute(ax::mojom::BoolAttribute::kSelected)) { - [axAttributes addObjectsFromArray:@[ NSAccessibilitySelectedAttribute ]]; - } - if (ui::IsMenuItem(_node->GetData().role)) { - [axAttributes addObjectsFromArray:@[ @"AXMenuItemMarkChar" ]]; - } + if (_node->GetData().HasBoolAttribute(ax::mojom::BoolAttribute::kSelected)) + [axAttributes addObject:NSAccessibilitySelectedAttribute]; + if (ui::IsMenuItem(_node->GetData().role)) + [axAttributes addObject:@"AXMenuItemMarkChar"]; + if (ui::IsItemLike(_node->GetData().role)) + [axAttributes addObjectsFromArray:@[ @"AXARIAPosInSet", @"AXARIASetSize" ]]; + if (ui::IsSetLike(_node->GetData().role)) + [axAttributes addObject:@"AXARIASetSize"]; return axAttributes.autorelease(); } @@ -842,6 +842,20 @@ return @""; } +- (NSNumber*)AXARIAPosInSet { + base::Optional<int> posInSet = _node->GetPosInSet(); + if (!posInSet) + return nil; + return @(*posInSet); +} + +- (NSNumber*)AXARIASetSize { + base::Optional<int> setSize = _node->GetSetSize(); + if (!setSize) + return nil; + return @(*setSize); +} + // Text-specific attributes. - (NSString*)AXSelectedText {
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc index 5f20023..19ea6fe 100644 --- a/ui/accessibility/platform/ax_platform_node_win.cc +++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -5417,9 +5417,6 @@ case ax::mojom::Role::kSlider: return ROLE_SYSTEM_SLIDER; - case ax::mojom::Role::kSliderThumb: - return ROLE_SYSTEM_SLIDER; - case ax::mojom::Role::kSpinButton: return ROLE_SYSTEM_SPINBUTTON; @@ -6251,9 +6248,6 @@ case ax::mojom::Role::kSlider: return L"slider"; - case ax::mojom::Role::kSliderThumb: - return L"slider"; - case ax::mojom::Role::kSpinButton: return L"spinbutton"; @@ -6910,9 +6904,6 @@ case ax::mojom::Role::kSlider: return UIA_SliderControlTypeId; - case ax::mojom::Role::kSliderThumb: - return UIA_SliderControlTypeId; - case ax::mojom::Role::kSpinButton: return UIA_SpinnerControlTypeId;
diff --git a/ui/gfx/canvas_skia.cc b/ui/gfx/canvas_skia.cc index ddc60e28..4ef6a066 100644 --- a/ui/gfx/canvas_skia.cc +++ b/ui/gfx/canvas_skia.cc
@@ -25,13 +25,16 @@ // Returns a range in |text| to underline or Range::InvalidRange() if // underlining is not needed. Range StripAcceleratorChars(int flags, base::string16* text) { - if (flags & (Canvas::SHOW_PREFIX | Canvas::HIDE_PREFIX)) { + if (flags & Canvas::SHOW_PREFIX) { int char_pos = -1; int char_span = 0; - *text = RemoveAcceleratorChar(*text, '&', &char_pos, &char_span); - if ((flags & Canvas::SHOW_PREFIX) && char_pos != -1) + *text = LocateAndRemoveAcceleratorChar(*text, &char_pos, &char_span); + if (char_pos != -1) return Range(char_pos, char_pos + char_span); + } else if (flags & Canvas::HIDE_PREFIX) { + *text = RemoveAccelerator(*text); } + return Range::InvalidRange(); }
diff --git a/ui/gfx/render_text.cc b/ui/gfx/render_text.cc index 4c1cd4d..6e661b2d 100644 --- a/ui/gfx/render_text.cc +++ b/ui/gfx/render_text.cc
@@ -2080,6 +2080,8 @@ if (trailing_text_direction != text_direction && new_text.length() + 2 > text.length() && guess >= 1) { new_text = slicer.CutString(guess - 1, false); + trailing_text_direction = + base::i18n::GetLastStrongCharacterDirection(new_text); } // Append the ellipsis and the optional directional marker characters.
diff --git a/ui/gfx/render_text_unittest.cc b/ui/gfx/render_text_unittest.cc index 578f655..57b1861 100644 --- a/ui/gfx/render_text_unittest.cc +++ b/ui/gfx/render_text_unittest.cc
@@ -2061,7 +2061,7 @@ {"rtl_ltr_3", L"\u05d0\u05d1\u05d2abc", L"\u05d0\u05d1\u2026"}, {"bidi_1", L"012a\u05d1b\u05d1c", L"012a\u2026"}, {"bidi_2", L"012a\u05d1b\u05d1c", L"012a\u05d1\u2026\u200F"}, - {"bidi_3", L"012a\u05d1b\u05d1c", L"012a\u05d1b\u2026\u200F"}, + {"bidi_3", L"012a\u05d1b\u05d1c", L"012a\u05d1b\u2026"}, // No RLM marker added as digits (012) have weak directionality. {"no_rlm", L"01\u05d0\u05d1\u05d2", L"01\u05d0\u2026"}, // RLM marker added as "ab" have strong LTR directionality.
diff --git a/ui/gfx/text_utils.cc b/ui/gfx/text_utils.cc index ab52cf4..58a002d 100644 --- a/ui/gfx/text_utils.cc +++ b/ui/gfx/text_utils.cc
@@ -22,6 +22,10 @@ namespace { +constexpr base::char16 kAcceleratorChar = '&'; +constexpr base::char16 kOpenParenthesisChar = '('; +constexpr base::char16 kCloseParenthesisChar = ')'; + // Returns true if the specified character must be elided from a string. // Examples are combining marks and whitespace. bool IsCombiningMark(UChar32 c) { @@ -39,10 +43,8 @@ char_type == U_PARAGRAPH_SEPARATOR || char_type == U_CONTROL_CHAR; } -} // namespace - -base::string16 RemoveAcceleratorChar(const base::string16& s, - base::char16 accelerator_char, +base::string16 RemoveAcceleratorChar(bool full_removal, + const base::string16& s, int* accelerated_char_pos, int* accelerated_char_span) { bool escaped = false; @@ -51,15 +53,47 @@ UTF16CharIterator chars(s); base::string16 accelerator_removed; + // The states of a state machine looking for a CJK-style accelerator (i.e. + // "(&x)"). |cjk_state| proceeds up from |kFoundNothing| through these states, + // resetting either when it sees a complete accelerator, or gives up because + // the current character doesn't match. + enum { + kFoundNothing, + kFoundOpenParen, + kFoundAcceleratorChar, + kFoundAccelerator + } cjk_state = kFoundNothing; + size_t pre_cjk_size = 0; + accelerator_removed.reserve(s.size()); while (!chars.end()) { int32_t c = chars.get(); int array_pos = chars.array_pos(); chars.Advance(); - if (c != accelerator_char || escaped) { + if (full_removal) { + if (cjk_state == kFoundNothing && c == kOpenParenthesisChar) { + pre_cjk_size = array_pos; + cjk_state = kFoundOpenParen; + } else if (cjk_state == kFoundOpenParen && c == kAcceleratorChar) { + cjk_state = kFoundAcceleratorChar; + } else if (cjk_state == kFoundAcceleratorChar) { + // Accept any character as the accelerator. + cjk_state = kFoundAccelerator; + } else if (cjk_state == kFoundAccelerator && c == kCloseParenthesisChar) { + cjk_state = kFoundNothing; + accelerator_removed.resize(pre_cjk_size); + pre_cjk_size = 0; + escaped = false; + continue; + } else { + cjk_state = kFoundNothing; + } + } + + if (c != kAcceleratorChar || escaped) { int span = chars.array_pos() - array_pos; - if (escaped && c != accelerator_char) { + if (escaped && c != kAcceleratorChar) { last_char_pos = accelerator_removed.size(); last_char_span = span; } @@ -71,14 +105,27 @@ } } - if (accelerated_char_pos) + if (accelerated_char_pos && !full_removal) *accelerated_char_pos = last_char_pos; - if (accelerated_char_span) + if (accelerated_char_span && !full_removal) *accelerated_char_span = last_char_span; return accelerator_removed; } +} // namespace + +base::string16 LocateAndRemoveAcceleratorChar(const base::string16& s, + int* accelerated_char_pos, + int* accelerated_char_span) { + return RemoveAcceleratorChar(false, s, accelerated_char_pos, + accelerated_char_span); +} + +base::string16 RemoveAccelerator(const base::string16& s) { + return RemoveAcceleratorChar(true, s, nullptr, nullptr); +} + size_t FindValidBoundaryBefore(const base::string16& text, size_t index, bool trim_whitespace) {
diff --git a/ui/gfx/text_utils.h b/ui/gfx/text_utils.h index ea342ee5..d1ca328 100644 --- a/ui/gfx/text_utils.h +++ b/ui/gfx/text_utils.h
@@ -17,15 +17,27 @@ class Insets; class Size; -// Strip the accelerator char (typically '&') from a menu string. A double -// accelerator char ('&&') will be converted to a single char. The out params +// Strips the accelerator char ('&') from a menu string. Useful for platforms +// which use underlining to indicate accelerators. +// +// Single accelerator chars ('&') will be stripped from the string. Double +// accelerator chars ('&&') will be converted to a single '&'. The out params // |accelerated_char_pos| and |accelerated_char_span| will be set to the index // and span of the last accelerated character, respectively, or -1 and 0 if // there was none. -GFX_EXPORT base::string16 RemoveAcceleratorChar(const base::string16& s, - base::char16 accelerator_char, - int* accelerated_char_pos, - int* accelerated_char_span); +GFX_EXPORT base::string16 LocateAndRemoveAcceleratorChar( + const base::string16& s, + int* accelerated_char_pos, + int* accelerated_char_span); + +// Strips all accelerator notation from a menu string. Useful for platforms +// which use underlining to indicate accelerators, as well as situations where +// accelerators are not indicated. +// +// Single accelerator chars ('&') will be stripped from the string. Double +// accelerator chars ('&&') will be converted to a single '&'. CJK language +// accelerators, specified as "(&x)", will be entirely removed too. +GFX_EXPORT base::string16 RemoveAccelerator(const base::string16& s); // Returns the number of horizontal pixels needed to display the specified // |text| with |font_list|. |typesetter| indicates where the text will be
diff --git a/ui/gfx/text_utils_unittest.cc b/ui/gfx/text_utils_unittest.cc index ed1eb98..12df151 100644 --- a/ui/gfx/text_utils_unittest.cc +++ b/ui/gfx/text_utils_unittest.cc
@@ -21,16 +21,6 @@ namespace gfx { namespace { -const base::char16 kAcceleratorChar = '&'; - -struct RemoveAcceleratorCharData { - const char* input; - int accelerated_char_pos; - int accelerated_char_span; - const char* output; - const char* name; -}; - TEST(TextUtilsTest, GetStringWidth) { FontList font_list; EXPECT_EQ(GetStringWidth(base::string16(), font_list), 0); @@ -117,6 +107,15 @@ EXPECT_EQ(0, GetFontCapHeightCenterOffset(original_font, original_font)); } +struct RemoveAcceleratorCharData { + const char* input; + int accelerated_char_pos; + int accelerated_char_span; + const char* output_locate_and_strip; + const char* output_full_strip; + const char* name; +}; + class RemoveAcceleratorCharTest : public testing::TestWithParam<RemoveAcceleratorCharData> { public: @@ -124,37 +123,62 @@ }; const RemoveAcceleratorCharData RemoveAcceleratorCharTest::kCases[] = { - {"", -1, 0, "", "EmptyString"}, - {"&", -1, 0, "", "AcceleratorCharOnly"}, - {"no accelerator", -1, 0, "no accelerator", "NoAccelerator"}, - {"&one accelerator", 0, 1, "one accelerator", "OneAccelerator_Start"}, - {"one &accelerator", 4, 1, "one accelerator", "OneAccelerator_Middle"}, - {"one_accelerator&", -1, 0, "one_accelerator", "OneAccelerator_End"}, - {"&two &accelerators", 4, 1, "two accelerators", + {"", -1, 0, "", "", "EmptyString"}, + {"&", -1, 0, "", "", "AcceleratorCharOnly"}, + {"no accelerator", -1, 0, "no accelerator", "no accelerator", + "NoAccelerator"}, + {"&one accelerator", 0, 1, "one accelerator", "one accelerator", + "OneAccelerator_Start"}, + {"one &accelerator", 4, 1, "one accelerator", "one accelerator", + "OneAccelerator_Middle"}, + {"one accelerator&", -1, 0, "one accelerator", "one accelerator", + "OneAccelerator_End"}, + {"&two &accelerators", 4, 1, "two accelerators", "two accelerators", "TwoAccelerators_OneAtStart"}, - {"two &accelerators&", 4, 1, "two accelerators", + {"two &accelerators&", 4, 1, "two accelerators", "two accelerators", "TwoAccelerators_OneAtEnd"}, - {"two& &accelerators", 4, 1, "two accelerators", + {"two& &accelerators", 4, 1, "two accelerators", "two accelerators", "TwoAccelerators_SpaceBetween"}, - {"&&escaping", -1, 0, "&escaping", "Escape_Start"}, - {"escap&&ing", -1, 0, "escap&ing", "Escape_Middle"}, - {"escaping&&", -1, 0, "escaping&", "Escape_End"}, - {"&mix&&ed", 0, 1, "mix&ed", "Mixed_EscapeAfterAccelerator"}, - {"&&m&ix&&e&d&", 6, 1, "&mix&ed", "Mixed_MiddleAcceleratorSkipped"}, - {"&&m&&ix&ed&&", 5, 1, "&m&ixed&", "Mixed_OneAccelerator"}, - {"&m&&ix&ed&&", 4, 1, "m&ixed&", "Mixed_InitialAcceleratorSkipped"}, + {"&&escaping", -1, 0, "&escaping", "&escaping", "Escape_Start"}, + {"escap&&ing", -1, 0, "escap&ing", "escap&ing", "Escape_Middle"}, + {"escaping&&", -1, 0, "escaping&", "escaping&", "Escape_End"}, + {"accelerator(&A)", 12, 1, "accelerator(A)", "accelerator", "CJK_Style"}, + {"accelerator(&A)...", 12, 1, "accelerator(A)...", "accelerator...", + "CJK_StyleEllipsis"}, + {"accelerator(paren", -1, 0, "accelerator(paren", "accelerator(paren", + "CJK_OpenParen"}, + {"accelerator(&paren", 12, 1, "accelerator(paren", "accelerator(paren", + "CJK_NoClosingParen"}, + {"accelerator(&paren)", 12, 1, "accelerator(paren)", "accelerator(paren)", + "CJK_LateClosingParen"}, + {"accelerator&paren)", 11, 1, "acceleratorparen)", "acceleratorparen)", + "CJK_NoOpeningParen"}, + {"accelerator(P)", -1, 0, "accelerator(P)", "accelerator(P)", + "CJK_JustParens"}, + {"accelerator(&)", 12, 1, "accelerator()", "accelerator()", + "CJK_MissingAccelerator"}, + {"&mix&&ed", 0, 1, "mix&ed", "mix&ed", "Mixed_EscapeAfterAccelerator"}, + {"&&m&ix&&e&d&", 6, 1, "&mix&ed", "&mix&ed", + "Mixed_MiddleAcceleratorSkipped"}, + {"&&m&&ix&ed&&", 5, 1, "&m&ixed&", "&m&ixed&", "Mixed_OneAccelerator"}, + {"&m&&ix&ed&&", 4, 1, "m&ixed&", "m&ixed&", + "Mixed_InitialAcceleratorSkipped"}, // U+1D49C MATHEMATICAL SCRIPT CAPITAL A, which occupies two |char16|'s. - {"&\U0001D49C", 0, 2, "\U0001D49C", "MultibyteAccelerator_Start"}, - {"Test&\U0001D49Cing", 4, 2, "Test\U0001D49Cing", + {"&\U0001D49C", 0, 2, "\U0001D49C", "\U0001D49C", + "MultibyteAccelerator_Start"}, + {"Test&\U0001D49Cing", 4, 2, "Test\U0001D49Cing", "Test\U0001D49Cing", "MultibyteAccelerator_Middle"}, - {"Test\U0001D49C&ing", 6, 1, "Test\U0001D49Cing", + {"Test\U0001D49C&ing", 6, 1, "Test\U0001D49Cing", "Test\U0001D49Cing", "OneAccelerator_AfterMultibyte"}, - {"Test&\U0001D49C&ing", 6, 1, "Test\U0001D49Cing", + {"Test&\U0001D49C&ing", 6, 1, "Test\U0001D49Cing", "Test\U0001D49Cing", "MultibyteAccelerator_Skipped"}, - {"Test&\U0001D49C&&ing", 4, 2, "Test\U0001D49C&ing", + {"Test&\U0001D49C&&ing", 4, 2, "Test\U0001D49C&ing", "Test\U0001D49C&ing", "MultibyteAccelerator_EscapeAfter"}, {"Test&\U0001D49C&\U0001D49Cing", 6, 2, "Test\U0001D49C\U0001D49Cing", + "Test\U0001D49C\U0001D49Cing", "MultibyteAccelerator_AfterMultibyteAccelerator"}, + {"accelerator(&\U0001D49C)", 12, 2, "accelerator(\U0001D49C)", + "accelerator", "MultibyteAccelerator_CJK"}, }; INSTANTIATE_TEST_SUITE_P( @@ -169,10 +193,14 @@ RemoveAcceleratorCharData data = GetParam(); int accelerated_char_pos; int accelerated_char_span; - base::string16 result = - RemoveAcceleratorChar(base::UTF8ToUTF16(data.input), kAcceleratorChar, - &accelerated_char_pos, &accelerated_char_span); - EXPECT_EQ(result, base::UTF8ToUTF16(data.output)); + base::string16 result_locate_and_strip = LocateAndRemoveAcceleratorChar( + base::UTF8ToUTF16(data.input), &accelerated_char_pos, + &accelerated_char_span); + base::string16 result_full_strip = + RemoveAccelerator(base::UTF8ToUTF16(data.input)); + EXPECT_EQ(result_locate_and_strip, + base::UTF8ToUTF16(data.output_locate_and_strip)); + EXPECT_EQ(result_full_strip, base::UTF8ToUTF16(data.output_full_strip)); EXPECT_EQ(accelerated_char_pos, data.accelerated_char_pos); EXPECT_EQ(accelerated_char_span, data.accelerated_char_span); }
diff --git a/ui/ozone/platform/wayland/host/wayland_window_drag_controller.h b/ui/ozone/platform/wayland/host/wayland_window_drag_controller.h index 94dae03f..997a6fd8 100644 --- a/ui/ozone/platform/wayland/host/wayland_window_drag_controller.h +++ b/ui/ozone/platform/wayland/host/wayland_window_drag_controller.h
@@ -153,8 +153,10 @@ std::unique_ptr<ScopedEventDispatcher> nested_dispatcher_; base::OnceClosure quit_loop_closure_; - // Tells if the current drag event should be processedc. E.g: received through - // wl_data_device::motion wayland event. + // Tells if the current drag event should be processed. Buggy compositors may + // send wl_pointer::motion events, for example, while a DND session is still + // in progress, which leads to issues in window dragging sessions, this flag + // is used to make window drag controller resistant to such scenarios. bool should_process_drag_event_ = false; base::WeakPtrFactory<WaylandWindowDragController> weak_factory_{this};
diff --git a/ui/views/touchui/touch_selection_menu_views.cc b/ui/views/touchui/touch_selection_menu_views.cc index d183819e..24bdead 100644 --- a/ui/views/touchui/touch_selection_menu_views.cc +++ b/ui/views/touchui/touch_selection_menu_views.cc
@@ -147,8 +147,7 @@ LabelButton* TouchSelectionMenuViews::CreateButton( const base::string16& title, Button::PressedCallback callback) { - base::string16 label = - gfx::RemoveAcceleratorChar(title, '&', nullptr, nullptr); + base::string16 label = gfx::RemoveAccelerator(title); auto* button = AddChildView(std::make_unique<LabelButton>( std::move(callback), label, style::CONTEXT_TOUCH_MENU)); constexpr gfx::Size kMenuButtonMinSize = gfx::Size(63, 38);
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc index 3b132d4..a4097553 100644 --- a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc +++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
@@ -421,7 +421,7 @@ Widget::MoveLoopSource source, Widget::MoveLoopEscapeBehavior escape_behavior) { const bool hide_on_escape = - escape_behavior == Widget::MOVE_LOOP_ESCAPE_BEHAVIOR_HIDE; + escape_behavior == Widget::MoveLoopEscapeBehavior::kHide; return message_handler_->RunMoveLoop(drag_offset, hide_on_escape) ? Widget::MOVE_LOOP_SUCCESSFUL : Widget::MOVE_LOOP_CANCELED;
diff --git a/ui/views/widget/desktop_aura/window_move_client_platform.cc b/ui/views/widget/desktop_aura/window_move_client_platform.cc index d561307..252c8d2e 100644 --- a/ui/views/widget/desktop_aura/window_move_client_platform.cc +++ b/ui/views/widget/desktop_aura/window_move_client_platform.cc
@@ -24,7 +24,7 @@ move_source == wm::WindowMoveSource::WINDOW_MOVE_SOURCE_MOUSE ? Widget::MoveLoopSource::kMouse : Widget::MoveLoopSource::kTouch, - Widget::MoveLoopEscapeBehavior::MOVE_LOOP_ESCAPE_BEHAVIOR_HIDE); + Widget::MoveLoopEscapeBehavior::kHide); return move_loop_result == Widget::MOVE_LOOP_SUCCESSFUL ? wm::MOVE_SUCCESSFUL : wm::MOVE_CANCELED;
diff --git a/ui/views/widget/widget.h b/ui/views/widget/widget.h index 97886b7..50f3fb1 100644 --- a/ui/views/widget/widget.h +++ b/ui/views/widget/widget.h
@@ -122,12 +122,12 @@ }; // Behavior when escape is pressed during a move loop. - enum MoveLoopEscapeBehavior { + enum class MoveLoopEscapeBehavior { // Indicates the window should be hidden. - MOVE_LOOP_ESCAPE_BEHAVIOR_HIDE, + kHide, // Indicates the window should not be hidden. - MOVE_LOOP_ESCAPE_BEHAVIOR_DONT_HIDE, + kDontHide, }; // Type of visibility change transition that should animate.