diff --git a/DEPS b/DEPS
index 2e9e9306..aa30f2c 100644
--- a/DEPS
+++ b/DEPS
@@ -44,7 +44,7 @@
   # 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': '46bd8103300461a53af05e58a389bf1aaf67ac3a',
+  'v8_revision': '72905fa422cb537075320ab89e80929c7c0931c1',
   # 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.
@@ -427,7 +427,7 @@
 
     # gRPC, an RPC framework. For Blimp use only.
     'src/third_party/grpc':
-      Var('chromium_git') + '/external/github.com/grpc/grpc' + '@' + 'b4cc5fc16c1368149c8a20c51248a18009ff8254',
+      Var('chromium_git') + '/external/github.com/grpc/grpc' + '@' + '5945dfa700a0566be7ea6691cc8a86ecb4a53924',
 
     # DevTools node modules. Used on Linux buildbots only.
     'src/third_party/WebKit/Source/devtools/devtools-node-modules':
diff --git a/chrome/browser/devtools/devtools_sanity_browsertest.cc b/chrome/browser/devtools/devtools_sanity_browsertest.cc
index a0421634..d5ceb17 100644
--- a/chrome/browser/devtools/devtools_sanity_browsertest.cc
+++ b/chrome/browser/devtools/devtools_sanity_browsertest.cc
@@ -1122,6 +1122,22 @@
   RunTest("testPauseWhenScriptIsRunning", kPauseWhenScriptIsRunning);
 }
 
+IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestTempFileIncognito) {
+  GURL url("about:blank");
+  ui_test_utils::BrowserAddedObserver window_observer;
+  chrome::NewEmptyWindow(browser()->profile()->GetOffTheRecordProfile());
+  Browser* new_browser = window_observer.WaitForSingleNewBrowser();
+  ui_test_utils::NavigateToURL(new_browser, url);
+  DevToolsWindow* window = DevToolsWindowTesting::OpenDevToolsWindowSync(
+      new_browser->tab_strip_model()->GetWebContentsAt(0), false);
+  RunTestFunction(window, "testTempFile");
+  DevToolsWindowTesting::CloseDevToolsWindowSync(window);
+}
+
+IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestTempFile) {
+  RunTest("testTempFile", kDebuggerTestPage);
+}
+
 // Tests network timing.
 IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestNetworkTiming) {
   RunTest("testNetworkTiming", kSlowTestPage);
diff --git a/chrome/browser/ntp_snippets/download_suggestions_provider.cc b/chrome/browser/ntp_snippets/download_suggestions_provider.cc
index 1189dd79..7dfb81d6 100644
--- a/chrome/browser/ntp_snippets/download_suggestions_provider.cc
+++ b/chrome/browser/ntp_snippets/download_suggestions_provider.cc
@@ -25,6 +25,7 @@
 #include "components/offline_pages/core/offline_page_model_query.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
+#include "components/variations/variations_associated_data.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/image/image.h"
 
@@ -51,7 +52,7 @@
 int GetMaxSuggestionsCount() {
   bool assets_enabled =
       base::FeatureList::IsEnabled(features::kAssetDownloadSuggestionsFeature);
-  return ntp_snippets::GetParamAsInt(
+  return variations::GetVariationParamByFeatureAsInt(
       assets_enabled ? features::kAssetDownloadSuggestionsFeature
                      : features::kOfflinePageDownloadSuggestionsFeature,
       kMaxSuggestionsCountParamName, kDefaultMaxSuggestionsCount);
diff --git a/chrome/browser/prerender/prerender_browsertest.cc b/chrome/browser/prerender/prerender_browsertest.cc
index 4cc65f26..9956202f 100644
--- a/chrome/browser/prerender/prerender_browsertest.cc
+++ b/chrome/browser/prerender/prerender_browsertest.cc
@@ -91,6 +91,7 @@
 #include "content/public/browser/site_instance.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_observer.h"
+#include "content/public/common/browser_side_navigation_policy.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/resource_request_body.h"
 #include "content/public/common/url_constants.h"
@@ -2834,6 +2835,11 @@
 // a server redirect.
 IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest,
                        PrerenderCrossProcessServerRedirect) {
+  // Cross-process navigations don't happen for prerendering with PlzNavigate,
+  // since we decide on a process after redirects are followed.
+  if (content::IsBrowserSideNavigationEnabled())
+    return;
+
   // Force everything to be a process swap.
   SwapProcessesContentBrowserClient test_browser_client;
   content::ContentBrowserClient* original_browser_client =
@@ -2851,6 +2857,11 @@
 // See http://crbug.com/341134
 IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest,
                        PrerenderCrossProcessServerRedirectNoHang) {
+  // Cross-process navigations don't happen for prerendering with PlzNavigate,
+  // since we decide on a process after redirects are followed.
+  if (content::IsBrowserSideNavigationEnabled())
+    return;
+
   const char kDestPath[] = "/prerender/prerender_page.html";
   // Force everything to be a process swap.
   SwapProcessesContentBrowserClient test_browser_client;
diff --git a/chrome/browser/ui/webui/devtools_ui.cc b/chrome/browser/ui/webui/devtools_ui.cc
index e16afaa..fcd2ce99 100644
--- a/chrome/browser/ui/webui/devtools_ui.cc
+++ b/chrome/browser/ui/webui/devtools_ui.cc
@@ -15,6 +15,8 @@
 #include "chrome/common/url_constants.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/devtools_frontend_host.h"
+#include "content/public/browser/site_instance.h"
+#include "content/public/browser/storage_partition.h"
 #include "content/public/browser/url_data_source.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_ui.h"
@@ -26,6 +28,7 @@
 #include "net/url_request/url_fetcher.h"
 #include "net/url_request/url_fetcher_delegate.h"
 #include "net/url_request/url_request_context_getter.h"
+#include "storage/browser/fileapi/file_system_context.h"
 #include "third_party/WebKit/public/public_features.h"
 
 using content::BrowserThread;
@@ -438,8 +441,15 @@
       new DevToolsDataSource(profile->GetRequestContext()));
 
   GURL url = web_ui->GetWebContents()->GetVisibleURL();
-  if (url.spec() == SanitizeFrontendURL(url).spec())
-    bindings_.reset(new DevToolsUIBindings(web_ui->GetWebContents()));
+  if (url.spec() != SanitizeFrontendURL(url).spec())
+    return;
+
+  if (profile->IsOffTheRecord()) {
+    GURL site = content::SiteInstance::GetSiteForURL(profile, url);
+    content::BrowserContext::GetStoragePartitionForSite(profile, site)->
+        GetFileSystemContext()->EnableTemporaryFileSystemInIncognito();
+  }
+  bindings_.reset(new DevToolsUIBindings(web_ui->GetWebContents()));
 }
 
 DevToolsUI::~DevToolsUI() {
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 13c35f6..fa1ec9d 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-9059.0.0
\ No newline at end of file
+9064.0.0
\ No newline at end of file
diff --git a/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.cc b/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.cc
index b27ba5d9..c8f9346 100644
--- a/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.cc
+++ b/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.cc
@@ -49,20 +49,22 @@
 // Note that bookmarks can be shown that do not meet this threshold.
 base::Time GetThresholdTime() {
   return base::Time::Now() -
-         base::TimeDelta::FromDays(GetParamAsInt(
+         base::TimeDelta::FromDays(variations::GetVariationParamByFeatureAsInt(
              ntp_snippets::kBookmarkSuggestionsFeature,
              kMaxBookmarkAgeInDaysParamName, kMaxBookmarkAgeInDays));
 }
 
 // The maximum number of suggestions ever provided.
 int GetMaxCount() {
-  return GetParamAsInt(ntp_snippets::kBookmarkSuggestionsFeature,
-                       kMaxBookmarksParamName, kMaxBookmarks);
+  return variations::GetVariationParamByFeatureAsInt(
+      ntp_snippets::kBookmarkSuggestionsFeature, kMaxBookmarksParamName,
+      kMaxBookmarks);
 }
 
 bool AreDesktopVisitsConsidered() {
-  return GetParamAsBool(ntp_snippets::kBookmarkSuggestionsFeature,
-                        kConsiderDesktopVisitsParamName, false);
+  return variations::GetVariationParamByFeatureAsBool(
+      ntp_snippets::kBookmarkSuggestionsFeature,
+      kConsiderDesktopVisitsParamName, false);
 }
 
 }  // namespace
diff --git a/components/ntp_snippets/features.cc b/components/ntp_snippets/features.cc
index fe007b5..085257b 100644
--- a/components/ntp_snippets/features.cc
+++ b/components/ntp_snippets/features.cc
@@ -4,7 +4,6 @@
 
 #include "components/ntp_snippets/features.h"
 
-#include "base/strings/string_number_conversions.h"
 #include "components/variations/variations_associated_data.h"
 
 namespace ntp_snippets {
@@ -42,46 +41,4 @@
 const base::Feature kFetchMoreFeature{"NTPSuggestionsFetchMore",
                                       base::FEATURE_ENABLED_BY_DEFAULT};
 
-int GetParamAsInt(const base::Feature& feature,
-                  const std::string& param_name,
-                  const int default_value) {
-  std::string value_as_string =
-      variations::GetVariationParamValueByFeature(feature, param_name);
-  int value_as_int = 0;
-  if (!base::StringToInt(value_as_string, &value_as_int)) {
-    if (!value_as_string.empty()) {
-      LOG(WARNING) << "Failed to parse variation param " << param_name
-                   << " with string value " << value_as_string
-                   << " under feature " << feature.name
-                   << " into an int. Falling back to default value of "
-                   << default_value;
-    }
-    value_as_int = default_value;
-  }
-  return value_as_int;
-}
-
-
-bool GetParamAsBool(const base::Feature& feature,
-                    const std::string& param_name,
-                    bool default_value) {
-  std::string value_as_string =
-      variations::GetVariationParamValueByFeature(feature, param_name);
-  if (value_as_string == "true") {
-    return true;
-  }
-  if (value_as_string == "false") {
-    return false;
-  }
-
-  if (!value_as_string.empty()) {
-    LOG(WARNING) << "Failed to parse variation param " << param_name
-                 << " with string value " << value_as_string
-                 << " under feature " << feature.name
-                 << " into a bool. Falling back to default value of "
-                 << default_value;
-  }
-  return default_value;
-}
-
 }  // namespace ntp_snippets
diff --git a/components/ntp_snippets/features.h b/components/ntp_snippets/features.h
index 25a3a295..3e90b3f 100644
--- a/components/ntp_snippets/features.h
+++ b/components/ntp_snippets/features.h
@@ -38,17 +38,6 @@
 // Feature to enable the Fetch More action
 extern const base::Feature kFetchMoreFeature;
 
-// Returns a feature param as an int instead of a string.
-int GetParamAsInt(const base::Feature& feature,
-                  const std::string& param_name,
-                  int default_value);
-
-// Returns a feature param as a bool instead of a string.
-// TODO(jkrcal): Use this function in other code in the ntp_snippets component.
-bool GetParamAsBool(const base::Feature& feature,
-                    const std::string& param_name,
-                    bool default_value);
-
 }  // namespace ntp_snippets
 
 #endif  // COMPONENTS_NTP_SNIPPETS_FEATURES_H_
diff --git a/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.cc b/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.cc
index 1585a67..f27892f 100644
--- a/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.cc
+++ b/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.cc
@@ -20,6 +20,7 @@
 #include "components/offline_pages/core/offline_page_model_query.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
+#include "components/variations/variations_associated_data.h"
 #include "grit/components_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/image/image.h"
@@ -38,9 +39,9 @@
 const char* kMaxSuggestionsCountParamName = "recent_tabs_max_count";
 
 int GetMaxSuggestionsCount() {
-  return GetParamAsInt(kRecentOfflineTabSuggestionsFeature,
-                       kMaxSuggestionsCountParamName,
-                       kDefaultMaxSuggestionsCount);
+  return variations::GetVariationParamByFeatureAsInt(
+      kRecentOfflineTabSuggestionsFeature, kMaxSuggestionsCountParamName,
+      kDefaultMaxSuggestionsCount);
 }
 
 struct OrderOfflinePagesByMostRecentlyCreatedFirst {
diff --git a/components/ntp_snippets/remote/remote_suggestions_hard_scheduler.h b/components/ntp_snippets/remote/remote_suggestions_hard_scheduler.h
new file mode 100644
index 0000000..6487e2f8
--- /dev/null
+++ b/components/ntp_snippets/remote/remote_suggestions_hard_scheduler.h
@@ -0,0 +1,38 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_NTP_SNIPPETS_REMOTE_REMOTE_SUGGESTIONS_HARD_SCHEDULER_H_
+#define COMPONENTS_NTP_SNIPPETS_REMOTE_REMOTE_SUGGESTIONS_HARD_SCHEDULER_H_
+
+#include "base/macros.h"
+#include "base/time/time.h"
+
+namespace ntp_snippets {
+
+// Interface to schedule "hard" periodic fetches of snippets. These "hard"
+// fetches must get triggered according to their schedule independent of whether
+// Chrome is running at that moment.
+class RemoteSuggestionsHardScheduler {
+ public:
+  // Schedule periodic fetching of snippets, with different periods depending on
+  // network state. Once per period, the concrete implementation should call
+  // RemoteSuggestionsScheduler::Updater::HardUpdate() where the updater is
+  // obtained from ContentSuggestionsService. Any of the periods can be zero to
+  // indicate that the corresponding task should not be scheduled.
+  virtual bool Schedule(base::TimeDelta period_wifi,
+                        base::TimeDelta period_fallback) = 0;
+
+  // Cancel any scheduled tasks.
+  virtual bool Unschedule() = 0;
+
+ protected:
+  RemoteSuggestionsHardScheduler() = default;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(RemoteSuggestionsHardScheduler);
+};
+
+}  // namespace ntp_snippets
+
+#endif  // COMPONENTS_NTP_SNIPPETS_REMOTE_REMOTE_SUGGESTIONS_HARD_SCHEDULER_H_
diff --git a/components/ntp_snippets/remote/remote_suggestions_scheduler.h b/components/ntp_snippets/remote/remote_suggestions_scheduler.h
new file mode 100644
index 0000000..bad65c9
--- /dev/null
+++ b/components/ntp_snippets/remote/remote_suggestions_scheduler.h
@@ -0,0 +1,61 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_NTP_SNIPPETS_REMOTE_REMOTE_SUGGESTIONS_SCHEDULER_H_
+#define COMPONENTS_NTP_SNIPPETS_REMOTE_REMOTE_SUGGESTIONS_SCHEDULER_H_
+
+#include "base/macros.h"
+#include "base/time/time.h"
+
+namespace ntp_snippets {
+
+// Class to take care of scheduling of periodic updates of snippets. There are
+// two types of scheduled updates:
+//  - "hard" ones that should outlive current running instance of Chrome. These
+//  should get triggered according to their schedule even if Chrome is not
+//  running at the given moment. This is OS-dependent, may be unavilable on
+//  some platforms.
+//  - "soft" ones that get triggered only if Chrome stays running until the
+//  scheduled point.
+class RemoteSuggestionsScheduler {
+ public:
+  // Interface to perform the scheduled update.
+  class Updater {
+    virtual void HardUpdate();
+    virtual void SoftUpdate();
+  };
+
+  // The passed in |updater| is called when an update is due according to the
+  // schedule. Note that hard fetches get access to the |updater| via the keyed
+  // ContentSuggestionService because the concrete instance passed to
+  // RemoteSuggestionsScheduler when the hard fetch was scheduled may not exist
+  // any more when the hard update is due.
+  explicit RemoteSuggestionsScheduler(Updater* updater);
+
+  // Schedules both "soft" and "hard" fetches. First removes existing schedule
+  // before scheduling new updates.
+  void Schedule();
+
+  // Removes any existing schedule.
+  void Unschedule();
+
+  // Schedule periodic fetching of snippets, with different periods depending on
+  // network state. Once per period, the concrete implementation should call
+  // RemoteSuggestionsUpdater::HardUpdate where RemoteSuggestionsUpdater is
+  // obtained from ContentSuggestionsService.
+  // Any of the periods can be zero to indicate that the corresponding task
+  // should not be scheduled.
+  virtual bool Schedule(base::TimeDelta period_wifi,
+                        base::TimeDelta period_fallback) = 0;
+
+  // Cancel any scheduled tasks.
+  virtual bool Unschedule() = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(RemoteSuggestionsHardScheduler);
+};
+
+}  // namespace ntp_snippets
+
+#endif  // COMPONENTS_NTP_SNIPPETS_REMOTE_REMOTE_SUGGESTIONS_HARD_SCHEDULER_H_
diff --git a/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.cc b/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.cc
index 5178292..c82de249 100644
--- a/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.cc
+++ b/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.cc
@@ -22,6 +22,7 @@
 #include "components/prefs/pref_service.h"
 #include "components/sessions/core/session_types.h"
 #include "components/sync_sessions/synced_session.h"
+#include "components/variations/variations_associated_data.h"
 #include "grit/components_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/image/image.h"
@@ -49,18 +50,19 @@
     "max_foreign_tabs_age_in_minutes";
 
 int GetMaxForeignTabsTotal() {
-  return GetParamAsInt(ntp_snippets::kForeignSessionsSuggestionsFeature,
-                       kMaxForeignTabsTotalParamName, kMaxForeignTabsTotal);
+  return variations::GetVariationParamByFeatureAsInt(
+      ntp_snippets::kForeignSessionsSuggestionsFeature,
+      kMaxForeignTabsTotalParamName, kMaxForeignTabsTotal);
 }
 
 int GetMaxForeignTabsPerDevice() {
-  return GetParamAsInt(ntp_snippets::kForeignSessionsSuggestionsFeature,
-                       kMaxForeignTabsPerDeviceParamName,
-                       kMaxForeignTabsPerDevice);
+  return variations::GetVariationParamByFeatureAsInt(
+      ntp_snippets::kForeignSessionsSuggestionsFeature,
+      kMaxForeignTabsPerDeviceParamName, kMaxForeignTabsPerDevice);
 }
 
 TimeDelta GetMaxForeignTabAge() {
-  return TimeDelta::FromMinutes(GetParamAsInt(
+  return TimeDelta::FromMinutes(variations::GetVariationParamByFeatureAsInt(
       ntp_snippets::kForeignSessionsSuggestionsFeature,
       kMaxForeignTabAgeInMinutesParamName, kMaxForeignTabAgeInMinutes));
 }
diff --git a/components/ntp_snippets/user_classifier.cc b/components/ntp_snippets/user_classifier.cc
index 10a26ac..35b5389 100644
--- a/components/ntp_snippets/user_classifier.cc
+++ b/components/ntp_snippets/user_classifier.cc
@@ -91,22 +91,11 @@
                       static_cast<int>(UserClassifier::Metric::COUNT),
               "Fill in info for all metrics.");
 
-double GetParamValue(const char* param_name, double default_value) {
-  std::string param_value_str = variations::GetVariationParamValueByFeature(
-      kArticleSuggestionsFeature, param_name);
-  double param_value = 0;
-  if (!base::StringToDouble(param_value_str, &param_value)) {
-    LOG_IF(WARNING, !param_value_str.empty())
-        << "Invalid variation parameter for " << param_name;
-    return default_value;
-  }
-  return param_value;
-}
-
 // Computes the discount rate.
 double GetDiscountRatePerHour() {
-  double discount_rate_per_day =
-      GetParamValue(kDiscountRatePerDayParam, kDiscountRatePerDay);
+  double discount_rate_per_day = variations::GetVariationParamByFeatureAsDouble(
+      kArticleSuggestionsFeature, kDiscountRatePerDayParam,
+      kDiscountRatePerDay);
   // Check for illegal values.
   if (discount_rate_per_day <= 0 || discount_rate_per_day >= 1) {
     DLOG(WARNING) << "Illegal value " << discount_rate_per_day
@@ -121,17 +110,20 @@
 }
 
 double GetInitialHoursBetweenEvents(UserClassifier::Metric metric) {
-  return GetParamValue(
+  return variations::GetVariationParamByFeatureAsDouble(
+      kArticleSuggestionsFeature,
       kInitialHoursBetweenEventsParams[static_cast<int>(metric)],
       kInitialHoursBetweenEvents[static_cast<int>(metric)]);
 }
 
 double GetMinHours() {
-  return GetParamValue(kMinHoursParam, kMinHours);
+  return variations::GetVariationParamByFeatureAsDouble(
+      kArticleSuggestionsFeature, kMinHoursParam, kMinHours);
 }
 
 double GetMaxHours() {
-  return GetParamValue(kMaxHoursParam, kMaxHours);
+  return variations::GetVariationParamByFeatureAsDouble(
+      kArticleSuggestionsFeature, kMaxHoursParam, kMaxHours);
 }
 
 // Returns the new value of the metric using its |old_value|, assuming
@@ -195,11 +187,15 @@
       min_hours_(GetMinHours()),
       max_hours_(GetMaxHours()),
       active_consumer_scrolls_at_least_once_per_hours_(
-          GetParamValue(kActiveConsumerScrollsAtLeastOncePerHoursParam,
-                        kActiveConsumerScrollsAtLeastOncePerHours)),
+          variations::GetVariationParamByFeatureAsDouble(
+              kArticleSuggestionsFeature,
+              kActiveConsumerScrollsAtLeastOncePerHoursParam,
+              kActiveConsumerScrollsAtLeastOncePerHours)),
       rare_user_opens_ntp_at_most_once_per_hours_(
-          GetParamValue(kRareUserOpensNTPAtMostOncePerHoursParam,
-                        kRareUserOpensNTPAtMostOncePerHours)) {
+          variations::GetVariationParamByFeatureAsDouble(
+              kArticleSuggestionsFeature,
+              kRareUserOpensNTPAtMostOncePerHoursParam,
+              kRareUserOpensNTPAtMostOncePerHours)) {
   // The pref_service_ can be null in tests.
   if (!pref_service_) {
     return;
diff --git a/components/reading_list/ios/reading_list_entry.cc b/components/reading_list/ios/reading_list_entry.cc
index 4908274..b3fc0e0 100644
--- a/components/reading_list/ios/reading_list_entry.cc
+++ b/components/reading_list/ios/reading_list_entry.cc
@@ -324,7 +324,7 @@
 
   int64_t first_read_time_us = 0;
   if (pb_entry.has_first_read_time_us()) {
-    creation_time_us = pb_entry.first_read_time_us();
+    first_read_time_us = pb_entry.first_read_time_us();
   }
 
   int64_t update_time_us = 0;
@@ -368,22 +368,27 @@
   }
   if (creation_time_us_ < other.creation_time_us_) {
     creation_time_us_ = std::move(other.creation_time_us_);
-  }
-  if (state_ == UNSEEN) {
-    state_ = std::move(other.state_);
-  } else if (other.state_ != UNSEEN) {
-    // Both are not UNSEEN, take the newer one.
-    if (update_time_us_ < other.update_time_us_) {
-      state_ = std::move(other.state_);
-    } else if (update_time_us_ == other.update_time_us_) {
-      // Both states are likely the same, but if they are not, READ should win.
-      if (other.state_ == READ) {
-        state_ = std::move(other.state_);
-      }
+    first_read_time_us_ = std::move(other.first_read_time_us_);
+  } else if (creation_time_us_ == other.creation_time_us_) {
+    // The first_time_read_us from |other| is used if
+    // - this.first_time_read_us == 0: the entry was never read in this device.
+    // - this.first_time_read_us > other.first_time_read_us: the entry was
+    //       first read on another device.
+    if (first_read_time_us_ == 0 ||
+        (other.first_read_time_us_ != 0 &&
+         other.first_read_time_us_ < first_read_time_us_)) {
+      first_read_time_us_ = std::move(other.first_read_time_us_);
     }
   }
   if (update_time_us_ < other.update_time_us_) {
     update_time_us_ = std::move(other.update_time_us_);
+    state_ = std::move(other.state_);
+  } else if (update_time_us_ == other.update_time_us_) {
+    if (state_ == UNSEEN) {
+      state_ = std::move(other.state_);
+    } else if (other.state_ == READ) {
+      state_ = std::move(other.state_);
+    }
   }
 #if !defined(NDEBUG)
   std::unique_ptr<sync_pb::ReadingListSpecifics> new_this_pb(
diff --git a/components/reading_list/ios/reading_list_entry_unittest.cc b/components/reading_list/ios/reading_list_entry_unittest.cc
index 0157f4c..bf9dec3 100644
--- a/components/reading_list/ios/reading_list_entry_unittest.cc
+++ b/components/reading_list/ios/reading_list_entry_unittest.cc
@@ -317,6 +317,8 @@
 }
 
 // Tests the merging of two ReadingListEntry.
+// Additional merging tests are done in
+// ReadingListStoreTest.CompareEntriesForSync
 TEST(ReadingListEntry, MergeWithEntry) {
   ReadingListEntry local_entry(GURL("http://example.com/"), "title");
   local_entry.SetDistilledState(ReadingListEntry::ERROR);
@@ -339,24 +341,3 @@
   base::TimeDelta delta = merge_next_call - next_call;
   EXPECT_NEAR(delta.InMillisecondsRoundedUp(), 0, 10);
 }
-
-// Tests the merging of two ReadingListEntry, the oldest one SEEN and the newer
-// UNSEEN.
-TEST(ReadingListEntry, MergeWithEntrySeen) {
-  ReadingListEntry local_entry(GURL("http://example.com/"), "title");
-  local_entry.SetRead(true);
-  int64_t local_update_time_us = local_entry.UpdateTime();
-  local_entry.SetDistilledPath(base::FilePath("distilled/page.html"));
-
-  ReadingListEntry sync_entry(GURL("http://example.com/"), "title2");
-  int64_t sync_update_time_us = sync_entry.UpdateTime();
-  EXPECT_NE(local_update_time_us, sync_update_time_us);
-  local_entry.MergeWithEntry(sync_entry);
-  EXPECT_EQ(local_entry.URL().spec(), "http://example.com/");
-  EXPECT_EQ(local_entry.Title(), "title2");
-  EXPECT_TRUE(local_entry.HasBeenSeen());
-  EXPECT_EQ(local_entry.UpdateTime(), sync_update_time_us);
-  EXPECT_EQ(local_entry.FailedDownloadCounter(), 0);
-  EXPECT_EQ(local_entry.DistilledState(), ReadingListEntry::PROCESSED);
-  EXPECT_EQ(local_entry.DistilledPath().value(), "distilled/page.html");
-}
diff --git a/components/reading_list/ios/reading_list_store.cc b/components/reading_list/ios/reading_list_store.cc
index 26ebf29..beb300b 100644
--- a/components/reading_list/ios/reading_list_store.cc
+++ b/components/reading_list/ios/reading_list_store.cc
@@ -442,5 +442,14 @@
          lhs.status() == sync_pb::ReadingListSpecifics::READ))
       return false;
   }
+  if (rhs.creation_time_us() == lhs.creation_time_us()) {
+    if (rhs.first_read_time_us() == 0 && lhs.first_read_time_us() != 0) {
+      return false;
+    }
+    if (rhs.first_read_time_us() > lhs.first_read_time_us() &&
+        lhs.first_read_time_us() != 0) {
+      return false;
+    }
+  }
   return true;
 }
diff --git a/components/reading_list/ios/reading_list_store.h b/components/reading_list/ios/reading_list_store.h
index 4dd3cfe8..c8463c8 100644
--- a/components/reading_list/ios/reading_list_store.h
+++ b/components/reading_list/ios/reading_list_store.h
@@ -79,11 +79,23 @@
   // Entries are in increasing order if all the fields respect increasing order.
   // - URL must be the same.
   // - title must verify rhs.title.compare(lhs.title) >= 0
-  // - rhs.creation_time_us >= lhs.creation_time_us
-  // - rhs.update_time_us >= lhs.update_time_us
-  // - if rhs.update_time_us > lhs.update_time_us, rhs.state can be anything.
-  // - if rhs.update_time_us == lhs.update_time_us, rhs.state >= lhs.state in
-  //          the order UNSEEN, UNREAD, READ.
+  // - creation_time_us:
+  //       rhs.creation_time_us >= lhs.creation_time_us
+  // - rhs.first_read_time_us:
+  //       if rhs.creation_time_us > lhs.creation_time_us,
+  //         rhs.first_read_time_us can be anything.
+  //       if rhs.creation_time_us == lhs.creation_time_us
+  //           and rhs.first_read_time_us == 0
+  //         rhs.first_read_time_us can be anything.
+  //       if rhs.creation_time_us == lhs.creation_time_us,
+  //         rhs.first_read_time_us <= lhs.first_read_time_us
+  // - update_time_us:
+  //       rhs.update_time_us >= lhs.update_time_us
+  // - state:
+  //       if rhs.update_time_us > lhs.update_time_us
+  //         rhs.state can be anything.
+  //       if rhs.update_time_us == lhs.update_time_us
+  //         rhs.state >= lhs.state in the order UNSEEN, UNREAD, READ.
   static bool CompareEntriesForSync(const sync_pb::ReadingListSpecifics& lhs,
                                     const sync_pb::ReadingListSpecifics& rhs);
 
diff --git a/components/reading_list/ios/reading_list_store_unittest.mm b/components/reading_list/ios/reading_list_store_unittest.mm
index 3c49c74..e6e00304 100644
--- a/components/reading_list/ios/reading_list_store_unittest.mm
+++ b/components/reading_list/ios/reading_list_store_unittest.mm
@@ -17,6 +17,30 @@
 #include "components/sync/model/model_type_store_test_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+// Tests that the transition from |entryA| to |entryB| is possible (|possible|
+// is true) or not.
+void ExpectAB(const sync_pb::ReadingListSpecifics& entryA,
+              const sync_pb::ReadingListSpecifics& entryB,
+              bool possible) {
+  EXPECT_EQ(ReadingListStore::CompareEntriesForSync(entryA, entryB), possible);
+  std::unique_ptr<ReadingListEntry> a =
+      ReadingListEntry::FromReadingListSpecifics(entryA);
+  std::unique_ptr<ReadingListEntry> b =
+      ReadingListEntry::FromReadingListSpecifics(entryB);
+  a->MergeWithEntry(*b);
+  std::unique_ptr<sync_pb::ReadingListSpecifics> mergedEntry =
+      a->AsReadingListSpecifics();
+  if (possible) {
+    // If transition is possible, the merge should be B.
+    EXPECT_EQ(entryB.SerializeAsString(), mergedEntry->SerializeAsString());
+  } else {
+    // If transition is not possible, the transition shold be possible to the
+    // merged state.
+    EXPECT_TRUE(ReadingListStore::CompareEntriesForSync(entryA, *mergedEntry));
+    EXPECT_TRUE(ReadingListStore::CompareEntriesForSync(entryB, *mergedEntry));
+  }
+}
+
 class FakeModelTypeChangeProcessorObserver {
  public:
   virtual void Put(const std::string& client_tag,
@@ -293,48 +317,73 @@
 TEST_F(ReadingListStoreTest, CompareEntriesForSync) {
   sync_pb::ReadingListSpecifics entryA;
   sync_pb::ReadingListSpecifics entryB;
-  entryA.set_url("http://foo.bar");
-  entryB.set_url("http://foo.bar");
+  entryA.set_entry_id("http://foo.bar/");
+  entryB.set_entry_id("http://foo.bar/");
+  entryA.set_url("http://foo.bar/");
+  entryB.set_url("http://foo.bar/");
   entryA.set_title("Foo Bar");
   entryB.set_title("Foo Bar");
   entryA.set_status(sync_pb::ReadingListSpecifics::UNREAD);
   entryB.set_status(sync_pb::ReadingListSpecifics::UNREAD);
   entryA.set_creation_time_us(10);
   entryB.set_creation_time_us(10);
+  entryA.set_first_read_time_us(50);
+  entryB.set_first_read_time_us(50);
   entryA.set_update_time_us(100);
   entryB.set_update_time_us(100);
   // Equal entries can be submitted.
-  EXPECT_TRUE(ReadingListStore::CompareEntriesForSync(entryA, entryB));
-  EXPECT_TRUE(ReadingListStore::CompareEntriesForSync(entryB, entryA));
+  ExpectAB(entryA, entryB, true);
+  ExpectAB(entryB, entryA, true);
 
   // Try to update each field.
 
   // You cannot change the URL of an entry.
-  entryA.set_url("http://foo.foo");
+  entryA.set_url("http://foo.foo/");
   EXPECT_FALSE(ReadingListStore::CompareEntriesForSync(entryA, entryB));
   EXPECT_FALSE(ReadingListStore::CompareEntriesForSync(entryB, entryA));
-  entryA.set_url("http://foo.bar");
+  entryA.set_url("http://foo.bar/");
 
   // You can set a title to a title later in alphabetical order.
   entryA.set_title("");
-  EXPECT_TRUE(ReadingListStore::CompareEntriesForSync(entryA, entryB));
-  EXPECT_FALSE(ReadingListStore::CompareEntriesForSync(entryB, entryA));
+  ExpectAB(entryA, entryB, true);
+  ExpectAB(entryB, entryA, false);
   entryA.set_title("Foo Aar");
-  EXPECT_TRUE(ReadingListStore::CompareEntriesForSync(entryA, entryB));
-  EXPECT_FALSE(ReadingListStore::CompareEntriesForSync(entryB, entryA));
+  ExpectAB(entryA, entryB, true);
+  ExpectAB(entryB, entryA, false);
   entryA.set_title("Foo Ba");
-  EXPECT_TRUE(ReadingListStore::CompareEntriesForSync(entryA, entryB));
-  EXPECT_FALSE(ReadingListStore::CompareEntriesForSync(entryB, entryA));
+  ExpectAB(entryA, entryB, true);
+  ExpectAB(entryB, entryA, false);
   entryA.set_title("Foo Bar");
 
   entryA.set_creation_time_us(9);
-  EXPECT_TRUE(ReadingListStore::CompareEntriesForSync(entryA, entryB));
-  EXPECT_FALSE(ReadingListStore::CompareEntriesForSync(entryB, entryA));
+  ExpectAB(entryA, entryB, true);
+  ExpectAB(entryB, entryA, false);
+  entryA.set_first_read_time_us(51);
+  ExpectAB(entryA, entryB, true);
+  ExpectAB(entryB, entryA, false);
+  entryA.set_first_read_time_us(49);
+  ExpectAB(entryA, entryB, true);
+  ExpectAB(entryB, entryA, false);
+  entryA.set_first_read_time_us(0);
+  ExpectAB(entryA, entryB, true);
+  ExpectAB(entryB, entryA, false);
+  entryA.set_first_read_time_us(50);
+  entryB.set_first_read_time_us(0);
+  ExpectAB(entryA, entryB, true);
+  ExpectAB(entryB, entryA, false);
+  entryB.set_first_read_time_us(50);
   entryA.set_creation_time_us(10);
+  entryA.set_first_read_time_us(51);
+  ExpectAB(entryA, entryB, true);
+  ExpectAB(entryB, entryA, false);
+  entryA.set_first_read_time_us(0);
+  ExpectAB(entryA, entryB, true);
+  ExpectAB(entryB, entryA, false);
+  entryA.set_first_read_time_us(50);
 
   entryA.set_update_time_us(99);
-  EXPECT_TRUE(ReadingListStore::CompareEntriesForSync(entryA, entryB));
-  EXPECT_FALSE(ReadingListStore::CompareEntriesForSync(entryB, entryA));
+  ExpectAB(entryA, entryB, true);
+  ExpectAB(entryB, entryA, false);
   sync_pb::ReadingListSpecifics::ReadingListEntryStatus status_oder[3] = {
       sync_pb::ReadingListSpecifics::UNSEEN,
       sync_pb::ReadingListSpecifics::UNREAD,
@@ -343,20 +392,20 @@
     entryA.set_status(status_oder[index_a]);
     for (int index_b = 0; index_b < 3; index_b++) {
       entryB.set_status(status_oder[index_b]);
-      EXPECT_TRUE(ReadingListStore::CompareEntriesForSync(entryA, entryB));
-      EXPECT_FALSE(ReadingListStore::CompareEntriesForSync(entryB, entryA));
+      ExpectAB(entryA, entryB, true);
+      ExpectAB(entryB, entryA, false);
     }
   }
   entryA.set_update_time_us(100);
   for (int index_a = 0; index_a < 3; index_a++) {
     entryA.set_status(status_oder[index_a]);
     entryB.set_status(status_oder[index_a]);
-    EXPECT_TRUE(ReadingListStore::CompareEntriesForSync(entryA, entryB));
-    EXPECT_TRUE(ReadingListStore::CompareEntriesForSync(entryB, entryA));
+    ExpectAB(entryA, entryB, true);
+    ExpectAB(entryB, entryA, true);
     for (int index_b = index_a + 1; index_b < 3; index_b++) {
       entryB.set_status(status_oder[index_b]);
-      EXPECT_TRUE(ReadingListStore::CompareEntriesForSync(entryA, entryB));
-      EXPECT_FALSE(ReadingListStore::CompareEntriesForSync(entryB, entryA));
+      ExpectAB(entryA, entryB, true);
+      ExpectAB(entryB, entryA, false);
     }
   }
 }
diff --git a/components/variations/variations_associated_data.cc b/components/variations/variations_associated_data.cc
index 465aed5..6701105 100644
--- a/components/variations/variations_associated_data.cc
+++ b/components/variations/variations_associated_data.cc
@@ -13,6 +13,7 @@
 #include "base/memory/singleton.h"
 #include "base/metrics/field_trial.h"
 #include "base/metrics/field_trial_param_associator.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "components/variations/variations_http_header_provider.h"
 
@@ -190,6 +191,64 @@
   return GetVariationParamValue(trial->trial_name(), param_name);
 }
 
+int GetVariationParamByFeatureAsInt(const base::Feature& feature,
+                                    const std::string& param_name,
+                                    int default_value) {
+  std::string value_as_string =
+      GetVariationParamValueByFeature(feature, param_name);
+  int value_as_int = 0;
+  if (!base::StringToInt(value_as_string, &value_as_int)) {
+    if (!value_as_string.empty()) {
+      DLOG(WARNING) << "Failed to parse variation param " << param_name
+                    << " with string value " << value_as_string
+                    << " under feature " << feature.name
+                    << " into an int. Falling back to default value of "
+                    << default_value;
+    }
+    value_as_int = default_value;
+  }
+  return value_as_int;
+}
+
+double GetVariationParamByFeatureAsDouble(const base::Feature& feature,
+                                          const std::string& param_name,
+                                          double default_value) {
+  std::string value_as_string =
+      GetVariationParamValueByFeature(feature, param_name);
+  double value_as_double = 0;
+  if (!base::StringToDouble(value_as_string, &value_as_double)) {
+    if (!value_as_string.empty()) {
+      DLOG(WARNING) << "Failed to parse variation param " << param_name
+                    << " with string value " << value_as_string
+                    << " under feature " << feature.name
+                    << " into a double. Falling back to default value of "
+                    << default_value;
+    }
+    value_as_double = default_value;
+  }
+  return value_as_double;
+}
+
+bool GetVariationParamByFeatureAsBool(const base::Feature& feature,
+                                      const std::string& param_name,
+                                      bool default_value) {
+  std::string value_as_string =
+      variations::GetVariationParamValueByFeature(feature, param_name);
+  if (value_as_string == "true")
+    return true;
+  if (value_as_string == "false")
+    return false;
+
+  if (!value_as_string.empty()) {
+    DLOG(WARNING) << "Failed to parse variation param " << param_name
+                  << " with string value " << value_as_string
+                  << " under feature " << feature.name
+                  << " into a bool. Falling back to default value of "
+                  << default_value;
+  }
+  return default_value;
+}
+
 // Functions below are exposed for testing explicitly behind this namespace.
 // They simply wrap existing functions in this file.
 namespace testing {
diff --git a/components/variations/variations_associated_data.h b/components/variations/variations_associated_data.h
index 0734e8b..ad359a4 100644
--- a/components/variations/variations_associated_data.h
+++ b/components/variations/variations_associated_data.h
@@ -152,13 +152,38 @@
 // with at most one variation, through the variation's associated field trial,
 // and selected group. See base/feature_list.h for more information on
 // features. If the feature is not enabled, or the specified parameter does not
-// exist, returns an empty string.Calling this function will result in the
+// exist, returns an empty string. Calling this function will result in the
 // associated field trial being marked as active if found (i.e. group() will be
 // called on it), if it wasn't already. Currently, this information is only
 // available from the browser process. Thread safe.
 std::string GetVariationParamValueByFeature(const base::Feature& feature,
                                             const std::string& param_name);
 
+// Same as GetVariationParamValueByFeature(). On top of that, it converts the
+// string value into an int using base::StringToInt() and returns it, if
+// successful. Otherwise, it returns |default_value|. If the string value is not
+// empty and the conversion does not succeed, it produces a warning to LOG.
+int GetVariationParamByFeatureAsInt(const base::Feature& feature,
+                                    const std::string& param_name,
+                                    int default_value);
+
+// Same as GetVariationParamValueByFeature(). On top of that, it converts the
+// string value into a double using base::StringToDouble() and returns it, if
+// successful. Otherwise, it returns |default_value|. If the string value is not
+// empty and the conversion does not succeed, it produces a warning to LOG.
+double GetVariationParamByFeatureAsDouble(const base::Feature& feature,
+                                          const std::string& param_name,
+                                          double default_value);
+
+// Same as GetVariationParamValueByFeature(). On top of that, it converts the
+// string value into a boolean and returns it, if successful. Otherwise, it
+// returns |default_value|. The only string representations accepted here are
+// "true" and "false". If the string value is not empty and the conversion does
+// not succeed, it produces a warning to LOG.
+bool GetVariationParamByFeatureAsBool(const base::Feature& feature,
+                                      const std::string& param_name,
+                                      bool default_value);
+
 // Expose some functions for testing.
 namespace testing {
 
diff --git a/components/variations/variations_associated_data_unittest.cc b/components/variations/variations_associated_data_unittest.cc
index 40ff746..2217bd5 100644
--- a/components/variations/variations_associated_data_unittest.cc
+++ b/components/variations/variations_associated_data_unittest.cc
@@ -403,4 +403,89 @@
   EXPECT_EQ(std::string(), GetVariationParamValueByFeature(kFeature, "x"));
 }
 
+TEST_F(VariationsAssociatedDataTest, GetVariationParamByFeatureAsInt) {
+  const std::string kTrialName = "GetVariationParamsByFeature";
+  const base::Feature kFeature{"TestFeature",
+                               base::FEATURE_DISABLED_BY_DEFAULT};
+
+  std::map<std::string, std::string> params;
+  params["a"] = "1";
+  params["b"] = "1.5";
+  params["c"] = "foo";
+  params["d"] = "";
+  // "e" is not registered
+  variations::AssociateVariationParams(kTrialName, "A", params);
+  scoped_refptr<base::FieldTrial> trial(
+      CreateFieldTrial(kTrialName, 100, "A", NULL));
+
+  CreateFeatureWithTrial(kFeature, base::FeatureList::OVERRIDE_ENABLE_FEATURE,
+                         trial.get());
+
+  std::map<std::string, std::string> actualParams;
+  EXPECT_EQ(1, GetVariationParamByFeatureAsInt(kFeature, "a", 0));
+  EXPECT_EQ(0, GetVariationParamByFeatureAsInt(kFeature, "b", 0));  // invalid
+  EXPECT_EQ(0, GetVariationParamByFeatureAsInt(kFeature, "c", 0));  // invalid
+  EXPECT_EQ(0, GetVariationParamByFeatureAsInt(kFeature, "d", 0));  // empty
+  EXPECT_EQ(0, GetVariationParamByFeatureAsInt(kFeature, "e", 0));  // empty
+}
+
+TEST_F(VariationsAssociatedDataTest, GetVariationParamByFeatureAsDouble) {
+  const std::string kTrialName = "GetVariationParamsByFeature";
+  const base::Feature kFeature{"TestFeature",
+                               base::FEATURE_DISABLED_BY_DEFAULT};
+
+  std::map<std::string, std::string> params;
+  params["a"] = "1";
+  params["b"] = "1.5";
+  params["c"] = "1.0e-10";
+  params["d"] = "foo";
+  params["e"] = "";
+  // "f" is not registered
+  variations::AssociateVariationParams(kTrialName, "A", params);
+  scoped_refptr<base::FieldTrial> trial(
+      CreateFieldTrial(kTrialName, 100, "A", NULL));
+
+  CreateFeatureWithTrial(kFeature, base::FeatureList::OVERRIDE_ENABLE_FEATURE,
+                         trial.get());
+
+  std::map<std::string, std::string> actualParams;
+  EXPECT_EQ(1, GetVariationParamByFeatureAsDouble(kFeature, "a", 0));
+  EXPECT_EQ(1.5, GetVariationParamByFeatureAsDouble(kFeature, "b", 0));
+  EXPECT_EQ(1.0e-10, GetVariationParamByFeatureAsDouble(kFeature, "c", 0));
+  EXPECT_EQ(0,
+            GetVariationParamByFeatureAsDouble(kFeature, "d", 0));  // invalid
+  EXPECT_EQ(0, GetVariationParamByFeatureAsDouble(kFeature, "e", 0));  // empty
+  EXPECT_EQ(0, GetVariationParamByFeatureAsDouble(kFeature, "f", 0));  // empty
+}
+
+TEST_F(VariationsAssociatedDataTest, GetVariationParamByFeatureAsBool) {
+  const std::string kTrialName = "GetVariationParamsByFeature";
+  const base::Feature kFeature{"TestFeature",
+                               base::FEATURE_DISABLED_BY_DEFAULT};
+
+  std::map<std::string, std::string> params;
+  params["a"] = "true";
+  params["b"] = "false";
+  params["c"] = "1";
+  params["d"] = "False";
+  params["e"] = "";
+  // "f" is not registered
+  variations::AssociateVariationParams(kTrialName, "A", params);
+  scoped_refptr<base::FieldTrial> trial(
+      CreateFieldTrial(kTrialName, 100, "A", NULL));
+
+  CreateFeatureWithTrial(kFeature, base::FeatureList::OVERRIDE_ENABLE_FEATURE,
+                         trial.get());
+
+  std::map<std::string, std::string> actualParams;
+  EXPECT_TRUE(GetVariationParamByFeatureAsBool(kFeature, "a", false));
+  EXPECT_FALSE(GetVariationParamByFeatureAsBool(kFeature, "b", true));
+  EXPECT_FALSE(
+      GetVariationParamByFeatureAsBool(kFeature, "c", false));  // invalid
+  EXPECT_TRUE(
+      GetVariationParamByFeatureAsBool(kFeature, "d", true));  // invalid
+  EXPECT_TRUE(GetVariationParamByFeatureAsBool(kFeature, "e", true));  // empty
+  EXPECT_TRUE(GetVariationParamByFeatureAsBool(kFeature, "f", true));  // empty
+}
+
 }  // namespace variations
diff --git a/content/browser/service_worker/service_worker_provider_host.cc b/content/browser/service_worker/service_worker_provider_host.cc
index d1e82aa..a4339e9 100644
--- a/content/browser/service_worker/service_worker_provider_host.cc
+++ b/content/browser/service_worker/service_worker_provider_host.cc
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "base/guid.h"
+#include "base/memory/ptr_util.h"
 #include "base/stl_util.h"
 #include "base/time/time.h"
 #include "content/browser/message_port_message_filter.h"
@@ -27,6 +28,7 @@
 #include "content/public/common/child_process_host.h"
 #include "content/public/common/content_client.h"
 #include "content/public/common/origin_util.h"
+#include "net/base/url_util.h"
 
 namespace content {
 
@@ -37,6 +39,38 @@
 // going down.
 int g_next_navigation_provider_id = -2;
 
+// A request handler derivative used to handle navigation requests when
+// skip_service_worker flag is set. It tracks the document URL and sets the url
+// to the provider host.
+class ServiceWorkerURLTrackingRequestHandler
+    : public ServiceWorkerRequestHandler {
+ public:
+  ServiceWorkerURLTrackingRequestHandler(
+      base::WeakPtr<ServiceWorkerContextCore> context,
+      base::WeakPtr<ServiceWorkerProviderHost> provider_host,
+      base::WeakPtr<storage::BlobStorageContext> blob_storage_context,
+      ResourceType resource_type)
+      : ServiceWorkerRequestHandler(context,
+                                    provider_host,
+                                    blob_storage_context,
+                                    resource_type) {}
+  ~ServiceWorkerURLTrackingRequestHandler() override {}
+
+  // Called via custom URLRequestJobFactory.
+  net::URLRequestJob* MaybeCreateJob(
+      net::URLRequest* request,
+      net::NetworkDelegate* network_delegate,
+      ResourceContext* resource_context) override {
+    const GURL stripped_url = net::SimplifyUrlForRequest(request->url());
+    provider_host_->SetDocumentUrl(stripped_url);
+    provider_host_->SetTopmostFrameUrl(request->first_party_for_cookies());
+    return nullptr;
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ServiceWorkerURLTrackingRequestHandler);
+};
+
 }  // anonymous namespace
 
 ServiceWorkerProviderHost::OneShotGetReadyCallback::OneShotGetReadyCallback(
@@ -333,19 +367,24 @@
     RequestContextType request_context_type,
     RequestContextFrameType frame_type,
     base::WeakPtr<storage::BlobStorageContext> blob_storage_context,
-    scoped_refptr<ResourceRequestBodyImpl> body) {
+    scoped_refptr<ResourceRequestBodyImpl> body,
+    bool skip_service_worker) {
+  if (skip_service_worker) {
+    if (!ServiceWorkerUtils::IsMainResourceType(resource_type))
+      return std::unique_ptr<ServiceWorkerRequestHandler>();
+    return base::MakeUnique<ServiceWorkerURLTrackingRequestHandler>(
+        context_, AsWeakPtr(), blob_storage_context, resource_type);
+  }
   if (IsHostToRunningServiceWorker()) {
-    return std::unique_ptr<ServiceWorkerRequestHandler>(
-        new ServiceWorkerContextRequestHandler(
-            context_, AsWeakPtr(), blob_storage_context, resource_type));
+    return base::MakeUnique<ServiceWorkerContextRequestHandler>(
+        context_, AsWeakPtr(), blob_storage_context, resource_type);
   }
   if (ServiceWorkerUtils::IsMainResourceType(resource_type) ||
       controlling_version()) {
-    return std::unique_ptr<ServiceWorkerRequestHandler>(
-        new ServiceWorkerControlleeRequestHandler(
-            context_, AsWeakPtr(), blob_storage_context, request_mode,
-            credentials_mode, redirect_mode, resource_type,
-            request_context_type, frame_type, body));
+    return base::MakeUnique<ServiceWorkerControlleeRequestHandler>(
+        context_, AsWeakPtr(), blob_storage_context, request_mode,
+        credentials_mode, redirect_mode, resource_type, request_context_type,
+        frame_type, body);
   }
   return std::unique_ptr<ServiceWorkerRequestHandler>();
 }
diff --git a/content/browser/service_worker/service_worker_provider_host.h b/content/browser/service_worker/service_worker_provider_host.h
index 3cfc6ea..0d18381 100644
--- a/content/browser/service_worker/service_worker_provider_host.h
+++ b/content/browser/service_worker/service_worker_provider_host.h
@@ -174,7 +174,8 @@
       RequestContextType request_context_type,
       RequestContextFrameType frame_type,
       base::WeakPtr<storage::BlobStorageContext> blob_storage_context,
-      scoped_refptr<ResourceRequestBodyImpl> body);
+      scoped_refptr<ResourceRequestBodyImpl> body,
+      bool skip_service_worker);
 
   // Used to get a ServiceWorkerObjectInfo to send to the renderer. Finds an
   // existing ServiceWorkerHandle, and increments its reference count, or else
diff --git a/content/browser/service_worker/service_worker_request_handler.cc b/content/browser/service_worker/service_worker_request_handler.cc
index 02eafc2..c129326 100644
--- a/content/browser/service_worker/service_worker_request_handler.cc
+++ b/content/browser/service_worker/service_worker_request_handler.cc
@@ -67,20 +67,11 @@
     RequestContextType request_context_type,
     RequestContextFrameType frame_type,
     scoped_refptr<ResourceRequestBodyImpl> body) {
-  if (skip_service_worker) {
-    // TODO(horo): Does this work properly for PlzNavigate?
-    if (ServiceWorkerUtils::IsMainResourceType(resource_type)) {
-      provider_host->SetDocumentUrl(net::SimplifyUrlForRequest(request->url()));
-      provider_host->SetTopmostFrameUrl(request->first_party_for_cookies());
-    }
-    return;
-  }
-
   std::unique_ptr<ServiceWorkerRequestHandler> handler(
       provider_host->CreateRequestHandler(
           request_mode, credentials_mode, redirect_mode, resource_type,
           request_context_type, frame_type, blob_storage_context->AsWeakPtr(),
-          body));
+          body, skip_service_worker));
   if (!handler)
     return;
 
diff --git a/content/browser/service_worker/service_worker_request_handler_unittest.cc b/content/browser/service_worker/service_worker_request_handler_unittest.cc
index 414f01b..1c243f1b 100644
--- a/content/browser/service_worker/service_worker_request_handler_unittest.cc
+++ b/content/browser/service_worker/service_worker_request_handler_unittest.cc
@@ -10,8 +10,8 @@
 #include "content/browser/fileapi/mock_url_request_delegate.h"
 #include "content/browser/service_worker/embedded_worker_test_helper.h"
 #include "content/browser/service_worker/service_worker_context_core.h"
+#include "content/browser/service_worker/service_worker_context_wrapper.h"
 #include "content/browser/service_worker/service_worker_provider_host.h"
-#include "content/browser/service_worker/service_worker_registration.h"
 #include "content/browser/service_worker/service_worker_test_utils.h"
 #include "content/common/resource_request_body_impl.h"
 #include "content/common/service_worker/service_worker_utils.h"
@@ -19,7 +19,9 @@
 #include "content/public/common/request_context_type.h"
 #include "content/public/common/resource_type.h"
 #include "content/public/test/test_browser_thread_bundle.h"
+#include "net/url_request/redirect_info.h"
 #include "net/url_request/url_request_context.h"
+#include "net/url_request/url_request_job.h"
 #include "storage/browser/blob/blob_storage_context.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -29,9 +31,6 @@
 
 int kMockProviderId = 1;
 
-void EmptyCallback() {
-}
-
 }
 
 class ServiceWorkerRequestHandlerTest : public testing::Test {
@@ -42,13 +41,6 @@
   void SetUp() override {
     helper_.reset(new EmbeddedWorkerTestHelper(base::FilePath()));
 
-    // A new unstored registration/version.
-    registration_ = new ServiceWorkerRegistration(GURL("https://host/scope/"),
-                                                  1L, context()->AsWeakPtr());
-    version_ = new ServiceWorkerVersion(registration_.get(),
-                                        GURL("https://host/script.js"), 1L,
-                                        context()->AsWeakPtr());
-
     // An empty host.
     std::unique_ptr<ServiceWorkerProviderHost> host(
         new ServiceWorkerProviderHost(
@@ -56,29 +48,12 @@
             kMockProviderId, SERVICE_WORKER_PROVIDER_FOR_WINDOW,
             ServiceWorkerProviderHost::FrameSecurityLevel::SECURE,
             context()->AsWeakPtr(), nullptr));
-    host->SetDocumentUrl(GURL("https://host/scope/"));
     provider_host_ = host->AsWeakPtr();
     context()->AddProviderHost(std::move(host));
 
-    context()->storage()->LazyInitialize(base::Bind(&EmptyCallback));
-    base::RunLoop().RunUntilIdle();
-
-    version_->set_fetch_handler_existence(
-        ServiceWorkerVersion::FetchHandlerExistence::EXISTS);
-    version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
-    registration_->SetActiveVersion(version_);
-    context()->storage()->StoreRegistration(
-        registration_.get(),
-        version_.get(),
-        base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
-    provider_host_->AssociateRegistration(registration_.get(),
-                                          false /* notify_controllerchange */);
-    base::RunLoop().RunUntilIdle();
   }
 
   void TearDown() override {
-    version_ = nullptr;
-    registration_ = nullptr;
     helper_.reset();
   }
 
@@ -87,30 +62,52 @@
     return helper_->context_wrapper();
   }
 
-  bool InitializeHandlerCheck(const std::string& url,
-                              const std::string& method,
-                              bool skip_service_worker,
-                              ResourceType resource_type) {
-    const GURL kDocUrl(url);
+  std::unique_ptr<net::URLRequest> CreateRequest(const std::string& url,
+                                                 const std::string& method) {
     std::unique_ptr<net::URLRequest> request =
-        url_request_context_.CreateRequest(kDocUrl, net::DEFAULT_PRIORITY,
+        url_request_context_.CreateRequest(GURL(url), net::DEFAULT_PRIORITY,
                                            &url_request_delegate_);
     request->set_method(method);
+    return request;
+  }
+
+  void InitializeHandler(net::URLRequest* request,
+                         bool skip_service_worker,
+                         ResourceType resource_type) {
     ServiceWorkerRequestHandler::InitializeHandler(
-        request.get(), context_wrapper(), &blob_storage_context_,
+        request, context_wrapper(), &blob_storage_context_,
         helper_->mock_render_process_id(), kMockProviderId, skip_service_worker,
         FETCH_REQUEST_MODE_NO_CORS, FETCH_CREDENTIALS_MODE_OMIT,
         FetchRedirectMode::FOLLOW_MODE, resource_type,
         REQUEST_CONTEXT_TYPE_HYPERLINK, REQUEST_CONTEXT_FRAME_TYPE_TOP_LEVEL,
         nullptr);
-    return ServiceWorkerRequestHandler::GetHandler(request.get()) != nullptr;
+  }
+
+  static ServiceWorkerRequestHandler* GetHandler(net::URLRequest* request) {
+    return ServiceWorkerRequestHandler::GetHandler(request);
+  }
+
+  std::unique_ptr<net::URLRequestJob> MaybeCreateJob(net::URLRequest* request) {
+    return std::unique_ptr<net::URLRequestJob>(
+        GetHandler(request)->MaybeCreateJob(
+            request, url_request_context_.network_delegate(),
+            context_wrapper()->resource_context()));
+  }
+
+  void InitializeHandlerSimpleTest(const std::string& url,
+                                   const std::string& method,
+                                   bool skip_service_worker,
+                                   ResourceType resource_type) {
+    std::unique_ptr<net::URLRequest> request = CreateRequest(url, method);
+    InitializeHandler(request.get(), skip_service_worker, resource_type);
+    ASSERT_TRUE(GetHandler(request.get()));
+    MaybeCreateJob(request.get());
+    EXPECT_EQ(url, provider_host_->document_url().spec());
   }
 
  protected:
   TestBrowserThreadBundle browser_thread_bundle_;
   std::unique_ptr<EmbeddedWorkerTestHelper> helper_;
-  scoped_refptr<ServiceWorkerRegistration> registration_;
-  scoped_refptr<ServiceWorkerVersion> version_;
   base::WeakPtr<ServiceWorkerProviderHost> provider_host_;
   net::URLRequestContext url_request_context_;
   MockURLRequestDelegate url_request_delegate_;
@@ -120,51 +117,57 @@
 class ServiceWorkerRequestHandlerTestP
     : public MojoServiceWorkerTestP<ServiceWorkerRequestHandlerTest> {};
 
-TEST_P(ServiceWorkerRequestHandlerTestP, InitializeHandler) {
+TEST_P(ServiceWorkerRequestHandlerTestP, InitializeHandler_FTP) {
+  std::unique_ptr<net::URLRequest> request =
+      CreateRequest("ftp://host/scope/doc", "GET");
+  InitializeHandler(request.get(), false, RESOURCE_TYPE_MAIN_FRAME);
   // Cannot initialize a handler for non-secure origins.
-  EXPECT_FALSE(InitializeHandlerCheck(
-      "ftp://host/scope/doc", "GET", false, RESOURCE_TYPE_MAIN_FRAME));
-  // HTTP is ok because it might redirect to HTTPS.
-  EXPECT_TRUE(InitializeHandlerCheck("http://host/scope/doc", "GET", false,
-                                     RESOURCE_TYPE_MAIN_FRAME));
-  EXPECT_TRUE(InitializeHandlerCheck("https://host/scope/doc", "GET", false,
-                                     RESOURCE_TYPE_MAIN_FRAME));
+  EXPECT_FALSE(GetHandler(request.get()));
+}
 
+TEST_P(ServiceWorkerRequestHandlerTestP, InitializeHandler_HTTP_MAIN_FRAME) {
+  // HTTP should have the handler because the response is possible to be a
+  // redirect to HTTPS.
+  InitializeHandlerSimpleTest("http://host/scope/doc", "GET", false,
+                              RESOURCE_TYPE_MAIN_FRAME);
+}
+
+TEST_P(ServiceWorkerRequestHandlerTestP, InitializeHandler_HTTPS_MAIN_FRAME) {
+  InitializeHandlerSimpleTest("https://host/scope/doc", "GET", false,
+                              RESOURCE_TYPE_MAIN_FRAME);
+}
+
+TEST_P(ServiceWorkerRequestHandlerTestP, InitializeHandler_HTTP_SUB_FRAME) {
+  // HTTP should have the handler because the response is possible to be a
+  // redirect to HTTPS.
+  InitializeHandlerSimpleTest("http://host/scope/doc", "GET", false,
+                              RESOURCE_TYPE_SUB_FRAME);
+}
+
+TEST_P(ServiceWorkerRequestHandlerTestP, InitializeHandler_HTTPS_SUB_FRAME) {
+  InitializeHandlerSimpleTest("https://host/scope/doc", "GET", false,
+                              RESOURCE_TYPE_SUB_FRAME);
+}
+
+TEST_P(ServiceWorkerRequestHandlerTestP, InitializeHandler_HTTPS_OPTIONS) {
   // OPTIONS is also supported. See crbug.com/434660.
-  EXPECT_TRUE(InitializeHandlerCheck(
-      "https://host/scope/doc", "OPTIONS", false, RESOURCE_TYPE_MAIN_FRAME));
+  InitializeHandlerSimpleTest("https://host/scope/doc", "OPTIONS", false,
+                              RESOURCE_TYPE_MAIN_FRAME);
+}
 
-  // Check provider host's URL after initializing a handler for main
-  // frame.
-  provider_host_->SetDocumentUrl(GURL(""));
-  EXPECT_FALSE(InitializeHandlerCheck(
-      "http://host/scope/doc", "GET", true, RESOURCE_TYPE_MAIN_FRAME));
-  EXPECT_STREQ("http://host/scope/doc",
-               provider_host_->document_url().spec().c_str());
-  EXPECT_FALSE(InitializeHandlerCheck(
-      "https://host/scope/doc", "GET", true, RESOURCE_TYPE_MAIN_FRAME));
-  EXPECT_STREQ("https://host/scope/doc",
-               provider_host_->document_url().spec().c_str());
+TEST_P(ServiceWorkerRequestHandlerTestP, InitializeHandler_HTTPS_SKIP) {
+  InitializeHandlerSimpleTest("https://host/scope/doc", "GET", true,
+                              RESOURCE_TYPE_MAIN_FRAME);
+}
 
-  // Check provider host's URL after initializing a handler for a subframe.
-  provider_host_->SetDocumentUrl(GURL(""));
-  EXPECT_FALSE(InitializeHandlerCheck(
-      "http://host/scope/doc", "GET", true, RESOURCE_TYPE_SUB_FRAME));
-  EXPECT_STREQ("http://host/scope/doc",
-               provider_host_->document_url().spec().c_str());
-  EXPECT_FALSE(InitializeHandlerCheck(
-      "https://host/scope/doc", "GET", true, RESOURCE_TYPE_SUB_FRAME));
-  EXPECT_STREQ("https://host/scope/doc",
-               provider_host_->document_url().spec().c_str());
-
+TEST_P(ServiceWorkerRequestHandlerTestP, InitializeHandler_IMAGE) {
   // Check provider host's URL after initializing a handler for an image.
-  provider_host_->SetDocumentUrl(GURL(""));
-  EXPECT_FALSE(InitializeHandlerCheck(
-      "http://host/scope/doc", "GET", true, RESOURCE_TYPE_IMAGE));
-  EXPECT_STREQ("", provider_host_->document_url().spec().c_str());
-  EXPECT_FALSE(InitializeHandlerCheck(
-      "https://host/scope/doc", "GET", true, RESOURCE_TYPE_IMAGE));
-  EXPECT_STREQ("", provider_host_->document_url().spec().c_str());
+  provider_host_->SetDocumentUrl(GURL("https://host/scope/doc"));
+  std::unique_ptr<net::URLRequest> request =
+      CreateRequest("https://host/scope/image", "GET");
+  InitializeHandler(request.get(), true, RESOURCE_TYPE_IMAGE);
+  ASSERT_FALSE(GetHandler(request.get()));
+  EXPECT_EQ(GURL("https://host/scope/doc"), provider_host_->document_url());
 }
 
 INSTANTIATE_TEST_CASE_P(ServiceWorkerRequestHandlerTest,
diff --git a/content/test/gpu/generate_buildbot_json.py b/content/test/gpu/generate_buildbot_json.py
index a6ac11c7..b3b5ca7 100755
--- a/content/test/gpu/generate_buildbot_json.py
+++ b/content/test/gpu/generate_buildbot_json.py
@@ -134,6 +134,7 @@
     'Linux ChromiumOS Builder' : {
       'additional_compile_targets' : [ "All" ]
     },
+    'Linux ChromiumOS Ozone Builder' : {},
   },
 
   'testers': {
diff --git a/gpu/config/gpu_info_collector_win.cc b/gpu/config/gpu_info_collector_win.cc
index 3e9141a..f983b65 100644
--- a/gpu/config/gpu_info_collector_win.cc
+++ b/gpu/config/gpu_info_collector_win.cc
@@ -423,8 +423,11 @@
   }
 
   if (id.length() <= 20) {
-    gpu_info->basic_info_state = kCollectInfoNonFatalFailure;
-    return kCollectInfoNonFatalFailure;
+    // Check if it is the RDP mirror driver "RDPUDD Chained DD"
+    if (wcscmp(dd.DeviceString, L"RDPUDD Chained DD") != 0) {
+      gpu_info->basic_info_state = kCollectInfoNonFatalFailure;
+      return kCollectInfoNonFatalFailure;
+    }
   }
 
   DeviceIDToVendorAndDevice(id, &gpu_info->gpu.vendor_id,
diff --git a/storage/browser/fileapi/file_system_context.cc b/storage/browser/fileapi/file_system_context.cc
index f1fcf23e..d6308377 100644
--- a/storage/browser/fileapi/file_system_context.cc
+++ b/storage/browser/fileapi/file_system_context.cc
@@ -483,11 +483,9 @@
   return CrackFileSystemURL(FileSystemURL(origin, type, path));
 }
 
-#if defined(OS_CHROMEOS)
 void FileSystemContext::EnableTemporaryFileSystemInIncognito() {
   sandbox_backend_->set_enable_temporary_file_system_in_incognito(true);
 }
-#endif
 
 bool FileSystemContext::CanServeURLRequest(const FileSystemURL& url) const {
   // We never support accessing files in isolated filesystems via an URL.
diff --git a/storage/browser/fileapi/file_system_context.h b/storage/browser/fileapi/file_system_context.h
index 0da374c..5822a2fa 100644
--- a/storage/browser/fileapi/file_system_context.h
+++ b/storage/browser/fileapi/file_system_context.h
@@ -282,10 +282,7 @@
                                            FileSystemType type,
                                            const base::FilePath& path) const;
 
-#if defined(OS_CHROMEOS)
-  // Used only on ChromeOS for now.
   void EnableTemporaryFileSystemInIncognito();
-#endif
 
   SandboxFileSystemBackendDelegate* sandbox_delegate() {
     return sandbox_delegate_.get();
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json
index eec63dfb..9922392 100644
--- a/testing/buildbot/chromium.gpu.fyi.json
+++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -2220,6 +2220,7 @@
       "All"
     ]
   },
+  "Linux ChromiumOS Ozone Builder": {},
   "Linux Debug (NVIDIA)": {
     "gtest_tests": [
       {
diff --git a/testing/buildbot/filters/browser-side-navigation.linux.browser_tests.filter b/testing/buildbot/filters/browser-side-navigation.linux.browser_tests.filter
index 9007d016..fd0562d 100644
--- a/testing/buildbot/filters/browser-side-navigation.linux.browser_tests.filter
+++ b/testing/buildbot/filters/browser-side-navigation.linux.browser_tests.filter
@@ -2,8 +2,6 @@
 -PDFExtensionTest.PdfAccessibilityInOOPIF
 -PlatformAppUrlRedirectorBrowserTest.PrerenderedClickInTabIntercepted
 -PredictorBrowserTest.RendererInitiatedNavigationPreconnect
--PrerenderBrowserTest.PrerenderCrossProcessServerRedirect
--PrerenderBrowserTest.PrerenderCrossProcessServerRedirectNoHang
 -ThreatDOMDetailsTest.Everything
 
 # https://crbug.com/652767: NavigationHandle::GetResponseHeaders sometimes
diff --git a/third_party/WebKit/LayoutTests/LeakExpectations b/third_party/WebKit/LayoutTests/LeakExpectations
index c667847..5800fbe 100644
--- a/third_party/WebKit/LayoutTests/LeakExpectations
+++ b/third_party/WebKit/LayoutTests/LeakExpectations
@@ -133,6 +133,9 @@
 crbug.com/664874 http/tests/xmlhttprequest/workers/xmlhttprequest-allowed-with-disabled-web-security.html [ Leak ]
 crbug.com/664874 virtual/mojo-loading/http/tests/xmlhttprequest/workers/xmlhttprequest-allowed-with-disabled-web-security.html [ Leak ]
 
+crbug.com/672740 http/tests/security/mixedContent/websocket/insecure-websocket-in-secure-page-worker.html [ Leak Pass ]
+crbug.com/672740 virtual/mojo-loading/http/tests/security/mixedContent/websocket/insecure-websocket-in-secure-page-worker.html [ Leak Pass ]
+
 ###########################################################################
 # WARNING: Memory leaks must be fixed asap. Sheriff is expected to revert #
 # culprit CLs instead of suppressing the leaks. If you have any question, #
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 2838160..91e1f4b 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -91,10 +91,10 @@
 crbug.com/626748 virtual/spinvalidation/paint/invalidation/table/cached-change-row-border-color.html [ Skip ]
 crbug.com/626748 virtual/spinvalidation/paint/invalidation/table/cached-change-tbody-border-color.html [ Skip ]
 
-crbug.com/645667 virtual/spinvalidation/paint/invalidation/outline-clip-change.html [ Crash ]
+crbug.com/645667 virtual/spinvalidation/paint/invalidation/outline-clip-change.html [ Crash Failure ]
 crbug.com/645667 virtual/spinvalidation/paint/invalidation/filter-repaint-accelerated-on-accelerated-filter.html [ Crash ]
 crbug.com/645667 virtual/spinvalidation/paint/invalidation/position-change-keeping-geometry.html [ Crash ]
-crbug.com/645667 virtual/spinvalidation/paint/invalidation/svg/marker-viewBox-changes.svg [ Crash ]
+crbug.com/645667 virtual/spinvalidation/paint/invalidation/svg/marker-viewBox-changes.svg [ Crash Failure ]
 crbug.com/645667 virtual/spinvalidation/paint/invalidation/compositing/should-not-repaint-composited-descendants.html [ Crash ]
 crbug.com/645667 virtual/spinvalidation/paint/invalidation/compositing/resize-repaint.html [ Crash ]
 crbug.com/645667 virtual/spinvalidation/paint/invalidation/compositing/shrink-layer.html [ Crash ]
diff --git a/third_party/WebKit/LayoutTests/fast/css/invalidation/independent-inheritance-fast-path.html b/third_party/WebKit/LayoutTests/fast/css/invalidation/independent-inheritance-fast-path.html
index 506963e3..d7d8dd50 100644
--- a/third_party/WebKit/LayoutTests/fast/css/invalidation/independent-inheritance-fast-path.html
+++ b/third_party/WebKit/LayoutTests/fast/css/invalidation/independent-inheritance-fast-path.html
@@ -17,6 +17,7 @@
     ["whiteSpace", "normal", "nowrap"],
     ["borderCollapse", "separate", "collapse"],
     ["emptyCells", "show", "hide"],
+    ["captionSide", "left", "right"],
 ];
 
 independent_properties.forEach(function(test_data)
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/service-workers/resources/bypass-for-network-redirect.php b/third_party/WebKit/LayoutTests/http/tests/inspector/service-workers/resources/bypass-for-network-redirect.php
new file mode 100644
index 0000000..2cfb1fc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/service-workers/resources/bypass-for-network-redirect.php
@@ -0,0 +1,5 @@
+<?php
+  $url = "http://127.0.0.1:8000/inspector/service-workers/resources/" .
+         "bypass-for-network-redirected.html";
+  header("Location: $url");
+?>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/service-workers/resources/bypass-for-network-redirected.html b/third_party/WebKit/LayoutTests/http/tests/inspector/service-workers/resources/bypass-for-network-redirected.html
new file mode 100644
index 0000000..ac10bc8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/service-workers/resources/bypass-for-network-redirected.html
@@ -0,0 +1,4 @@
+<script>
+navigator.serviceWorker.getRegistration().then(r =>
+  console.log("getRegistration finished"));
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/service-workers/service-workers-bypass-for-network-redirect-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector/service-workers/service-workers-bypass-for-network-redirect-expected.txt
new file mode 100644
index 0000000..d859416
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/service-workers/service-workers-bypass-for-network-redirect-expected.txt
@@ -0,0 +1,6 @@
+CONSOLE MESSAGE: line 3: getRegistration finished
+Tests "Bypass for network" checkbox with redirection doesn't cause crash.
+
+
+Success
+
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/service-workers/service-workers-bypass-for-network-redirect.html b/third_party/WebKit/LayoutTests/http/tests/inspector/service-workers/service-workers-bypass-for-network-redirect.html
new file mode 100644
index 0000000..ea267868
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/service-workers/service-workers-bypass-for-network-redirect.html
@@ -0,0 +1,47 @@
+<html>
+<head>
+<script src="../inspector-test.js"></script>
+<script src="service-workers-test.js"></script>
+<script src="../resources-test.js"></script>
+<script>
+
+function loadIframe()
+{
+    var frame = document.createElement('iframe');
+    frame.src = "http://localhost:8000/inspector/service-workers/resources/" +
+                "bypass-for-network-redirect.php"
+    document.body.appendChild(frame);
+}
+
+function test()
+{
+    UI.inspectorView.showPanel("sources")
+        .then(function(){
+            Common.settings.settingForTest("bypassServiceWorker").set(true);
+            var callback;
+            var promise = new Promise((fulfill) => callback = fulfill);
+            InspectorTest.addConsoleSniffer(message => {
+                if (message.messageText == "getRegistration finished") {
+                  callback();
+                }
+              }, true);
+            InspectorTest.evaluateInPage("loadIframe()");
+            return promise;
+        })
+        .then(function() {
+            InspectorTest.addResult("Success");
+            InspectorTest.completeTest();
+        })
+        .catch(function(exception) {
+            InspectorTest.addResult("Error");
+            InspectorTest.addResult(exception);
+            InspectorTest.completeTest();
+        });
+}
+
+</script>
+</head>
+<body onload="runTest()">
+<p>Tests "Bypass for network" checkbox with redirection doesn't cause crash.<p>
+</body>
+</html>
diff --git a/third_party/WebKit/Source/core/animation/BUILD.gn b/third_party/WebKit/Source/core/animation/BUILD.gn
index d97848d..b72f1034 100644
--- a/third_party/WebKit/Source/core/animation/BUILD.gn
+++ b/third_party/WebKit/Source/core/animation/BUILD.gn
@@ -47,6 +47,8 @@
     "CSSImageSliceInterpolationType.h",
     "CSSInterpolationType.cpp",
     "CSSInterpolationType.h",
+    "CSSInterpolationTypesMap.cpp",
+    "CSSInterpolationTypesMap.h",
     "CSSLengthInterpolationType.cpp",
     "CSSLengthInterpolationType.h",
     "CSSLengthListInterpolationType.cpp",
@@ -119,6 +121,7 @@
     "InterpolationEffect.cpp",
     "InterpolationEffect.h",
     "InterpolationType.h",
+    "InterpolationTypesMap.h",
     "InterpolationValue.h",
     "InvalidatableInterpolation.cpp",
     "InvalidatableInterpolation.h",
@@ -152,8 +155,6 @@
     "PrimitiveInterpolation.h",
     "PropertyHandle.cpp",
     "PropertyHandle.h",
-    "PropertyInterpolationTypesMapping.cpp",
-    "PropertyInterpolationTypesMapping.h",
     "SVGAngleInterpolationType.cpp",
     "SVGAngleInterpolationType.h",
     "SVGIntegerInterpolationType.cpp",
@@ -162,6 +163,8 @@
     "SVGIntegerOptionalIntegerInterpolationType.h",
     "SVGInterpolationType.cpp",
     "SVGInterpolationType.h",
+    "SVGInterpolationTypesMap.cpp",
+    "SVGInterpolationTypesMap.h",
     "SVGLengthInterpolationType.cpp",
     "SVGLengthInterpolationType.h",
     "SVGLengthListInterpolationType.cpp",
diff --git a/third_party/WebKit/Source/core/animation/CSSInterpolationTypesMap.cpp b/third_party/WebKit/Source/core/animation/CSSInterpolationTypesMap.cpp
new file mode 100644
index 0000000..1b2774fe
--- /dev/null
+++ b/third_party/WebKit/Source/core/animation/CSSInterpolationTypesMap.cpp
@@ -0,0 +1,300 @@
+// Copyright 2016 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/animation/CSSInterpolationTypesMap.h"
+
+#include "core/animation/CSSBasicShapeInterpolationType.h"
+#include "core/animation/CSSBorderImageLengthBoxInterpolationType.h"
+#include "core/animation/CSSClipInterpolationType.h"
+#include "core/animation/CSSColorInterpolationType.h"
+#include "core/animation/CSSFilterListInterpolationType.h"
+#include "core/animation/CSSFontSizeInterpolationType.h"
+#include "core/animation/CSSFontWeightInterpolationType.h"
+#include "core/animation/CSSImageInterpolationType.h"
+#include "core/animation/CSSImageListInterpolationType.h"
+#include "core/animation/CSSImageSliceInterpolationType.h"
+#include "core/animation/CSSLengthInterpolationType.h"
+#include "core/animation/CSSLengthListInterpolationType.h"
+#include "core/animation/CSSLengthPairInterpolationType.h"
+#include "core/animation/CSSNumberInterpolationType.h"
+#include "core/animation/CSSOffsetRotationInterpolationType.h"
+#include "core/animation/CSSPaintInterpolationType.h"
+#include "core/animation/CSSPathInterpolationType.h"
+#include "core/animation/CSSPositionAxisListInterpolationType.h"
+#include "core/animation/CSSPositionInterpolationType.h"
+#include "core/animation/CSSRotateInterpolationType.h"
+#include "core/animation/CSSScaleInterpolationType.h"
+#include "core/animation/CSSShadowListInterpolationType.h"
+#include "core/animation/CSSSizeListInterpolationType.h"
+#include "core/animation/CSSTextIndentInterpolationType.h"
+#include "core/animation/CSSTransformInterpolationType.h"
+#include "core/animation/CSSTransformOriginInterpolationType.h"
+#include "core/animation/CSSTranslateInterpolationType.h"
+#include "core/animation/CSSValueInterpolationType.h"
+#include "core/animation/CSSVisibilityInterpolationType.h"
+#include "core/css/CSSPropertyMetadata.h"
+#include "core/css/PropertyRegistry.h"
+#include "wtf/PtrUtil.h"
+#include <memory>
+
+namespace blink {
+
+const InterpolationTypes& CSSInterpolationTypesMap::get(
+    const PropertyHandle& property) const {
+  using ApplicableTypesMap =
+      HashMap<PropertyHandle, std::unique_ptr<const InterpolationTypes>>;
+  DEFINE_STATIC_LOCAL(ApplicableTypesMap, applicableTypesMap, ());
+  auto entry = applicableTypesMap.find(property);
+  if (entry != applicableTypesMap.end())
+    return *entry->value.get();
+
+  std::unique_ptr<InterpolationTypes> applicableTypes =
+      WTF::makeUnique<InterpolationTypes>();
+
+  CSSPropertyID cssProperty = property.isCSSProperty()
+                                  ? property.cssProperty()
+                                  : property.presentationAttribute();
+  // We treat presentation attributes identically to their CSS property
+  // equivalents when interpolating.
+  PropertyHandle usedProperty =
+      property.isCSSProperty() ? property : PropertyHandle(cssProperty);
+  switch (cssProperty) {
+    case CSSPropertyBaselineShift:
+    case CSSPropertyBorderBottomWidth:
+    case CSSPropertyBorderLeftWidth:
+    case CSSPropertyBorderRightWidth:
+    case CSSPropertyBorderTopWidth:
+    case CSSPropertyBottom:
+    case CSSPropertyCx:
+    case CSSPropertyCy:
+    case CSSPropertyFlexBasis:
+    case CSSPropertyHeight:
+    case CSSPropertyLeft:
+    case CSSPropertyLetterSpacing:
+    case CSSPropertyMarginBottom:
+    case CSSPropertyMarginLeft:
+    case CSSPropertyMarginRight:
+    case CSSPropertyMarginTop:
+    case CSSPropertyMaxHeight:
+    case CSSPropertyMaxWidth:
+    case CSSPropertyMinHeight:
+    case CSSPropertyMinWidth:
+    case CSSPropertyOffsetDistance:
+    case CSSPropertyOutlineOffset:
+    case CSSPropertyOutlineWidth:
+    case CSSPropertyPaddingBottom:
+    case CSSPropertyPaddingLeft:
+    case CSSPropertyPaddingRight:
+    case CSSPropertyPaddingTop:
+    case CSSPropertyPerspective:
+    case CSSPropertyR:
+    case CSSPropertyRight:
+    case CSSPropertyRx:
+    case CSSPropertyRy:
+    case CSSPropertyShapeMargin:
+    case CSSPropertyStrokeDashoffset:
+    case CSSPropertyStrokeWidth:
+    case CSSPropertyTop:
+    case CSSPropertyVerticalAlign:
+    case CSSPropertyWebkitBorderHorizontalSpacing:
+    case CSSPropertyWebkitBorderVerticalSpacing:
+    case CSSPropertyColumnGap:
+    case CSSPropertyColumnRuleWidth:
+    case CSSPropertyColumnWidth:
+    case CSSPropertyWebkitPerspectiveOriginX:
+    case CSSPropertyWebkitPerspectiveOriginY:
+    case CSSPropertyWebkitTransformOriginX:
+    case CSSPropertyWebkitTransformOriginY:
+    case CSSPropertyWebkitTransformOriginZ:
+    case CSSPropertyWidth:
+    case CSSPropertyWordSpacing:
+    case CSSPropertyX:
+    case CSSPropertyY:
+      applicableTypes->append(
+          WTF::makeUnique<CSSLengthInterpolationType>(usedProperty));
+      break;
+    case CSSPropertyFlexGrow:
+    case CSSPropertyFlexShrink:
+    case CSSPropertyFillOpacity:
+    case CSSPropertyFloodOpacity:
+    case CSSPropertyFontSizeAdjust:
+    case CSSPropertyOpacity:
+    case CSSPropertyOrphans:
+    case CSSPropertyShapeImageThreshold:
+    case CSSPropertyStopOpacity:
+    case CSSPropertyStrokeMiterlimit:
+    case CSSPropertyStrokeOpacity:
+    case CSSPropertyColumnCount:
+    case CSSPropertyWidows:
+    case CSSPropertyZIndex:
+      applicableTypes->append(
+          WTF::makeUnique<CSSNumberInterpolationType>(usedProperty));
+      break;
+    case CSSPropertyLineHeight:
+      applicableTypes->append(
+          WTF::makeUnique<CSSLengthInterpolationType>(usedProperty));
+      applicableTypes->append(
+          WTF::makeUnique<CSSNumberInterpolationType>(usedProperty));
+      break;
+    case CSSPropertyBackgroundColor:
+    case CSSPropertyBorderBottomColor:
+    case CSSPropertyBorderLeftColor:
+    case CSSPropertyBorderRightColor:
+    case CSSPropertyBorderTopColor:
+    case CSSPropertyColor:
+    case CSSPropertyFloodColor:
+    case CSSPropertyLightingColor:
+    case CSSPropertyOutlineColor:
+    case CSSPropertyStopColor:
+    case CSSPropertyTextDecorationColor:
+    case CSSPropertyColumnRuleColor:
+    case CSSPropertyWebkitTextStrokeColor:
+      applicableTypes->append(
+          WTF::makeUnique<CSSColorInterpolationType>(usedProperty));
+      break;
+    case CSSPropertyFill:
+    case CSSPropertyStroke:
+      applicableTypes->append(
+          WTF::makeUnique<CSSPaintInterpolationType>(usedProperty));
+      break;
+    case CSSPropertyD:
+      applicableTypes->append(
+          WTF::makeUnique<CSSPathInterpolationType>(usedProperty));
+      break;
+    case CSSPropertyBoxShadow:
+    case CSSPropertyTextShadow:
+      applicableTypes->append(
+          WTF::makeUnique<CSSShadowListInterpolationType>(usedProperty));
+      break;
+    case CSSPropertyBorderImageSource:
+    case CSSPropertyListStyleImage:
+    case CSSPropertyWebkitMaskBoxImageSource:
+      applicableTypes->append(
+          WTF::makeUnique<CSSImageInterpolationType>(usedProperty));
+      break;
+    case CSSPropertyBackgroundImage:
+    case CSSPropertyWebkitMaskImage:
+      applicableTypes->append(
+          WTF::makeUnique<CSSImageListInterpolationType>(usedProperty));
+      break;
+    case CSSPropertyStrokeDasharray:
+      applicableTypes->append(
+          WTF::makeUnique<CSSLengthListInterpolationType>(usedProperty));
+      break;
+    case CSSPropertyFontWeight:
+      applicableTypes->append(
+          WTF::makeUnique<CSSFontWeightInterpolationType>(usedProperty));
+      break;
+    case CSSPropertyVisibility:
+      applicableTypes->append(
+          WTF::makeUnique<CSSVisibilityInterpolationType>(usedProperty));
+      break;
+    case CSSPropertyClip:
+      applicableTypes->append(
+          WTF::makeUnique<CSSClipInterpolationType>(usedProperty));
+      break;
+    case CSSPropertyOffsetRotation:
+    case CSSPropertyOffsetRotate:
+      applicableTypes->append(
+          WTF::makeUnique<CSSOffsetRotationInterpolationType>(usedProperty));
+      break;
+    case CSSPropertyBackgroundPositionX:
+    case CSSPropertyBackgroundPositionY:
+    case CSSPropertyWebkitMaskPositionX:
+    case CSSPropertyWebkitMaskPositionY:
+      applicableTypes->append(
+          WTF::makeUnique<CSSPositionAxisListInterpolationType>(usedProperty));
+      break;
+    case CSSPropertyObjectPosition:
+    case CSSPropertyOffsetAnchor:
+    case CSSPropertyOffsetPosition:
+    case CSSPropertyPerspectiveOrigin:
+      applicableTypes->append(
+          WTF::makeUnique<CSSPositionInterpolationType>(usedProperty));
+      break;
+    case CSSPropertyBorderBottomLeftRadius:
+    case CSSPropertyBorderBottomRightRadius:
+    case CSSPropertyBorderTopLeftRadius:
+    case CSSPropertyBorderTopRightRadius:
+      applicableTypes->append(
+          WTF::makeUnique<CSSLengthPairInterpolationType>(usedProperty));
+      break;
+    case CSSPropertyTranslate:
+      applicableTypes->append(
+          WTF::makeUnique<CSSTranslateInterpolationType>(usedProperty));
+      break;
+    case CSSPropertyTransformOrigin:
+      applicableTypes->append(
+          WTF::makeUnique<CSSTransformOriginInterpolationType>(usedProperty));
+      break;
+    case CSSPropertyBackgroundSize:
+    case CSSPropertyWebkitMaskSize:
+      applicableTypes->append(
+          WTF::makeUnique<CSSSizeListInterpolationType>(usedProperty));
+      break;
+    case CSSPropertyBorderImageOutset:
+    case CSSPropertyBorderImageWidth:
+    case CSSPropertyWebkitMaskBoxImageOutset:
+    case CSSPropertyWebkitMaskBoxImageWidth:
+      applicableTypes->append(
+          WTF::makeUnique<CSSBorderImageLengthBoxInterpolationType>(
+              usedProperty));
+      break;
+    case CSSPropertyScale:
+      applicableTypes->append(
+          WTF::makeUnique<CSSScaleInterpolationType>(usedProperty));
+      break;
+    case CSSPropertyFontSize:
+      applicableTypes->append(
+          WTF::makeUnique<CSSFontSizeInterpolationType>(usedProperty));
+      break;
+    case CSSPropertyTextIndent:
+      applicableTypes->append(
+          WTF::makeUnique<CSSTextIndentInterpolationType>(usedProperty));
+      break;
+    case CSSPropertyBorderImageSlice:
+    case CSSPropertyWebkitMaskBoxImageSlice:
+      applicableTypes->append(
+          WTF::makeUnique<CSSImageSliceInterpolationType>(usedProperty));
+      break;
+    case CSSPropertyClipPath:
+    case CSSPropertyShapeOutside:
+      applicableTypes->append(
+          WTF::makeUnique<CSSBasicShapeInterpolationType>(usedProperty));
+      break;
+    case CSSPropertyRotate:
+      applicableTypes->append(
+          WTF::makeUnique<CSSRotateInterpolationType>(usedProperty));
+      break;
+    case CSSPropertyBackdropFilter:
+    case CSSPropertyFilter:
+      applicableTypes->append(
+          WTF::makeUnique<CSSFilterListInterpolationType>(usedProperty));
+      break;
+    case CSSPropertyTransform:
+      applicableTypes->append(
+          WTF::makeUnique<CSSTransformInterpolationType>(usedProperty));
+      break;
+    default:
+      DCHECK(!CSSPropertyMetadata::isInterpolableProperty(cssProperty));
+      // TODO(crbug.com/671904): Look up m_registry for custom property
+      // InterpolationTypes.
+      break;
+  }
+
+  applicableTypes->append(
+      WTF::makeUnique<CSSValueInterpolationType>(usedProperty));
+
+  auto addResult = applicableTypesMap.add(property, std::move(applicableTypes));
+  return *addResult.storedValue->value.get();
+}
+
+size_t CSSInterpolationTypesMap::version() const {
+  // Property registrations are never removed so the number of registered
+  // custom properties is equivalent to how many changes there have been to the
+  // property registry.
+  return m_registry ? m_registry->registrationCount() : 0;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/animation/CSSInterpolationTypesMap.h b/third_party/WebKit/Source/core/animation/CSSInterpolationTypesMap.h
new file mode 100644
index 0000000..88561ce
--- /dev/null
+++ b/third_party/WebKit/Source/core/animation/CSSInterpolationTypesMap.h
@@ -0,0 +1,29 @@
+// Copyright 2016 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 CSSInterpolationTypesMap_h
+#define CSSInterpolationTypesMap_h
+
+#include "core/animation/InterpolationTypesMap.h"
+#include "platform/heap/Handle.h"
+
+namespace blink {
+
+class PropertyRegistry;
+
+class CSSInterpolationTypesMap : public InterpolationTypesMap {
+ public:
+  CSSInterpolationTypesMap(const PropertyRegistry* registry)
+      : m_registry(registry) {}
+
+  const InterpolationTypes& get(const PropertyHandle&) const final;
+  size_t version() const final;
+
+ private:
+  Member<const PropertyRegistry> m_registry;
+};
+
+}  // namespace blink
+
+#endif  // CSSInterpolationTypesMap_h
diff --git a/third_party/WebKit/Source/core/animation/InterpolationEnvironment.h b/third_party/WebKit/Source/core/animation/InterpolationEnvironment.h
index cfae242..61d76ad 100644
--- a/third_party/WebKit/Source/core/animation/InterpolationEnvironment.h
+++ b/third_party/WebKit/Source/core/animation/InterpolationEnvironment.h
@@ -5,6 +5,7 @@
 #ifndef InterpolationEnvironment_h
 #define InterpolationEnvironment_h
 
+#include "core/animation/InterpolationTypesMap.h"
 #include "platform/heap/Handle.h"
 #include "wtf/Allocator.h"
 
@@ -18,15 +19,25 @@
   STACK_ALLOCATED();
 
  public:
-  explicit InterpolationEnvironment(StyleResolverState& state)
-      : m_state(&state), m_svgElement(nullptr), m_svgBaseValue(nullptr) {}
+  explicit InterpolationEnvironment(const InterpolationTypesMap& map,
+                                    StyleResolverState& state)
+      : m_interpolationTypesMap(map),
+        m_state(&state),
+        m_svgElement(nullptr),
+        m_svgBaseValue(nullptr) {}
 
-  explicit InterpolationEnvironment(SVGElement& svgElement,
+  explicit InterpolationEnvironment(const InterpolationTypesMap& map,
+                                    SVGElement& svgElement,
                                     const SVGPropertyBase& svgBaseValue)
-      : m_state(nullptr),
+      : m_interpolationTypesMap(map),
+        m_state(nullptr),
         m_svgElement(&svgElement),
         m_svgBaseValue(&svgBaseValue) {}
 
+  const InterpolationTypesMap& interpolationTypesMap() const {
+    return m_interpolationTypesMap;
+  }
+
   StyleResolverState& state() {
     DCHECK(m_state);
     return *m_state;
@@ -51,6 +62,7 @@
   }
 
  private:
+  const InterpolationTypesMap& m_interpolationTypesMap;
   StyleResolverState* m_state;
   Member<SVGElement> m_svgElement;
   Member<const SVGPropertyBase> m_svgBaseValue;
diff --git a/third_party/WebKit/Source/core/animation/InterpolationTypesMap.h b/third_party/WebKit/Source/core/animation/InterpolationTypesMap.h
new file mode 100644
index 0000000..a52a795
--- /dev/null
+++ b/third_party/WebKit/Source/core/animation/InterpolationTypesMap.h
@@ -0,0 +1,28 @@
+// Copyright 2016 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 InterpolationTypesMap_h
+#define InterpolationTypesMap_h
+
+#include "wtf/Vector.h"
+#include <memory>
+
+namespace blink {
+
+class InterpolationType;
+class PropertyHandle;
+
+using InterpolationTypes = Vector<std::unique_ptr<const InterpolationType>>;
+
+class InterpolationTypesMap {
+  STACK_ALLOCATED();
+
+ public:
+  virtual const InterpolationTypes& get(const PropertyHandle&) const = 0;
+  virtual size_t version() const { return 0; }
+};
+
+}  // namespace blink
+
+#endif  // InterpolationTypesMap_h
diff --git a/third_party/WebKit/Source/core/animation/InvalidatableInterpolation.cpp b/third_party/WebKit/Source/core/animation/InvalidatableInterpolation.cpp
index e480166..ef975f9 100644
--- a/third_party/WebKit/Source/core/animation/InvalidatableInterpolation.cpp
+++ b/third_party/WebKit/Source/core/animation/InvalidatableInterpolation.cpp
@@ -32,7 +32,7 @@
     const InterpolationEnvironment& environment,
     const UnderlyingValueOwner& underlyingValueOwner) const {
   DCHECK(m_currentFraction != 0 && m_currentFraction != 1);
-  for (const auto& interpolationType : m_interpolationTypes) {
+  for (const auto& interpolationType : *m_interpolationTypes) {
     if ((m_startKeyframe->isNeutral() || m_endKeyframe->isNeutral()) &&
         (!underlyingValueOwner ||
          underlyingValueOwner.type() != *interpolationType))
@@ -59,7 +59,7 @@
     const UnderlyingValueOwner& underlyingValueOwner) const {
   if (keyframe.isNeutral() && !underlyingValueOwner)
     return nullptr;
-  for (const auto& interpolationType : m_interpolationTypes) {
+  for (const auto& interpolationType : *m_interpolationTypes) {
     if (keyframe.isNeutral() &&
         underlyingValueOwner.type() != *interpolationType)
       continue;
@@ -89,7 +89,7 @@
 std::unique_ptr<TypedInterpolationValue>
 InvalidatableInterpolation::maybeConvertUnderlyingValue(
     const InterpolationEnvironment& environment) const {
-  for (const auto& interpolationType : m_interpolationTypes) {
+  for (const auto& interpolationType : *m_interpolationTypes) {
     InterpolationValue result =
         interpolationType->maybeConvertUnderlyingValue(environment);
     if (result)
@@ -144,6 +144,9 @@
     const InterpolationEnvironment& environment,
     const UnderlyingValueOwner& underlyingValueOwner) const {
   DCHECK(!std::isnan(m_currentFraction));
+  DCHECK(m_interpolationTypes &&
+         m_interpolationTypesVersion ==
+             environment.interpolationTypesMap().version());
   if (isConversionCacheValid(environment, underlyingValueOwner))
     return m_cachedValue.get();
   clearConversionCache();
@@ -172,6 +175,22 @@
   return m_cachedValue.get();
 }
 
+void InvalidatableInterpolation::ensureValidInterpolationTypes(
+    const InterpolationEnvironment& environment) const {
+  const InterpolationTypesMap& map = environment.interpolationTypesMap();
+  size_t latestVersion = map.version();
+  if (m_interpolationTypes && m_interpolationTypesVersion == latestVersion) {
+    return;
+  }
+  const InterpolationTypes* latestInterpolationTypes = &map.get(m_property);
+  DCHECK(latestInterpolationTypes);
+  if (m_interpolationTypes != latestInterpolationTypes) {
+    clearConversionCache();
+  }
+  m_interpolationTypes = latestInterpolationTypes;
+  m_interpolationTypesVersion = latestVersion;
+}
+
 void InvalidatableInterpolation::setFlagIfInheritUsed(
     InterpolationEnvironment& environment) const {
   if (!m_property.isCSSProperty() && !m_property.isPresentationAttribute())
@@ -208,6 +227,7 @@
   UnderlyingValueOwner underlyingValueOwner;
   const InvalidatableInterpolation& firstInterpolation =
       toInvalidatableInterpolation(*interpolations.at(startingIndex));
+  firstInterpolation.ensureValidInterpolationTypes(environment);
   if (firstInterpolation.dependsOnUnderlyingValue()) {
     underlyingValueOwner.set(
         firstInterpolation.maybeConvertUnderlyingValue(environment));
@@ -235,6 +255,7 @@
     const InvalidatableInterpolation& currentInterpolation =
         toInvalidatableInterpolation(*interpolations.at(i));
     DCHECK(currentInterpolation.dependsOnUnderlyingValue());
+    currentInterpolation.ensureValidInterpolationTypes(environment);
     const TypedInterpolationValue* currentValue =
         currentInterpolation.ensureValidConversion(environment,
                                                    underlyingValueOwner);
diff --git a/third_party/WebKit/Source/core/animation/InvalidatableInterpolation.h b/third_party/WebKit/Source/core/animation/InvalidatableInterpolation.h
index 1763d46..c45d3a08 100644
--- a/third_party/WebKit/Source/core/animation/InvalidatableInterpolation.h
+++ b/third_party/WebKit/Source/core/animation/InvalidatableInterpolation.h
@@ -6,8 +6,8 @@
 #define InvalidatableInterpolation_h
 
 #include "core/animation/InterpolationType.h"
+#include "core/animation/InterpolationTypesMap.h"
 #include "core/animation/PrimitiveInterpolation.h"
-#include "core/animation/PropertyInterpolationTypesMapping.h"
 #include "core/animation/StyleInterpolation.h"
 #include "core/animation/TypedInterpolationValue.h"
 #include <memory>
@@ -21,12 +21,10 @@
  public:
   static PassRefPtr<InvalidatableInterpolation> create(
       PropertyHandle property,
-      const InterpolationTypes& interpolationTypes,
       PassRefPtr<PropertySpecificKeyframe> startKeyframe,
       PassRefPtr<PropertySpecificKeyframe> endKeyframe) {
-    return adoptRef(new InvalidatableInterpolation(property, interpolationTypes,
-                                                   std::move(startKeyframe),
-                                                   std::move(endKeyframe)));
+    return adoptRef(new InvalidatableInterpolation(
+        property, std::move(startKeyframe), std::move(endKeyframe)));
   }
 
   PropertyHandle getProperty() const final { return m_property; }
@@ -40,12 +38,12 @@
 
  private:
   InvalidatableInterpolation(PropertyHandle property,
-                             const InterpolationTypes& interpolationTypes,
                              PassRefPtr<PropertySpecificKeyframe> startKeyframe,
                              PassRefPtr<PropertySpecificKeyframe> endKeyframe)
       : Interpolation(nullptr, nullptr),
         m_property(property),
-        m_interpolationTypes(interpolationTypes),
+        m_interpolationTypes(nullptr),
+        m_interpolationTypesVersion(0),
         m_startKeyframe(startKeyframe),
         m_endKeyframe(endKeyframe),
         m_currentFraction(std::numeric_limits<double>::quiet_NaN()),
@@ -58,6 +56,7 @@
   const TypedInterpolationValue* ensureValidConversion(
       const InterpolationEnvironment&,
       const UnderlyingValueOwner&) const;
+  void ensureValidInterpolationTypes(const InterpolationEnvironment&) const;
   void clearConversionCache() const;
   bool isConversionCacheValid(const InterpolationEnvironment&,
                               const UnderlyingValueOwner&) const;
@@ -75,7 +74,8 @@
   double underlyingFraction() const;
 
   const PropertyHandle m_property;
-  const InterpolationTypes& m_interpolationTypes;
+  mutable const InterpolationTypes* m_interpolationTypes;
+  mutable size_t m_interpolationTypesVersion;
   RefPtr<PropertySpecificKeyframe> m_startKeyframe;
   RefPtr<PropertySpecificKeyframe> m_endKeyframe;
   double m_currentFraction;
diff --git a/third_party/WebKit/Source/core/animation/Keyframe.cpp b/third_party/WebKit/Source/core/animation/Keyframe.cpp
index 5c733374..bf504e4a 100644
--- a/third_party/WebKit/Source/core/animation/Keyframe.cpp
+++ b/third_party/WebKit/Source/core/animation/Keyframe.cpp
@@ -5,7 +5,6 @@
 #include "core/animation/Keyframe.h"
 
 #include "core/animation/InvalidatableInterpolation.h"
-#include "core/animation/PropertyInterpolationTypesMapping.h"
 
 namespace blink {
 
@@ -15,8 +14,7 @@
     const Keyframe::PropertySpecificKeyframe& end) const {
   // const_cast to take refs.
   return InvalidatableInterpolation::create(
-      propertyHandle, PropertyInterpolationTypesMapping::get(propertyHandle),
-      const_cast<PropertySpecificKeyframe*>(this),
+      propertyHandle, const_cast<PropertySpecificKeyframe*>(this),
       const_cast<PropertySpecificKeyframe*>(&end));
 }
 
diff --git a/third_party/WebKit/Source/core/animation/PropertyInterpolationTypesMapping.cpp b/third_party/WebKit/Source/core/animation/PropertyInterpolationTypesMapping.cpp
deleted file mode 100644
index dd28e10..0000000
--- a/third_party/WebKit/Source/core/animation/PropertyInterpolationTypesMapping.cpp
+++ /dev/null
@@ -1,432 +0,0 @@
-// Copyright 2016 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/animation/PropertyInterpolationTypesMapping.h"
-
-#include "core/HTMLNames.h"
-#include "core/animation/CSSBasicShapeInterpolationType.h"
-#include "core/animation/CSSBorderImageLengthBoxInterpolationType.h"
-#include "core/animation/CSSClipInterpolationType.h"
-#include "core/animation/CSSColorInterpolationType.h"
-#include "core/animation/CSSFilterListInterpolationType.h"
-#include "core/animation/CSSFontSizeInterpolationType.h"
-#include "core/animation/CSSFontWeightInterpolationType.h"
-#include "core/animation/CSSImageInterpolationType.h"
-#include "core/animation/CSSImageListInterpolationType.h"
-#include "core/animation/CSSImageSliceInterpolationType.h"
-#include "core/animation/CSSLengthInterpolationType.h"
-#include "core/animation/CSSLengthListInterpolationType.h"
-#include "core/animation/CSSLengthPairInterpolationType.h"
-#include "core/animation/CSSNumberInterpolationType.h"
-#include "core/animation/CSSOffsetRotationInterpolationType.h"
-#include "core/animation/CSSPaintInterpolationType.h"
-#include "core/animation/CSSPathInterpolationType.h"
-#include "core/animation/CSSPositionAxisListInterpolationType.h"
-#include "core/animation/CSSPositionInterpolationType.h"
-#include "core/animation/CSSRotateInterpolationType.h"
-#include "core/animation/CSSScaleInterpolationType.h"
-#include "core/animation/CSSShadowListInterpolationType.h"
-#include "core/animation/CSSSizeListInterpolationType.h"
-#include "core/animation/CSSTextIndentInterpolationType.h"
-#include "core/animation/CSSTransformInterpolationType.h"
-#include "core/animation/CSSTransformOriginInterpolationType.h"
-#include "core/animation/CSSTranslateInterpolationType.h"
-#include "core/animation/CSSValueInterpolationType.h"
-#include "core/animation/CSSVisibilityInterpolationType.h"
-#include "core/animation/InterpolationType.h"
-#include "core/animation/SVGAngleInterpolationType.h"
-#include "core/animation/SVGIntegerInterpolationType.h"
-#include "core/animation/SVGIntegerOptionalIntegerInterpolationType.h"
-#include "core/animation/SVGLengthInterpolationType.h"
-#include "core/animation/SVGLengthListInterpolationType.h"
-#include "core/animation/SVGNumberInterpolationType.h"
-#include "core/animation/SVGNumberListInterpolationType.h"
-#include "core/animation/SVGNumberOptionalNumberInterpolationType.h"
-#include "core/animation/SVGPathInterpolationType.h"
-#include "core/animation/SVGPointListInterpolationType.h"
-#include "core/animation/SVGRectInterpolationType.h"
-#include "core/animation/SVGTransformListInterpolationType.h"
-#include "core/animation/SVGValueInterpolationType.h"
-#include "core/css/CSSPropertyMetadata.h"
-#include "wtf/PtrUtil.h"
-#include <memory>
-
-namespace blink {
-
-const InterpolationTypes& PropertyInterpolationTypesMapping::get(
-    const PropertyHandle& property) {
-  using ApplicableTypesMap =
-      HashMap<PropertyHandle, std::unique_ptr<const InterpolationTypes>>;
-  DEFINE_STATIC_LOCAL(ApplicableTypesMap, applicableTypesMap, ());
-  auto entry = applicableTypesMap.find(property);
-  if (entry != applicableTypesMap.end())
-    return *entry->value.get();
-
-  std::unique_ptr<InterpolationTypes> applicableTypes =
-      WTF::makeUnique<InterpolationTypes>();
-
-  if (property.isCSSProperty() || property.isPresentationAttribute()) {
-    CSSPropertyID cssProperty = property.isCSSProperty()
-                                    ? property.cssProperty()
-                                    : property.presentationAttribute();
-    // We treat presentation attributes identically to their CSS property
-    // equivalents when interpolating.
-    PropertyHandle usedProperty =
-        property.isCSSProperty() ? property : PropertyHandle(cssProperty);
-    switch (cssProperty) {
-      case CSSPropertyBaselineShift:
-      case CSSPropertyBorderBottomWidth:
-      case CSSPropertyBorderLeftWidth:
-      case CSSPropertyBorderRightWidth:
-      case CSSPropertyBorderTopWidth:
-      case CSSPropertyBottom:
-      case CSSPropertyCx:
-      case CSSPropertyCy:
-      case CSSPropertyFlexBasis:
-      case CSSPropertyHeight:
-      case CSSPropertyLeft:
-      case CSSPropertyLetterSpacing:
-      case CSSPropertyMarginBottom:
-      case CSSPropertyMarginLeft:
-      case CSSPropertyMarginRight:
-      case CSSPropertyMarginTop:
-      case CSSPropertyMaxHeight:
-      case CSSPropertyMaxWidth:
-      case CSSPropertyMinHeight:
-      case CSSPropertyMinWidth:
-      case CSSPropertyOffsetDistance:
-      case CSSPropertyOutlineOffset:
-      case CSSPropertyOutlineWidth:
-      case CSSPropertyPaddingBottom:
-      case CSSPropertyPaddingLeft:
-      case CSSPropertyPaddingRight:
-      case CSSPropertyPaddingTop:
-      case CSSPropertyPerspective:
-      case CSSPropertyR:
-      case CSSPropertyRight:
-      case CSSPropertyRx:
-      case CSSPropertyRy:
-      case CSSPropertyShapeMargin:
-      case CSSPropertyStrokeDashoffset:
-      case CSSPropertyStrokeWidth:
-      case CSSPropertyTop:
-      case CSSPropertyVerticalAlign:
-      case CSSPropertyWebkitBorderHorizontalSpacing:
-      case CSSPropertyWebkitBorderVerticalSpacing:
-      case CSSPropertyColumnGap:
-      case CSSPropertyColumnRuleWidth:
-      case CSSPropertyColumnWidth:
-      case CSSPropertyWebkitPerspectiveOriginX:
-      case CSSPropertyWebkitPerspectiveOriginY:
-      case CSSPropertyWebkitTransformOriginX:
-      case CSSPropertyWebkitTransformOriginY:
-      case CSSPropertyWebkitTransformOriginZ:
-      case CSSPropertyWidth:
-      case CSSPropertyWordSpacing:
-      case CSSPropertyX:
-      case CSSPropertyY:
-        applicableTypes->append(
-            WTF::makeUnique<CSSLengthInterpolationType>(usedProperty));
-        break;
-      case CSSPropertyFlexGrow:
-      case CSSPropertyFlexShrink:
-      case CSSPropertyFillOpacity:
-      case CSSPropertyFloodOpacity:
-      case CSSPropertyFontSizeAdjust:
-      case CSSPropertyOpacity:
-      case CSSPropertyOrphans:
-      case CSSPropertyShapeImageThreshold:
-      case CSSPropertyStopOpacity:
-      case CSSPropertyStrokeMiterlimit:
-      case CSSPropertyStrokeOpacity:
-      case CSSPropertyColumnCount:
-      case CSSPropertyWidows:
-      case CSSPropertyZIndex:
-        applicableTypes->append(
-            WTF::makeUnique<CSSNumberInterpolationType>(usedProperty));
-        break;
-      case CSSPropertyLineHeight:
-        applicableTypes->append(
-            WTF::makeUnique<CSSLengthInterpolationType>(usedProperty));
-        applicableTypes->append(
-            WTF::makeUnique<CSSNumberInterpolationType>(usedProperty));
-        break;
-      case CSSPropertyBackgroundColor:
-      case CSSPropertyBorderBottomColor:
-      case CSSPropertyBorderLeftColor:
-      case CSSPropertyBorderRightColor:
-      case CSSPropertyBorderTopColor:
-      case CSSPropertyColor:
-      case CSSPropertyFloodColor:
-      case CSSPropertyLightingColor:
-      case CSSPropertyOutlineColor:
-      case CSSPropertyStopColor:
-      case CSSPropertyTextDecorationColor:
-      case CSSPropertyColumnRuleColor:
-      case CSSPropertyWebkitTextStrokeColor:
-        applicableTypes->append(
-            WTF::makeUnique<CSSColorInterpolationType>(usedProperty));
-        break;
-      case CSSPropertyFill:
-      case CSSPropertyStroke:
-        applicableTypes->append(
-            WTF::makeUnique<CSSPaintInterpolationType>(usedProperty));
-        break;
-      case CSSPropertyD:
-        applicableTypes->append(
-            WTF::makeUnique<CSSPathInterpolationType>(usedProperty));
-        break;
-      case CSSPropertyBoxShadow:
-      case CSSPropertyTextShadow:
-        applicableTypes->append(
-            WTF::makeUnique<CSSShadowListInterpolationType>(usedProperty));
-        break;
-      case CSSPropertyBorderImageSource:
-      case CSSPropertyListStyleImage:
-      case CSSPropertyWebkitMaskBoxImageSource:
-        applicableTypes->append(
-            WTF::makeUnique<CSSImageInterpolationType>(usedProperty));
-        break;
-      case CSSPropertyBackgroundImage:
-      case CSSPropertyWebkitMaskImage:
-        applicableTypes->append(
-            WTF::makeUnique<CSSImageListInterpolationType>(usedProperty));
-        break;
-      case CSSPropertyStrokeDasharray:
-        applicableTypes->append(
-            WTF::makeUnique<CSSLengthListInterpolationType>(usedProperty));
-        break;
-      case CSSPropertyFontWeight:
-        applicableTypes->append(
-            WTF::makeUnique<CSSFontWeightInterpolationType>(usedProperty));
-        break;
-      case CSSPropertyVisibility:
-        applicableTypes->append(
-            WTF::makeUnique<CSSVisibilityInterpolationType>(usedProperty));
-        break;
-      case CSSPropertyClip:
-        applicableTypes->append(
-            WTF::makeUnique<CSSClipInterpolationType>(usedProperty));
-        break;
-      case CSSPropertyOffsetRotate:
-      case CSSPropertyOffsetRotation:
-        applicableTypes->append(
-            WTF::makeUnique<CSSOffsetRotationInterpolationType>(usedProperty));
-        break;
-      case CSSPropertyBackgroundPositionX:
-      case CSSPropertyBackgroundPositionY:
-      case CSSPropertyWebkitMaskPositionX:
-      case CSSPropertyWebkitMaskPositionY:
-        applicableTypes->append(
-            WTF::makeUnique<CSSPositionAxisListInterpolationType>(
-                usedProperty));
-        break;
-      case CSSPropertyObjectPosition:
-      case CSSPropertyOffsetAnchor:
-      case CSSPropertyOffsetPosition:
-      case CSSPropertyPerspectiveOrigin:
-        applicableTypes->append(
-            WTF::makeUnique<CSSPositionInterpolationType>(usedProperty));
-        break;
-      case CSSPropertyBorderBottomLeftRadius:
-      case CSSPropertyBorderBottomRightRadius:
-      case CSSPropertyBorderTopLeftRadius:
-      case CSSPropertyBorderTopRightRadius:
-        applicableTypes->append(
-            WTF::makeUnique<CSSLengthPairInterpolationType>(usedProperty));
-        break;
-      case CSSPropertyTranslate:
-        applicableTypes->append(
-            WTF::makeUnique<CSSTranslateInterpolationType>(usedProperty));
-        break;
-      case CSSPropertyTransformOrigin:
-        applicableTypes->append(
-            WTF::makeUnique<CSSTransformOriginInterpolationType>(usedProperty));
-        break;
-      case CSSPropertyBackgroundSize:
-      case CSSPropertyWebkitMaskSize:
-        applicableTypes->append(
-            WTF::makeUnique<CSSSizeListInterpolationType>(usedProperty));
-        break;
-      case CSSPropertyBorderImageOutset:
-      case CSSPropertyBorderImageWidth:
-      case CSSPropertyWebkitMaskBoxImageOutset:
-      case CSSPropertyWebkitMaskBoxImageWidth:
-        applicableTypes->append(WTF::wrapUnique(
-            new CSSBorderImageLengthBoxInterpolationType(usedProperty)));
-        break;
-      case CSSPropertyScale:
-        applicableTypes->append(
-            WTF::makeUnique<CSSScaleInterpolationType>(usedProperty));
-        break;
-      case CSSPropertyFontSize:
-        applicableTypes->append(
-            WTF::makeUnique<CSSFontSizeInterpolationType>(usedProperty));
-        break;
-      case CSSPropertyTextIndent:
-        applicableTypes->append(
-            WTF::makeUnique<CSSTextIndentInterpolationType>(usedProperty));
-        break;
-      case CSSPropertyBorderImageSlice:
-      case CSSPropertyWebkitMaskBoxImageSlice:
-        applicableTypes->append(
-            WTF::makeUnique<CSSImageSliceInterpolationType>(usedProperty));
-        break;
-      case CSSPropertyClipPath:
-      case CSSPropertyShapeOutside:
-        applicableTypes->append(
-            WTF::makeUnique<CSSBasicShapeInterpolationType>(usedProperty));
-        break;
-      case CSSPropertyRotate:
-        applicableTypes->append(
-            WTF::makeUnique<CSSRotateInterpolationType>(usedProperty));
-        break;
-      case CSSPropertyBackdropFilter:
-      case CSSPropertyFilter:
-        applicableTypes->append(
-            WTF::makeUnique<CSSFilterListInterpolationType>(usedProperty));
-        break;
-      case CSSPropertyTransform:
-        applicableTypes->append(
-            WTF::makeUnique<CSSTransformInterpolationType>(usedProperty));
-        break;
-      default:
-        DCHECK(!CSSPropertyMetadata::isInterpolableProperty(cssProperty));
-    }
-
-    applicableTypes->append(
-        WTF::makeUnique<CSSValueInterpolationType>(usedProperty));
-
-  } else {
-    const QualifiedName& attribute = property.svgAttribute();
-    if (attribute == SVGNames::orientAttr) {
-      applicableTypes->append(
-          WTF::makeUnique<SVGAngleInterpolationType>(attribute));
-    } else if (attribute == SVGNames::numOctavesAttr ||
-               attribute == SVGNames::targetXAttr ||
-               attribute == SVGNames::targetYAttr) {
-      applicableTypes->append(
-          WTF::makeUnique<SVGIntegerInterpolationType>(attribute));
-    } else if (attribute == SVGNames::orderAttr) {
-      applicableTypes->append(WTF::wrapUnique(
-          new SVGIntegerOptionalIntegerInterpolationType(attribute)));
-    } else if (attribute == SVGNames::cxAttr || attribute == SVGNames::cyAttr ||
-               attribute == SVGNames::fxAttr || attribute == SVGNames::fyAttr ||
-               attribute == SVGNames::heightAttr ||
-               attribute == SVGNames::markerHeightAttr ||
-               attribute == SVGNames::markerWidthAttr ||
-               attribute == SVGNames::rAttr ||
-               attribute == SVGNames::refXAttr ||
-               attribute == SVGNames::refYAttr ||
-               attribute == SVGNames::rxAttr || attribute == SVGNames::ryAttr ||
-               attribute == SVGNames::startOffsetAttr ||
-               attribute == SVGNames::textLengthAttr ||
-               attribute == SVGNames::widthAttr ||
-               attribute == SVGNames::x1Attr || attribute == SVGNames::x2Attr ||
-               attribute == SVGNames::y1Attr || attribute == SVGNames::y2Attr) {
-      applicableTypes->append(
-          WTF::makeUnique<SVGLengthInterpolationType>(attribute));
-    } else if (attribute == SVGNames::dxAttr || attribute == SVGNames::dyAttr) {
-      applicableTypes->append(
-          WTF::makeUnique<SVGNumberInterpolationType>(attribute));
-      applicableTypes->append(
-          WTF::makeUnique<SVGLengthListInterpolationType>(attribute));
-    } else if (attribute == SVGNames::xAttr || attribute == SVGNames::yAttr) {
-      applicableTypes->append(
-          WTF::makeUnique<SVGLengthInterpolationType>(attribute));
-      applicableTypes->append(
-          WTF::makeUnique<SVGLengthListInterpolationType>(attribute));
-    } else if (attribute == SVGNames::amplitudeAttr ||
-               attribute == SVGNames::azimuthAttr ||
-               attribute == SVGNames::biasAttr ||
-               attribute == SVGNames::diffuseConstantAttr ||
-               attribute == SVGNames::divisorAttr ||
-               attribute == SVGNames::elevationAttr ||
-               attribute == SVGNames::exponentAttr ||
-               attribute == SVGNames::interceptAttr ||
-               attribute == SVGNames::k1Attr || attribute == SVGNames::k2Attr ||
-               attribute == SVGNames::k3Attr || attribute == SVGNames::k4Attr ||
-               attribute == SVGNames::limitingConeAngleAttr ||
-               attribute == SVGNames::offsetAttr ||
-               attribute == SVGNames::pathLengthAttr ||
-               attribute == SVGNames::pointsAtXAttr ||
-               attribute == SVGNames::pointsAtYAttr ||
-               attribute == SVGNames::pointsAtZAttr ||
-               attribute == SVGNames::scaleAttr ||
-               attribute == SVGNames::seedAttr ||
-               attribute == SVGNames::slopeAttr ||
-               attribute == SVGNames::specularConstantAttr ||
-               attribute == SVGNames::specularExponentAttr ||
-               attribute == SVGNames::surfaceScaleAttr ||
-               attribute == SVGNames::zAttr) {
-      applicableTypes->append(
-          WTF::makeUnique<SVGNumberInterpolationType>(attribute));
-    } else if (attribute == SVGNames::kernelMatrixAttr ||
-               attribute == SVGNames::rotateAttr ||
-               attribute == SVGNames::tableValuesAttr ||
-               attribute == SVGNames::valuesAttr) {
-      applicableTypes->append(
-          WTF::makeUnique<SVGNumberListInterpolationType>(attribute));
-    } else if (attribute == SVGNames::baseFrequencyAttr ||
-               attribute == SVGNames::kernelUnitLengthAttr ||
-               attribute == SVGNames::radiusAttr ||
-               attribute == SVGNames::stdDeviationAttr) {
-      applicableTypes->append(
-          WTF::makeUnique<SVGNumberOptionalNumberInterpolationType>(attribute));
-    } else if (attribute == SVGNames::dAttr) {
-      applicableTypes->append(
-          WTF::makeUnique<SVGPathInterpolationType>(attribute));
-    } else if (attribute == SVGNames::pointsAttr) {
-      applicableTypes->append(
-          WTF::makeUnique<SVGPointListInterpolationType>(attribute));
-    } else if (attribute == SVGNames::viewBoxAttr) {
-      applicableTypes->append(
-          WTF::makeUnique<SVGRectInterpolationType>(attribute));
-    } else if (attribute == SVGNames::gradientTransformAttr ||
-               attribute == SVGNames::patternTransformAttr ||
-               attribute == SVGNames::transformAttr) {
-      applicableTypes->append(
-          WTF::makeUnique<SVGTransformListInterpolationType>(attribute));
-    } else if (attribute == HTMLNames::classAttr ||
-               attribute == SVGNames::clipPathUnitsAttr ||
-               attribute == SVGNames::edgeModeAttr ||
-               attribute == SVGNames::filterUnitsAttr ||
-               attribute == SVGNames::gradientUnitsAttr ||
-               attribute == SVGNames::hrefAttr ||
-               attribute == SVGNames::inAttr ||
-               attribute == SVGNames::in2Attr ||
-               attribute == SVGNames::lengthAdjustAttr ||
-               attribute == SVGNames::markerUnitsAttr ||
-               attribute == SVGNames::maskContentUnitsAttr ||
-               attribute == SVGNames::maskUnitsAttr ||
-               attribute == SVGNames::methodAttr ||
-               attribute == SVGNames::modeAttr ||
-               attribute == SVGNames::operatorAttr ||
-               attribute == SVGNames::patternContentUnitsAttr ||
-               attribute == SVGNames::patternUnitsAttr ||
-               attribute == SVGNames::preserveAlphaAttr ||
-               attribute == SVGNames::preserveAspectRatioAttr ||
-               attribute == SVGNames::primitiveUnitsAttr ||
-               attribute == SVGNames::resultAttr ||
-               attribute == SVGNames::spacingAttr ||
-               attribute == SVGNames::spreadMethodAttr ||
-               attribute == SVGNames::stitchTilesAttr ||
-               attribute == SVGNames::targetAttr ||
-               attribute == SVGNames::typeAttr ||
-               attribute == SVGNames::xChannelSelectorAttr ||
-               attribute == SVGNames::yChannelSelectorAttr) {
-      // Use default SVGValueInterpolationType.
-    } else {
-      NOTREACHED();
-    }
-
-    applicableTypes->append(
-        WTF::makeUnique<SVGValueInterpolationType>(attribute));
-  }
-
-  auto addResult = applicableTypesMap.add(property, std::move(applicableTypes));
-  return *addResult.storedValue->value.get();
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/core/animation/PropertyInterpolationTypesMapping.h b/third_party/WebKit/Source/core/animation/PropertyInterpolationTypesMapping.h
deleted file mode 100644
index 57fc605..0000000
--- a/third_party/WebKit/Source/core/animation/PropertyInterpolationTypesMapping.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2016 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 PropertyInterpolationTypesMapping_h
-#define PropertyInterpolationTypesMapping_h
-
-#include "wtf/Vector.h"
-#include <memory>
-
-namespace blink {
-
-class InterpolationType;
-class PropertyHandle;
-
-using InterpolationTypes = Vector<std::unique_ptr<const InterpolationType>>;
-
-namespace PropertyInterpolationTypesMapping {
-
-const InterpolationTypes& get(const PropertyHandle&);
-};
-
-}  // namespace blink
-
-#endif  // PropertyInterpolationTypesMapping_h
diff --git a/third_party/WebKit/Source/core/animation/SVGInterpolationTypesMap.cpp b/third_party/WebKit/Source/core/animation/SVGInterpolationTypesMap.cpp
new file mode 100644
index 0000000..1aca982
--- /dev/null
+++ b/third_party/WebKit/Source/core/animation/SVGInterpolationTypesMap.cpp
@@ -0,0 +1,166 @@
+// Copyright 2016 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/animation/SVGInterpolationTypesMap.h"
+
+#include "core/HTMLNames.h"
+#include "core/animation/SVGAngleInterpolationType.h"
+#include "core/animation/SVGIntegerInterpolationType.h"
+#include "core/animation/SVGIntegerOptionalIntegerInterpolationType.h"
+#include "core/animation/SVGLengthInterpolationType.h"
+#include "core/animation/SVGLengthListInterpolationType.h"
+#include "core/animation/SVGNumberInterpolationType.h"
+#include "core/animation/SVGNumberListInterpolationType.h"
+#include "core/animation/SVGNumberOptionalNumberInterpolationType.h"
+#include "core/animation/SVGPathInterpolationType.h"
+#include "core/animation/SVGPointListInterpolationType.h"
+#include "core/animation/SVGRectInterpolationType.h"
+#include "core/animation/SVGTransformListInterpolationType.h"
+#include "core/animation/SVGValueInterpolationType.h"
+#include "core/css/CSSPropertyMetadata.h"
+#include "wtf/PtrUtil.h"
+#include <memory>
+
+namespace blink {
+
+const InterpolationTypes& SVGInterpolationTypesMap::get(
+    const PropertyHandle& property) const {
+  using ApplicableTypesMap =
+      HashMap<PropertyHandle, std::unique_ptr<const InterpolationTypes>>;
+  DEFINE_STATIC_LOCAL(ApplicableTypesMap, applicableTypesMap, ());
+  auto entry = applicableTypesMap.find(property);
+  if (entry != applicableTypesMap.end())
+    return *entry->value.get();
+
+  std::unique_ptr<InterpolationTypes> applicableTypes =
+      WTF::makeUnique<InterpolationTypes>();
+
+  const QualifiedName& attribute = property.svgAttribute();
+  if (attribute == SVGNames::orientAttr) {
+    applicableTypes->append(
+        WTF::makeUnique<SVGAngleInterpolationType>(attribute));
+  } else if (attribute == SVGNames::numOctavesAttr ||
+             attribute == SVGNames::targetXAttr ||
+             attribute == SVGNames::targetYAttr) {
+    applicableTypes->append(
+        WTF::makeUnique<SVGIntegerInterpolationType>(attribute));
+  } else if (attribute == SVGNames::orderAttr) {
+    applicableTypes->append(
+        WTF::makeUnique<SVGIntegerOptionalIntegerInterpolationType>(attribute));
+  } else if (attribute == SVGNames::cxAttr || attribute == SVGNames::cyAttr ||
+             attribute == SVGNames::fxAttr || attribute == SVGNames::fyAttr ||
+             attribute == SVGNames::heightAttr ||
+             attribute == SVGNames::markerHeightAttr ||
+             attribute == SVGNames::markerWidthAttr ||
+             attribute == SVGNames::rAttr || attribute == SVGNames::refXAttr ||
+             attribute == SVGNames::refYAttr || attribute == SVGNames::rxAttr ||
+             attribute == SVGNames::ryAttr ||
+             attribute == SVGNames::startOffsetAttr ||
+             attribute == SVGNames::textLengthAttr ||
+             attribute == SVGNames::widthAttr ||
+             attribute == SVGNames::x1Attr || attribute == SVGNames::x2Attr ||
+             attribute == SVGNames::y1Attr || attribute == SVGNames::y2Attr) {
+    applicableTypes->append(
+        WTF::makeUnique<SVGLengthInterpolationType>(attribute));
+  } else if (attribute == SVGNames::dxAttr || attribute == SVGNames::dyAttr) {
+    applicableTypes->append(
+        WTF::makeUnique<SVGNumberInterpolationType>(attribute));
+    applicableTypes->append(
+        WTF::makeUnique<SVGLengthListInterpolationType>(attribute));
+  } else if (attribute == SVGNames::xAttr || attribute == SVGNames::yAttr) {
+    applicableTypes->append(
+        WTF::makeUnique<SVGLengthInterpolationType>(attribute));
+    applicableTypes->append(
+        WTF::makeUnique<SVGLengthListInterpolationType>(attribute));
+  } else if (attribute == SVGNames::amplitudeAttr ||
+             attribute == SVGNames::azimuthAttr ||
+             attribute == SVGNames::biasAttr ||
+             attribute == SVGNames::diffuseConstantAttr ||
+             attribute == SVGNames::divisorAttr ||
+             attribute == SVGNames::elevationAttr ||
+             attribute == SVGNames::exponentAttr ||
+             attribute == SVGNames::interceptAttr ||
+             attribute == SVGNames::k1Attr || attribute == SVGNames::k2Attr ||
+             attribute == SVGNames::k3Attr || attribute == SVGNames::k4Attr ||
+             attribute == SVGNames::limitingConeAngleAttr ||
+             attribute == SVGNames::offsetAttr ||
+             attribute == SVGNames::pathLengthAttr ||
+             attribute == SVGNames::pointsAtXAttr ||
+             attribute == SVGNames::pointsAtYAttr ||
+             attribute == SVGNames::pointsAtZAttr ||
+             attribute == SVGNames::scaleAttr ||
+             attribute == SVGNames::seedAttr ||
+             attribute == SVGNames::slopeAttr ||
+             attribute == SVGNames::specularConstantAttr ||
+             attribute == SVGNames::specularExponentAttr ||
+             attribute == SVGNames::surfaceScaleAttr ||
+             attribute == SVGNames::zAttr) {
+    applicableTypes->append(
+        WTF::makeUnique<SVGNumberInterpolationType>(attribute));
+  } else if (attribute == SVGNames::kernelMatrixAttr ||
+             attribute == SVGNames::rotateAttr ||
+             attribute == SVGNames::tableValuesAttr ||
+             attribute == SVGNames::valuesAttr) {
+    applicableTypes->append(
+        WTF::makeUnique<SVGNumberListInterpolationType>(attribute));
+  } else if (attribute == SVGNames::baseFrequencyAttr ||
+             attribute == SVGNames::kernelUnitLengthAttr ||
+             attribute == SVGNames::radiusAttr ||
+             attribute == SVGNames::stdDeviationAttr) {
+    applicableTypes->append(
+        WTF::makeUnique<SVGNumberOptionalNumberInterpolationType>(attribute));
+  } else if (attribute == SVGNames::dAttr) {
+    applicableTypes->append(
+        WTF::makeUnique<SVGPathInterpolationType>(attribute));
+  } else if (attribute == SVGNames::pointsAttr) {
+    applicableTypes->append(
+        WTF::makeUnique<SVGPointListInterpolationType>(attribute));
+  } else if (attribute == SVGNames::viewBoxAttr) {
+    applicableTypes->append(
+        WTF::makeUnique<SVGRectInterpolationType>(attribute));
+  } else if (attribute == SVGNames::gradientTransformAttr ||
+             attribute == SVGNames::patternTransformAttr ||
+             attribute == SVGNames::transformAttr) {
+    applicableTypes->append(
+        WTF::makeUnique<SVGTransformListInterpolationType>(attribute));
+  } else if (attribute == HTMLNames::classAttr ||
+             attribute == SVGNames::clipPathUnitsAttr ||
+             attribute == SVGNames::edgeModeAttr ||
+             attribute == SVGNames::filterUnitsAttr ||
+             attribute == SVGNames::gradientUnitsAttr ||
+             attribute == SVGNames::hrefAttr || attribute == SVGNames::inAttr ||
+             attribute == SVGNames::in2Attr ||
+             attribute == SVGNames::lengthAdjustAttr ||
+             attribute == SVGNames::markerUnitsAttr ||
+             attribute == SVGNames::maskContentUnitsAttr ||
+             attribute == SVGNames::maskUnitsAttr ||
+             attribute == SVGNames::methodAttr ||
+             attribute == SVGNames::modeAttr ||
+             attribute == SVGNames::operatorAttr ||
+             attribute == SVGNames::patternContentUnitsAttr ||
+             attribute == SVGNames::patternUnitsAttr ||
+             attribute == SVGNames::preserveAlphaAttr ||
+             attribute == SVGNames::preserveAspectRatioAttr ||
+             attribute == SVGNames::primitiveUnitsAttr ||
+             attribute == SVGNames::resultAttr ||
+             attribute == SVGNames::spacingAttr ||
+             attribute == SVGNames::spreadMethodAttr ||
+             attribute == SVGNames::stitchTilesAttr ||
+             attribute == SVGNames::targetAttr ||
+             attribute == SVGNames::typeAttr ||
+             attribute == SVGNames::xChannelSelectorAttr ||
+             attribute == SVGNames::yChannelSelectorAttr) {
+    // Use default SVGValueInterpolationType.
+  } else {
+    NOTREACHED();
+  }
+
+  applicableTypes->append(
+      WTF::makeUnique<SVGValueInterpolationType>(attribute));
+
+  auto addResult = applicableTypesMap.add(property, std::move(applicableTypes));
+  return *addResult.storedValue->value.get();
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/animation/SVGInterpolationTypesMap.h b/third_party/WebKit/Source/core/animation/SVGInterpolationTypesMap.h
new file mode 100644
index 0000000..7de36c0
--- /dev/null
+++ b/third_party/WebKit/Source/core/animation/SVGInterpolationTypesMap.h
@@ -0,0 +1,21 @@
+// Copyright 2016 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 SVGInterpolationTypesMap_h
+#define SVGInterpolationTypesMap_h
+
+#include "core/animation/InterpolationTypesMap.h"
+
+namespace blink {
+
+class SVGInterpolationTypesMap : public InterpolationTypesMap {
+ public:
+  SVGInterpolationTypesMap() {}
+
+  const InterpolationTypes& get(const PropertyHandle&) const final;
+};
+
+}  // namespace blink
+
+#endif  // SVGInterpolationTypesMap_h
diff --git a/third_party/WebKit/Source/core/css/CSSProperties.in b/third_party/WebKit/Source/core/css/CSSProperties.in
index 317166e2..f7b8105 100644
--- a/third_party/WebKit/Source/core/css/CSSProperties.in
+++ b/third_party/WebKit/Source/core/css/CSSProperties.in
@@ -207,7 +207,7 @@
 break-before type_name=EBreak
 break-inside type_name=EBreak
 buffered-rendering svg
-caption-side inherited, keyword_only, keywords=[top|bottom|left|right], initial_keyword=top
+caption-side inherited, keyword_only, independent, keywords=[top|bottom|left|right], initial_keyword=top
 caret-color inherited, custom_all
 clear
 clip interpolable, converter=convertClip, custom_all
diff --git a/third_party/WebKit/Source/core/css/PropertyRegistry.h b/third_party/WebKit/Source/core/css/PropertyRegistry.h
index b9212cb..0c33122 100644
--- a/third_party/WebKit/Source/core/css/PropertyRegistry.h
+++ b/third_party/WebKit/Source/core/css/PropertyRegistry.h
@@ -52,6 +52,7 @@
                         const CSSValue* initial,
                         PassRefPtr<CSSVariableData> initialVariableData);
   const Registration* registration(const AtomicString&) const;
+  size_t registrationCount() const { return m_registrations.size(); }
 
   DEFINE_INLINE_TRACE() { visitor->trace(m_registrations); }
 
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp b/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp
index 7747665..02a6b5c1 100644
--- a/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp
+++ b/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp
@@ -35,6 +35,7 @@
 #include "core/MediaTypeNames.h"
 #include "core/StylePropertyShorthand.h"
 #include "core/animation/AnimationTimeline.h"
+#include "core/animation/CSSInterpolationTypesMap.h"
 #include "core/animation/ElementAnimations.h"
 #include "core/animation/InterpolationEnvironment.h"
 #include "core/animation/InvalidatableInterpolation.h"
@@ -1230,7 +1231,8 @@
       continue;
     const Interpolation& interpolation = *entry.value.front();
     if (interpolation.isInvalidatableInterpolation()) {
-      InterpolationEnvironment environment(state);
+      CSSInterpolationTypesMap map(state.document().propertyRegistry());
+      InterpolationEnvironment environment(map, state);
       InvalidatableInterpolation::applyStack(entry.value, environment);
     } else {
       // TODO(alancutter): Remove this old code path once animations have
diff --git a/third_party/WebKit/Source/core/dom/Node.cpp b/third_party/WebKit/Source/core/dom/Node.cpp
index d5feaa1..fce91f7 100644
--- a/third_party/WebKit/Source/core/dom/Node.cpp
+++ b/third_party/WebKit/Source/core/dom/Node.cpp
@@ -2300,6 +2300,7 @@
 }
 
 HTMLSlotElement* Node::assignedSlot() const {
+  // assignedSlot doesn't need to call updateDistribution().
   DCHECK(!isPseudoElement());
   if (ShadowRoot* root = v1ShadowRootOfParent())
     return root->ensureSlotAssignment().findSlot(*this);
@@ -2307,7 +2308,7 @@
 }
 
 HTMLSlotElement* Node::assignedSlotForBinding() {
-  updateDistribution();
+  // assignedSlot doesn't need to call updateDistribution().
   if (ShadowRoot* root = v1ShadowRootOfParent()) {
     if (root->type() == ShadowRootType::Open)
       return root->ensureSlotAssignment().findSlot(*this);
diff --git a/third_party/WebKit/Source/core/editing/iterators/CharacterIterator.cpp b/third_party/WebKit/Source/core/editing/iterators/CharacterIterator.cpp
index 73404be..19b4b31 100644
--- a/third_party/WebKit/Source/core/editing/iterators/CharacterIterator.cpp
+++ b/third_party/WebKit/Source/core/editing/iterators/CharacterIterator.cpp
@@ -189,6 +189,8 @@
   advance(offset);
   const PositionTemplate<Strategy> startPos = startPosition();
 
+  if (!length)
+    return EphemeralRangeTemplate<Strategy>(startPos, startPos);
   if (length > 1)
     advance(length - 1);
   return EphemeralRangeTemplate<Strategy>(startPos, endPosition());
diff --git a/third_party/WebKit/Source/core/editing/iterators/CharacterIteratorTest.cpp b/third_party/WebKit/Source/core/editing/iterators/CharacterIteratorTest.cpp
index 6fc4293..a5e54ed 100644
--- a/third_party/WebKit/Source/core/editing/iterators/CharacterIteratorTest.cpp
+++ b/third_party/WebKit/Source/core/editing/iterators/CharacterIteratorTest.cpp
@@ -53,4 +53,21 @@
   EXPECT_EQ(Position(textNode, 3), result.endPosition());
 }
 
+TEST_F(CharacterIteratorTest, CollapsedSubrange) {
+  static const char* bodyContent =
+      "<div id='div' contenteditable='true'>hello</div>";
+  setBodyContent(bodyContent);
+  document().view()->updateAllLifecyclePhases();
+
+  Node* textNode = document().getElementById("div")->lastChild();
+  Range* entireRange = Range::create(document(), textNode, 1, textNode, 4);
+  EXPECT_EQ(1, entireRange->startOffset());
+  EXPECT_EQ(4, entireRange->endOffset());
+
+  const EphemeralRange& result =
+      calculateCharacterSubrange(EphemeralRange(entireRange), 2, 0);
+  EXPECT_EQ(Position(textNode, 3), result.startPosition());
+  EXPECT_EQ(Position(textNode, 3), result.endPosition());
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/frame/History.cpp b/third_party/WebKit/Source/core/frame/History.cpp
index ff278e4..470ca160 100644
--- a/third_party/WebKit/Source/core/frame/History.cpp
+++ b/third_party/WebKit/Source/core/frame/History.cpp
@@ -84,7 +84,7 @@
 }
 
 void History::setScrollRestoration(const String& value) {
-  ASSERT(value == "manual" || value == "auto");
+  DCHECK(value == "manual" || value == "auto");
   if (!frame() || !frame()->loader().client())
     return;
 
@@ -133,14 +133,15 @@
   if (!frame() || !frame()->loader().client())
     return;
 
-  ASSERT(isMainThread());
+  DCHECK(isMainThread());
   Document* activeDocument = toDocument(context);
   if (!activeDocument)
     return;
 
   if (!activeDocument->frame() ||
-      !activeDocument->frame()->canNavigate(*frame()))
+      !activeDocument->frame()->canNavigate(*frame())) {
     return;
+  }
   if (!NavigationDisablerForUnload::isNavigationAllowed())
     return;
 
@@ -185,8 +186,9 @@
 
   RefPtr<SecurityOrigin> requestedOrigin = SecurityOrigin::create(url);
   if (requestedOrigin->isUnique() ||
-      !requestedOrigin->isSameSchemeHostPort(documentOrigin))
+      !requestedOrigin->isSameSchemeHostPort(documentOrigin)) {
     return false;
+  }
 
   return true;
 }
diff --git a/third_party/WebKit/Source/core/frame/History.h b/third_party/WebKit/Source/core/frame/History.h
index 11622ba..5c30f08 100644
--- a/third_party/WebKit/Source/core/frame/History.h
+++ b/third_party/WebKit/Source/core/frame/History.h
@@ -42,6 +42,7 @@
 class ExceptionState;
 class SecurityOrigin;
 
+// This class corresponds to the History interface.
 class CORE_EXPORT History final : public GarbageCollectedFinalized<History>,
                                   public ScriptWrappable,
                                   public DOMWindowProperty {
diff --git a/third_party/WebKit/Source/core/frame/Location.cpp b/third_party/WebKit/Source/core/frame/Location.cpp
index bd0a124..dd3626c 100644
--- a/third_party/WebKit/Source/core/frame/Location.cpp
+++ b/third_party/WebKit/Source/core/frame/Location.cpp
@@ -112,8 +112,9 @@
   if (!m_frame)
     return origins;
   for (Frame* frame = m_frame->tree().parent(); frame;
-       frame = frame->tree().parent())
+       frame = frame->tree().parent()) {
     origins->append(frame->securityContext()->getSecurityOrigin()->toString());
+  }
   return origins;
 }
 
@@ -255,7 +256,7 @@
                            LocalDOMWindow* enteredWindow,
                            ExceptionState* exceptionState,
                            SetLocation locationPolicy) {
-  ASSERT(m_frame);
+  DCHECK(m_frame);
   if (!m_frame || !m_frame->host())
     return;
 
@@ -263,11 +264,12 @@
     return;
 
   if (!currentWindow->frame()->canNavigate(*m_frame)) {
-    if (exceptionState)
+    if (exceptionState) {
       exceptionState->throwSecurityError(
           "The current window does not have permission to navigate the target "
           "frame to '" +
           url + "'.");
+    }
     return;
   }
 
diff --git a/third_party/WebKit/Source/core/html/LinkStyle.cpp b/third_party/WebKit/Source/core/html/LinkStyle.cpp
index 9460d3c1..82bb9d8e 100644
--- a/third_party/WebKit/Source/core/html/LinkStyle.cpp
+++ b/third_party/WebKit/Source/core/html/LinkStyle.cpp
@@ -236,40 +236,41 @@
 void LinkStyle::setDisabledState(bool disabled) {
   LinkStyle::DisabledState oldDisabledState = m_disabledState;
   m_disabledState = disabled ? Disabled : EnabledViaScript;
-  if (oldDisabledState != m_disabledState) {
-    // If we change the disabled state while the sheet is still loading, then we
-    // have to perform three checks:
-    if (styleSheetIsLoading()) {
-      // Check #1: The sheet becomes disabled while loading.
-      if (m_disabledState == Disabled)
-        removePendingSheet();
+  if (oldDisabledState == m_disabledState)
+    return;
 
-      // Check #2: An alternate sheet becomes enabled while it is still loading.
-      if (m_owner->relAttribute().isAlternate() &&
-          m_disabledState == EnabledViaScript)
-        addPendingSheet(Blocking);
+  // If we change the disabled state while the sheet is still loading, then we
+  // have to perform three checks:
+  if (styleSheetIsLoading()) {
+    // Check #1: The sheet becomes disabled while loading.
+    if (m_disabledState == Disabled)
+      removePendingSheet();
 
-      // Check #3: A main sheet becomes enabled while it was still loading and
-      // after it was disabled via script. It takes really terrible code to make
-      // this happen (a double toggle for no reason essentially). This happens
-      // on virtualplastic.net, which manages to do about 12 enable/disables on
-      // only 3 sheets. :)
-      if (!m_owner->relAttribute().isAlternate() &&
-          m_disabledState == EnabledViaScript && oldDisabledState == Disabled)
-        addPendingSheet(Blocking);
+    // Check #2: An alternate sheet becomes enabled while it is still loading.
+    if (m_owner->relAttribute().isAlternate() &&
+        m_disabledState == EnabledViaScript)
+      addPendingSheet(Blocking);
 
-      // If the sheet is already loading just bail.
-      return;
-    }
+    // Check #3: A main sheet becomes enabled while it was still loading and
+    // after it was disabled via script. It takes really terrible code to make
+    // this happen (a double toggle for no reason essentially). This happens
+    // on virtualplastic.net, which manages to do about 12 enable/disables on
+    // only 3 sheets. :)
+    if (!m_owner->relAttribute().isAlternate() &&
+        m_disabledState == EnabledViaScript && oldDisabledState == Disabled)
+      addPendingSheet(Blocking);
 
-    if (m_sheet) {
-      m_sheet->setDisabled(disabled);
-      return;
-    }
-
-    if (m_disabledState == EnabledViaScript && m_owner->shouldProcessStyle())
-      process();
+    // If the sheet is already loading just bail.
+    return;
   }
+
+  if (m_sheet) {
+    m_sheet->setDisabled(disabled);
+    return;
+  }
+
+  if (m_disabledState == EnabledViaScript && m_owner->shouldProcessStyle())
+    process();
 }
 
 void LinkStyle::setCrossOriginStylesheetStatus(CSSStyleSheet* sheet) {
@@ -407,7 +408,7 @@
   if (title.isEmpty() || !isUnset() || m_owner->isAlternate())
     return;
 
-  KURL href = m_owner->getNonEmptyURLAttribute(hrefAttr);
+  const KURL& href = m_owner->getNonEmptyURLAttribute(hrefAttr);
   if (href.isValid() && !href.isEmpty()) {
     document().styleEngine().setPreferredStylesheetSetNameIfNotSet(
         title, updateActiveSheets);
diff --git a/third_party/WebKit/Source/core/html/TextControlElement.cpp b/third_party/WebKit/Source/core/html/TextControlElement.cpp
index 91f0510..1b1bf9d 100644
--- a/third_party/WebKit/Source/core/html/TextControlElement.cpp
+++ b/third_party/WebKit/Source/core/html/TextControlElement.cpp
@@ -865,7 +865,7 @@
   return enclosingTextControl(position.computeContainerNode());
 }
 
-TextControlElement* enclosingTextControl(Node* container) {
+TextControlElement* enclosingTextControl(const Node* container) {
   if (!container)
     return nullptr;
   Element* ancestor = container->ownerShadowHost();
diff --git a/third_party/WebKit/Source/core/html/TextControlElement.h b/third_party/WebKit/Source/core/html/TextControlElement.h
index 2d050e2..d95e6a18 100644
--- a/third_party/WebKit/Source/core/html/TextControlElement.h
+++ b/third_party/WebKit/Source/core/html/TextControlElement.h
@@ -223,7 +223,7 @@
 DEFINE_HTMLELEMENT_TYPE_CASTS_WITH_FUNCTION(TextControlElement);
 
 TextControlElement* enclosingTextControl(const Position&);
-TextControlElement* enclosingTextControl(Node*);
+TextControlElement* enclosingTextControl(const Node*);
 
 }  // namespace blink
 
diff --git a/third_party/WebKit/Source/core/layout/BUILD.gn b/third_party/WebKit/Source/core/layout/BUILD.gn
index 8dac83d2..fad269e2 100644
--- a/third_party/WebKit/Source/core/layout/BUILD.gn
+++ b/third_party/WebKit/Source/core/layout/BUILD.gn
@@ -313,6 +313,8 @@
     "ng/ng_layout_opportunity_iterator.h",
     "ng/ng_layout_opportunity_tree_node.cc",
     "ng/ng_layout_opportunity_tree_node.h",
+    "ng/ng_legacy_block_layout_algorithm.cc",
+    "ng/ng_legacy_block_layout_algorithm.h",
     "ng/ng_length_utils.cc",
     "ng/ng_length_utils.h",
     "ng/ng_macros.h",
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
index d8fae61..4369972 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
@@ -180,7 +180,8 @@
     NGBlockNode* first_child,
     NGConstraintSpace* constraint_space,
     NGBreakToken* break_token)
-    : state_(kStateInit),
+    : NGLayoutAlgorithm(kBlockLayoutAlgorithm),
+      state_(kStateInit),
       style_(style),
       first_child_(first_child),
       constraint_space_(constraint_space),
@@ -190,9 +191,9 @@
 }
 
 NGLayoutStatus NGBlockLayoutAlgorithm::Layout(
-    NGFragmentBase*,
+    NGPhysicalFragmentBase* child_fragment,
     NGPhysicalFragmentBase** fragment_out,
-    NGLayoutAlgorithm**) {
+    NGLayoutAlgorithm** algorithm_out) {
   switch (state_) {
     case kStateInit: {
       border_and_padding_ =
@@ -235,14 +236,12 @@
       builder_->SetDirection(constraint_space_->Direction());
       builder_->SetWritingMode(constraint_space_->WritingMode());
       builder_->SetInlineSize(inline_size).SetBlockSize(block_size);
-      current_child_ = first_child_;
-      if (current_child_)
-        space_for_current_child_ = CreateConstraintSpaceForCurrentChild();
 
-      state_ = kStateChildLayout;
+      current_child_ = first_child_;
+      state_ = kStatePrepareForChildLayout;
       return kNotFinished;
     }
-    case kStateChildLayout: {
+    case kStatePrepareForChildLayout: {
       if (current_child_) {
         // TODO(atotic): uncomment this code when implementing oof layout.
         // This code cannot be turned on because it prevents layout of
@@ -253,17 +252,32 @@
         //   GetChildSpaceOffset());
         // }
         // else
-        if (!LayoutCurrentChild())
-          return kNotFinished;
-        current_child_ = current_child_->NextSibling();
-        if (current_child_) {
-          space_for_current_child_ = CreateConstraintSpaceForCurrentChild();
-          return kNotFinished;
-        }
+        space_for_current_child_ = CreateConstraintSpaceForCurrentChild();
+        *algorithm_out = NGLayoutInputNode::AlgorithmForInputNode(
+            current_child_, space_for_current_child_);
+        state_ = kStateChildLayout;
+        return kChildAlgorithmRequired;
       }
+
       state_ = kStateFinalize;
       return kNotFinished;
     }
+    case kStateChildLayout: {
+      DCHECK(current_child_);
+      DCHECK(child_fragment);
+
+      // TODO(layout_ng): Seems like a giant hack to call this here.
+      current_child_->UpdateLayoutBox(toNGPhysicalFragment(child_fragment),
+                                      space_for_current_child_);
+
+      FinishCurrentChildLayout(
+          new NGFragment(space_for_current_child_->WritingMode(),
+                         current_child_->Style()->direction(),
+                         toNGPhysicalFragment(child_fragment)));
+      current_child_ = current_child_->NextSibling();
+      state_ = kStatePrepareForChildLayout;
+      return kNotFinished;
+    }
     case kStateFinalize: {
       content_size_ += border_and_padding_.block_end;
 
@@ -284,11 +298,8 @@
   return kNewFragment;
 }
 
-bool NGBlockLayoutAlgorithm::LayoutCurrentChild() {
-  NGFragmentBase* fragment;
-  if (!current_child_->Layout(space_for_current_child_, &fragment))
-    return false;
-
+void NGBlockLayoutAlgorithm::FinishCurrentChildLayout(
+    NGFragmentBase* fragment) {
   NGBoxStrut child_margins = ComputeMargins(
       *space_for_current_child_, CurrentChildStyle(),
       constraint_space_->WritingMode(), constraint_space_->Direction());
@@ -302,7 +313,6 @@
     fragment_offset = PositionFragment(*fragment, child_margins);
   }
   builder_->AddChild(fragment, fragment_offset);
-  return true;
 }
 
 NGBoxStrut NGBlockLayoutAlgorithm::CollapseMargins(
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h
index e7e7375..c9c4a70 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h
+++ b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h
@@ -36,7 +36,7 @@
                          NGConstraintSpace* space,
                          NGBreakToken* break_token = nullptr);
 
-  NGLayoutStatus Layout(NGFragmentBase*,
+  NGLayoutStatus Layout(NGPhysicalFragmentBase*,
                         NGPhysicalFragmentBase**,
                         NGLayoutAlgorithm**) override;
 
@@ -45,7 +45,7 @@
  private:
   // Creates a new constraint space for the current child.
   NGConstraintSpace* CreateConstraintSpaceForCurrentChild() const;
-  bool LayoutCurrentChild();
+  void FinishCurrentChildLayout(NGFragmentBase* fragment);
 
   // Computes collapsed margins for 2 adjoining blocks and updates the resultant
   // fragment's MarginStrut if needed.
@@ -98,7 +98,12 @@
 
   const ComputedStyle& Style() const { return *style_; }
 
-  enum State { kStateInit, kStateChildLayout, kStateFinalize };
+  enum State {
+    kStateInit,
+    kStatePrepareForChildLayout,
+    kStateChildLayout,
+    kStateFinalize
+  };
   State state_;
 
   RefPtr<const ComputedStyle> style_;
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm_test.cc b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm_test.cc
index 7ba9e05..195b4b0a 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm_test.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm_test.cc
@@ -9,6 +9,7 @@
 #include "core/layout/ng/ng_constraint_space_builder.h"
 #include "core/layout/ng/ng_physical_fragment_base.h"
 #include "core/layout/ng/ng_physical_fragment.h"
+#include "core/layout/ng/ng_layout_coordinator.h"
 #include "core/layout/ng/ng_length_utils.h"
 #include "core/layout/ng/ng_units.h"
 #include "core/style/ComputedStyle.h"
@@ -33,11 +34,18 @@
 
   NGPhysicalFragment* RunBlockLayoutAlgorithm(NGConstraintSpace* space,
                                               NGBlockNode* first_child) {
-    NGBlockLayoutAlgorithm algorithm(style_, first_child, space);
-    NGPhysicalFragmentBase* frag;
-    while (!algorithm.Layout(nullptr, &frag, nullptr))
-      continue;
-    return toNGPhysicalFragment(frag);
+    NGBlockNode parent(style_.get());
+    parent.SetFirstChild(first_child);
+
+    NGLayoutCoordinator coordinator(&parent, space);
+    NGPhysicalFragmentBase* fragment;
+    coordinator.Tick(&fragment);
+    EXPECT_EQ(kBlockLayoutAlgorithm,
+              coordinator.GetAlgorithmStackForTesting()[0]->algorithmType());
+    while (!coordinator.Tick(&fragment))
+      ;
+
+    return toNGPhysicalFragment(fragment);
   }
 
   RefPtr<ComputedStyle> style_;
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_node.cc b/third_party/WebKit/Source/core/layout/ng/ng_block_node.cc
index c9c627e..38a1351a 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_block_node.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_block_node.cc
@@ -61,9 +61,7 @@
 
     fragment_ = toNGPhysicalFragment(fragment);
 
-    if (layout_box_) {
-      CopyFragmentDataToLayoutBox(*constraint_space);
-    }
+    UpdateLayoutBox(fragment_, constraint_space);
   } else {
     DCHECK(layout_box_);
     fragment_ = RunOldLayout(*constraint_space);
@@ -75,6 +73,14 @@
   return true;
 }
 
+void NGBlockNode::UpdateLayoutBox(NGPhysicalFragment* fragment,
+                                  const NGConstraintSpace* constraint_space) {
+  fragment_ = fragment;
+  if (layout_box_) {
+    CopyFragmentDataToLayoutBox(*constraint_space);
+  }
+}
+
 bool NGBlockNode::ComputeMinAndMaxContentSizes(MinAndMaxContentSizes* sizes) {
   if (!CanUseNewLayout()) {
     DCHECK(layout_box_);
@@ -94,19 +100,14 @@
   }
   DCHECK(!layout_coordinator_)
       << "Can't interleave Layout and ComputeMinAndMaxContentSizes";
+
+  NGConstraintSpace* constraint_space =
+      NGConstraintSpaceBuilder(
+          FromPlatformWritingMode(Style()->getWritingMode()))
+          .SetTextDirection(Style()->direction())
+          .ToConstraintSpace();
+
   if (!minmax_algorithm_) {
-    NGConstraintSpaceBuilder builder(
-        FromPlatformWritingMode(Style()->getWritingMode()));
-
-    builder.SetAvailableSize(NGLogicalSize(LayoutUnit(), LayoutUnit()));
-    builder.SetPercentageResolutionSize(
-        NGLogicalSize(LayoutUnit(), LayoutUnit()));
-    NGConstraintSpace* constraint_space =
-        NGConstraintSpaceBuilder(
-            FromPlatformWritingMode(Style()->getWritingMode()))
-            .SetTextDirection(Style()->direction())
-            .ToConstraintSpace();
-
     minmax_algorithm_ = new NGBlockLayoutAlgorithm(
         Style(), toNGBlockNode(FirstChild()), constraint_space);
   }
@@ -122,9 +123,12 @@
   // TODO(cbiesinger): Replace the loops below with a state machine like in
   // Layout.
 
+  NGLayoutCoordinator* minmax_coordinator =
+      new NGLayoutCoordinator(this, constraint_space);
+
   // Have to synthesize this value.
   NGPhysicalFragmentBase* physical_fragment;
-  while (!minmax_algorithm_->Layout(nullptr, &physical_fragment, nullptr))
+  while (!minmax_coordinator->Tick(&physical_fragment))
     continue;
   NGFragment* fragment = new NGFragment(
       FromPlatformWritingMode(Style()->getWritingMode()), Style()->direction(),
@@ -133,7 +137,7 @@
   sizes->min_content = fragment->InlineOverflow();
 
   // Now, redo with infinite space for max_content
-  NGConstraintSpace* constraint_space =
+  constraint_space =
       NGConstraintSpaceBuilder(
           FromPlatformWritingMode(Style()->getWritingMode()))
           .SetTextDirection(Style()->direction())
@@ -141,9 +145,8 @@
           .SetPercentageResolutionSize({LayoutUnit(), LayoutUnit()})
           .ToConstraintSpace();
 
-  minmax_algorithm_ = new NGBlockLayoutAlgorithm(
-      Style(), toNGBlockNode(FirstChild()), constraint_space);
-  while (!minmax_algorithm_->Layout(nullptr, &physical_fragment, nullptr))
+  minmax_coordinator = new NGLayoutCoordinator(this, constraint_space);
+  while (!minmax_coordinator->Tick(&physical_fragment))
     continue;
 
   fragment = new NGFragment(FromPlatformWritingMode(Style()->getWritingMode()),
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_node.h b/third_party/WebKit/Source/core/layout/ng/ng_block_node.h
index d23ea7b..49513cd 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_block_node.h
+++ b/third_party/WebKit/Source/core/layout/ng/ng_block_node.h
@@ -57,6 +57,13 @@
 
   DECLARE_VIRTUAL_TRACE();
 
+  // Runs layout on layout_box_ and creates a fragment for the resulting
+  // geometry.
+  NGPhysicalFragment* RunOldLayout(const NGConstraintSpace&);
+
+  void UpdateLayoutBox(NGPhysicalFragment* fragment,
+                       const NGConstraintSpace* constraint_space);
+
  private:
   // This is necessary for interop between old and new trees -- after our parent
   // positions us, it calls this function so we can store the position on the
@@ -70,10 +77,6 @@
   // data to the layout box.
   void CopyFragmentDataToLayoutBox(const NGConstraintSpace&);
 
-  // Runs layout on layout_box_ and creates a fragment for the resulting
-  // geometry.
-  NGPhysicalFragment* RunOldLayout(const NGConstraintSpace&);
-
   // We can either wrap a layout_box_ or a style_/next_sibling_/first_child_
   // combination.
   LayoutBox* layout_box_;
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_inline_layout_algorithm.cc b/third_party/WebKit/Source/core/layout/ng/ng_inline_layout_algorithm.cc
index 1cbd272..55c3995 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_inline_layout_algorithm.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_inline_layout_algorithm.cc
@@ -18,7 +18,8 @@
     NGInlineNode* first_child,
     NGConstraintSpace* constraint_space,
     NGBreakToken* break_token)
-    : style_(style),
+    : NGLayoutAlgorithm(kInlineLayoutAlgorithm),
+      style_(style),
       first_child_(first_child),
       constraint_space_(constraint_space),
       break_token_(break_token) {
@@ -26,7 +27,7 @@
 }
 
 NGLayoutStatus NGInlineLayoutAlgorithm::Layout(
-    NGFragmentBase*,
+    NGPhysicalFragmentBase*,
     NGPhysicalFragmentBase** fragment_out,
     NGLayoutAlgorithm**) {
   NGFragmentBuilder builder(NGPhysicalFragmentBase::kFragmentBox);
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_inline_layout_algorithm.h b/third_party/WebKit/Source/core/layout/ng/ng_inline_layout_algorithm.h
index 31589fe2..eb96187 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_inline_layout_algorithm.h
+++ b/third_party/WebKit/Source/core/layout/ng/ng_inline_layout_algorithm.h
@@ -35,7 +35,7 @@
                           NGConstraintSpace* space,
                           NGBreakToken* break_token = nullptr);
 
-  NGLayoutStatus Layout(NGFragmentBase*,
+  NGLayoutStatus Layout(NGPhysicalFragmentBase*,
                         NGPhysicalFragmentBase**,
                         NGLayoutAlgorithm**) override;
 
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_layout_algorithm.h b/third_party/WebKit/Source/core/layout/ng/ng_layout_algorithm.h
index 9c1e9b3..e90fcb57 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_layout_algorithm.h
+++ b/third_party/WebKit/Source/core/layout/ng/ng_layout_algorithm.h
@@ -15,18 +15,24 @@
 struct MinAndMaxContentSizes;
 class NGBlockNode;
 class NGConstraintSpace;
-class NGFragmentBase;
 class NGPhysicalFragmentBase;
 
 enum NGLayoutStatus { kNotFinished, kChildAlgorithmRequired, kNewFragment };
 
+enum NGLayoutAlgorithmType {
+  kBlockLayoutAlgorithm,
+  kInlineLayoutAlgorithm,
+  kLegacyBlockLayoutAlgorithm,
+  kTextLayoutAlgorithm
+};
+
 // Base class for all LayoutNG algorithms.
 class CORE_EXPORT NGLayoutAlgorithm
     : public GarbageCollectedFinalized<NGLayoutAlgorithm> {
   WTF_MAKE_NONCOPYABLE(NGLayoutAlgorithm);
 
  public:
-  NGLayoutAlgorithm() {}
+  NGLayoutAlgorithm(NGLayoutAlgorithmType type) : type_(type) {}
   virtual ~NGLayoutAlgorithm() {}
 
   // Actual layout function. Lays out the children and descendents within the
@@ -39,7 +45,7 @@
   // be set with the NGBlockNode that needs to be layed out next.
   // If it returns NewFragment, the NGPhysicalFragmentBase out parameter
   // will contain the new fragment.
-  virtual NGLayoutStatus Layout(NGFragmentBase*,
+  virtual NGLayoutStatus Layout(NGPhysicalFragmentBase*,
                                 NGPhysicalFragmentBase**,
                                 NGLayoutAlgorithm**) = 0;
 
@@ -58,6 +64,11 @@
   }
 
   DEFINE_INLINE_VIRTUAL_TRACE() {}
+
+  NGLayoutAlgorithmType algorithmType() const { return type_; }
+
+ private:
+  NGLayoutAlgorithmType type_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_layout_coordinator.cc b/third_party/WebKit/Source/core/layout/ng/ng_layout_coordinator.cc
index 15adc8a..3876200 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_layout_coordinator.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_layout_coordinator.cc
@@ -5,6 +5,7 @@
 #include "core/layout/ng/ng_layout_coordinator.h"
 
 #include "core/layout/ng/ng_layout_input_node.h"
+#include "core/layout/ng/ng_physical_fragment_base.h"
 
 namespace blink {
 
@@ -15,20 +16,28 @@
       NGLayoutInputNode::AlgorithmForInputNode(input_node, constraint_space));
 }
 
-bool NGLayoutCoordinator::Tick(NGPhysicalFragmentBase** fragment) {
+bool NGLayoutCoordinator::Tick(NGPhysicalFragmentBase** out_fragment) {
   NGLayoutAlgorithm* child_algorithm;
 
   // Tick should never be called without a layout algorithm on the stack.
   DCHECK(layout_algorithms_.size());
 
-  // TODO(layout-dev): store box from last tick and pass it into Layout here.
-  switch (
-      layout_algorithms_.back()->Layout(nullptr, fragment, &child_algorithm)) {
+  NGPhysicalFragmentBase* fragment;
+  NGPhysicalFragmentBase* in_fragment = fragment_;
+  fragment_ = nullptr;
+
+  switch (layout_algorithms_.back()->Layout(in_fragment, &fragment,
+                                            &child_algorithm)) {
     case kNotFinished:
       return false;
     case kNewFragment:
       layout_algorithms_.pop_back();
-      return (layout_algorithms_.size() == 0);
+      if (layout_algorithms_.size() == 0) {
+        *out_fragment = fragment;
+        return true;
+      }
+      fragment_ = fragment;
+      return false;
     case kChildAlgorithmRequired:
       layout_algorithms_.append(child_algorithm);
       return false;
@@ -40,5 +49,6 @@
 
 DEFINE_TRACE(NGLayoutCoordinator) {
   visitor->trace(layout_algorithms_);
+  visitor->trace(fragment_);
 }
 }
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_layout_coordinator.h b/third_party/WebKit/Source/core/layout/ng/ng_layout_coordinator.h
index b4f8628e..6926e1d 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_layout_coordinator.h
+++ b/third_party/WebKit/Source/core/layout/ng/ng_layout_coordinator.h
@@ -24,8 +24,14 @@
 
   DECLARE_TRACE()
 
+  const HeapVector<Member<NGLayoutAlgorithm>>& GetAlgorithmStackForTesting()
+      const {
+    return layout_algorithms_;
+  };
+
  private:
   HeapVector<Member<NGLayoutAlgorithm>> layout_algorithms_;
+  Member<NGPhysicalFragmentBase> fragment_;
 };
 }
 
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_layout_input_node.cc b/third_party/WebKit/Source/core/layout/ng/ng_layout_input_node.cc
index 71273e9d..6a0798d 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_layout_input_node.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_layout_input_node.cc
@@ -10,6 +10,7 @@
 #include "core/layout/ng/ng_inline_node.h"
 #include "core/layout/ng/ng_inline_layout_algorithm.h"
 #include "core/layout/ng/ng_layout_algorithm.h"
+#include "core/layout/ng/ng_legacy_block_layout_algorithm.h"
 #include "core/style/ComputedStyle.h"
 
 namespace blink {
@@ -23,12 +24,16 @@
   DCHECK(input_node->Type() == kLegacyBlock);
   NGBlockNode* block = toNGBlockNode(input_node);
 
-  if (block->HasInlineChildren())
-    return new NGInlineLayoutAlgorithm(
-        block->Style(), toNGInlineNode(block->FirstChild()),
+  if (block->CanUseNewLayout()) {
+    if (block->HasInlineChildren())
+      return new NGInlineLayoutAlgorithm(
+          block->Style(), toNGInlineNode(block->FirstChild()),
+          constraint_space->ChildSpace(block->Style()));
+    return new NGBlockLayoutAlgorithm(
+        block->Style(), toNGBlockNode(block->FirstChild()),
         constraint_space->ChildSpace(block->Style()));
-  return new NGBlockLayoutAlgorithm(
-      block->Style(), toNGBlockNode(block->FirstChild()),
-      constraint_space->ChildSpace(block->Style()));
+  }
+
+  return new NGLegacyBlockLayoutAlgorithm(block, constraint_space);
 }
 }
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_legacy_block_layout_algorithm.cc b/third_party/WebKit/Source/core/layout/ng/ng_legacy_block_layout_algorithm.cc
new file mode 100644
index 0000000..015213d
--- /dev/null
+++ b/third_party/WebKit/Source/core/layout/ng/ng_legacy_block_layout_algorithm.cc
@@ -0,0 +1,31 @@
+// Copyright 2016 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/layout/ng/ng_legacy_block_layout_algorithm.h"
+
+#include "core/layout/ng/ng_physical_fragment.h"
+
+namespace blink {
+
+NGLegacyBlockLayoutAlgorithm::NGLegacyBlockLayoutAlgorithm(
+    NGBlockNode* block,
+    const NGConstraintSpace* constraint_space)
+    : NGLayoutAlgorithm(kLegacyBlockLayoutAlgorithm),
+      block_(block),
+      constraint_space_(constraint_space) {}
+
+NGLayoutStatus NGLegacyBlockLayoutAlgorithm::Layout(
+    NGPhysicalFragmentBase*,
+    NGPhysicalFragmentBase** fragment_out,
+    NGLayoutAlgorithm**) {
+  *fragment_out = block_->RunOldLayout(*constraint_space_);
+  return kNewFragment;
+}
+
+DEFINE_TRACE(NGLegacyBlockLayoutAlgorithm) {
+  NGLayoutAlgorithm::trace(visitor);
+  visitor->trace(block_);
+  visitor->trace(constraint_space_);
+}
+}
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_legacy_block_layout_algorithm.h b/third_party/WebKit/Source/core/layout/ng/ng_legacy_block_layout_algorithm.h
new file mode 100644
index 0000000..c0147c1
--- /dev/null
+++ b/third_party/WebKit/Source/core/layout/ng/ng_legacy_block_layout_algorithm.h
@@ -0,0 +1,34 @@
+// Copyright 2016 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 NGLegacyBlockLayoutAlgorithm_h
+#define NGLegacyBlockLayoutAlgorithm_h
+
+#include "core/CoreExport.h"
+#include "core/layout/ng/ng_block_node.h"
+#include "core/layout/ng/ng_constraint_space.h"
+#include "core/layout/ng/ng_layout_algorithm.h"
+#include "wtf/RefPtr.h"
+
+namespace blink {
+
+// A class for legacy block layout (blocks that can't be handled by NG yet).
+// Defers to the old layout method of the block
+class CORE_EXPORT NGLegacyBlockLayoutAlgorithm : public NGLayoutAlgorithm {
+ public:
+  NGLegacyBlockLayoutAlgorithm(NGBlockNode*, const NGConstraintSpace*);
+
+  NGLayoutStatus Layout(NGPhysicalFragmentBase*,
+                        NGPhysicalFragmentBase**,
+                        NGLayoutAlgorithm**) override;
+
+  DECLARE_VIRTUAL_TRACE();
+
+ private:
+  Member<NGBlockNode> block_;
+  Member<const NGConstraintSpace> constraint_space_;
+};
+}
+
+#endif  // NGLegacyBlockLayoutAlgorithm_h
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_text_layout_algorithm.cc b/third_party/WebKit/Source/core/layout/ng/ng_text_layout_algorithm.cc
index 4de2cda..f72caec 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_text_layout_algorithm.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_text_layout_algorithm.cc
@@ -14,14 +14,15 @@
     NGInlineNode* inline_box,
     NGConstraintSpace* constraint_space,
     NGBreakToken* break_token)
-    : inline_box_(inline_box),
+    : NGLayoutAlgorithm(kTextLayoutAlgorithm),
+      inline_box_(inline_box),
       constraint_space_(constraint_space),
       break_token_(break_token) {
   DCHECK(inline_box_);
 }
 
 NGLayoutStatus NGTextLayoutAlgorithm::Layout(
-    NGFragmentBase*,
+    NGPhysicalFragmentBase*,
     NGPhysicalFragmentBase** fragment_out,
     NGLayoutAlgorithm**) {
   // TODO(layout-dev): implement.
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_text_layout_algorithm.h b/third_party/WebKit/Source/core/layout/ng/ng_text_layout_algorithm.h
index 2150df5..c286ffb 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_text_layout_algorithm.h
+++ b/third_party/WebKit/Source/core/layout/ng/ng_text_layout_algorithm.h
@@ -30,7 +30,7 @@
                         NGConstraintSpace* space,
                         NGBreakToken* break_token = nullptr);
 
-  NGLayoutStatus Layout(NGFragmentBase*,
+  NGLayoutStatus Layout(NGPhysicalFragmentBase*,
                         NGPhysicalFragmentBase**,
                         NGLayoutAlgorithm**) override;
 
diff --git a/third_party/WebKit/Source/core/svg/SVGElement.cpp b/third_party/WebKit/Source/core/svg/SVGElement.cpp
index 6c7113ac..41faa266 100644
--- a/third_party/WebKit/Source/core/svg/SVGElement.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGElement.cpp
@@ -33,6 +33,7 @@
 #include "core/animation/ElementAnimations.h"
 #include "core/animation/InterpolationEnvironment.h"
 #include "core/animation/InvalidatableInterpolation.h"
+#include "core/animation/SVGInterpolationTypesMap.h"
 #include "core/css/CSSCursorImageValue.h"
 #include "core/css/resolver/StyleResolver.h"
 #include "core/dom/Document.h"
@@ -234,8 +235,9 @@
           KeyframeEffectReadOnly::DefaultPriority, isSVGAttributeHandle);
   for (auto& entry : activeInterpolationsMap) {
     const QualifiedName& attribute = entry.key.svgAttribute();
+    SVGInterpolationTypesMap map;
     InterpolationEnvironment environment(
-        *this, propertyFromAttribute(attribute)->baseValueBase());
+        map, *this, propertyFromAttribute(attribute)->baseValueBase());
     InvalidatableInterpolation::applyStack(entry.value, environment);
   }
   svgRareData()->setWebAnimatedAttributesDirty(false);
diff --git a/third_party/WebKit/Source/core/workers/BUILD.gn b/third_party/WebKit/Source/core/workers/BUILD.gn
index db516ceb..073e6975 100644
--- a/third_party/WebKit/Source/core/workers/BUILD.gn
+++ b/third_party/WebKit/Source/core/workers/BUILD.gn
@@ -35,6 +35,8 @@
     "SharedWorkerThread.h",
     "ThreadedMessagingProxyBase.cpp",
     "ThreadedMessagingProxyBase.h",
+    "ThreadedObjectProxyBase.cpp",
+    "ThreadedObjectProxyBase.h",
     "ThreadedWorkletGlobalScope.cpp",
     "ThreadedWorkletGlobalScope.h",
     "ThreadedWorkletMessagingProxy.cpp",
diff --git a/third_party/WebKit/Source/core/workers/InProcessWorkerObjectProxy.cpp b/third_party/WebKit/Source/core/workers/InProcessWorkerObjectProxy.cpp
index 720bd9d..0a5aa09 100644
--- a/third_party/WebKit/Source/core/workers/InProcessWorkerObjectProxy.cpp
+++ b/third_party/WebKit/Source/core/workers/InProcessWorkerObjectProxy.cpp
@@ -97,6 +97,8 @@
 }
 
 void InProcessWorkerObjectProxy::countFeature(UseCounter::Feature feature) {
+  // TODO(nhiroki): Move this to ThreadedObjectProxyBase so that
+  // ThreadedWorklets can record API use (https://crbug.com/667357).
   getParentFrameTaskRunners()
       ->get(TaskType::Internal)
       ->postTask(BLINK_FROM_HERE,
@@ -105,6 +107,8 @@
 }
 
 void InProcessWorkerObjectProxy::countDeprecation(UseCounter::Feature feature) {
+  // TODO(nhiroki): Move this to ThreadedObjectProxyBase so that
+  // ThreadedWorklets can record API use (https://crbug.com/667357).
   getParentFrameTaskRunners()
       ->get(TaskType::Internal)
       ->postTask(
@@ -126,37 +130,6 @@
                           WTF::passed(location->clone()), exceptionId));
 }
 
-void InProcessWorkerObjectProxy::reportConsoleMessage(
-    MessageSource source,
-    MessageLevel level,
-    const String& message,
-    SourceLocation* location) {
-  getParentFrameTaskRunners()
-      ->get(TaskType::Internal)
-      ->postTask(
-          BLINK_FROM_HERE,
-          crossThreadBind(&InProcessWorkerMessagingProxy::reportConsoleMessage,
-                          m_messagingProxyWeakPtr, source, level, message,
-                          WTF::passed(location->clone())));
-}
-
-void InProcessWorkerObjectProxy::postMessageToPageInspector(
-    const String& message) {
-  // The TaskType of Inspector tasks need to be Unthrottled because they need to
-  // run even on a suspended page.
-  getParentFrameTaskRunners()
-      ->get(TaskType::Unthrottled)
-      ->postTask(BLINK_FROM_HERE,
-                 crossThreadBind(
-                     &InProcessWorkerMessagingProxy::postMessageToPageInspector,
-                     m_messagingProxyWeakPtr, message));
-}
-
-ParentFrameTaskRunners*
-InProcessWorkerObjectProxy::getParentFrameTaskRunners() {
-  return m_parentFrameTaskRunners.get();
-}
-
 void InProcessWorkerObjectProxy::didCreateWorkerGlobalScope(
     WorkerOrWorkletGlobalScope* globalScope) {
   DCHECK(!m_workerGlobalScope);
@@ -169,35 +142,16 @@
   startPendingActivityTimer();
 }
 
-void InProcessWorkerObjectProxy::didCloseWorkerGlobalScope() {
-  getParentFrameTaskRunners()
-      ->get(TaskType::Internal)
-      ->postTask(
-          BLINK_FROM_HERE,
-          crossThreadBind(&InProcessWorkerMessagingProxy::terminateGlobalScope,
-                          m_messagingProxyWeakPtr));
-}
-
 void InProcessWorkerObjectProxy::willDestroyWorkerGlobalScope() {
   m_timer.reset();
   m_workerGlobalScope = nullptr;
 }
 
-void InProcessWorkerObjectProxy::didTerminateWorkerThread() {
-  // This will terminate the MessagingProxy.
-  getParentFrameTaskRunners()
-      ->get(TaskType::Internal)
-      ->postTask(BLINK_FROM_HERE,
-                 crossThreadBind(
-                     &InProcessWorkerMessagingProxy::workerThreadTerminated,
-                     m_messagingProxyWeakPtr));
-}
-
 InProcessWorkerObjectProxy::InProcessWorkerObjectProxy(
     const WeakPtr<InProcessWorkerMessagingProxy>& messagingProxyWeakPtr,
     ParentFrameTaskRunners* parentFrameTaskRunners)
-    : m_messagingProxyWeakPtr(messagingProxyWeakPtr),
-      m_parentFrameTaskRunners(parentFrameTaskRunners),
+    : ThreadedObjectProxyBase(parentFrameTaskRunners),
+      m_messagingProxyWeakPtr(messagingProxyWeakPtr),
       m_defaultIntervalInSec(kDefaultIntervalInSec),
       m_nextIntervalInSec(kDefaultIntervalInSec),
       m_maxIntervalInSec(kMaxIntervalInSec) {}
@@ -224,4 +178,9 @@
   startPendingActivityTimer();
 }
 
+WeakPtr<ThreadedMessagingProxyBase>
+InProcessWorkerObjectProxy::messagingProxyWeakPtr() {
+  return m_messagingProxyWeakPtr;
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/workers/InProcessWorkerObjectProxy.h b/third_party/WebKit/Source/core/workers/InProcessWorkerObjectProxy.h
index 280f32f9..1a226509 100644
--- a/third_party/WebKit/Source/core/workers/InProcessWorkerObjectProxy.h
+++ b/third_party/WebKit/Source/core/workers/InProcessWorkerObjectProxy.h
@@ -33,6 +33,7 @@
 
 #include "core/CoreExport.h"
 #include "core/dom/MessagePort.h"
+#include "core/workers/ThreadedObjectProxyBase.h"
 #include "core/workers/WorkerReportingProxy.h"
 #include "platform/Timer.h"
 #include "platform/heap/Handle.h"
@@ -44,18 +45,16 @@
 
 class InProcessWorkerMessagingProxy;
 class ParentFrameTaskRunners;
+class ThreadedMessagingProxyBase;
 class WorkerGlobalScope;
 class WorkerOrWorkletGlobalScope;
 
-// A proxy to talk to the parent worker object. This object is created and
-// destroyed on the parent context thread (i.e. usually the main thread), and
-// used on the worker thread for proxying messages to the
-// InProcessWorkerMessagingProxy on the parent context thread.
-// InProcessWorkerMessagingProxy always outlives this proxy.
+// A proxy to talk to the parent worker object. See class comments on
+// ThreadedObjectProxyBase.h for lifetime of this class etc.
 //
 // This also checks pending activities on WorkerGlobalScope and reports a result
 // to the message proxy when an exponential backoff timer is fired.
-class CORE_EXPORT InProcessWorkerObjectProxy : public WorkerReportingProxy {
+class CORE_EXPORT InProcessWorkerObjectProxy : public ThreadedObjectProxyBase {
   USING_FAST_MALLOC(InProcessWorkerObjectProxy);
   WTF_MAKE_NONCOPYABLE(InProcessWorkerObjectProxy);
 
@@ -70,28 +69,22 @@
   void confirmMessageFromWorkerObject();
   void startPendingActivityTimer();
 
-  // WorkerReportingProxy overrides.
-  void countFeature(UseCounter::Feature) override;
-  void countDeprecation(UseCounter::Feature) override;
+  // ThreadedMessagingProxyBase overrides.
+  void countFeature(UseCounter::Feature) final;
+  void countDeprecation(UseCounter::Feature) final;
   void reportException(const String& errorMessage,
                        std::unique_ptr<SourceLocation>,
                        int exceptionId) override;
-  void reportConsoleMessage(MessageSource,
-                            MessageLevel,
-                            const String& message,
-                            SourceLocation*) override;
-  void postMessageToPageInspector(const String&) override;
-  ParentFrameTaskRunners* getParentFrameTaskRunners() override;
   void didCreateWorkerGlobalScope(WorkerOrWorkletGlobalScope*) override;
   void didEvaluateWorkerScript(bool success) override;
-  void didCloseWorkerGlobalScope() override;
   void willDestroyWorkerGlobalScope() override;
-  void didTerminateWorkerThread() override;
 
  protected:
   InProcessWorkerObjectProxy(const WeakPtr<InProcessWorkerMessagingProxy>&,
                              ParentFrameTaskRunners*);
 
+  WeakPtr<ThreadedMessagingProxyBase> messagingProxyWeakPtr() final;
+
  private:
   friend class InProcessWorkerMessagingProxyForTest;
 
@@ -102,10 +95,6 @@
   // the tasks.
   WeakPtr<InProcessWorkerMessagingProxy> m_messagingProxyWeakPtr;
 
-  // Used to post a task to InProcessWorkerMessagingProxy on the parent context
-  // thread.
-  CrossThreadPersistent<ParentFrameTaskRunners> m_parentFrameTaskRunners;
-
   // Used for checking pending activities on the worker global scope. This is
   // cancelled when the worker global scope is destroyed.
   std::unique_ptr<Timer<InProcessWorkerObjectProxy>> m_timer;
diff --git a/third_party/WebKit/Source/core/workers/ThreadedObjectProxyBase.cpp b/third_party/WebKit/Source/core/workers/ThreadedObjectProxyBase.cpp
new file mode 100644
index 0000000..29b67952e
--- /dev/null
+++ b/third_party/WebKit/Source/core/workers/ThreadedObjectProxyBase.cpp
@@ -0,0 +1,71 @@
+// Copyright 2016 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/ThreadedObjectProxyBase.h"
+
+#include "core/dom/ExecutionContext.h"
+#include "core/inspector/ConsoleMessage.h"
+#include "core/workers/ParentFrameTaskRunners.h"
+#include "core/workers/ThreadedMessagingProxyBase.h"
+#include "platform/CrossThreadFunctional.h"
+#include "platform/WebTaskRunner.h"
+#include "wtf/Functional.h"
+#include "wtf/PtrUtil.h"
+#include <memory>
+
+namespace blink {
+
+void ThreadedObjectProxyBase::reportConsoleMessage(MessageSource source,
+                                                   MessageLevel level,
+                                                   const String& message,
+                                                   SourceLocation* location) {
+  getParentFrameTaskRunners()
+      ->get(TaskType::Internal)
+      ->postTask(
+          BLINK_FROM_HERE,
+          crossThreadBind(&ThreadedMessagingProxyBase::reportConsoleMessage,
+                          messagingProxyWeakPtr(), source, level, message,
+                          WTF::passed(location->clone())));
+}
+
+void ThreadedObjectProxyBase::postMessageToPageInspector(
+    const String& message) {
+  // The TaskType of Inspector tasks need to be Unthrottled because they need to
+  // run even on a suspended page.
+  getParentFrameTaskRunners()
+      ->get(TaskType::Unthrottled)
+      ->postTask(BLINK_FROM_HERE,
+                 crossThreadBind(
+                     &ThreadedMessagingProxyBase::postMessageToPageInspector,
+                     messagingProxyWeakPtr(), message));
+}
+
+ParentFrameTaskRunners* ThreadedObjectProxyBase::getParentFrameTaskRunners() {
+  return m_parentFrameTaskRunners.get();
+}
+
+void ThreadedObjectProxyBase::didCloseWorkerGlobalScope() {
+  getParentFrameTaskRunners()
+      ->get(TaskType::Internal)
+      ->postTask(
+          BLINK_FROM_HERE,
+          crossThreadBind(&ThreadedMessagingProxyBase::terminateGlobalScope,
+                          messagingProxyWeakPtr()));
+}
+
+void ThreadedObjectProxyBase::didTerminateWorkerThread() {
+  // This will terminate the MessagingProxy.
+  getParentFrameTaskRunners()
+      ->get(TaskType::Internal)
+      ->postTask(
+          BLINK_FROM_HERE,
+          crossThreadBind(&ThreadedMessagingProxyBase::workerThreadTerminated,
+                          messagingProxyWeakPtr()));
+}
+
+ThreadedObjectProxyBase::ThreadedObjectProxyBase(
+    ParentFrameTaskRunners* parentFrameTaskRunners)
+    : m_parentFrameTaskRunners(parentFrameTaskRunners) {}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/workers/ThreadedObjectProxyBase.h b/third_party/WebKit/Source/core/workers/ThreadedObjectProxyBase.h
new file mode 100644
index 0000000..9bc7176
--- /dev/null
+++ b/third_party/WebKit/Source/core/workers/ThreadedObjectProxyBase.h
@@ -0,0 +1,54 @@
+// Copyright 2016 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 ThreadedObjectProxyBase_h
+#define ThreadedObjectProxyBase_h
+
+#include "bindings/core/v8/SourceLocation.h"
+#include "core/CoreExport.h"
+#include "core/dom/MessagePort.h"
+#include "core/workers/WorkerReportingProxy.h"
+
+namespace blink {
+
+class ThreadedMessagingProxyBase;
+
+// A proxy to talk to the parent object. This object is created and destroyed on
+// the main thread, and used on the worker thread for proxying messages to the
+// ThreadedMessagingProxyBase on the main thread. ThreadedMessagingProxyBase
+// always outlives this proxy.
+class CORE_EXPORT ThreadedObjectProxyBase : public WorkerReportingProxy {
+  USING_FAST_MALLOC(ThreadedObjectProxyBase);
+  WTF_MAKE_NONCOPYABLE(ThreadedObjectProxyBase);
+
+ public:
+  ~ThreadedObjectProxyBase() override = default;
+
+  void reportPendingActivity(bool hasPendingActivity);
+
+  // WorkerReportingProxy overrides.
+  void countFeature(UseCounter::Feature) override{};
+  void countDeprecation(UseCounter::Feature) override{};
+  void reportConsoleMessage(MessageSource,
+                            MessageLevel,
+                            const String& message,
+                            SourceLocation*) override;
+  void postMessageToPageInspector(const String&) override;
+  ParentFrameTaskRunners* getParentFrameTaskRunners() override;
+  void didCloseWorkerGlobalScope() override;
+  void didTerminateWorkerThread() override;
+
+ protected:
+  explicit ThreadedObjectProxyBase(ParentFrameTaskRunners*);
+  virtual WeakPtr<ThreadedMessagingProxyBase> messagingProxyWeakPtr() = 0;
+
+ private:
+  // Used to post a task to ThreadedMessagingProxyBase on the parent context
+  // thread.
+  CrossThreadPersistent<ParentFrameTaskRunners> m_parentFrameTaskRunners;
+};
+
+}  // namespace blink
+
+#endif  // ThreadedObjectProxyBase_h
diff --git a/third_party/WebKit/Source/core/workers/ThreadedWorkletObjectProxy.cpp b/third_party/WebKit/Source/core/workers/ThreadedWorkletObjectProxy.cpp
index b2b3a03..4bee693 100644
--- a/third_party/WebKit/Source/core/workers/ThreadedWorkletObjectProxy.cpp
+++ b/third_party/WebKit/Source/core/workers/ThreadedWorkletObjectProxy.cpp
@@ -4,13 +4,7 @@
 
 #include "core/workers/ThreadedWorkletObjectProxy.h"
 
-#include "core/dom/ExecutionContext.h"
-#include "core/inspector/ConsoleMessage.h"
-#include "core/workers/ParentFrameTaskRunners.h"
 #include "core/workers/ThreadedWorkletMessagingProxy.h"
-#include "platform/CrossThreadFunctional.h"
-#include "platform/WebTaskRunner.h"
-#include "wtf/Functional.h"
 #include "wtf/PtrUtil.h"
 #include <memory>
 
@@ -28,73 +22,15 @@
   DCHECK(m_messagingProxyWeakPtr);
 }
 
-void ThreadedWorkletObjectProxy::countFeature(UseCounter::Feature) {
-  // TODO(nhiroki): Support UseCounter for ThreadedWorklets. We could do the
-  // same thing with InProcessWorkerObjectProxy here.
-  // (https://crbug.com/376039)
-}
-
-void ThreadedWorkletObjectProxy::countDeprecation(UseCounter::Feature) {
-  // TODO(nhiroki): Support UseCounter for ThreadedWorklets. We could do the
-  // same thing with InProcessWorkerObjectProxy here.
-  // (https://crbug.com/376039)
-}
-
-void ThreadedWorkletObjectProxy::reportConsoleMessage(
-    MessageSource source,
-    MessageLevel level,
-    const String& message,
-    SourceLocation* location) {
-  getParentFrameTaskRunners()
-      ->get(TaskType::Internal)
-      ->postTask(
-          BLINK_FROM_HERE,
-          crossThreadBind(&ThreadedWorkletMessagingProxy::reportConsoleMessage,
-                          m_messagingProxyWeakPtr, source, level, message,
-                          WTF::passed(location->clone())));
-}
-
-void ThreadedWorkletObjectProxy::postMessageToPageInspector(
-    const String& message) {
-  DCHECK(m_messagingProxyWeakPtr->getExecutionContext()->isDocument());
-  // The TaskType of Inspector tasks need to be Unthrottled because they need to
-  // run even on a suspended page.
-  getParentFrameTaskRunners()
-      ->get(TaskType::Unthrottled)
-      ->postTask(BLINK_FROM_HERE,
-                 crossThreadBind(
-                     &ThreadedWorkletMessagingProxy::postMessageToPageInspector,
-                     m_messagingProxyWeakPtr, message));
-}
-
-ParentFrameTaskRunners*
-ThreadedWorkletObjectProxy::getParentFrameTaskRunners() {
-  return m_parentFrameTaskRunners.get();
-}
-
-void ThreadedWorkletObjectProxy::didCloseWorkerGlobalScope() {
-  getParentFrameTaskRunners()
-      ->get(TaskType::Internal)
-      ->postTask(
-          BLINK_FROM_HERE,
-          crossThreadBind(&ThreadedWorkletMessagingProxy::terminateGlobalScope,
-                          m_messagingProxyWeakPtr));
-}
-
-void ThreadedWorkletObjectProxy::didTerminateWorkerThread() {
-  // This will terminate the MessagingProxy.
-  getParentFrameTaskRunners()
-      ->get(TaskType::Internal)
-      ->postTask(BLINK_FROM_HERE,
-                 crossThreadBind(
-                     &ThreadedWorkletMessagingProxy::workerThreadTerminated,
-                     m_messagingProxyWeakPtr));
-}
-
 ThreadedWorkletObjectProxy::ThreadedWorkletObjectProxy(
     const WeakPtr<ThreadedWorkletMessagingProxy>& messagingProxyWeakPtr,
     ParentFrameTaskRunners* parentFrameTaskRunners)
-    : m_messagingProxyWeakPtr(messagingProxyWeakPtr),
-      m_parentFrameTaskRunners(parentFrameTaskRunners) {}
+    : ThreadedObjectProxyBase(parentFrameTaskRunners),
+      m_messagingProxyWeakPtr(messagingProxyWeakPtr) {}
+
+WeakPtr<ThreadedMessagingProxyBase>
+ThreadedWorkletObjectProxy::messagingProxyWeakPtr() {
+  return m_messagingProxyWeakPtr;
+}
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/workers/ThreadedWorkletObjectProxy.h b/third_party/WebKit/Source/core/workers/ThreadedWorkletObjectProxy.h
index 4c04c47..78bbe629 100644
--- a/third_party/WebKit/Source/core/workers/ThreadedWorkletObjectProxy.h
+++ b/third_party/WebKit/Source/core/workers/ThreadedWorkletObjectProxy.h
@@ -8,17 +8,16 @@
 #include "bindings/core/v8/SourceLocation.h"
 #include "core/CoreExport.h"
 #include "core/dom/MessagePort.h"
+#include "core/workers/ThreadedObjectProxyBase.h"
 #include "core/workers/WorkerReportingProxy.h"
 
 namespace blink {
 
 class ThreadedWorkletMessagingProxy;
 
-// A proxy to talk to the parent worklet object. This object is created and
-// destroyed on the main thread, and used on the worklet thread for proxying
-// messages to the ThreadedWorkletMessagingProxy on the main thread.
-// ThreadedWorkletMessagingProxy always outlives this proxy.
-class CORE_EXPORT ThreadedWorkletObjectProxy : public WorkerReportingProxy {
+// A proxy to talk to the parent worker object. See class comments on
+// ThreadedObjectProxyBase.h for lifetime of this class etc.
+class CORE_EXPORT ThreadedWorkletObjectProxy : public ThreadedObjectProxyBase {
   USING_FAST_MALLOC(ThreadedWorkletObjectProxy);
   WTF_MAKE_NONCOPYABLE(ThreadedWorkletObjectProxy);
 
@@ -30,36 +29,24 @@
 
   void reportPendingActivity(bool hasPendingActivity);
 
-  // WorkerReportingProxy overrides.
-  void countFeature(UseCounter::Feature) override;
-  void countDeprecation(UseCounter::Feature) override;
+  // ThreadedObjectProxyBase overrides.
   void reportException(const String& errorMessage,
                        std::unique_ptr<SourceLocation>,
-                       int exceptionId) override {}
-  void reportConsoleMessage(MessageSource,
-                            MessageLevel,
-                            const String& message,
-                            SourceLocation*) override;
-  void postMessageToPageInspector(const String&) override;
-  ParentFrameTaskRunners* getParentFrameTaskRunners() override;
-  void didEvaluateWorkerScript(bool success) override {}
-  void didCloseWorkerGlobalScope() override;
-  void willDestroyWorkerGlobalScope() override {}
-  void didTerminateWorkerThread() override;
+                       int exceptionId) final {}
+  void didEvaluateWorkerScript(bool success) final {}
+  void willDestroyWorkerGlobalScope() final {}
 
  protected:
   ThreadedWorkletObjectProxy(const WeakPtr<ThreadedWorkletMessagingProxy>&,
                              ParentFrameTaskRunners*);
 
+  WeakPtr<ThreadedMessagingProxyBase> messagingProxyWeakPtr() final;
+
  private:
   // No guarantees about the lifetimes of tasks posted by this proxy wrt the
   // ThreadedWorkletMessagingProxy so a weak pointer must be used when posting
   // the tasks.
   WeakPtr<ThreadedWorkletMessagingProxy> m_messagingProxyWeakPtr;
-
-  // Used to post a task to ThreadedWorkletMessagingProxy on the parent context
-  // thread.
-  CrossThreadPersistent<ParentFrameTaskRunners> m_parentFrameTaskRunners;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/devtools/front_end/Tests.js b/third_party/WebKit/Source/devtools/front_end/Tests.js
index 74afd920..62714a8 100644
--- a/third_party/WebKit/Source/devtools/front_end/Tests.js
+++ b/third_party/WebKit/Source/devtools/front_end/Tests.js
@@ -871,6 +871,12 @@
     Bindings.TempFile.ensureTempStorageCleared().then(() => this.releaseControl());
   };
 
+  TestSuite.prototype.testTempFile = function() {
+    this.takeControl();
+    Bindings.TempFile.create('test-file', 'test')
+        .then(() => this.releaseControl(), (error) => this.fail(String(error)));
+  };
+
   TestSuite.prototype.waitForTestResultsInConsole = function() {
     var messages = SDK.multitargetConsoleModel.messages();
     for (var i = 0; i < messages.length; ++i) {
diff --git a/third_party/WebKit/Source/web/TextFinder.cpp b/third_party/WebKit/Source/web/TextFinder.cpp
index 9f8410f7f..6bdd96d 100644
--- a/third_party/WebKit/Source/web/TextFinder.cpp
+++ b/third_party/WebKit/Source/web/TextFinder.cpp
@@ -379,7 +379,7 @@
       m_currentActiveMatchFrame = true;
       foundActiveMatch = true;
       // We also know which tickmark is active now.
-      m_activeMatchIndex = matchCount - 1;
+      m_activeMatchIndex = m_totalMatchCount + matchCount - 1;
       // To stop looking for the active tickmark, we set this flag.
       m_locatingActiveRect = false;
 
diff --git a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
index d473c31..3d209f9 100644
--- a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
+++ b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
@@ -5004,6 +5004,88 @@
   EXPECT_FALSE(activeNow);
 }
 
+struct FakeTimerSetter {
+  FakeTimerSetter() {
+    s_timeElapsed = 0.0;
+    m_originalTimeFunction = setTimeFunctionsForTesting(returnMockTime);
+  }
+
+  ~FakeTimerSetter() { setTimeFunctionsForTesting(m_originalTimeFunction); }
+  static double returnMockTime() {
+    s_timeElapsed += 1.0;
+    return s_timeElapsed;
+  }
+
+ private:
+  TimeFunction m_originalTimeFunction;
+  static double s_timeElapsed;
+};
+double FakeTimerSetter::s_timeElapsed = 0.;
+
+TEST_P(ParameterizedWebFrameTest, FindInPageJavaScriptUpdatesDOMProperOrdinal) {
+  FakeTimerSetter fakeTimer;
+
+  const WebString searchPattern = WebString::fromUTF8("abc");
+  // We have 2 occurrences of the pattern in our text.
+  const char* html =
+      "foo bar foo bar foo abc bar foo bar foo bar foo bar foo bar foo bar foo "
+      "bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo "
+      "bar foo bar foo abc bar <div id='new_text'></div>";
+
+  FindUpdateWebFrameClient client;
+  FrameTestHelpers::WebViewHelper webViewHelper;
+  webViewHelper.initialize(true, &client);
+
+  WebLocalFrameImpl* frame = webViewHelper.webView()->mainFrameImpl();
+  FrameTestHelpers::loadHTMLString(frame, html,
+                                   URLTestHelpers::toKURL(m_baseURL));
+  webViewHelper.resize(WebSize(640, 480));
+  webViewHelper.webView()->setFocus(true);
+  runPendingTasks();
+
+  const int findIdentifier = 12345;
+  WebFindOptions options;
+
+  // The first search that will start the scoping process.
+  frame->requestFind(findIdentifier, searchPattern, options);
+  EXPECT_FALSE(client.findResultsAreReady());
+  EXPECT_EQ(1, client.count());
+  EXPECT_TRUE(frame->ensureTextFinder().scopingInProgress());
+
+  // The scoping won't find all the entries on the first run due to the fake
+  // timer.
+  while (frame->ensureTextFinder().scopingInProgress())
+    runPendingTasks();
+
+  EXPECT_EQ(2, client.count());
+  EXPECT_EQ(1, client.activeIndex());
+
+  options.findNext = true;
+
+  // The second search will jump to the next match without any scoping.
+  frame->requestFind(findIdentifier, searchPattern, options);
+
+  EXPECT_EQ(2, client.count());
+  EXPECT_EQ(2, client.activeIndex());
+  EXPECT_FALSE(frame->ensureTextFinder().scopingInProgress());
+
+  // Insert new text, which contains occurence of |searchText|.
+  frame->executeScript(
+      WebScriptSource("var textDiv = document.getElementById('new_text');"
+                      "textDiv.innerHTML = 'foo abc';"));
+
+  // The third search will find a new match and initiate a new scoping.
+  frame->requestFind(findIdentifier, searchPattern, options);
+
+  EXPECT_TRUE(frame->ensureTextFinder().scopingInProgress());
+
+  while (frame->ensureTextFinder().scopingInProgress())
+    runPendingTasks();
+
+  EXPECT_EQ(3, client.count());
+  EXPECT_EQ(3, client.activeIndex());
+}
+
 static WebPoint topLeft(const WebRect& rect) {
   return WebPoint(rect.x, rect.y);
 }
diff --git a/third_party/WebKit/Source/wtf/BUILD.gn b/third_party/WebKit/Source/wtf/BUILD.gn
index f1b449d..11fccb12 100644
--- a/third_party/WebKit/Source/wtf/BUILD.gn
+++ b/third_party/WebKit/Source/wtf/BUILD.gn
@@ -334,6 +334,7 @@
     "text/StringBuilderTest.cpp",
     "text/StringImplTest.cpp",
     "text/StringOperatorsTest.cpp",
+    "text/StringToNumberTest.cpp",
     "text/StringViewTest.cpp",
     "text/TextCodecICUTest.cpp",
     "text/TextCodecLatin1Test.cpp",
diff --git a/third_party/WebKit/Source/wtf/StdLibExtras.h b/third_party/WebKit/Source/wtf/StdLibExtras.h
index 885f9dd..454e1a18 100644
--- a/third_party/WebKit/Source/wtf/StdLibExtras.h
+++ b/third_party/WebKit/Source/wtf/StdLibExtras.h
@@ -33,7 +33,7 @@
 #include "wtf/TypeTraits.h"
 #include <cstddef>
 
-#if ENABLE(ASSERT)
+#if DCHECK_IS_ON()
 #include "wtf/Noncopyable.h"
 #include "wtf/Threading.h"
 
@@ -90,7 +90,7 @@
   }
 };
 
-#if ENABLE(ASSERT)
+#if DCHECK_IS_ON()
 #define DEFINE_STATIC_LOCAL_CHECK_THREADSAFE_ACCESS(Name) \
   static StaticLocalVerifier Name##StaticLocalVerifier;   \
   ASSERT(Name##StaticLocalVerifier.isNotRacy())
diff --git a/third_party/WebKit/Source/wtf/text/StringToNumber.cpp b/third_party/WebKit/Source/wtf/text/StringToNumber.cpp
index 9fa2ff5a..423bf68 100644
--- a/third_party/WebKit/Source/wtf/text/StringToNumber.cpp
+++ b/third_party/WebKit/Source/wtf/text/StringToNumber.cpp
@@ -7,6 +7,7 @@
 #include "wtf/ASCIICType.h"
 #include "wtf/dtoa.h"
 #include "wtf/text/StringImpl.h"
+#include <type_traits>
 
 namespace WTF {
 
@@ -29,10 +30,13 @@
                                           size_t length,
                                           bool* ok,
                                           int base) {
-  static const IntegralType integralMax =
+  static_assert(std::is_integral<IntegralType>::value,
+                "IntegralType must be an integral type.");
+  static constexpr IntegralType integralMax =
       std::numeric_limits<IntegralType>::max();
-  static const bool isSigned = std::numeric_limits<IntegralType>::is_signed;
-  const IntegralType maxMultiplier = integralMax / base;
+  static constexpr IntegralType integralMin =
+      std::numeric_limits<IntegralType>::min();
+  static constexpr bool isSigned = std::numeric_limits<IntegralType>::is_signed;
 
   IntegralType value = 0;
   bool isOk = false;
@@ -70,27 +74,31 @@
     else
       digitValue = c - 'A' + 10;
 
-    if (value > maxMultiplier ||
-        (value == maxMultiplier &&
-         digitValue > (integralMax % base) + isNegative))
+    bool overflow;
+    if (isNegative) {
+      // Overflow condition:
+      //       value * base - digitValue < integralMin
+      //   <=> value < (integralMin + digitValue) / base
+      // We must be careful of rounding errors here, but the default rounding
+      // mode (round to zero) works well, so we can use this formula as-is.
+      overflow = value < (integralMin + digitValue) / base;
+    } else {
+      // Overflow condition:
+      //       value * base + digitValue > integralMax
+      //   <=> value > (integralMax + digitValue) / base
+      // Ditto regarding rounding errors.
+      overflow = value > (integralMax - digitValue) / base;
+    }
+    if (overflow)
       goto bye;
 
-    value = base * value + digitValue;
+    if (isNegative)
+      value = base * value - digitValue;
+    else
+      value = base * value + digitValue;
     ++data;
   }
 
-#if COMPILER(MSVC)
-#pragma warning(push, 0)
-#pragma warning(disable : 4146)
-#endif
-
-  if (isNegative)
-    value = -value;
-
-#if COMPILER(MSVC)
-#pragma warning(pop)
-#endif
-
   // skip trailing space
   while (length && isSpaceOrNewline(*data)) {
     --length;
diff --git a/third_party/WebKit/Source/wtf/text/StringToNumberTest.cpp b/third_party/WebKit/Source/wtf/text/StringToNumberTest.cpp
new file mode 100644
index 0000000..429147c
--- /dev/null
+++ b/third_party/WebKit/Source/wtf/text/StringToNumberTest.cpp
@@ -0,0 +1,126 @@
+// Copyright 2016 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 "wtf/text/StringToNumber.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include <cstring>
+
+namespace WTF {
+
+TEST(StringToNumberTest, TestCharactersToIntStrict) {
+#define EXPECT_VALID(string, expectedValue, base)                             \
+  do {                                                                        \
+    bool ok;                                                                  \
+    int value = charactersToIntStrict(reinterpret_cast<const LChar*>(string), \
+                                      std::strlen(string), &ok, base);        \
+    EXPECT_TRUE(ok);                                                          \
+    EXPECT_EQ(value, expectedValue);                                          \
+  } while (false)
+
+#define EXPECT_INVALID(string, base)                              \
+  do {                                                            \
+    bool ok;                                                      \
+    charactersToIntStrict(reinterpret_cast<const LChar*>(string), \
+                          std::strlen(string), &ok, base);        \
+    EXPECT_FALSE(ok);                                             \
+  } while (false)
+
+#define EXPECT_VALID_DECIMAL(string, expectedValue) \
+  EXPECT_VALID(string, expectedValue, 10)
+#define EXPECT_INVALID_DECIMAL(string) EXPECT_INVALID(string, 10)
+#define EXPECT_VALID_HEXADECIMAL(string, expectedValue) \
+  EXPECT_VALID(string, expectedValue, 16)
+#define EXPECT_INVALID_HEXADECIMAL(string) EXPECT_INVALID(string, 16)
+
+  EXPECT_VALID_DECIMAL("1", 1);
+  EXPECT_VALID_DECIMAL("2", 2);
+  EXPECT_VALID_DECIMAL("9", 9);
+  EXPECT_VALID_DECIMAL("10", 10);
+  EXPECT_VALID_DECIMAL("0", 0);
+  EXPECT_VALID_DECIMAL("-0", 0);
+  EXPECT_VALID_DECIMAL("-1", -1);
+  EXPECT_VALID_DECIMAL("-2", -2);
+  EXPECT_VALID_DECIMAL("-9", -9);
+  EXPECT_VALID_DECIMAL("-10", -10);
+  EXPECT_VALID_DECIMAL("+0", 0);
+  EXPECT_VALID_DECIMAL("+1", 1);
+  EXPECT_VALID_DECIMAL("+2", 2);
+  EXPECT_VALID_DECIMAL("+9", 9);
+  EXPECT_VALID_DECIMAL("+10", 10);
+  EXPECT_VALID_DECIMAL("00", 0);
+  EXPECT_VALID_DECIMAL("+00", 0);
+  EXPECT_VALID_DECIMAL("-00", 0);
+  EXPECT_VALID_DECIMAL("01", 1);
+  EXPECT_VALID_DECIMAL("-01", -1);
+  EXPECT_VALID_DECIMAL("00000000000000000000", 0);
+  EXPECT_INVALID_DECIMAL("a");
+  EXPECT_INVALID_DECIMAL("1a");
+  EXPECT_INVALID_DECIMAL("a1");
+  EXPECT_INVALID_DECIMAL("-a");
+  EXPECT_INVALID_DECIMAL("");
+  EXPECT_INVALID_DECIMAL("-");
+  EXPECT_INVALID_DECIMAL("--1");
+  EXPECT_INVALID_DECIMAL("++1");
+  EXPECT_INVALID_DECIMAL("+-1");
+  EXPECT_INVALID_DECIMAL("-+1");
+  EXPECT_INVALID_DECIMAL("0-");
+  EXPECT_INVALID_DECIMAL("0+");
+
+  EXPECT_VALID_DECIMAL("2147483647", 2147483647);
+  EXPECT_VALID_DECIMAL("02147483647", 2147483647);
+  EXPECT_INVALID_DECIMAL("2147483648");
+  EXPECT_INVALID_DECIMAL("2147483649");
+  EXPECT_INVALID_DECIMAL("2147483650");
+  EXPECT_INVALID_DECIMAL("2147483700");
+  EXPECT_INVALID_DECIMAL("2147484000");
+  EXPECT_INVALID_DECIMAL("2200000000");
+  EXPECT_INVALID_DECIMAL("3000000000");
+  EXPECT_INVALID_DECIMAL("10000000000");
+  EXPECT_VALID_DECIMAL("-2147483647", -2147483647);
+  EXPECT_VALID_DECIMAL("-2147483648", -2147483647 - 1);
+  EXPECT_INVALID_DECIMAL("-2147483649");
+  EXPECT_INVALID_DECIMAL("-2147483650");
+  EXPECT_INVALID_DECIMAL("-2147483700");
+  EXPECT_INVALID_DECIMAL("-2147484000");
+  EXPECT_INVALID_DECIMAL("-2200000000");
+  EXPECT_INVALID_DECIMAL("-3000000000");
+  EXPECT_INVALID_DECIMAL("-10000000000");
+
+  EXPECT_VALID_HEXADECIMAL("1", 1);
+  EXPECT_VALID_HEXADECIMAL("a", 0xA);
+  EXPECT_VALID_HEXADECIMAL("A", 0xA);
+  EXPECT_VALID_HEXADECIMAL("+a", 0xA);
+  EXPECT_VALID_HEXADECIMAL("+A", 0xA);
+  EXPECT_VALID_HEXADECIMAL("-a", -0xA);
+  EXPECT_VALID_HEXADECIMAL("-A", -0xA);
+
+  EXPECT_VALID_HEXADECIMAL("7fffffff", 0x7FFFFFFF);
+  EXPECT_INVALID_HEXADECIMAL("80000000");
+  EXPECT_INVALID_HEXADECIMAL("8000000a");
+  EXPECT_INVALID_HEXADECIMAL("8000000f");
+  EXPECT_INVALID_HEXADECIMAL("90000000");
+  EXPECT_INVALID_HEXADECIMAL("fffffff0");
+  EXPECT_INVALID_HEXADECIMAL("ffffffff");
+  EXPECT_INVALID_HEXADECIMAL("100000000");
+  EXPECT_INVALID_HEXADECIMAL("7fffffff0");
+  EXPECT_VALID_HEXADECIMAL("-7fffffff", -0x7FFFFFFF);
+  EXPECT_VALID_HEXADECIMAL("-80000000", -0x7FFFFFFF - 1);
+  EXPECT_INVALID_HEXADECIMAL("-80000001");
+  EXPECT_INVALID_HEXADECIMAL("-8000000a");
+  EXPECT_INVALID_HEXADECIMAL("-8000000f");
+  EXPECT_INVALID_HEXADECIMAL("-80000010");
+  EXPECT_INVALID_HEXADECIMAL("-90000000");
+  EXPECT_INVALID_HEXADECIMAL("-f0000000");
+  EXPECT_INVALID_HEXADECIMAL("-fffffff0");
+  EXPECT_INVALID_HEXADECIMAL("-ffffffff");
+
+#undef EXPECT_VALID_DECIMAL
+#undef EXPECT_INVALID_DECIMAL
+#undef EXPECT_VALID_HEXADECIMAL
+#undef EXPECT_INVALID_HEXADECIMAL
+#undef EXPECT_VALID
+#undef EXPECT_INVALID
+}
+}
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index 3cf2be53..90f5d6a2 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -234,6 +234,7 @@
       'GPU Win x64 Builder': 'gpu_tests_deqp_gles_release_trybot',
       'GPU Win x64 Builder (dbg)': 'gpu_tests_deqp_gles_debug_trybot',
       'Linux ChromiumOS Builder': 'gpu_fyi_tests_chromeos_release_trybot',
+      'Linux ChromiumOS Ozone Builder': 'gpu_fyi_tests_chromeos_ozone_release_trybot',
       'Mac GPU ASAN Release': 'gpu_fyi_tests_release_trybot_asan',
     },
 
@@ -1145,6 +1146,10 @@
       'debug_trybot', 'x86',
     ],
 
+    'gpu_fyi_tests_chromeos_ozone_release_trybot': [
+      'gpu_fyi_tests', 'release_trybot', 'chromeos', 'ozone',
+    ],
+
     'gpu_fyi_tests_chromeos_release_trybot': [
       'gpu_fyi_tests', 'release_trybot', 'chromeos',
     ],