diff --git a/DEPS b/DEPS index cfdcf844..d295bd97 100644 --- a/DEPS +++ b/DEPS
@@ -40,11 +40,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': '1bfece8556cc03b6aa904b2445d2332136bce037', + 'skia_revision': 'd5bee5d50c60eedda697ac305658d3817125e147', # 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': '60d37ab26372b10eef25127e1ae3dd5270f73f68', + 'v8_revision': '539f7ab310f8865090c494b0251c45e7c52ae5f5', # 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. @@ -56,7 +56,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling build tools # and whatever else without interference from each other. - 'buildtools_revision': '104574186c17cd4701857454feba8872e52a7d82', + 'buildtools_revision': '31d4daad5d9af672d4e234570a24f3fd844bb713', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. @@ -64,7 +64,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. - 'pdfium_revision': '8cb884102c17ef0530277126fd8da054d329d065', + 'pdfium_revision': '1d95c68f912102dfda5d6e9ad7ca79411cda5900', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling openmax_dl # and whatever else without interference from each other.
diff --git a/build/config/BUILD.gn b/build/config/BUILD.gn index 882f183..6a1061f 100644 --- a/build/config/BUILD.gn +++ b/build/config/BUILD.gn
@@ -258,6 +258,7 @@ } else if (is_linux) { libs = [ "dl", + "pthread", "rt", ] }
diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn index 95572936..38a6119 100644 --- a/build/config/BUILDCONFIG.gn +++ b/build/config/BUILDCONFIG.gn
@@ -509,7 +509,6 @@ "//build/config:feature_flags", "//build/config/compiler:afdo", "//build/config/compiler:compiler", - "//build/config/compiler:pthread", "//build/config/compiler:clang_stackrealign", "//build/config/compiler:compiler_arm_fpu", "//build/config/compiler:compiler_arm_thumb",
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn index 7eb4fb3f..95996ab 100644 --- a/build/config/compiler/BUILD.gn +++ b/build/config/compiler/BUILD.gn
@@ -421,6 +421,13 @@ cflags += [ "-B$binutils_path" ] } + if (is_linux) { + cflags += [ "-pthread" ] + # Do not use the -pthread ldflag here since it becomes a no-op + # when using -nodefaultlibs, which would cause an unused argument + # error. "-lpthread" is added in //build/config:default_libs. + } + # Clang-specific compiler flags setup. # ------------------------------------ if (is_clang) { @@ -545,16 +552,6 @@ } } -# This is separate from :compiler (and not even a sub-config there) -# so that some targets can remove it from the list with: -# configs -= [ "//build/config/compiler:pthread" ] -config("pthread") { - if (is_linux) { - cflags = [ "-pthread" ] - ldflags = [ "-pthread" ] - } -} - # This provides the basic options to select the target CPU and ABI. # It is factored out of "compiler" so that special cases can use this # without using everything that "compiler" brings in. Options that
diff --git a/build/fuchsia/test_runner.py b/build/fuchsia/test_runner.py index 8df94d23..e7e2b789 100755 --- a/build/fuchsia/test_runner.py +++ b/build/fuchsia/test_runner.py
@@ -124,6 +124,9 @@ if gtest_filter: autorun_file.write(' --gtest_filter=' + gtest_filter) autorun_file.write('\n') + # If shutdown happens too soon after the test completion, log statements from + # the end of the run will be lost, so sleep for a bit before shutting down. + autorun_file.write('sleep 3\n') autorun_file.write('dm poweroff\n') autorun_file.flush() os.chmod(autorun_file.name, 0750) @@ -188,12 +191,17 @@ qemu_path = os.path.join(SDK_ROOT, 'qemu', 'bin', 'qemu-system-x86_64') + if int(os.environ.get('CHROME_HEADLESS', 0)) == 0: + args_for_kvm_and_cpu = ['-enable-kvm', '-cpu', 'host,migratable=no'] + else: + args_for_kvm_and_cpu = ['-cpu', 'Haswell,+smap,-check'] RunAndCheck(args.dry_run, [qemu_path, '-m', '2048', '-nographic', '-net', 'none', '-smp', '4', - '-machine', 'q35', '-kernel', - os.path.join(SDK_ROOT, 'kernel', 'magenta.bin'), - '-cpu', 'Haswell,+smap,-check', '-initrd', bootfs, - '-append', 'TERM=xterm-256color']) + '-machine', 'q35', + '-kernel', os.path.join(SDK_ROOT, 'kernel', 'magenta.bin'), + '-initrd', bootfs, + '-append', 'TERM=xterm-256color kernel.halt_on_panic=true'] + + args_for_kvm_and_cpu) return 0
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java index 9ed4e76..a6f0500 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java
@@ -66,8 +66,10 @@ private static final float WEBVR_DPR = 1.0f; // Fairly arbitrary values that put a good amount of content on the screen without making the // text too small to read. - private static final float DEFAULT_CONTENT_WIDTH = 960f; - private static final float DEFAULT_CONTENT_HEIGHT = 640f; + @VisibleForTesting + public static final float DEFAULT_CONTENT_WIDTH = 960f; + @VisibleForTesting + public static final float DEFAULT_CONTENT_HEIGHT = 640f; // Make full screen 16:9 until we get exact dimensions from playing video. private static final float FULLSCREEN_CONTENT_WIDTH = 1024f;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/VrShellNavigationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/VrShellNavigationTest.java index d6e9154e..69cabcc 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/VrShellNavigationTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/VrShellNavigationTest.java
@@ -27,6 +27,7 @@ import org.chromium.content.browser.ContentViewCore; import org.chromium.content.browser.test.util.DOMUtils; import org.chromium.content_public.browser.WebContents; +import org.chromium.ui.display.DisplayAndroid; import java.util.concurrent.TimeoutException; @@ -260,4 +261,36 @@ assertState(mVrTestRule.getFirstTabWebContents(), Page.PAGE_WEBVR, PresentationMode.NON_PRESENTING, FullscreenMode.NON_FULLSCREENED); } + + /** + * Tests exit presentation transition from WebVR to VrShell + */ + @Test + @CommandLineFlags.Add("enable-webvr") + @MediumTest + public void testExitPresentationWebVrToVrShell() + throws IllegalArgumentException, InterruptedException, TimeoutException { + mVrTestRule.loadUrlAndAwaitInitialization(TEST_PAGE_WEBVR_URL, PAGE_LOAD_TIMEOUT_S); + enterPresentationOrFail(mVrTestRule.getFirstTabCvc()); + + // Validate our size is what we expect. + DisplayAndroid primaryDisplay = + DisplayAndroid.getNonMultiDisplay(mVrTestRule.getActivity()); + float expectedWidth = primaryDisplay.getDisplayWidth(); + float expectedHeight = primaryDisplay.getDisplayHeight(); + Assert.assertTrue(mVrTestRule.pollJavaScriptBoolean( + "screen.width == " + expectedWidth + " && screen.height == " + expectedHeight, + POLL_TIMEOUT_LONG_MS, mVrTestRule.getFirstTabWebContents())); + + // Exit presentation through JavaScript. + mVrTestRule.runJavaScriptOrFail("vrDisplay.exitPresent();", POLL_TIMEOUT_SHORT_MS, + mVrTestRule.getFirstTabWebContents()); + + // Validate our size is what we expect. + expectedWidth = VrShellImpl.DEFAULT_CONTENT_WIDTH; + expectedHeight = VrShellImpl.DEFAULT_CONTENT_HEIGHT; + Assert.assertTrue(mVrTestRule.pollJavaScriptBoolean( + "screen.width == " + expectedWidth + " && screen.height == " + expectedHeight, + POLL_TIMEOUT_LONG_MS, mVrTestRule.getFirstTabWebContents())); + } }
diff --git a/chrome/browser/extensions/extension_install_ui_browsertest.cc b/chrome/browser/extensions/extension_install_ui_browsertest.cc index 8902bd59..3941ca78 100644 --- a/chrome/browser/extensions/extension_install_ui_browsertest.cc +++ b/chrome/browser/extensions/extension_install_ui_browsertest.cc
@@ -26,7 +26,6 @@ #include "content/public/browser/web_contents.h" #include "content/public/test/browser_test_utils.h" #include "extensions/browser/app_sorting.h" -#include "extensions/browser/extension_registry.h" #include "extensions/common/constants.h" using content::WebContents; @@ -35,9 +34,6 @@ class ExtensionInstallUIBrowserTest : public ExtensionBrowserTest { public: - ExtensionInstallUIBrowserTest() {} - ~ExtensionInstallUIBrowserTest() override {} - // Checks that a theme info bar is currently visible and issues an undo to // revert to the previous theme. void VerifyThemeInfoBarAndUndoInstall() { @@ -51,29 +47,18 @@ infobar_service->infobar_at(0)->delegate()->AsConfirmInfoBarDelegate(); ASSERT_TRUE(delegate); delegate->Cancel(); - WaitForThemeChange(); ASSERT_EQ(0U, infobar_service->infobar_count()); } // Install the given theme from the data dir and verify expected name. void InstallThemeAndVerify(const char* theme_name, const std::string& expected_name) { + // If there is already a theme installed, the current theme should be + // disabled and the new one installed + enabled. + int expected_change = GetTheme() ? 0 : 1; const base::FilePath theme_path = test_data_dir_.AppendASCII(theme_name); - const bool theme_exists = GetTheme(); - // Themes install asynchronously so we must check the number of enabled - // extensions after theme install completes. - size_t num_before = extensions::ExtensionRegistry::Get(profile()) - ->enabled_extensions() - .size(); - ASSERT_TRUE(InstallExtensionWithUIAutoConfirm(theme_path, 1, browser())); - WaitForThemeChange(); - size_t num_after = extensions::ExtensionRegistry::Get(profile()) - ->enabled_extensions() - .size(); - // If a theme was already installed, we're just swapping one for another, so - // no change in extension count. - EXPECT_EQ(num_before + (theme_exists ? 0 : 1), num_after); - + ASSERT_TRUE(InstallExtensionWithUIAutoConfirm(theme_path, expected_change, + browser())); const Extension* theme = GetTheme(); ASSERT_TRUE(theme); ASSERT_EQ(theme->name(), expected_name); @@ -82,17 +67,6 @@ const Extension* GetTheme() const { return ThemeServiceFactory::GetThemeForProfile(browser()->profile()); } - - void WaitForThemeChange() { - content::WindowedNotificationObserver theme_change_observer( - chrome::NOTIFICATION_BROWSER_THEME_CHANGED, - content::Source<ThemeService>( - ThemeServiceFactory::GetForProfile(browser()->profile()))); - theme_change_observer.Wait(); - } - - private: - DISALLOW_COPY_AND_ASSIGN(ExtensionInstallUIBrowserTest); }; // Fails on Linux and Windows (http://crbug.com/580907). @@ -101,7 +75,6 @@ // Install theme once and undo to verify we go back to default theme. base::FilePath theme_crx = PackExtension(test_data_dir_.AppendASCII("theme")); ASSERT_TRUE(InstallExtensionWithUIAutoConfirm(theme_crx, 1, browser())); - WaitForThemeChange(); const Extension* theme = GetTheme(); ASSERT_TRUE(theme); std::string theme_id = theme->id(); @@ -110,12 +83,10 @@ // Set the same theme twice and undo to verify we go back to default theme. ASSERT_TRUE(InstallExtensionWithUIAutoConfirm(theme_crx, 0, browser())); - WaitForThemeChange(); theme = GetTheme(); ASSERT_TRUE(theme); ASSERT_EQ(theme_id, theme->id()); ASSERT_TRUE(InstallExtensionWithUIAutoConfirm(theme_crx, 0, browser())); - WaitForThemeChange(); theme = GetTheme(); ASSERT_TRUE(theme); ASSERT_EQ(theme_id, theme->id()); @@ -133,7 +104,7 @@ // Then install second theme. InstallThemeAndVerify("theme2", "snowflake theme"); const Extension* theme2 = GetTheme(); - EXPECT_NE(theme_id, theme2->id()); + EXPECT_FALSE(theme_id == theme2->id()); // Undo second theme will revert to first theme. VerifyThemeInfoBarAndUndoInstall();
diff --git a/chrome/browser/extensions/extension_service_sync_unittest.cc b/chrome/browser/extensions/extension_service_sync_unittest.cc index 8d91faa8..1b810fa 100644 --- a/chrome/browser/extensions/extension_service_sync_unittest.cc +++ b/chrome/browser/extensions/extension_service_sync_unittest.cc
@@ -18,7 +18,6 @@ #include "base/metrics/field_trial.h" #include "base/test/mock_entropy_provider.h" #include "base/test/scoped_feature_list.h" -#include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/extensions/api/webstore_private/webstore_private_api.h" #include "chrome/browser/extensions/component_loader.h" #include "chrome/browser/extensions/extension_service.h" @@ -29,8 +28,6 @@ #include "chrome/browser/extensions/scripting_permissions_modifier.h" #include "chrome/browser/extensions/updater/extension_updater.h" #include "chrome/browser/sync/profile_sync_service_factory.h" -#include "chrome/browser/themes/theme_service.h" -#include "chrome/browser/themes/theme_service_factory.h" #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/extensions/sync_helper.h" @@ -1566,11 +1563,6 @@ // Installing a theme should not result in a sync change (themes are handled // separately by ThemeSyncableService). InstallCRX(data_dir().AppendASCII("theme.crx"), INSTALL_NEW); - content::WindowedNotificationObserver theme_change_observer( - chrome::NOTIFICATION_BROWSER_THEME_CHANGED, - content::Source<ThemeService>( - ThemeServiceFactory::GetForProfile(profile()))); - theme_change_observer.Wait(); EXPECT_TRUE(processor->changes().empty()); }
diff --git a/chrome/browser/extensions/theme_installed_infobar_delegate.cc b/chrome/browser/extensions/theme_installed_infobar_delegate.cc index e432bbdc..16d349d 100644 --- a/chrome/browser/extensions/theme_installed_infobar_delegate.cc +++ b/chrome/browser/extensions/theme_installed_infobar_delegate.cc
@@ -144,9 +144,7 @@ const extensions::Extension* previous_theme = extension_service_->GetExtensionById(previous_theme_id_, true); if (previous_theme) { - theme_service_->RevertToTheme(previous_theme); - // TODO(estade): while we're waiting to close, it would be nice to - // indicate that the theme is busy reverting. + theme_service_->SetTheme(previous_theme); return false; // The theme change will close us. } }
diff --git a/chrome/browser/infobars/infobars_browsertest.cc b/chrome/browser/infobars/infobars_browsertest.cc index a887674..090f91b 100644 --- a/chrome/browser/infobars/infobars_browsertest.cc +++ b/chrome/browser/infobars/infobars_browsertest.cc
@@ -76,8 +76,8 @@ chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED, content::NotificationService::AllSources()); InstallExtension("theme2.crx"); - infobar_removed_1.Wait(); infobar_added_2.Wait(); + infobar_removed_1.Wait(); EXPECT_EQ( 0u, InfoBarService::FromWebContents(
diff --git a/chrome/browser/resources/chromeos/login/encryption_migration.html b/chrome/browser/resources/chromeos/login/encryption_migration.html index 99b35ad..14afc2a 100644 --- a/chrome/browser/resources/chromeos/login/encryption_migration.html +++ b/chrome/browser/resources/chromeos/login/encryption_migration.html
@@ -90,7 +90,7 @@ <div>$i18n{migrationButtonReportAnIssue}</div> </oobe-text-button> </if> - <oobe-text-button inverse on-tap="onRestart_"> + <oobe-text-button inverse on-tap="onRestartOnFailure_"> <div>$i18n{migrationButtonRestart}</div> </oobe-text-button> </div> @@ -117,7 +117,7 @@ </oobe-text-button> </template> <template is="dom-if" if="[[isResuming]]"> - <oobe-text-button inverse on-tap="onRestart_"> + <oobe-text-button inverse on-tap="onRestartOnLowStorage_"> <div>$i18n{migrationButtonRestart}</div> </oobe-text-button> </template>
diff --git a/chrome/browser/resources/chromeos/login/encryption_migration.js b/chrome/browser/resources/chromeos/login/encryption_migration.js index 5a99b34b..c166910 100644 --- a/chrome/browser/resources/chromeos/login/encryption_migration.js +++ b/chrome/browser/resources/chromeos/login/encryption_migration.js
@@ -216,8 +216,16 @@ * Handles tap on RESTART button. * @private */ - onRestart_: function() { - this.fire('restart'); + onRestartOnLowStorage_: function() { + this.fire('restart-on-low-storage'); + }, + + /** + * Handles tap on RESTART button on the migration failure screen. + * @private + */ + onRestartOnFailure_: function() { + this.fire('restart-on-failure'); }, /**
diff --git a/chrome/browser/resources/chromeos/login/screen_encryption_migration.js b/chrome/browser/resources/chromeos/login/screen_encryption_migration.js index 6163d1e..c6b5415 100644 --- a/chrome/browser/resources/chromeos/login/screen_encryption_migration.js +++ b/chrome/browser/resources/chromeos/login/screen_encryption_migration.js
@@ -28,8 +28,12 @@ encryptionMigration.addEventListener('skip', function() { chrome.send('skipMigration'); }); - encryptionMigration.addEventListener('restart', function() { - chrome.send('requestRestart'); + encryptionMigration.addEventListener( + 'restart-on-low-storage', function() { + chrome.send('requestRestartOnLowStorage'); + }); + encryptionMigration.addEventListener('restart-on-failure', function() { + chrome.send('requestRestartOnFailure'); }); encryptionMigration.addEventListener('openFeedbackDialog', function() { chrome.send('openFeedbackDialog');
diff --git a/chrome/browser/resources/md_bookmarks/OWNERS b/chrome/browser/resources/md_bookmarks/OWNERS index d0663e0..b02ce2c 100644 --- a/chrome/browser/resources/md_bookmarks/OWNERS +++ b/chrome/browser/resources/md_bookmarks/OWNERS
@@ -1,5 +1,4 @@ calamity@chromium.org -dbeam@chromium.org tsergeant@chromium.org # COMPONENT: UI>Browser>Bookmarks
diff --git a/chrome/browser/sync/test/integration/single_client_themes_sync_test.cc b/chrome/browser/sync/test/integration/single_client_themes_sync_test.cc index fa5b140d..ce5099f 100644 --- a/chrome/browser/sync/test/integration/single_client_themes_sync_test.cc +++ b/chrome/browser/sync/test/integration/single_client_themes_sync_test.cc
@@ -4,25 +4,20 @@ #include "base/macros.h" #include "build/build_config.h" -#include "chrome/browser/chrome_notification_types.h" -#include "chrome/browser/sync/test/integration/sync_integration_test_util.h" #include "chrome/browser/sync/test/integration/sync_test.h" #include "chrome/browser/sync/test/integration/themes_helper.h" #include "chrome/browser/sync/test/integration/updated_progress_marker_checker.h" -#include "chrome/browser/themes/theme_service_factory.h" #include "components/browser_sync/profile_sync_service.h" -#include "content/public/test/test_utils.h" using themes_helper::GetCustomTheme; using themes_helper::GetThemeID; +using themes_helper::UseCustomTheme; using themes_helper::UseDefaultTheme; using themes_helper::UseSystemTheme; using themes_helper::UsingCustomTheme; using themes_helper::UsingDefaultTheme; using themes_helper::UsingSystemTheme; -namespace { - class SingleClientThemesSyncTest : public SyncTest { public: SingleClientThemesSyncTest() : SyncTest(SINGLE_CLIENT) {} @@ -39,18 +34,18 @@ IN_PROC_BROWSER_TEST_F(SingleClientThemesSyncTest, CustomTheme) { ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; - EXPECT_FALSE(UsingCustomTheme(GetProfile(0))); - EXPECT_FALSE(UsingCustomTheme(verifier())); + ASSERT_FALSE(UsingCustomTheme(GetProfile(0))); + ASSERT_FALSE(UsingCustomTheme(verifier())); - SetCustomTheme(GetProfile(0)); - SetCustomTheme(verifier()); - EXPECT_EQ(GetCustomTheme(0), GetThemeID(GetProfile(0))); - EXPECT_EQ(GetCustomTheme(0), GetThemeID(verifier())); + UseCustomTheme(GetProfile(0), 0); + UseCustomTheme(verifier(), 0); + ASSERT_EQ(GetCustomTheme(0), GetThemeID(GetProfile(0))); + ASSERT_EQ(GetCustomTheme(0), GetThemeID(verifier())); - EXPECT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait()); + ASSERT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait()); - EXPECT_EQ(GetCustomTheme(0), GetThemeID(GetProfile(0))); - EXPECT_EQ(GetCustomTheme(0), GetThemeID(verifier())); + ASSERT_EQ(GetCustomTheme(0), GetThemeID(GetProfile(0))); + ASSERT_EQ(GetCustomTheme(0), GetThemeID(verifier())); } // TODO(sync): Fails on Chrome OS. See http://crbug.com/84575. @@ -61,43 +56,41 @@ #endif // OS_CHROMEOS ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; - SetCustomTheme(GetProfile(0)); - SetCustomTheme(verifier()); - EXPECT_FALSE(UsingSystemTheme(GetProfile(0))); - EXPECT_FALSE(UsingSystemTheme(verifier())); + UseCustomTheme(GetProfile(0), 0); + UseCustomTheme(verifier(), 0); + ASSERT_FALSE(UsingSystemTheme(GetProfile(0))); + ASSERT_FALSE(UsingSystemTheme(verifier())); - EXPECT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait()); + ASSERT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait()); UseSystemTheme(GetProfile(0)); UseSystemTheme(verifier()); - EXPECT_TRUE(UsingSystemTheme(GetProfile(0))); - EXPECT_TRUE(UsingSystemTheme(verifier())); + ASSERT_TRUE(UsingSystemTheme(GetProfile(0))); + ASSERT_TRUE(UsingSystemTheme(verifier())); - EXPECT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait()); + ASSERT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait()); - EXPECT_TRUE(UsingSystemTheme(GetProfile(0))); - EXPECT_TRUE(UsingSystemTheme(verifier())); + ASSERT_TRUE(UsingSystemTheme(GetProfile(0))); + ASSERT_TRUE(UsingSystemTheme(verifier())); } IN_PROC_BROWSER_TEST_F(SingleClientThemesSyncTest, DefaultTheme) { ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; - SetCustomTheme(GetProfile(0)); - EXPECT_FALSE(UsingDefaultTheme(GetProfile(0))); + UseCustomTheme(GetProfile(0), 0); + UseCustomTheme(verifier(), 0); + ASSERT_FALSE(UsingDefaultTheme(GetProfile(0))); + ASSERT_FALSE(UsingDefaultTheme(verifier())); - SetCustomTheme(verifier()); - EXPECT_FALSE(UsingDefaultTheme(verifier())); + ASSERT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait()); - EXPECT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait()); UseDefaultTheme(GetProfile(0)); - EXPECT_TRUE(UsingDefaultTheme(GetProfile(0))); UseDefaultTheme(verifier()); - EXPECT_TRUE(UsingDefaultTheme(verifier())); + ASSERT_TRUE(UsingDefaultTheme(GetProfile(0))); + ASSERT_TRUE(UsingDefaultTheme(verifier())); - EXPECT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait()); + ASSERT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait()); - EXPECT_TRUE(UsingDefaultTheme(GetProfile(0))); - EXPECT_TRUE(UsingDefaultTheme(verifier())); + ASSERT_TRUE(UsingDefaultTheme(GetProfile(0))); + ASSERT_TRUE(UsingDefaultTheme(verifier())); } - -} // namespace
diff --git a/chrome/browser/sync/test/integration/sync_integration_test_util.cc b/chrome/browser/sync/test/integration/sync_integration_test_util.cc index d9afa063..42ef3e24 100644 --- a/chrome/browser/sync/test/integration/sync_integration_test_util.cc +++ b/chrome/browser/sync/test/integration/sync_integration_test_util.cc
@@ -5,20 +5,7 @@ #include "chrome/browser/sync/test/integration/sync_integration_test_util.h" #include "base/strings/stringprintf.h" -#include "chrome/browser/chrome_notification_types.h" -#include "chrome/browser/sync/test/integration/themes_helper.h" -#include "chrome/browser/themes/theme_service_factory.h" #include "components/browser_sync/profile_sync_service.h" -#include "content/public/test/test_utils.h" - -void SetCustomTheme(Profile* profile, int theme_index) { - themes_helper::UseCustomTheme(profile, theme_index); - content::WindowedNotificationObserver theme_change_observer( - chrome::NOTIFICATION_BROWSER_THEME_CHANGED, - content::Source<ThemeService>( - ThemeServiceFactory::GetForProfile(profile))); - theme_change_observer.Wait(); -} ServerCountMatchStatusChecker::ServerCountMatchStatusChecker( syncer::ModelType type,
diff --git a/chrome/browser/sync/test/integration/sync_integration_test_util.h b/chrome/browser/sync/test/integration/sync_integration_test_util.h index 63df4c9..c3af2d7 100644 --- a/chrome/browser/sync/test/integration/sync_integration_test_util.h +++ b/chrome/browser/sync/test/integration/sync_integration_test_util.h
@@ -11,15 +11,10 @@ #include "chrome/browser/sync/test/integration/single_client_status_change_checker.h" #include "components/sync/base/model_type.h" -class Profile; - namespace browser_sync { class ProfileSyncService; } // namespace browser_sync -// Sets a custom theme and wait until the asynchronous process is done. -void SetCustomTheme(Profile* profile, int theme_index = 0); - // Checker to block until the server has a given number of entities. class ServerCountMatchStatusChecker : public fake_server::FakeServerMatchStatusChecker {
diff --git a/chrome/browser/sync/test/integration/two_client_themes_sync_test.cc b/chrome/browser/sync/test/integration/two_client_themes_sync_test.cc index 68beb142..530f209 100644 --- a/chrome/browser/sync/test/integration/two_client_themes_sync_test.cc +++ b/chrome/browser/sync/test/integration/two_client_themes_sync_test.cc
@@ -38,7 +38,7 @@ ASSERT_FALSE(UsingCustomTheme(GetProfile(0))); ASSERT_FALSE(UsingCustomTheme(GetProfile(1))); - SetCustomTheme(GetProfile(0)); + UseCustomTheme(GetProfile(0), 0); ASSERT_EQ(GetCustomTheme(0), GetThemeID(GetProfile(0))); // TODO(sync): Add functions to simulate when a pending extension @@ -57,8 +57,8 @@ E2E_ENABLED(CustomThenSyncNative)) { ASSERT_TRUE(SetupClients()); - SetCustomTheme(GetProfile(0)); - SetCustomTheme(GetProfile(1)); + UseCustomTheme(GetProfile(0), 0); + UseCustomTheme(GetProfile(1), 0); ASSERT_TRUE(SetupSync()); @@ -77,8 +77,8 @@ E2E_ENABLED(CustomThenSyncDefault)) { ASSERT_TRUE(SetupClients()); - SetCustomTheme(GetProfile(0)); - SetCustomTheme(GetProfile(1)); + UseCustomTheme(GetProfile(0), 0); + UseCustomTheme(GetProfile(1), 0); ASSERT_TRUE(SetupSync()); @@ -97,7 +97,7 @@ IN_PROC_BROWSER_TEST_F(TwoClientThemesSyncTest, E2E_ENABLED(CycleOptions)) { ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; - SetCustomTheme(GetProfile(0)); + UseCustomTheme(GetProfile(0), 0); ASSERT_TRUE( ThemePendingInstallChecker(GetProfile(1), GetCustomTheme(0)).Wait()); @@ -115,7 +115,7 @@ EXPECT_TRUE(UsingDefaultTheme(GetProfile(0))); EXPECT_TRUE(UsingDefaultTheme(GetProfile(1))); - SetCustomTheme(GetProfile(0), 1); + UseCustomTheme(GetProfile(0), 1); ASSERT_TRUE( ThemePendingInstallChecker(GetProfile(1), GetCustomTheme(1)).Wait()); EXPECT_EQ(GetCustomTheme(1), GetThemeID(GetProfile(0)));
diff --git a/chrome/browser/themes/browser_theme_pack.cc b/chrome/browser/themes/browser_theme_pack.cc index 4f3da008..a352c67 100644 --- a/chrome/browser/themes/browser_theme_pack.cc +++ b/chrome/browser/themes/browser_theme_pack.cc
@@ -546,13 +546,13 @@ } // static -void BrowserThemePack::BuildFromExtension( - const extensions::Extension* extension, - scoped_refptr<BrowserThemePack> pack) { +scoped_refptr<BrowserThemePack> BrowserThemePack::BuildFromExtension( + const Extension* extension) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK(extension); DCHECK(extension->is_theme()); - DCHECK(!pack->is_valid()); + scoped_refptr<BrowserThemePack> pack(new BrowserThemePack); pack->BuildHeader(extension); pack->BuildTintsFromJSON(extensions::ThemeInfo::GetTints(extension)); pack->BuildColorsFromJSON(extensions::ThemeInfo::GetColors(extension)); @@ -567,14 +567,14 @@ &file_paths); pack->BuildSourceImagesArray(file_paths); - if (!pack->LoadRawBitmapsTo(file_paths, &pack->images_)) - return; + if (!pack->LoadRawBitmapsTo(file_paths, &pack->images_on_ui_thread_)) + return NULL; - pack->CreateImages(&pack->images_); + pack->CreateImages(&pack->images_on_ui_thread_); // Make sure the |images_on_file_thread_| has bitmaps for supported // scale factors before passing to FILE thread. - pack->images_on_file_thread_ = pack->images_; + pack->images_on_file_thread_ = pack->images_on_ui_thread_; for (ImageCache::iterator it = pack->images_on_file_thread_.begin(); it != pack->images_on_file_thread_.end(); ++it) { gfx::ImageSkia* image_skia = @@ -582,13 +582,13 @@ image_skia->MakeThreadSafe(); } - // Set ThemeImageSource on |images_| to resample the source + // Set ThemeImageSource on |images_on_ui_thread_| to resample the source // image if a caller of BrowserThemePack::GetImageNamed() requests an // ImageSkiaRep for a scale factor not specified by the theme author. // Callers of BrowserThemePack::GetImageNamed() to be able to retrieve // ImageSkiaReps for all supported scale factors. - for (ImageCache::iterator it = pack->images_.begin(); - it != pack->images_.end(); ++it) { + for (ImageCache::iterator it = pack->images_on_ui_thread_.begin(); + it != pack->images_on_ui_thread_.end(); ++it) { const gfx::ImageSkia source_image_skia = it->second.AsImageSkia(); ThemeImageSource* source = new ThemeImageSource(source_image_skia); // image_skia takes ownership of source. @@ -603,7 +603,7 @@ } // The BrowserThemePack is now in a consistent state. - pack->is_valid_ = true; + return pack; } // static @@ -671,7 +671,6 @@ << "from those supported by platform."; return NULL; } - pack->is_valid_ = true; return pack; } @@ -684,13 +683,6 @@ return false; } -BrowserThemePack::BrowserThemePack() : CustomThemeSupplier(EXTENSION) { - scale_factors_ = ui::GetSupportedScaleFactors(); - // On Windows HiDPI SCALE_FACTOR_100P may not be supported by default. - if (!base::ContainsValue(scale_factors_, ui::SCALE_FACTOR_100P)) - scale_factors_.push_back(ui::SCALE_FACTOR_100P); -} - bool BrowserThemePack::WriteToDisk(const base::FilePath& path) const { // Add resources for each of the property arrays. RawDataForWriting resources; @@ -779,8 +771,8 @@ return gfx::Image(); // Check if the image is cached. - ImageCache::const_iterator image_iter = images_.find(prs_id); - if (image_iter != images_.end()) + ImageCache::const_iterator image_iter = images_on_ui_thread_.find(prs_id); + if (image_iter != images_on_ui_thread_.end()) return image_iter->second; ThemeImagePngSource::PngMap png_map; @@ -794,7 +786,7 @@ gfx::ImageSkia image_skia(new ThemeImagePngSource(png_map), 1.0f); // |image_skia| takes ownership of ThemeImagePngSource. gfx::Image ret = gfx::Image(image_skia); - images_[prs_id] = ret; + images_on_ui_thread_[prs_id] = ret; return ret; } @@ -838,6 +830,19 @@ // private: +BrowserThemePack::BrowserThemePack() + : CustomThemeSupplier(EXTENSION), + header_(NULL), + tints_(NULL), + colors_(NULL), + display_properties_(NULL), + source_images_(NULL) { + scale_factors_ = ui::GetSupportedScaleFactors(); + // On Windows HiDPI SCALE_FACTOR_100P may not be supported by default. + if (!base::ContainsValue(scale_factors_, ui::SCALE_FACTOR_100P)) + scale_factors_.push_back(ui::SCALE_FACTOR_100P); +} + void BrowserThemePack::BuildHeader(const Extension* extension) { header_ = new BrowserThemePackHeader; header_->version = kThemePackVersion;
diff --git a/chrome/browser/themes/browser_theme_pack.h b/chrome/browser/themes/browser_theme_pack.h index d527e973..cc975cc 100644 --- a/chrome/browser/themes/browser_theme_pack.h +++ b/chrome/browser/themes/browser_theme_pack.h
@@ -53,11 +53,11 @@ // will trip our IO on the UI thread detector. class BrowserThemePack : public CustomThemeSupplier { public: - // Builds the theme from |extension| into |pack|. This may be done on a - // separate thread as it takes so long. This can fail in the case where the - // theme has invalid data, in which case |pack->is_valid()| will be false. - static void BuildFromExtension(const extensions::Extension* extension, - scoped_refptr<BrowserThemePack> pack); + // Builds the theme pack from all data from |extension|. This is often done + // on a separate thread as it takes so long. This can fail and return NULL in + // the case where the theme has invalid data. + static scoped_refptr<BrowserThemePack> BuildFromExtension( + const extensions::Extension* extension); // Builds the theme pack from a previously performed WriteToDisk(). This // operation should be relatively fast, as it should be an mmap() and some @@ -69,11 +69,6 @@ // in the data pack. static bool IsPersistentImageID(int id); - // Default. Everything is empty. - BrowserThemePack(); - - bool is_valid() const { return is_valid_; } - // Builds a data pack on disk at |path| for future quick loading by // BuildFromDataPack(). Often (but not always) called from the file thread; // implementation should be threadsafe because neither thread will write to @@ -108,6 +103,9 @@ // Maps image ids to maps of scale factors to file paths. typedef std::map<int, ScaleFactorToFileMap> FilePathMap; + // Default. Everything is empty. + BrowserThemePack(); + ~BrowserThemePack() override; // Builds a header ready to write to disk. @@ -219,7 +217,7 @@ // theme_id without NULL terminator. uint8_t theme_id[16]; - }* header_ = nullptr; + } *header_; // The remaining structs represent individual entries in an array. For the // following three structs, BrowserThemePack will either allocate an array or @@ -229,21 +227,21 @@ double h; double s; double l; - }* tints_ = nullptr; + } *tints_; struct ColorPair { int32_t id; SkColor color; - }* colors_ = nullptr; + } *colors_; struct DisplayPropertyPair { int32_t id; int32_t property; - }* display_properties_ = nullptr; + } *display_properties_; // A list of included source images. A pointer to a -1 terminated array of // our persistent IDs. - int* source_images_ = nullptr; + int* source_images_; #pragma pack(pop) // The scale factors represented by the images in the theme pack. @@ -256,8 +254,9 @@ RawImages image_memory_; // Loaded images. These are loaded from |image_memory_|, from |data_pack_|, - // and by BuildFromExtension(). - ImageCache images_; + // and by BuildFromExtension(). These images should only be accessed on the UI + // thread. + ImageCache images_on_ui_thread_; // Cache of images created in BuildFromExtension(). Once the theme pack is // created, this cache should only be accessed on the file thread. There @@ -265,10 +264,6 @@ // or vice versa. ImageCache images_on_file_thread_; - // Whether the theme pack has been succesfully initialized and is ready to - // use. - bool is_valid_ = false; - DISALLOW_COPY_AND_ASSIGN(BrowserThemePack); };
diff --git a/chrome/browser/themes/browser_theme_pack_unittest.cc b/chrome/browser/themes/browser_theme_pack_unittest.cc index 22e9d2f..1180081 100644 --- a/chrome/browser/themes/browser_theme_pack_unittest.cc +++ b/chrome/browser/themes/browser_theme_pack_unittest.cc
@@ -10,7 +10,6 @@ #include "base/json/json_file_value_serializer.h" #include "base/json/json_reader.h" #include "base/path_service.h" -#include "base/synchronization/waitable_event.h" #include "base/values.h" #include "build/build_config.h" #include "chrome/browser/themes/theme_properties.h" @@ -35,16 +34,14 @@ class BrowserThemePackTest : public ::testing::Test { public: - BrowserThemePackTest() - : thread_bundle_(content::TestBrowserThreadBundle::REAL_IO_THREAD), - theme_pack_(new BrowserThemePack()) { + BrowserThemePackTest() { std::vector<ui::ScaleFactor> scale_factors; scale_factors.push_back(ui::SCALE_FACTOR_100P); scale_factors.push_back(ui::SCALE_FACTOR_200P); scoped_set_supported_scale_factors_.reset( - new ui::test::ScopedSetSupportedScaleFactors(scale_factors)); + new ui::test::ScopedSetSupportedScaleFactors(scale_factors)); + theme_pack_ = new BrowserThemePack(); } - ~BrowserThemePackTest() override {} // Transformation for link underline colors. SkColor BuildThirdOpacity(SkColor color_link) { @@ -145,22 +142,33 @@ } bool LoadRawBitmapsTo(const TestFilePathMap& out_file_paths) { - return theme_pack_->LoadRawBitmapsTo(out_file_paths, &theme_pack_->images_); + return theme_pack_->LoadRawBitmapsTo(out_file_paths, + &theme_pack_->images_on_ui_thread_); } // This function returns void in order to be able use ASSERT_... // The BrowserThemePack is returned in |pack|. void BuildFromUnpackedExtension(const base::FilePath& extension_path, - scoped_refptr<BrowserThemePack>* pack) { - io_waiter_.reset(new base::WaitableEvent( - base::WaitableEvent::ResetPolicy::AUTOMATIC, - base::WaitableEvent::InitialState::NOT_SIGNALED)); - content::BrowserThread::PostTask( - content::BrowserThread::IO, FROM_HERE, - base::Bind(&BrowserThemePackTest::DoBuildFromUnpackedExtension, - base::Unretained(this), extension_path, pack)); - io_waiter_->Wait(); - ASSERT_TRUE((*pack)->is_valid()); + scoped_refptr<BrowserThemePack>& pack) { + base::FilePath manifest_path = + extension_path.AppendASCII("manifest.json"); + std::string error; + JSONFileValueDeserializer deserializer(manifest_path); + std::unique_ptr<base::DictionaryValue> valid_value = + base::DictionaryValue::From(deserializer.Deserialize(NULL, &error)); + EXPECT_EQ("", error); + ASSERT_TRUE(valid_value.get()); + scoped_refptr<Extension> extension( + Extension::Create( + extension_path, + extensions::Manifest::INVALID_LOCATION, + *valid_value, + Extension::REQUIRE_KEY, + &error)); + ASSERT_TRUE(extension.get()); + ASSERT_EQ("", error); + pack = BrowserThemePack::BuildFromExtension(extension.get()); + ASSERT_TRUE(pack.get()); } base::FilePath GetStarGazingPath() { @@ -339,33 +347,12 @@ } } - protected: + content::TestBrowserThreadBundle test_browser_thread_bundle_; + typedef std::unique_ptr<ui::test::ScopedSetSupportedScaleFactors> ScopedSetSupportedScaleFactors; ScopedSetSupportedScaleFactors scoped_set_supported_scale_factors_; - - void DoBuildFromUnpackedExtension(const base::FilePath& extension_path, - scoped_refptr<BrowserThemePack>* pack) { - base::FilePath manifest_path = extension_path.AppendASCII("manifest.json"); - std::string error; - JSONFileValueDeserializer deserializer(manifest_path); - std::unique_ptr<base::DictionaryValue> valid_value = - base::DictionaryValue::From(deserializer.Deserialize(NULL, &error)); - EXPECT_EQ("", error); - ASSERT_TRUE(valid_value.get()); - scoped_refptr<Extension> extension(Extension::Create( - extension_path, extensions::Manifest::INVALID_LOCATION, *valid_value, - Extension::REQUIRE_KEY, &error)); - ASSERT_TRUE(extension.get()); - ASSERT_EQ("", error); - *pack = new BrowserThemePack; - BrowserThemePack::BuildFromExtension(extension.get(), *pack); - io_waiter_->Signal(); - } - - content::TestBrowserThreadBundle thread_bundle_; scoped_refptr<BrowserThemePack> theme_pack_; - std::unique_ptr<base::WaitableEvent> io_waiter_; }; // 'ntp_section' used to correspond to ThemeProperties::COLOR_NTP_SECTION, @@ -582,7 +569,7 @@ { base::FilePath star_gazing_path = GetStarGazingPath(); scoped_refptr<BrowserThemePack> pack; - BuildFromUnpackedExtension(star_gazing_path, &pack); + BuildFromUnpackedExtension(star_gazing_path, pack); ASSERT_TRUE(pack->WriteToDisk(file)); VerifyStarGazing(pack.get()); } @@ -606,7 +593,7 @@ { base::FilePath hidpi_path = GetHiDpiThemePath(); scoped_refptr<BrowserThemePack> pack; - BuildFromUnpackedExtension(hidpi_path, &pack); + BuildFromUnpackedExtension(hidpi_path, pack); ASSERT_TRUE(pack->WriteToDisk(file)); VerifyHiDpiTheme(pack.get()); }
diff --git a/chrome/browser/themes/theme_service.cc b/chrome/browser/themes/theme_service.cc index 34cd105..6a9d0e1 100644 --- a/chrome/browser/themes/theme_service.cc +++ b/chrome/browser/themes/theme_service.cc
@@ -17,12 +17,10 @@ #include "base/single_thread_task_runner.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" -#include "base/task_scheduler/post_task.h" #include "base/threading/thread_task_runner_handle.h" #include "build/build_config.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/extensions/extension_service.h" -#include "chrome/browser/extensions/theme_installed_infobar_delegate.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/themes/browser_theme_pack.h" #include "chrome/browser/themes/custom_theme_supplier.h" @@ -264,7 +262,7 @@ case extensions::NOTIFICATION_EXTENSION_ENABLED: { const Extension* extension = Details<const Extension>(details).ptr(); if (extension->is_theme()) - DoSetTheme(extension, true); + SetTheme(extension); break; } default: @@ -273,18 +271,40 @@ } void ThemeService::SetTheme(const Extension* extension) { - DoSetTheme(extension, false); -} - -void ThemeService::RevertToTheme(const Extension* extension) { DCHECK(extension->is_theme()); ExtensionService* service = extensions::ExtensionSystem::Get(profile_)->extension_service(); - DCHECK(!service->IsExtensionEnabled(extension->id())); - // |extension| is disabled when reverting to the previous theme via an - // infobar. - service->EnableExtension(extension->id()); - // Enabling the extension will call back to SetTheme(). + if (!service->IsExtensionEnabled(extension->id())) { + // |extension| is disabled when reverting to the previous theme via an + // infobar. + service->EnableExtension(extension->id()); + // Enabling the extension will call back to SetTheme(). + return; + } + + std::string previous_theme_id = GetThemeID(); + + // Clear our image cache. + FreePlatformCaches(); + + BuildFromExtension(extension); + SaveThemeID(extension->id()); + + NotifyThemeChanged(); + base::RecordAction(UserMetricsAction("Themes_Installed")); + + if (previous_theme_id != kDefaultThemeID && + previous_theme_id != extension->id() && + service->GetInstalledExtension(previous_theme_id)) { + // Do not disable the previous theme if it is already uninstalled. Sending + // NOTIFICATION_BROWSER_THEME_CHANGED causes the previous theme to be + // uninstalled when the notification causes the remaining infobar to close + // and does not open any new infobars. See crbug.com/468280. + + // Disable the old theme. + service->DisableExtension(previous_theme_id, + extensions::Extension::DISABLE_USER_ACTION); + } } void ThemeService::UseDefaultTheme() { @@ -329,10 +349,8 @@ void ThemeService::OnInfobarDestroyed() { number_of_infobars_--; - if (number_of_infobars_ == 0 && - !build_extension_task_tracker_.HasTrackedTasks()) { + if (number_of_infobars_ == 0) RemoveUnusedThemes(false); - } } void ThemeService::RemoveUnusedThemes(bool ignore_infobars) { @@ -357,8 +375,8 @@ for (extensions::ExtensionSet::const_iterator it = extensions->begin(); it != extensions->end(); ++it) { const extensions::Extension* extension = it->get(); - if (extension->is_theme() && extension->id() != current_theme && - extension->id() != building_extension_id_) { + if (extension->is_theme() && + extension->id() != current_theme) { // Only uninstall themes which are not disabled or are disabled with // reason DISABLE_USER_ACTION. We cannot blanket uninstall all disabled // themes because externally installed themes are initially disabled. @@ -560,7 +578,7 @@ // If we don't have a file pack, we're updating from an old version. base::FilePath path = prefs->GetFilePath(prefs::kCurrentThemePackFilename); - if (!path.empty()) { + if (path != base::FilePath()) { path = path.Append(chrome::kThemePackFilename); SwapThemeSupplier(BrowserThemePack::BuildFromDataPack(path, current_id)); if (theme_supplier_) @@ -667,15 +685,6 @@ return SkColorSetA(separator_color, alpha); } -void ThemeService::DoSetTheme(const Extension* extension, - bool suppress_infobar) { - DCHECK(extension->is_theme()); - DCHECK(extensions::ExtensionSystem::Get(profile_) - ->extension_service() - ->IsExtensionEnabled(extension->id())); - BuildFromExtension(extension, suppress_infobar); -} - gfx::ImageSkia* ThemeService::GetImageSkiaNamed(int id, bool incognito) const { gfx::Image image = GetImageNamed(id, incognito); if (image.IsEmpty()) @@ -776,6 +785,10 @@ // be recreated from the extension. MigrateTheme(); set_ready(); + + // Send notification in case anyone requested data and cached it when the + // theme service was not ready yet. + NotifyThemeChanged(); } #if BUILDFLAG(ENABLE_EXTENSIONS) @@ -793,18 +806,15 @@ } void ThemeService::MigrateTheme() { + // TODO(erg): We need to pop up a dialog informing the user that their + // theme is being migrated. ExtensionService* service = extensions::ExtensionSystem::Get(profile_)->extension_service(); const Extension* extension = service ? service->GetExtensionById(GetThemeID(), false) : nullptr; if (extension) { DLOG(ERROR) << "Migrating theme"; - // Theme migration is done on the UI thread. Blocking the UI from appearing - // until it's ready is deemed better than showing a blip of the default - // theme. - scoped_refptr<BrowserThemePack> pack(new BrowserThemePack); - BrowserThemePack::BuildFromExtension(extension, pack); - OnThemeBuiltFromExtension(extension->id(), pack, true); + BuildFromExtension(extension); base::RecordAction(UserMetricsAction("Themes.Migrated")); } else { DLOG(ERROR) << "Theme is mysteriously gone."; @@ -831,26 +841,10 @@ profile_->GetPrefs()->SetString(prefs::kCurrentThemeID, id); } -void ThemeService::BuildFromExtension(const Extension* extension, - bool suppress_infobar) { - build_extension_task_tracker_.TryCancelAll(); - building_extension_id_ = extension->id(); - scoped_refptr<BrowserThemePack> pack(new BrowserThemePack); - auto task_runner = base::CreateTaskRunnerWithTraits( - {base::MayBlock(), base::TaskPriority::USER_BLOCKING}); - build_extension_task_tracker_.PostTaskAndReply( - task_runner.get(), FROM_HERE, - base::Bind(&BrowserThemePack::BuildFromExtension, extension, pack), - base::Bind(&ThemeService::OnThemeBuiltFromExtension, - weak_ptr_factory_.GetWeakPtr(), extension->id(), pack, - suppress_infobar)); -} - -void ThemeService::OnThemeBuiltFromExtension( - const extensions::ExtensionId& extension_id, - scoped_refptr<BrowserThemePack> pack, - bool suppress_infobar) { - if (!pack->is_valid()) { +void ThemeService::BuildFromExtension(const Extension* extension) { + scoped_refptr<BrowserThemePack> pack( + BrowserThemePack::BuildFromExtension(extension)); + if (!pack.get()) { // TODO(erg): We've failed to install the theme; perhaps we should tell the // user? http://crbug.com/34780 LOG(ERROR) << "Could not load theme."; @@ -861,57 +855,16 @@ extensions::ExtensionSystem::Get(profile_)->extension_service(); if (!service) return; - const Extension* extension = extensions::ExtensionRegistry::Get(profile_) - ->enabled_extensions() - .GetByID(extension_id); - if (!extension) - return; // Write the packed file to disk. service->GetFileTaskRunner()->PostTask( FROM_HERE, base::Bind(&WritePackToDiskCallback, base::RetainedRef(pack), extension->path())); - const std::string previous_theme_id = GetThemeID(); - const bool previous_using_system_theme = UsingSystemTheme(); - // Save only the extension path. The packed file will be loaded via // LoadThemePrefs(). SavePackName(extension->path()); SwapThemeSupplier(pack); - - // Clear our image cache. - FreePlatformCaches(); - SaveThemeID(extension->id()); - NotifyThemeChanged(); - - // Same old theme, but the theme has changed (migrated) or auto-updated. - if (previous_theme_id == extension->id()) - return; - - base::RecordAction(UserMetricsAction("Themes_Installed")); - - bool can_revert_theme = previous_theme_id == kDefaultThemeID; - if (previous_theme_id != kDefaultThemeID && - service->GetInstalledExtension(previous_theme_id)) { - // Do not disable the previous theme if it is already uninstalled. Sending - // NOTIFICATION_BROWSER_THEME_CHANGED causes the previous theme to be - // uninstalled when the notification causes the remaining infobar to close - // and does not open any new infobars. See crbug.com/468280. - - // Disable the old theme. - service->DisableExtension(previous_theme_id, - extensions::Extension::DISABLE_USER_ACTION); - - can_revert_theme = true; - } - - // Offer to revert to the old theme. - if (can_revert_theme && !suppress_infobar) { - ThemeInstalledInfoBarDelegate::Create( - extension, profile_, previous_theme_id, previous_using_system_theme); - } - building_extension_id_.clear(); } #if BUILDFLAG(ENABLE_SUPERVISED_USERS)
diff --git a/chrome/browser/themes/theme_service.h b/chrome/browser/themes/theme_service.h index c941a63..51c676c 100644 --- a/chrome/browser/themes/theme_service.h +++ b/chrome/browser/themes/theme_service.h
@@ -16,17 +16,14 @@ #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "base/sequence_checker.h" -#include "base/task/cancelable_task_tracker.h" #include "build/build_config.h" #include "chrome/common/features.h" #include "components/keyed_service/core/keyed_service.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" -#include "extensions/common/extension_id.h" #include "extensions/features/features.h" #include "ui/base/theme_provider.h" -class BrowserThemePack; class CustomThemeSupplier; class ThemeSyncableService; class Profile; @@ -85,9 +82,6 @@ // ExtensionService. virtual void SetTheme(const extensions::Extension* extension); - // Similar to SetTheme, but doesn't show an undo infobar. - void RevertToTheme(const extensions::Extension* extension); - // Reset the theme to default. virtual void UseDefaultTheme(); @@ -236,9 +230,6 @@ // and contrasting with the foreground tab is the most important). static SkColor GetSeparatorColor(SkColor tab_color, SkColor frame_color); - void DoSetTheme(const extensions::Extension* extension, - bool suppress_infobar); - // These methods provide the implementation for ui::ThemeProvider (exposed // via BrowserThemeProvider). gfx::ImageSkia* GetImageSkiaNamed(int id, bool incognito) const; @@ -279,15 +270,8 @@ void SaveThemeID(const std::string& id); // Implementation of SetTheme() (and the fallback from LoadThemePrefs() in - // case we don't have a theme pack). |new_theme| indicates whether this is a - // newly installed theme or a migration. - void BuildFromExtension(const extensions::Extension* extension, - bool new_theme); - - // Callback when |pack| has finished or failed building. - void OnThemeBuiltFromExtension(const extensions::ExtensionId& extension_id, - scoped_refptr<BrowserThemePack> pack, - bool new_theme); + // case we don't have a theme pack). + void BuildFromExtension(const extensions::Extension* extension); #if BUILDFLAG(ENABLE_SUPERVISED_USERS) // Returns true if the profile belongs to a supervised user. @@ -344,14 +328,6 @@ SEQUENCE_CHECKER(sequence_checker_); - // Allows us to cancel building a theme pack from an extension. - base::CancelableTaskTracker build_extension_task_tracker_; - - // The ID of the theme that's currently being built on a different thread. - // We hold onto this just to be sure not to uninstall the extension view - // RemoveUnusedThemes while it's still being built. - std::string building_extension_id_; - base::WeakPtrFactory<ThemeService> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(ThemeService);
diff --git a/chrome/browser/themes/theme_service_browsertest.cc b/chrome/browser/themes/theme_service_browsertest.cc index d9d19f9..7ed17415 100644 --- a/chrome/browser/themes/theme_service_browsertest.cc +++ b/chrome/browser/themes/theme_service_browsertest.cc
@@ -7,7 +7,6 @@ #include "base/macros.h" #include "base/threading/sequenced_worker_pool.h" #include "base/threading/thread_restrictions.h" -#include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/extensions/component_loader.h" #include "chrome/browser/extensions/extension_browsertest.h" #include "chrome/browser/profiles/profile.h" @@ -16,7 +15,6 @@ #include "chrome/browser/ui/browser.h" #include "chrome/common/pref_names.h" #include "components/prefs/pref_service.h" -#include "content/public/test/test_utils.h" namespace { @@ -61,14 +59,6 @@ profile->GetPrefs()->GetFilePath(prefs::kCurrentThemePackFilename)); InstallExtension(test_data_dir_.AppendASCII("theme"), 1); - // The theme isn't installed synchronously. - EXPECT_FALSE(UsingCustomTheme(*theme_service)); - - // Wait for the theme to be loaded. - content::WindowedNotificationObserver theme_change_observer( - chrome::NOTIFICATION_BROWSER_THEME_CHANGED, - content::Source<ThemeService>(theme_service)); - theme_change_observer.Wait(); // Check that the theme was installed. EXPECT_TRUE(UsingCustomTheme(*theme_service));
diff --git a/chrome/browser/themes/theme_service_unittest.cc b/chrome/browser/themes/theme_service_unittest.cc index 83114e6..7f6807ee 100644 --- a/chrome/browser/themes/theme_service_unittest.cc +++ b/chrome/browser/themes/theme_service_unittest.cc
@@ -10,7 +10,6 @@ #include "base/path_service.h" #include "base/run_loop.h" #include "base/strings/stringprintf.h" -#include "base/test/scoped_task_environment.h" #include "build/build_config.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/extensions/extension_service.h" @@ -78,7 +77,8 @@ installer->Load(temp_dir); std::string extension_id = observer.WaitForExtensionLoaded()->id(); - WaitForThemeInstall(); + // Let the ThemeService finish creating the theme pack. + base::RunLoop().RunUntilIdle(); return extension_id; } @@ -111,14 +111,6 @@ return theme_service->get_theme_supplier(); } - void WaitForThemeInstall() { - content::WindowedNotificationObserver theme_change_observer( - chrome::NOTIFICATION_BROWSER_THEME_CHANGED, - content::Source<ThemeService>( - ThemeServiceFactory::GetForProfile(profile()))); - theme_change_observer.Wait(); - } - // Alpha blends a non-opaque foreground color against an opaque background. // This is not the same as color_utils::AlphaBlend() since it gets the opacity // from the foreground color and then does not blend the two colors' alpha @@ -171,6 +163,8 @@ ThemeService* theme_service = ThemeServiceFactory::GetForProfile(profile_.get()); theme_service->UseDefaultTheme(); + // Let the ThemeService uninstall unused themes. + base::RunLoop().RunUntilIdle(); base::ScopedTempDir temp_dir1; ASSERT_TRUE(temp_dir1.CreateUniqueTempDir()); @@ -194,19 +188,19 @@ // 2) Enabling a disabled theme extension should swap the current theme. service_->EnableExtension(extension1_id); - WaitForThemeInstall(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(extension1_id, theme_service->GetThemeID()); EXPECT_TRUE(service_->IsExtensionEnabled(extension1_id)); EXPECT_TRUE(registry_->GetExtensionById(extension2_id, ExtensionRegistry::DISABLED)); - // 3) Using RevertToTheme() with a disabled theme should enable and set the + // 3) Using SetTheme() with a disabled theme should enable and set the // theme. This is the case when the user reverts to the previous theme // via an infobar. const extensions::Extension* extension2 = service_->GetInstalledExtension(extension2_id); - theme_service->RevertToTheme(extension2); - WaitForThemeInstall(); + theme_service->SetTheme(extension2); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(extension2_id, theme_service->GetThemeID()); EXPECT_TRUE(service_->IsExtensionEnabled(extension2_id)); EXPECT_TRUE(registry_->GetExtensionById(extension1_id, @@ -346,21 +340,18 @@ // Show an infobar. theme_service->OnInfobarDisplayed(); - // Install another theme. The first extension shouldn't be uninstalled yet as - // it should be possible to revert to it. Emulate the infobar destroying - // itself as a result of the NOTIFICATION_BROWSER_THEME_CHANGED notification. + // Install another theme. Emulate the infobar destroying itself (and + // causing unused themes to be uninstalled) as a result of the + // NOTIFICATION_BROWSER_THEME_CHANGED notification. { InfobarDestroyerOnThemeChange destroyer(profile_.get()); const std::string& extension2_id = LoadUnpackedThemeAt(temp_dir2.GetPath()); - EXPECT_EQ(extension2_id, theme_service->GetThemeID()); + ASSERT_EQ(extension2_id, theme_service->GetThemeID()); + ASSERT_FALSE(service_->GetInstalledExtension(extension1_id)); } - auto* extension1 = service_->GetInstalledExtension(extension1_id); - ASSERT_TRUE(extension1); - // Check that it is possible to reinstall extension1. - ThemeServiceFactory::GetForProfile(profile_.get())->RevertToTheme(extension1); - WaitForThemeInstall(); + ASSERT_EQ(extension1_id, LoadUnpackedThemeAt(temp_dir1.GetPath())); EXPECT_EQ(extension1_id, theme_service->GetThemeID()); }
diff --git a/chrome/browser/ui/bookmarks/bookmark_bar_constants.h b/chrome/browser/ui/bookmarks/bookmark_bar_constants.h index d6e35ea..f80b23f 100644 --- a/chrome/browser/ui/bookmarks/bookmark_bar_constants.h +++ b/chrome/browser/ui/bookmarks/bookmark_bar_constants.h
@@ -10,7 +10,7 @@ namespace chrome { // The height of Bookmarks Bar, when visible in "New Tab Page" mode. -const int kNTPBookmarkBarHeight = 40; +const int kNTPBookmarkBarHeight = 39; // The minimum height of Bookmarks Bar, when attached to the toolbar. The // height of the toolbar may grow to more than this value if the embedded @@ -20,9 +20,9 @@ // points) because of the visual overlap with the main toolbar. When using this // to compute values other than the actual height of the toolbar, be sure to add // |kVisualHeightOffset|. -const int kMinimumBookmarkBarHeight = 26; +const int kMinimumBookmarkBarHeight = 25; #elif defined(TOOLKIT_VIEWS) -const int kMinimumBookmarkBarHeight = 28; +const int kMinimumBookmarkBarHeight = 27; #endif } // namespace chrome
diff --git a/chrome/browser/ui/cocoa/browser_window_cocoa.mm b/chrome/browser/ui/cocoa/browser_window_cocoa.mm index 0416c62d..01d1e5e6 100644 --- a/chrome/browser/ui/cocoa/browser_window_cocoa.mm +++ b/chrome/browser/ui/cocoa/browser_window_cocoa.mm
@@ -22,6 +22,7 @@ #include "chrome/browser/shell_integration.h" #include "chrome/browser/signin/chrome_signin_helper.h" #include "chrome/browser/translate/chrome_translate_client.h" +#include "chrome/browser/ui/bookmarks/bookmark_bar_constants.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_command_controller.h" #include "chrome/browser/ui/browser_commands.h" @@ -842,7 +843,7 @@ BrowserWindowCocoa::GetRenderViewHeightInsetWithDetachedBookmarkBar() { if (browser_->bookmark_bar_state() != BookmarkBar::DETACHED) return 0; - return 40; + return chrome::kNTPBookmarkBarHeight; } void BrowserWindowCocoa::ExecuteExtensionCommand(
diff --git a/chrome/browser/ui/extensions/extension_install_ui_default.cc b/chrome/browser/ui/extensions/extension_install_ui_default.cc index 6114b11..53fda5b 100644 --- a/chrome/browser/ui/extensions/extension_install_ui_default.cc +++ b/chrome/browser/ui/extensions/extension_install_ui_default.cc
@@ -9,6 +9,7 @@ #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" #include "chrome/browser/chrome_notification_types.h" +#include "chrome/browser/extensions/theme_installed_infobar_delegate.h" #include "chrome/browser/infobars/infobar_service.h" #include "chrome/browser/prefs/incognito_mode_prefs.h" #include "chrome/browser/profiles/profile.h" @@ -140,13 +141,25 @@ content::BrowserContext* context) : profile_(Profile::FromBrowserContext(context)), skip_post_install_ui_(false), - use_app_installed_bubble_(false) {} + previous_using_system_theme_(false), + use_app_installed_bubble_(false) { + // |profile| can be NULL during tests. + if (profile_) { + // Remember the current theme in case the user presses undo. + const Extension* previous_theme = + ThemeServiceFactory::GetThemeForProfile(profile_); + if (previous_theme) + previous_theme_id_ = previous_theme->id(); + previous_using_system_theme_ = + ThemeServiceFactory::GetForProfile(profile_)->UsingSystemTheme(); + } +} ExtensionInstallUIDefault::~ExtensionInstallUIDefault() {} void ExtensionInstallUIDefault::OnInstallSuccess(const Extension* extension, const SkBitmap* icon) { - if (skip_post_install_ui_ || extension->is_theme()) + if (skip_post_install_ui_) return; if (!profile_) { @@ -156,6 +169,12 @@ return; } + if (extension->is_theme()) { + ThemeInstalledInfoBarDelegate::Create( + extension, profile_, previous_theme_id_, previous_using_system_theme_); + return; + } + // Extensions aren't enabled by default in incognito so we confirm // the install in a normal window. Profile* current_profile = profile_->GetOriginalProfile();
diff --git a/chrome/browser/ui/extensions/extension_install_ui_default.h b/chrome/browser/ui/extensions/extension_install_ui_default.h index 2586f2e..32d40e1 100644 --- a/chrome/browser/ui/extensions/extension_install_ui_default.h +++ b/chrome/browser/ui/extensions/extension_install_ui_default.h
@@ -35,6 +35,10 @@ // Whether or not to show the default UI after completing the installation. bool skip_post_install_ui_; + // Used to undo theme installation. + std::string previous_theme_id_; + bool previous_using_system_theme_; + // Whether to show an installed bubble on app install, or use the default // action of opening a new tab page. bool use_app_installed_bubble_;
diff --git a/chrome/browser/ui/search/instant_extended_interactive_uitest.cc b/chrome/browser/ui/search/instant_extended_interactive_uitest.cc index e61e99b4..7bc09d7 100644 --- a/chrome/browser/ui/search/instant_extended_interactive_uitest.cc +++ b/chrome/browser/ui/search/instant_extended_interactive_uitest.cc
@@ -291,7 +291,8 @@ void InstallThemeAndVerify(const std::string& theme_dir, const std::string& theme_name) { const extensions::Extension* theme = - ThemeServiceFactory::GetThemeForProfile(profile()); + ThemeServiceFactory::GetThemeForProfile( + ExtensionBrowserTest::browser()->profile()); // If there is already a theme installed, the current theme should be // disabled and the new one installed + enabled. int expected_change = theme ? 0 : 1; @@ -299,13 +300,9 @@ const base::FilePath theme_path = test_data_dir_.AppendASCII(theme_dir); ASSERT_TRUE(InstallExtensionWithUIAutoConfirm( theme_path, expected_change, ExtensionBrowserTest::browser())); - content::WindowedNotificationObserver theme_change_observer( - chrome::NOTIFICATION_BROWSER_THEME_CHANGED, - content::Source<ThemeService>( - ThemeServiceFactory::GetForProfile(profile()))); - theme_change_observer.Wait(); const extensions::Extension* new_theme = - ThemeServiceFactory::GetThemeForProfile(profile()); + ThemeServiceFactory::GetThemeForProfile( + ExtensionBrowserTest::browser()->profile()); ASSERT_NE(static_cast<extensions::Extension*>(NULL), new_theme); ASSERT_EQ(new_theme->name(), theme_name); }
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc index 9e4f912..14def1c78 100644 --- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc +++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
@@ -605,7 +605,6 @@ // Don't let the bookmarks show on top of the location bar while animating. SetPaintToLayer(); layer()->SetMasksToBounds(true); - layer()->SetFillsBoundsOpaquely(false); size_animation_.Reset(1); } @@ -799,23 +798,19 @@ } int BookmarkBarView::GetToolbarOverlap() const { - int attached_overlap = kToolbarAttachedBookmarkBarOverlap + - views::NonClientFrameView::kClientEdgeThickness; + int attached_overlap = kToolbarAttachedBookmarkBarOverlap; + if (!IsDetached()) return attached_overlap; - int detached_overlap = views::NonClientFrameView::kClientEdgeThickness; - // Do not animate the overlap when the infobar is above us (i.e. when we're // detached), since drawing over the infobar looks weird. if (infobar_visible_) - return detached_overlap; + return 0; // When detached with no infobar, animate the overlap between the attached and // detached states. - return detached_overlap + static_cast<int>( - (attached_overlap - detached_overlap) * - size_animation_.GetCurrentValue()); + return static_cast<int>(attached_overlap * size_animation_.GetCurrentValue()); } int BookmarkBarView::GetPreferredHeight() const {
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc index e530c8d..e7e19ede 100644 --- a/chrome/browser/ui/views/frame/browser_view.cc +++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -197,10 +197,6 @@ // Paint background for detached state; if animating, this is fade in/out. const ui::ThemeProvider* tp = view->GetThemeProvider(); gfx::Rect fill_rect = view->GetLocalBounds(); - // We have to not color the top 1dp, because that should be painted by the - // toolbar. We will, however, paint the 1px separator at the bottom of the - // first dp. See crbug.com/610359 - fill_rect.Inset(0, 1, 0, 0); // In detached mode, the bar is meant to overlap with |contents_container_|. // The detached background color may be partially transparent, but the layer @@ -2547,8 +2543,7 @@ } // Don't use bookmark_bar_view_->height() which won't be the final height if // the bookmark bar is animating. - return chrome::kNTPBookmarkBarHeight - - views::NonClientFrameView::kClientEdgeThickness; + return chrome::kNTPBookmarkBarHeight; } void BrowserView::ExecuteExtensionCommand(
diff --git a/chrome/browser/ui/views/frame/browser_view_layout.cc b/chrome/browser/ui/views/frame/browser_view_layout.cc index f781e84..0b8410c 100644 --- a/chrome/browser/ui/views/frame/browser_view_layout.cc +++ b/chrome/browser/ui/views/frame/browser_view_layout.cc
@@ -512,8 +512,7 @@ } // Offset for the detached bookmark bar. - return bookmark_bar_->height() - - views::NonClientFrameView::kClientEdgeThickness; + return bookmark_bar_->height(); } int BrowserViewLayout::LayoutDownloadShelf(int bottom) {
diff --git a/chrome/browser/ui/views/frame/browser_view_unittest.cc b/chrome/browser/ui/views/frame/browser_view_unittest.cc index a12611c..3a13912 100644 --- a/chrome/browser/ui/views/frame/browser_view_unittest.cc +++ b/chrome/browser/ui/views/frame/browser_view_unittest.cc
@@ -140,17 +140,10 @@ // Bookmark bar layout on NTP. EXPECT_EQ(0, bookmark_bar->x()); - EXPECT_EQ(tabstrip->bounds().bottom() + toolbar->height() - - views::NonClientFrameView::kClientEdgeThickness, - bookmark_bar->y()); + EXPECT_EQ(tabstrip->bounds().bottom() + toolbar->height(), bookmark_bar->y()); EXPECT_EQ(toolbar->bounds().bottom(), contents_container->y()); - // Contents view has a "top margin" pushing it below the bookmark bar. - EXPECT_EQ(bookmark_bar->height() - - views::NonClientFrameView::kClientEdgeThickness, - devtools_web_view->y()); - EXPECT_EQ(bookmark_bar->height() - - views::NonClientFrameView::kClientEdgeThickness, - contents_web_view->y()); + EXPECT_EQ(bookmark_bar->height(), devtools_web_view->y()); + EXPECT_EQ(bookmark_bar->height(), contents_web_view->y()); // Bookmark bar is parented back to top container on normal page. NavigateAndCommitActiveTabWithTitle(browser,
diff --git a/chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.cc index f6e284a1..c57c266e 100644 --- a/chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.cc
@@ -16,6 +16,8 @@ #include "base/strings/stringprintf.h" #include "base/sys_info.h" #include "base/task_scheduler/post_task.h" +#include "base/threading/thread_task_runner_handle.h" +#include "base/time/time.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/arc/arc_migration_constants.h" #include "chrome/browser/chromeos/login/ui/login_feedback.h" @@ -46,18 +48,25 @@ // JS API callbacks names. constexpr char kJsApiStartMigration[] = "startMigration"; constexpr char kJsApiSkipMigration[] = "skipMigration"; -constexpr char kJsApiRequestRestart[] = "requestRestart"; +constexpr char kJsApiRequestRestartOnLowStorage[] = + "requestRestartOnLowStorage"; +constexpr char kJsApiRequestRestartOnFailure[] = "requestRestartOnFailure"; constexpr char kJsApiOpenFeedbackDialog[] = "openFeedbackDialog"; // UMA names. constexpr char kUmaNameFirstScreen[] = "Cryptohome.MigrationUI.FirstScreen"; constexpr char kUmaNameUserChoice[] = "Cryptohome.MigrationUI.UserChoice"; +constexpr char kUmaNameMigrationResult[] = + "Cryptohome.MigrationUI.MigrationResult"; +constexpr char kUmaNameRemoveCryptohomeResult[] = + "Cryptohome.MigrationUI.RemoveCryptohomeResult"; constexpr char kUmaNameConsumedBatteryPercent[] = "Cryptohome.MigrationUI.ConsumedBatteryPercent"; +constexpr char kUmaNameVisibleScreen[] = "Cryptohome.MigrationUI.VisibleScreen"; -// This enum must match the numbering for Cryptohome.MigrationUI.FirstScreen in -// histograms.xml. Do not reorder or remove items, only add new items before -// FIRST_SCREEN_MAX. +// This enum must match the numbering for MigrationUIFirstScreen in +// histograms/enums.xml. Do not reorder or remove items, only add new items +// before FIRST_SCREEN_COUNT. enum class FirstScreen { FIRST_SCREEN_READY = 0, FIRST_SCREEN_RESUME = 1, @@ -65,15 +74,44 @@ FIRST_SCREEN_COUNT }; -// This enum must match the numbering for Cryptohome.MigrationUI.UserChoice in -// histograms.xml. Do not reorder or remove items, only add new items before -// FIRST_SCREEN_MAX. +// This enum must match the numbering for MigrationUIUserChoice in +// histograms/enums.xml. Do not reorder or remove items, only add new items +// before USER_CHOICE_COUNT. enum class UserChoice { USER_CHOICE_UPDATE = 0, USER_CHOICE_SKIP = 1, + USER_CHOICE_RESTART_ON_FAILURE = 2, + USER_CHOICE_RESTART_ON_LOW_STORAGE = 3, + USER_CHOICE_REPORT_AN_ISSUE = 4, USER_CHOICE_COUNT }; +// This enum must match the numbering for MigrationUIMigrationResult in +// histograms/enums.xml. Do not reorder or remove items, only add new items +// before COUNT. +enum class MigrationResult { + SUCCESS_IN_NEW_MIGRATION = 0, + SUCCESS_IN_RESUMED_MIGRATION = 1, + GENERAL_FAILURE_IN_NEW_MIGRATION = 2, + GENERAL_FAILURE_IN_RESUMED_MIGRATION = 3, + REQUEST_FAILURE_IN_NEW_MIGRATION = 4, + REQUEST_FAILURE_IN_RESUMED_MIGRATION = 5, + MOUNT_FAILURE_IN_NEW_MIGRATION = 6, + MOUNT_FAILURE_IN_RESUMED_MIGRATION = 7, + COUNT +}; + +// This enum must match the numbering for MigrationUIRemoveCryptohomeResult in +// histograms/enums.xml. Do not reorder or remove items, only add new items +// before COUNT. +enum class RemoveCryptohomeResult { + SUCCESS_IN_NEW_MIGRATION = 0, + SUCCESS_IN_RESUMED_MIGRATION = 1, + FAILURE_IN_NEW_MIGRATION = 2, + FAILURE_IN_RESUMED_MIGRATION = 3, + COUNT +}; + bool IsTestingUI() { return base::CommandLine::ForCurrentProcess()->HasSwitch( chromeos::switches::kTestEncryptionMigrationUI); @@ -81,13 +119,30 @@ // Wrapper functions for histogram macros to avoid duplication of expanded code. void RecordFirstScreen(FirstScreen first_screen) { - UMA_HISTOGRAM_ENUMERATION(kUmaNameFirstScreen, static_cast<int>(first_screen), - static_cast<int>(FirstScreen::FIRST_SCREEN_COUNT)); + UMA_HISTOGRAM_ENUMERATION(kUmaNameFirstScreen, first_screen, + FirstScreen::FIRST_SCREEN_COUNT); } void RecordUserChoice(UserChoice user_choice) { - UMA_HISTOGRAM_ENUMERATION(kUmaNameUserChoice, static_cast<int>(user_choice), - static_cast<int>(UserChoice::USER_CHOICE_COUNT)); + UMA_HISTOGRAM_ENUMERATION(kUmaNameUserChoice, user_choice, + UserChoice::USER_CHOICE_COUNT); +} + +void RecordMigrationResult(MigrationResult migration_result) { + UMA_HISTOGRAM_ENUMERATION(kUmaNameMigrationResult, migration_result, + MigrationResult::COUNT); +} + +void RecordRemoveCryptohomeResult(bool success, bool is_resumed_migration) { + RemoveCryptohomeResult result = + success ? (is_resumed_migration + ? RemoveCryptohomeResult::SUCCESS_IN_RESUMED_MIGRATION + : RemoveCryptohomeResult::SUCCESS_IN_NEW_MIGRATION) + : (is_resumed_migration + ? RemoveCryptohomeResult::FAILURE_IN_RESUMED_MIGRATION + : RemoveCryptohomeResult::FAILURE_IN_NEW_MIGRATION); + UMA_HISTOGRAM_ENUMERATION(kUmaNameRemoveCryptohomeResult, result, + RemoveCryptohomeResult::COUNT); } } // namespace @@ -204,8 +259,11 @@ &EncryptionMigrationScreenHandler::HandleStartMigration); AddCallback(kJsApiSkipMigration, &EncryptionMigrationScreenHandler::HandleSkipMigration); - AddCallback(kJsApiRequestRestart, - &EncryptionMigrationScreenHandler::HandleRequestRestart); + AddCallback( + kJsApiRequestRestartOnLowStorage, + &EncryptionMigrationScreenHandler::HandleRequestRestartOnLowStorage); + AddCallback(kJsApiRequestRestartOnFailure, + &EncryptionMigrationScreenHandler::HandleRequestRestartOnFailure); AddCallback(kJsApiOpenFeedbackDialog, &EncryptionMigrationScreenHandler::HandleOpenFeedbackDialog); } @@ -258,11 +316,18 @@ } } -void EncryptionMigrationScreenHandler::HandleRequestRestart() { +void EncryptionMigrationScreenHandler::HandleRequestRestartOnLowStorage() { + RecordUserChoice(UserChoice::USER_CHOICE_RESTART_ON_LOW_STORAGE); + DBusThreadManager::Get()->GetPowerManagerClient()->RequestRestart(); +} + +void EncryptionMigrationScreenHandler::HandleRequestRestartOnFailure() { + RecordUserChoice(UserChoice::USER_CHOICE_RESTART_ON_FAILURE); DBusThreadManager::Get()->GetPowerManagerClient()->RequestRestart(); } void EncryptionMigrationScreenHandler::HandleOpenFeedbackDialog() { + RecordUserChoice(UserChoice::USER_CHOICE_REPORT_AN_ISSUE); const std::string description = base::StringPrintf( "Auto generated feedback for http://crbug.com/719266.\n" "(uniquifier:%s)", @@ -291,6 +356,16 @@ StopBlockingPowerSave(); PowerPolicyController::Get()->SetEncryptionMigrationActive(false); } + + // Record which screen is visible to the user. + // We record it after delay to make sure that the user was actually able + // to see the screen (i.e. the screen is not just a flash). + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, + base::BindOnce( + &EncryptionMigrationScreenHandler::OnDelayedRecordVisibleScreen, + weak_ptr_factory_.GetWeakPtr(), state), + base::TimeDelta::FromSeconds(1)); } void EncryptionMigrationScreenHandler::CheckAvailableStorage() { @@ -351,6 +426,9 @@ cryptohome::MountError return_code, const std::string& mount_hash) { if (!success || return_code != cryptohome::MOUNT_ERROR_NONE) { + RecordMigrationResult( + should_resume_ ? MigrationResult::MOUNT_FAILURE_IN_RESUMED_MIGRATION + : MigrationResult::MOUNT_FAILURE_IN_NEW_MIGRATION); UpdateUIState(UIState::MIGRATION_FAILED); return; } @@ -402,6 +480,7 @@ cryptohome::MountError return_code) { LOG_IF(ERROR, !success) << "Removing cryptohome failed. return code: " << return_code; + RecordRemoveCryptohomeResult(success, should_resume_); UpdateUIState(UIState::MIGRATION_FAILED); } @@ -433,6 +512,9 @@ CallJS("setMigrationProgress", static_cast<double>(current) / total); break; case cryptohome::DIRCRYPTO_MIGRATION_SUCCESS: + RecordMigrationResult(should_resume_ + ? MigrationResult::SUCCESS_IN_RESUMED_MIGRATION + : MigrationResult::SUCCESS_IN_NEW_MIGRATION); // If the battery level decreased during migration, record the consumed // battery level. if (*current_battery_percent_ < initial_battery_percent_) { @@ -445,6 +527,9 @@ DBusThreadManager::Get()->GetPowerManagerClient()->RequestRestart(); break; case cryptohome::DIRCRYPTO_MIGRATION_FAILED: + RecordMigrationResult( + should_resume_ ? MigrationResult::GENERAL_FAILURE_IN_RESUMED_MIGRATION + : MigrationResult::GENERAL_FAILURE_IN_NEW_MIGRATION); // Stop listening to the progress updates. DBusThreadManager::Get() ->GetCryptohomeClient() @@ -461,8 +546,21 @@ void EncryptionMigrationScreenHandler::OnMigrationRequested(bool success) { if (!success) { LOG(ERROR) << "Requesting MigrateToDircrypto failed."; + RecordMigrationResult( + should_resume_ ? MigrationResult::REQUEST_FAILURE_IN_RESUMED_MIGRATION + : MigrationResult::REQUEST_FAILURE_IN_NEW_MIGRATION); UpdateUIState(UIState::MIGRATION_FAILED); } } +void EncryptionMigrationScreenHandler::OnDelayedRecordVisibleScreen( + UIState ui_state) { + if (current_ui_state_ != ui_state) + return; + + // If |current_ui_state_| is not changed for a second, record the current + // screen as a "visible" screen. + UMA_HISTOGRAM_ENUMERATION(kUmaNameVisibleScreen, ui_state, UIState::COUNT); +} + } // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.h index 968a9ebd..5dba39d5 100644 --- a/chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.h +++ b/chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.h
@@ -47,14 +47,17 @@ void Initialize() override; private: - // Enumeration for the migration state. These values must be kept in sync with - // EncryptionMigrationUIState in JS code. + // Enumeration for migration UI state. These values must be kept in sync with + // EncryptionMigrationUIState in JS code, and match the numbering for + // MigrationUIScreen in histograms/enums.xml. Do not reorder or remove items, + // only add new items before COUNT. enum UIState { INITIAL = 0, READY = 1, MIGRATING = 2, MIGRATION_FAILED = 3, NOT_ENOUGH_STORAGE = 4, + COUNT }; // WebUIMessageHandler implementation: @@ -66,7 +69,8 @@ // Handlers for JS API callbacks. void HandleStartMigration(); void HandleSkipMigration(); - void HandleRequestRestart(); + void HandleRequestRestartOnLowStorage(); + void HandleRequestRestartOnFailure(); void HandleOpenFeedbackDialog(); // Updates UI state. @@ -94,6 +98,9 @@ uint64_t total); void OnMigrationRequested(bool success); + // Records UMA about visible screen after delay. + void OnDelayedRecordVisibleScreen(UIState state); + Delegate* delegate_ = nullptr; bool show_on_init_ = false;
diff --git a/components/cronet/android/cronet_bidirectional_stream_adapter.cc b/components/cronet/android/cronet_bidirectional_stream_adapter.cc index a637d490..104cb43 100644 --- a/components/cronet/android/cronet_bidirectional_stream_adapter.cc +++ b/components/cronet/android/cronet_bidirectional_stream_adapter.cc
@@ -398,15 +398,9 @@ pending_write_data_ = std::move(pending_write_data); bool end_of_stream = pending_write_data_->jwrite_end_of_stream == JNI_TRUE; - if (pending_write_data_->write_buffer_list.size() == 1) { - bidi_stream_->SendData(pending_write_data_->write_buffer_list[0], - pending_write_data_->write_buffer_len_list[0], - end_of_stream); - } else { - bidi_stream_->SendvData(pending_write_data_->write_buffer_list, - pending_write_data_->write_buffer_len_list, - end_of_stream); - } + bidi_stream_->SendvData(pending_write_data_->write_buffer_list, + pending_write_data_->write_buffer_len_list, + end_of_stream); } void CronetBidirectionalStreamAdapter::DestroyOnNetworkThread(
diff --git a/device/generic_sensor/public/interfaces/BUILD.gn b/device/generic_sensor/public/interfaces/BUILD.gn index bd043fd..9ffc6b3 100644 --- a/device/generic_sensor/public/interfaces/BUILD.gn +++ b/device/generic_sensor/public/interfaces/BUILD.gn
@@ -17,9 +17,6 @@ "sensor_provider.mojom", ] - # TODO(crbug.com/714018): Convert the implementation to use OnceCallback. - use_once_callback = false - # TODO(crbug.com/699569): Convert to use the new JS bindings. use_new_js_bindings = false }
diff --git a/device/generic_sensor/sensor_impl.cc b/device/generic_sensor/sensor_impl.cc index 1cf9eb8..33e9cd0b 100644 --- a/device/generic_sensor/sensor_impl.cc +++ b/device/generic_sensor/sensor_impl.cc
@@ -25,21 +25,21 @@ void SensorImpl::AddConfiguration( const PlatformSensorConfiguration& configuration, - const AddConfigurationCallback& callback) { + AddConfigurationCallback callback) { // TODO(Mikhail): To avoid overflowing browser by repeated AddConfigs // (maybe limit the number of configs per client). - callback.Run(sensor_->StartListening(this, configuration)); + std::move(callback).Run(sensor_->StartListening(this, configuration)); } void SensorImpl::GetDefaultConfiguration( - const GetDefaultConfigurationCallback& callback) { - callback.Run(sensor_->GetDefaultConfiguration()); + GetDefaultConfigurationCallback callback) { + std::move(callback).Run(sensor_->GetDefaultConfiguration()); } void SensorImpl::RemoveConfiguration( const PlatformSensorConfiguration& configuration, - const RemoveConfigurationCallback& callback) { - callback.Run(sensor_->StopListening(this, configuration)); + RemoveConfigurationCallback callback) { + std::move(callback).Run(sensor_->StopListening(this, configuration)); } void SensorImpl::Suspend() {
diff --git a/device/generic_sensor/sensor_impl.h b/device/generic_sensor/sensor_impl.h index 3730fc6..4a6ecc95 100644 --- a/device/generic_sensor/sensor_impl.h +++ b/device/generic_sensor/sensor_impl.h
@@ -23,12 +23,11 @@ private: // Sensor implementation. void AddConfiguration(const PlatformSensorConfiguration& configuration, - const AddConfigurationCallback& callback) override; + AddConfigurationCallback callback) override; void GetDefaultConfiguration( - const GetDefaultConfigurationCallback& callback) override; - void RemoveConfiguration( - const PlatformSensorConfiguration& configuration, - const RemoveConfigurationCallback& callback) override; + GetDefaultConfigurationCallback callback) override; + void RemoveConfiguration(const PlatformSensorConfiguration& configuration, + RemoveConfigurationCallback callback) override; void Suspend() override; void Resume() override;
diff --git a/device/generic_sensor/sensor_provider_impl.cc b/device/generic_sensor/sensor_provider_impl.cc index 8f36c47f..3e78e3a1 100644 --- a/device/generic_sensor/sensor_provider_impl.cc +++ b/device/generic_sensor/sensor_provider_impl.cc
@@ -18,17 +18,16 @@ void RunCallback(mojom::SensorInitParamsPtr init_params, mojom::SensorClientRequest client, - const SensorProviderImpl::GetSensorCallback& callback) { - callback.Run(std::move(init_params), std::move(client)); + SensorProviderImpl::GetSensorCallback callback) { + std::move(callback).Run(std::move(init_params), std::move(client)); } -void NotifySensorCreated( - mojom::SensorInitParamsPtr init_params, - mojom::SensorClientRequest client, - const SensorProviderImpl::GetSensorCallback& callback) { +void NotifySensorCreated(mojom::SensorInitParamsPtr init_params, + mojom::SensorClientRequest client, + SensorProviderImpl::GetSensorCallback callback) { base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(RunCallback, base::Passed(&init_params), - base::Passed(&client), callback)); + FROM_HERE, base::BindOnce(&RunCallback, std::move(init_params), + std::move(client), std::move(callback))); } } // namespace @@ -54,10 +53,10 @@ void SensorProviderImpl::GetSensor(mojom::SensorType type, mojom::SensorRequest sensor_request, - const GetSensorCallback& callback) { + GetSensorCallback callback) { auto cloned_handle = provider_->CloneSharedBufferHandle(); if (!cloned_handle.is_valid()) { - NotifySensorCreated(nullptr, nullptr, callback); + NotifySensorCreated(nullptr, nullptr, std::move(callback)); return; } @@ -66,23 +65,23 @@ PlatformSensorProviderBase::CreateSensorCallback cb = base::Bind( &SensorProviderImpl::SensorCreated, weak_ptr_factory_.GetWeakPtr(), type, base::Passed(&cloned_handle), base::Passed(&sensor_request), - callback); + base::Passed(&callback)); provider_->CreateSensor(type, cb); return; } SensorCreated(type, std::move(cloned_handle), std::move(sensor_request), - callback, std::move(sensor)); + std::move(callback), std::move(sensor)); } void SensorProviderImpl::SensorCreated( mojom::SensorType type, mojo::ScopedSharedBufferHandle cloned_handle, mojom::SensorRequest sensor_request, - const GetSensorCallback& callback, + GetSensorCallback callback, scoped_refptr<PlatformSensor> sensor) { if (!sensor) { - NotifySensorCreated(nullptr, nullptr, callback); + NotifySensorCreated(nullptr, nullptr, std::move(callback)); return; } @@ -104,7 +103,7 @@ DCHECK_GT(init_params->minimum_frequency, 0.0); NotifySensorCreated(std::move(init_params), sensor_impl->GetClient(), - callback); + std::move(callback)); mojo::MakeStrongBinding(std::move(sensor_impl), std::move(sensor_request)); }
diff --git a/device/generic_sensor/sensor_provider_impl.h b/device/generic_sensor/sensor_provider_impl.h index 3435f12..2dd3728b 100644 --- a/device/generic_sensor/sensor_provider_impl.h +++ b/device/generic_sensor/sensor_provider_impl.h
@@ -33,13 +33,13 @@ // SensorProvider implementation. void GetSensor(mojom::SensorType type, mojom::SensorRequest sensor_request, - const GetSensorCallback& callback) override; + GetSensorCallback callback) override; // Helper callback method to return created sensors. void SensorCreated(mojom::SensorType type, mojo::ScopedSharedBufferHandle cloned_handle, mojom::SensorRequest sensor_request, - const GetSensorCallback& callback, + GetSensorCallback callback, scoped_refptr<PlatformSensor> sensor); PlatformSensorProvider* provider_;
diff --git a/media/base/key_system_properties.cc b/media/base/key_system_properties.cc index 5c6bcb5..0a15064 100644 --- a/media/base/key_system_properties.cc +++ b/media/base/key_system_properties.cc
@@ -9,12 +9,11 @@ namespace media { +#if defined(OS_ANDROID) SupportedCodecs KeySystemProperties::GetSupportedSecureCodecs() const { -#if !defined(OS_ANDROID) - NOTREACHED(); -#endif return EME_CODEC_NONE; } +#endif bool KeySystemProperties::UseAesDecryptor() const { return false;
diff --git a/media/base/key_system_properties.h b/media/base/key_system_properties.h index a5f890b..b00147d 100644 --- a/media/base/key_system_properties.h +++ b/media/base/key_system_properties.h
@@ -7,6 +7,7 @@ #include <string> +#include "build/build_config.h" #include "media/base/eme_constants.h" #include "media/base/media_export.h" @@ -27,8 +28,10 @@ // Returns the codecs supported by this key system. virtual SupportedCodecs GetSupportedCodecs() const = 0; +#if defined(OS_ANDROID) // Returns the codecs with hardware-secure support in this key system. virtual SupportedCodecs GetSupportedSecureCodecs() const; +#endif // Returns the configuration rule for supporting a robustness requirement. virtual EmeConfigRule GetRobustnessConfigRule(
diff --git a/media/base/key_systems.cc b/media/base/key_systems.cc index 773cc62..691bc03 100644 --- a/media/base/key_systems.cc +++ b/media/base/key_systems.cc
@@ -238,7 +238,7 @@ void UpdateSupportedKeySystems(); void AddSupportedKeySystems( - std::vector<std::unique_ptr<KeySystemProperties>>* key_systems); + std::vector<std::unique_ptr<KeySystemProperties>> key_systems); void RegisterMimeType(const std::string& mime_type, EmeCodec codecs_mask); bool IsValidMimeTypeCodecsCombination(const std::string& mime_type, @@ -340,7 +340,7 @@ // Clear Key is always supported. key_systems_properties.emplace_back(new ClearKeyProperties()); - AddSupportedKeySystems(&key_systems_properties); + AddSupportedKeySystems(std::move(key_systems_properties)); } // Returns whether distinctive identifiers and persistent state can be reliably @@ -371,11 +371,11 @@ } void KeySystemsImpl::AddSupportedKeySystems( - std::vector<std::unique_ptr<KeySystemProperties>>* key_systems) { + std::vector<std::unique_ptr<KeySystemProperties>> key_systems) { DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(key_system_properties_map_.empty()); - for (auto& properties : *key_systems) { + for (auto& properties : key_systems) { DCHECK(!properties->GetKeySystemName().empty()); DCHECK(properties->GetPersistentLicenseSessionSupport() != EmeSessionTypeSupport::INVALID); @@ -393,7 +393,7 @@ continue; } - // Supporting persistent state is a prerequsite for supporting persistent + // Supporting persistent state is a prerequisite for supporting persistent // sessions. if (properties->GetPersistentStateSupport() == EmeFeatureSupport::NOT_SUPPORTED) {
diff --git a/media/base/key_systems_unittest.cc b/media/base/key_systems_unittest.cc index e5676cf9..9eea543 100644 --- a/media/base/key_systems_unittest.cc +++ b/media/base/key_systems_unittest.cc
@@ -37,6 +37,10 @@ const char kAudioFoo[] = "audio/foo"; const char kVideoFoo[] = "video/foo"; +const char kRobustnessSupported[] = "supported"; +const char kRobustnessSecureCodecsRequired[] = "secure-codecs-required"; +const char kRobustnessNotSupported[] = "not-supported"; + // Pick some arbitrary bit fields as long as they are not in conflict with the // real ones. enum TestCodec : uint32_t { @@ -50,71 +54,111 @@ static_assert((TEST_CODEC_FOO_ALL & EME_CODEC_ALL) == EME_CODEC_NONE, "test codec masks should only use invalid codec masks"); -class TestKeySystemProperties : public KeySystemProperties { +// Base class to provide default implementations. +class TestKeySystemPropertiesBase : public KeySystemProperties { public: bool IsSupportedInitDataType(EmeInitDataType init_data_type) const override { return init_data_type == EmeInitDataType::WEBM; } + SupportedCodecs GetSupportedCodecs() const override { return EME_CODEC_WEBM_ALL | TEST_CODEC_FOO_ALL; } + EmeConfigRule GetRobustnessConfigRule( EmeMediaType media_type, const std::string& requested_robustness) const override { return requested_robustness.empty() ? EmeConfigRule::SUPPORTED : EmeConfigRule::NOT_SUPPORTED; } + EmeSessionTypeSupport GetPersistentReleaseMessageSessionSupport() const override { return EmeSessionTypeSupport::NOT_SUPPORTED; } }; -class AesKeySystemProperties : public TestKeySystemProperties { +class AesKeySystemProperties : public TestKeySystemPropertiesBase { public: AesKeySystemProperties(const std::string& name) : name_(name) {} std::string GetKeySystemName() const override { return name_; } + EmeSessionTypeSupport GetPersistentLicenseSessionSupport() const override { return EmeSessionTypeSupport::NOT_SUPPORTED; } + EmeFeatureSupport GetPersistentStateSupport() const override { return EmeFeatureSupport::NOT_SUPPORTED; } + EmeFeatureSupport GetDistinctiveIdentifierSupport() const override { return EmeFeatureSupport::NOT_SUPPORTED; } + bool UseAesDecryptor() const override { return true; } private: std::string name_; }; -class ExternalKeySystemProperties : public TestKeySystemProperties { +class ExternalKeySystemProperties : public TestKeySystemPropertiesBase { public: std::string GetKeySystemName() const override { return kExternal; } + +#if defined(OS_ANDROID) + // We have hw-secure FOO_VIDEO codec support. + SupportedCodecs GetSupportedSecureCodecs() const override { + return TEST_CODEC_FOO_VIDEO; + } +#endif + + EmeConfigRule GetRobustnessConfigRule( + EmeMediaType media_type, + const std::string& requested_robustness) const override { + if (requested_robustness == kRobustnessSupported) + return EmeConfigRule::SUPPORTED; + else if (requested_robustness == kRobustnessSecureCodecsRequired) + return EmeConfigRule::HW_SECURE_CODECS_REQUIRED; + else if (requested_robustness == kRobustnessNotSupported) + return EmeConfigRule::NOT_SUPPORTED; + else + NOTREACHED(); + return EmeConfigRule::NOT_SUPPORTED; + } + EmeSessionTypeSupport GetPersistentLicenseSessionSupport() const override { return EmeSessionTypeSupport::SUPPORTED; } + EmeFeatureSupport GetPersistentStateSupport() const override { return EmeFeatureSupport::ALWAYS_ENABLED; } + EmeFeatureSupport GetDistinctiveIdentifierSupport() const override { return EmeFeatureSupport::ALWAYS_ENABLED; } + std::string GetPepperType() const override { return "application/x-ppapi-external-cdm"; } }; +static EmeConfigRule GetVideoContentTypeConfigRule( + const std::string& mime_type, + const std::vector<std::string>& codecs, + const std::string& key_system) { + return KeySystems::GetInstance()->GetContentTypeConfigRule( + key_system, EmeMediaType::VIDEO, mime_type, codecs); +} + // Adapt IsSupportedKeySystemWithMediaMimeType() to the new API, // IsSupportedCodecCombination(). static bool IsSupportedKeySystemWithMediaMimeType( const std::string& mime_type, const std::vector<std::string>& codecs, const std::string& key_system) { - return (KeySystems::GetInstance()->GetContentTypeConfigRule( - key_system, EmeMediaType::VIDEO, mime_type, codecs) != + return (GetVideoContentTypeConfigRule(mime_type, codecs, key_system) != EmeConfigRule::NOT_SUPPORTED); } @@ -131,6 +175,12 @@ return KeySystems::GetInstance()->IsSupportedKeySystem(key_system); } +static EmeConfigRule GetRobustnessConfigRule( + const std::string& requested_robustness) { + return KeySystems::GetInstance()->GetRobustnessConfigRule( + kExternal, EmeMediaType::VIDEO, requested_robustness); +} + // Adds test container and codec masks. // This function must be called after SetMediaClient() if a MediaClient will be // provided. @@ -695,4 +745,35 @@ EXPECT_FALSE(IsSupportedKeySystem(kExternal)); } +TEST_F(KeySystemsTest, GetContentTypeConfigRule) { + if (!CanRunExternalKeySystemTests()) + return; + + EXPECT_EQ(EmeConfigRule::SUPPORTED, + GetRobustnessConfigRule(kRobustnessSupported)); + EXPECT_EQ(EmeConfigRule::NOT_SUPPORTED, + GetRobustnessConfigRule(kRobustnessNotSupported)); + EXPECT_EQ(EmeConfigRule::HW_SECURE_CODECS_REQUIRED, + GetRobustnessConfigRule(kRobustnessSecureCodecsRequired)); +} + +#if defined(OS_ANDROID) +TEST_F(KeySystemsTest, HardwareSecureCodecs) { + if (!CanRunExternalKeySystemTests()) + return; + + EXPECT_EQ(EmeConfigRule::HW_SECURE_CODECS_NOT_ALLOWED, + GetVideoContentTypeConfigRule(kVideoWebM, vp8_codec(), kUsesAes)); + EXPECT_EQ( + EmeConfigRule::HW_SECURE_CODECS_NOT_ALLOWED, + GetVideoContentTypeConfigRule(kVideoFoo, foovideo_codec(), kUsesAes)); + + EXPECT_EQ(EmeConfigRule::HW_SECURE_CODECS_NOT_ALLOWED, + GetVideoContentTypeConfigRule(kVideoWebM, vp8_codec(), kExternal)); + EXPECT_EQ( + EmeConfigRule::SUPPORTED, + GetVideoContentTypeConfigRule(kVideoFoo, foovideo_codec(), kExternal)); +} +#endif + } // namespace media
diff --git a/net/BUILD.gn b/net/BUILD.gn index ac40a7a..cbe13593 100644 --- a/net/BUILD.gn +++ b/net/BUILD.gn
@@ -4724,6 +4724,8 @@ "quic/platform/impl/quic_chromium_clock_test.cc", "quic/platform/impl/quic_test_impl.cc", "quic/platform/impl/quic_test_impl.h", + "quic/quartc/quartc_session_test.cc", + "quic/quartc/quartc_stream_test.cc", "quic/test_tools/crypto_test_utils.cc", "quic/test_tools/crypto_test_utils.h", "quic/test_tools/crypto_test_utils_test.cc",
diff --git a/net/cert/internal/nist_pkits_unittest.cc b/net/cert/internal/nist_pkits_unittest.cc index 6697ded9..8980709 100644 --- a/net/cert/internal/nist_pkits_unittest.cc +++ b/net/cert/internal/nist_pkits_unittest.cc
@@ -57,18 +57,15 @@ } void PkitsTestInfo::SetInitialExplicitPolicy(bool b) { - initial_explicit_policy = - b ? InitialExplicitPolicy::kTrue : InitialExplicitPolicy::kFalse; + initial_explicit_policy = b; } void PkitsTestInfo::SetInitialPolicyMappingInhibit(bool b) { - initial_policy_mapping_inhibit = b ? InitialPolicyMappingInhibit::kTrue - : InitialPolicyMappingInhibit::kFalse; + initial_policy_mapping_inhibit = b; } void PkitsTestInfo::SetInitialInhibitAnyPolicy(bool b) { - initial_inhibit_any_policy = - b ? InitialAnyPolicyInhibit::kTrue : InitialAnyPolicyInhibit::kFalse; + initial_inhibit_any_policy = b; } PkitsTestInfo::~PkitsTestInfo() = default;
diff --git a/net/cert/internal/nist_pkits_unittest.h b/net/cert/internal/nist_pkits_unittest.h index 8f9ef42..adc064b6 100644 --- a/net/cert/internal/nist_pkits_unittest.h +++ b/net/cert/internal/nist_pkits_unittest.h
@@ -46,15 +46,13 @@ std::set<der::Input> initial_policy_set; // The value of "initial-explicit-policy". - InitialExplicitPolicy initial_explicit_policy = InitialExplicitPolicy::kFalse; + bool initial_explicit_policy = false; // The value of "initial-policy-mapping-inhibit". - InitialPolicyMappingInhibit initial_policy_mapping_inhibit = - InitialPolicyMappingInhibit::kFalse; + bool initial_policy_mapping_inhibit = false; // The value of "initial-inhibit-any-policy". - InitialAnyPolicyInhibit initial_inhibit_any_policy = - InitialAnyPolicyInhibit::kFalse; + bool initial_inhibit_any_policy = false; // This is the time when PKITS was published. der::GeneralizedTime time = {2011, 4, 15, 0, 0, 0};
diff --git a/net/cert/internal/path_builder.cc b/net/cert/internal/path_builder.cc index 05b66d6..d1ce0bdb 100644 --- a/net/cert/internal/path_builder.cc +++ b/net/cert/internal/path_builder.cc
@@ -604,12 +604,9 @@ // Verify the entire certificate chain. auto result_path = base::MakeUnique<ResultPath>(); - // TODO(eroman): don't pass placeholder for policy. - VerifyCertificateChain( - next_path_.certs, next_path_.last_cert_trust, signature_policy_, time_, - key_purpose_, InitialExplicitPolicy::kFalse, {AnyPolicy()}, - InitialPolicyMappingInhibit::kFalse, InitialAnyPolicyInhibit::kFalse, - nullptr /*user_constrained_policy_set*/, &result_path->errors); + VerifyCertificateChain(next_path_.certs, next_path_.last_cert_trust, + signature_policy_, time_, key_purpose_, + &result_path->errors); bool verify_result = !result_path->errors.ContainsHighSeverityErrors(); DVLOG(1) << "CertPathBuilder VerifyCertificateChain result = "
diff --git a/net/cert/internal/test_helpers.cc b/net/cert/internal/test_helpers.cc index 70bd6447..16c39cf1 100644 --- a/net/cert/internal/test_helpers.cc +++ b/net/cert/internal/test_helpers.cc
@@ -125,8 +125,7 @@ return ::testing::AssertionSuccess(); } -VerifyCertChainTest::VerifyCertChainTest() - : user_initial_policy_set{AnyPolicy()} {} +VerifyCertChainTest::VerifyCertChainTest() = default; VerifyCertChainTest::~VerifyCertChainTest() = default; bool VerifyCertChainTest::HasHighSeverityErrors() const {
diff --git a/net/cert/internal/test_helpers.h b/net/cert/internal/test_helpers.h index d8b1c69..dceb068 100644 --- a/net/cert/internal/test_helpers.h +++ b/net/cert/internal/test_helpers.h
@@ -95,16 +95,6 @@ // The Key Purpose to use when verifying the chain. KeyPurpose key_purpose = KeyPurpose::ANY_EKU; - InitialExplicitPolicy initial_explicit_policy = InitialExplicitPolicy::kFalse; - - std::set<der::Input> user_initial_policy_set; - - InitialPolicyMappingInhibit initial_policy_mapping_inhibit = - InitialPolicyMappingInhibit::kFalse; - - InitialAnyPolicyInhibit initial_any_policy_inhibit = - InitialAnyPolicyInhibit::kFalse; - // The expected errors/warnings from verification (as a string). std::string expected_errors;
diff --git a/net/cert/internal/verify_certificate_chain.cc b/net/cert/internal/verify_certificate_chain.cc index 3985cd8a..2560b942 100644 --- a/net/cert/internal/verify_certificate_chain.cc +++ b/net/cert/internal/verify_certificate_chain.cc
@@ -4,7 +4,6 @@ #include "net/cert/internal/verify_certificate_chain.h" -#include <algorithm> #include <memory> #include "base/logging.h" @@ -64,9 +63,6 @@ "The extended key usage does not include client auth"); DEFINE_CERT_ERROR_ID(kCertIsNotTrustAnchor, "Certificate is not a trust anchor"); -DEFINE_CERT_ERROR_ID(kNoValidPolicy, "No valid policy"); -DEFINE_CERT_ERROR_ID(kPolicyMappingAnyPolicy, - "PolicyMappings must not map anyPolicy"); bool IsHandledCriticalExtensionOid(const der::Input& oid) { if (oid == BasicConstraintsOid()) @@ -82,19 +78,8 @@ return true; if (oid == SubjectAltNameOid()) return true; - // TODO(eroman): The policy qualifiers are not processed (or in some cases - // even parsed). This is fine when the policies extension is non-critical, - // however if it is critical the code should also ensure that the policy - // qualifiers are only recognized ones (CPS and User Notice). - if (oid == CertificatePoliciesOid()) - return true; - if (oid == PolicyMappingsOid()) - return true; - if (oid == PolicyConstraintsOid()) - return true; - if (oid == InhibitAnyPolicyOid()) - return true; + // TODO(eroman): Make this more complete. return false; } @@ -135,7 +120,7 @@ // The validity period for a certificate is the period of time from // notBefore through notAfter, inclusive. void VerifyTimeValidity(const ParsedCertificate& cert, - const der::GeneralizedTime& time, + const der::GeneralizedTime time, CertErrors* errors) { if (time < cert.tbs().validity_not_before) errors->AddError(kValidityFailedNotBefore); @@ -231,545 +216,16 @@ } } -// Returns |true| if |policies| contains the OID |search_oid|. -bool SetContains(const std::set<der::Input>& policies, - const der::Input& search_oid) { - return policies.count(search_oid) > 0; -} - -// Representation of RFC 5280's "valid_policy_tree", used to keep track of the -// valid policies and policy re-mappings. -// -// ValidPolicyTree differs slightly from RFC 5280's description in that: -// -// (1) It does not track "qualifier_set". This is not needed as it is not -// output by this implementation. -// -// (2) It only stores the most recent level of the policy tree rather than -// the full tree of nodes. -class ValidPolicyTree { - public: - ValidPolicyTree() {} - - struct Node { - // |root_policy| is equivalent to |valid_policy|, but in the domain of the - // caller. - // - // The reason for this distinction is the Policy Mappings extension. - // - // So whereas |valid_policy| is in the remapped domain defined by the - // issuing certificate, |root_policy| is in the fixed domain of the caller. - // - // OIDs in "user_initial_policy_set" and "user_constrained_policy_set" are - // directly comparable to |root_policy| values, but not necessarily to - // |valid_policy|. - // - // In terms of the valid policy tree, |root_policy| can be found by - // starting at the node's root ancestor, and finding the first node with a - // valid_policy other than anyPolicy. This is effectively the same process - // as used during policy tree intersection in RFC 5280 6.1.5.g.iii.1 - der::Input root_policy; - - // The same as RFC 5280's "valid_policy" variable. - der::Input valid_policy; - - // The same as RFC 5280s "expected_policy_set" variable. - std::set<der::Input> expected_policy_set; - - // Note that RFC 5280's "qualifier_set" is omitted. - }; - - // Level represents all the nodes at depth "i" in the valid_policy_tree. - using Level = std::vector<Node>; - - // Initializes the ValidPolicyTree for the given "user_initial_policy_set". - // - // In RFC 5280, the valid_policy_tree is initialized to a root node at depth - // 0 of "anyPolicy"; the intersection with the "user_initial_policy_set" is - // done at the end (Wrap Up) as described in section 6.1.5 step g. - // - // Whereas in this implementation, the restriction on policies is added here, - // and intersecting the valid policy tree during Wrap Up is no longer needed. - // - // The final "user_constrained_policy_set" obtained will be the same. The - // advantages of this approach is simpler code. - void Init(const std::set<der::Input>& user_initial_policy_set) { - Clear(); - for (const der::Input& policy_oid : user_initial_policy_set) - AddRootNode(policy_oid); - } - - // Returns the current level (i.e. all nodes at depth i in the valid - // policy tree). - const Level& current_level() const { return current_level_; } - Level& current_level() { return current_level_; } - - // In RFC 5280 valid_policy_tree may be set to null. That is represented here - // by emptiness. - bool IsNull() const { return current_level_.empty(); } - void SetNull() { Clear(); } - - // This implementation keeps only the last level of the valid policy - // tree. Calling StartLevel() returns the nodes for the previous - // level, and starts a new level. - Level StartLevel() { - Level prev_level; - std::swap(prev_level, current_level_); - return prev_level; - } - - // Gets the set of policies (in terms of root authority's policy domain) that - // are valid at the curent level of the policy tree. - // - // For example: - // - // * If the valid policy tree was initialized with anyPolicy, then this - // function returns what X.509 calls "authorities-constrained-policy-set". - // - // * If the valid policy tree was instead initialized with the - // "user-initial-policy_set", then this function returns what X.509 - // calls "user-constrained-policy-set" - // ("authorities-constrained-policy-set" intersected with the - // "user-initial-policy-set"). - void GetValidRootPolicySet(std::set<der::Input>* policy_set) { - policy_set->clear(); - for (const Node& node : current_level_) - policy_set->insert(node.root_policy); - - // If the result includes anyPolicy, simplify it to a set of size 1. - if (policy_set->size() > 1 && SetContains(*policy_set, AnyPolicy())) - *policy_set = {AnyPolicy()}; - } - - // Adds a node |n| to the current level which is a child of |parent| - // such that: - // * n.valid_policy = policy_oid - // * n.expected_policy_set = {policy_oid} - void AddNode(const Node& parent, const der::Input& policy_oid) { - AddNodeWithExpectedPolicySet(parent, policy_oid, {policy_oid}); - } - - // Adds a node |n| to the current level which is a child of |parent| - // such that: - // * n.valid_policy = policy_oid - // * n.expected_policy_set = expected_policy_set - void AddNodeWithExpectedPolicySet( - const Node& parent, - const der::Input& policy_oid, - const std::set<der::Input>& expected_policy_set) { - Node new_node; - new_node.valid_policy = policy_oid; - new_node.expected_policy_set = expected_policy_set; - - // Consider the root policy as the first policy other than anyPolicy (or - // anyPolicy if it hasn't been restricted yet). - new_node.root_policy = - (parent.root_policy == AnyPolicy()) ? policy_oid : parent.root_policy; - - current_level_.push_back(std::move(new_node)); - } - - // Returns the first node having valid_policy == anyPolicy in |level|, or - // nullptr if there is none. - static const Node* FindAnyPolicyNode(const Level& level) { - for (const Node& node : level) { - if (node.valid_policy == AnyPolicy()) - return &node; - } - return nullptr; - } - - // Deletes all nodes |n| in |level| where |n.valid_policy| matches the given - // |valid_policy|. This may re-order the nodes in |level|. - static void DeleteNodesMatchingValidPolicy(const der::Input& valid_policy, - Level* level) { - // This works by swapping nodes to the end of the vector, and then doing a - // single resize to delete them all. - auto cur = level->begin(); - auto end = level->end(); - while (cur != end) { - bool should_delete_node = cur->valid_policy == valid_policy; - if (should_delete_node) { - end = std::prev(end); - std::iter_swap(cur, end); - } else { - ++cur; - } - } - level->erase(end, level->end()); - } - - private: - // Deletes all nodes in the valid policy tree. - void Clear() { current_level_.clear(); } - - // Adds a node to the current level for OID |policy_oid|. The current level - // is assumed to be the root level. - void AddRootNode(const der::Input& policy_oid) { - Node new_node; - new_node.root_policy = policy_oid; - new_node.valid_policy = policy_oid; - new_node.expected_policy_set = {policy_oid}; - current_level_.push_back(std::move(new_node)); - } - - Level current_level_; - - DISALLOW_COPY_AND_ASSIGN(ValidPolicyTree); -}; - -// Class that encapsulates the state variables used by certificate path -// validation. -class PathVerifier { - public: - // Same parameters and meaning as VerifyCertificateChain(). - void Run(const ParsedCertificateList& certs, - const CertificateTrust& last_cert_trust, - const SignaturePolicy* signature_policy, - const der::GeneralizedTime& time, - KeyPurpose required_key_purpose, - InitialExplicitPolicy initial_explicit_policy, - const std::set<der::Input>& user_initial_policy_set, - InitialPolicyMappingInhibit initial_policy_mapping_inhibit, - InitialAnyPolicyInhibit initial_any_policy_inhibit, - std::set<der::Input>* user_constrained_policy_set, - CertPathErrors* errors); - - private: - // Verifies and updates the valid policies. This corresponds with RFC 5280 - // section 6.1.3 steps d-f. - void VerifyPolicies(const ParsedCertificate& cert, - bool is_target_cert, - CertErrors* errors); - - // Applies the policy mappings. This corresponds with RFC 5280 section 6.1.4 - // steps a-b. - void VerifyPolicyMappings(const ParsedCertificate& cert, CertErrors* errors); - - // This function corresponds to RFC 5280 section 6.1.3's "Basic Certificate - // Processing" procedure. - void BasicCertificateProcessing(const ParsedCertificate& cert, - bool is_target_cert, - const SignaturePolicy* signature_policy, - const der::GeneralizedTime& time, - KeyPurpose required_key_purpose, - CertErrors* errors); - - // This function corresponds to RFC 5280 section 6.1.4's "Preparation for - // Certificate i+1" procedure. |cert| is expected to be an intermediate. - void PrepareForNextCertificate(const ParsedCertificate& cert, - CertErrors* errors); - - // This function corresponds with RFC 5280 section 6.1.5's "Wrap-Up - // Procedure". It does processing for the final certificate (the target cert). - void WrapUp(const ParsedCertificate& cert, CertErrors* errors); - - // Enforces trust anchor constraints compatibile with RFC 5937. - // - // Note that the anchor constraints are encoded via the attached certificate - // itself. - void ApplyTrustAnchorConstraints(const ParsedCertificate& cert, - KeyPurpose required_key_purpose, - CertErrors* errors); - - // Initializes the path validation algorithm given anchor constraints. This - // follows the description in RFC 5937 - void ProcessRootCertificate(const ParsedCertificate& cert, - const CertificateTrust& trust, - KeyPurpose required_key_purpose, - CertErrors* errors); - - ValidPolicyTree valid_policy_tree_; - - // Will contain a NameConstraints for each previous cert in the chain which - // had nameConstraints. This corresponds to the permitted_subtrees and - // excluded_subtrees state variables from RFC 5280. - std::vector<const NameConstraints*> name_constraints_list_; - - // |explicit_policy_| corresponds with the same named variable from RFC 5280 - // section 6.1.2: - // - // explicit_policy: an integer that indicates if a non-NULL - // valid_policy_tree is required. The integer indicates the - // number of non-self-issued certificates to be processed before - // this requirement is imposed. Once set, this variable may be - // decreased, but may not be increased. That is, if a certificate in the - // path requires a non-NULL valid_policy_tree, a later certificate cannot - // remove this requirement. If initial-explicit-policy is set, then the - // initial value is 0, otherwise the initial value is n+1. - size_t explicit_policy_; - - // |inhibit_any_policy_| corresponds with the same named variable from RFC - // 5280 section 6.1.2: - // - // inhibit_anyPolicy: an integer that indicates whether the - // anyPolicy policy identifier is considered a match. The - // integer indicates the number of non-self-issued certificates - // to be processed before the anyPolicy OID, if asserted in a - // certificate other than an intermediate self-issued - // certificate, is ignored. Once set, this variable may be - // decreased, but may not be increased. That is, if a - // certificate in the path inhibits processing of anyPolicy, a - // later certificate cannot permit it. If initial-any-policy- - // inhibit is set, then the initial value is 0, otherwise the - // initial value is n+1. - size_t inhibit_any_policy_; - - // |policy_mapping_| corresponds with the same named variable from RFC 5280 - // section 6.1.2: - // - // policy_mapping: an integer that indicates if policy mapping - // is permitted. The integer indicates the number of non-self- - // issued certificates to be processed before policy mapping is - // inhibited. Once set, this variable may be decreased, but may - // not be increased. That is, if a certificate in the path - // specifies that policy mapping is not permitted, it cannot be - // overridden by a later certificate. If initial-policy- - // mapping-inhibit is set, then the initial value is 0, - // otherwise the initial value is n+1. - size_t policy_mapping_; - - // |working_spki_| is an amalgamation of 3 separate variables from RFC 5280: - // * working_public_key - // * working_public_key_algorithm - // * working_public_key_parameters - // - // They are combined for simplicity since the signature verification takes an - // SPKI, and the parameter inheritence is not applicable for the supported - // key types. - // - // An approximate explanation of |working_spki| is this description from RFC - // 5280 section 6.1.2: - // - // working_public_key: the public key used to verify the - // signature of a certificate. - der::Input working_spki_; - - // |working_normalized_issuer_name_| is the normalized value of the - // working_issuer_name variable in RFC 5280 section 6.1.2: - // - // working_issuer_name: the issuer distinguished name expected - // in the next certificate in the chain. - der::Input working_normalized_issuer_name_; - - // |max_path_length_| corresponds with the same named variable in RFC 5280 - // section 6.1.2. - // - // max_path_length: this integer is initialized to n, is - // decremented for each non-self-issued certificate in the path, - // and may be reduced to the value in the path length constraint - // field within the basic constraints extension of a CA - // certificate. - size_t max_path_length_; -}; - -void PathVerifier::VerifyPolicies(const ParsedCertificate& cert, - bool is_target_cert, - CertErrors* errors) { - // From RFC 5280 section 6.1.3: - // - // (d) If the certificate policies extension is present in the - // certificate and the valid_policy_tree is not NULL, process - // the policy information by performing the following steps in - // order: - if (cert.has_policy_oids() && !valid_policy_tree_.IsNull()) { - ValidPolicyTree::Level previous_level = valid_policy_tree_.StartLevel(); - - // Identify if there was a node with valid_policy == anyPolicy at depth i-1. - const ValidPolicyTree::Node* any_policy_node_prev_level = - ValidPolicyTree::FindAnyPolicyNode(previous_level); - - // (1) For each policy P not equal to anyPolicy in the - // certificate policies extension, let P-OID denote the OID - // for policy P and P-Q denote the qualifier set for policy - // P. Perform the following steps in order: - bool cert_has_any_policy = false; - for (const der::Input& p_oid : cert.policy_oids()) { - if (p_oid == AnyPolicy()) { - cert_has_any_policy = true; - continue; - } - - // (i) For each node of depth i-1 in the valid_policy_tree - // where P-OID is in the expected_policy_set, create a - // child node as follows: set the valid_policy to P-OID, - // set the qualifier_set to P-Q, and set the - // expected_policy_set to {P-OID}. - bool found_match = false; - for (const ValidPolicyTree::Node& prev_node : previous_level) { - if (SetContains(prev_node.expected_policy_set, p_oid)) { - valid_policy_tree_.AddNode(prev_node, p_oid); - found_match = true; - } - } - - // (ii) If there was no match in step (i) and the - // valid_policy_tree includes a node of depth i-1 with - // the valid_policy anyPolicy, generate a child node with - // the following values: set the valid_policy to P-OID, - // set the qualifier_set to P-Q, and set the - // expected_policy_set to {P-OID}. - if (!found_match && any_policy_node_prev_level) - valid_policy_tree_.AddNode(*any_policy_node_prev_level, p_oid); - } - - // (2) If the certificate policies extension includes the policy - // anyPolicy with the qualifier set AP-Q and either (a) - // inhibit_anyPolicy is greater than 0 or (b) i<n and the - // certificate is self-issued, then: - // - // For each node in the valid_policy_tree of depth i-1, for - // each value in the expected_policy_set (including - // anyPolicy) that does not appear in a child node, create a - // child node with the following values: set the valid_policy - // to the value from the expected_policy_set in the parent - // node, set the qualifier_set to AP-Q, and set the - // expected_policy_set to the value in the valid_policy from - // this node. - if (cert_has_any_policy && ((inhibit_any_policy_ > 0) || - (!is_target_cert && IsSelfIssued(cert)))) { - // Keep track of the existing policies at depth i. - std::set<der::Input> child_node_policies; - for (const ValidPolicyTree::Node& node : - valid_policy_tree_.current_level()) - child_node_policies.insert(node.valid_policy); - - for (const ValidPolicyTree::Node& prev_node : previous_level) { - for (const der::Input& expected_policy : - prev_node.expected_policy_set) { - if (!SetContains(child_node_policies, expected_policy)) { - child_node_policies.insert(expected_policy); - valid_policy_tree_.AddNode(prev_node, expected_policy); - } - } - } - } - - // (3) If there is a node in the valid_policy_tree of depth i-1 - // or less without any child nodes, delete that node. Repeat - // this step until there are no nodes of depth i-1 or less - // without children. - // - // Nothing needs to be done for this step, since this implementation only - // stores the nodes at depth i, and the entire level has already been - // calculated. - } - - // (e) If the certificate policies extension is not present, set the - // valid_policy_tree to NULL. - if (!cert.has_policy_oids()) - valid_policy_tree_.SetNull(); - - // (f) Verify that either explicit_policy is greater than 0 or the - // valid_policy_tree is not equal to NULL; - if (!((explicit_policy_ > 0) || !valid_policy_tree_.IsNull())) - errors->AddError(kNoValidPolicy); -} - -void PathVerifier::VerifyPolicyMappings(const ParsedCertificate& cert, - CertErrors* errors) { - if (!cert.has_policy_mappings()) - return; - - // From RFC 5280 section 6.1.4: - // - // (a) If a policy mappings extension is present, verify that the - // special value anyPolicy does not appear as an - // issuerDomainPolicy or a subjectDomainPolicy. - for (const ParsedPolicyMapping& mapping : cert.policy_mappings()) { - if (mapping.issuer_domain_policy == AnyPolicy() || - mapping.subject_domain_policy == AnyPolicy()) { - // Because this implementation continues processing certificates after - // this error, clear the valid policy tree to ensure the - // "user_constrained_policy_set" output upon failure is empty. - valid_policy_tree_.SetNull(); - errors->AddError(kPolicyMappingAnyPolicy); - } - } - - // (b) If a policy mappings extension is present, then for each - // issuerDomainPolicy ID-P in the policy mappings extension: - // - // (1) If the policy_mapping variable is greater than 0, for each - // node in the valid_policy_tree of depth i where ID-P is the - // valid_policy, set expected_policy_set to the set of - // subjectDomainPolicy values that are specified as - // equivalent to ID-P by the policy mappings extension. - // - // If no node of depth i in the valid_policy_tree has a - // valid_policy of ID-P but there is a node of depth i with a - // valid_policy of anyPolicy, then generate a child node of - // the node of depth i-1 that has a valid_policy of anyPolicy - // as follows: - // - // (i) set the valid_policy to ID-P; - // - // (ii) set the qualifier_set to the qualifier set of the - // policy anyPolicy in the certificate policies - // extension of certificate i; and - // - // (iii) set the expected_policy_set to the set of - // subjectDomainPolicy values that are specified as - // equivalent to ID-P by the policy mappings extension. - // - if (policy_mapping_ > 0) { - const ValidPolicyTree::Node* any_policy_node = - ValidPolicyTree::FindAnyPolicyNode(valid_policy_tree_.current_level()); - - // Group mappings by issuer domain policy. - std::map<der::Input, std::set<der::Input>> mappings; - for (const ParsedPolicyMapping& mapping : cert.policy_mappings()) { - mappings[mapping.issuer_domain_policy].insert( - mapping.subject_domain_policy); - } - - for (const auto& it : mappings) { - const der::Input& issuer_domain_policy = it.first; - const std::set<der::Input>& subject_domain_policies = it.second; - bool found_node = false; - - for (ValidPolicyTree::Node& node : valid_policy_tree_.current_level()) { - if (node.valid_policy == issuer_domain_policy) { - node.expected_policy_set = subject_domain_policies; - found_node = true; - } - } - - if (!found_node && any_policy_node) { - valid_policy_tree_.AddNodeWithExpectedPolicySet( - *any_policy_node, issuer_domain_policy, subject_domain_policies); - } - } - } - - // (b) If a policy mappings extension is present, then for each - // issuerDomainPolicy ID-P in the policy mappings extension: - // - // ... - // - // (2) If the policy_mapping variable is equal to 0: - // - // (i) delete each node of depth i in the valid_policy_tree - // where ID-P is the valid_policy. - // - // (ii) If there is a node in the valid_policy_tree of depth - // i-1 or less without any child nodes, delete that - // node. Repeat this step until there are no nodes of - // depth i-1 or less without children. - if (policy_mapping_ == 0) { - for (const ParsedPolicyMapping& mapping : cert.policy_mappings()) { - ValidPolicyTree::DeleteNodesMatchingValidPolicy( - mapping.issuer_domain_policy, &valid_policy_tree_.current_level()); - } - } -} - -void PathVerifier::BasicCertificateProcessing( +// This function corresponds to RFC 5280 section 6.1.3's "Basic Certificate +// Processing" procedure. +void BasicCertificateProcessing( const ParsedCertificate& cert, bool is_target_cert, const SignaturePolicy* signature_policy, const der::GeneralizedTime& time, - KeyPurpose required_key_purpose, + const der::Input& working_spki, + const der::Input& working_normalized_issuer_name, + const std::vector<const NameConstraints*>& name_constraints_list, CertErrors* errors) { // Check that the signature algorithms in Certificate vs TBSCertificate // match. This isn't part of RFC 5280 section 6.1.3, but is mandated by @@ -779,7 +235,7 @@ // Verify the digital signature using the previous certificate's key (RFC // 5280 section 6.1.3 step a.1). if (!VerifySignedData(cert.signature_algorithm(), cert.tbs_certificate_tlv(), - cert.signature_value(), working_spki_, signature_policy, + cert.signature_value(), working_spki, signature_policy, errors)) { errors->AddError(kVerifySignedDataFailed); } @@ -793,15 +249,15 @@ // Verify the certificate's issuer name matches the issuing certificate's // subject name. (RFC 5280 section 6.1.3 step a.4) - if (cert.normalized_issuer() != working_normalized_issuer_name_) + if (cert.normalized_issuer() != working_normalized_issuer_name) errors->AddError(kSubjectDoesNotMatchIssuer); // Name constraints (RFC 5280 section 6.1.3 step b & c) // If certificate i is self-issued and it is not the final certificate in the // path, skip this step for certificate i. - if (!name_constraints_list_.empty() && + if (!name_constraints_list.empty() && (!IsSelfIssued(cert) || is_target_cert)) { - for (const NameConstraints* nc : name_constraints_list_) { + for (const NameConstraints* nc : name_constraints_list) { if (!nc->IsPermittedCert(cert.normalized_subject(), cert.subject_alt_names())) { errors->AddError(kNotPermittedByNameConstraints); @@ -809,30 +265,31 @@ } } - // RFC 5280 section 6.1.3 step d - f. - VerifyPolicies(cert, is_target_cert, errors); - - // The key purpose is checked not just for the end-entity certificate, but - // also interpreted as a constraint when it appears in intermediates. This - // goes beyond what RFC 5280 describes, but is the de-facto standard. See - // https://wiki.mozilla.org/CA:CertificatePolicyV2.1#Frequently_Asked_Questions - VerifyExtendedKeyUsage(cert, required_key_purpose, errors); + // TODO(eroman): Steps d-f are omitted, as policy constraints are not yet + // implemented. } -void PathVerifier::PrepareForNextCertificate(const ParsedCertificate& cert, - CertErrors* errors) { - // RFC 5280 section 6.1.4 step a-b - VerifyPolicyMappings(cert, errors); +// This function corresponds to RFC 5280 section 6.1.4's "Preparation for +// Certificate i+1" procedure. |cert| is expected to be an intermediate. +void PrepareForNextCertificate( + const ParsedCertificate& cert, + size_t* max_path_length_ptr, + der::Input* working_spki, + der::Input* working_normalized_issuer_name, + std::vector<const NameConstraints*>* name_constraints_list, + CertErrors* errors) { + // TODO(crbug.com/634456): Steps a-b are omitted, as policy mappings are not + // yet implemented. // From RFC 5280 section 6.1.4 step c: // // Assign the certificate subject name to working_normalized_issuer_name. - working_normalized_issuer_name_ = cert.normalized_subject(); + *working_normalized_issuer_name = cert.normalized_subject(); // From RFC 5280 section 6.1.4 step d: // // Assign the certificate subjectPublicKey to working_public_key. - working_spki_ = cert.tbs().spki_tlv; + *working_spki = cert.tbs().spki_tlv; // Note that steps e and f are omitted as they are handled by // the assignment to |working_spki| above. See the definition @@ -840,53 +297,10 @@ // From RFC 5280 section 6.1.4 step g: if (cert.has_name_constraints()) - name_constraints_list_.push_back(&cert.name_constraints()); + name_constraints_list->push_back(&cert.name_constraints()); - // (h) If certificate i is not self-issued: - if (!IsSelfIssued(cert)) { - // (1) If explicit_policy is not 0, decrement explicit_policy by - // 1. - if (explicit_policy_ > 0) - explicit_policy_ -= 1; - - // (2) If policy_mapping is not 0, decrement policy_mapping by 1. - if (policy_mapping_ > 0) - policy_mapping_ -= 1; - - // (3) If inhibit_anyPolicy is not 0, decrement inhibit_anyPolicy - // by 1. - if (inhibit_any_policy_ > 0) - inhibit_any_policy_ -= 1; - } - - // (i) If a policy constraints extension is included in the - // certificate, modify the explicit_policy and policy_mapping - // state variables as follows: - if (cert.has_policy_constraints()) { - // (1) If requireExplicitPolicy is present and is less than - // explicit_policy, set explicit_policy to the value of - // requireExplicitPolicy. - if (cert.policy_constraints().has_require_explicit_policy && - cert.policy_constraints().require_explicit_policy < explicit_policy_) { - explicit_policy_ = cert.policy_constraints().require_explicit_policy; - } - - // (2) If inhibitPolicyMapping is present and is less than - // policy_mapping, set policy_mapping to the value of - // inhibitPolicyMapping. - if (cert.policy_constraints().has_inhibit_policy_mapping && - cert.policy_constraints().inhibit_policy_mapping < policy_mapping_) { - policy_mapping_ = cert.policy_constraints().inhibit_policy_mapping; - } - } - - // (j) If the inhibitAnyPolicy extension is included in the - // certificate and is less than inhibit_anyPolicy, set - // inhibit_anyPolicy to the value of inhibitAnyPolicy. - if (cert.has_inhibit_any_policy() && - cert.inhibit_any_policy() < inhibit_any_policy_) { - inhibit_any_policy_ = cert.inhibit_any_policy(); - } + // TODO(eroman): Steps h-j are omitted as policy + // constraints/mappings/inhibitAnyPolicy are not yet implemented. // From RFC 5280 section 6.1.4 step k: // @@ -913,10 +327,10 @@ // max_path_length is greater than zero and decrement // max_path_length by 1. if (!IsSelfIssued(cert)) { - if (max_path_length_ == 0) { + if (*max_path_length_ptr == 0) { errors->AddError(kMaxPathLengthViolated); } else { - --max_path_length_; + --(*max_path_length_ptr); } } @@ -926,8 +340,8 @@ // less than max_path_length, set max_path_length to the value // of pathLenConstraint. if (cert.has_basic_constraints() && cert.basic_constraints().has_path_len && - cert.basic_constraints().path_len < max_path_length_) { - max_path_length_ = cert.basic_constraints().path_len; + cert.basic_constraints().path_len < *max_path_length_ptr) { + *max_path_length_ptr = cert.basic_constraints().path_len; } // From RFC 5280 section 6.1.4 step n: @@ -994,22 +408,13 @@ } } -void PathVerifier::WrapUp(const ParsedCertificate& cert, CertErrors* errors) { - // From RFC 5280 section 6.1.5: - // (a) If explicit_policy is not 0, decrement explicit_policy by 1. - if (explicit_policy_ > 0) - explicit_policy_ -= 1; +// This function corresponds with RFC 5280 section 6.1.5's "Wrap-Up Procedure". +// It does processing for the final certificate (the target cert). +void WrapUp(const ParsedCertificate& cert, CertErrors* errors) { + // TODO(crbug.com/634452): Steps a-b are omitted as policy constraints are not + // yet implemented. - // (b) If a policy constraints extension is included in the - // certificate and requireExplicitPolicy is present and has a - // value of 0, set the explicit_policy state variable to 0. - if (cert.has_policy_constraints() && - cert.policy_constraints().has_require_explicit_policy && - cert.policy_constraints().require_explicit_policy == 0) { - explicit_policy_ = 0; - } - - // Note step c-e are omitted as the verification function does + // Note step c-e are omitted the verification function does // not output the working public key. // From RFC 5280 section 6.1.5 step f: @@ -1023,24 +428,24 @@ // directly match the procedures in RFC 5280's section 6.1. VerifyNoUnconsumedCriticalExtensions(cert, errors); - // RFC 5280 section 6.1.5 step g is skipped, as the intersection of valid - // policies was computed during previous steps. - // - // If either (1) the value of explicit_policy variable is greater than - // zero or (2) the valid_policy_tree is not NULL, then path processing - // has succeeded. - if (!(explicit_policy_ > 0 || !valid_policy_tree_.IsNull())) { - errors->AddError(kNoValidPolicy); - } + // TODO(eroman): Step g is omitted, as policy constraints are not yet + // implemented. // The following check is NOT part of RFC 5280 6.1.5's "Wrap-Up Procedure", // however is implied by RFC 5280 section 4.2.1.9. VerifyTargetCertHasConsistentCaBits(cert, errors); } -void PathVerifier::ApplyTrustAnchorConstraints(const ParsedCertificate& cert, - KeyPurpose required_key_purpose, - CertErrors* errors) { +// Enforces trust anchor constraints compatibile with RFC 5937. +// +// Note that the anchor constraints are encoded via the attached certificate +// itself. +void ApplyTrustAnchorConstraints( + const ParsedCertificate& cert, + KeyPurpose required_key_purpose, + size_t* max_path_length_ptr, + std::vector<const NameConstraints*>* name_constraints_list, + CertErrors* errors) { // This is not part of RFC 5937 nor RFC 5280, but matches the EKU handling // done for intermediates (described in Web PKI's Baseline Requirements). VerifyExtendedKeyUsage(cert, required_key_purpose, errors); @@ -1049,7 +454,7 @@ // Initialize name constraints initial-permitted/excluded-subtrees. if (cert.has_name_constraints()) - name_constraints_list_.push_back(&cert.name_constraints()); + name_constraints_list->push_back(&cert.name_constraints()); // TODO(eroman): Initialize user-initial-policy-set based on anchor // constraints. @@ -1072,7 +477,7 @@ // NOTE: RFC 5937 does not say to enforce the CA=true part of basic // constraints. if (cert.has_basic_constraints() && cert.basic_constraints().has_path_len) - max_path_length_ = cert.basic_constraints().path_len; + *max_path_length_ptr = cert.basic_constraints().path_len; // From RFC 5937 section 2: // @@ -1082,15 +487,22 @@ VerifyNoUnconsumedCriticalExtensions(cert, errors); } -void PathVerifier::ProcessRootCertificate(const ParsedCertificate& cert, - const CertificateTrust& trust, - KeyPurpose required_key_purpose, - CertErrors* errors) { +// Initializes the path validation algorithm given anchor constraints. This +// follows the description in RFC 5937 +void ProcessRootCertificate( + const ParsedCertificate& cert, + const CertificateTrust& trust, + KeyPurpose required_key_purpose, + size_t* max_path_length_ptr, + std::vector<const NameConstraints*>* name_constraints_list, + der::Input* working_spki, + der::Input* working_normalized_issuer_name, + CertErrors* errors) { // Use the certificate's SPKI and subject when verifying the next certificate. // Note this is initialized even in the case of untrusted roots (they already // emit an error for the distrust). - working_spki_ = cert.tbs().spki_tlv; - working_normalized_issuer_name_ = cert.normalized_subject(); + *working_spki = cert.tbs().spki_tlv; + *working_normalized_issuer_name = cert.normalized_subject(); switch (trust.type) { case CertificateTrustType::UNSPECIFIED: @@ -1105,26 +517,24 @@ case CertificateTrustType::TRUSTED_ANCHOR_WITH_CONSTRAINTS: // If the trust anchor has constraints, enforce them. if (trust.type == CertificateTrustType::TRUSTED_ANCHOR_WITH_CONSTRAINTS) { - ApplyTrustAnchorConstraints(cert, required_key_purpose, errors); + ApplyTrustAnchorConstraints(cert, required_key_purpose, + max_path_length_ptr, name_constraints_list, + errors); } break; } } -void PathVerifier::Run( - const ParsedCertificateList& certs, - const CertificateTrust& last_cert_trust, - const SignaturePolicy* signature_policy, - const der::GeneralizedTime& time, - KeyPurpose required_key_purpose, - InitialExplicitPolicy initial_explicit_policy, - const std::set<der::Input>& user_initial_policy_set, - InitialPolicyMappingInhibit initial_policy_mapping_inhibit, - InitialAnyPolicyInhibit initial_any_policy_inhibit, - std::set<der::Input>* user_constrained_policy_set, - CertPathErrors* errors) { - // This implementation is structured to mimic the description of certificate - // path verification given by RFC 5280 section 6.1. +} // namespace + +// This implementation is structured to mimic the description of certificate +// path verification given by RFC 5280 section 6.1. +void VerifyCertificateChain(const ParsedCertificateList& certs, + const CertificateTrust& last_cert_trust, + const SignaturePolicy* signature_policy, + const der::GeneralizedTime& time, + KeyPurpose required_key_purpose, + CertPathErrors* errors) { DCHECK(signature_policy); DCHECK(errors); @@ -1141,48 +551,50 @@ return; } - // RFC 5280's "n" variable is the length of the path, which does not count - // the trust anchor. (Although in practice it doesn't really change behaviors - // if n is used in place of n+1). - const size_t n = certs.size() - 1; + // Will contain a NameConstraints for each previous cert in the chain which + // had nameConstraints. This corresponds to the permitted_subtrees and + // excluded_subtrees state variables from RFC 5280. + std::vector<const NameConstraints*> name_constraints_list; - valid_policy_tree_.Init(user_initial_policy_set); - - // RFC 5280 section section 6.1.2: + // |working_spki| is an amalgamation of 3 separate variables from RFC 5280: + // * working_public_key + // * working_public_key_algorithm + // * working_public_key_parameters // - // If initial-explicit-policy is set, then the initial value - // [of explicit_policy] is 0, otherwise the initial value is n+1. - explicit_policy_ = - initial_explicit_policy == InitialExplicitPolicy::kTrue ? 0 : n + 1; - - // RFC 5280 section section 6.1.2: + // They are combined for simplicity since the signature verification takes an + // SPKI, and the parameter inheritence is not applicable for the supported + // key types. // - // If initial-any-policy-inhibit is set, then the initial value - // [of inhibit_anyPolicy] is 0, otherwise the initial value is n+1. - inhibit_any_policy_ = - initial_any_policy_inhibit == InitialAnyPolicyInhibit::kTrue ? 0 : n + 1; - - // RFC 5280 section section 6.1.2: + // An approximate explanation of |working_spki| is this description from RFC + // 5280 section 6.1.2: // - // If initial-policy-mapping-inhibit is set, then the initial value - // [of policy_mapping] is 0, otherwise the initial value is n+1. - policy_mapping_ = - initial_policy_mapping_inhibit == InitialPolicyMappingInhibit::kTrue - ? 0 - : n + 1; + // working_public_key: the public key used to verify the + // signature of a certificate. + der::Input working_spki; - // RFC 5280 section section 6.1.2: + // |working_normalized_issuer_name| is the normalized value of the + // working_issuer_name variable in RFC 5280 section 6.1.2: // - // max_path_length: this integer is initialized to n, ... - max_path_length_ = n; + // working_issuer_name: the issuer distinguished name expected + // in the next certificate in the chain. + der::Input working_normalized_issuer_name; + + // |max_path_length| corresponds with the same named variable in RFC 5280 + // section 6.1.2: + // + // max_path_length: this integer is initialized to n, is + // decremented for each non-self-issued certificate in the path, + // and may be reduced to the value in the path length constraint + // field within the basic constraints extension of a CA + // certificate. + size_t max_path_length = certs.size(); // Iterate over all the certificates in the reverse direction: starting from // the root certificate and progressing towards the target certificate. // - // * i=0 : Root certificate (i.e. trust anchor) - // * i=1 : Certificate issued by root - // * i=x : Certificate i=x is issued by certificate i=x-1 - // * i=n : Target certificate. + // * i=0 : Root certificate (i.e. trust anchor) + // * i=1 : Certificated signed by the root certificate + // * i=certs.size()-1 : Target certificate. for (size_t i = 0; i < certs.size(); ++i) { const size_t index_into_certs = certs.size() - i - 1; @@ -1200,6 +612,8 @@ if (is_root_cert) { ProcessRootCertificate(cert, last_cert_trust, required_key_purpose, + &max_path_length, &name_constraints_list, + &working_spki, &working_normalized_issuer_name, cert_errors); // Don't do any other checks for root certificates. @@ -1212,45 +626,28 @@ // - Then run "Wrap up" // - Otherwise run "Prepare for Next cert" BasicCertificateProcessing(cert, is_target_cert, signature_policy, time, - required_key_purpose, cert_errors); + working_spki, working_normalized_issuer_name, + name_constraints_list, cert_errors); + + // The key purpose is checked not just for the end-entity certificate, but + // also interpreted as a constraint when it appears in intermediates. This + // goes beyond what RFC 5280 describes, but is the de-facto standard. See + // https://wiki.mozilla.org/CA:CertificatePolicyV2.1#Frequently_Asked_Questions + VerifyExtendedKeyUsage(cert, required_key_purpose, cert_errors); + if (!is_target_cert) { - PrepareForNextCertificate(cert, cert_errors); + PrepareForNextCertificate(cert, &max_path_length, &working_spki, + &working_normalized_issuer_name, + &name_constraints_list, cert_errors); } else { WrapUp(cert, cert_errors); } } - if (user_constrained_policy_set) { - // valid_policy_tree_ already contains the intersection of valid policies - // with user_initial_policy_set. - valid_policy_tree_.GetValidRootPolicySet(user_constrained_policy_set); - } - // TODO(eroman): RFC 5280 forbids duplicate certificates per section 6.1: // // A certificate MUST NOT appear more than once in a prospective // certification path. } -} // namespace - -void VerifyCertificateChain( - const ParsedCertificateList& certs, - const CertificateTrust& last_cert_trust, - const SignaturePolicy* signature_policy, - const der::GeneralizedTime& time, - KeyPurpose required_key_purpose, - InitialExplicitPolicy initial_explicit_policy, - const std::set<der::Input>& user_initial_policy_set, - InitialPolicyMappingInhibit initial_policy_mapping_inhibit, - InitialAnyPolicyInhibit initial_any_policy_inhibit, - std::set<der::Input>* user_constrained_policy_set, - CertPathErrors* errors) { - PathVerifier verifier; - verifier.Run(certs, last_cert_trust, signature_policy, time, - required_key_purpose, initial_explicit_policy, - user_initial_policy_set, initial_policy_mapping_inhibit, - initial_any_policy_inhibit, user_constrained_policy_set, errors); -} - } // namespace net
diff --git a/net/cert/internal/verify_certificate_chain.h b/net/cert/internal/verify_certificate_chain.h index a8b2917..8d1f044 100644 --- a/net/cert/internal/verify_certificate_chain.h +++ b/net/cert/internal/verify_certificate_chain.h
@@ -5,7 +5,7 @@ #ifndef NET_CERT_INTERNAL_VERIFY_CERTIFICATE_CHAIN_H_ #define NET_CERT_INTERNAL_VERIFY_CERTIFICATE_CHAIN_H_ -#include <set> +#include <vector> #include "base/compiler_specific.h" #include "base/memory/ref_counted.h" @@ -30,160 +30,72 @@ CLIENT_AUTH, }; -enum class InitialExplicitPolicy { - kFalse, - kTrue, -}; - -enum class InitialPolicyMappingInhibit { - kFalse, - kTrue, -}; - -enum class InitialAnyPolicyInhibit { - kFalse, - kTrue, -}; - // VerifyCertificateChain() verifies an ordered certificate path in accordance -// with RFC 5280's "Certification Path Validation" algorithm (section 6). +// with RFC 5280 (with some modifications [1]). // -// ----------------------------------------- -// Deviations from RFC 5280 -// ----------------------------------------- +// [1] Deviations from RFC 5280: // -// * If Extended Key Usage appears on intermediates, it is treated as -// a restriction on subordinate certificates. +// * If Extended Key Usage appears on intermediates it is treated as a +// restriction on subordinate certificates. // -// ----------------------------------------- -// Additional responsibilities of the caller -// ----------------------------------------- -// -// After successful path verification, the caller is responsible for -// subsequently checking: +// The caller is responsible for additionally checking: // // * The end-entity's KeyUsage before using its SPKI. -// * The end-entity's name/subjectAltName. Name constraints from intermediates -// will have already been applied, so it is sufficient to check the -// end-entity for a match. +// * The end-entity's name/subjectAltName (note that name constraints from +// intermediates will have already been applied, so just need to check +// the end-entity for a match). +// * Policies +// +// WARNING: This implementation is in progress, and is currently incomplete. +// Consult an OWNER before using it. +// +// TODO(eroman): Take a CertPath instead of ParsedCertificateList + +// TrustAnchor. // // --------- // Inputs // --------- // -// certs: -// A non-empty chain of DER-encoded certificates, listed in the -// "forward" direction. The first certificate is the target -// certificate to verify, and the last certificate has trustedness -// given by |last_cert_trust| (generally a trust anchor). +// cert_chain: +// A non-empty chain of N DER-encoded certificates, listed in the +// "forward" direction. The first certificate is the target certificate to +// verify, and the last certificate has trustedness given by +// |last_cert_trust|. // -// * certs[0] is the target certificate to verify. -// * certs[i+1] holds the certificate that issued cert_chain[i]. -// * certs[N-1] the root certificate -// -// Note that THIS IS NOT identical in meaning to the same named -// "certs" input defined in RFC 5280 section 6.1.1.a. The differences -// are: -// -// * The order of certificates is reversed -// * In RFC 5280 "certs" DOES NOT include the trust anchor +// * cert_chain[0] is the target certificate to verify. +// * cert_chain[i+1] holds the certificate that issued cert_chain[i]. +// * cert_chain[N-1] the root certificate // // last_cert_trust: -// Trustedness of |certs.back()|. The trustedness of |certs.back()| -// MUST BE decided by the caller -- this function takes it purely as -// an input. Moreover, the CertificateTrust can be used to specify -// trust anchor constraints. -// -// This combined with |certs.back()| (the root certificate) fills a -// similar role to "trust anchor information" defined in RFC 5280 -// section 6.1.1.d. +// Trustedness of certs.back(). The trustedness of certs.back() MUST BE +// decided by the caller -- this function takes it purely as an input. +// Moreover, the CertificateTrust can be used to specify trust anchor +// constraints [1] // // signature_policy: // The policy to use when verifying signatures (what hash algorithms are // allowed, what length keys, what named curves, etc). // // time: -// The UTC time to use for expiration checks. This is equivalent to -// the input from RFC 5280 section 6.1.1: +// The UTC time to use for expiration checks. // -// (b) the current date/time. -// -// required_key_purpose: +// key_purpose: // The key purpose that the target certificate needs to be valid for. // -// user_initial_policy_set: -// This is equivalent to the same named input in RFC 5280 section -// 6.1.1: -// -// (c) user-initial-policy-set: A set of certificate policy -// identifiers naming the policies that are acceptable to the -// certificate user. The user-initial-policy-set contains the -// special value any-policy if the user is not concerned about -// certificate policy. -// -// initial_policy_mapping_inhibit: -// This is equivalent to the same named input in RFC 5280 section -// 6.1.1: -// -// (e) initial-policy-mapping-inhibit, which indicates if policy -// mapping is allowed in the certification path. -// -// initial_explicit_policy: -// This is equivalent to the same named input in RFC 5280 section -// 6.1.1: -// -// (f) initial-explicit-policy, which indicates if the path must be -// valid for at least one of the certificate policies in the -// user-initial-policy-set. -// -// initial_any_policy_inhibit: -// This is equivalent to the same named input in RFC 5280 section -// 6.1.1: -// -// (g) initial-any-policy-inhibit, which indicates whether the -// anyPolicy OID should be processed if it is included in a -// certificate. -// // --------- // Outputs // --------- -// -// user_constrained_policy_set: -// Can be null. If non-null, |user_constrained_policy_set| will be filled -// with the matching policies (intersected with user_initial_policy_set). -// This is equivalent to the same named output in X.509 section 10.2. -// Note that it is OK for this to point to input user_initial_policy_set. -// // errors: // Must be non-null. The set of errors/warnings encountered while // validating the path are appended to this structure. If verification // failed, then there is guaranteed to be at least 1 high severity error // written to |errors|. // -// ------------------------- -// Trust Anchor constraints -// ------------------------- -// -// Conceptually, VerifyCertificateChain() sets RFC 5937's -// "enforceTrustAnchorConstraints" to true. -// -// One specifies trust anchor constraints using the |last_cert_trust| -// parameter in conjunction with extensions appearing in |certs.back()|. -// -// The trust anchor |certs.back()| is always passed as a certificate to -// this function, however the manner in which that certificate is -// interpreted depends on |last_cert_trust|: -// -// TRUSTED_ANCHOR: -// -// No properties from the root certificate, other than its Subject and -// SPKI, are checked during verification. This is the usual -// interpretation for a "trust anchor". -// -// TRUSTED_ANCHOR_WITH_CONSTRAINTS: -// -// Only a subset of extensions and properties from the certificate are checked, -// as described by RFC 5937. +// [1] Conceptually VerifyCertificateChain() sets RFC 5937's +// "enforceTrustAnchorConstraints" to true. And one specifies whether to +// interpret a root certificate as having trust anchor constraints through the +// |last_cert_trust| parameter. The constraints are just a subset of the +// extensions present in the certificate: // // * Signature: No // * Validity (expiration): No @@ -192,24 +104,17 @@ // * Basic constraints: Yes, but only the pathlen (CA=false is accepted) // * Name constraints: Yes // * Certificate policies: Not currently, TODO(crbug.com/634453) -// * Policy Mappings: No // * inhibitAnyPolicy: Not currently, TODO(crbug.com/634453) // * PolicyConstraints: Not currently, TODO(crbug.com/634452) // // The presence of any other unrecognized extension marked as critical fails // validation. -NET_EXPORT void VerifyCertificateChain( - const ParsedCertificateList& certs, - const CertificateTrust& last_cert_trust, - const SignaturePolicy* signature_policy, - const der::GeneralizedTime& time, - KeyPurpose required_key_purpose, - InitialExplicitPolicy initial_explicit_policy, - const std::set<der::Input>& user_initial_policy_set, - InitialPolicyMappingInhibit initial_policy_mapping_inhibit, - InitialAnyPolicyInhibit initial_any_policy_inhibit, - std::set<der::Input>* user_constrained_policy_set, - CertPathErrors* errors); +NET_EXPORT void VerifyCertificateChain(const ParsedCertificateList& certs, + const CertificateTrust& last_cert_trust, + const SignaturePolicy* signature_policy, + const der::GeneralizedTime& time, + KeyPurpose required_key_purpose, + CertPathErrors* errors); // TODO(crbug.com/634443): Move exported errors to a central location? extern CertErrorId kValidityFailedNotAfter;
diff --git a/net/cert/internal/verify_certificate_chain_pkits_unittest.cc b/net/cert/internal/verify_certificate_chain_pkits_unittest.cc index f86e1e9e..8138dae9 100644 --- a/net/cert/internal/verify_certificate_chain_pkits_unittest.cc +++ b/net/cert/internal/verify_certificate_chain_pkits_unittest.cc
@@ -67,19 +67,12 @@ SimpleSignaturePolicy signature_policy(1024); - std::set<der::Input> user_constrained_policy_set; - CertPathErrors path_errors; - VerifyCertificateChain( - input_chain, CertificateTrust::ForTrustAnchor(), &signature_policy, - info.time, KeyPurpose::ANY_EKU, info.initial_explicit_policy, - info.initial_policy_set, info.initial_policy_mapping_inhibit, - info.initial_inhibit_any_policy, &user_constrained_policy_set, - &path_errors); + VerifyCertificateChain(input_chain, CertificateTrust::ForTrustAnchor(), + &signature_policy, info.time, KeyPurpose::ANY_EKU, + &path_errors); bool did_succeed = !path_errors.ContainsHighSeverityErrors(); - EXPECT_EQ(info.user_constrained_policy_set, user_constrained_policy_set); - // TODO(crbug.com/634443): Test errors on failure? if (info.should_validate != did_succeed) { ASSERT_EQ(info.should_validate, did_succeed) @@ -229,21 +222,6 @@ PkitsTest07KeyUsage, VerifyCertificateChainPkitsTestDelegate); INSTANTIATE_TYPED_TEST_CASE_P(VerifyCertificateChain, - PkitsTest08CertificatePolicies, - VerifyCertificateChainPkitsTestDelegate); -INSTANTIATE_TYPED_TEST_CASE_P(VerifyCertificateChain, - PkitsTest09RequireExplicitPolicy, - VerifyCertificateChainPkitsTestDelegate); -INSTANTIATE_TYPED_TEST_CASE_P(VerifyCertificateChain, - PkitsTest10PolicyMappings, - VerifyCertificateChainPkitsTestDelegate); -INSTANTIATE_TYPED_TEST_CASE_P(VerifyCertificateChain, - PkitsTest11InhibitPolicyMapping, - VerifyCertificateChainPkitsTestDelegate); -INSTANTIATE_TYPED_TEST_CASE_P(VerifyCertificateChain, - PkitsTest12InhibitAnyPolicy, - VerifyCertificateChainPkitsTestDelegate); -INSTANTIATE_TYPED_TEST_CASE_P(VerifyCertificateChain, PkitsTest13NameConstraints, VerifyCertificateChainPkitsTestDelegate); INSTANTIATE_TYPED_TEST_CASE_P(VerifyCertificateChain, @@ -254,4 +232,8 @@ // PkitsTest05VerifyingPathswithSelfIssuedCertificates, // PkitsTest14DistributionPoints, PkitsTest15DeltaCRLs +// TODO(mattm): Certificate Policies support: PkitsTest08CertificatePolicies, +// PkitsTest09RequireExplicitPolicy PkitsTest10PolicyMappings, +// PkitsTest11InhibitPolicyMapping, PkitsTest12InhibitAnyPolicy + } // namespace net
diff --git a/net/cert/internal/verify_certificate_chain_unittest.cc b/net/cert/internal/verify_certificate_chain_unittest.cc index 82851d0..13c689f 100644 --- a/net/cert/internal/verify_certificate_chain_unittest.cc +++ b/net/cert/internal/verify_certificate_chain_unittest.cc
@@ -19,13 +19,8 @@ SimpleSignaturePolicy signature_policy(1024); CertPathErrors errors; - // TODO(eroman): Check user_constrained_policy_set. - VerifyCertificateChain( - test.chain, test.last_cert_trust, &signature_policy, test.time, - test.key_purpose, test.initial_explicit_policy, - test.user_initial_policy_set, test.initial_policy_mapping_inhibit, - test.initial_any_policy_inhibit, - nullptr /*user_constrained_policy_set*/, &errors); + VerifyCertificateChain(test.chain, test.last_cert_trust, &signature_policy, + test.time, test.key_purpose, &errors); EXPECT_EQ(test.expected_errors, errors.ToDebugString(test.chain)) << "Test file: " << test_file_path; }
diff --git a/net/http/bidirectional_stream.cc b/net/http/bidirectional_stream.cc index f76dee08..a050bb72 100644 --- a/net/http/bidirectional_stream.cc +++ b/net/http/bidirectional_stream.cc
@@ -167,21 +167,6 @@ return rv; } -void BidirectionalStream::SendData(const scoped_refptr<IOBuffer>& data, - int length, - bool end_stream) { - DCHECK(stream_impl_); - DCHECK(write_buffer_list_.empty()); - DCHECK(write_buffer_len_list_.empty()); - - if (net_log_.IsCapturing()) { - net_log_.AddEvent(NetLogEventType::BIDIRECTIONAL_STREAM_SEND_DATA); - } - stream_impl_->SendData(data, length, end_stream); - write_buffer_list_.push_back(data); - write_buffer_len_list_.push_back(length); -} - void BidirectionalStream::SendvData( const std::vector<scoped_refptr<IOBuffer>>& buffers, const std::vector<int>& lengths,
diff --git a/net/http/bidirectional_stream.h b/net/http/bidirectional_stream.h index 09b809cb..aaab6e4e 100644 --- a/net/http/bidirectional_stream.h +++ b/net/http/bidirectional_stream.h
@@ -147,11 +147,6 @@ // invoked, and should not be called again until Delegate::OnDataSent is // invoked. If |end_stream| is true, the DATA frame will have an END_STREAM // flag. - void SendData(const scoped_refptr<IOBuffer>& data, - int length, - bool end_stream); - - // Same as SendData except this takes in a vector of IOBuffers. void SendvData(const std::vector<scoped_refptr<IOBuffer>>& buffers, const std::vector<int>& lengths, bool end_stream);
diff --git a/net/http/bidirectional_stream_impl.h b/net/http/bidirectional_stream_impl.h index 54f9d04..9b5ffab7 100644 --- a/net/http/bidirectional_stream_impl.h +++ b/net/http/bidirectional_stream_impl.h
@@ -128,10 +128,6 @@ // Delegate::OnHeadersSent is invoked, and should not be called again until // Delegate::OnDataSent is invoked. If |end_stream| is true, the DATA frame // will have an END_STREAM flag. - virtual void SendData(const scoped_refptr<IOBuffer>& data, - int length, - bool end_stream) = 0; - virtual void SendvData(const std::vector<scoped_refptr<IOBuffer>>& buffers, const std::vector<int>& lengths, bool end_stream) = 0;
diff --git a/net/http/bidirectional_stream_unittest.cc b/net/http/bidirectional_stream_unittest.cc index 6d62d57..037a21e 100644 --- a/net/http/bidirectional_stream_unittest.cc +++ b/net/http/bidirectional_stream_unittest.cc
@@ -184,9 +184,7 @@ void SendData(const scoped_refptr<IOBuffer>& data, int length, bool end_of_stream) { - not_expect_callback_ = true; - stream_->SendData(data, length, end_of_stream); - not_expect_callback_ = false; + SendvData({data}, {length}, end_of_stream); } void SendvData(const std::vector<scoped_refptr<IOBuffer>>& data, @@ -769,7 +767,7 @@ entries, index, NetLogEventType::BIDIRECTIONAL_STREAM_RECV_TRAILERS, NetLogEventPhase::NONE); index = ExpectLogContainsSomewhere( - entries, index, NetLogEventType::BIDIRECTIONAL_STREAM_SEND_DATA, + entries, index, NetLogEventType::BIDIRECTIONAL_STREAM_SENDV_DATA, NetLogEventPhase::NONE); index = ExpectLogContainsSomewhere( entries, index, NetLogEventType::BIDIRECTIONAL_STREAM_READ_DATA,
diff --git a/net/log/net_log_event_type_list.h b/net/log/net_log_event_type_list.h index 4d0dc5b..014bb5f1 100644 --- a/net/log/net_log_event_type_list.h +++ b/net/log/net_log_event_type_list.h
@@ -1249,9 +1249,6 @@ // } EVENT_TYPE(BIDIRECTIONAL_STREAM_READ_DATA) -// Marks the SendData call of a net::BidirectionalStream. -EVENT_TYPE(BIDIRECTIONAL_STREAM_SEND_DATA) - // Marks the SendvData call of a net::BidirectionalStream. // The following parameters are attached: // {
diff --git a/net/quic/chromium/bidirectional_stream_quic_impl.cc b/net/quic/chromium/bidirectional_stream_quic_impl.cc index df82cec1..f07bc68 100644 --- a/net/quic/chromium/bidirectional_stream_quic_impl.cc +++ b/net/quic/chromium/bidirectional_stream_quic_impl.cc
@@ -145,43 +145,6 @@ return rv; } -void BidirectionalStreamQuicImpl::SendData(const scoped_refptr<IOBuffer>& data, - int length, - bool end_stream) { - DCHECK(length > 0 || (length == 0 && end_stream)); - if (!stream_) { - LOG(ERROR) << "Trying to send data after stream has been destroyed."; - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(&BidirectionalStreamQuicImpl::NotifyError, - weak_factory_.GetWeakPtr(), ERR_UNEXPECTED)); - return; - } - - std::unique_ptr<QuicConnection::ScopedPacketBundler> bundler; - if (!has_sent_headers_) { - DCHECK(!send_request_headers_automatically_); - // Creates a bundler only if there are headers to be sent along with the - // single data buffer. - bundler = - session_->CreatePacketBundler(QuicConnection::SEND_ACK_IF_PENDING); - // Sending the request might result in the stream being closed. - if (!WriteHeaders()) - return; - } - - QuicStringPiece string_data(data->data(), length); - int rv = stream_->WriteStreamData( - string_data, end_stream, - base::Bind(&BidirectionalStreamQuicImpl::OnSendDataComplete, - weak_factory_.GetWeakPtr())); - DCHECK(rv == OK || rv == ERR_IO_PENDING); - if (rv == OK) { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(&BidirectionalStreamQuicImpl::OnSendDataComplete, - weak_factory_.GetWeakPtr(), OK)); - } -} - void BidirectionalStreamQuicImpl::SendvData( const std::vector<scoped_refptr<IOBuffer>>& buffers, const std::vector<int>& lengths,
diff --git a/net/quic/chromium/bidirectional_stream_quic_impl.h b/net/quic/chromium/bidirectional_stream_quic_impl.h index af5bcf4..f2a4055 100644 --- a/net/quic/chromium/bidirectional_stream_quic_impl.h +++ b/net/quic/chromium/bidirectional_stream_quic_impl.h
@@ -45,9 +45,6 @@ std::unique_ptr<base::Timer> timer) override; void SendRequestHeaders() override; int ReadData(IOBuffer* buffer, int buffer_len) override; - void SendData(const scoped_refptr<IOBuffer>& data, - int length, - bool end_stream) override; void SendvData(const std::vector<scoped_refptr<IOBuffer>>& buffers, const std::vector<int>& lengths, bool end_stream) override;
diff --git a/net/quic/chromium/bidirectional_stream_quic_impl_unittest.cc b/net/quic/chromium/bidirectional_stream_quic_impl_unittest.cc index 2efcb02..bd81ec3 100644 --- a/net/quic/chromium/bidirectional_stream_quic_impl_unittest.cc +++ b/net/quic/chromium/bidirectional_stream_quic_impl_unittest.cc
@@ -173,9 +173,7 @@ void SendData(const scoped_refptr<IOBuffer>& data, int length, bool end_of_stream) { - not_expect_callback_ = true; - stream_->SendData(data, length, end_of_stream); - not_expect_callback_ = false; + SendvData({data}, {length}, end_of_stream); } void SendvData(const std::vector<scoped_refptr<IOBuffer>>& data,
diff --git a/net/quic/core/frames/quic_ack_frame.cc b/net/quic/core/frames/quic_ack_frame.cc index 8dcb1373..0741a15 100644 --- a/net/quic/core/frames/quic_ack_frame.cc +++ b/net/quic/core/frames/quic_ack_frame.cc
@@ -80,13 +80,6 @@ packet_number_intervals_.Difference(*packet_number_intervals_.begin()); } -void PacketNumberQueue::Complement() { - if (Empty()) { - return; - } - packet_number_intervals_.Complement(Min(), Max() + 1); -} - bool PacketNumberQueue::Contains(QuicPacketNumber packet_number) const { return packet_number_intervals_.Contains(packet_number); }
diff --git a/net/quic/core/frames/quic_ack_frame.h b/net/quic/core/frames/quic_ack_frame.h index 0a8991a..ef4829c 100644 --- a/net/quic/core/frames/quic_ack_frame.h +++ b/net/quic/core/frames/quic_ack_frame.h
@@ -52,11 +52,6 @@ // Removes the smallest interval in the queue. void RemoveSmallestInterval(); - // Mutates packet number set so that it contains only those packet numbers - // from minimum to maximum packet number not currently in the set. Do nothing - // if packet number set is empty. - void Complement(); - // Returns true if the queue contains |packet_number|. bool Contains(QuicPacketNumber packet_number) const;
diff --git a/net/quic/core/frames/quic_frames_test.cc b/net/quic/core/frames/quic_frames_test.cc index 67ff6f8..b0a77377 100644 --- a/net/quic/core/frames/quic_frames_test.cc +++ b/net/quic/core/frames/quic_frames_test.cc
@@ -278,19 +278,6 @@ EXPECT_FALSE(queue.Contains(20)); } -TEST_F(PacketNumberQueueTest, Complement) { - PacketNumberQueue queue; - queue.Add(1, 10); - queue.Add(12, 20); - queue.Add(22, 30); - queue.Complement(); - EXPECT_EQ(2u, queue.NumIntervals()); - EXPECT_TRUE(queue.Contains(10)); - EXPECT_TRUE(queue.Contains(11)); - EXPECT_TRUE(queue.Contains(20)); - EXPECT_TRUE(queue.Contains(21)); -} - } // namespace } // namespace test } // namespace net
diff --git a/net/quic/core/quic_bandwidth.cc b/net/quic/core/quic_bandwidth.cc index 86f0664..f831087 100644 --- a/net/quic/core/quic_bandwidth.cc +++ b/net/quic/core/quic_bandwidth.cc
@@ -5,111 +5,11 @@ #include "net/quic/core/quic_bandwidth.h" #include <cinttypes> -#include <limits> -#include "net/quic/core/quic_constants.h" -#include "net/quic/core/quic_time.h" -#include "net/quic/core/quic_types.h" -#include "net/quic/platform/api/quic_bug_tracker.h" #include "net/quic/platform/api/quic_str_cat.h" namespace net { -// Highest number that QuicBandwidth can hold. -const int64_t kQuicInfiniteBandwidth = INT64_C(0x7fffffffffffffff); - -// static -QuicBandwidth QuicBandwidth::Zero() { - return QuicBandwidth(0); -} - -// static -QuicBandwidth QuicBandwidth::Infinite() { - return QuicBandwidth(std::numeric_limits<int64_t>::max()); -} - -// static -QuicBandwidth QuicBandwidth::FromBitsPerSecond(int64_t bits_per_second) { - return QuicBandwidth(bits_per_second); -} - -// static -QuicBandwidth QuicBandwidth::FromKBitsPerSecond(int64_t k_bits_per_second) { - DCHECK(k_bits_per_second < kQuicInfiniteBandwidth / 1000); - return QuicBandwidth(k_bits_per_second * 1000); -} - -// static -QuicBandwidth QuicBandwidth::FromBytesPerSecond(int64_t bytes_per_second) { - DCHECK(bytes_per_second < kQuicInfiniteBandwidth / 8); - return QuicBandwidth(bytes_per_second * 8); -} - -// static -QuicBandwidth QuicBandwidth::FromKBytesPerSecond(int64_t k_bytes_per_second) { - DCHECK(k_bytes_per_second < kQuicInfiniteBandwidth / 8000); - return QuicBandwidth(k_bytes_per_second * 8000); -} - -// static -QuicBandwidth QuicBandwidth::FromBytesAndTimeDelta(QuicByteCount bytes, - QuicTime::Delta delta) { - DCHECK_LT(bytes, static_cast<uint64_t>(kQuicInfiniteBandwidth / - (8 * kNumMicrosPerSecond))); - int64_t bytes_per_second = - (bytes * kNumMicrosPerSecond) / delta.ToMicroseconds(); - return QuicBandwidth(bytes_per_second * 8); -} - -QuicBandwidth::QuicBandwidth(int64_t bits_per_second) - : bits_per_second_(bits_per_second) { - if (bits_per_second < 0) { - QUIC_BUG << "Can't set negative bandwidth " << bits_per_second; - bits_per_second_ = 0; - return; - } - bits_per_second_ = bits_per_second; -} - -int64_t QuicBandwidth::ToBitsPerSecond() const { - return bits_per_second_; -} - -int64_t QuicBandwidth::ToKBitsPerSecond() const { - return bits_per_second_ / 1000; -} - -int64_t QuicBandwidth::ToBytesPerSecond() const { - return bits_per_second_ / 8; -} - -int64_t QuicBandwidth::ToKBytesPerSecond() const { - return bits_per_second_ / 8000; -} - -QuicByteCount QuicBandwidth::ToBytesPerPeriod( - QuicTime::Delta time_period) const { - return ToBytesPerSecond() * time_period.ToMicroseconds() / - kNumMicrosPerSecond; -} - -int64_t QuicBandwidth::ToKBytesPerPeriod(QuicTime::Delta time_period) const { - return ToKBytesPerSecond() * time_period.ToMicroseconds() / - kNumMicrosPerSecond; -} - -bool QuicBandwidth::IsZero() const { - return (bits_per_second_ == 0); -} - -QuicTime::Delta QuicBandwidth::TransferTime(QuicByteCount bytes) const { - if (bits_per_second_ == 0) { - return QuicTime::Delta::Zero(); - } - return QuicTime::Delta::FromMicroseconds(bytes * 8 * kNumMicrosPerSecond / - bits_per_second_); -} - std::string QuicBandwidth::ToDebugValue() const { if (bits_per_second_ < 80000) { return QuicStringPrintf("%" PRId64 " bits/s (%" PRId64 " bytes/s)",
diff --git a/net/quic/core/quic_bandwidth.h b/net/quic/core/quic_bandwidth.h index 4e11d5f..e710b2edb 100644 --- a/net/quic/core/quic_bandwidth.h +++ b/net/quic/core/quic_bandwidth.h
@@ -9,9 +9,11 @@ #include <cmath> #include <cstdint> +#include <limits> #include <ostream> #include "base/compiler_specific.h" +#include "net/quic/core/quic_constants.h" #include "net/quic/core/quic_time.h" #include "net/quic/core/quic_types.h" #include "net/quic/platform/api/quic_export.h" @@ -21,47 +23,75 @@ class QUIC_EXPORT_PRIVATE QuicBandwidth { public: // Creates a new QuicBandwidth with an internal value of 0. - static QuicBandwidth Zero(); + static constexpr QuicBandwidth Zero() { return QuicBandwidth(0); } // Creates a new QuicBandwidth with an internal value of INT64_MAX. - static QuicBandwidth Infinite(); + static constexpr QuicBandwidth Infinite() { + return QuicBandwidth(std::numeric_limits<int64_t>::max()); + } // Create a new QuicBandwidth holding the bits per second. - static QuicBandwidth FromBitsPerSecond(int64_t bits_per_second); + static constexpr QuicBandwidth FromBitsPerSecond(int64_t bits_per_second) { + return QuicBandwidth(bits_per_second); + } // Create a new QuicBandwidth holding the kilo bits per second. - static QuicBandwidth FromKBitsPerSecond(int64_t k_bits_per_second); + static constexpr QuicBandwidth FromKBitsPerSecond(int64_t k_bits_per_second) { + return QuicBandwidth(k_bits_per_second * 1000); + } // Create a new QuicBandwidth holding the bytes per second. - static QuicBandwidth FromBytesPerSecond(int64_t bytes_per_second); + static constexpr QuicBandwidth FromBytesPerSecond(int64_t bytes_per_second) { + return QuicBandwidth(bytes_per_second * 8); + } // Create a new QuicBandwidth holding the kilo bytes per second. - static QuicBandwidth FromKBytesPerSecond(int64_t k_bytes_per_second); + static constexpr QuicBandwidth FromKBytesPerSecond( + int64_t k_bytes_per_second) { + return QuicBandwidth(k_bytes_per_second * 8000); + } // Create a new QuicBandwidth based on the bytes per the elapsed delta. - static QuicBandwidth FromBytesAndTimeDelta(QuicByteCount bytes, - QuicTime::Delta delta); + static inline QuicBandwidth FromBytesAndTimeDelta(QuicByteCount bytes, + QuicTime::Delta delta) { + return QuicBandwidth((bytes * kNumMicrosPerSecond) / + delta.ToMicroseconds() * 8); + } - int64_t ToBitsPerSecond() const; + inline int64_t ToBitsPerSecond() const { return bits_per_second_; } - int64_t ToKBitsPerSecond() const; + inline int64_t ToKBitsPerSecond() const { return bits_per_second_ / 1000; } - int64_t ToBytesPerSecond() const; + inline int64_t ToBytesPerSecond() const { return bits_per_second_ / 8; } - int64_t ToKBytesPerSecond() const; + inline int64_t ToKBytesPerSecond() const { return bits_per_second_ / 8000; } - QuicByteCount ToBytesPerPeriod(QuicTime::Delta time_period) const; + inline QuicByteCount ToBytesPerPeriod(QuicTime::Delta time_period) const { + return ToBytesPerSecond() * time_period.ToMicroseconds() / + kNumMicrosPerSecond; + } - int64_t ToKBytesPerPeriod(QuicTime::Delta time_period) const; + inline int64_t ToKBytesPerPeriod(QuicTime::Delta time_period) const { + return ToKBytesPerSecond() * time_period.ToMicroseconds() / + kNumMicrosPerSecond; + } - bool IsZero() const; + inline bool IsZero() const { return bits_per_second_ == 0; } - QuicTime::Delta TransferTime(QuicByteCount bytes) const; + inline QuicTime::Delta TransferTime(QuicByteCount bytes) const { + if (bits_per_second_ == 0) { + return QuicTime::Delta::Zero(); + } + return QuicTime::Delta::FromMicroseconds(bytes * 8 * kNumMicrosPerSecond / + bits_per_second_); + } std::string ToDebugValue() const; private: - explicit QuicBandwidth(int64_t bits_per_second); + explicit constexpr QuicBandwidth(int64_t bits_per_second) + : bits_per_second_(bits_per_second >= 0 ? bits_per_second : 0) {} + int64_t bits_per_second_; friend QuicBandwidth operator+(QuicBandwidth lhs, QuicBandwidth rhs);
diff --git a/net/quic/core/quic_connection.cc b/net/quic/core/quic_connection.cc index 6ca5955..26f097d 100644 --- a/net/quic/core/quic_connection.cc +++ b/net/quic/core/quic_connection.cc
@@ -253,7 +253,12 @@ time_of_last_received_packet_(clock_->ApproximateNow()), time_of_last_sent_new_packet_(clock_->ApproximateNow()), last_send_for_timeout_(clock_->ApproximateNow()), - sent_packet_manager_(perspective, clock_, &stats_, kCubicBytes, kNack), + sent_packet_manager_( + perspective, + clock_, + &stats_, + FLAGS_quic_reloadable_flag_quic_default_to_bbr ? kBBR : kCubicBytes, + kNack), version_negotiation_state_(START_NEGOTIATION), perspective_(perspective), connected_(true), @@ -2431,4 +2436,9 @@ } } +void QuicConnection::SetStreamNotifier( + StreamNotifierInterface* stream_notifier) { + sent_packet_manager_.SetStreamNotifier(stream_notifier); +} + } // namespace net
diff --git a/net/quic/core/quic_connection.h b/net/quic/core/quic_connection.h index fd78c93..4503c6c 100644 --- a/net/quic/core/quic_connection.h +++ b/net/quic/core/quic_connection.h
@@ -659,6 +659,9 @@ // the MTU discovery alarm. void DiscoverMtu(); + // Sets the stream notifer on the SentPacketManager. + void SetStreamNotifier(StreamNotifierInterface* stream_notifier); + // Return the name of the cipher of the primary decrypter of the framer. const char* cipher_name() const { return framer_.decrypter()->cipher_name(); } // Return the id of the cipher of the primary decrypter of the framer.
diff --git a/net/quic/core/quic_flags_list.h b/net/quic/core/quic_flags_list.h index 56c7420..56c7860 100644 --- a/net/quic/core/quic_flags_list.h +++ b/net/quic/core/quic_flags_list.h
@@ -156,7 +156,7 @@ // written in big endian. QUIC_FLAG(bool, FLAGS_quic_restart_flag_quic_big_endian_connection_id_client, - false) + true) // If true, on server side, 8-byte connection ID in public header is read and // written in big endian. @@ -170,7 +170,7 @@ // If true, enable random padding of size [1, 256] when response body is // compressed for QUIC version >= 38. -QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_random_padding, false) +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_random_padding, true) // Use conservation in PROBE_BW ouside of super-unity gain and immediately // preceeding cycle. @@ -219,3 +219,10 @@ // If true, use the more CPU efficient bandwidth sampler datastructure. QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_faster_bandwidth_sampler, false) + +// In QUIC, notify StreamNotifier instead of per-packet AckNotifier on +// every ack or retransmitted. +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_use_stream_notifier, false) + +// When true, defaults to BBR congestion control instead of Cubic. +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_default_to_bbr, false)
diff --git a/net/quic/core/quic_framer_test.cc b/net/quic/core/quic_framer_test.cc index 64feb881..a04fdc6 100644 --- a/net/quic/core/quic_framer_test.cc +++ b/net/quic/core/quic_framer_test.cc
@@ -4763,7 +4763,7 @@ static_cast<unsigned char>( FLAGS_quic_reloadable_flag_quic_remove_v33_hacks2 ? 0x39 : 0x3D), // connection_id - 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, + 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, // version tag 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(), // packet number @@ -4805,7 +4805,7 @@ static_cast<unsigned char>( FLAGS_quic_reloadable_flag_quic_remove_v33_hacks2 ? 0x39 : 0x3D), // connection_id - 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, + 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, // version tag 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(), // packet number
diff --git a/net/quic/core/quic_headers_stream.cc b/net/quic/core/quic_headers_stream.cc index 38e3ff48..b6dfec1 100644 --- a/net/quic/core/quic_headers_stream.cc +++ b/net/quic/core/quic_headers_stream.cc
@@ -9,6 +9,20 @@ namespace net { +QuicHeadersStream::CompressedHeaderInfo::CompressedHeaderInfo( + QuicStreamOffset headers_stream_offset, + QuicStreamOffset full_length, + QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) + : headers_stream_offset(headers_stream_offset), + full_length(full_length), + unacked_length(full_length), + ack_listener(std::move(ack_listener)) {} + +QuicHeadersStream::CompressedHeaderInfo::CompressedHeaderInfo( + const CompressedHeaderInfo& other) = default; + +QuicHeadersStream::CompressedHeaderInfo::~CompressedHeaderInfo() {} + QuicHeadersStream::QuicHeadersStream(QuicSpdySession* session) : QuicStream(kHeadersStreamId, session), spdy_session_(session) { // The headers stream is exempt from connection level flow control. @@ -43,4 +57,95 @@ } } +QuicConsumedData QuicHeadersStream::WritevDataInner( + QuicIOVector iov, + QuicStreamOffset offset, + bool fin, + QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) { + if (!session()->use_stream_notifier()) { + return QuicStream::WritevDataInner(iov, offset, fin, + std::move(ack_listener)); + } + QuicConsumedData consumed = + QuicStream::WritevDataInner(iov, offset, fin, nullptr); + if (consumed.bytes_consumed == 0 || ack_listener == nullptr) { + // No need to update unacked_headers_ if no byte is consumed or there is no + // ack listener. + return consumed; + } + + if (!unacked_headers_.empty() && + (offset == unacked_headers_.back().headers_stream_offset + + unacked_headers_.back().full_length) && + ack_listener == unacked_headers_.back().ack_listener) { + // Try to combine with latest inserted entry if they belong to the same + // header (i.e., having contiguous offset and the same ack listener). + unacked_headers_.back().full_length += consumed.bytes_consumed; + unacked_headers_.back().unacked_length += consumed.bytes_consumed; + } else { + unacked_headers_.push_back(CompressedHeaderInfo( + offset, consumed.bytes_consumed, std::move(ack_listener))); + } + return consumed; +} + +void QuicHeadersStream::OnStreamFrameAcked(const QuicStreamFrame& frame, + QuicTime::Delta ack_delay_time) { + for (CompressedHeaderInfo& header : unacked_headers_) { + if (frame.offset < header.headers_stream_offset) { + // This header frame offset belongs to headers with smaller offset, stop + // processing. + break; + } + + if (frame.offset >= header.headers_stream_offset + header.full_length) { + // This header frame belongs to headers with larger offset. + continue; + } + + if (header.unacked_length < frame.data_length) { + // This header frame is out of range. + CloseConnectionWithDetails(QUIC_INTERNAL_ERROR, + "Unsent stream data is acked"); + return; + } + + header.unacked_length -= frame.data_length; + + if (header.ack_listener != nullptr) { + header.ack_listener->OnPacketAcked(frame.data_length, ack_delay_time); + } + break; + } + + // Remove headers which are fully acked. Please note, header frames can be + // acked out of order, but unacked_headers_ is cleaned up in order. + while (!unacked_headers_.empty() && + unacked_headers_.front().unacked_length == 0) { + unacked_headers_.pop_front(); + } + QuicStream::OnStreamFrameAcked(frame, ack_delay_time); +} + +void QuicHeadersStream::OnStreamFrameRetransmitted( + const QuicStreamFrame& frame) { + for (CompressedHeaderInfo& header : unacked_headers_) { + if (frame.offset < header.headers_stream_offset) { + // This header frame offset belongs to headers with smaller offset, stop + // processing. + break; + } + + if (frame.offset >= header.headers_stream_offset + header.full_length) { + // This header frame belongs to headers with larger offset. + continue; + } + + if (header.ack_listener != nullptr) { + header.ack_listener->OnPacketRetransmitted(frame.data_length); + } + break; + } +} + } // namespace net
diff --git a/net/quic/core/quic_headers_stream.h b/net/quic/core/quic_headers_stream.h index b28a7a4..f74b869 100644 --- a/net/quic/core/quic_headers_stream.h +++ b/net/quic/core/quic_headers_stream.h
@@ -6,6 +6,7 @@ #define NET_QUIC_CORE_QUIC_HEADERS_STREAM_H_ #include <cstddef> +#include <deque> #include <memory> #include "base/macros.h" @@ -37,14 +38,53 @@ // Release underlying buffer if allowed. void MaybeReleaseSequencerBuffer(); + void OnStreamFrameAcked(const QuicStreamFrame& frame, + QuicTime::Delta ack_delay_time) override; + + void OnStreamFrameRetransmitted(const QuicStreamFrame& frame) override; + private: friend class test::QuicHeadersStreamPeer; + // Override to store mapping from offset, length to ack_listener. This + // ack_listener is notified once data within [offset, offset + length] is + // acked or retransmitted. + QuicConsumedData WritevDataInner( + QuicIOVector iov, + QuicStreamOffset offset, + bool fin, + QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) + override; + + // CompressedHeaderInfo includes simple information of a header, including + // offset in headers stream, unacked length and ack listener of this header. + struct QUIC_EXPORT_PRIVATE CompressedHeaderInfo { + CompressedHeaderInfo( + QuicStreamOffset headers_stream_offset, + QuicStreamOffset full_length, + QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener); + CompressedHeaderInfo(const CompressedHeaderInfo& other); + ~CompressedHeaderInfo(); + + // Offset the header was sent on the headers stream. + QuicStreamOffset headers_stream_offset; + // The full length of the header. + QuicByteCount full_length; + // The remaining bytes to be acked. + QuicByteCount unacked_length; + // Ack listener of this header, and it is notified once any of the bytes has + // been acked or retransmitted. + QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener; + }; + // Returns true if the session is still connected. bool IsConnected(); QuicSpdySession* spdy_session_; + // Headers that have not been fully acked. + std::deque<CompressedHeaderInfo> unacked_headers_; + DISALLOW_COPY_AND_ASSIGN(QuicHeadersStream); };
diff --git a/net/quic/core/quic_headers_stream_test.cc b/net/quic/core/quic_headers_stream_test.cc index a2e16a42..14401ee6 100644 --- a/net/quic/core/quic_headers_stream_test.cc +++ b/net/quic/core/quic_headers_stream_test.cc
@@ -972,7 +972,7 @@ framer_->ProcessInput(saved_data_.data(), saved_data_.length()); EXPECT_EQ(saved_payloads_, data); - if (use_ack_listener) { + if (use_ack_listener && !session_.use_stream_notifier()) { // Notice, acked bytes doesn't include extra bytes used by // HTTP/2 DATA frame headers. EXPECT_EQ(ack_listener->total_acked_bytes(), data_len); @@ -1041,6 +1041,65 @@ EXPECT_EQ(consumed_data.fin_consumed, false); } +TEST_P(QuicHeadersStreamTest, AckSentData) { + if (!session_.use_stream_notifier()) { + return; + } + EXPECT_CALL(session_, + WritevData(headers_stream_, kHeadersStreamId, _, _, NO_FIN, _)) + .WillRepeatedly( + WithArgs<2>(Invoke(this, &QuicHeadersStreamTest::SaveIov))); + InSequence s; + QuicReferenceCountedPointer<MockAckListener> ack_listener1( + new MockAckListener()); + QuicReferenceCountedPointer<MockAckListener> ack_listener2( + new MockAckListener()); + QuicReferenceCountedPointer<MockAckListener> ack_listener3( + new MockAckListener()); + + // Packet 1. + headers_stream_->WriteOrBufferData("Header5", false, ack_listener1); + headers_stream_->WriteOrBufferData("Header5", false, ack_listener1); + headers_stream_->WriteOrBufferData("Header7", false, ack_listener2); + + // Packet 2. + headers_stream_->WriteOrBufferData("Header9", false, ack_listener3); + headers_stream_->WriteOrBufferData("Header7", false, ack_listener2); + + // Packet 3. + headers_stream_->WriteOrBufferData("Header9", false, ack_listener3); + + QuicStreamFrame frame1(kHeadersStreamId, false, 0, "Header5"); + QuicStreamFrame frame2(kHeadersStreamId, false, 7, "Header5"); + // This is a bad frame3. + QuicStreamFrame frame3(kHeadersStreamId, false, 14, "BadHeader7"); + QuicStreamFrame frame4(kHeadersStreamId, false, 21, "Header9"); + QuicStreamFrame frame5(kHeadersStreamId, false, 28, "Header7"); + QuicStreamFrame frame6(kHeadersStreamId, false, 35, "Header9"); + // Packet 2 gets retransmitted. + EXPECT_CALL(*ack_listener3, OnPacketRetransmitted(7)).Times(1); + EXPECT_CALL(*ack_listener2, OnPacketRetransmitted(7)).Times(1); + headers_stream_->OnStreamFrameRetransmitted(frame4); + headers_stream_->OnStreamFrameRetransmitted(frame5); + + // Packets are acked in order: 2, 3, 1. + EXPECT_CALL(*ack_listener3, OnPacketAcked(7, _)); + EXPECT_CALL(*ack_listener2, OnPacketAcked(7, _)); + headers_stream_->OnStreamFrameAcked(frame4, QuicTime::Delta::Zero()); + headers_stream_->OnStreamFrameAcked(frame5, QuicTime::Delta::Zero()); + + EXPECT_CALL(*ack_listener3, OnPacketAcked(7, _)); + headers_stream_->OnStreamFrameAcked(frame6, QuicTime::Delta::Zero()); + + EXPECT_CALL(*ack_listener1, OnPacketAcked(7, _)); + EXPECT_CALL(*ack_listener1, OnPacketAcked(7, _)); + headers_stream_->OnStreamFrameAcked(frame1, QuicTime::Delta::Zero()); + headers_stream_->OnStreamFrameAcked(frame2, QuicTime::Delta::Zero()); + // Unsent data is acked. + EXPECT_CALL(*connection_, CloseConnection(QUIC_INTERNAL_ERROR, _, _)); + headers_stream_->OnStreamFrameAcked(frame3, QuicTime::Delta::Zero()); +} + } // namespace } // namespace test } // namespace net
diff --git a/net/quic/core/quic_sent_packet_manager.cc b/net/quic/core/quic_sent_packet_manager.cc index 9b3b3dc9..7233e52 100644 --- a/net/quic/core/quic_sent_packet_manager.cc +++ b/net/quic/core/quic_sent_packet_manager.cc
@@ -117,6 +117,9 @@ } } else if (config.HasClientRequestedIndependentOption(kBYTE, perspective_)) { SetSendAlgorithm(kCubic); + } else if (FLAGS_quic_reloadable_flag_quic_default_to_bbr && + config.HasClientRequestedIndependentOption(kQBIC, perspective_)) { + SetSendAlgorithm(kCubicBytes); } else if (FLAGS_quic_reloadable_flag_quic_enable_pcc && config.HasClientRequestedIndependentOption(kTPCC, perspective_)) { SetSendAlgorithm(kPCC); @@ -464,6 +467,7 @@ // The AckListener needs to be notified about the most recent // transmission, since that's the one only one it tracks. if (newest_transmission == packet_number) { + unacked_packets_.NotifyStreamFramesAcked(*info, ack_delay_time); unacked_packets_.NotifyAndClearListeners(&info->ack_listeners, ack_delay_time); } else { @@ -478,6 +482,8 @@ // only handle nullptr encrypted packets in a special way. const QuicTransmissionInfo& newest_transmission_info = unacked_packets_.GetTransmissionInfo(newest_transmission); + unacked_packets_.NotifyStreamFramesAcked(newest_transmission_info, + ack_delay_time); if (HasCryptoHandshake(newest_transmission_info)) { unacked_packets_.RemoveFromInFlight(newest_transmission); } @@ -962,4 +968,9 @@ return send_algorithm_.get(); } +void QuicSentPacketManager::SetStreamNotifier( + StreamNotifierInterface* stream_notifier) { + unacked_packets_.SetStreamNotifier(stream_notifier); +} + } // namespace net
diff --git a/net/quic/core/quic_sent_packet_manager.h b/net/quic/core/quic_sent_packet_manager.h index acdf795d..268a54c4 100644 --- a/net/quic/core/quic_sent_packet_manager.h +++ b/net/quic/core/quic_sent_packet_manager.h
@@ -224,6 +224,8 @@ const SendAlgorithmInterface* GetSendAlgorithm() const; + void SetStreamNotifier(StreamNotifierInterface* stream_notifier); + QuicPacketNumber largest_packet_peer_knows_is_acked() const { return largest_packet_peer_knows_is_acked_; }
diff --git a/net/quic/core/quic_session.cc b/net/quic/core/quic_session.cc index 3afc985..7c1bf263 100644 --- a/net/quic/core/quic_session.cc +++ b/net/quic/core/quic_session.cc
@@ -45,10 +45,15 @@ perspective() == Perspective::IS_SERVER, nullptr), currently_writing_stream_id_(0), - respect_goaway_(true) {} + respect_goaway_(true), + use_stream_notifier_( + FLAGS_quic_reloadable_flag_quic_use_stream_notifier) {} void QuicSession::Initialize() { connection_->set_visitor(this); + if (use_stream_notifier_) { + connection_->SetStreamNotifier(this); + } connection_->SetFromConfig(config_); DCHECK_EQ(kCryptoStreamId, GetMutableCryptoStream()->id()); @@ -66,6 +71,7 @@ << "Surprisingly high number of locally closed self initiated streams" "still waiting for final byte offset: " << GetNumLocallyClosedOutgoingStreamsHighestOffset(); + QUIC_LOG_IF(WARNING, !zombie_streams_.empty()) << "Still have zombie streams"; } void QuicSession::OnStreamFrame(const QuicStreamFrame& frame) { @@ -129,6 +135,13 @@ } } + // Cleanup zombie stream map on connection close. + while (!zombie_streams_.empty()) { + ZombieStreamMap::iterator it = zombie_streams_.begin(); + closed_streams_.push_back(std::move(it->second)); + zombie_streams_.erase(it); + } + if (visitor_) { visitor_->OnConnectionClosed(connection_->connection_id(), error, error_details); @@ -369,7 +382,11 @@ stream->set_rst_sent(true); } - closed_streams_.push_back(std::move(it->second)); + if (stream->IsWaitingForAcks()) { + zombie_streams_[stream->id()] = std::move(it->second); + } else { + closed_streams_.push_back(std::move(it->second)); + } // If we haven't received a FIN or RST for this stream, we need to keep track // of the how many bytes the stream's flow controller believes it has @@ -944,4 +961,45 @@ return stream_ptr; } +void QuicSession::OnStreamDoneWaitingForAcks(QuicStreamId id) { + auto it = zombie_streams_.find(id); + if (it == zombie_streams_.end()) { + return; + } + + closed_streams_.push_back(std::move(it->second)); + zombie_streams_.erase(it); +} + +QuicStream* QuicSession::GetStream(QuicStreamId id) const { + auto static_stream = static_stream_map_.find(id); + if (static_stream != static_stream_map_.end()) { + return static_stream->second; + } + auto active_stream = dynamic_stream_map_.find(id); + if (active_stream != dynamic_stream_map_.end()) { + return active_stream->second.get(); + } + auto zombie_stream = zombie_streams_.find(id); + if (zombie_stream != zombie_streams_.end()) { + return zombie_stream->second.get(); + } + return nullptr; +} + +void QuicSession::OnStreamFrameAcked(const QuicStreamFrame& frame, + QuicTime::Delta ack_delay_time) { + QuicStream* stream = GetStream(frame.stream_id); + if (stream != nullptr) { + stream->OnStreamFrameAcked(frame, ack_delay_time); + } +} + +void QuicSession::OnStreamFrameRetransmitted(const QuicStreamFrame& frame) { + QuicStream* stream = GetStream(frame.stream_id); + if (stream != nullptr) { + stream->OnStreamFrameRetransmitted(frame); + } +} + } // namespace net
diff --git a/net/quic/core/quic_session.h b/net/quic/core/quic_session.h index 403f0e5..d70e4bdf 100644 --- a/net/quic/core/quic_session.h +++ b/net/quic/core/quic_session.h
@@ -22,6 +22,7 @@ #include "net/quic/core/quic_packets.h" #include "net/quic/core/quic_stream.h" #include "net/quic/core/quic_write_blocked_list.h" +#include "net/quic/core/stream_notifier_interface.h" #include "net/quic/platform/api/quic_containers.h" #include "net/quic/platform/api/quic_export.h" #include "net/quic/platform/api/quic_socket_address.h" @@ -36,7 +37,8 @@ class QuicSessionPeer; } // namespace test -class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface { +class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface, + public StreamNotifierInterface { public: // An interface from the session to the entity owning the session. // This lets the session notify its owner (the Dispatcher) when the connection @@ -107,6 +109,11 @@ bool HasOpenDynamicStreams() const override; void OnPathDegrading() override; + // StreamNotifierInterface methods: + void OnStreamFrameAcked(const QuicStreamFrame& frame, + QuicTime::Delta ack_delay_time) override; + void OnStreamFrameRetransmitted(const QuicStreamFrame& frame) override; + // Called on every incoming packet. Passes |packet| through to |connection_|. virtual void ProcessUdpPacket(const QuicSocketAddress& self_address, const QuicSocketAddress& peer_address, @@ -208,6 +215,11 @@ // WINDOW_UPDATE arrives. void MarkConnectionLevelWriteBlocked(QuicStreamId id); + // Called when stream |id| is done waiting for acks either because all data + // gets acked or is not interested in data being acked (which happens when + // a stream is reset because of an error). + void OnStreamDoneWaitingForAcks(QuicStreamId id); + // Returns true if the session has data to be sent, either queued in the // connection, or in a write-blocked stream. bool HasDataToWrite() const; @@ -254,6 +266,8 @@ respect_goaway_ = respect_goaway; } + bool use_stream_notifier() const { return use_stream_notifier_; } + protected: using StaticStreamMap = QuicSmallMap<QuicStreamId, QuicStream*, 2>; @@ -262,6 +276,9 @@ using ClosedStreams = std::vector<std::unique_ptr<QuicStream>>; + using ZombieStreamMap = + QuicSmallMap<QuicStreamId, std::unique_ptr<QuicStream>, 10>; + // TODO(ckrasic) - For all *DynamicStream2 below, rename after // quic_reloadable_flag_quic_refactor_stream_creation is deprecated. @@ -347,6 +364,8 @@ ClosedStreams* closed_streams() { return &closed_streams_; } + const ZombieStreamMap& zombie_streams() const { return zombie_streams_; } + void set_max_open_incoming_streams(size_t max_open_incoming_streams); void set_max_open_outgoing_streams(size_t max_open_outgoing_streams); @@ -416,6 +435,10 @@ // starting with larger flow control receive windows. void AdjustInitialFlowControlWindows(size_t stream_window); + // Find stream with |id|, returns nullptr if the stream does not exist or + // closed. + QuicStream* GetStream(QuicStreamId id) const; + // Keep track of highest received byte offset of locally closed streams, while // waiting for a definitive final highest offset from the peer. std::map<QuicStreamId, QuicStreamOffset> @@ -428,6 +451,10 @@ ClosedStreams closed_streams_; + // Streams which are closed, but need to be kept alive. Currently, the only + // reason is the stream's sent data (including FIN) does not get fully acked. + ZombieStreamMap zombie_streams_; + QuicConfig config_; // The maximum number of outgoing streams this connection can open. @@ -485,6 +512,9 @@ // chance they will fail. bool respect_goaway_; + // This session is notified on every ack or loss. + const bool use_stream_notifier_; + DISALLOW_COPY_AND_ASSIGN(QuicSession); };
diff --git a/net/quic/core/quic_session_test.cc b/net/quic/core/quic_session_test.cc index a502562..8a251a7 100644 --- a/net/quic/core/quic_session_test.cc +++ b/net/quic/core/quic_session_test.cc
@@ -228,6 +228,8 @@ } using QuicSession::PostProcessAfterData; + using QuicSession::closed_streams; + using QuicSession::zombie_streams; private: StrictMock<TestCryptoStream> crypto_stream_; @@ -1346,6 +1348,24 @@ } } +TEST_P(QuicSessionTestServer, ZombieStreams) { + if (!session_.use_stream_notifier()) { + return; + } + TestStream* stream2 = session_.CreateOutgoingDynamicStream(kDefaultPriority); + QuicStreamPeer::SetStreamBytesWritten(3, stream2); + EXPECT_TRUE(stream2->IsWaitingForAcks()); + + EXPECT_CALL(*connection_, SendRstStream(2, _, _)); + session_.CloseStream(2); + EXPECT_TRUE(QuicContainsKey(session_.zombie_streams(), 2)); + EXPECT_TRUE(session_.closed_streams()->empty()); + session_.OnStreamDoneWaitingForAcks(2); + EXPECT_FALSE(QuicContainsKey(session_.zombie_streams(), 2)); + EXPECT_EQ(1u, session_.closed_streams()->size()); + EXPECT_EQ(2u, session_.closed_streams()->front()->id()); +} + } // namespace } // namespace test } // namespace net
diff --git a/net/quic/core/quic_spdy_session.cc b/net/quic/core/quic_spdy_session.cc index ec533eade..be9aa55d 100644 --- a/net/quic/core/quic_spdy_session.cc +++ b/net/quic/core/quic_spdy_session.cc
@@ -360,6 +360,9 @@ for (auto& stream : *closed_streams()) { static_cast<QuicSpdyStream*>(stream.get())->ClearSession(); } + for (auto const& kv : zombie_streams()) { + static_cast<QuicSpdyStream*>(kv.second.get())->ClearSession(); + } for (auto const& kv : dynamic_streams()) { static_cast<QuicSpdyStream*>(kv.second.get())->ClearSession(); }
diff --git a/net/quic/core/quic_spdy_stream_test.cc b/net/quic/core/quic_spdy_stream_test.cc index 63aaa89..2a87a4d 100644 --- a/net/quic/core/quic_spdy_stream_test.cc +++ b/net/quic/core/quic_spdy_stream_test.cc
@@ -11,11 +11,13 @@ #include "net/quic/core/quic_utils.h" #include "net/quic/core/quic_write_blocked_list.h" #include "net/quic/core/spdy_utils.h" +#include "net/quic/platform/api/quic_map_util.h" #include "net/quic/platform/api/quic_ptr_util.h" #include "net/quic/platform/api/quic_string_piece.h" #include "net/quic/platform/api/quic_test.h" #include "net/quic/platform/api/quic_text_utils.h" #include "net/quic/test_tools/quic_flow_controller_peer.h" +#include "net/quic/test_tools/quic_session_peer.h" #include "net/quic/test_tools/quic_spdy_session_peer.h" #include "net/quic/test_tools/quic_stream_peer.h" #include "net/quic/test_tools/quic_test_utils.h" @@ -55,6 +57,7 @@ using QuicStream::WriteOrBufferData; using QuicStream::CloseWriteSide; + using QuicSpdyStream::set_ack_listener; const string& data() const { return data_; } @@ -963,6 +966,67 @@ "Trailers cannot be sent after a FIN"); } +TEST_P(QuicSpdyStreamTest, HeaderStreamNotiferCorrespondingSpdyStream) { + Initialize(kShouldProcessData); + if (!session_->use_stream_notifier()) { + return; + } + + EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)) + .Times(AnyNumber()) + .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData)); + testing::InSequence s; + QuicReferenceCountedPointer<MockAckListener> ack_listener1( + new MockAckListener()); + QuicReferenceCountedPointer<MockAckListener> ack_listener2( + new MockAckListener()); + stream_->set_ack_listener(ack_listener1); + stream2_->set_ack_listener(ack_listener2); + + session_->headers_stream()->WriteOrBufferData("Header1", false, + ack_listener1); + stream_->WriteOrBufferData("Test1", true, nullptr); + + session_->headers_stream()->WriteOrBufferData("Header2", false, + ack_listener2); + stream2_->WriteOrBufferData("Test2", false, nullptr); + + QuicStreamFrame frame1(kHeadersStreamId, false, 0, "Header1"); + QuicStreamFrame frame2(stream_->id(), true, 0, "Test1"); + QuicStreamFrame frame3(kHeadersStreamId, false, 7, "Header2"); + QuicStreamFrame frame4(stream2_->id(), false, 0, "Test2"); + + EXPECT_CALL(*ack_listener1, OnPacketRetransmitted(7)); + session_->OnStreamFrameRetransmitted(frame1); + + EXPECT_CALL(*ack_listener1, OnPacketAcked(7, _)); + session_->OnStreamFrameAcked(frame1, QuicTime::Delta::Zero()); + EXPECT_CALL(*ack_listener1, OnPacketAcked(5, _)); + session_->OnStreamFrameAcked(frame2, QuicTime::Delta::Zero()); + EXPECT_CALL(*ack_listener2, OnPacketAcked(7, _)); + session_->OnStreamFrameAcked(frame3, QuicTime::Delta::Zero()); + EXPECT_CALL(*ack_listener2, OnPacketAcked(5, _)); + session_->OnStreamFrameAcked(frame4, QuicTime::Delta::Zero()); +} + +TEST_P(QuicSpdyStreamTest, StreamBecomesZombieWithWriteThatCloses) { + Initialize(kShouldProcessData); + if (!session_->use_stream_notifier()) { + return; + } + + EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)) + .Times(AnyNumber()) + .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData)); + QuicStreamPeer::CloseReadSide(stream_); + // This write causes stream to be closed. + stream_->WriteOrBufferData("Test1", true, nullptr); + // stream_ has unacked data and should become zombie. + EXPECT_TRUE(QuicContainsKey(QuicSessionPeer::zombie_streams(session_.get()), + stream_->id())); + EXPECT_TRUE(QuicSessionPeer::closed_streams(session_.get()).empty()); +} + } // namespace } // namespace test } // namespace net
diff --git a/net/quic/core/quic_stream.cc b/net/quic/core/quic_stream.cc index 733a805..95d91e4 100644 --- a/net/quic/core/quic_stream.cc +++ b/net/quic/core/quic_stream.cc
@@ -54,12 +54,14 @@ session_(session), stream_bytes_read_(0), stream_bytes_written_(0), + stream_bytes_acked_(0), stream_error_(QUIC_STREAM_NO_ERROR), connection_error_(QUIC_NO_ERROR), read_side_closed_(false), write_side_closed_(false), fin_buffered_(false), fin_sent_(false), + fin_acked_(false), fin_received_(false), rst_sent_(false), rst_received_(false), @@ -74,11 +76,15 @@ connection_flow_controller_(session_->flow_controller()), stream_contributes_to_connection_flow_control_(true), busy_counter_(0), - add_random_padding_after_fin_(false) { + add_random_padding_after_fin_(false), + ack_listener_(nullptr) { SetFromConfig(); } -QuicStream::~QuicStream() {} +QuicStream::~QuicStream() { + QUIC_LOG_IF(WARNING, !IsWaitingForAcks()) + << "Stream destroyed while waiting for acks."; +} void QuicStream::SetFromConfig() {} @@ -171,6 +177,9 @@ // Sending a RstStream results in calling CloseStream. session()->SendRstStream(id(), error, stream_bytes_written_); rst_sent_ = true; + if (session()->use_stream_notifier() && !IsWaitingForAcks()) { + session_->OnStreamDoneWaitingForAcks(id_); + } } void QuicStream::CloseConnectionWithDetails(QuicErrorCode error, @@ -492,4 +501,48 @@ add_random_padding_after_fin_ = true; } +void QuicStream::OnStreamFrameAcked(const QuicStreamFrame& frame, + QuicTime::Delta ack_delay_time) { + DCHECK_EQ(frame.stream_id, id()); + stream_bytes_acked_ += frame.data_length; + if (stream_bytes_acked_ > stream_bytes_written_) { + CloseConnectionWithDetails(QUIC_INTERNAL_ERROR, + "Unsent stream data is acked"); + return; + } + if (frame.fin) { + fin_acked_ = true; + } + if (ack_listener_ != nullptr) { + ack_listener_->OnPacketAcked(frame.data_length, ack_delay_time); + } + if (!IsWaitingForAcks()) { + session_->OnStreamDoneWaitingForAcks(id_); + } +} + +void QuicStream::OnStreamFrameRetransmitted(const QuicStreamFrame& frame) { + if (ack_listener_ != nullptr) { + ack_listener_->OnPacketRetransmitted(frame.data_length); + } +} + +bool QuicStream::IsWaitingForAcks() const { + if (rst_sent_ && stream_error_ != QUIC_STREAM_NO_ERROR) { + // RST_STREAM sent because of error. + return false; + } + if (connection_error_ != QUIC_NO_ERROR) { + // Connection encounters error and is going to close. + return false; + } + if (stream_bytes_acked_ == stream_bytes_written_ && + ((fin_sent_ && fin_acked_) || !fin_sent_)) { + // All sent data has been acked. + return false; + } + + return true; +} + } // namespace net
diff --git a/net/quic/core/quic_stream.h b/net/quic/core/quic_stream.h index df1ebf02..e88c684b 100644 --- a/net/quic/core/quic_stream.h +++ b/net/quic/core/quic_stream.h
@@ -29,6 +29,7 @@ #include "net/quic/core/quic_packets.h" #include "net/quic/core/quic_stream_sequencer.h" #include "net/quic/core/quic_types.h" +#include "net/quic/core/stream_notifier_interface.h" #include "net/quic/platform/api/quic_export.h" #include "net/quic/platform/api/quic_reference_counted.h" #include "net/quic/platform/api/quic_string_piece.h" @@ -41,11 +42,11 @@ class QuicSession; -class QUIC_EXPORT_PRIVATE QuicStream { +class QUIC_EXPORT_PRIVATE QuicStream : public StreamNotifierInterface { public: QuicStream(QuicStreamId id, QuicSession* session); - virtual ~QuicStream(); + ~QuicStream() override; // Not in use currently. void SetFromConfig(); @@ -91,6 +92,12 @@ virtual void CloseConnectionWithDetails(QuicErrorCode error, const std::string& details); + // Returns true if this stream is still waiting for acks of sent data. + // This will return false if all data has been acked, or if the stream + // is no longer interested in data being acked (which happens when + // a stream is reset because of an error). + bool IsWaitingForAcks() const; + QuicStreamId id() const { return id_; } QuicRstStreamErrorCode stream_error() const { return stream_error_; } @@ -189,6 +196,11 @@ // Adds random padding after the fin is consumed for this stream. void AddRandomPaddingAfterFin(); + // StreamNotifierInterface methods: + void OnStreamFrameAcked(const QuicStreamFrame& frame, + QuicTime::Delta ack_delay_time) override; + void OnStreamFrameRetransmitted(const QuicStreamFrame& frame) override; + protected: // Sends as many bytes in the first |count| buffers of |iov| to the connection // as the connection will consume. @@ -226,6 +238,11 @@ stream_contributes_to_connection_flow_control_ = false; } + void set_ack_listener( + QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) { + ack_listener_ = std::move(ack_listener); + } + private: friend class test::QuicStreamPeer; friend class QuicStreamUtils; @@ -270,6 +287,8 @@ // framing, encryption overhead etc. uint64_t stream_bytes_read_; uint64_t stream_bytes_written_; + // Written bytes which have been acked. + uint64_t stream_bytes_acked_; // Stream error code received from a RstStreamFrame or error code sent by the // visitor or sequencer in the RstStreamFrame. @@ -289,6 +308,8 @@ bool fin_buffered_; // True if a FIN has been sent to the session. bool fin_sent_; + // True if a FIN has been acked. + bool fin_acked_; // True if this stream has received (and the sequencer has accepted) a // StreamFrame with the FIN set. @@ -324,6 +345,10 @@ // stream. bool add_random_padding_after_fin_; + // Ack listener of this stream, and it is notified when any of written bytes + // are acked. + QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener_; + DISALLOW_COPY_AND_ASSIGN(QuicStream); };
diff --git a/net/quic/core/quic_stream_test.cc b/net/quic/core/quic_stream_test.cc index 6e83dae..a2aebf5 100644 --- a/net/quic/core/quic_stream_test.cc +++ b/net/quic/core/quic_stream_test.cc
@@ -714,6 +714,124 @@ EXPECT_TRUE(stream_->HasFinalReceivedByteOffset()); } +TEST_F(QuicStreamTest, StreamWaitsForAcks) { + Initialize(kShouldProcessData); + if (!session_->use_stream_notifier()) { + return; + } + EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)) + .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData)); + // Stream is not waiting for acks initially. + EXPECT_FALSE(stream_->IsWaitingForAcks()); + + // Send kData1. + stream_->WriteOrBufferData(kData1, false, nullptr); + EXPECT_TRUE(stream_->IsWaitingForAcks()); + QuicStreamFrame frame1(stream_->id(), false, 0, kData1); + stream_->OnStreamFrameAcked(frame1, QuicTime::Delta::Zero()); + // Stream is not waiting for acks as all sent data is acked. + EXPECT_FALSE(stream_->IsWaitingForAcks()); + + // Send kData2. + stream_->WriteOrBufferData(kData2, false, nullptr); + EXPECT_TRUE(stream_->IsWaitingForAcks()); + // Send FIN. + stream_->WriteOrBufferData("", true, nullptr); + + // kData2 is acked. + QuicStreamFrame frame2(stream_->id(), false, 9, kData2); + stream_->OnStreamFrameAcked(frame2, QuicTime::Delta::Zero()); + // Stream is waiting for acks as FIN is not acked. + EXPECT_TRUE(stream_->IsWaitingForAcks()); + + // FIN is acked. + QuicStreamFrame frame3(stream_->id(), true, 18, ""); + stream_->OnStreamFrameAcked(frame3, QuicTime::Delta::Zero()); + EXPECT_FALSE(stream_->IsWaitingForAcks()); +} + +TEST_F(QuicStreamTest, CancelStream) { + Initialize(kShouldProcessData); + if (!session_->use_stream_notifier()) { + return; + } + + EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)) + .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData)); + EXPECT_FALSE(stream_->IsWaitingForAcks()); + + stream_->WriteOrBufferData(kData1, false, nullptr); + EXPECT_TRUE(stream_->IsWaitingForAcks()); + // Cancel stream. + stream_->Reset(QUIC_STREAM_NO_ERROR); + // stream still waits for acks as the error code is QUIC_STREAM_NO_ERROR, and + // data is going to be retransmitted. + EXPECT_TRUE(stream_->IsWaitingForAcks()); + stream_->Reset(QUIC_STREAM_CANCELLED); + // Stream stops waiting for acks as data is not going to be retransmitted. + EXPECT_FALSE(stream_->IsWaitingForAcks()); +} + +TEST_F(QuicStreamTest, RstFrameReceivedStreamNotFinishSending) { + Initialize(kShouldProcessData); + if (!session_->use_stream_notifier()) { + return; + } + + EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)) + .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData)); + EXPECT_FALSE(stream_->IsWaitingForAcks()); + + stream_->WriteOrBufferData(kData1, false, nullptr); + EXPECT_TRUE(stream_->IsWaitingForAcks()); + + // RST_STREAM received. + QuicRstStreamFrame rst_frame(stream_->id(), QUIC_STREAM_CANCELLED, 1234); + stream_->OnStreamReset(rst_frame); + // Stream stops waiting for acks as it does not finish sending and rst is + // sent. + EXPECT_FALSE(stream_->IsWaitingForAcks()); +} + +TEST_F(QuicStreamTest, RstFrameReceivedStreamFinishSending) { + Initialize(kShouldProcessData); + if (!session_->use_stream_notifier()) { + return; + } + + EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)) + .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData)); + EXPECT_FALSE(stream_->IsWaitingForAcks()); + + stream_->WriteOrBufferData(kData1, true, nullptr); + EXPECT_TRUE(stream_->IsWaitingForAcks()); + + // RST_STREAM received. + QuicRstStreamFrame rst_frame(stream_->id(), QUIC_STREAM_CANCELLED, 1234); + stream_->OnStreamReset(rst_frame); + // Stream stops waiting for acks as it has unacked data. + EXPECT_TRUE(stream_->IsWaitingForAcks()); +} + +TEST_F(QuicStreamTest, ConnectionClosed) { + Initialize(kShouldProcessData); + if (!session_->use_stream_notifier()) { + return; + } + + EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)) + .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData)); + EXPECT_FALSE(stream_->IsWaitingForAcks()); + + stream_->WriteOrBufferData(kData1, false, nullptr); + EXPECT_TRUE(stream_->IsWaitingForAcks()); + + stream_->OnConnectionClosed(QUIC_INTERNAL_ERROR, + ConnectionCloseSource::FROM_SELF); + // Stream stops waiting for acks as connection is going to close. + EXPECT_FALSE(stream_->IsWaitingForAcks()); +} + } // namespace } // namespace test } // namespace net
diff --git a/net/quic/core/quic_unacked_packet_map.cc b/net/quic/core/quic_unacked_packet_map.cc index 8c5fbf1..4c5f8b2d 100644 --- a/net/quic/core/quic_unacked_packet_map.cc +++ b/net/quic/core/quic_unacked_packet_map.cc
@@ -16,7 +16,8 @@ largest_observed_(0), least_unacked_(1), bytes_in_flight_(0), - pending_crypto_packet_count_(0) {} + pending_crypto_packet_count_(0), + stream_notifier_(nullptr) {} QuicUnackedPacketMap::~QuicUnackedPacketMap() { for (QuicTransmissionInfo& transmission_info : unacked_packets_) { @@ -102,6 +103,13 @@ QuicTransmissionInfo* transmission_info = &unacked_packets_.at(old_packet_number - least_unacked_); QuicFrames* frames = &transmission_info->retransmittable_frames; + if (stream_notifier_ != nullptr) { + for (const QuicFrame& frame : *frames) { + if (frame.type == STREAM_FRAME) { + stream_notifier_->OnStreamFrameRetransmitted(*frame.stream_frame); + } + } + } for (AckListenerWrapper& wrapper : transmission_info->ack_listeners) { wrapper.ack_listener->OnPacketRetransmitted(wrapper.length); } @@ -350,4 +358,23 @@ return least_unacked_; } +void QuicUnackedPacketMap::SetStreamNotifier( + StreamNotifierInterface* stream_notifier) { + stream_notifier_ = stream_notifier; +} + +void QuicUnackedPacketMap::NotifyStreamFramesAcked( + const QuicTransmissionInfo& info, + QuicTime::Delta ack_delay) { + if (stream_notifier_ == nullptr) { + return; + } + + for (const QuicFrame& frame : info.retransmittable_frames) { + if (frame.type == STREAM_FRAME) { + stream_notifier_->OnStreamFrameAcked(*frame.stream_frame, ack_delay); + } + } +} + } // namespace net
diff --git a/net/quic/core/quic_unacked_packet_map.h b/net/quic/core/quic_unacked_packet_map.h index 1901f49e..70549b5 100644 --- a/net/quic/core/quic_unacked_packet_map.h +++ b/net/quic/core/quic_unacked_packet_map.h
@@ -11,6 +11,7 @@ #include "base/macros.h" #include "net/quic/core/quic_packets.h" #include "net/quic/core/quic_transmission_info.h" +#include "net/quic/core/stream_notifier_interface.h" #include "net/quic/platform/api/quic_export.h" namespace net { @@ -50,6 +51,10 @@ void NotifyAndClearListeners(QuicPacketNumber newest_transmission, QuicTime::Delta delta_largest_observed); + // Notifies stream_notifier that stream frames have been acked. + void NotifyStreamFramesAcked(const QuicTransmissionInfo& info, + QuicTime::Delta ack_delay); + // Marks |info| as no longer in flight. void RemoveFromInFlight(QuicTransmissionInfo* info); @@ -146,6 +151,8 @@ // RTT measurement purposes. void RemoveObsoletePackets(); + void SetStreamNotifier(StreamNotifierInterface* stream_notifier); + private: // Called when a packet is retransmitted with a new packet number. // |old_packet_number| will remain unacked, but will have no @@ -194,6 +201,10 @@ // Number of retransmittable crypto handshake packets. size_t pending_crypto_packet_count_; + // Receives notifications of stream frames being retransmitted or + // acknowledged. + StreamNotifierInterface* stream_notifier_; + DISALLOW_COPY_AND_ASSIGN(QuicUnackedPacketMap); };
diff --git a/net/quic/core/stream_notifier_interface.h b/net/quic/core/stream_notifier_interface.h new file mode 100644 index 0000000..34d90be9 --- /dev/null +++ b/net/quic/core/stream_notifier_interface.h
@@ -0,0 +1,29 @@ +// 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. + +#ifndef NET_QUIC_CORE_STREAM_NOTIFIER_INTERFACE_H_ +#define NET_QUIC_CORE_STREAM_NOTIFIER_INTERFACE_H_ + +#include "net/quic/core/frames/quic_stream_frame.h" +#include "net/quic/core/quic_time.h" + +namespace net { + +// Pure virtual class to be notified when a packet containing a stream frame is +// acked or lost. +class QUIC_EXPORT_PRIVATE StreamNotifierInterface { + public: + virtual ~StreamNotifierInterface() {} + + // Called when |frame| is acked. + virtual void OnStreamFrameAcked(const QuicStreamFrame& frame, + QuicTime::Delta ack_delay_time) = 0; + + // Called when |frame| is retransmitted. + virtual void OnStreamFrameRetransmitted(const QuicStreamFrame& frame) = 0; +}; + +} // namespace net + +#endif // NET_QUIC_CORE_STREAM_NOTIFIER_INTERFACE_H_
diff --git a/net/quic/quartc/quartc_factory.cc b/net/quic/quartc/quartc_factory.cc index 2591214..c65a86e 100644 --- a/net/quic/quartc/quartc_factory.cc +++ b/net/quic/quartc/quartc_factory.cc
@@ -112,7 +112,14 @@ : Perspective::IS_CLIENT; std::unique_ptr<QuicConnection> quic_connection = CreateQuicConnection(quartc_session_config, perspective); + QuicTagVector copt; + if (quartc_session_config.congestion_control == + QuartcCongestionControl::kBBR) { + copt.push_back(kTBBR); + } QuicConfig quic_config; + quic_config.SetConnectionOptionsToSend(copt); + quic_config.SetClientConnectionOptions(copt); return std::unique_ptr<QuartcSessionInterface>(new QuartcSession( std::move(quic_connection), quic_config, quartc_session_config.unique_remote_server_id, perspective,
diff --git a/net/quic/quartc/quartc_factory.h b/net/quic/quartc/quartc_factory.h index d6601d9..99268a5 100644 --- a/net/quic/quartc/quartc_factory.h +++ b/net/quic/quartc/quartc_factory.h
@@ -18,9 +18,9 @@ // QuartcSessionInterface. Implements the QuicAlarmFactory to create alarms // using the QuartcTaskRunner. Implements the QuicConnectionHelperInterface used // by the QuicConnections. Only one QuartcFactory is expected to be created. -class QuartcFactory : public QuartcFactoryInterface, - public QuicAlarmFactory, - public QuicConnectionHelperInterface { +class QUIC_EXPORT_PRIVATE QuartcFactory : public QuartcFactoryInterface, + public QuicAlarmFactory, + public QuicConnectionHelperInterface { public: QuartcFactory(const QuartcFactoryConfig& factory_config); ~QuartcFactory() override;
diff --git a/net/quic/quartc/quartc_factory_interface.h b/net/quic/quartc/quartc_factory_interface.h index 1d4db2f..d9e6c1f 100644 --- a/net/quic/quartc/quartc_factory_interface.h +++ b/net/quic/quartc/quartc_factory_interface.h
@@ -16,8 +16,14 @@ namespace net { +// Algorithm to use for congestion control. +enum class QuartcCongestionControl { + kDefault, // Use an arbitrary algorithm chosen by QUIC. + kBBR, // Use BBR. +}; + // Used to create instances for Quartc objects such as QuartcSession. -class QuartcFactoryInterface { +class QUIC_EXPORT_PRIVATE QuartcFactoryInterface { public: virtual ~QuartcFactoryInterface() {} @@ -36,6 +42,10 @@ // The maximum size of the packet can be written with the packet writer. // 1200 bytes by default. uint64_t max_packet_size = 1200; + // Algorithm to use for congestion control. By default, uses an arbitrary + // congestion control algorithm chosen by QUIC. + QuartcCongestionControl congestion_control = + QuartcCongestionControl::kDefault; }; virtual std::unique_ptr<QuartcSessionInterface> CreateQuartcSession(
diff --git a/net/quic/quartc/quartc_packet_writer.h b/net/quic/quartc/quartc_packet_writer.h index 0eda2710..6a18cd4 100644 --- a/net/quic/quartc/quartc_packet_writer.h +++ b/net/quic/quartc/quartc_packet_writer.h
@@ -13,7 +13,7 @@ // Implements a QuicPacketWriter using a // QuartcSessionInterface::PacketTransport, which allows a QuicConnection to // use(for example), a WebRTC IceTransport. -class QuartcPacketWriter : public QuicPacketWriter { +class QUIC_EXPORT_PRIVATE QuartcPacketWriter : public QuicPacketWriter { public: QuartcPacketWriter(QuartcSessionInterface::PacketTransport* packet_transport, QuicByteCount max_packet_size);
diff --git a/net/quic/quartc/quartc_session.cc b/net/quic/quartc/quartc_session.cc index 0e839c9..7e5c5af6 100644 --- a/net/quic/quartc/quartc_session.cc +++ b/net/quic/quartc/quartc_session.cc
@@ -149,7 +149,8 @@ QuartcStream* QuartcSession::CreateOutgoingDynamicStream( SpdyPriority priority) { - return CreateDataStream(GetNextOutgoingStreamId(), priority); + return ActivateDataStream( + CreateDataStream(GetNextOutgoingStreamId(), priority)); } void QuartcSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) { @@ -173,6 +174,21 @@ QuicSession::CloseStream(stream_id); } +void QuartcSession::CancelStream(QuicStreamId stream_id) { + ResetStream(stream_id, QuicRstStreamErrorCode::QUIC_STREAM_CANCELLED); +} + +void QuartcSession::ResetStream(QuicStreamId stream_id, + QuicRstStreamErrorCode error) { + if (!IsOpenStream(stream_id)) { + return; + } + QuicStream* stream = QuicSession::GetOrCreateStream(stream_id); + if (stream) { + stream->Reset(error); + } +} + void QuartcSession::OnConnectionClosed(QuicErrorCode error, const string& error_details, ConnectionCloseSource source) { @@ -267,35 +283,50 @@ } QuicStream* QuartcSession::CreateIncomingDynamicStream(QuicStreamId id) { - QuartcStream* stream = CreateDataStream(id, kDefaultPriority); - if (stream) { - DCHECK(session_delegate_); - session_delegate_->OnIncomingStream(stream); - } - return stream; + return ActivateDataStream(CreateDataStream(id, kDefaultPriority)); } std::unique_ptr<QuicStream> QuartcSession::CreateStream(QuicStreamId id) { - QuartcStream* stream = CreateDataStream(id, kDefaultPriority); - return QuicWrapUnique(stream); + return CreateDataStream(id, kDefaultPriority); } -QuartcStream* QuartcSession::CreateDataStream(QuicStreamId id, - SpdyPriority priority) { +std::unique_ptr<QuartcStream> QuartcSession::CreateDataStream( + QuicStreamId id, + SpdyPriority priority) { if (crypto_stream_ == nullptr || !crypto_stream_->encryption_established()) { // Encryption not active so no stream created return nullptr; } - QuartcStream* stream = new QuartcStream(id, this); + auto stream = QuicMakeUnique<QuartcStream>(id, this); if (stream) { - // Make QuicSession take ownership of the stream. - ActivateStream(std::unique_ptr<QuicStream>(stream)); // Register the stream to the QuicWriteBlockedList. |priority| is clamped // between 0 and 7, with 0 being the highest priority and 7 the lowest // priority. write_blocked_streams()->RegisterStream(stream->id(), priority); + + if (IsIncomingStream(id)) { + DCHECK(session_delegate_); + // Incoming streams need to be registered with the session_delegate_. + session_delegate_->OnIncomingStream(stream.get()); + // Quartc doesn't send on incoming streams. + stream->set_fin_sent(true); + } else { + // Quartc doesn't receive on outgoing streams. + stream->set_fin_received(true); + } } return stream; } +QuartcStream* QuartcSession::ActivateDataStream( + std::unique_ptr<QuartcStream> stream) { + // Transfer ownership of the data stream to the session via ActivateStream(). + QuartcStream* raw = stream.release(); + if (raw) { + // Make QuicSession take ownership of the stream. + ActivateStream(std::unique_ptr<QuicStream>(raw)); + } + return raw; +} + } // namespace net
diff --git a/net/quic/quartc/quartc_session.h b/net/quic/quartc/quartc_session.h index 98a3650..de347aa 100644 --- a/net/quic/quartc/quartc_session.h +++ b/net/quic/quartc/quartc_session.h
@@ -8,6 +8,7 @@ #include "net/quic/core/quic_crypto_client_stream.h" #include "net/quic/core/quic_crypto_server_stream.h" #include "net/quic/core/quic_crypto_stream.h" +#include "net/quic/core/quic_error_codes.h" #include "net/quic/core/quic_session.h" #include "net/quic/quartc/quartc_clock_interface.h" #include "net/quic/quartc/quartc_session_interface.h" @@ -26,9 +27,10 @@ std::string* error_details) const override; }; -class QuartcSession : public QuicSession, - public QuartcSessionInterface, - public QuicCryptoClientStream::ProofHandler { +class QUIC_EXPORT_PRIVATE QuartcSession + : public QuicSession, + public QuartcSessionInterface, + public QuicCryptoClientStream::ProofHandler { public: QuartcSession(std::unique_ptr<QuicConnection> connection, const QuicConfig& config, @@ -67,6 +69,8 @@ QuartcStreamInterface* CreateOutgoingStream( const OutgoingStreamParameters& param) override; + void CancelStream(QuicStreamId stream_id) override; + void SetDelegate(QuartcSessionInterface::Delegate* session_delegate) override; void OnTransportCanWrite() override; @@ -94,7 +98,13 @@ QuicStream* CreateIncomingDynamicStream(QuicStreamId id) override; std::unique_ptr<QuicStream> CreateStream(QuicStreamId id) override; - QuartcStream* CreateDataStream(QuicStreamId id, SpdyPriority priority); + std::unique_ptr<QuartcStream> CreateDataStream(QuicStreamId id, + SpdyPriority priority); + // Activates a QuartcStream. The session takes ownership of the stream, but + // returns an unowned pointer to the stream for convenience. + QuartcStream* ActivateDataStream(std::unique_ptr<QuartcStream> stream); + + void ResetStream(QuicStreamId stream_id, QuicRstStreamErrorCode error); private: // For crypto handshake.
diff --git a/net/quic/quartc/quartc_session_interface.h b/net/quic/quartc/quartc_session_interface.h index f4d88453..03996e6 100644 --- a/net/quic/quartc/quartc_session_interface.h +++ b/net/quic/quartc/quartc_session_interface.h
@@ -9,6 +9,8 @@ #include <stdint.h> #include <string> +#include "net/quic/core/quic_error_codes.h" +#include "net/quic/core/quic_types.h" #include "net/quic/quartc/quartc_stream_interface.h" namespace net { @@ -16,7 +18,7 @@ // Given a PacketTransport, provides a way to send and receive separate streams // of reliable, in-order, encrypted data. For example, this can build on top of // a WebRTC IceTransport for sending and receiving data over QUIC. -class QuartcSessionInterface { +class QUIC_EXPORT_PRIVATE QuartcSessionInterface { public: virtual ~QuartcSessionInterface() {} @@ -48,6 +50,13 @@ virtual QuartcStreamInterface* CreateOutgoingStream( const OutgoingStreamParameters& params) = 0; + // If the given stream is still open, sends a reset frame to cancel it. + // Note: This method cancels a stream by QuicStreamId rather than by pointer + // (or by a method on QuartcStreamInterface) because QuartcSession (and not + // the caller) owns the streams. Streams may finish and be deleted before the + // caller tries to cancel them, rendering the caller's pointers invalid. + virtual void CancelStream(QuicStreamId stream_id) = 0; + // Send and receive packets, like a virtual UDP socket. For example, this // could be implemented by WebRTC's IceTransport. class PacketTransport {
diff --git a/net/quic/quartc/quartc_session_test.cc b/net/quic/quartc/quartc_session_test.cc new file mode 100644 index 0000000..a4fc6232 --- /dev/null +++ b/net/quic/quartc/quartc_session_test.cc
@@ -0,0 +1,641 @@ +// 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 "net/quic/quartc/quartc_session.h" + +#include "net/quic/core/crypto/crypto_server_config_protobuf.h" +#include "net/quic/core/quic_simple_buffer_allocator.h" +#include "net/quic/core/quic_types.h" +#include "net/quic/quartc/quartc_factory.h" +#include "net/quic/quartc/quartc_factory_interface.h" +#include "net/quic/quartc/quartc_packet_writer.h" +#include "net/quic/quartc/quartc_stream_interface.h" +#include "net/quic/test_tools/mock_clock.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using std::string; + +namespace net { + +namespace { + +static const char kExporterLabel[] = "label"; +static const uint8_t kExporterContext[] = "context"; +static const size_t kExporterContextLen = sizeof(kExporterContext); +static const size_t kOutputKeyLength = 20; +static QuartcStreamInterface::WriteParameters kDefaultWriteParam; +static QuartcSessionInterface::OutgoingStreamParameters kDefaultStreamParam; +static QuicByteCount kDefaultMaxPacketSize = 1200; + +// Single-threaded scheduled task runner based on a MockClock. +// +// Simulates asynchronous execution on a single thread by holding scheduled +// tasks until Run() is called. Performs no synchronization, assumes that +// Schedule() and Run() are called on the same thread. +class FakeTaskRunner : public QuartcTaskRunnerInterface { + public: + explicit FakeTaskRunner(MockClock* clock) + : tasks_([this](const TaskType& l, const TaskType& r) { + // Items at a later time should run after items at an earlier time. + // Priority queue comparisons should return true if l appears after r. + return l->time() > r->time(); + }), + clock_(clock) {} + + ~FakeTaskRunner() override {} + + // Runs all tasks scheduled in the next total_ms milliseconds. Advances the + // clock by total_ms. Runs tasks in time order. Executes tasks scheduled at + // the same in an arbitrary order. + void Run(uint32_t total_ms) { + for (uint32_t i = 0; i < total_ms; ++i) { + while (!tasks_.empty() && tasks_.top()->time() <= clock_->Now()) { + tasks_.top()->Run(); + tasks_.pop(); + } + clock_->AdvanceTime(QuicTime::Delta::FromMilliseconds(1)); + } + } + + private: + class InnerTask { + public: + InnerTask(std::function<void()> task, QuicTime time) + : task_(std::move(task)), time_(time) {} + + void Cancel() { cancelled_ = true; } + + void Run() { + if (!cancelled_) { + task_(); + } + } + + QuicTime time() const { return time_; } + + private: + bool cancelled_ = false; + std::function<void()> task_; + QuicTime time_; + }; + + public: + // Hook for cancelling a scheduled task. + class ScheduledTask : public QuartcTaskRunnerInterface::ScheduledTask { + public: + explicit ScheduledTask(std::shared_ptr<InnerTask> inner) + : inner_(std::move(inner)) {} + + // Cancel if the caller deletes the ScheduledTask. This behavior is + // consistent with the actual task runner Quartc uses. + ~ScheduledTask() override { Cancel(); } + + // ScheduledTask implementation. + void Cancel() override { inner_->Cancel(); } + + private: + std::shared_ptr<InnerTask> inner_; + }; + + // See QuartcTaskRunnerInterface. + std::unique_ptr<QuartcTaskRunnerInterface::ScheduledTask> Schedule( + Task* task, + uint64_t delay_ms) override { + auto inner = std::shared_ptr<InnerTask>(new InnerTask( + [task] { task->Run(); }, + clock_->Now() + QuicTime::Delta::FromMilliseconds(delay_ms))); + tasks_.push(inner); + return std::unique_ptr<QuartcTaskRunnerInterface::ScheduledTask>( + new ScheduledTask(inner)); + } + + // Schedules a function to run immediately. + void Schedule(std::function<void()> task) { + tasks_.push(std::shared_ptr<InnerTask>( + new InnerTask(std::move(task), clock_->Now()))); + } + + private: + // InnerTasks are shared by the queue and ScheduledTask (which hooks into it + // to implement Cancel()). + using TaskType = std::shared_ptr<InnerTask>; + std::priority_queue<TaskType, + std::vector<TaskType>, + std::function<bool(const TaskType&, const TaskType&)>> + tasks_; + MockClock* clock_; +}; + +// QuartcClock that wraps a MockClock. +// +// This is silly because Quartc wraps it as a QuicClock, and MockClock is +// already a QuicClock. But we don't have much choice. We need to pass a +// QuartcClockInterface into the Quartc wrappers. +class MockQuartcClock : public QuartcClockInterface { + public: + explicit MockQuartcClock(MockClock* clock) : clock_(clock) {} + + int64_t NowMicroseconds() override { + return clock_->WallNow().ToUNIXMicroseconds(); + } + + private: + MockClock* clock_; +}; + +// Used by QuicCryptoServerConfig to provide server credentials, returning a +// canned response equal to |success|. +class FakeProofSource : public ProofSource { + public: + explicit FakeProofSource(bool success) : success_(success) {} + + // ProofSource override. + void GetProof(const QuicSocketAddress& server_ip, + const string& hostname, + const string& server_config, + QuicVersion quic_version, + QuicStringPiece chlo_hash, + const QuicTagVector& connection_options, + std::unique_ptr<Callback> callback) override { + QuicReferenceCountedPointer<ProofSource::Chain> chain; + QuicCryptoProof proof; + if (success_) { + std::vector<string> certs; + certs.push_back("Required to establish handshake"); + chain = new ProofSource::Chain(certs); + proof.signature = "Signature"; + proof.leaf_cert_scts = "Time"; + } + callback->Run(success_, chain, proof, nullptr /* details */); + } + + private: + // Whether or not obtaining proof source succeeds. + bool success_; +}; + +// Used by QuicCryptoClientConfig to verify server credentials, returning a +// canned response of QUIC_SUCCESS if |success| is true. +class FakeProofVerifier : public ProofVerifier { + public: + explicit FakeProofVerifier(bool success) : success_(success) {} + + // ProofVerifier override + QuicAsyncStatus VerifyProof( + const string& hostname, + const uint16_t port, + const string& server_config, + QuicVersion quic_version, + QuicStringPiece chlo_hash, + const std::vector<string>& certs, + const string& cert_sct, + const string& signature, + const ProofVerifyContext* context, + string* error_details, + std::unique_ptr<ProofVerifyDetails>* verify_details, + std::unique_ptr<ProofVerifierCallback> callback) override { + return success_ ? QUIC_SUCCESS : QUIC_FAILURE; + } + + QuicAsyncStatus VerifyCertChain( + const string& hostname, + const std::vector<string>& certs, + const ProofVerifyContext* context, + string* error_details, + std::unique_ptr<ProofVerifyDetails>* details, + std::unique_ptr<ProofVerifierCallback> callback) override { + LOG(INFO) << "VerifyProof() ignoring credentials and returning success"; + return success_ ? QUIC_SUCCESS : QUIC_FAILURE; + } + + private: + // Whether or not proof verification succeeds. + bool success_; +}; + +// Used by the FakeTransportChannel. +class FakeTransportChannelObserver { + public: + virtual ~FakeTransportChannelObserver() {} + + // Called when the other peer is trying to send message. + virtual void OnTransportChannelReadPacket(const string& data) = 0; +}; + +// Simulate the P2P communication transport. Used by the +// QuartcSessionInterface::Transport. +class FakeTransportChannel { + public: + explicit FakeTransportChannel(FakeTaskRunner* task_runner, MockClock* clock) + : task_runner_(task_runner), clock_(clock) {} + + void SetDestination(FakeTransportChannel* dest) { + if (!dest_) { + dest_ = dest; + dest_->SetDestination(this); + } + } + + int SendPacket(const char* data, size_t len) { + // If the destination is not set. + if (!dest_) { + return -1; + } + // Advance the time 10us to ensure the RTT is never 0ms. + clock_->AdvanceTime(QuicTime::Delta::FromMicroseconds(10)); + if (async_ && task_runner_) { + string packet(data, len); + task_runner_->Schedule([this, packet] { send(packet); }); + } else { + send(string(data, len)); + } + return static_cast<int>(len); + } + + void send(const string& data) { + DCHECK(dest_); + DCHECK(dest_->observer()); + dest_->observer()->OnTransportChannelReadPacket(data); + } + + FakeTransportChannelObserver* observer() { return observer_; } + + void SetObserver(FakeTransportChannelObserver* observer) { + observer_ = observer; + } + + void SetAsync(bool async) { async_ = async; } + + private: + // The writing destination of this channel. + FakeTransportChannel* dest_ = nullptr; + // The observer of this channel. Called when the received the data. + FakeTransportChannelObserver* observer_ = nullptr; + // If async, will send packets by running asynchronous tasks. + bool async_ = false; + // Used to send data asynchronously. + FakeTaskRunner* task_runner_; + // The test clock. Used to ensure the RTT is not 0. + MockClock* clock_; +}; + +// Used by the QuartcPacketWriter. +class FakeTransport : public QuartcSessionInterface::PacketTransport { + public: + explicit FakeTransport(FakeTransportChannel* channel) : channel_(channel) {} + + bool CanWrite() override { return true; } + + int Write(const char* buffer, size_t buf_len) override { + DCHECK(channel_); + return channel_->SendPacket(buffer, buf_len); + } + + private: + FakeTransportChannel* channel_; +}; + +class FakeQuartcSessionDelegate : public QuartcSessionInterface::Delegate { + public: + explicit FakeQuartcSessionDelegate( + QuartcStreamInterface::Delegate* stream_delegate) + : stream_delegate_(stream_delegate) {} + // Called when peers have established forward-secure encryption + void OnCryptoHandshakeComplete() override { + LOG(INFO) << "Crypto handshake complete!"; + } + // Called when connection closes locally, or remotely by peer. + void OnConnectionClosed(int error_code, bool from_remote) override { + connected_ = false; + } + // Called when an incoming QUIC stream is created. + void OnIncomingStream(QuartcStreamInterface* quartc_stream) override { + last_incoming_stream_ = quartc_stream; + last_incoming_stream_->SetDelegate(stream_delegate_); + } + + QuartcStreamInterface* incoming_stream() { return last_incoming_stream_; } + + bool connected() { return connected_; } + + private: + QuartcStreamInterface* last_incoming_stream_; + bool connected_ = true; + QuartcStream::Delegate* stream_delegate_; +}; + +class FakeQuartcStreamDelegate : public QuartcStreamInterface::Delegate { + public: + void OnReceived(QuartcStreamInterface* stream, + const char* data, + size_t size) override { + last_received_data_ = string(data, size); + } + + void OnClose(QuartcStreamInterface* stream) override {} + + void OnBufferedAmountDecrease(QuartcStreamInterface* stream) override {} + + string data() { return last_received_data_; } + + private: + string last_received_data_; +}; + +class QuartcSessionForTest : public QuartcSession, + public FakeTransportChannelObserver { + public: + QuartcSessionForTest(std::unique_ptr<QuicConnection> connection, + const QuicConfig& config, + const string& remote_fingerprint_value, + Perspective perspective, + QuicConnectionHelperInterface* helper, + QuicClock* clock) + : QuartcSession(std::move(connection), + config, + remote_fingerprint_value, + perspective, + helper, + clock) { + stream_delegate_.reset(new FakeQuartcStreamDelegate); + session_delegate_.reset( + new FakeQuartcSessionDelegate(stream_delegate_.get())); + + SetDelegate(session_delegate_.get()); + } + + // QuartcPacketWriter override. + void OnTransportChannelReadPacket(const string& data) override { + OnTransportReceived(data.c_str(), data.length()); + } + + string data() { return stream_delegate_->data(); } + + bool has_data() { return !data().empty(); } + + FakeQuartcSessionDelegate* session_delegate() { + return session_delegate_.get(); + } + + FakeQuartcStreamDelegate* stream_delegate() { return stream_delegate_.get(); } + + private: + std::unique_ptr<FakeQuartcStreamDelegate> stream_delegate_; + std::unique_ptr<FakeQuartcSessionDelegate> session_delegate_; +}; + +class QuartcSessionTest : public ::testing::Test, + public QuicConnectionHelperInterface { + public: + ~QuartcSessionTest() override {} + + void Init() { + // Quic crashes if packets are sent at time 0, and the clock defaults to 0. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1000)); + client_channel_.reset(new FakeTransportChannel(&task_runner_, &clock_)); + server_channel_.reset(new FakeTransportChannel(&task_runner_, &clock_)); + // Make the channel asynchronous so that two peer will not keep calling each + // other when they exchange information. + client_channel_->SetAsync(true); + client_channel_->SetDestination(server_channel_.get()); + + client_transport_.reset(new FakeTransport(client_channel_.get())); + server_transport_.reset(new FakeTransport(server_channel_.get())); + + client_writer_.reset( + new QuartcPacketWriter(client_transport_.get(), kDefaultMaxPacketSize)); + server_writer_.reset( + new QuartcPacketWriter(server_transport_.get(), kDefaultMaxPacketSize)); + } + + // The parameters are used to control whether the handshake will success or + // not. + void CreateClientAndServerSessions(bool client_handshake_success = true, + bool server_handshake_success = true) { + Init(); + client_peer_ = CreateSession(Perspective::IS_CLIENT); + server_peer_ = CreateSession(Perspective::IS_SERVER); + + client_channel_->SetObserver(client_peer_.get()); + server_channel_->SetObserver(server_peer_.get()); + + client_peer_->SetClientCryptoConfig( + new QuicCryptoClientConfig(std::unique_ptr<ProofVerifier>( + new FakeProofVerifier(client_handshake_success)))); + + QuicCryptoServerConfig* server_config = new QuicCryptoServerConfig( + "TESTING", QuicRandom::GetInstance(), + std::unique_ptr<FakeProofSource>( + new FakeProofSource(server_handshake_success))); + // Provide server with serialized config string to prove ownership. + QuicCryptoServerConfig::ConfigOptions options; + std::unique_ptr<QuicServerConfigProtobuf> primary_config( + server_config->GenerateConfig(QuicRandom::GetInstance(), &clock_, + options)); + std::unique_ptr<CryptoHandshakeMessage> message( + server_config->AddConfig(std::move(primary_config), clock_.WallNow())); + + server_peer_->SetServerCryptoConfig(server_config); + } + + std::unique_ptr<QuartcSessionForTest> CreateSession(Perspective perspective) { + std::unique_ptr<QuicConnection> quic_connection = + CreateConnection(perspective); + string remote_fingerprint_value = "value"; + QuicConfig config; + return std::unique_ptr<QuartcSessionForTest>(new QuartcSessionForTest( + std::move(quic_connection), config, remote_fingerprint_value, + perspective, this, &clock_)); + } + + std::unique_ptr<QuicConnection> CreateConnection(Perspective perspective) { + QuartcPacketWriter* writer = perspective == Perspective::IS_CLIENT + ? client_writer_.get() + : server_writer_.get(); + QuicIpAddress ip; + ip.FromString("0.0.0.0"); + bool owns_writer = false; + if (!alarm_factory_) { + // QuartcFactory is only used as an alarm factory. + QuartcFactoryConfig config; + config.clock = &quartc_clock_; + config.task_runner = &task_runner_; + alarm_factory_.reset(new QuartcFactory(config)); + } + return std::unique_ptr<QuicConnection>(new QuicConnection( + 0, QuicSocketAddress(ip, 0), this /*QuicConnectionHelperInterface*/, + alarm_factory_.get(), writer, owns_writer, perspective, + AllSupportedVersions())); + } + + // Runs all tasks scheduled in the next 200 ms. + void RunTasks() { task_runner_.Run(200); } + + void StartHandshake() { + server_peer_->StartCryptoHandshake(); + client_peer_->StartCryptoHandshake(); + RunTasks(); + } + + // Test handshake establishment and sending/receiving of data for two + // directions. + void TestStreamConnection() { + ASSERT_TRUE(server_peer_->IsCryptoHandshakeConfirmed()); + ASSERT_TRUE(client_peer_->IsCryptoHandshakeConfirmed()); + ASSERT_TRUE(server_peer_->IsEncryptionEstablished()); + ASSERT_TRUE(client_peer_->IsEncryptionEstablished()); + + uint8_t server_key[kOutputKeyLength]; + uint8_t client_key[kOutputKeyLength]; + bool use_context = true; + bool server_success = server_peer_->ExportKeyingMaterial( + kExporterLabel, kExporterContext, kExporterContextLen, use_context, + server_key, kOutputKeyLength); + ASSERT_TRUE(server_success); + bool client_success = client_peer_->ExportKeyingMaterial( + kExporterLabel, kExporterContext, kExporterContextLen, use_context, + client_key, kOutputKeyLength); + ASSERT_TRUE(client_success); + EXPECT_EQ(0, memcmp(server_key, client_key, sizeof(server_key))); + + // Now we can establish encrypted outgoing stream. + QuartcStreamInterface* outgoing_stream = + server_peer_->CreateOutgoingStream(kDefaultStreamParam); + ASSERT_NE(nullptr, outgoing_stream); + EXPECT_TRUE(server_peer_->HasOpenDynamicStreams()); + + outgoing_stream->SetDelegate(server_peer_->stream_delegate()); + + // Send a test message from peer 1 to peer 2. + const char kTestMessage[] = "Hello"; + outgoing_stream->Write(kTestMessage, strlen(kTestMessage), + kDefaultWriteParam); + RunTasks(); + + // Wait for peer 2 to receive messages. + ASSERT_TRUE(client_peer_->has_data()); + + QuartcStreamInterface* incoming = + client_peer_->session_delegate()->incoming_stream(); + ASSERT_TRUE(incoming); + EXPECT_TRUE(client_peer_->HasOpenDynamicStreams()); + + EXPECT_EQ(client_peer_->data(), kTestMessage); + // Send a test message from peer 2 to peer 1. + const char kTestResponse[] = "Response"; + incoming->Write(kTestResponse, strlen(kTestResponse), kDefaultWriteParam); + RunTasks(); + // Wait for peer 1 to receive messages. + ASSERT_TRUE(server_peer_->has_data()); + + EXPECT_EQ(server_peer_->data(), kTestResponse); + } + + // Test that client and server are not connected after handshake failure. + void TestDisconnectAfterFailedHandshake() { + EXPECT_TRUE(!client_peer_->session_delegate()->connected()); + EXPECT_TRUE(!server_peer_->session_delegate()->connected()); + + EXPECT_FALSE(client_peer_->IsEncryptionEstablished()); + EXPECT_FALSE(client_peer_->IsCryptoHandshakeConfirmed()); + + EXPECT_FALSE(server_peer_->IsEncryptionEstablished()); + EXPECT_FALSE(server_peer_->IsCryptoHandshakeConfirmed()); + } + + const QuicClock* GetClock() const override { return &clock_; } + + QuicRandom* GetRandomGenerator() override { + return QuicRandom::GetInstance(); + } + + QuicBufferAllocator* GetBufferAllocator() override { + return &buffer_allocator_; + } + + protected: + std::unique_ptr<QuicAlarmFactory> alarm_factory_; + SimpleBufferAllocator buffer_allocator_; + MockClock clock_; + MockQuartcClock quartc_clock_{&clock_}; + + std::unique_ptr<FakeTransportChannel> client_channel_; + std::unique_ptr<FakeTransportChannel> server_channel_; + std::unique_ptr<FakeTransport> client_transport_; + std::unique_ptr<FakeTransport> server_transport_; + std::unique_ptr<QuartcPacketWriter> client_writer_; + std::unique_ptr<QuartcPacketWriter> server_writer_; + std::unique_ptr<QuartcSessionForTest> client_peer_; + std::unique_ptr<QuartcSessionForTest> server_peer_; + + FakeTaskRunner task_runner_{&clock_}; +}; + +TEST_F(QuartcSessionTest, StreamConnection) { + CreateClientAndServerSessions(); + StartHandshake(); + TestStreamConnection(); +} + +TEST_F(QuartcSessionTest, ClientRejection) { + CreateClientAndServerSessions(false /*client_handshake_success*/, + true /*server_handshake_success*/); + StartHandshake(); + TestDisconnectAfterFailedHandshake(); +} + +TEST_F(QuartcSessionTest, ServerRejection) { + CreateClientAndServerSessions(true /*client_handshake_success*/, + false /*server_handshake_success*/); + StartHandshake(); + TestDisconnectAfterFailedHandshake(); +} + +// Test that data streams are not created before handshake. +TEST_F(QuartcSessionTest, CannotCreateDataStreamBeforeHandshake) { + CreateClientAndServerSessions(); + EXPECT_EQ(nullptr, server_peer_->CreateOutgoingStream(kDefaultStreamParam)); + EXPECT_EQ(nullptr, client_peer_->CreateOutgoingStream(kDefaultStreamParam)); +} + +TEST_F(QuartcSessionTest, CloseQuartcStream) { + CreateClientAndServerSessions(); + StartHandshake(); + ASSERT_TRUE(client_peer_->IsCryptoHandshakeConfirmed()); + ASSERT_TRUE(server_peer_->IsCryptoHandshakeConfirmed()); + QuartcStreamInterface* stream = + client_peer_->CreateOutgoingStream(kDefaultStreamParam); + ASSERT_NE(nullptr, stream); + + uint32_t id = stream->stream_id(); + EXPECT_FALSE(client_peer_->IsClosedStream(id)); + stream->SetDelegate(client_peer_->stream_delegate()); + stream->Close(); + RunTasks(); + EXPECT_TRUE(client_peer_->IsClosedStream(id)); +} + +TEST_F(QuartcSessionTest, CancelQuartcStream) { + CreateClientAndServerSessions(); + StartHandshake(); + ASSERT_TRUE(client_peer_->IsCryptoHandshakeConfirmed()); + ASSERT_TRUE(server_peer_->IsCryptoHandshakeConfirmed()); + + QuartcStreamInterface* stream = + client_peer_->CreateOutgoingStream(kDefaultStreamParam); + ASSERT_NE(nullptr, stream); + + uint32_t id = stream->stream_id(); + EXPECT_FALSE(client_peer_->IsClosedStream(id)); + stream->SetDelegate(client_peer_->stream_delegate()); + client_peer_->CancelStream(id); + EXPECT_EQ(stream->stream_error(), + QuicRstStreamErrorCode::QUIC_STREAM_CANCELLED); + EXPECT_TRUE(client_peer_->IsClosedStream(id)); +} + +} // namespace + +} // namespace net
diff --git a/net/quic/quartc/quartc_stream.cc b/net/quic/quartc/quartc_stream.cc index 932f14d1..2cae48d 100644 --- a/net/quic/quartc/quartc_stream.cc +++ b/net/quic/quartc/quartc_stream.cc
@@ -31,7 +31,7 @@ void QuartcStream::OnClose() { QuicStream::OnClose(); DCHECK(delegate_); - delegate_->OnClose(this, connection_error()); + delegate_->OnClose(this); } void QuartcStream::OnCanWrite() { @@ -52,6 +52,14 @@ return QuicStream::fin_sent(); } +int QuartcStream::stream_error() { + return QuicStream::stream_error(); +} + +int QuartcStream::connection_error() { + return QuicStream::connection_error(); +} + void QuartcStream::Write(const char* data, size_t size, const WriteParameters& param) {
diff --git a/net/quic/quartc/quartc_stream.h b/net/quic/quartc/quartc_stream.h index 1883451..3ee21a4 100644 --- a/net/quic/quartc/quartc_stream.h +++ b/net/quic/quartc/quartc_stream.h
@@ -12,7 +12,8 @@ namespace net { // Implements a QuartcStreamInterface using a QuicStream. -class QuartcStream : public QuicStream, public QuartcStreamInterface { +class QUIC_EXPORT_PRIVATE QuartcStream : public QuicStream, + public QuartcStreamInterface { public: QuartcStream(QuicStreamId id, QuicSession* session); @@ -32,6 +33,10 @@ bool fin_sent() override; + int stream_error() override; + + int connection_error() override; + void Write(const char* data, size_t size, const WriteParameters& param) override;
diff --git a/net/quic/quartc/quartc_stream_interface.h b/net/quic/quartc/quartc_stream_interface.h index 25e928e..5e816a32 100644 --- a/net/quic/quartc/quartc_stream_interface.h +++ b/net/quic/quartc/quartc_stream_interface.h
@@ -14,7 +14,7 @@ // in-order. To send/receive data out of order, use separate streams. To // send/receive unreliably, close a stream after reliability is no longer // needed. -class QuartcStreamInterface { +class QUIC_EXPORT_PRIVATE QuartcStreamInterface { public: virtual ~QuartcStreamInterface() {} @@ -28,6 +28,10 @@ // determine if all the data has been sent virtual bool fin_sent() = 0; + virtual int stream_error() = 0; + + virtual int connection_error() = 0; + struct WriteParameters { WriteParameters() : fin(false) {} // |fin| is set to be true when there is no more data need to be send @@ -61,7 +65,7 @@ // endpoint. // TODO(zhihuang) Creates a map from the integer error_code to WebRTC native // error code. - virtual void OnClose(QuartcStreamInterface* stream, int error_code) = 0; + virtual void OnClose(QuartcStreamInterface* stream) = 0; // Called when buffered_amount() decreases. virtual void OnBufferedAmountDecrease(QuartcStreamInterface* stream) = 0;
diff --git a/net/quic/quartc/quartc_stream_test.cc b/net/quic/quartc/quartc_stream_test.cc new file mode 100644 index 0000000..3302df6 --- /dev/null +++ b/net/quic/quartc/quartc_stream_test.cc
@@ -0,0 +1,276 @@ +// 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 "net/quic/quartc/quartc_stream.h" + +#include "net/quic/core/crypto/quic_random.h" +#include "net/quic/core/quic_session.h" +#include "net/quic/core/quic_simple_buffer_allocator.h" +#include "net/quic/quartc/quartc_clock_interface.h" +#include "net/quic/quartc/quartc_factory.h" +#include "net/quic/test_tools/mock_clock.h" +#include "net/spdy/core/spdy_protocol.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace net { + +namespace { + +static const SpdyPriority kDefaultPriority = 3; +static const QuicStreamId kStreamId = 5; +static const QuartcStreamInterface::WriteParameters kDefaultParam; + +// MockQuicSession that does not create streams and writes data from +// QuicStream to a string. +class MockQuicSession : public QuicSession { + public: + MockQuicSession(QuicConnection* connection, + const QuicConfig& config, + std::string* write_buffer) + : QuicSession(connection, nullptr /*visitor*/, config), + write_buffer_(write_buffer) {} + + ~MockQuicSession() override {} + + // Writes outgoing data from QuicStream to a string. + QuicConsumedData WritevData( + QuicStream* stream, + QuicStreamId id, + QuicIOVector iovector, + QuicStreamOffset offset, + StreamSendingState state, + QuicReferenceCountedPointer< + QuicAckListenerInterface> /*ack_notifier_delegate*/) override { + if (!writable_) { + return QuicConsumedData(0, false); + } + + const char* data = reinterpret_cast<const char*>(iovector.iov->iov_base); + size_t len = iovector.total_length; + write_buffer_->append(data, len); + return QuicConsumedData(len, state != StreamSendingState::NO_FIN); + } + + QuartcStream* CreateIncomingDynamicStream(QuicStreamId id) override { + return nullptr; + } + + QuartcStream* CreateOutgoingDynamicStream(SpdyPriority priority) override { + return nullptr; + } + + const QuicCryptoStream* GetCryptoStream() const override { return nullptr; } + QuicCryptoStream* GetMutableCryptoStream() override { return nullptr; } + + // Called by QuicStream when they want to close stream. + void SendRstStream(QuicStreamId id, + QuicRstStreamErrorCode error, + QuicStreamOffset bytes_written) override {} + + // Sets whether data is written to buffer, or else if this is write blocked. + void set_writable(bool writable) { writable_ = writable; } + + // Tracks whether the stream is write blocked and its priority. + void RegisterReliableStream(QuicStreamId stream_id, SpdyPriority priority) { + write_blocked_streams()->RegisterStream(stream_id, priority); + } + + // The session take ownership of the stream. + void ActivateReliableStream(std::unique_ptr<QuicStream> stream) { + ActivateStream(std::move(stream)); + } + + protected: + std::unique_ptr<QuicStream> CreateStream(QuicStreamId id) override { + return nullptr; + } + + private: + // Stores written data from ReliableQuicStreamAdapter. + std::string* write_buffer_; + // Whether data is written to write_buffer_. + bool writable_ = true; +}; + +// Packet writer that does nothing. This is required for QuicConnection but +// isn't used for writing data. +class DummyPacketWriter : public QuicPacketWriter { + public: + DummyPacketWriter() {} + + // QuicPacketWriter overrides. + WriteResult WritePacket(const char* buffer, + size_t buf_len, + const QuicIpAddress& self_address, + const QuicSocketAddress& peer_address, + PerPacketOptions* options) override { + return WriteResult(WRITE_STATUS_ERROR, 0); + } + + bool IsWriteBlockedDataBuffered() const override { return false; } + + bool IsWriteBlocked() const override { return false; }; + + void SetWritable() override {} + + QuicByteCount GetMaxPacketSize( + const QuicSocketAddress& peer_address) const override { + return 0; + } +}; + +class MockQuartcStreamDelegate : public QuartcStreamInterface::Delegate { + public: + MockQuartcStreamDelegate(int id, std::string* read_buffer) + : id_(id), read_buffer_(read_buffer) {} + + void OnBufferedAmountDecrease(QuartcStreamInterface* stream) override { + queued_bytes_amount_ = stream->buffered_amount(); + } + + void OnReceived(QuartcStreamInterface* stream, + const char* data, + size_t size) override { + EXPECT_EQ(id_, stream->stream_id()); + read_buffer_->append(data, size); + } + + void OnClose(QuartcStreamInterface* stream) override { closed_ = true; } + + bool closed() { return closed_; } + + int queued_bytes_amount() { return queued_bytes_amount_; } + + protected: + uint32_t id_; + // Data read by the QuicStream. + std::string* read_buffer_; + // Whether the QuicStream is closed. + bool closed_ = false; + int queued_bytes_amount_ = -1; +}; + +class QuartcStreamTest : public ::testing::Test, + public QuicConnectionHelperInterface { + public: + void CreateReliableQuicStream() { + // Arbitrary values for QuicConnection. + Perspective perspective = Perspective::IS_SERVER; + QuicIpAddress ip; + ip.FromString("0.0.0.0"); + bool owns_writer = true; + + // We only use QuartcFactory for its role as an alarm factory. + QuartcFactoryConfig config; + alarm_factory_.reset(new QuartcFactory(config)); + + connection_.reset(new QuicConnection( + 0, QuicSocketAddress(ip, 0), this /*QuicConnectionHelperInterface*/, + alarm_factory_.get(), new DummyPacketWriter(), owns_writer, perspective, + AllSupportedVersions())); + + session_.reset( + new MockQuicSession(connection_.get(), QuicConfig(), &write_buffer_)); + mock_stream_delegate_.reset( + new MockQuartcStreamDelegate(kStreamId, &read_buffer_)); + stream_ = new QuartcStream(kStreamId, session_.get()); + stream_->SetDelegate(mock_stream_delegate_.get()); + session_->RegisterReliableStream(stream_->stream_id(), kDefaultPriority); + session_->ActivateReliableStream(std::unique_ptr<QuartcStream>(stream_)); + } + + ~QuartcStreamTest() override {} + + const QuicClock* GetClock() const override { return &clock_; } + + QuicRandom* GetRandomGenerator() override { + return QuicRandom::GetInstance(); + } + + QuicBufferAllocator* GetBufferAllocator() override { + return &buffer_allocator_; + } + + protected: + // The QuicSession will take the ownership. + QuartcStream* stream_; + std::unique_ptr<MockQuartcStreamDelegate> mock_stream_delegate_; + std::unique_ptr<MockQuicSession> session_; + // Data written by the ReliableQuicStreamAdapterTest. + std::string write_buffer_; + // Data read by the ReliableQuicStreamAdapterTest. + std::string read_buffer_; + std::unique_ptr<QuicAlarmFactory> alarm_factory_; + std::unique_ptr<QuicConnection> connection_; + // Used to implement the QuicConnectionHelperInterface. + SimpleBufferAllocator buffer_allocator_; + MockClock clock_; +}; + +// Write an entire string. +TEST_F(QuartcStreamTest, WriteDataWhole) { + CreateReliableQuicStream(); + stream_->Write("Foo bar", 7, kDefaultParam); + EXPECT_EQ("Foo bar", write_buffer_); +} + +// Write part of a string. +TEST_F(QuartcStreamTest, WriteDataPartial) { + CreateReliableQuicStream(); + stream_->Write("Foo bar", 5, kDefaultParam); + EXPECT_EQ("Foo b", write_buffer_); +} + +// Test that strings are buffered correctly. +TEST_F(QuartcStreamTest, BufferData) { + CreateReliableQuicStream(); + + session_->set_writable(false); + stream_->Write("Foo bar", 7, kDefaultParam); + // The data will be buffered. + EXPECT_EQ(0ul, write_buffer_.size()); + EXPECT_TRUE(stream_->HasBufferedData()); + EXPECT_EQ(-1, mock_stream_delegate_->queued_bytes_amount()); + // The session is writable and the buffered data amount will change. + session_->set_writable(true); + stream_->OnCanWrite(); + EXPECT_EQ(0, mock_stream_delegate_->queued_bytes_amount()); + EXPECT_FALSE(stream_->HasBufferedData()); + EXPECT_EQ("Foo bar", write_buffer_); + + stream_->Write("xyzzy", 5, kDefaultParam); + EXPECT_EQ("Foo barxyzzy", write_buffer_); +} + +// Read an entire string. +TEST_F(QuartcStreamTest, ReadDataWhole) { + CreateReliableQuicStream(); + QuicStreamFrame frame(kStreamId, false, 0, "Hello, World!"); + stream_->OnStreamFrame(frame); + + EXPECT_EQ("Hello, World!", read_buffer_); +} + +// Read part of a string. +TEST_F(QuartcStreamTest, ReadDataPartial) { + CreateReliableQuicStream(); + QuicStreamFrame frame(kStreamId, false, 0, "Hello, World!"); + frame.data_length = 5; + stream_->OnStreamFrame(frame); + + EXPECT_EQ("Hello", read_buffer_); +} + +// Test that closing the stream results in a callback. +TEST_F(QuartcStreamTest, CloseStream) { + CreateReliableQuicStream(); + EXPECT_FALSE(mock_stream_delegate_->closed()); + stream_->OnClose(); + EXPECT_TRUE(mock_stream_delegate_->closed()); +} + +} // namespace + +} // namespace net
diff --git a/net/quic/test_tools/quic_session_peer.cc b/net/quic/test_tools/quic_session_peer.cc index b744aa3..a5ca5d62 100644 --- a/net/quic/test_tools/quic_session_peer.cc +++ b/net/quic/test_tools/quic_session_peer.cc
@@ -71,6 +71,18 @@ } // static +const QuicSession::ClosedStreams& QuicSessionPeer::closed_streams( + QuicSession* session) { + return *session->closed_streams(); +} + +// static +const QuicSession::ZombieStreamMap& QuicSessionPeer::zombie_streams( + QuicSession* session) { + return session->zombie_streams(); +} + +// static std::unordered_set<QuicStreamId>* QuicSessionPeer::GetDrainingStreams( QuicSession* session) { return &session->draining_streams_;
diff --git a/net/quic/test_tools/quic_session_peer.h b/net/quic/test_tools/quic_session_peer.h index f89238b1..f0c3e00 100644 --- a/net/quic/test_tools/quic_session_peer.h +++ b/net/quic/test_tools/quic_session_peer.h
@@ -38,6 +38,9 @@ GetLocallyClosedStreamsHighestOffset(QuicSession* session); static QuicSession::StaticStreamMap& static_streams(QuicSession* session); static QuicSession::DynamicStreamMap& dynamic_streams(QuicSession* session); + static const QuicSession::ClosedStreams& closed_streams(QuicSession* session); + static const QuicSession::ZombieStreamMap& zombie_streams( + QuicSession* session); static std::unordered_set<QuicStreamId>* GetDrainingStreams( QuicSession* session); static void ActivateStream(QuicSession* session,
diff --git a/net/quic/test_tools/simulator/quic_endpoint_test.cc b/net/quic/test_tools/simulator/quic_endpoint_test.cc index 1253517..fffd3638 100644 --- a/net/quic/test_tools/simulator/quic_endpoint_test.cc +++ b/net/quic/test_tools/simulator/quic_endpoint_test.cc
@@ -147,8 +147,6 @@ // Simulate three hosts trying to send data to a fourth one simultaneously. TEST_F(QuicEndpointTest, Competition) { - simulator_.set_enable_random_delays(true); - auto endpoint_a = QuicMakeUnique<QuicEndpoint>( &simulator_, "Endpoint A", "Endpoint D (A)", Perspective::IS_CLIENT, 42); auto endpoint_b = QuicMakeUnique<QuicEndpoint>(
diff --git a/net/spdy/chromium/bidirectional_stream_spdy_impl.cc b/net/spdy/chromium/bidirectional_stream_spdy_impl.cc index dbef1f0c..fa223bb4 100644 --- a/net/spdy/chromium/bidirectional_stream_spdy_impl.cc +++ b/net/spdy/chromium/bidirectional_stream_spdy_impl.cc
@@ -110,30 +110,6 @@ return ERR_IO_PENDING; } -void BidirectionalStreamSpdyImpl::SendData(const scoped_refptr<IOBuffer>& data, - int length, - bool end_stream) { - DCHECK(length > 0 || (length == 0 && end_stream)); - DCHECK(!write_pending_); - - if (written_end_of_stream_) { - LOG(ERROR) << "Writing after end of stream is written."; - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(&BidirectionalStreamSpdyImpl::NotifyError, - weak_factory_.GetWeakPtr(), ERR_UNEXPECTED)); - return; - } - - write_pending_ = true; - written_end_of_stream_ = end_stream; - if (MaybeHandleStreamClosedInSendData()) - return; - - DCHECK(!stream_closed_); - stream_->SendData(data.get(), length, - end_stream ? NO_MORE_DATA_TO_SEND : MORE_DATA_TO_SEND); -} - void BidirectionalStreamSpdyImpl::SendvData( const std::vector<scoped_refptr<IOBuffer>>& buffers, const std::vector<int>& lengths, @@ -160,13 +136,17 @@ total_len += len; } - pending_combined_buffer_ = new net::IOBuffer(total_len); - int len = 0; - // TODO(xunjieli): Get rid of extra copy. Coalesce headers and data frames. - for (size_t i = 0; i < buffers.size(); ++i) { - memcpy(pending_combined_buffer_->data() + len, buffers[i]->data(), - lengths[i]); - len += lengths[i]; + if (buffers.size() == 1) { + pending_combined_buffer_ = buffers[0]; + } else { + pending_combined_buffer_ = new net::IOBuffer(total_len); + int len = 0; + // TODO(xunjieli): Get rid of extra copy. Coalesce headers and data frames. + for (size_t i = 0; i < buffers.size(); ++i) { + memcpy(pending_combined_buffer_->data() + len, buffers[i]->data(), + lengths[i]); + len += lengths[i]; + } } stream_->SendData(pending_combined_buffer_.get(), total_len, end_stream ? NO_MORE_DATA_TO_SEND : MORE_DATA_TO_SEND);
diff --git a/net/spdy/chromium/bidirectional_stream_spdy_impl.h b/net/spdy/chromium/bidirectional_stream_spdy_impl.h index b40f3c0..61e00e0 100644 --- a/net/spdy/chromium/bidirectional_stream_spdy_impl.h +++ b/net/spdy/chromium/bidirectional_stream_spdy_impl.h
@@ -50,9 +50,6 @@ std::unique_ptr<base::Timer> timer) override; void SendRequestHeaders() override; int ReadData(IOBuffer* buf, int buf_len) override; - void SendData(const scoped_refptr<IOBuffer>& data, - int length, - bool end_stream) override; void SendvData(const std::vector<scoped_refptr<IOBuffer>>& buffers, const std::vector<int>& lengths, bool end_stream) override;
diff --git a/net/spdy/chromium/bidirectional_stream_spdy_impl_unittest.cc b/net/spdy/chromium/bidirectional_stream_spdy_impl_unittest.cc index 3b81307c..e291424b 100644 --- a/net/spdy/chromium/bidirectional_stream_spdy_impl_unittest.cc +++ b/net/spdy/chromium/bidirectional_stream_spdy_impl_unittest.cc
@@ -139,9 +139,7 @@ } void SendData(IOBuffer* data, int length, bool end_of_stream) { - not_expect_callback_ = true; - stream_->SendData(data, length, end_of_stream); - not_expect_callback_ = false; + SendvData({data}, {length}, end_of_stream); } void SendvData(const std::vector<scoped_refptr<IOBuffer>>& data,
diff --git a/net/third_party/nist-pkits/generate_tests.py b/net/third_party/nist-pkits/generate_tests.py index 8083d62a..04afc6f8 100644 --- a/net/third_party/nist-pkits/generate_tests.py +++ b/net/third_party/nist-pkits/generate_tests.py
@@ -688,17 +688,6 @@ user_constrained_policy_set=[]), ], - '4.10.7': [ # Invalid Mapping From anyPolicy Test7 - # Procedure: Validate Invalid Mapping From anyPolicy Test7 EE using the - # default settings or open and verify Signed Test Message 6.2.2.100 using - # the default settings. - # - # Expected Result: The path should not validate successfully since the - # intermediate certificate includes a policy mapping extension in which - # anyPolicy appears as an issuerDomainPolicy. - TestInfo(False, user_constrained_policy_set=[]), - ], - '4.10.8': [ # Invalid Mapping To anyPolicy Test8 # Procedure: Validate Invalid Mapping To anyPolicy Test8 EE using the # default settings or open and verify Signed Test Message 6.2.2.101 using @@ -707,6 +696,8 @@ # Expected Result: The path should not validate successfully since the # intermediate certificate includes a policy mapping extension in which # anyPolicy appears as an subjectDomainPolicy. + # + # TODO(eroman): What should user_constrained_policy_set be? TestInfo(False, user_constrained_policy_set=[]), ],
diff --git a/net/third_party/nist-pkits/pkits_testcases-inl.h b/net/third_party/nist-pkits/pkits_testcases-inl.h index 8ddf7c6..d4b709d 100644 --- a/net/third_party/nist-pkits/pkits_testcases-inl.h +++ b/net/third_party/nist-pkits/pkits_testcases-inl.h
@@ -2113,7 +2113,6 @@ "MappingFromanyPolicyCACRL"}; PkitsTestInfo info; info.should_validate = false; - info.SetUserConstrainedPolicySet(""); this->RunTest(certs, crls, info); }
diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc index ca66c54..59b09424 100644 --- a/net/tools/quic/end_to_end_test.cc +++ b/net/tools/quic/end_to_end_test.cc
@@ -555,7 +555,9 @@ void VerifyCleanConnection(bool had_packet_loss) { QuicConnectionStats client_stats = client_->client()->session()->connection()->GetStats(); - if (!had_packet_loss) { + // TODO(ianswett): Determine why this becomes even more flaky with BBR + // enabled. b/62141144 + if (!had_packet_loss && !FLAGS_quic_reloadable_flag_quic_default_to_bbr) { EXPECT_EQ(0u, client_stats.packets_lost); } EXPECT_EQ(0u, client_stats.packets_discarded); @@ -2250,6 +2252,27 @@ EXPECT_EQ("200", client_->response_headers()->find(":status")->second); } +TEST_P(EndToEndTest, CanceledStreamDoesNotBecomeZombie) { + ASSERT_TRUE(Initialize()); + if (!FLAGS_quic_reloadable_flag_quic_use_stream_notifier) { + return; + } + + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + // Lose the request. + SetPacketLossPercentage(100); + client_->SendRequest("/small_response"); + // Cancel the stream, and let the RST_STREAM go through. + SetPacketLossPercentage(0); + QuicSpdyClientStream* stream = client_->GetOrCreateStream(); + // Reset stream. + stream->Reset(QUIC_STREAM_CANCELLED); + QuicSession* session = client_->client()->session(); + // Verify canceled stream does not become zombie. + EXPECT_TRUE(QuicSessionPeer::zombie_streams(session).empty()); + EXPECT_EQ(1u, QuicSessionPeer::closed_streams(session).size()); +} + // A test stream that gives |response_body_| as an error response body. class ServerStreamWithErrorResponseBody : public QuicSimpleServerStream { public:
diff --git a/skia/public/interfaces/BUILD.gn b/skia/public/interfaces/BUILD.gn index 9b87555..7654731e 100644 --- a/skia/public/interfaces/BUILD.gn +++ b/skia/public/interfaces/BUILD.gn
@@ -9,6 +9,9 @@ "bitmap.mojom", "image_filter.mojom", ] + + # TODO(crbug.com/699569): Convert to use the new JS bindings. + use_new_js_bindings = false } mojom("test_interfaces") {
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG index bd322ac..4145aceb 100644 --- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG +++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -4375,6 +4375,7 @@ crbug.com/591099 external/wpt/content-security-policy/embedded-enforcement/subsumption_algorithm-host_sources-paths.html [ Crash ] crbug.com/591099 external/wpt/content-security-policy/embedded-enforcement/subsumption_algorithm-host_sources-ports.html [ Crash ] crbug.com/591099 external/wpt/content-security-policy/embedded-enforcement/subsumption_algorithm-host_sources-protocols.html [ Crash ] +crbug.com/591099 external/wpt/content-security-policy/embedded-enforcement/subsumption_algorithm-nonces.html [ Crash ] crbug.com/591099 external/wpt/content-security-policy/embedded-enforcement/subsumption_algorithm-none.html [ Crash ] crbug.com/591099 external/wpt/content-security-policy/embedded-enforcement/subsumption_algorithm-self.html [ Crash ] crbug.com/591099 external/wpt/content-security-policy/embedded-enforcement/subsumption_algorithm-strict_dynamic.html [ Crash ] @@ -4524,7 +4525,7 @@ crbug.com/591099 external/wpt/css/CSS2/linebox/border-padding-bleed-001.xht [ Failure Pass ] crbug.com/591099 external/wpt/css/CSS2/linebox/border-padding-bleed-002.xht [ Failure Pass ] crbug.com/591099 external/wpt/css/CSS2/linebox/border-padding-bleed-003.xht [ Failure Pass ] -crbug.com/591099 external/wpt/css/CSS2/linebox/empty-inline-002.xht [ Failure ] +crbug.com/591099 external/wpt/css/CSS2/linebox/empty-inline-002.xht [ Failure Pass ] crbug.com/591099 external/wpt/css/CSS2/linebox/inline-formatting-context-001.xht [ Failure ] crbug.com/591099 external/wpt/css/CSS2/linebox/inline-formatting-context-013.xht [ Failure Pass ] crbug.com/591099 external/wpt/css/CSS2/linebox/inline-formatting-context-022.xht [ Failure Pass ] @@ -4651,7 +4652,7 @@ crbug.com/591099 external/wpt/css/CSS2/normal-flow/inline-replaced-width-013.xht [ Failure ] crbug.com/591099 external/wpt/css/CSS2/normal-flow/inline-replaced-width-015.xht [ Failure ] crbug.com/591099 external/wpt/css/CSS2/normal-flow/inlines-013.xht [ Failure ] -crbug.com/591099 external/wpt/css/CSS2/normal-flow/inlines-020.xht [ Failure ] +crbug.com/591099 external/wpt/css/CSS2/normal-flow/inlines-020.xht [ Failure Pass ] crbug.com/591099 external/wpt/css/CSS2/normal-flow/inline-table-zorder-003.xht [ Failure Pass ] crbug.com/591099 external/wpt/css/CSS2/normal-flow/inline-table-zorder-005.xht [ Failure ] crbug.com/591099 external/wpt/css/CSS2/normal-flow/max-height-002.xht [ Failure ] @@ -5109,11 +5110,16 @@ crbug.com/591099 external/wpt/css/css-grid-1/grid-definition/fr-unit.html [ Failure ] crbug.com/591099 external/wpt/css/css-grid-1/grid-definition/fr-unit-with-percentage.html [ Failure ] crbug.com/591099 external/wpt/css/css-grid-1/grid-definition/grid-layout-auto-tracks.html [ Failure Pass ] +crbug.com/591099 external/wpt/css/css-grid-1/grid-items/grid-inline-z-axis-ordering-overlapped-items-006.html [ Failure ] crbug.com/591099 external/wpt/css/css-grid-1/grid-items/grid-item-containing-block-001.html [ Failure ] crbug.com/591099 external/wpt/css/css-grid-1/grid-items/grid-item-containing-block-002.html [ Failure ] crbug.com/591099 external/wpt/css/css-grid-1/grid-items/grid-item-containing-block-003.html [ Failure ] crbug.com/591099 external/wpt/css/css-grid-1/grid-items/grid-item-containing-block-004.html [ Failure ] crbug.com/591099 external/wpt/css/css-grid-1/grid-items/grid-items-sizing-alignment-001.html [ Failure Pass ] +crbug.com/591099 external/wpt/css/css-grid-1/grid-items/grid-z-axis-ordering-overlapped-items-006.html [ Failure ] +crbug.com/591099 external/wpt/css/css-grid-1/grid-model/grid-inline-margins-no-collapse-001.html [ Failure ] +crbug.com/591099 external/wpt/css/css-grid-1/grid-model/grid-margins-no-collapse-001.html [ Failure ] +crbug.com/591099 external/wpt/css/css-grid-1/grid-model/grid-support-display-001.html [ Crash ] crbug.com/591099 external/wpt/css/css-position-3/position-sticky-left.html [ Crash Failure ] crbug.com/591099 external/wpt/css/css-position-3/position-sticky-table-th-bottom.html [ Failure ] crbug.com/591099 external/wpt/css/css-position-3/position-sticky-table-th-left.html [ Failure ] @@ -5582,7 +5588,7 @@ crbug.com/591099 external/wpt/css/css-writing-modes-3/line-box-direction-vlr-013.xht [ Failure ] crbug.com/591099 external/wpt/css/css-writing-modes-3/line-box-direction-vlr-014.xht [ Failure ] crbug.com/591099 external/wpt/css/css-writing-modes-3/line-box-direction-vlr-018.xht [ Failure Pass ] -crbug.com/591099 external/wpt/css/css-writing-modes-3/line-box-direction-vlr-020.xht [ Failure ] +crbug.com/591099 external/wpt/css/css-writing-modes-3/line-box-direction-vlr-020.xht [ Crash Failure ] crbug.com/591099 external/wpt/css/css-writing-modes-3/line-box-direction-vrl-002.xht [ Failure ] crbug.com/591099 external/wpt/css/css-writing-modes-3/line-box-direction-vrl-005.xht [ Failure ] crbug.com/591099 external/wpt/css/css-writing-modes-3/line-box-direction-vrl-006.xht [ Failure ] @@ -5899,6 +5905,7 @@ crbug.com/591099 external/wpt/eventsource/eventsource-onmessage-realm.htm [ Crash ] crbug.com/591099 external/wpt/fetch/api/request/multi-globals/url-parsing.html [ Crash ] crbug.com/591099 external/wpt/fetch/api/response/multi-globals/url-parsing.html [ Crash ] +crbug.com/591099 external/wpt/fetch/dangling-markup-mitigation.tentative.html [ Crash ] crbug.com/591099 external/wpt/FileAPI/idlharness.html [ Crash ] crbug.com/591099 external/wpt/FileAPI/url/blob-url-in-sandboxed-iframe.html [ Crash ] crbug.com/591099 external/wpt/FileAPI/url/multi-global-origin-serialization.sub.html [ Crash ] @@ -6853,7 +6860,7 @@ crbug.com/591099 external/wpt/service-workers/service-worker/windowclient-navigate.https.html [ Crash ] crbug.com/591099 external/wpt/shadow-dom/leaktests/html-collection.html [ Crash ] crbug.com/591099 external/wpt/shadow-dom/leaktests/window-frames.html [ Crash ] -crbug.com/591099 external/wpt/shadow-dom/MouseEvent-prototype-offsetX-offsetY.html [ Failure ] +crbug.com/591099 external/wpt/shadow-dom/MouseEvent-prototype-offsetX-offsetY.html [ Failure Pass ] crbug.com/591099 external/wpt/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-attributes/test-007.html [ Crash Pass ] crbug.com/591099 external/wpt/shadow-dom/untriaged/events/event-retargeting/test-001.html [ Crash ] crbug.com/591099 external/wpt/shadow-dom/untriaged/events/test-001.html [ Crash ] @@ -7205,6 +7212,7 @@ crbug.com/591099 fast/block/float/vertical-move-relayout.html [ Failure ] crbug.com/591099 fast/block/float/width-update-after-clear.html [ Failure ] crbug.com/591099 fast/block/hr-border-box-sizing.html [ Failure ] +crbug.com/591099 fast/block/hr-with-float.html [ Failure ] crbug.com/591099 fast/block/inline-children-root-linebox-crash.html [ Crash Failure ] crbug.com/591099 fast/block/line-layout/crash-in-isolate-with-positioned-child.html [ Failure Pass ] crbug.com/591099 fast/block/line-layout/double-line-break-obj-removal-crash.html [ Crash Pass ] @@ -7443,7 +7451,7 @@ crbug.com/591099 fast/borders/border-image-massive-scale.html [ Failure ] crbug.com/591099 fast/borders/border-image-outset.html [ Failure ] crbug.com/591099 fast/borders/border-image-outset-in-shorthand.html [ Failure ] -crbug.com/591099 fast/borders/border-image-outset-split-inline.html [ Failure ] +crbug.com/591099 fast/borders/border-image-outset-split-inline.html [ Failure Pass ] crbug.com/591099 fast/borders/border-image-repeat.html [ Failure ] crbug.com/591099 fast/borders/border-image-repeat-round.html [ Failure ] crbug.com/591099 fast/borders/border-image-rotate-transform.html [ Failure ] @@ -12530,7 +12538,7 @@ crbug.com/591099 fast/inline/inline-box-background-long-image.html [ Failure ] crbug.com/591099 fast/inline/inline-box-background-repeat-x.html [ Failure ] crbug.com/591099 fast/inline/inline-box-background-repeat-y.html [ Failure ] -crbug.com/591099 fast/inline/inline-continuation-borders.html [ Failure ] +crbug.com/591099 fast/inline/inline-continuation-borders.html [ Failure Pass ] crbug.com/591099 fast/inline/inline-destroy-dirty-lines-crash.html [ Failure ] crbug.com/591099 fast/inline/inline-fixed-position-boundingbox.html [ Failure ] crbug.com/591099 fast/inline/inline-focus-ring.html [ Failure ] @@ -12544,7 +12552,7 @@ crbug.com/591099 fast/inline/inline-text-quirk-bpm.html [ Failure ] crbug.com/591099 fast/inline/inline-width-containing-collapsed-whitespace-and-image-in-float.html [ Crash Failure ] crbug.com/591099 fast/inline/inline-with-empty-inline-children.html [ Failure ] -crbug.com/591099 fast/inline/inline-wrap-with-parent-padding.html [ Failure ] +crbug.com/591099 fast/inline/inline-wrap-with-parent-padding.html [ Failure Pass ] crbug.com/591099 fast/inline/justify-emphasis-inline-box.html [ Failure ] crbug.com/591099 fast/inline/leading-space-after-nested-empty-inlines.html [ Failure ] crbug.com/591099 fast/inline/left-right-center-inline-alignment-in-ltr-and-rtl-blocks.html [ Failure ] @@ -12956,6 +12964,7 @@ crbug.com/591099 fast/lists/li-br.html [ Crash Failure ] crbug.com/591099 fast/lists/li-minimum-long-value.html [ Crash Pass ] crbug.com/591099 fast/lists/list-item-line-height.html [ Crash Failure ] +crbug.com/591099 fast/lists/list-marker-avoid-float.html [ Crash Failure ] crbug.com/591099 fast/lists/list-marker-before-content-table.html [ Failure ] crbug.com/591099 fast/lists/list-marker-before-float.html [ Crash Failure ] crbug.com/591099 fast/lists/list-marker-before-float-nested.html [ Crash Failure ] @@ -14770,7 +14779,7 @@ crbug.com/591099 fast/text/line-breaks-after-ideographic-comma-or-full-stop-2.html [ Failure ] crbug.com/591099 fast/text/line-breaks-after-ideographic-comma-or-full-stop.html [ Failure ] crbug.com/591099 fast/text/line-breaks-after-white-space.html [ Failure Pass ] -crbug.com/591099 fast/text/line-breaks.html [ Failure ] +crbug.com/591099 fast/text/line-breaks.html [ Failure Pass ] crbug.com/591099 fast/text/line-initial-and-final-swashes.html [ Failure ] crbug.com/591099 fast/text/long-word.html [ Failure Timeout ] crbug.com/591099 fast/text/midword-break-after-breakable-char.html [ Failure ] @@ -15819,6 +15828,7 @@ crbug.com/591099 http/tests/inspector/fragment.html [ Crash Failure ] crbug.com/591099 http/tests/inspector/indexeddb/database-data.html [ Failure ] crbug.com/591099 http/tests/inspector/indexeddb/database-names.html [ Failure ] +crbug.com/591099 http/tests/inspector/indexeddb/database-refresh-view.html [ Crash ] crbug.com/591099 http/tests/inspector/indexeddb/database-structure.html [ Failure ] crbug.com/591099 http/tests/inspector/indexeddb/resources-panel.html [ Failure ] crbug.com/591099 http/tests/inspector/indexeddb/transaction-promise-console.html [ Failure ] @@ -15855,7 +15865,7 @@ crbug.com/591099 http/tests/inspector/network/network-eventsource.html [ Crash Failure ] crbug.com/591099 http/tests/inspector/network/network-fetch.html [ Crash Failure ] crbug.com/591099 http/tests/inspector/network/network-fetch-post-payload.html [ Crash Failure ] -crbug.com/591099 http/tests/inspector/network/network-filters.html [ Failure ] +crbug.com/591099 http/tests/inspector/network/network-filters.html [ Crash Failure ] crbug.com/591099 http/tests/inspector/network/network-filters-internals.html [ Failure ] crbug.com/591099 http/tests/inspector/network/network-iframe-load-and-delete.html [ Crash Failure ] crbug.com/591099 http/tests/inspector/network/network-image-404.html [ Failure ] @@ -16167,7 +16177,7 @@ crbug.com/591099 http/tests/mime/reload-subresource-when-type-changes.html [ Crash ] crbug.com/591099 http/tests/misc/acid2.html [ Crash ] crbug.com/591099 http/tests/misc/acid2-pixel.html [ Crash ] -crbug.com/591099 http/tests/misc/acid3.html [ Failure ] +crbug.com/591099 http/tests/misc/acid3.html [ Crash Failure ] crbug.com/591099 http/tests/misc/adopt-iframe-src-attr-after-remove.html [ Crash ] crbug.com/591099 http/tests/misc/async-script.html [ Failure ] crbug.com/591099 http/tests/misc/async-script-removed.html [ Failure ] @@ -16201,7 +16211,7 @@ crbug.com/591099 http/tests/misc/delete-frame-during-readystatechange.html [ Crash ] crbug.com/591099 http/tests/misc/delete-frame-during-readystatechange-with-gc-after-video-removal.html [ Crash ] crbug.com/591099 http/tests/misc/detach-during-notifyDone.html [ Crash ] -crbug.com/591099 http/tests/misc/dns-prefetch-control.html [ Failure ] +crbug.com/591099 http/tests/misc/dns-prefetch-control.html [ Crash Failure ] crbug.com/591099 http/tests/misc/DOMContentLoaded-event.html [ Crash Failure ] crbug.com/591099 http/tests/misc/drag-over-iframe-invalid-source-crash.html [ Crash Failure ] crbug.com/591099 http/tests/misc/embed-image-load-outlives-gc-without-crashing.html [ Crash Pass ] @@ -17066,7 +17076,7 @@ crbug.com/591099 http/tests/worklet/chromium/import-on-detached-iframe.html [ Crash ] crbug.com/591099 http/tests/xmlhttprequest/abort-should-destroy-responseText.html [ Failure ] crbug.com/591099 http/tests/xmlhttprequest/access-control-allow-lists-starting-with-comma.html [ Failure ] -crbug.com/591099 http/tests/xmlhttprequest/access-control-and-redirects-async.html [ Failure ] +crbug.com/591099 http/tests/xmlhttprequest/access-control-and-redirects-async.html [ Failure Timeout ] crbug.com/591099 http/tests/xmlhttprequest/access-control-and-redirects-async-same-origin.html [ Failure ] crbug.com/591099 http/tests/xmlhttprequest/access-control-and-redirects.html [ Failure ] crbug.com/591099 http/tests/xmlhttprequest/access-control-basic-denied-preflight-cache.html [ Crash Failure ] @@ -17714,7 +17724,7 @@ crbug.com/591099 inspector/editor/text-editor-indent-autodetection.html [ Crash Failure Timeout ] crbug.com/591099 inspector/editor/text-editor-line-breaks.html [ Crash Failure ] crbug.com/591099 inspector/editor/text-editor-mark-clean.html [ Crash Failure Timeout ] -crbug.com/591099 inspector/editor/text-editor-reveal-line.html [ Failure Timeout ] +crbug.com/591099 inspector/editor/text-editor-reveal-line.html [ Crash Failure Timeout ] crbug.com/591099 inspector/editor/text-editor-search-replace.html [ Crash Failure ] crbug.com/591099 inspector/editor/text-editor-selection-to-search.html [ Crash Failure ] crbug.com/591099 inspector/editor/text-editor-smart-braces.html [ Crash Failure ] @@ -17950,7 +17960,7 @@ crbug.com/591099 inspector/extensions/extensions-audits-content-script.html [ Crash Failure ] crbug.com/591099 inspector/extensions/extensions-audits.html [ Crash Failure ] crbug.com/591099 inspector/extensions/extensions-eval-content-script.html [ Failure ] -crbug.com/591099 inspector/extensions/extensions-eval.html [ Failure ] +crbug.com/591099 inspector/extensions/extensions-eval.html [ Crash Failure ] crbug.com/591099 inspector/extensions/extensions-events.html [ Crash ] crbug.com/591099 inspector/extensions/extensions-network.html [ Crash Failure ] crbug.com/591099 inspector/extensions/extensions-panel.html [ Crash ] @@ -17992,7 +18002,7 @@ crbug.com/591099 inspector/profiler/agents-disabled-check.html [ Crash Failure ] crbug.com/591099 inspector/profiler/cpu-profiler-agent-crash-on-start.html [ Crash Failure ] crbug.com/591099 inspector/profiler/cpu-profiler-bottom-up-large-tree-search.html [ Crash Failure ] -crbug.com/591099 inspector/profiler/cpu-profiler-bottom-up-times.html [ Failure ] +crbug.com/591099 inspector/profiler/cpu-profiler-bottom-up-times.html [ Crash Failure ] crbug.com/591099 inspector/profiler/cpu-profiler-calculate-time.html [ Crash Failure ] crbug.com/591099 inspector/profiler/cpu-profiler-flame-chart-overview.html [ Crash Failure ] crbug.com/591099 inspector/profiler/cpu-profiler-native-nodes-filter.html [ Crash Failure ] @@ -18261,7 +18271,7 @@ crbug.com/591099 inspector/sources/debugger-step/debugger-step-into-across-timeouts.html [ Failure ] crbug.com/591099 inspector/sources/debugger-step/debugger-step-into-custom-element-callbacks.html [ Crash Failure Timeout ] crbug.com/591099 inspector/sources/debugger-step/debugger-step-into-document-write.html [ Failure ] -crbug.com/591099 inspector/sources/debugger-step/debugger-step-into-event-listener.html [ Failure ] +crbug.com/591099 inspector/sources/debugger-step/debugger-step-into-event-listener.html [ Crash Failure ] crbug.com/591099 inspector/sources/debugger-step/debugger-step-into-inlined-scripts.html [ Failure ] crbug.com/591099 inspector/sources/debugger-step/debugger-step-out-across-timeouts.html [ Failure ] crbug.com/591099 inspector/sources/debugger-step/debugger-step-out-custom-element-callbacks.html [ Failure ] @@ -18273,14 +18283,14 @@ crbug.com/591099 inspector/sources/debugger-step/debugger-step-over.html [ Crash Failure ] crbug.com/591099 inspector/sources/debugger-step/debugger-step-over-inlined-scripts.html [ Failure ] crbug.com/591099 inspector/sources/debugger-step/debugger-step-through-promises.html [ Failure ] -crbug.com/591099 inspector/sources/debugger-step/step-through-event-listeners.html [ Failure ] +crbug.com/591099 inspector/sources/debugger-step/step-through-event-listeners.html [ Crash Failure ] crbug.com/591099 inspector/sources/debugger-ui/async-call-stack-async-function.html [ Crash Failure ] crbug.com/591099 inspector/sources/debugger-ui/async-call-stack-url.html [ Crash Failure ] crbug.com/591099 inspector/sources/debugger-ui/break-on-empty-event-listener.html [ Crash Failure ] crbug.com/591099 inspector/sources/debugger-ui/break-on-set-timeout-with-syntax-error.html [ Crash Failure ] crbug.com/591099 inspector/sources/debugger-ui/callstack-placards-discarded.html [ Crash Failure ] crbug.com/591099 inspector/sources/debugger-ui/click-gutter-breakpoint.html [ Crash Failure ] -crbug.com/591099 inspector/sources/debugger-ui/continue-to-location-markers.html [ Failure ] +crbug.com/591099 inspector/sources/debugger-ui/continue-to-location-markers.html [ Crash Failure ] crbug.com/591099 inspector/sources/debugger-ui/copy-stack-trace.html [ Crash Failure ] crbug.com/591099 inspector/sources/debugger-ui/custom-element-lifecycle-events.html [ Crash Failure ] crbug.com/591099 inspector/sources/debugger-ui/debugger-expand-scope.html [ Crash Failure ] @@ -18295,7 +18305,7 @@ crbug.com/591099 inspector/sources/debugger-ui/last-execution-context.html [ Crash Failure ] crbug.com/591099 inspector/sources/debugger-ui/monitor-console-command.html [ Crash Failure ] crbug.com/591099 inspector/sources/debugger-ui/reveal-execution-line.html [ Crash Failure ] -crbug.com/591099 inspector/sources/debugger-ui/reveal-not-skipped.html [ Failure ] +crbug.com/591099 inspector/sources/debugger-ui/reveal-not-skipped.html [ Crash Failure ] crbug.com/591099 inspector/sources/debugger-ui/script-formatter-breakpoints-2.html [ Crash Failure ] crbug.com/591099 inspector/sources/debugger-ui/script-formatter-breakpoints-3.html [ Crash Failure ] crbug.com/591099 inspector/sources/debugger-ui/script-formatter-search.html [ Crash Failure ] @@ -18304,7 +18314,7 @@ crbug.com/591099 inspector/sources/debugger-ui/scripts-sorting.html [ Crash Failure ] crbug.com/591099 inspector/sources/debugger-ui/scripts-with-same-source-url.html [ Crash Failure ] crbug.com/591099 inspector/sources/debugger-ui/selected-call-frame-after-formatting-source.html [ Crash Failure ] -crbug.com/591099 inspector/sources/debugger-ui/show-function-definition.html [ Failure ] +crbug.com/591099 inspector/sources/debugger-ui/show-function-definition.html [ Crash Failure ] crbug.com/591099 inspector/sources/debugger-ui/show-generator-location.html [ Crash Failure ] crbug.com/591099 inspector/sources/debugger-ui/source-frame-count.html [ Crash Failure ] crbug.com/591099 inspector/sources/debugger-ui/source-frame.html [ Failure ] @@ -18460,6 +18470,7 @@ crbug.com/591099 media/audio-delete-while-slider-thumb-clicked.html [ Crash ] crbug.com/591099 media/audio-only-video-intrinsic-size.html [ Failure ] crbug.com/591099 media/autoplay-document-move.html [ Crash ] +crbug.com/591099 media/autoplay/document-user-activation.html [ Failure ] crbug.com/591099 media/auto-play-in-sandbox-with-allow-scripts.html [ Crash ] crbug.com/591099 media/autoplay-muted-conditions.html [ Crash ] crbug.com/591099 media/autoplay-muted.html [ Crash Timeout ] @@ -18485,6 +18496,8 @@ crbug.com/591099 media/controls/controls-cast-do-not-fade-out.html [ Crash ] crbug.com/591099 media/controls/controls-cast-overlay-slow-fade.html [ Crash ] crbug.com/591099 media/controls/controls-overlay-cast-button.html [ Crash ] +crbug.com/591099 media/controls/controls-video-keynav.html [ Crash ] +crbug.com/591099 media/controls/controls-video-keynav-no-controls.html [ Crash ] crbug.com/591099 media/controls-css-overload.html [ Crash ] crbug.com/591099 media/controls/download-button-displays-with-preload-none.html [ Crash ] crbug.com/591099 media/controls-drag-timebar.html [ Crash ] @@ -19701,6 +19714,7 @@ crbug.com/591099 printing/absolute-positioned.html [ Failure ] crbug.com/591099 printing/absolute-position-headers-and-footers.html [ Failure ] crbug.com/591099 printing/allowed-page-breaks.html [ Failure ] +crbug.com/591099 printing/block-width-relayout-shrink.html [ Failure ] crbug.com/591099 printing/css2.1/page-break-after-000.html [ Failure ] crbug.com/591099 printing/css2.1/page-break-after-002.html [ Failure ] crbug.com/591099 printing/css2.1/page-break-after-003.html [ Failure ] @@ -23400,7 +23414,7 @@ crbug.com/591099 virtual/gpu-rasterization/images/zoomed-img-size.html [ Failure ] crbug.com/591099 virtual/gpu-rasterization/images/zoomed-offset-size.html [ Crash ] crbug.com/591099 virtual/layout_ng/external/wpt/css/CSS2/floats/floats-wrap-top-below-inline-003r.xht [ Failure Pass ] -crbug.com/591099 virtual/layout_ng/external/wpt/css/CSS2/linebox/empty-inline-002.xht [ Failure ] +crbug.com/591099 virtual/layout_ng/external/wpt/css/CSS2/linebox/empty-inline-002.xht [ Failure Pass ] crbug.com/591099 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/height-114.xht [ Failure ] crbug.com/591099 virtual/layout_ng/external/wpt/css/CSS2/positioning/top-019.xht [ Failure ] crbug.com/591099 virtual/layout_ng/external/wpt/css/CSS2/positioning/top-020.xht [ Failure ] @@ -23469,6 +23483,8 @@ crbug.com/591099 virtual/new-remote-playback-pipeline/media/controls/controls-cast-do-not-fade-out.html [ Crash ] crbug.com/591099 virtual/new-remote-playback-pipeline/media/controls/controls-cast-overlay-slow-fade.html [ Crash Timeout ] crbug.com/591099 virtual/new-remote-playback-pipeline/media/controls/controls-overlay-cast-button.html [ Crash ] +crbug.com/591099 virtual/new-remote-playback-pipeline/media/controls/controls-video-keynav.html [ Crash ] +crbug.com/591099 virtual/new-remote-playback-pipeline/media/controls/controls-video-keynav-no-controls.html [ Crash ] crbug.com/591099 virtual/new-remote-playback-pipeline/media/controls/download-button-displays-with-preload-none.html [ Crash ] crbug.com/591099 virtual/new-remote-playback-pipeline/media/controls/overflow-fully-hidden.html [ Crash ] crbug.com/591099 virtual/new-remote-playback-pipeline/media/controls/overlay-play-button-document-move.html [ Crash ] @@ -24478,6 +24494,7 @@ crbug.com/591099 virtual/threaded/printing/absolute-positioned.html [ Failure ] crbug.com/591099 virtual/threaded/printing/absolute-position-headers-and-footers.html [ Failure ] crbug.com/591099 virtual/threaded/printing/allowed-page-breaks.html [ Failure ] +crbug.com/591099 virtual/threaded/printing/block-width-relayout-shrink.html [ Failure ] crbug.com/591099 virtual/threaded/printing/css2.1/page-break-after-000.html [ Failure ] crbug.com/591099 virtual/threaded/printing/css2.1/page-break-after-002.html [ Failure ] crbug.com/591099 virtual/threaded/printing/css2.1/page-break-after-003.html [ Failure ] @@ -24625,6 +24642,7 @@ crbug.com/591099 vr/requestPresent_resolve_webgl2.html [ Crash ] crbug.com/591099 vr/stageParameters_match.html [ Crash ] crbug.com/591099 web-animations-api/time-consistent-across-frames.html [ Crash ] +crbug.com/591099 webaudio/BiquadFilter/tail-time-lowpass.html [ Timeout ] crbug.com/591099 webaudio/internals/audiocontext-lock-threading-race.html [ Failure ] crbug.com/591099 webaudio/internals/cycle-connection-gc.html [ Failure ] crbug.com/591099 webaudio/internals/mediaelementaudiosourcenode-gc.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/LeakExpectations b/third_party/WebKit/LayoutTests/LeakExpectations index 374817d5..3091fce 100644 --- a/third_party/WebKit/LayoutTests/LeakExpectations +++ b/third_party/WebKit/LayoutTests/LeakExpectations
@@ -70,10 +70,6 @@ crbug.com/451577 [ Linux ] inspector/extensions/extensions-reload.html [ Slow ] crbug.com/451577 [ Linux ] inspector/extensions/extensions-sidebar.html [ Slow ] -crbug.com/578297 [ Linux ] virtual/threaded/printing/webgl-oversized-printing.html [ Slow Leak ] -crbug.com/578297 [ Linux ] http/tests/media/media-source/mediasource-appendstream-quota-exceeded.html [ Slow ] -crbug.com/578297 [ Linux ] virtual/mojo-loading/http/tests/media/media-source/mediasource-appendstream-quota-exceeded.html [ Slow ] - # ----------------------------------------------------------------- # Leaks in external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/* # -----------------------------------------------------------------
diff --git a/third_party/WebKit/LayoutTests/NeverFixTests b/third_party/WebKit/LayoutTests/NeverFixTests index 0e56f9c..422fcebd 100644 --- a/third_party/WebKit/LayoutTests/NeverFixTests +++ b/third_party/WebKit/LayoutTests/NeverFixTests
@@ -758,3 +758,8 @@ # run-webkit-tests; see https://crbug.com/359838. http/tests/ManualTests/ [ WontFix ] virtual/mojo-loading/http/tests/ManualTests/ [ WontFix ] + +# These test produce invisible different pixels on Win7 Debug. +[ Win7 Debug ] fast/table/backgr_border-table-column-group-collapsed-border.html [ WontFix ] +[ Win7 Debug ] virtual/mojo-loading/fast/table/backgr_border-table-column-group-collapsed-border.html [ WontFix ] +
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index 8cfa388..9045e0d5 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -2996,6 +2996,3 @@ crbug.com/727505 [ Linux Mac Win ] virtual/threaded/fast/compositorworker/basic-plumbing-main-to-worker.html [ Pass Failure Timeout Crash ] crbug.com/727505 [ Linux Mac Win ] virtual/threaded/fast/compositorworker/basic-plumbing-worker-to-main.html [ Pass Failure Timeout Crash ] crbug.com/727505 [ Linux Mac Win ] virtual/threaded/fast/compositorworker/request-animation-frame.html [ Pass Failure Timeout Crash ] - -crbug.com/728895 [ Win7 Debug ] fast/table/backgr_border-table-column-group-collapsed-border.html [ Failure ] -crbug.com/728895 [ Win7 Debug ] virtual/mojo-loading/fast/table/backgr_border-table-column-group-collapsed-border.html [ Failure ] \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/events/touch/gesture/pad-gesture-fling-expected.txt b/third_party/WebKit/LayoutTests/fast/events/touch/gesture/pad-gesture-fling-expected.txt index 6229272..2fc4f16 100644 --- a/third_party/WebKit/LayoutTests/fast/events/touch/gesture/pad-gesture-fling-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/events/touch/gesture/pad-gesture-fling-expected.txt
@@ -6,7 +6,7 @@ PASS successfullyParsed is true TEST COMPLETE -PASS actualWheelEventsOccurred is >= 2 +PASS actualWheelEventsOccurred is >= 1 PASS cumulativeScrollX is >= 300 PASS cumulativeScrollY is >= 300 PASS successfullyParsed is true
diff --git a/third_party/WebKit/LayoutTests/fast/events/touch/gesture/pad-gesture-fling.js b/third_party/WebKit/LayoutTests/fast/events/touch/gesture/pad-gesture-fling.js index 5b86bedb..1f9bdea 100644 --- a/third_party/WebKit/LayoutTests/fast/events/touch/gesture/pad-gesture-fling.js +++ b/third_party/WebKit/LayoutTests/fast/events/touch/gesture/pad-gesture-fling.js
@@ -4,7 +4,7 @@ var cumulativeScrollX = 0; var cumulativeScrollY = 0; -var minimumWheelEventsExpected = "2"; +var minimumWheelEventsExpected = "1"; var minimumScrollXExpected = 300; var minimumScrollYExpected = 300;
diff --git a/third_party/WebKit/LayoutTests/fast/scroll-behavior/scroll-customization/touch-scroll-customization.html b/third_party/WebKit/LayoutTests/fast/scroll-behavior/scroll-customization/touch-scroll-customization.html index 05057cd..5248363 100644 --- a/third_party/WebKit/LayoutTests/fast/scroll-behavior/scroll-customization/touch-scroll-customization.html +++ b/third_party/WebKit/LayoutTests/fast/scroll-behavior/scroll-customization/touch-scroll-customization.html
@@ -204,12 +204,14 @@ assert_equals(document.scrollingElement.scrollTop, scrollingElementTop, "For scrollingElement on step " + step); }; + assertScrollTops(0, 0, 0, 0); + var frame_actions = [ function() { eventSender.gestureFlingStart(10, 10, -1000000, -1000000, "touchscreen"); }, flingTest.step_func(function() { - assertScrollTops(0, 0, 0, 1); + assertScrollTops(100, 0, 0, 1); }), flingTest.step_func(function() { assertScrollTops(100, 0, 0, 2);
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/indexeddb/database-data.html b/third_party/WebKit/LayoutTests/http/tests/inspector/indexeddb/database-data.html index 09aa702b..0badd0e 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/indexeddb/database-data.html +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/indexeddb/database-data.html
@@ -183,7 +183,7 @@ function runClearTests() { - indexedDBModel.clearObjectStore(databaseId, objectStoreName, step1); + indexedDBModel.clearObjectStore(databaseId, objectStoreName).then(step1); InspectorTest.addResult("Cleared data from objectStore"); function step1() {
diff --git a/third_party/WebKit/Source/core/animation/BUILD.gn b/third_party/WebKit/Source/core/animation/BUILD.gn index cbf02c6f..3e5d7ed 100644 --- a/third_party/WebKit/Source/core/animation/BUILD.gn +++ b/third_party/WebKit/Source/core/animation/BUILD.gn
@@ -102,6 +102,8 @@ "CompositorMutatorImpl.h", "CompositorPendingAnimations.cpp", "CompositorPendingAnimations.h", + "CompositorProxyClientImpl.cpp", + "CompositorProxyClientImpl.h", "CustomCompositorAnimationManager.cpp", "CustomCompositorAnimationManager.h", "CustomCompositorAnimations.cpp",
diff --git a/third_party/WebKit/Source/web/CompositorProxyClientImpl.cpp b/third_party/WebKit/Source/core/animation/CompositorProxyClientImpl.cpp similarity index 92% rename from third_party/WebKit/Source/web/CompositorProxyClientImpl.cpp rename to third_party/WebKit/Source/core/animation/CompositorProxyClientImpl.cpp index 7090ffa..04af0b1 100644 --- a/third_party/WebKit/Source/web/CompositorProxyClientImpl.cpp +++ b/third_party/WebKit/Source/core/animation/CompositorProxyClientImpl.cpp
@@ -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 "web/CompositorProxyClientImpl.h" +#include "core/animation/CompositorProxyClientImpl.h" #include "core/dom/CompositorProxy.h"
diff --git a/third_party/WebKit/Source/web/CompositorProxyClientImpl.h b/third_party/WebKit/Source/core/animation/CompositorProxyClientImpl.h similarity index 93% rename from third_party/WebKit/Source/web/CompositorProxyClientImpl.h rename to third_party/WebKit/Source/core/animation/CompositorProxyClientImpl.h index 0832d652..055ae93 100644 --- a/third_party/WebKit/Source/web/CompositorProxyClientImpl.h +++ b/third_party/WebKit/Source/core/animation/CompositorProxyClientImpl.h
@@ -5,13 +5,14 @@ #ifndef CompositorProxyClientImpl_h #define CompositorProxyClientImpl_h +#include "core/CoreExport.h" #include "core/dom/CompositorProxyClient.h" namespace blink { // Registry for CompositorProxies on the control thread. // Owned by the control thread. -class CompositorProxyClientImpl +class CORE_EXPORT CompositorProxyClientImpl : public GarbageCollectedFinalized<CompositorProxyClientImpl>, public CompositorProxyClient { USING_GARBAGE_COLLECTED_MIXIN(CompositorProxyClientImpl);
diff --git a/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h b/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h index c7e7630..b939018 100644 --- a/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h +++ b/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h
@@ -2026,49 +2026,6 @@ } template <> -inline CSSIdentifierValue::CSSIdentifierValue(EImageRendering e) - : CSSValue(kIdentifierClass) { - switch (e) { - case EImageRendering::kAuto: - value_id_ = CSSValueAuto; - break; - case EImageRendering::kOptimizeSpeed: - value_id_ = CSSValueOptimizeSpeed; - break; - case EImageRendering::kOptimizeQuality: - value_id_ = CSSValueOptimizeQuality; - break; - case EImageRendering::kPixelated: - value_id_ = CSSValuePixelated; - break; - case EImageRendering::kOptimizeContrast: - value_id_ = CSSValueWebkitOptimizeContrast; - break; - } -} - -template <> -inline EImageRendering CSSIdentifierValue::ConvertTo() const { - switch (value_id_) { - case CSSValueAuto: - return EImageRendering::kAuto; - case CSSValueOptimizeSpeed: - return EImageRendering::kOptimizeSpeed; - case CSSValueOptimizeQuality: - return EImageRendering::kOptimizeQuality; - case CSSValuePixelated: - return EImageRendering::kPixelated; - case CSSValueWebkitOptimizeContrast: - return EImageRendering::kOptimizeContrast; - default: - break; - } - - NOTREACHED(); - return EImageRendering::kAuto; -} - -template <> inline CSSIdentifierValue::CSSIdentifierValue(ETransformStyle3D e) : CSSValue(kIdentifierClass) { switch (e) {
diff --git a/third_party/WebKit/Source/core/css/CSSProperties.json5 b/third_party/WebKit/Source/core/css/CSSProperties.json5 index 1fc15f4..3938290e 100644 --- a/third_party/WebKit/Source/core/css/CSSProperties.json5 +++ b/third_party/WebKit/Source/core/css/CSSProperties.json5
@@ -1284,10 +1284,9 @@ { name: "image-rendering", inherited: true, - field_template: "storage_only", - type_name: "EImageRendering", - default_value: "EImageRendering::kAuto", - field_size: 3, + field_template: "keyword", + keywords: ["auto", "optimize-speed", "optimize-quality", "-webkit-optimize-contrast", "pixelated"], + default_value: "auto", field_group: "rare-inherited", }, {
diff --git a/third_party/WebKit/Source/core/css/OWNERS b/third_party/WebKit/Source/core/css/OWNERS index 9c6d10c2..dc8cf82 100644 --- a/third_party/WebKit/Source/core/css/OWNERS +++ b/third_party/WebKit/Source/core/css/OWNERS
@@ -1,4 +1,5 @@ meade@chromium.org suzyh@chromium.org +nainar@chromium.org # COMPONENT: Blink>CSS
diff --git a/third_party/WebKit/Source/core/css/cssom/CSSUnitValue.cpp b/third_party/WebKit/Source/core/css/cssom/CSSUnitValue.cpp index 256f86a..4d50580 100644 --- a/third_party/WebKit/Source/core/css/cssom/CSSUnitValue.cpp +++ b/third_party/WebKit/Source/core/css/cssom/CSSUnitValue.cpp
@@ -75,7 +75,7 @@ return CSSPrimitiveValue::UnitTypeToString(unit_); } -String CSSUnitValue::cssType() const { +String CSSUnitValue::type() const { if (unit_ == CSSPrimitiveValue::UnitType::kNumber) return "number"; if (unit_ == CSSPrimitiveValue::UnitType::kPercentage)
diff --git a/third_party/WebKit/Source/core/css/cssom/CSSUnitValue.h b/third_party/WebKit/Source/core/css/cssom/CSSUnitValue.h index 8ec12fd0..ffd2703 100644 --- a/third_party/WebKit/Source/core/css/cssom/CSSUnitValue.h +++ b/third_party/WebKit/Source/core/css/cssom/CSSUnitValue.h
@@ -27,7 +27,7 @@ void setUnit(const String& new_unit, ExceptionState&); String unit() const; - String cssType() const; + String type() const; StyleValueType GetType() const override { return StyleValueType::kUnitType; }
diff --git a/third_party/WebKit/Source/core/css/cssom/CSSUnitValue.idl b/third_party/WebKit/Source/core/css/cssom/CSSUnitValue.idl index 02ab6d4..8d7dcf3 100644 --- a/third_party/WebKit/Source/core/css/cssom/CSSUnitValue.idl +++ b/third_party/WebKit/Source/core/css/cssom/CSSUnitValue.idl
@@ -14,5 +14,5 @@ ] interface CSSUnitValue : CSSNumericValue { [EnforceRange] attribute double value; [RaisesException=Setter] attribute DOMString unit; - [ImplementedAs=cssType] readonly attribute DOMString type; + readonly attribute DOMString type; };
diff --git a/third_party/WebKit/Source/core/dom/NodeListsNodeData.h b/third_party/WebKit/Source/core/dom/NodeListsNodeData.h index 12d43d3..8480aa9 100644 --- a/third_party/WebKit/Source/core/dom/NodeListsNodeData.h +++ b/third_party/WebKit/Source/core/dom/NodeListsNodeData.h
@@ -62,15 +62,14 @@ return list; } + using NamedNodeListKey = std::pair<CollectionType, AtomicString>; struct NodeListAtomicCacheMapEntryHash { STATIC_ONLY(NodeListAtomicCacheMapEntryHash); - static unsigned GetHash( - const std::pair<unsigned char, AtomicString>& entry) { + static unsigned GetHash(const NamedNodeListKey& entry) { return DefaultHash<AtomicString>::Hash::GetHash(entry.second) + entry.first; } - static bool Equal(const std::pair<unsigned char, AtomicString>& a, - const std::pair<unsigned char, AtomicString>& b) { + static bool Equal(const NamedNodeListKey& a, const NamedNodeListKey& b) { return a == b; } static const bool safe_to_compare_to_empty_or_deleted = @@ -79,7 +78,7 @@ // Oilpan: keep a weak reference to the collection objects. // Object unregistration is handled by GC's weak processing. - typedef HeapHashMap<std::pair<unsigned char, AtomicString>, + typedef HeapHashMap<NamedNodeListKey, WeakMember<LiveNodeListBase>, NodeListAtomicCacheMapEntryHash> NodeListAtomicNameCacheMap; @@ -92,7 +91,7 @@ const AtomicString& name) { DCHECK(ThreadState::Current()->IsGCForbidden()); NodeListAtomicNameCacheMap::AddResult result = atomic_name_caches_.insert( - NamedNodeListKey(collection_type, name), nullptr); + std::make_pair(collection_type, name), nullptr); if (!result.is_new_entry) { return static_cast<T*>(result.stored_value->value.Get()); } @@ -181,12 +180,6 @@ private: NodeListsNodeData() : child_node_list_(nullptr) {} - std::pair<unsigned char, AtomicString> NamedNodeListKey( - CollectionType type, - const AtomicString& name) { - return std::pair<unsigned char, AtomicString>(type, name); - } - // Can be a ChildNodeList or an EmptyNodeList. WeakMember<NodeList> child_node_list_; NodeListAtomicNameCacheMap atomic_name_caches_;
diff --git a/third_party/WebKit/Source/core/editing/spellcheck/IdleSpellCheckCallbackTest.cpp b/third_party/WebKit/Source/core/editing/spellcheck/IdleSpellCheckCallbackTest.cpp index fc6e225..f3351b8 100644 --- a/third_party/WebKit/Source/core/editing/spellcheck/IdleSpellCheckCallbackTest.cpp +++ b/third_party/WebKit/Source/core/editing/spellcheck/IdleSpellCheckCallbackTest.cpp
@@ -16,7 +16,7 @@ class IdleSpellCheckCallbackTest : public SpellCheckTestBase { protected: IdleSpellCheckCallback& IdleChecker() { - return GetFrame().GetSpellChecker().GetIdleSpellCheckCallback(); + return GetSpellChecker().GetIdleSpellCheckCallback(); } void TransitTo(State state) {
diff --git a/third_party/WebKit/Source/core/editing/spellcheck/SpellCheckTestBase.cpp b/third_party/WebKit/Source/core/editing/spellcheck/SpellCheckTestBase.cpp index 321d14f3..f0a4e7e6 100644 --- a/third_party/WebKit/Source/core/editing/spellcheck/SpellCheckTestBase.cpp +++ b/third_party/WebKit/Source/core/editing/spellcheck/SpellCheckTestBase.cpp
@@ -4,6 +4,8 @@ #include "core/editing/spellcheck/SpellCheckTestBase.h" +#include "core/frame/LocalFrame.h" + namespace blink { void SpellCheckTestBase::SetUp() { @@ -14,4 +16,8 @@ SetupPageWithClients(&page_clients); } +SpellChecker& SpellCheckTestBase::GetSpellChecker() const { + return GetFrame().GetSpellChecker(); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/core/editing/spellcheck/SpellCheckTestBase.h b/third_party/WebKit/Source/core/editing/spellcheck/SpellCheckTestBase.h index de455da..b31852c 100644 --- a/third_party/WebKit/Source/core/editing/spellcheck/SpellCheckTestBase.h +++ b/third_party/WebKit/Source/core/editing/spellcheck/SpellCheckTestBase.h
@@ -11,10 +11,14 @@ namespace blink { +class SpellChecker; + class SpellCheckTestBase : public EditingTestBase { protected: void SetUp() override; + SpellChecker& GetSpellChecker() const; + private: class DummySpellCheckerClient : public EmptySpellCheckerClient { public:
diff --git a/third_party/WebKit/Source/core/editing/spellcheck/SpellCheckerTest.cpp b/third_party/WebKit/Source/core/editing/spellcheck/SpellCheckerTest.cpp index 6fb4114..9af8433 100644 --- a/third_party/WebKit/Source/core/editing/spellcheck/SpellCheckerTest.cpp +++ b/third_party/WebKit/Source/core/editing/spellcheck/SpellCheckerTest.cpp
@@ -36,7 +36,7 @@ Element* input = GetDocument().QuerySelector("input"); input->focus(); // Do not crash in advanceToNextMisspelling. - GetDocument().GetFrame()->GetSpellChecker().AdvanceToNextMisspelling(false); + GetSpellChecker().AdvanceToNextMisspelling(false); } // Regression test for crbug.com/701309 @@ -52,7 +52,7 @@ UpdateAllLifecyclePhases(); // Do not crash in advanceToNextMisspelling. - GetDocument().GetFrame()->GetSpellChecker().AdvanceToNextMisspelling(false); + GetSpellChecker().AdvanceToNextMisspelling(false); } // Regression test for crbug.com/728801 @@ -66,8 +66,7 @@ .Build()); UpdateAllLifecyclePhases(); - // TODO(xiaochengh): We should have SpellCheckTestBase::GetSpellChecker(). - GetFrame().GetSpellChecker().AdvanceToNextMisspelling(false); + GetSpellChecker().AdvanceToNextMisspelling(false); } TEST_F(SpellCheckerTest, SpellCheckDoesNotCauseUpdateLayout) { @@ -88,10 +87,10 @@ SelectionInDOMTree::Builder().Collapse(new_position).Build()); ASSERT_EQ(3u, input->selectionStart()); - EXPECT_TRUE(GetFrame().GetSpellChecker().IsSpellCheckingEnabled()); + EXPECT_TRUE(GetSpellChecker().IsSpellCheckingEnabled()); ForceLayout(); int start_count = LayoutCount(); - GetFrame().GetSpellChecker().RespondToChangedSelection( + GetSpellChecker().RespondToChangedSelection( old_selection.Start(), FrameSelection::kCloseTyping | FrameSelection::kClearTypingStyle); EXPECT_EQ(start_count, LayoutCount());
diff --git a/third_party/WebKit/Source/core/frame/LocalFrameClient.h b/third_party/WebKit/Source/core/frame/LocalFrameClient.h index 5dd9ed4..58be94c 100644 --- a/third_party/WebKit/Source/core/frame/LocalFrameClient.h +++ b/third_party/WebKit/Source/core/frame/LocalFrameClient.h
@@ -203,7 +203,7 @@ }; virtual bool CanCreatePluginWithoutRenderer( const String& mime_type) const = 0; - virtual PluginView* CreatePlugin(HTMLPlugInElement*, + virtual PluginView* CreatePlugin(HTMLPlugInElement&, const KURL&, const Vector<String>&, const Vector<String>&,
diff --git a/third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp b/third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp index 1e7a734..ac7486f 100644 --- a/third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp
@@ -557,7 +557,8 @@ require_layout_object ? LocalFrameClient::kFailOnDetachedPlugin : LocalFrameClient::kAllowDetachedPlugin; PluginView* plugin = frame->Loader().Client()->CreatePlugin( - this, url, param_names, param_values, mime_type, load_manually, policy); + *this, url, param_names, param_values, mime_type, load_manually, + policy); if (!plugin) { if (!layout_item.IsNull() && !layout_item.ShowsUnavailablePluginIndicator()) {
diff --git a/third_party/WebKit/Source/core/layout/ImageQualityController.cpp b/third_party/WebKit/Source/core/layout/ImageQualityController.cpp index 3245bac..d0d4eab 100644 --- a/third_party/WebKit/Source/core/layout/ImageQualityController.cpp +++ b/third_party/WebKit/Source/core/layout/ImageQualityController.cpp
@@ -179,7 +179,8 @@ if (!layer) return false; - if (object.Style()->ImageRendering() == EImageRendering::kOptimizeContrast) + if (object.Style()->ImageRendering() == + EImageRendering::kWebkitOptimizeContrast) return true; if (LocalFrame* frame = object.GetFrame()) {
diff --git a/third_party/WebKit/Source/core/layout/LayoutObject.h b/third_party/WebKit/Source/core/layout/LayoutObject.h index c881d97..ed733a9 100644 --- a/third_party/WebKit/Source/core/layout/LayoutObject.h +++ b/third_party/WebKit/Source/core/layout/LayoutObject.h
@@ -1438,13 +1438,6 @@ TransformState&, VisualRectFlags = kDefaultVisualRectFlags) const; - // Allows objects to adjust |visualEffect|, which is in the space of the - // paint invalidation container, for any special raster effects that might - // expand the rastered pixel area. Returns true if the rect is expanded. - virtual bool AdjustVisualRectForRasterEffects(LayoutRect& visual_rect) const { - return false; - } - // Return the offset to the column in which the specified point (in // flow-thread coordinates) lives. This is used to convert a flow-thread point // to a point in the containing coordinate space.
diff --git a/third_party/WebKit/Source/core/layout/PaintInvalidationState.cpp b/third_party/WebKit/Source/core/layout/PaintInvalidationState.cpp index a44ab00..9e8d2ac 100644 --- a/third_party/WebKit/Source/core/layout/PaintInvalidationState.cpp +++ b/third_party/WebKit/Source/core/layout/PaintInvalidationState.cpp
@@ -468,7 +468,8 @@ PaintLayer::MapRectInPaintInvalidationContainerToBacking( *paint_invalidation_container_, rect); - current_object_.AdjustVisualRectForRasterEffects(rect); + if (!rect.IsEmpty()) + rect.Inflate(current_object_.VisualRectOutsetForRasterEffects()); rect.Move(current_object_.ScrollAdjustmentForPaintInvalidation( *paint_invalidation_container_)); @@ -518,7 +519,8 @@ PaintLayer::MapRectInPaintInvalidationContainerToBacking( *paint_invalidation_container_, rect); - current_object_.AdjustVisualRectForRasterEffects(rect); + if (!rect.IsEmpty()) + rect.Inflate(current_object_.VisualRectOutsetForRasterEffects()); rect.Move(current_object_.ScrollAdjustmentForPaintInvalidation( *paint_invalidation_container_));
diff --git a/third_party/WebKit/Source/core/layout/TextAutosizer.cpp b/third_party/WebKit/Source/core/layout/TextAutosizer.cpp index 77650aa..f5212eae 100644 --- a/third_party/WebKit/Source/core/layout/TextAutosizer.cpp +++ b/third_party/WebKit/Source/core/layout/TextAutosizer.cpp
@@ -1155,7 +1155,8 @@ parent_deepest_block_containing_all_text)); #endif - float content_width = cluster->root_->ContentLogicalWidth().ToFloat(); + float content_width = + DeepestBlockContainingAllText(cluster)->ContentLogicalWidth().ToFloat(); float cluster_text_width = parent_deepest_block_containing_all_text->ContentLogicalWidth().ToFloat();
diff --git a/third_party/WebKit/Source/core/layout/TextAutosizerTest.cpp b/third_party/WebKit/Source/core/layout/TextAutosizerTest.cpp index da1c5880..b6fdb705 100644 --- a/third_party/WebKit/Source/core/layout/TextAutosizerTest.cpp +++ b/third_party/WebKit/Source/core/layout/TextAutosizerTest.cpp
@@ -739,7 +739,7 @@ Element* html = GetDocument().body()->parentElement(); html->setInnerHTML( "<head>" - " <meta name='viewport' content='800'>" + " <meta name='viewport' content='width=800'>" " <style>" " html { font-size:16px; font-family:'Times New Roman';}" " </style>" @@ -774,4 +774,41 @@ IntSize(360, 640)); GetDocument().View()->UpdateAllLifecyclePhases(); } + +TEST_F(TextAutosizerTest, narrowContentInsideNestedWideBlock) { + Element* html = GetDocument().body()->parentElement(); + html->setInnerHTML( + "<head>" + " <meta name='viewport' content='width=800'>" + " <style>" + " html { font-size:16px;}" + " </style>" + "</head>" + "<body>" + " <div style='width:800px'>" + " <div style='width:800px'>" + " <div style='width:200px' id='content'>" + " Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed " + " do eiusmod tempor incididunt ut labore et dolore magna aliqua." + " Ut enim ad minim veniam, quis nostrud exercitation ullamco " + " laboris nisi ut aliquip ex ea commodo consequat. Duis aute " + " irure dolor in reprehenderit in voluptate velit esse cillum " + " dolore eu fugiat nulla pariatur. Excepteur sint occaecat " + " cupidatat non proident, sunt in culpa qui officia deserunt " + " mollit anim id est laborum." + " </div>" + " </div>" + " Content belong to first wide block." + " </div>" + "</body>", + ASSERT_NO_EXCEPTION); + GetDocument().View()->UpdateAllLifecyclePhases(); + + Element* content = GetDocument().getElementById("content"); + //(content width = 200px) / (window width = 320px) < 1.0f, multiplier = 1.0, + // font-size = 16px; + EXPECT_FLOAT_EQ(16.f, + content->GetLayoutObject()->Style()->ComputedFontSize()); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGShape.cpp b/third_party/WebKit/Source/core/layout/svg/LayoutSVGShape.cpp index bfe6efc..dec3bb7 100644 --- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGShape.cpp +++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGShape.cpp
@@ -45,19 +45,6 @@ namespace blink { -bool LayoutSVGShape::AdjustVisualRectForRasterEffects( - LayoutRect& visual_rect) const { - // Account for raster expansions due to SVG stroke hairline raster effects. - if (!visual_rect.IsEmpty() && StyleRef().SvgStyle().HasVisibleStroke()) { - LayoutUnit pad(0.5f); - if (StyleRef().SvgStyle().CapStyle() != kButtCap) - pad += 0.5f; - visual_rect.Inflate(pad); - return true; - } - return false; -} - LayoutSVGShape::LayoutSVGShape(SVGGeometryElement* node) : LayoutSVGModelObject(node), // Default is false, the cached rects are empty from the beginning. @@ -340,4 +327,15 @@ return *rare_data_.get(); } +LayoutUnit LayoutSVGShape::VisualRectOutsetForRasterEffects() const { + // Account for raster expansions due to SVG stroke hairline raster effects. + if (StyleRef().SvgStyle().HasVisibleStroke()) { + LayoutUnit outset(0.5f); + if (StyleRef().SvgStyle().CapStyle() != kButtCap) + outset += 0.5f; + return outset; + } + return LayoutUnit(); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGShape.h b/third_party/WebKit/Source/core/layout/svg/LayoutSVGShape.h index 1cd89611..f59a3f0 100644 --- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGShape.h +++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGShape.h
@@ -106,7 +106,7 @@ const char* GetName() const override { return "LayoutSVGShape"; } protected: - bool AdjustVisualRectForRasterEffects(LayoutRect&) const override; + LayoutUnit VisualRectOutsetForRasterEffects() const override; void ClearPath() { path_.reset(); } void CreatePath();
diff --git a/third_party/WebKit/Source/core/loader/EmptyClients.cpp b/third_party/WebKit/Source/core/loader/EmptyClients.cpp index 003ff95..9871f76 100644 --- a/third_party/WebKit/Source/core/loader/EmptyClients.cpp +++ b/third_party/WebKit/Source/core/loader/EmptyClients.cpp
@@ -169,7 +169,7 @@ return nullptr; } -PluginView* EmptyLocalFrameClient::CreatePlugin(HTMLPlugInElement*, +PluginView* EmptyLocalFrameClient::CreatePlugin(HTMLPlugInElement&, const KURL&, const Vector<String>&, const Vector<String>&,
diff --git a/third_party/WebKit/Source/core/loader/EmptyClients.h b/third_party/WebKit/Source/core/loader/EmptyClients.h index f6469c8..9138d0c 100644 --- a/third_party/WebKit/Source/core/loader/EmptyClients.h +++ b/third_party/WebKit/Source/core/loader/EmptyClients.h
@@ -335,7 +335,7 @@ LocalFrame* CreateFrame(const FrameLoadRequest&, const AtomicString&, HTMLFrameOwnerElement*) override; - PluginView* CreatePlugin(HTMLPlugInElement*, + PluginView* CreatePlugin(HTMLPlugInElement&, const KURL&, const Vector<String>&, const Vector<String>&,
diff --git a/third_party/WebKit/Source/core/paint/HTMLCanvasPainter.cpp b/third_party/WebKit/Source/core/paint/HTMLCanvasPainter.cpp index a6411b2..0362d91b 100644 --- a/third_party/WebKit/Source/core/paint/HTMLCanvasPainter.cpp +++ b/third_party/WebKit/Source/core/paint/HTMLCanvasPainter.cpp
@@ -56,7 +56,7 @@ // is set. See bug for more details: crbug.com/353716. InterpolationQuality interpolation_quality = layout_html_canvas_.Style()->ImageRendering() == - EImageRendering::kOptimizeContrast + EImageRendering::kWebkitOptimizeContrast ? kInterpolationLow : CanvasDefaultInterpolationQuality; if (layout_html_canvas_.Style()->ImageRendering() ==
diff --git a/third_party/WebKit/Source/core/paint/PaintInvalidator.cpp b/third_party/WebKit/Source/core/paint/PaintInvalidator.cpp index 058ed32..2bc0b55 100644 --- a/third_party/WebKit/Source/core/paint/PaintInvalidator.cpp +++ b/third_party/WebKit/Source/core/paint/PaintInvalidator.cpp
@@ -135,7 +135,8 @@ result.MoveBy(-context.paint_invalidation_container->PaintOffset()); } - object.AdjustVisualRectForRasterEffects(result); + if (!result.IsEmpty()) + result.Inflate(object.VisualRectOutsetForRasterEffects()); PaintLayer::MapRectInPaintInvalidationContainerToBacking( *context.paint_invalidation_container, result);
diff --git a/third_party/WebKit/Source/core/style/BUILD.gn b/third_party/WebKit/Source/core/style/BUILD.gn index 317da73..112d3d55 100644 --- a/third_party/WebKit/Source/core/style/BUILD.gn +++ b/third_party/WebKit/Source/core/style/BUILD.gn
@@ -51,8 +51,10 @@ "NinePieceImage.cpp", "NinePieceImage.h", "OutlineValue.h", + "PaintImages.h", "QuotesData.cpp", "QuotesData.h", + "ScrollSnapPoints.h", "ShadowData.cpp", "ShadowData.h", "ShadowList.cpp",
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.cpp b/third_party/WebKit/Source/core/style/ComputedStyle.cpp index ddf32276..b073dd9 100644 --- a/third_party/WebKit/Source/core/style/ComputedStyle.cpp +++ b/third_party/WebKit/Source/core/style/ComputedStyle.cpp
@@ -921,7 +921,7 @@ void ComputedStyle::AddPaintImage(StyleImage* image) { if (!rare_non_inherited_data_.Access()->paint_images_) { rare_non_inherited_data_.Access()->paint_images_ = - WTF::MakeUnique<Vector<Persistent<StyleImage>>>(); + WTF::MakeUnique<PaintImages>(); } rare_non_inherited_data_.Access()->paint_images_->push_back(image); }
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.h b/third_party/WebKit/Source/core/style/ComputedStyle.h index 5a9ad613..b772b0a 100644 --- a/third_party/WebKit/Source/core/style/ComputedStyle.h +++ b/third_party/WebKit/Source/core/style/ComputedStyle.h
@@ -677,7 +677,11 @@ // column-rule-width (aka -webkit-column-rule-width) static unsigned short InitialColumnRuleWidth() { return 3; } unsigned short ColumnRuleWidth() const { - return rare_non_inherited_data_->multi_col_->RuleWidth(); + const BorderValue& rule = rare_non_inherited_data_->multi_col_->rule_; + if (rule.Style() == EBorderStyle::kNone || + rule.Style() == EBorderStyle::kHidden) + return 0; + return rule.Width(); } void SetColumnRuleWidth(unsigned short w) { SET_NESTED_BORDER_WIDTH(rare_non_inherited_data_, multi_col_, rule_, w); @@ -1007,17 +1011,6 @@ SET_VAR(rare_inherited_data_, respect_image_orientation_, v); } - // image-rendering - static EImageRendering InitialImageRendering() { - return EImageRendering::kAuto; - } - EImageRendering ImageRendering() const { - return static_cast<EImageRendering>(rare_inherited_data_->image_rendering_); - } - void SetImageRendering(EImageRendering v) { - SET_VAR(rare_inherited_data_, image_rendering_, static_cast<unsigned>(v)); - } - // isolation static EIsolation InitialIsolation() { return kIsolationAuto; } EIsolation Isolation() const {
diff --git a/third_party/WebKit/Source/core/style/ComputedStyleConstants.h b/third_party/WebKit/Source/core/style/ComputedStyleConstants.h index be6ea14..d4a285e 100644 --- a/third_party/WebKit/Source/core/style/ComputedStyleConstants.h +++ b/third_party/WebKit/Source/core/style/ComputedStyleConstants.h
@@ -266,14 +266,6 @@ enum TextOverflow { kTextOverflowClip = 0, kTextOverflowEllipsis }; -enum class EImageRendering { - kAuto, - kOptimizeSpeed, - kOptimizeQuality, - kOptimizeContrast, - kPixelated -}; - static const size_t kGridAutoFlowBits = 4; enum InternalGridAutoFlowAlgorithm { kInternalAutoFlowAlgorithmSparse = 0x1,
diff --git a/third_party/WebKit/Source/core/style/OWNERS b/third_party/WebKit/Source/core/style/OWNERS index 9c6d10c2..e501eae3 100644 --- a/third_party/WebKit/Source/core/style/OWNERS +++ b/third_party/WebKit/Source/core/style/OWNERS
@@ -1,4 +1,6 @@ meade@chromium.org suzyh@chromium.org +nainar@chromium.org +shend@chromium.org # COMPONENT: Blink>CSS
diff --git a/third_party/WebKit/Source/core/style/PaintImages.h b/third_party/WebKit/Source/core/style/PaintImages.h new file mode 100644 index 0000000..27864fe --- /dev/null +++ b/third_party/WebKit/Source/core/style/PaintImages.h
@@ -0,0 +1,26 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PaintImages_h +#define PaintImages_h + +#include <memory> +#include "core/style/StyleImage.h" +#include "platform/heap/Persistent.h" +#include "platform/wtf/PtrUtil.h" +#include "platform/wtf/Vector.h" + +namespace blink { + +// Not to be deleted through a pointer to the base class. +class PaintImages : public Vector<Persistent<StyleImage>> { + public: + std::unique_ptr<PaintImages> Clone() const { + return WTF::WrapUnique(new PaintImages(*this)); + } +}; + +} // namespace blink + +#endif // PaintImages_h
diff --git a/third_party/WebKit/Source/core/style/ScrollSnapPoints.h b/third_party/WebKit/Source/core/style/ScrollSnapPoints.h new file mode 100644 index 0000000..473265b6 --- /dev/null +++ b/third_party/WebKit/Source/core/style/ScrollSnapPoints.h
@@ -0,0 +1,35 @@ +// 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 ScrollSnapPoints_h +#define ScrollSnapPoints_h + +#include <memory> +#include "platform/Length.h" + +namespace blink { + +struct ScrollSnapPoints { + DISALLOW_NEW(); + + ScrollSnapPoints() + : repeat_offset(100, kPercent), has_repeat(false), uses_elements(false) {} + + bool operator==(const ScrollSnapPoints& other) const { + return repeat_offset == other.repeat_offset && + has_repeat == other.has_repeat && + uses_elements == other.uses_elements; + } + bool operator!=(const ScrollSnapPoints& other) const { + return !(*this == other); + } + + Length repeat_offset; + bool has_repeat; + bool uses_elements; +}; + +} // namespace blink + +#endif // ScrollSnapPoints_h
diff --git a/third_party/WebKit/Source/core/style/StyleMultiColData.h b/third_party/WebKit/Source/core/style/StyleMultiColData.h index bc9d257a..122465cd 100644 --- a/third_party/WebKit/Source/core/style/StyleMultiColData.h +++ b/third_party/WebKit/Source/core/style/StyleMultiColData.h
@@ -47,13 +47,6 @@ bool operator==(const StyleMultiColData&) const; bool operator!=(const StyleMultiColData& o) const { return !(*this == o); } - unsigned short RuleWidth() const { - if (rule_.Style() == EBorderStyle::kNone || - rule_.Style() == EBorderStyle::kHidden) - return 0; - return rule_.Width(); - } - float width_; unsigned short count_; float gap_;
diff --git a/third_party/WebKit/Source/core/style/StyleRareNonInheritedData.cpp b/third_party/WebKit/Source/core/style/StyleRareNonInheritedData.cpp index c5f5bec..72b1d5b 100644 --- a/third_party/WebKit/Source/core/style/StyleRareNonInheritedData.cpp +++ b/third_party/WebKit/Source/core/style/StyleRareNonInheritedData.cpp
@@ -176,6 +176,9 @@ visited_link_border_right_color_(o.visited_link_border_right_color_), visited_link_border_top_color_(o.visited_link_border_top_color_), visited_link_border_bottom_color_(o.visited_link_border_bottom_color_), + callback_selectors_(o.callback_selectors_), + paint_images_(o.paint_images_ ? new PaintImages(*o.paint_images_) + : nullptr), variables_(o.variables_ ? o.variables_->Clone() : nullptr), align_content_(o.align_content_), align_items_(o.align_items_),
diff --git a/third_party/WebKit/Source/core/style/StyleRareNonInheritedData.h b/third_party/WebKit/Source/core/style/StyleRareNonInheritedData.h index 912ff09..0ea0316 100644 --- a/third_party/WebKit/Source/core/style/StyleRareNonInheritedData.h +++ b/third_party/WebKit/Source/core/style/StyleRareNonInheritedData.h
@@ -37,6 +37,7 @@ #include "core/style/LineClampValue.h" #include "core/style/NinePieceImage.h" #include "core/style/OutlineValue.h" +#include "core/style/PaintImages.h" #include "core/style/ShapeValue.h" #include "core/style/StyleContentAlignmentData.h" #include "core/style/StyleScrollSnapData.h" @@ -147,7 +148,7 @@ Vector<String> callback_selectors_; - std::unique_ptr<Vector<Persistent<StyleImage>>> paint_images_; + std::unique_ptr<PaintImages> paint_images_; std::unique_ptr<StyleNonInheritedVariables> variables_;
diff --git a/third_party/WebKit/Source/core/style/StyleScrollSnapData.cpp b/third_party/WebKit/Source/core/style/StyleScrollSnapData.cpp index 5acff71..b33d1b2 100644 --- a/third_party/WebKit/Source/core/style/StyleScrollSnapData.cpp +++ b/third_party/WebKit/Source/core/style/StyleScrollSnapData.cpp
@@ -29,14 +29,6 @@ namespace blink { -ScrollSnapPoints::ScrollSnapPoints() - : repeat_offset(100, kPercent), has_repeat(false), uses_elements(false) {} - -bool operator==(const ScrollSnapPoints& a, const ScrollSnapPoints& b) { - return a.repeat_offset == b.repeat_offset && a.has_repeat == b.has_repeat && - a.uses_elements == b.uses_elements; -} - StyleScrollSnapData::StyleScrollSnapData() : x_points_(ComputedStyle::InitialScrollSnapPointsX()), y_points_(ComputedStyle::InitialScrollSnapPointsY()),
diff --git a/third_party/WebKit/Source/core/style/StyleScrollSnapData.h b/third_party/WebKit/Source/core/style/StyleScrollSnapData.h index f0ae6bcf..517f57b 100644 --- a/third_party/WebKit/Source/core/style/StyleScrollSnapData.h +++ b/third_party/WebKit/Source/core/style/StyleScrollSnapData.h
@@ -26,6 +26,7 @@ #ifndef StyleScrollSnapData_h #define StyleScrollSnapData_h +#include "core/style/ScrollSnapPoints.h" #include "platform/LengthPoint.h" #include "platform/wtf/Allocator.h" #include "platform/wtf/RefCounted.h" @@ -33,19 +34,6 @@ namespace blink { -struct ScrollSnapPoints { - DISALLOW_NEW(); - Length repeat_offset; - bool has_repeat; - bool uses_elements; - ScrollSnapPoints(); -}; - -bool operator==(const ScrollSnapPoints&, const ScrollSnapPoints&); -inline bool operator!=(const ScrollSnapPoints& a, const ScrollSnapPoints& b) { - return !(a == b); -} - class StyleScrollSnapData : public RefCounted<StyleScrollSnapData> { public: static PassRefPtr<StyleScrollSnapData> Create() {
diff --git a/third_party/WebKit/Source/core/svg/SVGElement.cpp b/third_party/WebKit/Source/core/svg/SVGElement.cpp index 4ff98319..8225f3e 100644 --- a/third_party/WebKit/Source/core/svg/SVGElement.cpp +++ b/third_party/WebKit/Source/core/svg/SVGElement.cpp
@@ -743,7 +743,18 @@ } } -typedef HashMap<QualifiedName, AnimatedPropertyType> AttributeToPropertyTypeMap; +// If the attribute is not present in the map, the map will return the "empty +// value" - which is kAnimatedUnknown. +struct AnimatedPropertyTypeHashTraits : HashTraits<AnimatedPropertyType> { + static const bool kEmptyValueIsZero = true; + static AnimatedPropertyType EmptyValue() { return kAnimatedUnknown; } +}; + +using AttributeToPropertyTypeMap = HashMap<QualifiedName, + AnimatedPropertyType, + DefaultHash<QualifiedName>::Hash, + HashTraits<QualifiedName>, + AnimatedPropertyTypeHashTraits>; AnimatedPropertyType SVGElement::AnimatedPropertyTypeForCSSAttribute( const QualifiedName& attribute_name) { DEFINE_STATIC_LOCAL(AttributeToPropertyTypeMap, css_property_map, ()); @@ -812,9 +823,6 @@ for (size_t i = 0; i < WTF_ARRAY_LENGTH(attr_to_types); i++) css_property_map.Set(attr_to_types[i].attr, attr_to_types[i].prop_type); } - // If the attribute is not present in the map, this will return the "empty - // value" per HashTraits - which is AnimatedUnknown. - DCHECK_EQ(HashTraits<AnimatedPropertyType>::EmptyValue(), kAnimatedUnknown); return css_property_map.at(attribute_name); }
diff --git a/third_party/WebKit/Source/core/workers/BUILD.gn b/third_party/WebKit/Source/core/workers/BUILD.gn index bf0958a..ccc8e28 100644 --- a/third_party/WebKit/Source/core/workers/BUILD.gn +++ b/third_party/WebKit/Source/core/workers/BUILD.gn
@@ -22,8 +22,6 @@ "InProcessWorkerMessagingProxy.h", "InProcessWorkerObjectProxy.cpp", "InProcessWorkerObjectProxy.h", - "MainThreadWorklet.cpp", - "MainThreadWorklet.h", "MainThreadWorkletGlobalScope.cpp", "MainThreadWorkletGlobalScope.h", "ParentFrameTaskRunners.cpp",
diff --git a/third_party/WebKit/Source/core/workers/MainThreadWorklet.cpp b/third_party/WebKit/Source/core/workers/MainThreadWorklet.cpp deleted file mode 100644 index 4ff8973..0000000 --- a/third_party/WebKit/Source/core/workers/MainThreadWorklet.cpp +++ /dev/null
@@ -1,96 +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 "core/workers/MainThreadWorklet.h" - -#include "bindings/core/v8/ScriptPromiseResolver.h" -#include "bindings/core/v8/ScriptSourceCode.h" -#include "bindings/core/v8/V8BindingForCore.h" -#include "core/dom/TaskRunnerHelper.h" -#include "core/frame/LocalFrame.h" -#include "core/workers/WorkletGlobalScopeProxy.h" -#include "core/workers/WorkletPendingTasks.h" -#include "platform/WebTaskRunner.h" -#include "platform/wtf/WTF.h" - -namespace blink { - -MainThreadWorklet::MainThreadWorklet(LocalFrame* frame) : Worklet(frame) {} - -WorkletGlobalScopeProxy* MainThreadWorklet::FindAvailableGlobalScope() const { - DCHECK(IsMainThread()); - // TODO(nhiroki): Support the case where there are multiple global scopes. - DCHECK_EQ(1u, GetNumberOfGlobalScopes()); - return proxies_.begin()->get(); -} - -// Implementation of the second half of the "addModule(moduleURL, options)" -// algorithm: -// https://drafts.css-houdini.org/worklets/#dom-worklet-addmodule -void MainThreadWorklet::FetchAndInvokeScript(const KURL& module_url_record, - const WorkletOptions& options, - ScriptPromiseResolver* resolver) { - DCHECK(IsMainThread()); - if (!GetExecutionContext()) - return; - - // Step 6: "Let credentialOptions be the credentials member of options." - // TODO(nhiroki): Add tests for credentialOptions (https://crbug.com/710837). - WebURLRequest::FetchCredentialsMode credentials_mode = - ParseCredentialsOption(options.credentials()); - - // Step 7: "Let outsideSettings be the relevant settings object of this." - // In the specification, outsideSettings is used for posting a task to the - // document's responsible event loop. In our implementation, we use the - // document's UnspecedLoading task runner as that is what we commonly use for - // module loading. - RefPtr<WebTaskRunner> outside_settings_task_runner = - TaskRunnerHelper::Get(TaskType::kUnspecedLoading, GetExecutionContext()); - - // Step 8: "Let moduleResponsesMap be worklet's module responses map." - // TODO(nhiroki): Implement moduleResponsesMap (https://crbug.com/627945). - - // Step 9: "Let workletGlobalScopeType be worklet's worklet global scope - // type." - // workletGlobalScopeType is encoded into the class name (e.g., PaintWorklet). - - // Step 10: "If the worklet's WorkletGlobalScopes is empty, run the following - // steps:" - // 10.1: "Create a WorkletGlobalScope given workletGlobalScopeType, - // moduleResponsesMap, and outsideSettings." - // 10.2: "Add the WorkletGlobalScope to worklet's WorkletGlobalScopes." - // "Depending on the type of worklet the user agent may create additional - // WorkletGlobalScopes at this time." - while (NeedsToCreateGlobalScope()) - proxies_.insert(CreateGlobalScope()); - DCHECK_EQ(1u, GetNumberOfGlobalScopes()); - - // Step 11: "Let pendingTaskStruct be a new pending tasks struct with counter - // initialized to the length of worklet's WorkletGlobalScopes." - WorkletPendingTasks* pending_tasks = - new WorkletPendingTasks(GetNumberOfGlobalScopes(), resolver); - - // Step 12: "For each workletGlobalScope in the worklet's - // WorkletGlobalScopes, queue a task on the workletGlobalScope to fetch and - // invoke a worklet script given workletGlobalScope, moduleURLRecord, - // moduleResponsesMap, credentialOptions, outsideSettings, pendingTaskStruct, - // and promise." - // TODO(nhiroki): Queue a task instead of executing this here. - for (const auto& proxy : proxies_) { - proxy->FetchAndInvokeScript(module_url_record, credentials_mode, - outside_settings_task_runner, pending_tasks); - } -} - -void MainThreadWorklet::ContextDestroyed(ExecutionContext* execution_context) { - DCHECK(IsMainThread()); - for (const auto& proxy : proxies_) - proxy->TerminateWorkletGlobalScope(); -} - -DEFINE_TRACE(MainThreadWorklet) { - Worklet::Trace(visitor); -} - -} // namespace blink
diff --git a/third_party/WebKit/Source/core/workers/MainThreadWorklet.h b/third_party/WebKit/Source/core/workers/MainThreadWorklet.h deleted file mode 100644 index 72b1bc6..0000000 --- a/third_party/WebKit/Source/core/workers/MainThreadWorklet.h +++ /dev/null
@@ -1,67 +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 MainThreadWorklet_h -#define MainThreadWorklet_h - -#include "core/workers/Worklet.h" - -#include "bindings/core/v8/ScriptPromise.h" -#include "core/CoreExport.h" -#include "platform/heap/Handle.h" - -namespace blink { - -class LocalFrame; -class ScriptPromiseResolver; -class WorkletGlobalScopeProxy; - -// A MainThreadWorklet is a worklet that runs only on the main thread. -// TODO(nhiroki): This is a temporary class to support module loading for main -// thread worklets. This and ThreadedWorklet will be merged into the base -// Worklet class once threaded worklets are ready to use module loading. -class CORE_EXPORT MainThreadWorklet : public Worklet { - USING_GARBAGE_COLLECTED_MIXIN(MainThreadWorklet); - WTF_MAKE_NONCOPYABLE(MainThreadWorklet); - - public: - virtual ~MainThreadWorklet() = default; - - // ContextLifecycleObserver - void ContextDestroyed(ExecutionContext*) final; - - DECLARE_VIRTUAL_TRACE(); - - protected: - explicit MainThreadWorklet(LocalFrame*); - - // Returns one of available global scopes. - WorkletGlobalScopeProxy* FindAvailableGlobalScope() const; - - size_t GetNumberOfGlobalScopes() const { return proxies_.size(); } - - private: - // Worklet. - void FetchAndInvokeScript(const KURL& module_url_record, - const WorkletOptions&, - ScriptPromiseResolver*) override; - - // Returns true if there are no global scopes or additional global scopes are - // necessary. CreateGlobalScope() will be called in that case. Each worklet - // can define how to pool global scopes here. - virtual bool NeedsToCreateGlobalScope() = 0; - virtual std::unique_ptr<WorkletGlobalScopeProxy> CreateGlobalScope() = 0; - - // "A Worklet has a list of the worklet's WorkletGlobalScopes. Initially this - // list is empty; it is populated when the user agent chooses to create its - // WorkletGlobalScope." - // https://drafts.css-houdini.org/worklets/#worklet-section - // TODO(nhiroki): Make (Paint)WorkletGlobalScopeProxy GC-managed object to - // avoid that GC graphs are disjointed (https://crbug.com/719775). - HashSet<std::unique_ptr<WorkletGlobalScopeProxy>> proxies_; -}; - -} // namespace blink - -#endif // MainThreadWorklet_h
diff --git a/third_party/WebKit/Source/core/workers/ThreadedWorklet.cpp b/third_party/WebKit/Source/core/workers/ThreadedWorklet.cpp index 7a873ded..1d7b5f9 100644 --- a/third_party/WebKit/Source/core/workers/ThreadedWorklet.cpp +++ b/third_party/WebKit/Source/core/workers/ThreadedWorklet.cpp
@@ -83,6 +83,16 @@ std::move(outside_settings_task_runner), pending_tasks); } +bool ThreadedWorklet::NeedsToCreateGlobalScope() { + NOTREACHED(); + return false; +} + +std::unique_ptr<WorkletGlobalScopeProxy> ThreadedWorklet::CreateGlobalScope() { + NOTREACHED(); + return nullptr; +} + void ThreadedWorklet::ContextDestroyed(ExecutionContext* execution_context) { DCHECK(IsMainThread()); if (IsInitialized())
diff --git a/third_party/WebKit/Source/core/workers/ThreadedWorklet.h b/third_party/WebKit/Source/core/workers/ThreadedWorklet.h index 297d997..46c8e05 100644 --- a/third_party/WebKit/Source/core/workers/ThreadedWorklet.h +++ b/third_party/WebKit/Source/core/workers/ThreadedWorklet.h
@@ -43,7 +43,9 @@ // Worklet void FetchAndInvokeScript(const KURL& module_url_record, const WorkletOptions&, - ScriptPromiseResolver*) override; + ScriptPromiseResolver*) final; + bool NeedsToCreateGlobalScope() final; + std::unique_ptr<WorkletGlobalScopeProxy> CreateGlobalScope() final; // Called when addModule() is called for the first time. virtual void Initialize() = 0;
diff --git a/third_party/WebKit/Source/core/workers/Worklet.cpp b/third_party/WebKit/Source/core/workers/Worklet.cpp index deb56b048..5fc33e55 100644 --- a/third_party/WebKit/Source/core/workers/Worklet.cpp +++ b/third_party/WebKit/Source/core/workers/Worklet.cpp
@@ -9,7 +9,9 @@ #include "core/dom/Document.h" #include "core/dom/TaskRunnerHelper.h" #include "core/frame/LocalFrame.h" -#include "core/workers/WorkletGlobalScopeProxy.h" +#include "core/workers/WorkletPendingTasks.h" +#include "platform/WebTaskRunner.h" +#include "platform/wtf/WTF.h" namespace blink { @@ -62,6 +64,12 @@ return promise; } +void Worklet::ContextDestroyed(ExecutionContext* execution_context) { + DCHECK(IsMainThread()); + for (const auto& proxy : proxies_) + proxy->TerminateWorkletGlobalScope(); +} + WebURLRequest::FetchCredentialsMode Worklet::ParseCredentialsOption( const String& credentials_option) { if (credentials_option == "omit") @@ -74,6 +82,71 @@ return WebURLRequest::kFetchCredentialsModeOmit; } +WorkletGlobalScopeProxy* Worklet::FindAvailableGlobalScope() const { + DCHECK(IsMainThread()); + // TODO(nhiroki): Support the case where there are multiple global scopes. + DCHECK_EQ(1u, GetNumberOfGlobalScopes()); + return proxies_.begin()->get(); +} + +// Implementation of the second half of the "addModule(moduleURL, options)" +// algorithm: +// https://drafts.css-houdini.org/worklets/#dom-worklet-addmodule +void Worklet::FetchAndInvokeScript(const KURL& module_url_record, + const WorkletOptions& options, + ScriptPromiseResolver* resolver) { + DCHECK(IsMainThread()); + if (!GetExecutionContext()) + return; + + // Step 6: "Let credentialOptions be the credentials member of options." + // TODO(nhiroki): Add tests for credentialOptions (https://crbug.com/710837). + WebURLRequest::FetchCredentialsMode credentials_mode = + ParseCredentialsOption(options.credentials()); + + // Step 7: "Let outsideSettings be the relevant settings object of this." + // In the specification, outsideSettings is used for posting a task to the + // document's responsible event loop. In our implementation, we use the + // document's UnspecedLoading task runner as that is what we commonly use for + // module loading. + RefPtr<WebTaskRunner> outside_settings_task_runner = + TaskRunnerHelper::Get(TaskType::kUnspecedLoading, GetExecutionContext()); + + // Step 8: "Let moduleResponsesMap be worklet's module responses map." + // TODO(nhiroki): Implement moduleResponsesMap (https://crbug.com/627945). + + // Step 9: "Let workletGlobalScopeType be worklet's worklet global scope + // type." + // workletGlobalScopeType is encoded into the class name (e.g., PaintWorklet). + + // Step 10: "If the worklet's WorkletGlobalScopes is empty, run the following + // steps:" + // 10.1: "Create a WorkletGlobalScope given workletGlobalScopeType, + // moduleResponsesMap, and outsideSettings." + // 10.2: "Add the WorkletGlobalScope to worklet's WorkletGlobalScopes." + // "Depending on the type of worklet the user agent may create additional + // WorkletGlobalScopes at this time." + while (NeedsToCreateGlobalScope()) + proxies_.insert(CreateGlobalScope()); + DCHECK_EQ(1u, GetNumberOfGlobalScopes()); + + // Step 11: "Let pendingTaskStruct be a new pending tasks struct with counter + // initialized to the length of worklet's WorkletGlobalScopes." + WorkletPendingTasks* pending_tasks = + new WorkletPendingTasks(GetNumberOfGlobalScopes(), resolver); + + // Step 12: "For each workletGlobalScope in the worklet's + // WorkletGlobalScopes, queue a task on the workletGlobalScope to fetch and + // invoke a worklet script given workletGlobalScope, moduleURLRecord, + // moduleResponsesMap, credentialOptions, outsideSettings, pendingTaskStruct, + // and promise." + // TODO(nhiroki): Queue a task instead of executing this here. + for (const auto& proxy : proxies_) { + proxy->FetchAndInvokeScript(module_url_record, credentials_mode, + outside_settings_task_runner, pending_tasks); + } +} + DEFINE_TRACE(Worklet) { ContextLifecycleObserver::Trace(visitor); }
diff --git a/third_party/WebKit/Source/core/workers/Worklet.h b/third_party/WebKit/Source/core/workers/Worklet.h index 690d9aa..8775818 100644 --- a/third_party/WebKit/Source/core/workers/Worklet.h +++ b/third_party/WebKit/Source/core/workers/Worklet.h
@@ -8,6 +8,7 @@ #include "bindings/core/v8/ScriptPromise.h" #include "core/CoreExport.h" #include "core/dom/ContextLifecycleObserver.h" +#include "core/workers/WorkletGlobalScopeProxy.h" #include "core/workers/WorkletOptions.h" #include "platform/bindings/ScriptWrappable.h" #include "platform/heap/Handle.h" @@ -34,9 +35,12 @@ // Worklet.idl // addModule() imports ES6 module scripts. - virtual ScriptPromise addModule(ScriptState*, - const String& module_url, - const WorkletOptions&); + ScriptPromise addModule(ScriptState*, + const String& module_url, + const WorkletOptions&); + + // ContextLifecycleObserver + void ContextDestroyed(ExecutionContext*) override; DECLARE_VIRTUAL_TRACE(); @@ -47,10 +51,29 @@ static WebURLRequest::FetchCredentialsMode ParseCredentialsOption( const String& credentials_option); + // Returns one of available global scopes. + WorkletGlobalScopeProxy* FindAvailableGlobalScope() const; + + size_t GetNumberOfGlobalScopes() const { return proxies_.size(); } + private: virtual void FetchAndInvokeScript(const KURL& module_url_record, const WorkletOptions&, - ScriptPromiseResolver*) = 0; + ScriptPromiseResolver*); + + // Returns true if there are no global scopes or additional global scopes are + // necessary. CreateGlobalScope() will be called in that case. Each worklet + // can define how to pool global scopes here. + virtual bool NeedsToCreateGlobalScope() = 0; + virtual std::unique_ptr<WorkletGlobalScopeProxy> CreateGlobalScope() = 0; + + // "A Worklet has a list of the worklet's WorkletGlobalScopes. Initially this + // list is empty; it is populated when the user agent chooses to create its + // WorkletGlobalScope." + // https://drafts.css-houdini.org/worklets/#worklet-section + // TODO(nhiroki): Make (Paint)WorkletGlobalScopeProxy GC-managed object to + // avoid that GC graphs are disjointed (https://crbug.com/719775). + HashSet<std::unique_ptr<WorkletGlobalScopeProxy>> proxies_; }; } // namespace blink
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/ApplicationPanelSidebar.js b/third_party/WebKit/Source/devtools/front_end/resources/ApplicationPanelSidebar.js index 6b2d25e..6f7fdec 100644 --- a/third_party/WebKit/Source/devtools/front_end/resources/ApplicationPanelSidebar.js +++ b/third_party/WebKit/Source/devtools/front_end/resources/ApplicationPanelSidebar.js
@@ -1299,14 +1299,9 @@ contextMenu.show(); } - _clearObjectStore() { - /** - * @this {Resources.IDBObjectStoreTreeElement} - */ - function callback() { - this.update(this._objectStore); - } - this._model.clearObjectStore(this._databaseId, this._objectStore.name, callback.bind(this)); + async _clearObjectStore() { + await this._model.clearObjectStore(this._databaseId, this._objectStore.name); + this.update(this._objectStore); } /**
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/IndexedDBModel.js b/third_party/WebKit/Source/devtools/front_end/resources/IndexedDBModel.js index 1418001..9b495578 100644 --- a/third_party/WebKit/Source/devtools/front_end/resources/IndexedDBModel.js +++ b/third_party/WebKit/Source/devtools/front_end/resources/IndexedDBModel.js
@@ -168,14 +168,11 @@ /** * @param {!Resources.IndexedDBModel.DatabaseId} databaseId */ - deleteDatabase(databaseId) { + async deleteDatabase(databaseId) { if (!this._enabled) return; - this._agent.deleteDatabase(databaseId.securityOrigin, databaseId.name, error => { - if (error) - console.error('Unable to delete ' + databaseId.name, error); - this._loadDatabaseNames(databaseId.securityOrigin); - }); + await this._agent.deleteDatabase(databaseId.securityOrigin, databaseId.name); + this._loadDatabaseNames(databaseId.securityOrigin); } refreshDatabaseNames() { @@ -193,10 +190,10 @@ /** * @param {!Resources.IndexedDBModel.DatabaseId} databaseId * @param {string} objectStoreName - * @param {function()} callback + * @return {!Promise} */ - clearObjectStore(databaseId, objectStoreName, callback) { - this._agent.clearObjectStore(databaseId.securityOrigin, databaseId.name, objectStoreName, callback); + clearObjectStore(databaseId, objectStoreName) { + return this._agent.clearObjectStore(databaseId.securityOrigin, databaseId.name, objectStoreName); } /** @@ -289,65 +286,44 @@ /** * @param {string} securityOrigin */ - _loadDatabaseNames(securityOrigin) { - /** - * @param {?Protocol.Error} error - * @param {!Array.<string>} databaseNames - * @this {Resources.IndexedDBModel} - */ - function callback(error, databaseNames) { - if (error) { - console.error('IndexedDBAgent error: ' + error); - return; - } - - if (!this._databaseNamesBySecurityOrigin[securityOrigin]) - return; - this._updateOriginDatabaseNames(securityOrigin, databaseNames); - } - - this._agent.requestDatabaseNames(securityOrigin, callback.bind(this)); + async _loadDatabaseNames(securityOrigin) { + var databaseNames = await this._agent.requestDatabaseNames(securityOrigin); + if (!databaseNames) + return; + if (!this._databaseNamesBySecurityOrigin[securityOrigin]) + return; + this._updateOriginDatabaseNames(securityOrigin, databaseNames); } /** * @param {!Resources.IndexedDBModel.DatabaseId} databaseId */ - _loadDatabase(databaseId) { - /** - * @param {?Protocol.Error} error - * @param {!Protocol.IndexedDB.DatabaseWithObjectStores} databaseWithObjectStores - * @this {Resources.IndexedDBModel} - */ - function callback(error, databaseWithObjectStores) { - if (error) { - console.error('IndexedDBAgent error: ' + error); - return; - } + async _loadDatabase(databaseId) { + var databaseWithObjectStores = await this._agent.requestDatabase(databaseId.securityOrigin, databaseId.name); - if (!this._databaseNamesBySecurityOrigin[databaseId.securityOrigin]) - return; - var databaseModel = new Resources.IndexedDBModel.Database(databaseId, databaseWithObjectStores.version); - this._databases.set(databaseId, databaseModel); - for (var i = 0; i < databaseWithObjectStores.objectStores.length; ++i) { - var objectStore = databaseWithObjectStores.objectStores[i]; - var objectStoreIDBKeyPath = Resources.IndexedDBModel.idbKeyPathFromKeyPath(objectStore.keyPath); - var objectStoreModel = new Resources.IndexedDBModel.ObjectStore( - objectStore.name, objectStoreIDBKeyPath, objectStore.autoIncrement); - for (var j = 0; j < objectStore.indexes.length; ++j) { - var index = objectStore.indexes[j]; - var indexIDBKeyPath = Resources.IndexedDBModel.idbKeyPathFromKeyPath(index.keyPath); - var indexModel = - new Resources.IndexedDBModel.Index(index.name, indexIDBKeyPath, index.unique, index.multiEntry); - objectStoreModel.indexes[indexModel.name] = indexModel; - } - databaseModel.objectStores[objectStoreModel.name] = objectStoreModel; - } + if (!databaseWithObjectStores) + return; + if (!this._databaseNamesBySecurityOrigin[databaseId.securityOrigin]) + return; - this.dispatchEventToListeners( - Resources.IndexedDBModel.Events.DatabaseLoaded, {model: this, database: databaseModel}); + var databaseModel = new Resources.IndexedDBModel.Database(databaseId, databaseWithObjectStores.version); + this._databases.set(databaseId, databaseModel); + for (var objectStore of databaseWithObjectStores.objectStores) { + var objectStoreIDBKeyPath = Resources.IndexedDBModel.idbKeyPathFromKeyPath(objectStore.keyPath); + var objectStoreModel = + new Resources.IndexedDBModel.ObjectStore(objectStore.name, objectStoreIDBKeyPath, objectStore.autoIncrement); + for (var j = 0; j < objectStore.indexes.length; ++j) { + var index = objectStore.indexes[j]; + var indexIDBKeyPath = Resources.IndexedDBModel.idbKeyPathFromKeyPath(index.keyPath); + var indexModel = + new Resources.IndexedDBModel.Index(index.name, indexIDBKeyPath, index.unique, index.multiEntry); + objectStoreModel.indexes[indexModel.name] = indexModel; + } + databaseModel.objectStores[objectStoreModel.name] = objectStoreModel; } - this._agent.requestDatabase(databaseId.securityOrigin, databaseId.name, callback.bind(this)); + this.dispatchEventToListeners( + Resources.IndexedDBModel.Events.DatabaseLoaded, {model: this, database: databaseModel}); } /** @@ -386,36 +362,36 @@ * @param {number} pageSize * @param {function(!Array.<!Resources.IndexedDBModel.Entry>, boolean)} callback */ - _requestData(databaseId, databaseName, objectStoreName, indexName, idbKeyRange, skipCount, pageSize, callback) { - /** - * @param {?Protocol.Error} error - * @param {!Array.<!Protocol.IndexedDB.DataEntry>} dataEntries - * @param {boolean} hasMore - * @this {Resources.IndexedDBModel} - */ - function innerCallback(error, dataEntries, hasMore) { - if (error) { - console.error('IndexedDBAgent error: ' + error); - return; - } + async _requestData(databaseId, databaseName, objectStoreName, indexName, idbKeyRange, skipCount, pageSize, callback) { + var keyRange = Resources.IndexedDBModel.keyRangeFromIDBKeyRange(idbKeyRange) || undefined; - var runtimeModel = this.target().model(SDK.RuntimeModel); - if (!runtimeModel || !this._databaseNamesBySecurityOrigin[databaseId.securityOrigin]) - return; - var entries = []; - for (var i = 0; i < dataEntries.length; ++i) { - var key = runtimeModel.createRemoteObject(dataEntries[i].key); - var primaryKey = runtimeModel.createRemoteObject(dataEntries[i].primaryKey); - var value = runtimeModel.createRemoteObject(dataEntries[i].value); - entries.push(new Resources.IndexedDBModel.Entry(key, primaryKey, value)); - } - callback(entries, hasMore); + var response = await this._agent.invoke_requestData({ + securityOrigin: databaseId.securityOrigin, + databaseName, + objectStoreName, + indexName, + skipCount, + pageSize, + keyRange + }); + + if (response[Protocol.Error]) { + console.error('IndexedDBAgent error: ' + response[Protocol.Error]); + return; } - var keyRange = Resources.IndexedDBModel.keyRangeFromIDBKeyRange(idbKeyRange); - this._agent.requestData( - databaseId.securityOrigin, databaseName, objectStoreName, indexName, skipCount, pageSize, - keyRange ? keyRange : undefined, innerCallback.bind(this)); + var runtimeModel = this.target().model(SDK.RuntimeModel); + if (!runtimeModel || !this._databaseNamesBySecurityOrigin[databaseId.securityOrigin]) + return; + var dataEntries = response.objectStoreDataEntries; + var entries = []; + for (var dataEntry of dataEntries) { + var key = runtimeModel.createRemoteObject(dataEntry.key); + var primaryKey = runtimeModel.createRemoteObject(dataEntry.primaryKey); + var value = runtimeModel.createRemoteObject(dataEntry.value); + entries.push(new Resources.IndexedDBModel.Entry(key, primaryKey, value)); + } + callback(entries, response.hasMore); } }; @@ -434,7 +410,6 @@ ArrayType: 'array' }; - /** @enum {symbol} */ Resources.IndexedDBModel.Events = { DatabaseAdded: Symbol('DatabaseAdded'),
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/IndexedDBViews.js b/third_party/WebKit/Source/devtools/front_end/resources/IndexedDBViews.js index a421227..efeface 100644 --- a/third_party/WebKit/Source/devtools/front_end/resources/IndexedDBViews.js +++ b/third_party/WebKit/Source/devtools/front_end/resources/IndexedDBViews.js
@@ -331,16 +331,11 @@ /** * @param {!Common.Event} event */ - _clearButtonClicked(event) { - /** - * @this {Resources.IDBDataView} - */ - function cleared() { - this._clearButton.setEnabled(true); - this._updateData(true); - } + async _clearButtonClicked(event) { this._clearButton.setEnabled(false); - this._model.clearObjectStore(this._databaseId, this._objectStore.name, cleared.bind(this)); + await this._model.clearObjectStore(this._databaseId, this._objectStore.name); + this._clearButton.setEnabled(true); + this._updateData(true); } /**
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChartView.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChartView.js index 47a5fde..ddeccd4 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChartView.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChartView.js
@@ -157,7 +157,7 @@ this._nextExtensionIndex = 0; this._appendExtensionData(); - this._updateSearchHighlight(false, true); + this._updateSearchResults(false, false); this._refresh(); } @@ -264,18 +264,13 @@ this._countersView.setWindowTimes(startTime, endTime); this._windowStartTime = startTime; this._windowEndTime = endTime; + this._updateSearchResults(false, false); } /** - * @param {?SDK.TracingModel.Event} event - * @param {string=} regex - * @param {boolean=} select + * @param {!SDK.TracingModel.Event} event */ - _highlightSearchResult(event, regex, select) { - if (!event) { - this._delegate.select(null); - return; - } + _highlightSearchResult(event) { var timelineSelection = this._mainDataProvider.selectionForEvent(event); if (timelineSelection) this._delegate.select(timelineSelection); @@ -336,7 +331,7 @@ if (!this._searchResults || !this._searchResults.length) return; var index = this._selectedSearchResult ? this._searchResults.indexOf(this._selectedSearchResult) : -1; - this._jumpToSearchResult(index + 1); + this._selectSearchResult(mod(index + 1, this._searchResults.length)); } /** @@ -346,7 +341,7 @@ if (!this._searchResults || !this._searchResults.length) return; var index = this._selectedSearchResult ? this._searchResults.indexOf(this._selectedSearchResult) : 0; - this._jumpToSearchResult(index - 1); + this._selectSearchResult(mod(index - 1, this._searchResults.length)); } /** @@ -368,36 +363,10 @@ /** * @param {number} index */ - _jumpToSearchResult(index) { - this._selectSearchResult(mod(index, this._searchResults.length)); - this._highlightSearchResult(this._selectedSearchResult, this._searchRegex, true); - } - - /** - * @param {number} index - */ _selectSearchResult(index) { this._selectedSearchResult = this._searchResults[index]; this._searchableView.updateCurrentMatchIndex(index); - } - - _clearHighlight() { - this._highlightSearchResult(null); - } - - /** - * @param {boolean} revealRecord - * @param {boolean} shouldJump - * @param {boolean=} jumpBackwards - */ - _updateSearchHighlight(revealRecord, shouldJump, jumpBackwards) { - if (!this._searchRegex) { - this._clearHighlight(); - return; - } - if (!this._searchResults) - this._updateSearchResults(shouldJump, jumpBackwards); - this._highlightSearchResult(this._selectedSearchResult, this._searchRegex, revealRecord); + this._highlightSearchResult(this._selectedSearchResult); } /** @@ -405,6 +374,9 @@ * @param {boolean=} jumpBackwards */ _updateSearchResults(shouldJump, jumpBackwards) { + var oldSelectedSearchResult = this._selectedSearchResult; + delete this._selectedSearchResult; + this._searchResults = []; if (!this._searchRegex) return; @@ -421,26 +393,22 @@ matches.push(event); } - var matchesCount = matches.length; - if (matchesCount) { - this._searchResults = matches; - this._searchableView.updateSearchMatchesCount(matchesCount); - - var selectedIndex = matches.indexOf(this._selectedSearchResult); - if (shouldJump && selectedIndex === -1) - selectedIndex = jumpBackwards ? this._searchResults.length - 1 : 0; - this._selectSearchResult(selectedIndex); - } else { - this._searchableView.updateSearchMatchesCount(0); - delete this._selectedSearchResult; - } + this._searchableView.updateSearchMatchesCount(matches.length); + this._searchResults = matches; + if (!shouldJump || !matches.length) + return; + var selectedIndex = matches.indexOf(oldSelectedSearchResult); + if (selectedIndex === -1) + selectedIndex = jumpBackwards ? this._searchResults.length - 1 : 0; + this._selectSearchResult(selectedIndex); } /** * @override */ searchCanceled() { - this._clearHighlight(); + if (this._selectedSearchResult) + this._delegate.select(null); delete this._searchResults; delete this._selectedSearchResult; delete this._searchRegex; @@ -454,8 +422,7 @@ */ performSearch(searchConfig, shouldJump, jumpBackwards) { this._searchRegex = searchConfig.toSearchRegex(); - delete this._searchResults; - this._updateSearchHighlight(true, shouldJump, jumpBackwards); + this._updateSearchResults(shouldJump, jumpBackwards); } };
diff --git a/third_party/WebKit/Source/devtools/scripts/build/generate_protocol_externs.py b/third_party/WebKit/Source/devtools/scripts/build/generate_protocol_externs.py index c6b4a9c..a3c865c1 100755 --- a/third_party/WebKit/Source/devtools/scripts/build/generate_protocol_externs.py +++ b/third_party/WebKit/Source/devtools/scripts/build/generate_protocol_externs.py
@@ -49,7 +49,6 @@ NON_PROMISIFIED_DOMAINS = frozenset([ "CSS", "DOMDebugger", - "IndexedDB", ])
diff --git a/third_party/WebKit/Source/modules/accessibility/AXObjectImpl.cpp b/third_party/WebKit/Source/modules/accessibility/AXObjectImpl.cpp index e7b38a2..7ff8a43 100644 --- a/third_party/WebKit/Source/modules/accessibility/AXObjectImpl.cpp +++ b/third_party/WebKit/Source/modules/accessibility/AXObjectImpl.cpp
@@ -56,7 +56,19 @@ using namespace HTMLNames; namespace { -typedef HashMap<String, AccessibilityRole, CaseFoldingHash> ARIARoleMap; + +struct AccessibilityRoleHashTraits : HashTraits<AccessibilityRole> { + static const bool kEmptyValueIsZero = true; + static AccessibilityRole EmptyValue() { + return AccessibilityRole::kUnknownRole; + } +}; + +using ARIARoleMap = HashMap<String, + AccessibilityRole, + CaseFoldingHash, + HashTraits<String>, + AccessibilityRoleHashTraits>; struct RoleEntry { const char* aria_role;
diff --git a/third_party/WebKit/Source/web/AnimationWorkletProxyClientImpl.cpp b/third_party/WebKit/Source/modules/compositorworker/AnimationWorkletProxyClientImpl.cpp similarity index 92% rename from third_party/WebKit/Source/web/AnimationWorkletProxyClientImpl.cpp rename to third_party/WebKit/Source/modules/compositorworker/AnimationWorkletProxyClientImpl.cpp index 41ae51d..b077724 100644 --- a/third_party/WebKit/Source/web/AnimationWorkletProxyClientImpl.cpp +++ b/third_party/WebKit/Source/modules/compositorworker/AnimationWorkletProxyClientImpl.cpp
@@ -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 "web/AnimationWorkletProxyClientImpl.h" +#include "modules/compositorworker/AnimationWorkletProxyClientImpl.h" #include "core/animation/CompositorMutatorImpl.h" #include "core/dom/CompositorProxy.h"
diff --git a/third_party/WebKit/Source/web/AnimationWorkletProxyClientImpl.h b/third_party/WebKit/Source/modules/compositorworker/AnimationWorkletProxyClientImpl.h similarity index 91% rename from third_party/WebKit/Source/web/AnimationWorkletProxyClientImpl.h rename to third_party/WebKit/Source/modules/compositorworker/AnimationWorkletProxyClientImpl.h index 94de72d2..2778e623 100644 --- a/third_party/WebKit/Source/web/AnimationWorkletProxyClientImpl.h +++ b/third_party/WebKit/Source/modules/compositorworker/AnimationWorkletProxyClientImpl.h
@@ -6,10 +6,11 @@ #define AnimationWorkletProxyClientImpl_h #include "core/animation/CompositorAnimator.h" +#include "core/animation/CompositorProxyClientImpl.h" #include "core/dom/AnimationWorkletProxyClient.h" +#include "modules/ModulesExport.h" #include "platform/heap/Handle.h" #include "platform/wtf/Noncopyable.h" -#include "web/CompositorProxyClientImpl.h" namespace blink { @@ -21,7 +22,7 @@ // // This is constructed on the main thread but it is used in the worklet backing // thread i.e., compositor thread. -class AnimationWorkletProxyClientImpl final +class MODULES_EXPORT AnimationWorkletProxyClientImpl final : public GarbageCollectedFinalized<AnimationWorkletProxyClientImpl>, public AnimationWorkletProxyClient, public CompositorAnimator {
diff --git a/third_party/WebKit/Source/modules/compositorworker/BUILD.gn b/third_party/WebKit/Source/modules/compositorworker/BUILD.gn index df26dd2..c6f2574 100644 --- a/third_party/WebKit/Source/modules/compositorworker/BUILD.gn +++ b/third_party/WebKit/Source/modules/compositorworker/BUILD.gn
@@ -14,6 +14,8 @@ "AnimationWorkletGlobalScope.h", "AnimationWorkletMessagingProxy.cpp", "AnimationWorkletMessagingProxy.h", + "AnimationWorkletProxyClientImpl.cpp", + "AnimationWorkletProxyClientImpl.h", "AnimationWorkletThread.cpp", "AnimationWorkletThread.h", "Animator.cpp", @@ -26,6 +28,8 @@ "CompositorWorkerGlobalScope.h", "CompositorWorkerMessagingProxy.cpp", "CompositorWorkerMessagingProxy.h", + "CompositorWorkerProxyClientImpl.cpp", + "CompositorWorkerProxyClientImpl.h", "CompositorWorkerThread.cpp", "CompositorWorkerThread.h", "WindowAnimationWorklet.cpp",
diff --git a/third_party/WebKit/Source/web/CompositorWorkerProxyClientImpl.cpp b/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerProxyClientImpl.cpp similarity index 98% rename from third_party/WebKit/Source/web/CompositorWorkerProxyClientImpl.cpp rename to third_party/WebKit/Source/modules/compositorworker/CompositorWorkerProxyClientImpl.cpp index 9d12da3..2e873ca 100644 --- a/third_party/WebKit/Source/web/CompositorWorkerProxyClientImpl.cpp +++ b/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerProxyClientImpl.cpp
@@ -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 "web/CompositorWorkerProxyClientImpl.h" +#include "modules/compositorworker/CompositorWorkerProxyClientImpl.h" #include "core/animation/CompositorMutatorImpl.h" #include "core/dom/CompositorProxy.h"
diff --git a/third_party/WebKit/Source/web/CompositorWorkerProxyClientImpl.h b/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerProxyClientImpl.h similarity index 93% rename from third_party/WebKit/Source/web/CompositorWorkerProxyClientImpl.h rename to third_party/WebKit/Source/modules/compositorworker/CompositorWorkerProxyClientImpl.h index 10cce10e..07ff568c 100644 --- a/third_party/WebKit/Source/web/CompositorWorkerProxyClientImpl.h +++ b/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerProxyClientImpl.h
@@ -6,10 +6,11 @@ #define CompositorWorkerProxyClientImpl_h #include "core/animation/CompositorAnimator.h" +#include "core/animation/CompositorProxyClientImpl.h" #include "core/dom/CompositorWorkerProxyClient.h" +#include "modules/ModulesExport.h" #include "platform/heap/Handle.h" #include "platform/wtf/Noncopyable.h" -#include "web/CompositorProxyClientImpl.h" namespace blink { @@ -25,7 +26,7 @@ // // Owned by the main thread. // Should be accessed only on the compositor thread. -class CompositorWorkerProxyClientImpl final +class MODULES_EXPORT CompositorWorkerProxyClientImpl final : public GarbageCollectedFinalized<CompositorWorkerProxyClientImpl>, public CompositorWorkerProxyClient, public CompositorAnimator {
diff --git a/third_party/WebKit/Source/modules/csspaint/PaintWorklet.cpp b/third_party/WebKit/Source/modules/csspaint/PaintWorklet.cpp index 063effb..bef58fc 100644 --- a/third_party/WebKit/Source/modules/csspaint/PaintWorklet.cpp +++ b/third_party/WebKit/Source/modules/csspaint/PaintWorklet.cpp
@@ -17,7 +17,7 @@ } PaintWorklet::PaintWorklet(LocalFrame* frame) - : MainThreadWorklet(frame), + : Worklet(frame), pending_generator_registry_(new PaintWorkletPendingGeneratorRegistry) {} PaintWorklet::~PaintWorklet() = default; @@ -38,7 +38,7 @@ DEFINE_TRACE(PaintWorklet) { visitor->Trace(pending_generator_registry_); - MainThreadWorklet::Trace(visitor); + Worklet::Trace(visitor); } bool PaintWorklet::NeedsToCreateGlobalScope() {
diff --git a/third_party/WebKit/Source/modules/csspaint/PaintWorklet.h b/third_party/WebKit/Source/modules/csspaint/PaintWorklet.h index 35848ae4..ec7cf2f 100644 --- a/third_party/WebKit/Source/modules/csspaint/PaintWorklet.h +++ b/third_party/WebKit/Source/modules/csspaint/PaintWorklet.h
@@ -5,7 +5,7 @@ #ifndef PaintWorklet_h #define PaintWorklet_h -#include "core/workers/MainThreadWorklet.h" +#include "core/workers/Worklet.h" #include "modules/ModulesExport.h" #include "modules/csspaint/PaintWorkletGlobalScopeProxy.h" #include "modules/csspaint/PaintWorkletPendingGeneratorRegistry.h" @@ -18,7 +18,7 @@ // Manages a paint worklet: // https://drafts.css-houdini.org/css-paint-api/#dom-css-paintworklet -class MODULES_EXPORT PaintWorklet final : public MainThreadWorklet { +class MODULES_EXPORT PaintWorklet final : public Worklet { WTF_MAKE_NONCOPYABLE(PaintWorklet); public: @@ -35,7 +35,7 @@ explicit PaintWorklet(LocalFrame*); - // Implements MainThreadWorklet. + // Implements Worklet. bool NeedsToCreateGlobalScope() final; std::unique_ptr<WorkletGlobalScopeProxy> CreateGlobalScope() final;
diff --git a/third_party/WebKit/Source/modules/mediasource/SourceBuffer.cpp b/third_party/WebKit/Source/modules/mediasource/SourceBuffer.cpp index a52fdab..e7871108 100644 --- a/third_party/WebKit/Source/modules/mediasource/SourceBuffer.cpp +++ b/third_party/WebKit/Source/modules/mediasource/SourceBuffer.cpp
@@ -353,21 +353,25 @@ void SourceBuffer::appendBuffer(DOMArrayBuffer* data, ExceptionState& exception_state) { - BLINK_SBLOG << __func__ << " this=" << this << " size=" << data->ByteLength(); + double media_time = GetMediaTime(); + BLINK_SBLOG << __func__ << " this=" << this << " media_time=" << media_time + << " size=" << data->ByteLength(); // Section 3.2 appendBuffer() // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#widl-SourceBuffer-appendBuffer-void-ArrayBufferView-data - AppendBufferInternal(static_cast<const unsigned char*>(data->Data()), + AppendBufferInternal(media_time, + static_cast<const unsigned char*>(data->Data()), data->ByteLength(), exception_state); } void SourceBuffer::appendBuffer(NotShared<DOMArrayBufferView> data, ExceptionState& exception_state) { - BLINK_SBLOG << __func__ << " this=" << this + double media_time = GetMediaTime(); + BLINK_SBLOG << __func__ << " this=" << this << " media_time=" << media_time << " size=" << data.View()->byteLength(); // Section 3.2 appendBuffer() // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#widl-SourceBuffer-appendBuffer-void-ArrayBufferView-data AppendBufferInternal( - static_cast<const unsigned char*>(data.View()->BaseAddress()), + media_time, static_cast<const unsigned char*>(data.View()->BaseAddress()), data.View()->byteLength(), exception_state); } @@ -682,6 +686,13 @@ // 7-8. TODO(servolk): Remove text tracks once SourceBuffer has text tracks. } +double SourceBuffer::GetMediaTime() { + double media_time = std::numeric_limits<float>::quiet_NaN(); + if (source_ && source_->MediaElement()) + media_time = source_->MediaElement()->currentTime(); + return media_time; +} + template <class T> T* FindExistingTrackById(const TrackListBase<T>& track_list, const String& id) { // According to MSE specification @@ -1070,7 +1081,8 @@ async_event_queue_->EnqueueEvent(event); } -bool SourceBuffer::PrepareAppend(size_t new_data_size, +bool SourceBuffer::PrepareAppend(double media_time, + size_t new_data_size, ExceptionState& exception_state) { TRACE_EVENT_ASYNC_BEGIN0("media", "SourceBuffer::prepareAppend", this); // http://w3c.github.io/media-source/#sourcebuffer-prepare-append @@ -1106,7 +1118,7 @@ source_->OpenIfInEndedState(); // 5. Run the coded frame eviction algorithm. - if (!EvictCodedFrames(new_data_size)) { + if (!EvictCodedFrames(media_time, new_data_size)) { // 6. If the buffer full flag equals true, then throw a QUOTA_EXCEEDED_ERR // exception and abort these steps. BLINK_SBLOG << __func__ << " this=" << this @@ -1123,7 +1135,7 @@ return true; } -bool SourceBuffer::EvictCodedFrames(size_t new_data_size) { +bool SourceBuffer::EvictCodedFrames(double media_time, size_t new_data_size) { DCHECK(source_); DCHECK(source_->MediaElement()); @@ -1133,19 +1145,18 @@ return true; } - double current_time = source_->MediaElement()->currentTime(); - bool result = - web_source_buffer_->EvictCodedFrames(current_time, new_data_size); + bool result = web_source_buffer_->EvictCodedFrames(media_time, new_data_size); if (!result) { BLINK_SBLOG << __func__ << " this=" << this << " failed. newDataSize=" << new_data_size - << " currentTime=" << current_time << " buffered=" + << " media_time=" << media_time << " buffered=" << WebTimeRangesToString(web_source_buffer_->Buffered()); } return result; } -void SourceBuffer::AppendBufferInternal(const unsigned char* data, +void SourceBuffer::AppendBufferInternal(double media_time, + const unsigned char* data, unsigned size, ExceptionState& exception_state) { TRACE_EVENT_ASYNC_BEGIN1("media", "SourceBuffer::appendBuffer", this, "size", @@ -1154,7 +1165,7 @@ // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#widl-SourceBuffer-appendBuffer-void-ArrayBufferView-data // 1. Run the prepare append algorithm. - if (!PrepareAppend(size, exception_state)) { + if (!PrepareAppend(media_time, size, exception_state)) { TRACE_EVENT_ASYNC_END0("media", "SourceBuffer::appendBuffer", this); return; } @@ -1246,7 +1257,9 @@ } TRACE_EVENT_ASYNC_END0("media", "SourceBuffer::appendBuffer", this); - BLINK_SBLOG << __func__ << " done. this=" << this << " buffered=" + double media_time = GetMediaTime(); + BLINK_SBLOG << __func__ << " done. this=" << this + << " media_time=" << media_time << " buffered=" << WebTimeRangesToString(web_source_buffer_->Buffered()); }
diff --git a/third_party/WebKit/Source/modules/mediasource/SourceBuffer.h b/third_party/WebKit/Source/modules/mediasource/SourceBuffer.h index 7045ad03..a5f1726 100644 --- a/third_party/WebKit/Source/modules/mediasource/SourceBuffer.h +++ b/third_party/WebKit/Source/modules/mediasource/SourceBuffer.h
@@ -126,9 +126,12 @@ bool IsRemoved() const; void ScheduleEvent(const AtomicString& event_name); - bool PrepareAppend(size_t new_data_size, ExceptionState&); - bool EvictCodedFrames(size_t new_data_size); - void AppendBufferInternal(const unsigned char*, unsigned, ExceptionState&); + bool PrepareAppend(double media_time, size_t new_data_size, ExceptionState&); + bool EvictCodedFrames(double media_time, size_t new_data_size); + void AppendBufferInternal(double media_time, + const unsigned char*, + unsigned, + ExceptionState&); void AppendBufferAsyncPart(); void AppendError(); @@ -139,6 +142,10 @@ void RemoveMediaTracks(); + // Returns MediaElement playback position (i.e. MediaElement.currentTime() ) + // in seconds, or NaN if media element is not available. + double GetMediaTime(); + const TrackDefault* GetTrackDefault( const AtomicString& track_type, const AtomicString& byte_stream_track_id) const;
diff --git a/third_party/WebKit/Source/platform/exported/WebActiveGestureAnimation.cpp b/third_party/WebKit/Source/platform/exported/WebActiveGestureAnimation.cpp index a1490260..aa3070dc 100644 --- a/third_party/WebKit/Source/platform/exported/WebActiveGestureAnimation.cpp +++ b/third_party/WebKit/Source/platform/exported/WebActiveGestureAnimation.cpp
@@ -33,20 +33,12 @@ namespace blink { std::unique_ptr<WebActiveGestureAnimation> -WebActiveGestureAnimation::CreateAtAnimationStart( - std::unique_ptr<WebGestureCurve> curve, - WebGestureCurveTarget* target) { - return WTF::WrapUnique( - new WebActiveGestureAnimation(std::move(curve), target, 0, true)); -} - -std::unique_ptr<WebActiveGestureAnimation> WebActiveGestureAnimation::CreateWithTimeOffset( std::unique_ptr<WebGestureCurve> curve, WebGestureCurveTarget* target, double start_time) { - return WTF::WrapUnique(new WebActiveGestureAnimation(std::move(curve), target, - start_time, false)); + return WTF::WrapUnique( + new WebActiveGestureAnimation(std::move(curve), target, start_time)); } WebActiveGestureAnimation::~WebActiveGestureAnimation() {} @@ -54,18 +46,10 @@ WebActiveGestureAnimation::WebActiveGestureAnimation( std::unique_ptr<WebGestureCurve> curve, WebGestureCurveTarget* target, - double start_time, - bool waiting_for_first_tick) - : start_time_(start_time), - waiting_for_first_tick_(waiting_for_first_tick), - curve_(std::move(curve)), - target_(target) {} + double start_time) + : start_time_(start_time), curve_(std::move(curve)), target_(target) {} bool WebActiveGestureAnimation::Animate(double time) { - if (waiting_for_first_tick_) { - start_time_ = time; - waiting_for_first_tick_ = false; - } // All WebGestureCurves assume zero-based time, so we subtract // the animation start time before passing to the curve. return curve_->Apply(time - start_time_, target_);
diff --git a/third_party/WebKit/Source/platform/exported/WebActiveGestureAnimation.h b/third_party/WebKit/Source/platform/exported/WebActiveGestureAnimation.h index 45b29d4f..e1adc588 100644 --- a/third_party/WebKit/Source/platform/exported/WebActiveGestureAnimation.h +++ b/third_party/WebKit/Source/platform/exported/WebActiveGestureAnimation.h
@@ -46,9 +46,6 @@ WTF_MAKE_NONCOPYABLE(WebActiveGestureAnimation); public: - static std::unique_ptr<WebActiveGestureAnimation> CreateAtAnimationStart( - std::unique_ptr<WebGestureCurve>, - WebGestureCurveTarget*); static std::unique_ptr<WebActiveGestureAnimation> CreateWithTimeOffset( std::unique_ptr<WebGestureCurve>, WebGestureCurveTarget*, @@ -61,11 +58,9 @@ // Assumes a valid WebGestureCurveTarget that outlives the animation. WebActiveGestureAnimation(std::unique_ptr<WebGestureCurve>, WebGestureCurveTarget*, - double start_time, - bool waiting_for_first_tick); + double start_time); double start_time_; - bool waiting_for_first_tick_; std::unique_ptr<WebGestureCurve> curve_; WebGestureCurveTarget* target_; };
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp index b95765c..0e9ce5c 100644 --- a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp +++ b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp
@@ -257,6 +257,7 @@ // Now rect is in the space of the containing transform node of pending_layer, // so need to subtract off the layer offset. rect.Rect().Move(-layer_offset.x(), -layer_offset.y()); + rect.Rect().Inflate(paint_chunk.outset_for_raster_effects); return EnclosingIntRect(rect.Rect()); } @@ -330,9 +331,6 @@ auto info = raster_tracking->invalidations[i]; info.rect = rect; cc_tracking.invalidations.push_back(info); - // TODO(crbug.com/496260): Some antialiasing effects overflow the paint - // invalidation rect. - rect.Inflate(1); cc_tracking.invalidation_region_since_last_paint.Unite(rect); } }
diff --git a/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.cpp b/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.cpp index 5686ef19..8f6b369 100644 --- a/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.cpp +++ b/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.cpp
@@ -10,6 +10,7 @@ virtual ~SameSizeAsDisplayItem() {} // Allocate vtable pointer. void* pointer; LayoutRect rect; + LayoutUnit outset; int i; #ifndef NDEBUG WTF::String debug_string_; @@ -247,7 +248,12 @@ } string_builder.Append("\", visualRect: \""); string_builder.Append(VisualRect().ToString()); - string_builder.Append("\", type: \""); + string_builder.Append("\", "); + if (OutsetForRasterEffects()) { + string_builder.Append( + String::Format("outset: %f, ", OutsetForRasterEffects().ToFloat())); + } + string_builder.Append("type: \""); string_builder.Append(TypeAsDebugString(GetType())); string_builder.Append('"'); if (skipped_cache_)
diff --git a/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.h b/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.h index a3608a3..0b0c013 100644 --- a/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.h +++ b/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.h
@@ -200,6 +200,7 @@ DisplayItem(const DisplayItemClient& client, Type type, size_t derived_size) : client_(&client), visual_rect_(client.VisualRect()), + outset_for_raster_effects_(client.VisualRectOutsetForRasterEffects()), type_(type), derived_size_(derived_size), skipped_cache_(false) @@ -239,6 +240,9 @@ // not invalidated. Otherwise it saves the previous visual rect of the client. // See DisplayItemClient::VisualRect() about its coordinate space. const LayoutRect& VisualRect() const { return visual_rect_; } + LayoutUnit OutsetForRasterEffects() const { + return outset_for_raster_effects_; + } // Visual rect can change without needing invalidation of the client, e.g. // when ancestor clip changes. This is called from PaintController:: @@ -376,6 +380,7 @@ const DisplayItemClient* client_; LayoutRect visual_rect_; + LayoutUnit outset_for_raster_effects_; static_assert(kTypeLast < (1 << 16), "DisplayItem::Type should fit in 16 bits");
diff --git a/third_party/WebKit/Source/platform/graphics/paint/DisplayItemClient.h b/third_party/WebKit/Source/platform/graphics/paint/DisplayItemClient.h index 4b10024..a743328 100644 --- a/third_party/WebKit/Source/platform/graphics/paint/DisplayItemClient.h +++ b/third_party/WebKit/Source/platform/graphics/paint/DisplayItemClient.h
@@ -51,11 +51,19 @@ virtual String DebugName() const = 0; - // The visual rect of this DisplayItemClient, in the object space of the - // object that owns the GraphicsLayer, i.e. offset by + // The visual rect of this DisplayItemClient. For SPv1, it's in the object + // space of the object that owns the GraphicsLayer, i.e. offset by // GraphicsLayer::OffsetFromLayoutObjectWithSubpixelAccumulation(). + // For SPv2, it's in the space of the parent transform node. virtual LayoutRect VisualRect() const = 0; + // The outset will be used to inflate visual rect after the visual rect is + // mapped into the space of the composited layer, for any special raster + // effects that might expand the rastered pixel area. + virtual LayoutUnit VisualRectOutsetForRasterEffects() const { + return LayoutUnit(); + } + // This is declared here instead of in LayoutObject for verifying the // condition in DrawingRecorder. // Returns true if the object itself will not generate any effective painted
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintChunk.h b/third_party/WebKit/Source/platform/graphics/paint/PaintChunk.h index 74c0d28..41e1be6 100644 --- a/third_party/WebKit/Source/platform/graphics/paint/PaintChunk.h +++ b/third_party/WebKit/Source/platform/graphics/paint/PaintChunk.h
@@ -23,7 +23,11 @@ // This is a Slimming Paint v2 class. struct PaintChunk { DISALLOW_NEW_EXCEPT_PLACEMENT_NEW(); - PaintChunk() : begin_index(0), end_index(0), known_to_be_opaque(false) {} + PaintChunk() + : begin_index(0), + end_index(0), + outset_for_raster_effects(0), + known_to_be_opaque(false) {} PaintChunk(size_t begin, size_t end, const DisplayItem::Id* chunk_id, @@ -31,6 +35,7 @@ : begin_index(begin), end_index(end), properties(props), + outset_for_raster_effects(0), known_to_be_opaque(false) { if (chunk_id) id.emplace(*chunk_id); @@ -83,6 +88,11 @@ // the containing transform node. FloatRect bounds; + // Some raster effects can exceed |bounds| in the rasterization space. This + // is the maximum DisplayItemClient::VisualRectOutsetForRasterEffects() of + // all clients of items in this chunk. + float outset_for_raster_effects; + // True if the bounds are filled entirely with opaque contents. bool known_to_be_opaque;
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp b/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp index 00159eab..085a75c 100644 --- a/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp +++ b/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp
@@ -271,6 +271,10 @@ new_paint_chunks_.PaintChunkAt(last_chunk_index)); } } + + new_paint_chunks_.LastChunk().outset_for_raster_effects = + std::max(new_paint_chunks_.LastChunk().outset_for_raster_effects, + display_item.OutsetForRasterEffects().ToFloat()); } #if DCHECK_IS_ON()
diff --git a/third_party/WebKit/Source/platform/weborigin/SchemeRegistry.cpp b/third_party/WebKit/Source/platform/weborigin/SchemeRegistry.cpp index d8e60eea1..6cf1cc3 100644 --- a/third_party/WebKit/Source/platform/weborigin/SchemeRegistry.cpp +++ b/third_party/WebKit/Source/platform/weborigin/SchemeRegistry.cpp
@@ -36,6 +36,13 @@ namespace { +struct PolicyAreasHashTraits : HashTraits<SchemeRegistry::PolicyAreas> { + static const bool kEmptyValueIsZero = true; + static SchemeRegistry::PolicyAreas EmptyValue() { + return SchemeRegistry::kPolicyAreaNone; + } +}; + class URLSchemesRegistry final { public: URLSchemesRegistry() @@ -73,7 +80,7 @@ URLSchemesSet service_worker_schemes; URLSchemesSet fetch_api_schemes; URLSchemesSet first_party_when_top_level_schemes; - URLSchemesMap<SchemeRegistry::PolicyAreas> + URLSchemesMap<SchemeRegistry::PolicyAreas, PolicyAreasHashTraits> content_security_policy_bypassing_schemes; URLSchemesSet secure_context_bypassing_schemes; URLSchemesSet allowed_in_referrer_schemes;
diff --git a/third_party/WebKit/Source/platform/weborigin/SchemeRegistry.h b/third_party/WebKit/Source/platform/weborigin/SchemeRegistry.h index e58eea3..7a62412 100644 --- a/third_party/WebKit/Source/platform/weborigin/SchemeRegistry.h +++ b/third_party/WebKit/Source/platform/weborigin/SchemeRegistry.h
@@ -38,8 +38,12 @@ using URLSchemesSet = HashSet<String>; -template <typename T> -using URLSchemesMap = HashMap<String, T>; +template <typename Mapped, typename MappedTraits> +using URLSchemesMap = HashMap<String, + Mapped, + DefaultHash<String>::Hash, + HashTraits<String>, + MappedTraits>; class PLATFORM_EXPORT SchemeRegistry { STATIC_ONLY(SchemeRegistry);
diff --git a/third_party/WebKit/Source/platform/wtf/HashFunctions.h b/third_party/WebKit/Source/platform/wtf/HashFunctions.h index 37f1956..2d0decb 100644 --- a/third_party/WebKit/Source/platform/wtf/HashFunctions.h +++ b/third_party/WebKit/Source/platform/wtf/HashFunctions.h
@@ -214,7 +214,9 @@ // Canonical implementation of DefaultHash. template <typename T> -struct DefaultHash : DefaultHashImpl<T, std::is_integral<T>::value> {}; +struct DefaultHash + : DefaultHashImpl<T, std::is_integral<T>::value || std::is_enum<T>::value> { +}; // Specializations of DefaultHash follow. template <>
diff --git a/third_party/WebKit/Source/platform/wtf/HashSetTest.cpp b/third_party/WebKit/Source/platform/wtf/HashSetTest.cpp index e123ff0..e596af9 100644 --- a/third_party/WebKit/Source/platform/wtf/HashSetTest.cpp +++ b/third_party/WebKit/Source/platform/wtf/HashSetTest.cpp
@@ -502,6 +502,21 @@ EXPECT_TRUE(IsOneTwoThree(ReturnOneTwoThree())); } +enum TestEnum { + kItem0, +}; + +enum class TestEnumClass : unsigned char { + kItem0, +}; + +TEST(HashSetTest, HasTraitsForEnum) { + // Ensure that enum hash keys are buildable. + HashSet<TestEnum> set1; + HashSet<TestEnumClass> set2; + HashSet<std::pair<TestEnum, TestEnumClass>> set3; +} + } // anonymous namespace } // namespace WTF
diff --git a/third_party/WebKit/Source/platform/wtf/HashTraits.h b/third_party/WebKit/Source/platform/wtf/HashTraits.h index 1e6122a..0623ed7 100644 --- a/third_party/WebKit/Source/platform/wtf/HashTraits.h +++ b/third_party/WebKit/Source/platform/wtf/HashTraits.h
@@ -37,6 +37,8 @@ template <bool isInteger, typename T> struct GenericHashTraitsBase; +template <bool is_enum, typename T> +struct EnumOrGenericHashTraits; template <typename T> struct HashTraits; @@ -138,7 +140,22 @@ }; template <typename T> -struct HashTraits : GenericHashTraits<T> {}; +struct EnumOrGenericHashTraits<false, T> : GenericHashTraits<T> {}; + +// Default traits for an enum type. 0 is very popular, and -1 is also popular. +// So we use -128 and -127. +template <typename T> +struct EnumOrGenericHashTraits<true, T> : GenericHashTraits<T> { + static const bool kEmptyValueIsZero = false; + static T EmptyValue() { return static_cast<T>(-128); } + static void ConstructDeletedValue(T& slot, bool) { + slot = static_cast<T>(-127); + } + static bool IsDeletedValue(T value) { return value == static_cast<T>(-127); } +}; + +template <typename T> +struct HashTraits : EnumOrGenericHashTraits<std::is_enum<T>::value, T> {}; template <typename T> struct FloatHashTraits : GenericHashTraits<T> {
diff --git a/third_party/WebKit/Source/web/BUILD.gn b/third_party/WebKit/Source/web/BUILD.gn index 6b92b6a..3d10b41 100644 --- a/third_party/WebKit/Source/web/BUILD.gn +++ b/third_party/WebKit/Source/web/BUILD.gn
@@ -36,8 +36,6 @@ defines = [ "BLINK_WEB_IMPLEMENTATION=1" ] sources = [ - "AnimationWorkletProxyClientImpl.cpp", - "AnimationWorkletProxyClientImpl.h", "AssertMatchingEnums.cpp", "AudioOutputDeviceClientImpl.cpp", "AudioOutputDeviceClientImpl.h", @@ -47,10 +45,6 @@ "ColorChooserPopupUIController.h", "ColorChooserUIController.cpp", "ColorChooserUIController.h", - "CompositorProxyClientImpl.cpp", - "CompositorProxyClientImpl.h", - "CompositorWorkerProxyClientImpl.cpp", - "CompositorWorkerProxyClientImpl.h", "ContextMenuClientImpl.cpp", "ContextMenuClientImpl.h", "DedicatedWorkerMessagingProxyProviderImpl.cpp",
diff --git a/third_party/WebKit/Source/web/LocalFrameClientImpl.cpp b/third_party/WebKit/Source/web/LocalFrameClientImpl.cpp index 56b9734..78a1ecfc 100644 --- a/third_party/WebKit/Source/web/LocalFrameClientImpl.cpp +++ b/third_party/WebKit/Source/web/LocalFrameClientImpl.cpp
@@ -748,7 +748,7 @@ } PluginView* LocalFrameClientImpl::CreatePlugin( - HTMLPlugInElement* element, + HTMLPlugInElement& element, const KURL& url, const Vector<String>& param_names, const Vector<String>& param_values, @@ -776,7 +776,7 @@ if (!web_plugin->Initialize(container)) return nullptr; - if (policy != kAllowDetachedPlugin && !element->GetLayoutObject()) + if (policy != kAllowDetachedPlugin && !element.GetLayoutObject()) return nullptr; return container;
diff --git a/third_party/WebKit/Source/web/LocalFrameClientImpl.h b/third_party/WebKit/Source/web/LocalFrameClientImpl.h index 9cffed0..76554d2b 100644 --- a/third_party/WebKit/Source/web/LocalFrameClientImpl.h +++ b/third_party/WebKit/Source/web/LocalFrameClientImpl.h
@@ -149,7 +149,7 @@ const WTF::AtomicString& name, HTMLFrameOwnerElement*) override; virtual bool CanCreatePluginWithoutRenderer(const String& mime_type) const; - PluginView* CreatePlugin(HTMLPlugInElement*, + PluginView* CreatePlugin(HTMLPlugInElement&, const KURL&, const Vector<WTF::String>&, const Vector<WTF::String>&,
diff --git a/third_party/WebKit/Source/web/WebFrameWidgetImpl.cpp b/third_party/WebKit/Source/web/WebFrameWidgetImpl.cpp index f77db328..a26f281 100644 --- a/third_party/WebKit/Source/web/WebFrameWidgetImpl.cpp +++ b/third_party/WebKit/Source/web/WebFrameWidgetImpl.cpp
@@ -59,6 +59,8 @@ #include "core/page/FocusController.h" #include "core/page/Page.h" #include "core/page/PointerLockController.h" +#include "modules/compositorworker/AnimationWorkletProxyClientImpl.h" +#include "modules/compositorworker/CompositorWorkerProxyClientImpl.h" #include "platform/KeyboardCodes.h" #include "platform/WebFrameScheduler.h" #include "platform/animation/CompositorAnimationHost.h" @@ -70,8 +72,6 @@ #include "public/web/WebPlugin.h" #include "public/web/WebRange.h" #include "public/web/WebWidgetClient.h" -#include "web/AnimationWorkletProxyClientImpl.h" -#include "web/CompositorWorkerProxyClientImpl.h" #include "web/WebDevToolsAgentImpl.h" #include "web/WebPagePopupImpl.h" #include "web/WebRemoteFrameImpl.h"
diff --git a/third_party/WebKit/Source/web/WebHelperPluginImpl.cpp b/third_party/WebKit/Source/web/WebHelperPluginImpl.cpp index db365906..48856a7 100644 --- a/third_party/WebKit/Source/web/WebHelperPluginImpl.cpp +++ b/third_party/WebKit/Source/web/WebHelperPluginImpl.cpp
@@ -66,7 +66,7 @@ DCHECK(frame->GetFrame()->GetDocument()->Url().IsValid()); plugin_container_ = ToWebPluginContainerBase( frame->GetFrame()->Loader().Client()->CreatePlugin( - object_element_.Get(), frame->GetFrame()->GetDocument()->Url(), + *object_element_, frame->GetFrame()->GetDocument()->Url(), attribute_names, attribute_values, plugin_type, false, LocalFrameClient::kAllowDetachedPlugin));
diff --git a/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp b/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp index f39385d..0df0ec45 100644 --- a/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp +++ b/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp
@@ -682,9 +682,9 @@ // Private methods ------------------------------------------------------------- -WebPluginContainerImpl::WebPluginContainerImpl(HTMLPlugInElement* element, +WebPluginContainerImpl::WebPluginContainerImpl(HTMLPlugInElement& element, WebPlugin* web_plugin) - : WebPluginContainerBase(element->GetDocument().GetFrame()), + : WebPluginContainerBase(element.GetDocument().GetFrame()), is_attached_(false), element_(element), web_plugin_(web_plugin),
diff --git a/third_party/WebKit/Source/web/WebPluginContainerImpl.h b/third_party/WebKit/Source/web/WebPluginContainerImpl.h index f03ffdb..16f5d69 100644 --- a/third_party/WebKit/Source/web/WebPluginContainerImpl.h +++ b/third_party/WebKit/Source/web/WebPluginContainerImpl.h
@@ -65,7 +65,7 @@ USING_PRE_FINALIZER(WebPluginContainerImpl, PreFinalize); public: - static WebPluginContainerImpl* Create(HTMLPlugInElement* element, + static WebPluginContainerImpl* Create(HTMLPlugInElement& element, WebPlugin* web_plugin) { return new WebPluginContainerImpl(element, web_plugin); } @@ -199,7 +199,7 @@ IntRect& clipped_local_rect, IntRect& unclipped_int_local_rect) const; - WebPluginContainerImpl(HTMLPlugInElement*, WebPlugin*); + WebPluginContainerImpl(HTMLPlugInElement&, WebPlugin*); WebTouchEvent TransformTouchEvent(const WebInputEvent&); WebCoalescedInputEvent TransformCoalescedTouchEvent(
diff --git a/third_party/WebKit/Source/web/WebViewImpl.cpp b/third_party/WebKit/Source/web/WebViewImpl.cpp index bf4ec99..c710189a 100644 --- a/third_party/WebKit/Source/web/WebViewImpl.cpp +++ b/third_party/WebKit/Source/web/WebViewImpl.cpp
@@ -97,6 +97,8 @@ #include "core/timing/DOMWindowPerformance.h" #include "core/timing/Performance.h" #include "modules/accessibility/AXObjectCacheImpl.h" +#include "modules/compositorworker/AnimationWorkletProxyClientImpl.h" +#include "modules/compositorworker/CompositorWorkerProxyClientImpl.h" #include "modules/credentialmanager/CredentialManagerClient.h" #include "modules/encryptedmedia/MediaKeysController.h" #include "modules/speech/SpeechRecognitionClientProxy.h" @@ -164,8 +166,6 @@ #include "public/web/WebSelection.h" #include "public/web/WebViewClient.h" #include "public/web/WebWindowFeatures.h" -#include "web/AnimationWorkletProxyClientImpl.h" -#include "web/CompositorWorkerProxyClientImpl.h" #include "web/DedicatedWorkerMessagingProxyProviderImpl.h" #include "web/FullscreenController.h" #include "web/LinkHighlightImpl.h" @@ -698,8 +698,8 @@ event.data.fling_start.velocity_y), WebSize()); DCHECK(fling_curve); - gesture_animation_ = WebActiveGestureAnimation::CreateAtAnimationStart( - std::move(fling_curve), this); + gesture_animation_ = WebActiveGestureAnimation::CreateWithTimeOffset( + std::move(fling_curve), this, event.TimeStampSeconds()); MainFrameImpl()->FrameWidget()->ScheduleAnimation(); event_result = WebInputEventResult::kHandledSystem;
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 1bf8fe4..cc60142 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -24365,9 +24365,38 @@ <int value="2" label="LowStorage"/> </enum> +<enum name="MigrationUIMigrationResult" type="int"> + <int value="0" label="Success in new migration"/> + <int value="1" label="Success in resumed migration"/> + <int value="2" label="General failure in new migration"/> + <int value="3" label="General failure in resumed migration"/> + <int value="4" label="Request failure in new migration"/> + <int value="5" label="Request failure in resumed migration"/> + <int value="6" label="Mount failure in new migration"/> + <int value="7" label="Mount failure in resumed migration"/> +</enum> + +<enum name="MigrationUIRemoveCryptohomeResult" type="int"> + <int value="0" label="Success in new migration"/> + <int value="1" label="Success in resumed migration"/> + <int value="2" label="Failure in new migration"/> + <int value="3" label="Failure in resumed migration"/> +</enum> + +<enum name="MigrationUIScreen" type="int"> + <int value="0" label="Initial"/> + <int value="1" label="Ready"/> + <int value="2" label="Migrating"/> + <int value="3" label="Migration failed"/> + <int value="4" label="Not enough storage"/> +</enum> + <enum name="MigrationUIUserChoice" type="int"> <int value="0" label="Update"/> <int value="1" label="Skip"/> + <int value="2" label="Restart on migration failure"/> + <int value="3" label="Restart on low storage"/> + <int value="4" label="Report an issue"/> </enum> <enum name="MissingStartType" type="int">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 9402456..f84a4d36 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -9871,6 +9871,27 @@ </summary> </histogram> +<histogram name="Cryptohome.MigrationUI.MigrationResult" + enum="MigrationUIMigrationResult"> + <owner>fukino@chromium.org</owner> + <summary> + The result of encryption migration from eCryptfs to Ext4 dircrypto. The + recorded result is what the migration UI in Chrome side is notified from + cryptohomed. + </summary> +</histogram> + +<histogram name="Cryptohome.MigrationUI.RemoveCryptohomeResult" + enum="MigrationUIRemoveCryptohomeResult"> + <owner>fukino@chromium.org</owner> + <summary> + The result of the removal of user's cryptohome. When the migration UI is + notified that the migration failed, the UI tries to remove the user's + cryptohome to make sure that the user can create clean crytohome directory + in the next sign-in. + </summary> +</histogram> + <histogram name="Cryptohome.MigrationUI.UserChoice" enum="MigrationUIUserChoice"> <owner>fukino@chromium.org</owner> @@ -9881,6 +9902,15 @@ </summary> </histogram> +<histogram name="Cryptohome.MigrationUI.VisibleScreen" enum="MigrationUIScreen"> + <owner>fukino@chromium.org</owner> + <summary> + How many times each screen in migration UI is shown to the user. A screen is + recorded as a visible screen when the screen is kept displayed at least for + a second. + </summary> +</histogram> + <histogram name="Cryptohome.TimeToCompleteDircryptoMigration" units="ms"> <owner>dspaid@chromium.org</owner> <summary>
diff --git a/ui/arc/notification/arc_notification_view.cc b/ui/arc/notification/arc_notification_view.cc index c5f0115..dcf1887 100644 --- a/ui/arc/notification/arc_notification_view.cc +++ b/ui/arc/notification/arc_notification_view.cc
@@ -86,6 +86,11 @@ contents_view_delegate_->UpdateControlButtonsVisibility(); } +void ArcNotificationView::GetAccessibleNodeData(ui::AXNodeData* node_data) { + // This data is never used since this view is never focused when the content + // view is focusable. +} + void ArcNotificationView::OnSlideChanged() { if (contents_view_delegate_) contents_view_delegate_->OnSlideChanged();
diff --git a/ui/arc/notification/arc_notification_view.h b/ui/arc/notification/arc_notification_view.h index 8384327..a940766 100644 --- a/ui/arc/notification/arc_notification_view.h +++ b/ui/arc/notification/arc_notification_view.h
@@ -40,6 +40,7 @@ bool IsCloseButtonFocused() const override; void RequestFocusOnCloseButton() override; void UpdateControlButtonsVisibility() override; + void GetAccessibleNodeData(ui::AXNodeData* node_data) override; // views::SlideOutController::Delegate: void OnSlideChanged() override;