diff --git a/DEPS b/DEPS
index 40a49997..8c4f64f 100644
--- a/DEPS
+++ b/DEPS
@@ -43,7 +43,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': '62edb0c29bcea560a375c89bd775c3ae572ad256',
+  'v8_revision': 'c233dc130e87cb9b36c568dff576d22895a47891',
   # 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.
@@ -87,7 +87,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling NaCl
   # and whatever else without interference from each other.
-  'nacl_revision': '296d9ac73190fbd37f699461600e83b16ec0d2b3',
+  'nacl_revision': '0c539908088374d1c4074e331456644b21628a65',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling dEQP
   # and whatever else without interference from each other.
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc
index 0b88116..573e241 100644
--- a/android_webview/browser/aw_content_browser_client.cc
+++ b/android_webview/browser/aw_content_browser_client.cc
@@ -311,7 +311,7 @@
                                             content::ResourceContext* context,
                                             int render_process_id,
                                             int render_frame_id,
-                                            net::CookieOptions* options) {
+                                            const net::CookieOptions& options) {
   return AwCookieAccessPolicy::GetInstance()->AllowSetCookie(url,
                                                              first_party,
                                                              cookie_line,
diff --git a/android_webview/browser/aw_content_browser_client.h b/android_webview/browser/aw_content_browser_client.h
index 960c3e88..adc27458 100644
--- a/android_webview/browser/aw_content_browser_client.h
+++ b/android_webview/browser/aw_content_browser_client.h
@@ -71,7 +71,7 @@
                       content::ResourceContext* context,
                       int render_process_id,
                       int render_frame_id,
-                      net::CookieOptions* options) override;
+                      const net::CookieOptions& options) override;
   bool AllowWorkerDatabase(
       const GURL& url,
       const base::string16& name,
diff --git a/android_webview/browser/aw_cookie_access_policy.cc b/android_webview/browser/aw_cookie_access_policy.cc
index 242abca..5b5274a 100644
--- a/android_webview/browser/aw_cookie_access_policy.cc
+++ b/android_webview/browser/aw_cookie_access_policy.cc
@@ -100,7 +100,7 @@
                                           content::ResourceContext* context,
                                           int render_process_id,
                                           int render_frame_id,
-                                          net::CookieOptions* options) {
+                                          const net::CookieOptions& options) {
   bool global = GetShouldAcceptCookies();
   bool thirdParty =
       GetShouldAcceptThirdPartyCookies(render_process_id, render_frame_id);
diff --git a/android_webview/browser/aw_cookie_access_policy.h b/android_webview/browser/aw_cookie_access_policy.h
index a2de037..867df7c 100644
--- a/android_webview/browser/aw_cookie_access_policy.h
+++ b/android_webview/browser/aw_cookie_access_policy.h
@@ -62,7 +62,7 @@
                       content::ResourceContext* context,
                       int render_process_id,
                       int render_frame_id,
-                      net::CookieOptions* options);
+                      const net::CookieOptions& options);
 
  private:
   friend struct base::DefaultLazyInstanceTraits<AwCookieAccessPolicy>;
diff --git a/chrome/browser/banners/app_banner_data_fetcher.cc b/chrome/browser/banners/app_banner_data_fetcher.cc
index 321e8d3e..0090d10 100644
--- a/chrome/browser/banners/app_banner_data_fetcher.cc
+++ b/chrome/browser/banners/app_banner_data_fetcher.cc
@@ -188,9 +188,6 @@
     return;
   }
 
-  AppBannerSettingsHelper::RecordMinutesFromFirstVisitToShow(
-      web_contents, validated_url_, GetAppIdentifier(), GetCurrentTime());
-
   // Definitely going to show the banner now.
   FOR_EACH_OBSERVER(Observer, observer_list_,
                     OnDecidedWhetherToShow(this, true));
diff --git a/chrome/browser/banners/app_banner_data_fetcher_browsertest.cc b/chrome/browser/banners/app_banner_data_fetcher_browsertest.cc
index c868268..b37df5f 100644
--- a/chrome/browser/banners/app_banner_data_fetcher_browsertest.cc
+++ b/chrome/browser/banners/app_banner_data_fetcher_browsertest.cc
@@ -9,10 +9,8 @@
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/task_runner.h"
-#include "base/test/histogram_tester.h"
 #include "base/thread_task_runner_handle.h"
 #include "chrome/browser/banners/app_banner_data_fetcher_desktop.h"
-#include "chrome/browser/banners/app_banner_metrics.h"
 #include "chrome/browser/banners/app_banner_settings_helper.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -99,7 +97,6 @@
                                         weak_factory_.GetWeakPtr(),
                                         128, 128));
 
-    base::HistogramTester histograms;
     base::RunLoop run_loop;
     quit_closure_ = run_loop.QuitClosure();
     scoped_ptr<TestObserver> observer(new TestObserver(fetcher.get(),
@@ -110,10 +107,6 @@
     EXPECT_EQ(expected_non_web_platform, non_web_platform_);
     EXPECT_EQ(expected_to_show, observer->will_show());
     ASSERT_FALSE(fetcher->is_active());
-
-    // If showing the banner, ensure that the minutes histogram is recorded.
-    histograms.ExpectTotalCount(banners::kMinutesHistogram,
-                                (observer->will_show() ? 1 : 0));
   }
 
   void RunBannerTest(const std::string& manifest_page,
diff --git a/chrome/browser/banners/app_banner_metrics.cc b/chrome/browser/banners/app_banner_metrics.cc
index f9bbd34..5ab6f59a 100644
--- a/chrome/browser/banners/app_banner_metrics.cc
+++ b/chrome/browser/banners/app_banner_metrics.cc
@@ -4,48 +4,32 @@
 
 #include "chrome/browser/banners/app_banner_metrics.h"
 
-#include "base/metrics/histogram_macros.h"
 #include "base/metrics/sparse_histogram.h"
 
 namespace banners {
 
-const char kDismissEventHistogram[] = "AppBanners.DismissEvent";
-const char kDisplayEventHistogram[] = "AppBanners.DisplayEvent";
-const char kInstallEventHistogram[] = "AppBanners.InstallEvent";
-const char kMinutesHistogram[] =
-    "AppBanners.MinutesFromFirstVisitToBannerShown";
-const char kUserResponseHistogram[] = "AppBanners.UserResponse";
-
 void TrackDismissEvent(int event) {
   DCHECK_LT(DISMISS_EVENT_MIN, event);
   DCHECK_LT(event, DISMISS_EVENT_MAX);
-  UMA_HISTOGRAM_SPARSE_SLOWLY(kDismissEventHistogram, event);
+  UMA_HISTOGRAM_SPARSE_SLOWLY("AppBanners.DismissEvent", event);
 }
 
 void TrackDisplayEvent(int event) {
   DCHECK_LT(DISPLAY_EVENT_MIN, event);
   DCHECK_LT(event, DISPLAY_EVENT_MAX);
-  UMA_HISTOGRAM_SPARSE_SLOWLY(kDisplayEventHistogram, event);
+  UMA_HISTOGRAM_SPARSE_SLOWLY("AppBanners.DisplayEvent", event);
 }
 
 void TrackInstallEvent(int event) {
   DCHECK_LT(INSTALL_EVENT_MIN, event);
   DCHECK_LT(event, INSTALL_EVENT_MAX);
-  UMA_HISTOGRAM_SPARSE_SLOWLY(kInstallEventHistogram, event);
-}
-
-void TrackMinutesFromFirstVisitToBannerShown(int minutes) {
-  // Histogram ranges from 1 minute to the number of minutes in 21 days.
-  // This is one more day than the decay length of time for site engagement,
-  // and seven more days than the expiry of visits for the app banner
-  // navigation heuristic.
-  UMA_HISTOGRAM_CUSTOM_COUNTS(kMinutesHistogram, minutes, 1, 30240, 100);
+  UMA_HISTOGRAM_SPARSE_SLOWLY("AppBanners.InstallEvent", event);
 }
 
 void TrackUserResponse(int event) {
   DCHECK_LT(USER_RESPONSE_MIN, event);
   DCHECK_LT(event, USER_RESPONSE_MAX);
-  UMA_HISTOGRAM_SPARSE_SLOWLY(kUserResponseHistogram, event);
+  UMA_HISTOGRAM_SPARSE_SLOWLY("AppBanners.UserResponse", event);
 }
 
 }  // namespace banners
diff --git a/chrome/browser/banners/app_banner_metrics.h b/chrome/browser/banners/app_banner_metrics.h
index 0b0939ee..7c781792 100644
--- a/chrome/browser/banners/app_banner_metrics.h
+++ b/chrome/browser/banners/app_banner_metrics.h
@@ -57,16 +57,9 @@
   USER_RESPONSE_MAX = 7,
 };
 
-extern const char kDismissEventHistogram[];
-extern const char kDisplayEventHistogram[];
-extern const char kInstallEventHistogram[];
-extern const char kMinutesHistogram[];
-extern const char kUserResponseHistogram[];
-
 void TrackDismissEvent(int event);
 void TrackDisplayEvent(int event);
 void TrackInstallEvent(int event);
-void TrackMinutesFromFirstVisitToBannerShown(int minutes);
 void TrackUserResponse(int event);
 
 };  // namespace banners
diff --git a/chrome/browser/banners/app_banner_settings_helper.cc b/chrome/browser/banners/app_banner_settings_helper.cc
index aca24f6..2f0bb43 100644
--- a/chrome/browser/banners/app_banner_settings_helper.cc
+++ b/chrome/browser/banners/app_banner_settings_helper.cc
@@ -8,14 +8,11 @@
 #include <string>
 
 #include "base/command_line.h"
-#include "base/metrics/field_trial.h"
 #include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
 #include "chrome/browser/banners/app_banner_data_fetcher.h"
 #include "chrome/browser/banners/app_banner_metrics.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
-#include "chrome/browser/engagement/site_engagement_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_switches.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
@@ -66,11 +63,9 @@
 const char kBannerParamsIndirectKey[] = "indirect";
 const char kBannerParamsTotalKey[] = "total";
 const char kBannerParamsMinutesKey[] = "minutes";
-const char kBannerSiteEngagementParamsKey[] = "app_banner_triggering";
-const char kBannerSiteEngagementParamsTotalKey[] =
-    "app_banner_triggering_total";
 
-// Total engagement score required before a banner will actually be triggered.
+// Total site engagements where a banner could have been shown before
+// a banner will actually be triggered.
 double gTotalEngagementToTrigger = 2;
 
 // Engagement weight assigned to direct and indirect navigations.
@@ -120,26 +115,10 @@
   }
 }
 
-// Queries variations for the maximum site engagement score required to trigger
-// the banner showing.
-void UpdateSiteEngagementToTrigger() {
-  std::string total_param = variations::GetVariationParamValue(
-      SiteEngagementService::kEngagementParams,
-      kBannerSiteEngagementParamsTotalKey);
-
-  if (!total_param.empty()) {
-    double total_engagement = -1;
-
-    if (base::StringToDouble(total_param, &total_engagement) &&
-        total_engagement > 0) {
-      AppBannerSettingsHelper::SetTotalEngagementToTrigger(total_engagement);
-    }
-  }
-}
-
 // Queries variations for updates to the default engagement values assigned
 // to direct and indirect navigations.
 void UpdateEngagementWeights() {
+  std::map<std::string, std::string> params;
   std::string direct_param = variations::GetVariationParamValue(
       kBannerParamsKey, kBannerParamsDirectKey);
   std::string indirect_param = variations::GetVariationParamValue(
@@ -181,16 +160,6 @@
   }
 }
 
-// Returns the site engagement karma score for the given origin URL under the
-// current profile.
-double GetSiteEngagementScoreForOrigin(
-    content::WebContents* web_contents,
-    const GURL& origin_url) {
-  SiteEngagementService* service = SiteEngagementService::Get(
-      Profile::FromBrowserContext(web_contents->GetBrowserContext()));
-  return service ? service->GetScore(origin_url) : 0;
-}
-
 }  // namespace
 
 void AppBannerSettingsHelper::ClearHistoryForURLs(
@@ -383,10 +352,6 @@
     return true;
   }
 
-  // Never show a banner when the package name or URL is empty.
-  if (package_name_or_start_url.empty())
-    return false;
-
   // Don't show if it has been added to the homescreen.
   base::Time added_time =
       GetSingleBannerEvent(web_contents, origin_url, package_name_or_start_url,
@@ -417,17 +382,14 @@
     return false;
   }
 
-  double total_engagement = 0;
-  if (ShouldUseSiteEngagementScore()) {
-    total_engagement =
-        GetSiteEngagementScoreForOrigin(web_contents, origin_url);
-  } else {
-    std::vector<BannerEvent> could_show_events = GetCouldShowBannerEvents(
-        web_contents, origin_url, package_name_or_start_url);
+  std::vector<BannerEvent> could_show_events = GetCouldShowBannerEvents(
+      web_contents, origin_url, package_name_or_start_url);
 
-    for (const auto& event : could_show_events)
-      total_engagement += event.engagement;
-  }
+  // Return true if the total engagement of each applicable could show event
+  // meets the trigger threshold.
+  double total_engagement = 0;
+  for (const auto& event : could_show_events)
+    total_engagement += event.engagement;
 
   if (total_engagement < gTotalEngagementToTrigger) {
     banners::TrackDisplayEvent(banners::DISPLAY_EVENT_NOT_VISITED_ENOUGH);
@@ -443,6 +405,8 @@
     const GURL& origin_url,
     const std::string& package_name_or_start_url) {
   std::vector<BannerEvent> result;
+  if (package_name_or_start_url.empty())
+    return result;
 
   Profile* profile =
       Profile::FromBrowserContext(web_contents->GetBrowserContext());
@@ -490,6 +454,9 @@
   DCHECK(event != APP_BANNER_EVENT_COULD_SHOW);
   DCHECK(event < APP_BANNER_EVENT_NUM_EVENTS);
 
+  if (package_name_or_start_url.empty())
+    return base::Time();
+
   Profile* profile =
       Profile::FromBrowserContext(web_contents->GetBrowserContext());
   HostContentSettingsMap* settings =
@@ -513,21 +480,6 @@
   return base::Time::FromInternalValue(internal_time);
 }
 
-void AppBannerSettingsHelper::RecordMinutesFromFirstVisitToShow(
-    content::WebContents* web_contents,
-    const GURL& origin_url,
-    const std::string& package_name_or_start_url,
-    base::Time time) {
-  std::vector<BannerEvent> could_show_events = GetCouldShowBannerEvents(
-      web_contents, origin_url, package_name_or_start_url);
-
-  int minutes = 0;
-  if (could_show_events.size())
-    minutes = (time - could_show_events[0].time).InMinutes();
-
-  banners::TrackMinutesFromFirstVisitToBannerShown(minutes);
-}
-
 void AppBannerSettingsHelper::SetEngagementWeights(double direct_engagement,
                                                    double indirect_engagement) {
   gDirectNavigationEngagement = direct_engagement;
@@ -571,32 +523,6 @@
 }
 
 void AppBannerSettingsHelper::UpdateFromFieldTrial() {
-  // If we are using the site engagement score, only extract the total
-  // engagement to trigger from the params variations.
-  if (ShouldUseSiteEngagementScore()) {
-    UpdateSiteEngagementToTrigger();
-  } else {
-    UpdateEngagementWeights();
-    UpdateMinutesBetweenVisits();
-  }
-}
-
-bool AppBannerSettingsHelper::ShouldUseSiteEngagementScore() {
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kEnableSiteEngagementAppBanner)) {
-    return true;
-  }
-
-  // This experiment is controlled under the same key as the broader site
-  // engagement experiment rather than the banner experiment. This avoids cross
-  // pollution with other site engagement experiments. However, this experiment
-  // must only be active when there is one singular group under the banner
-  // experiment, otherwise the banner and site engagement banner experiments
-  // will conflict.
-  //
-  // Making the experiment active when a variations key is present allows us
-  // to have experiments which enable multiple features under site engagement.
-  std::string param = variations::GetVariationParamValue(
-      SiteEngagementService::kEngagementParams, kBannerSiteEngagementParamsKey);
-  return !param.empty();
+  UpdateEngagementWeights();
+  UpdateMinutesBetweenVisits();
 }
diff --git a/chrome/browser/banners/app_banner_settings_helper.h b/chrome/browser/banners/app_banner_settings_helper.h
index b46bc168..3ff877c0 100644
--- a/chrome/browser/banners/app_banner_settings_helper.h
+++ b/chrome/browser/banners/app_banner_settings_helper.h
@@ -117,14 +117,6 @@
       const std::string& package_name_or_start_url,
       AppBannerEvent event);
 
-  // Record a UMA statistic measuring the minutes between the first visit to the
-  // site and the first showing of the banner.
-  static void RecordMinutesFromFirstVisitToShow(
-      content::WebContents* web_contents,
-      const GURL& origin_url,
-      const std::string& package_name_or_start_url,
-      base::Time time);
-
   // Set the engagement weights assigned to direct and indirect navigations.
   static void SetEngagementWeights(double direct_engagement,
                                    double indirect_engagement);
@@ -145,10 +137,6 @@
   // Updates all values from field trial.
   static void UpdateFromFieldTrial();
 
-  // Returns true if the app banner trigger condition should use the site
-  // engagement score instead of the navigation-based heuristic.
-  static bool ShouldUseSiteEngagementScore();
-
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(AppBannerSettingsHelper);
 };
diff --git a/chrome/browser/banners/app_banner_settings_helper_unittest.cc b/chrome/browser/banners/app_banner_settings_helper_unittest.cc
index 254758a..82550f1 100644
--- a/chrome/browser/banners/app_banner_settings_helper_unittest.cc
+++ b/chrome/browser/banners/app_banner_settings_helper_unittest.cc
@@ -4,14 +4,8 @@
 
 #include <vector>
 
-#include "base/command_line.h"
-#include "chrome/browser/banners/app_banner_metrics.h"
 #include "chrome/browser/banners/app_banner_settings_helper.h"
-#include "chrome/browser/engagement/site_engagement_service.h"
-#include "chrome/browser/engagement/site_engagement_service_factory.h"
-#include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
-#include "chrome/test/base/testing_profile.h"
 #include "ui/base/page_transition_types.h"
 
 namespace {
@@ -737,93 +731,3 @@
   EXPECT_TRUE(AppBannerSettingsHelper::ShouldShowBanner(
       web_contents(), url, kTestPackageName, reference_time));
 }
-
-TEST_F(AppBannerSettingsHelperTest, ShouldShowWithHigherTotal) {
-  AppBannerSettingsHelper::SetEngagementWeights(1, 1);
-  AppBannerSettingsHelper::SetTotalEngagementToTrigger(5);
-  GURL url(kTestURL);
-  NavigateAndCommit(url);
-
-  base::Time reference_time = GetReferenceTime();
-  base::Time second_day = reference_time + base::TimeDelta::FromDays(1);
-  base::Time third_day = reference_time + base::TimeDelta::FromDays(2);
-  base::Time fourth_day = reference_time + base::TimeDelta::FromDays(3);
-  base::Time fifth_day = reference_time + base::TimeDelta::FromDays(4);
-
-  EXPECT_FALSE(AppBannerSettingsHelper::ShouldShowBanner(
-      web_contents(), url, kTestPackageName, reference_time));
-
-  // It should take five visits to trigger the banner.
-  AppBannerSettingsHelper::RecordBannerCouldShowEvent(
-      web_contents(), url, kTestPackageName, reference_time,
-      ui::PAGE_TRANSITION_LINK);
-  EXPECT_FALSE(AppBannerSettingsHelper::ShouldShowBanner(
-      web_contents(), url, kTestPackageName, reference_time));
-
-  AppBannerSettingsHelper::RecordBannerCouldShowEvent(
-      web_contents(), url, kTestPackageName, second_day,
-      ui::PAGE_TRANSITION_TYPED);
-  EXPECT_FALSE(AppBannerSettingsHelper::ShouldShowBanner(
-      web_contents(), url, kTestPackageName, second_day));
-
-  AppBannerSettingsHelper::RecordBannerCouldShowEvent(
-      web_contents(), url, kTestPackageName, third_day,
-      ui::PAGE_TRANSITION_GENERATED);
-  EXPECT_FALSE(AppBannerSettingsHelper::ShouldShowBanner(
-      web_contents(), url, kTestPackageName, third_day));
-
-  AppBannerSettingsHelper::RecordBannerCouldShowEvent(
-      web_contents(), url, kTestPackageName, fourth_day,
-      ui::PAGE_TRANSITION_LINK);
-  EXPECT_FALSE(AppBannerSettingsHelper::ShouldShowBanner(
-      web_contents(), url, kTestPackageName, fourth_day));
-
-  // Visit the site again; now it should be shown.
-  AppBannerSettingsHelper::RecordBannerCouldShowEvent(
-      web_contents(), url, kTestPackageName, fifth_day,
-      ui::PAGE_TRANSITION_TYPED);
-  EXPECT_TRUE(AppBannerSettingsHelper::ShouldShowBanner(
-      web_contents(), url, kTestPackageName, fifth_day));
-}
-
-// Test that the banner triggers correctly using site engagement.
-TEST_F(AppBannerSettingsHelperTest, SiteEngagementTrigger) {
-  AppBannerSettingsHelper::SetTotalEngagementToTrigger(2);
-  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-  command_line->AppendSwitch(switches::kEnableSiteEngagementAppBanner);
-
-  SiteEngagementService* service =
-      SiteEngagementServiceFactory::GetForProfile(profile());
-  DCHECK(service);
-
-  // Not used, but needed for method call.
-  base::Time reference_time = GetReferenceTime();
-  GURL url(kTestURL);
-
-  EXPECT_FALSE(AppBannerSettingsHelper::ShouldShowBanner(
-      web_contents(), url, kTestPackageName, reference_time));
-
-  service->AddPoints(url, 1);
-  EXPECT_FALSE(AppBannerSettingsHelper::ShouldShowBanner(
-      web_contents(), url, kTestPackageName, reference_time));
-
-  service->AddPoints(url, 1);
-  EXPECT_TRUE(AppBannerSettingsHelper::ShouldShowBanner(
-      web_contents(), url, kTestPackageName, reference_time));
-
-  AppBannerSettingsHelper::SetTotalEngagementToTrigger(5);
-  EXPECT_FALSE(AppBannerSettingsHelper::ShouldShowBanner(
-      web_contents(), url, kTestPackageName, reference_time));
-
-  service->AddPoints(url, 1.5);
-  EXPECT_FALSE(AppBannerSettingsHelper::ShouldShowBanner(
-      web_contents(), url, kTestPackageName, reference_time));
-
-  service->AddPoints(url, 0.5);
-  EXPECT_FALSE(AppBannerSettingsHelper::ShouldShowBanner(
-      web_contents(), url, kTestPackageName, reference_time));
-
-  service->AddPoints(url, 1.5);
-  EXPECT_TRUE(AppBannerSettingsHelper::ShouldShowBanner(
-      web_contents(), url, kTestPackageName, reference_time));
-}
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 14ee957..f9f87bc 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -1745,7 +1745,7 @@
     content::ResourceContext* context,
     int render_process_id,
     int render_frame_id,
-    net::CookieOptions* options) {
+    const net::CookieOptions& options) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   ProfileIOData* io_data = ProfileIOData::FromResourceContext(context);
   content_settings::CookieSettings* cookie_settings =
@@ -1755,7 +1755,7 @@
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
       base::Bind(&TabSpecificContentSettings::CookieChanged, render_process_id,
-                 render_frame_id, url, first_party, cookie_line, *options,
+                 render_frame_id, url, first_party, cookie_line, options,
                  !allow));
   return allow;
 }
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index ce1a1ad0..13af6ee 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -143,7 +143,7 @@
                       content::ResourceContext* context,
                       int render_process_id,
                       int render_frame_id,
-                      net::CookieOptions* options) override;
+                      const net::CookieOptions& options) override;
   bool AllowSaveLocalState(content::ResourceContext* context) override;
   bool AllowWorkerDatabase(
       const GURL& url,
diff --git a/chrome/browser/content_settings/content_settings_browsertest.cc b/chrome/browser/content_settings/content_settings_browsertest.cc
index c08f653d..32e52bc02 100644
--- a/chrome/browser/content_settings/content_settings_browsertest.cc
+++ b/chrome/browser/content_settings/content_settings_browsertest.cc
@@ -33,6 +33,7 @@
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_utils.h"
+#include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/test/url_request/url_request_mock_http_job.h"
 
@@ -45,6 +46,19 @@
 using content::BrowserThread;
 using net::URLRequestMockHTTPJob;
 
+namespace {
+
+const LocalSharedObjectsContainer* GetSiteSettingsCookieContainer(
+    Browser* browser) {
+  TabSpecificContentSettings* settings =
+      TabSpecificContentSettings::FromWebContents(
+          browser->tab_strip_model()->GetWebContentsAt(0));
+  return static_cast<const LocalSharedObjectsContainer*>(
+      &settings->allowed_local_shared_objects());
+}
+
+}  // namespace
+
 class ContentSettingsTest : public InProcessBrowserTest {
  public:
   ContentSettingsTest() : https_server_(net::EmbeddedTestServer::TYPE_HTTPS) {
@@ -232,6 +246,38 @@
       IsContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES));
 }
 
+// TODO(jww): This should be removed after strict secure cookies is enabled for
+// all and this test should be moved into ContentSettingsTest above.
+class ContentSettingsStrictSecureCookiesBrowserTest
+    : public ContentSettingsTest {
+ protected:
+  void SetUpCommandLine(base::CommandLine* cmd) override {
+    cmd->AppendSwitch(switches::kEnableExperimentalWebPlatformFeatures);
+  }
+};
+
+// This test verifies that if strict secure cookies is enabled, the site
+// settings accurately reflect that an attempt to create a secure cookie by an
+// insecure origin fails.
+IN_PROC_BROWSER_TEST_F(ContentSettingsStrictSecureCookiesBrowserTest, Cookies) {
+  host_resolver()->AddRule("*", "127.0.0.1");
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
+  https_server.ServeFilesFromSourceDirectory("chrome/test/data");
+  ASSERT_TRUE(https_server.Start());
+
+  GURL http_url = embedded_test_server()->GetURL("/setsecurecookie.html");
+  GURL https_url = https_server.GetURL("/setsecurecookie.html");
+
+  ui_test_utils::NavigateToURL(browser(), http_url);
+  EXPECT_TRUE(GetSiteSettingsCookieContainer(browser())->cookies()->empty());
+
+  ui_test_utils::NavigateToURL(browser(),
+                               https_server.GetURL("/setsecurecookie.html"));
+  EXPECT_FALSE(GetSiteSettingsCookieContainer(browser())->cookies()->empty());
+};
+
 IN_PROC_BROWSER_TEST_F(ContentSettingsTest, ContentSettingsBlockDataURLs) {
   GURL url("data:text/html,<title>Data URL</title><script>alert(1)</script>");
 
diff --git a/chrome/browser/engagement/site_engagement_service.cc b/chrome/browser/engagement/site_engagement_service.cc
index 52cbaf0..b875eb6 100644
--- a/chrome/browser/engagement/site_engagement_service.cc
+++ b/chrome/browser/engagement/site_engagement_service.cc
@@ -15,7 +15,6 @@
 #include "base/time/clock.h"
 #include "base/time/default_clock.h"
 #include "base/values.h"
-#include "chrome/browser/banners/app_banner_settings_helper.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/engagement/site_engagement_eviction_policy.h"
 #include "chrome/browser/engagement/site_engagement_helper.h"
@@ -282,8 +281,7 @@
   // return true immediately.
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kEnableSiteEngagementService) ||
-      SiteEngagementEvictionPolicy::IsEnabled() ||
-      AppBannerSettingsHelper::ShouldUseSiteEngagementScore()) {
+      SiteEngagementEvictionPolicy::IsEnabled()) {
     return true;
   }
 
diff --git a/chrome/browser/engagement/site_engagement_service.h b/chrome/browser/engagement/site_engagement_service.h
index 46bf9896..6489fff 100644
--- a/chrome/browser/engagement/site_engagement_service.h
+++ b/chrome/browser/engagement/site_engagement_service.h
@@ -180,7 +180,6 @@
   FRIEND_TEST_ALL_PREFIXES(SiteEngagementServiceTest, GetTotalUserInputPoints);
   FRIEND_TEST_ALL_PREFIXES(SiteEngagementServiceTest,
                            CleanupOriginsOnHistoryDeletion);
-  FRIEND_TEST_ALL_PREFIXES(AppBannerSettingsHelperTest, SiteEngagementTrigger);
 
   // Only used in tests.
   SiteEngagementService(Profile* profile, scoped_ptr<base::Clock> clock);
diff --git a/chrome/browser/net/chrome_network_delegate.cc b/chrome/browser/net/chrome_network_delegate.cc
index b7fc936..eeee086 100644
--- a/chrome/browser/net/chrome_network_delegate.cc
+++ b/chrome/browser/net/chrome_network_delegate.cc
@@ -14,6 +14,7 @@
 #include "base/debug/dump_without_crashing.h"
 #include "base/debug/stack_trace.h"
 #include "base/logging.h"
+#include "base/metrics/field_trial.h"
 #include "base/metrics/histogram.h"
 #include "base/metrics/sparse_histogram.h"
 #include "base/metrics/user_metrics.h"
@@ -725,6 +726,14 @@
   return experimental_web_platform_features_enabled_;
 }
 
+bool ChromeNetworkDelegate::OnAreStrictSecureCookiesEnabled() const {
+  const std::string enforce_strict_secure_group =
+      base::FieldTrialList::FindFullName("StrictSecureCookies");
+  return experimental_web_platform_features_enabled_ ||
+         base::StartsWith(enforce_strict_secure_group, "Enabled",
+                          base::CompareCase::INSENSITIVE_ASCII);
+}
+
 bool ChromeNetworkDelegate::OnCancelURLRequestWithPolicyViolatingReferrerHeader(
     const net::URLRequest& request,
     const GURL& target_url,
diff --git a/chrome/browser/net/chrome_network_delegate.h b/chrome/browser/net/chrome_network_delegate.h
index e0ab87af..901e5423 100644
--- a/chrome/browser/net/chrome_network_delegate.h
+++ b/chrome/browser/net/chrome_network_delegate.h
@@ -183,6 +183,7 @@
       const GURL& url,
       const GURL& first_party_for_cookies) const override;
   bool OnAreExperimentalCookieFeaturesEnabled() const override;
+  bool OnAreStrictSecureCookiesEnabled() const override;
   bool OnCancelURLRequestWithPolicyViolatingReferrerHeader(
       const net::URLRequest& request,
       const GURL& target_url,
diff --git a/chrome/browser/ssl/ssl_browser_tests.cc b/chrome/browser/ssl/ssl_browser_tests.cc
index b4dfc61..a7416d75 100644
--- a/chrome/browser/ssl/ssl_browser_tests.cc
+++ b/chrome/browser/ssl/ssl_browser_tests.cc
@@ -552,36 +552,6 @@
   net::EmbeddedTestServer https_server_mismatched_;
   net::SpawnedTestServer wss_server_expired_;
 
- protected:
-  // Navigates to an interstitial and clicks through the certificate
-  // error; then navigates to a page at |path| that loads unsafe content.
-  void SetUpUnsafeContentsWithUserException(const std::string& path) {
-    ASSERT_TRUE(https_server_.Start());
-    // Note that it is necessary to user https_server_mismatched_ here over the
-    // other invalid cert servers. This is because the test relies on the two
-    // servers having different hosts since SSL exceptions are per-host, not per
-    // origin, and https_server_mismatched_ uses 'localhost' rather than
-    // '127.0.0.1'.
-    ASSERT_TRUE(https_server_mismatched_.Start());
-
-    // Navigate to an unsafe site. Proceed with interstitial page to indicate
-    // the user approves the bad certificate.
-    ui_test_utils::NavigateToURL(
-        browser(), https_server_mismatched_.GetURL("/ssl/blank_page.html"));
-    WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
-    CheckAuthenticationBrokenState(tab, net::CERT_STATUS_COMMON_NAME_INVALID,
-                                   AuthState::SHOWING_INTERSTITIAL);
-    ProceedThroughInterstitial(tab);
-    CheckAuthenticationBrokenState(tab, net::CERT_STATUS_COMMON_NAME_INVALID,
-                                   AuthState::NONE);
-
-    std::string replacement_path;
-    GetFilePathWithHostAndPortReplacement(
-        path, https_server_mismatched_.host_port_pair(), &replacement_path);
-    ui_test_utils::NavigateToURL(browser(),
-                                 https_server_.GetURL(replacement_path));
-  }
-
  private:
   typedef net::SpawnedTestServer::SSLOptions SSLOptions;
 
@@ -2152,7 +2122,10 @@
 
 // This test, and the related test TestUnsafeContentsWithUserException, verify
 // that if unsafe content is loaded but the host of that unsafe content has a
-// user exception, the content runs and the security style is downgraded.
+// user exception, the content runs and the security style remains
+// authenticated. This is not necessarily the behavior that should exist, but it
+// is verification that it does behave that way. See https://crbug.com/477868
+// for more inforamtion on this.
 IN_PROC_BROWSER_TEST_F(SSLUITest, TestUnsafeContentsInWorkerWithUserException) {
   ASSERT_TRUE(https_server_.Start());
   // Note that it is necessary to user https_server_mismatched_ here over the
@@ -2182,19 +2155,44 @@
   ui_test_utils::NavigateToURL(
       browser(), https_server_.GetURL(page_with_unsafe_worker_path));
   CheckWorkerLoadResult(tab, true);  // Worker loads insecure content
-  CheckAuthenticationBrokenState(tab, CertError::NONE,
-                                 AuthState::RAN_INSECURE_CONTENT);
+  CheckAuthenticatedState(tab, CertError::NONE);
 }
 
 // Visits a page with unsafe content and makes sure that if a user exception to
 // the certificate error is present, the image is loaded and script executes.
+//
+// See the comment above SSLUITest.TestUnsafeContentsInWorkerWithUserException
+// for a discussion about the desired behavior.
 IN_PROC_BROWSER_TEST_F(SSLUITest, TestUnsafeContentsWithUserException) {
+  ASSERT_TRUE(https_server_.Start());
+  // Note that it is necessary to user https_server_mismatched_ here over the
+  // other invalid cert servers. This is because the test relies on the two
+  // servers having different hosts since SSL exceptions are per-host, not per
+  // origin, and https_server_mismatched_ uses 'localhost' rather than
+  // '127.0.0.1'.
+  ASSERT_TRUE(https_server_mismatched_.Start());
+
+  // Navigate to an unsafe site. Proceed with interstitial page to indicate
+  // the user approves the bad certificate.
+  ui_test_utils::NavigateToURL(
+      browser(), https_server_mismatched_.GetURL("/ssl/blank_page.html"));
   WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
-  ASSERT_NO_FATAL_FAILURE(SetUpUnsafeContentsWithUserException(
-      "/ssl/page_with_unsafe_contents.html"));
-  CheckAuthenticationBrokenState(
-      tab, CertError::NONE,
-      AuthState::RAN_INSECURE_CONTENT | AuthState::DISPLAYED_INSECURE_CONTENT);
+  CheckAuthenticationBrokenState(tab, net::CERT_STATUS_COMMON_NAME_INVALID,
+                                 AuthState::SHOWING_INTERSTITIAL);
+  ProceedThroughInterstitial(tab);
+  CheckAuthenticationBrokenState(tab, net::CERT_STATUS_COMMON_NAME_INVALID,
+                                 AuthState::NONE);
+
+  std::string replacement_path;
+  GetFilePathWithHostAndPortReplacement(
+      "/ssl/page_with_unsafe_contents.html",
+      https_server_mismatched_.host_port_pair(), &replacement_path);
+  ui_test_utils::NavigateToURL(browser(),
+                               https_server_.GetURL(replacement_path));
+
+  // When the bad content is filtered, the state is expected to be
+  // authenticated.
+  CheckAuthenticatedState(tab, AuthState::NONE);
 
   int img_width;
   EXPECT_TRUE(content::ExecuteScriptAndExtractInt(
@@ -2208,38 +2206,7 @@
   EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
       tab, "window.domAutomationController.send(IsFooSet());", &js_result));
   EXPECT_TRUE(js_result);
-
-  // Test that active subresources with the same certificate errors as
-  // the main resources don't cause mixed content UI downgrades. (Such
-  // errors would be confusing and duplicative.)
-  std::string replacement_path;
-  GetFilePathWithHostAndPortReplacement(
-      "/ssl/page_with_unsafe_contents.html",
-      https_server_mismatched_.host_port_pair(), &replacement_path);
-  ui_test_utils::NavigateToURL(
-      browser(), https_server_mismatched_.GetURL(replacement_path));
-  js_result = false;
-  EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
-      tab, "window.domAutomationController.send(IsFooSet());", &js_result));
-  EXPECT_TRUE(js_result);
-  CheckAuthenticationBrokenState(tab, net::CERT_STATUS_COMMON_NAME_INVALID,
-                                 AuthState::NONE);
-}
-
-// Like the test above, but only displaying inactive content (an image).
-IN_PROC_BROWSER_TEST_F(SSLUITest, TestUnsafeImageWithUserException) {
-  WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
-  ASSERT_NO_FATAL_FAILURE(
-      SetUpUnsafeContentsWithUserException("/ssl/page_with_unsafe_image.html"));
-  CheckAuthenticatedState(tab, AuthState::DISPLAYED_INSECURE_CONTENT);
-
-  int img_width;
-  EXPECT_TRUE(content::ExecuteScriptAndExtractInt(
-      tab, "window.domAutomationController.send(ImageWidth());", &img_width));
-  // In order to check that the image was loaded, we check its width.
-  // The actual image (Google logo) is 114 pixels wide, so we assume a good
-  // image is greater than 100.
-  EXPECT_GT(img_width, 100);
+  CheckAuthenticatedState(tab, CertError::NONE);
 }
 
 // Test that when the browser blocks displaying insecure content (images), the
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index f71178a..9443ec0 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -520,12 +520,6 @@
 const char kDisableSimplifiedFullscreenUI[] =
     "disable-simplified-fullscreen-ui";
 
-// Enable the Site Engagement App Banner which triggers app install banners
-// using the site engagement service rather than a navigation-based heuristic.
-// Implicitly enables the site engagement service.
-const char kEnableSiteEngagementAppBanner[] =
-    "enable-site-engagement-app-banner";
-
 // Enable the Site Engagement Eviction Policy which evicts temporary storage
 // using the site engagement service. Implicitly enables the site engagement
 // service.
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 67908f2..6a4e48f 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -150,7 +150,6 @@
 extern const char kDisableSettingsWindow[];
 extern const char kEnableSimplifiedFullscreenUI[];
 extern const char kDisableSimplifiedFullscreenUI[];
-extern const char kEnableSiteEngagementAppBanner[];
 extern const char kEnableSiteEngagementEvictionPolicy[];
 extern const char kEnableSiteEngagementService[];
 extern const char kEnableSupervisedUserManagedBookmarksFolder[];
diff --git a/chrome/test/data/setsecurecookie.html b/chrome/test/data/setsecurecookie.html
new file mode 100644
index 0000000..18dc2dd
--- /dev/null
+++ b/chrome/test/data/setsecurecookie.html
@@ -0,0 +1,17 @@
+<html>
+<head>
+<title>This page sets a secure cookie</title>
+<script type="text/javascript">
+function makeCookie()
+{
+    console.log("cookies = " + document.cookie);
+    expireAt = new Date;
+    expireAt.setMonth(expireAt.getMonth() + 3);
+    username = "Good";
+    document.cookie = "name=" + username + ";expires=" + expireAt.toGMTString()
+      + ";secure";
+}
+makeCookie();
+</script>
+</head>
+</html>
diff --git a/chrome/test/data/ssl/page_with_dynamic_unsafe_image.html b/chrome/test/data/ssl/page_with_dynamic_unsafe_image.html
deleted file mode 100644
index d232531..0000000
--- a/chrome/test/data/ssl/page_with_dynamic_unsafe_image.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<html>
-<head><title>Page with unsafe image loaded dynamically</title>
-<script>
-  var url = "https://REPLACE_WITH_HOST_AND_PORT/ssl/google_files/logo.gif";
-
-  function AddImage() {
-    var img = document.createElement("img");
-    img.src = url;
-    document.body.appendChild(img);
-  }
-</script>
-<body></body>
-</html>
diff --git a/chrome/test/data/ssl/page_with_unsafe_image.html b/chrome/test/data/ssl/page_with_unsafe_image.html
deleted file mode 100644
index 9136e377..0000000
--- a/chrome/test/data/ssl/page_with_unsafe_image.html
+++ /dev/null
@@ -1,14 +0,0 @@
-<html>
-<head><title>Page with unsafe image</title>
-<script>
-  function ImageWidth() {
-    return document.getElementById("bad_image").width;
-  }
-</script>
-</head>
-
-<body>
-This page contains an image which is served over an insecure HTTPS connection...<br>
-<img id="bad_image" src="https://REPLACE_WITH_HOST_AND_PORT/ssl/google_files/logo.gif"/>
-</body>
-</html>
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_tamper_detection.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_tamper_detection.cc
index eaaf44e3..572cce52 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_tamper_detection.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_tamper_detection.cc
@@ -250,6 +250,10 @@
           "DataReductionProxy.HeaderTamperDetectionHTTP_Image_500KB",
           carrier_id_);
     }
+  } else if (net::MatchesMimeType("video/*", mime_type)) {
+    REPORT_TAMPER_DETECTION_UMA(
+        scheme_is_https_, "DataReductionProxy.HeaderTamperDetectionHTTPS_Video",
+        "DataReductionProxy.HeaderTamperDetectionHTTP_Video", carrier_id_);
   }
 }
 
@@ -490,6 +494,12 @@
       REPORT_TAMPER_DETECTION_UMA_COMPRESSION_RATIO(
           scheme_is_https_, "_Image_500KB", compression_ratio);
     }
+  } else if (net::MatchesMimeType("video/*", mime_type)) {
+    REPORT_TAMPER_DETECTION_UMA_AND_COMPRESSION_RATIO(
+        scheme_is_https_,
+        "DataReductionProxy.HeaderTamperedHTTPS_ContentLength_Video",
+        "DataReductionProxy.HeaderTamperedHTTP_ContentLength_Video",
+        carrier_id_, "_Video", compression_ratio);
   } else {
     REPORT_TAMPER_DETECTION_UMA(
         scheme_is_https_,
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_tamper_detection.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_tamper_detection.h
index 03611d6..b497712 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_tamper_detection.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_tamper_detection.h
@@ -105,6 +105,8 @@
                            HistogramCount);
   FRIEND_TEST_ALL_PREFIXES(DataReductionProxyTamperDetectionTest,
                            DetectAndReport);
+  FRIEND_TEST_ALL_PREFIXES(DataReductionProxyTamperDetectionTest,
+                           CompressionRatio);
 
   // Reports UMA for the numbers of responses with valid fingerprints, separated
   // by MIME type.
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_tamper_detection_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_tamper_detection_unittest.cc
index cdda92c..fff0914 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_tamper_detection_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_tamper_detection_unittest.cc
@@ -4,9 +4,9 @@
 
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_tamper_detection.h"
 
-#include <string.h>
 #include <algorithm>
 #include <map>
+#include <string>
 #include <vector>
 
 #include "base/base64.h"
@@ -14,6 +14,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
+#include "base/strings/stringprintf.h"
 #include "base/test/histogram_tester.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers_test_utils.h"
@@ -606,45 +607,35 @@
       // Checks the correctness of histogram for Javascript
       {"HTTP/1.1 200 OK\n"
        "Content-Type: text/javascript\n",
-       "_JS",
-       -1,
-       ""},
+       "_JS", -1, ""},
       // Checks the correctness of histogram for CSS
       {"HTTP/1.1 200 OK\n"
        "Content-Type: text/css\n",
-       "_CSS",
-       -1,
-       ""},
+       "_CSS", -1, ""},
       // Checks the correctness of histogram for image
       {"HTTP/1.1 200 OK\n"
        "Content-Type: image/test\n",
-       "_Image",
-       1,
-       "_Image_0_10KB"},
+       "_Image", 1, "_Image_0_10KB"},
       // Checks the correctness of histogram for GIF
       {"HTTP/1.1 200 OK\n"
        "Content-Type: image/gif\n",
-       "_Image_GIF",
-       20 * 1024,
-       "_Image_10_100KB"},
+       "_Image_GIF", 20 * 1024, "_Image_10_100KB"},
       // Checks the correctness of histogram for JPG
       {"HTTP/1.1 200 OK\n"
        "Content-Type: image/jpeg\n",
-       "_Image_JPG",
-       200 * 1024,
-       "_Image_100_500KB"},
+       "_Image_JPG", 200 * 1024, "_Image_100_500KB"},
       // Checks the correctness of histogram for PNG
       {"HTTP/1.1 200 OK\n"
        "Content-Type: image/png\n",
-       "_Image_PNG",
-       600 * 1024,
-       "_Image_500KB"},
+       "_Image_PNG", 600 * 1024, "_Image_500KB"},
       // Checks the correctness of histogram for WebP
       {"HTTP/1.1 200 OK\n"
        "Content-Type: image/webp\n",
-       "_Image_WEBP",
-       -1,
-       ""},
+       "_Image_WEBP", -1, ""},
+      // Checks the correctness of histogram for Video
+      {"HTTP/1.1 200 OK\n"
+       "Content-Type: video/webm\n",
+       "_Video", -1, ""},
   };
 
   const int carrier_id = 100;
@@ -665,37 +656,113 @@
       tamper_detection.ReportUMAForTamperDetectionCount(
           test.original_content_length);
       histogram_tester.ExpectTotalCount(
-          std::string("DataReductionProxy.HeaderTamperDetectionHTTP") +
-              (https ? "S" : "") + test.histogram_name_suffix + "_Total",
+          base::StringPrintf("DataReductionProxy.HeaderTamperDetectionHTTP%s"
+                             "%s_Total",
+                             (https ? "S" : ""),
+                             test.histogram_name_suffix.c_str()),
           1);
       histogram_tester.ExpectUniqueSample(
-          std::string("DataReductionProxy.HeaderTamperDetectionHTTP") +
-              (https ? "S" : "") + test.histogram_name_suffix,
+          base::StringPrintf("DataReductionProxy.HeaderTamperDetectionHTTP%s"
+                             "%s",
+                             (https ? "S" : ""),
+                             test.histogram_name_suffix.c_str()),
           carrier_id, 1);
       histogram_tester.ExpectTotalCount(
-          std::string("DataReductionProxy.HeaderTamperDetectionHTTP") +
-              (https ? "S" : "") + "_Total",
+          base::StringPrintf("DataReductionProxy.HeaderTamperDetectionHTTP%s"
+                             "_Total",
+                             (https ? "S" : "")),
           1);
       histogram_tester.ExpectUniqueSample(
-          std::string("DataReductionProxy.HeaderTamperDetectionHTTP") +
-              (https ? "S" : ""),
+          base::StringPrintf("DataReductionProxy.HeaderTamperDetectionHTTP%s",
+                             (https ? "S" : "")),
           carrier_id, 1);
 
       if (test.original_content_length != -1) {
         histogram_tester.ExpectTotalCount(
-            std::string("DataReductionProxy.HeaderTamperDetectionHTTP") +
-                (https ? "S" : "") + test.image_histogram_name_suffix +
-                "_Total",
+            base::StringPrintf("DataReductionProxy.HeaderTamperDetectionHTTP%s"
+                               "%s_Total",
+                               (https ? "S" : ""),
+                               test.image_histogram_name_suffix.c_str()),
             1);
         histogram_tester.ExpectUniqueSample(
-            std::string("DataReductionProxy.HeaderTamperDetectionHTTP") +
-                (https ? "S" : "") + test.image_histogram_name_suffix,
+            base::StringPrintf("DataReductionProxy.HeaderTamperDetectionHTTP%s"
+                               "%s",
+                               (https ? "S" : ""),
+                               test.image_histogram_name_suffix.c_str()),
             carrier_id, 1);
       }
     }
   }
 }
 
+// Tests function ReportUMAForContentLength, with the focus on compression
+// ratio.
+TEST_F(DataReductionProxyTamperDetectionTest, CompressionRatio) {
+  struct {
+    std::string raw_header;
+    std::string histogram_name_suffix;
+    int original_content_length;
+    int content_length;
+    int compression_ratio;
+    ;
+  } tests[] = {
+      // Checks the correctness of histogram for Video
+      {"HTTP/1.1 200 OK\n"
+       "Content-Type: video/webm\n",
+       "_Video", 1000, 800, 80},
+      // Checks the correctness of histogram for JPEG
+      {"HTTP/1.1 200 OK\n"
+       "Content-Type: image/jpg\n",
+       "_Image_JPG", 1000, 1, 0},
+      // Checks the correctness of histogram for PNG
+      {"HTTP/1.1 200 OK\n"
+       "Content-Type: image/png\n",
+       "_Image_PNG", 1000, 0, 0},
+      // Checks the correctness of histogram for WebP
+      {"HTTP/1.1 200 OK\n"
+       "Content-Type: image/webp\n",
+       "_Image_WEBP", 1000, 5000, 500},
+  };
+
+  const int carrier_id = 100;
+
+  for (auto& test : tests) {
+    std::string raw_headers(test.raw_header);
+    HeadersToRaw(&raw_headers);
+    scoped_refptr<net::HttpResponseHeaders> headers(
+        new net::HttpResponseHeaders(raw_headers));
+
+    // Test HTTPS and HTTP separately.
+    int https_values[] = {true, false};
+    for (auto https : https_values) {
+      base::HistogramTester histogram_tester;
+
+      DataReductionProxyTamperDetection tamper_detection(headers.get(), https,
+                                                         carrier_id);
+      tamper_detection.ReportUMAForContentLength(test.content_length,
+                                                 test.original_content_length);
+      histogram_tester.ExpectTotalCount(
+          base::StringPrintf("DataReductionProxy.HeaderTamperedHTTP%s"
+                             "_ContentLength%s_Total",
+                             (https ? "S" : ""),
+                             test.histogram_name_suffix.c_str()),
+          1);
+      histogram_tester.ExpectUniqueSample(
+          base::StringPrintf("DataReductionProxy.HeaderTamperedHTTP%s"
+                             "_ContentLength%s",
+                             (https ? "S" : ""),
+                             test.histogram_name_suffix.c_str()),
+          carrier_id, 1);
+      histogram_tester.ExpectUniqueSample(
+          base::StringPrintf("DataReductionProxy.HeaderTamperedHTTP%s"
+                             "_CompressionRatio%s",
+                             (https ? "S" : ""),
+                             test.histogram_name_suffix.c_str()),
+          test.compression_ratio, 1);
+    }
+  }
+}
+
 // Tests main function DetectAndReport.
 TEST_F(DataReductionProxyTamperDetectionTest, DetectAndReport) {
   struct {
diff --git a/components/web_view/frame.cc b/components/web_view/frame.cc
index 39077ae..de267a3 100644
--- a/components/web_view/frame.cc
+++ b/components/web_view/frame.cc
@@ -387,12 +387,12 @@
     // case we do not use the WindowTreeClient (because the app has a Window
     // already
     // and ends up reusing it).
-    DCHECK(!window_tree_client.get());
+    DCHECK(!window_tree_client);
     ChangeClient(frame_client, user_data.Pass(), window_tree_client.Pass(),
                  app_id, navigation_start_time);
   } else {
     waiting_for_on_will_navigate_ack_ = true;
-    DCHECK(window_tree_client.get());
+    DCHECK(window_tree_client);
     // TODO(sky): url isn't correct here, it should be a security origin.
     frame_client_->OnWillNavigate(
         url.spec(),
diff --git a/content/browser/browser_child_process_host_impl.cc b/content/browser/browser_child_process_host_impl.cc
index e297d778..671708a 100644
--- a/content/browser/browser_child_process_host_impl.cc
+++ b/content/browser/browser_child_process_host_impl.cc
@@ -401,8 +401,6 @@
   const base::Process& process = child_process_->GetProcess();
   DCHECK(process.IsValid());
 
-#if defined(OS_WIN)
-  // TODO(jam): enable on POSIX
   if (base::CommandLine::ForCurrentProcess()->HasSwitch("use-new-edk")) {
     mojo::embedder::ScopedPlatformHandle client_pipe =
         mojo::embedder::ChildProcessLaunched(process.Handle());
@@ -415,7 +413,6 @@
 #endif
                                      process.Handle(), true)));
   }
-#endif
 
 #if defined(OS_WIN)
   // Start a WaitableEventWatcher that will invoke OnProcessExitedEarly if the
diff --git a/content/browser/frame_host/render_frame_message_filter.cc b/content/browser/frame_host/render_frame_message_filter.cc
index 462f219..f14f8eb 100644
--- a/content/browser/frame_host/render_frame_message_filter.cc
+++ b/content/browser/frame_host/render_frame_message_filter.cc
@@ -351,22 +351,22 @@
   }
 
   net::CookieOptions options;
+  bool experimental_web_platform_features_enabled =
+      base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kEnableExperimentalWebPlatformFeatures);
+  const std::string enforce_strict_secure_group =
+      base::FieldTrialList::FindFullName(kEnforceStrictSecureExperiment);
+  if (experimental_web_platform_features_enabled)
+    options.set_enforce_prefixes();
+  if (experimental_web_platform_features_enabled ||
+      base::StartsWith(enforce_strict_secure_group, "Enabled",
+                       base::CompareCase::INSENSITIVE_ASCII)) {
+    options.set_enforce_strict_secure();
+  }
   if (GetContentClient()->browser()->AllowSetCookie(
           url, first_party_for_cookies, cookie, resource_context_,
-          render_process_id_, render_frame_id, &options)) {
+          render_process_id_, render_frame_id, options)) {
     net::URLRequestContext* context = GetRequestContextForURL(url);
-    bool experimental_web_platform_features_enabled =
-        base::CommandLine::ForCurrentProcess()->HasSwitch(
-            switches::kEnableExperimentalWebPlatformFeatures);
-    const std::string enforce_strict_secure_group =
-        base::FieldTrialList::FindFullName(kEnforceStrictSecureExperiment);
-    if (experimental_web_platform_features_enabled)
-      options.set_enforce_prefixes();
-    if (experimental_web_platform_features_enabled ||
-        base::StartsWith(enforce_strict_secure_group, "Enabled",
-                         base::CompareCase::INSENSITIVE_ASCII)) {
-      options.set_enforce_strict_secure();
-    }
     // Pass a null callback since we don't care about when the 'set' completes.
     context->cookie_store()->SetCookieWithOptionsAsync(
         url, cookie, options, net::CookieStore::SetCookiesCallback());
diff --git a/content/browser/loader/resource_loader.cc b/content/browser/loader/resource_loader.cc
index e8a404f..6238b25 100644
--- a/content/browser/loader/resource_loader.cc
+++ b/content/browser/loader/resource_loader.cc
@@ -115,9 +115,6 @@
     GetSSLStatusForRequest(request->url(), request->ssl_info(),
                            info->GetChildID(), &ssl_status);
     response->head.security_info = SerializeSecurityInfo(ssl_status);
-    response->head.has_major_certificate_errors =
-        net::IsCertStatusError(ssl_status.cert_status) &&
-        !net::IsCertStatusMinorError(ssl_status.cert_status);
   } else {
     // We should not have any SSL state.
     DCHECK(!request->ssl_info().cert_status);
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index c695f6f..12fb07aa 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -2478,8 +2478,6 @@
   SendExternalMojoShellHandleToChild(GetHandle(), this);
 #endif
 
-#if defined(OS_WIN)
-  // TODO(jam): enable on POSIX
   if (base::CommandLine::ForCurrentProcess()->HasSwitch("use-new-edk") &&
       child_process_launcher_.get()) {
     base::ProcessHandle process_handle =
@@ -2495,7 +2493,6 @@
 #endif
                                      process_handle, true)));
   }
-#endif
 
   // Allow Mojo to be setup before the renderer sees any Chrome IPC messages.
   // This way, Mojo can be safely used from the renderer in response to any
diff --git a/content/browser/ssl/ssl_manager.cc b/content/browser/ssl/ssl_manager.cc
index c1b42f0..cd6c2bea 100644
--- a/content/browser/ssl/ssl_manager.cc
+++ b/content/browser/ssl/ssl_manager.cc
@@ -134,7 +134,11 @@
   NotifyDidChangeVisibleSSLState();
 }
 
-void SSLManager::DidRunInsecureContent(const GURL& security_origin) {
+void SSLManager::DidDisplayInsecureContent() {
+  UpdateEntry(controller_->GetLastCommittedEntry());
+}
+
+void SSLManager::DidRunInsecureContent(const std::string& security_origin) {
   NavigationEntryImpl* navigation_entry = controller_->GetLastCommittedEntry();
   policy()->DidRunInsecureContent(navigation_entry, security_origin);
   UpdateEntry(navigation_entry);
diff --git a/content/browser/ssl/ssl_manager.h b/content/browser/ssl/ssl_manager.h
index fb31a25..6e46705 100644
--- a/content/browser/ssl/ssl_manager.h
+++ b/content/browser/ssl/ssl_manager.h
@@ -31,7 +31,6 @@
 struct LoadFromMemoryCacheDetails;
 struct ResourceRedirectDetails;
 struct ResourceRequestDetails;
-struct SSLStatus;
 
 // The SSLManager SSLManager controls the SSL UI elements in a WebContents.  It
 // listens for various events that influence when these elements should or
@@ -89,7 +88,8 @@
   void DidReceiveResourceRedirect(const ResourceRedirectDetails& details);
 
   // Insecure content entry point.
-  void DidRunInsecureContent(const GURL& security_origin);
+  void DidDisplayInsecureContent();
+  void DidRunInsecureContent(const std::string& security_origin);
 
  private:
   // Updates the NavigationEntry with our current state. This will
diff --git a/content/browser/ssl/ssl_policy.cc b/content/browser/ssl/ssl_policy.cc
index 06677dc..ed8d80b3 100644
--- a/content/browser/ssl/ssl_policy.cc
+++ b/content/browser/ssl/ssl_policy.cc
@@ -105,7 +105,7 @@
 }
 
 void SSLPolicy::DidRunInsecureContent(NavigationEntryImpl* entry,
-                                      const GURL& security_origin) {
+                                      const std::string& security_origin) {
   if (!entry)
     return;
 
@@ -113,16 +113,20 @@
   if (!site_instance)
       return;
 
-  backend_->HostRanInsecureContent(security_origin.host(),
+  backend_->HostRanInsecureContent(GURL(security_origin).host(),
                                    site_instance->GetProcess()->GetID());
 }
 
 void SSLPolicy::OnRequestStarted(SSLRequestInfo* info) {
-  if (info->ssl_cert_id() && info->url().SchemeIsCryptographic() &&
-      !net::IsCertStatusError(info->ssl_cert_status())) {
-    // If the scheme is https: or wss: *and* the security info for the
-    // cert has been set (i.e. the cert id is not 0) and the cert did
-    // not have any errors, revoke any previous decisions that
+  // TODO(abarth): This mechanism is wrong.  What we should be doing is sending
+  // this information back through WebKit and out some FrameLoaderClient
+  // methods.
+
+  if (net::IsCertStatusError(info->ssl_cert_status())) {
+    backend_->HostRanInsecureContent(info->url().host(), info->child_id());
+  } else if (info->ssl_cert_id() && info->url().SchemeIsCryptographic()) {
+    // If the scheme is https: or wss: *and* the security info for the cert has
+    // been set (i.e. the cert id is not 0), revoke any previous decisions that
     // have occurred. If the cert info has not been set, do nothing since it
     // isn't known if the connection was actually a valid connection or if it
     // had a cert error.
diff --git a/content/browser/ssl/ssl_policy.h b/content/browser/ssl/ssl_policy.h
index c002bfc..2855a1b 100644
--- a/content/browser/ssl/ssl_policy.h
+++ b/content/browser/ssl/ssl_policy.h
@@ -36,7 +36,7 @@
   void OnCertError(SSLCertErrorHandler* handler);
 
   void DidRunInsecureContent(NavigationEntryImpl* entry,
-                             const GURL& security_origin);
+                             const std::string& security_origin);
 
   // We have started a resource request with the given info.
   void OnRequestStarted(SSLRequestInfo* info);
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index da841da..7556ae8 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -645,10 +645,6 @@
                         OnDidDisplayInsecureContent)
     IPC_MESSAGE_HANDLER(FrameHostMsg_DidRunInsecureContent,
                         OnDidRunInsecureContent)
-    IPC_MESSAGE_HANDLER(FrameHostMsg_DidDisplayContentWithCertificateErrors,
-                        OnDidDisplayContentWithCertificateErrors)
-    IPC_MESSAGE_HANDLER(FrameHostMsg_DidRunContentWithCertificateErrors,
-                        OnDidRunContentWithCertificateErrors)
     IPC_MESSAGE_HANDLER(ViewHostMsg_GoToEntryAtOffset, OnGoToEntryAtOffset)
     IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateZoomLimits, OnUpdateZoomLimits)
     IPC_MESSAGE_HANDLER(ViewHostMsg_PageScaleFactorChanged,
@@ -3185,12 +3181,12 @@
       GetController().GetBrowserContext());
 }
 
-void WebContentsImpl::OnDidRunInsecureContent(const GURL& security_origin,
-                                              const GURL& target_url) {
+void WebContentsImpl::OnDidRunInsecureContent(
+    const std::string& security_origin, const GURL& target_url) {
   LOG(WARNING) << security_origin << " ran insecure content from "
                << target_url.possibly_invalid_spec();
   RecordAction(base::UserMetricsAction("SSL.RanInsecureContent"));
-  if (base::EndsWith(security_origin.spec(), kDotGoogleDotCom,
+  if (base::EndsWith(security_origin, kDotGoogleDotCom,
                      base::CompareCase::INSENSITIVE_ASCII))
     RecordAction(base::UserMetricsAction("SSL.RanInsecureContentGoogle"));
   controller_.ssl_manager()->DidRunInsecureContent(security_origin);
@@ -3198,39 +3194,6 @@
       GetController().GetBrowserContext());
 }
 
-void WebContentsImpl::OnDidDisplayContentWithCertificateErrors(
-    const GURL& url,
-    const std::string& security_info) {
-  SSLStatus ssl;
-  if (!DeserializeSecurityInfo(security_info, &ssl)) {
-    bad_message::ReceivedBadMessage(
-        GetRenderProcessHost(),
-        bad_message::WC_CONTENT_WITH_CERT_ERRORS_BAD_SECURITY_INFO);
-    return;
-  }
-
-  displayed_insecure_content_ = true;
-  SSLManager::NotifySSLInternalStateChanged(
-      GetController().GetBrowserContext());
-}
-
-void WebContentsImpl::OnDidRunContentWithCertificateErrors(
-    const GURL& security_origin,
-    const GURL& url,
-    const std::string& security_info) {
-  SSLStatus ssl;
-  if (!DeserializeSecurityInfo(security_info, &ssl)) {
-    bad_message::ReceivedBadMessage(
-        GetRenderProcessHost(),
-        bad_message::WC_CONTENT_WITH_CERT_ERRORS_BAD_SECURITY_INFO);
-    return;
-  }
-
-  controller_.ssl_manager()->DidRunInsecureContent(security_origin);
-  SSLManager::NotifySSLInternalStateChanged(
-      GetController().GetBrowserContext());
-}
-
 void WebContentsImpl::OnDocumentLoadedInFrame() {
   if (!HasValidFrameSource())
     return;
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index 016566e..213cc58 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -841,14 +841,8 @@
                                         const std::string& mime_type,
                                         ResourceType resource_type);
   void OnDidDisplayInsecureContent();
-  void OnDidRunInsecureContent(const GURL& security_origin,
+  void OnDidRunInsecureContent(const std::string& security_origin,
                                const GURL& target_url);
-  void OnDidDisplayContentWithCertificateErrors(
-      const GURL& url,
-      const std::string& security_info);
-  void OnDidRunContentWithCertificateErrors(const GURL& security_origin,
-                                            const GURL& url,
-                                            const std::string& security_info);
   void OnDocumentLoadedInFrame();
   void OnDidFinishLoad(const GURL& url);
   void OnGoToEntryAtOffset(int offset);
diff --git a/content/child/child_thread_impl.cc b/content/child/child_thread_impl.cc
index cf466cc..07977ba 100644
--- a/content/child/child_thread_impl.cc
+++ b/content/child/child_thread_impl.cc
@@ -414,6 +414,7 @@
     IPC::Logging::GetInstance()->SetIPCSender(this);
 #endif
 
+  mojo_ipc_support_.reset(new IPC::ScopedIPCSupport(GetIOTaskRunner()));
   mojo_application_.reset(new MojoApplication(GetIOTaskRunner()));
 
   sync_message_filter_ = channel_->CreateSyncMessageFilter();
@@ -653,10 +654,8 @@
                         OnProcessBackgrounded)
     IPC_MESSAGE_HANDLER(MojoMsg_BindExternalMojoShellHandle,
                         OnBindExternalMojoShellHandle)
-#if defined(OS_WIN)
     IPC_MESSAGE_HANDLER(ChildProcessMsg_SetMojoParentPipeHandle,
                         OnSetMojoParentPipeHandle)
-#endif
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
 
diff --git a/content/child/child_thread_impl.h b/content/child/child_thread_impl.h
index 09a58b8..9f4df7f 100644
--- a/content/child/child_thread_impl.h
+++ b/content/child/child_thread_impl.h
@@ -235,6 +235,7 @@
 
   void EnsureConnected();
 
+  scoped_ptr<IPC::ScopedIPCSupport> mojo_ipc_support_;
   scoped_ptr<MojoApplication> mojo_application_;
 
   std::string channel_name_;
diff --git a/content/child/web_url_loader_impl.cc b/content/child/web_url_loader_impl.cc
index dbcff212..bea6020 100644
--- a/content/child/web_url_loader_impl.cc
+++ b/content/child/web_url_loader_impl.cc
@@ -887,7 +887,6 @@
   response->setTextEncodingName(WebString::fromUTF8(info.charset));
   response->setExpectedContentLength(info.content_length);
   response->setSecurityInfo(info.security_info);
-  response->setHasMajorCertificateErrors(info.has_major_certificate_errors);
   response->setAppCacheID(info.appcache_id);
   response->setAppCacheManifestURL(info.appcache_manifest_url);
   response->setWasCached(!info.load_timing.request_start_time.is_null() &&
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h
index 01d5fdf..36aebda 100644
--- a/content/common/frame_messages.h
+++ b/content/common/frame_messages.h
@@ -1224,22 +1224,9 @@
 
 // Sent when the renderer runs insecure content in a secure origin.
 IPC_MESSAGE_ROUTED2(FrameHostMsg_DidRunInsecureContent,
-                    GURL /* security_origin */,
+                    std::string /* security_origin */,
                     GURL /* target URL */)
 
-// Sent when the renderer displays content that was loaded with
-// certificate errors.
-IPC_MESSAGE_ROUTED2(FrameHostMsg_DidDisplayContentWithCertificateErrors,
-                    GURL /* resource url */,
-                    std::string /* serialized security info */)
-
-// Sent when the renderer runs content that was loaded with certificate
-// errors.
-IPC_MESSAGE_ROUTED3(FrameHostMsg_DidRunContentWithCertificateErrors,
-                    GURL /* security_origin */,
-                    GURL /* resource url */,
-                    std::string /* serialized security info */)
-
 // Response to FrameMsg_GetSavableResourceLinks.
 IPC_MESSAGE_ROUTED3(FrameHostMsg_SavableResourceLinksResponse,
                     std::vector<GURL> /* savable resource links */,
diff --git a/content/common/resource_messages.h b/content/common/resource_messages.h
index a1918ed..dc4bac4 100644
--- a/content/common/resource_messages.h
+++ b/content/common/resource_messages.h
@@ -115,7 +115,6 @@
   IPC_STRUCT_TRAITS_MEMBER(mime_type)
   IPC_STRUCT_TRAITS_MEMBER(charset)
   IPC_STRUCT_TRAITS_MEMBER(security_info)
-  IPC_STRUCT_TRAITS_MEMBER(has_major_certificate_errors)
   IPC_STRUCT_TRAITS_MEMBER(content_length)
   IPC_STRUCT_TRAITS_MEMBER(encoded_data_length)
   IPC_STRUCT_TRAITS_MEMBER(appcache_id)
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc
index cc76f06c..9e803011 100644
--- a/content/public/browser/content_browser_client.cc
+++ b/content/public/browser/content_browser_client.cc
@@ -175,7 +175,7 @@
                                           ResourceContext* context,
                                           int render_process_id,
                                           int render_frame_id,
-                                          net::CookieOptions* options) {
+                                          const net::CookieOptions& options) {
   return true;
 }
 
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index d3d9f01..0f80710 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -361,7 +361,7 @@
                               ResourceContext* context,
                               int render_process_id,
                               int render_frame_id,
-                              net::CookieOptions* options);
+                              const net::CookieOptions& options);
 
   // This is called on the IO thread.
   virtual bool AllowSaveLocalState(ResourceContext* context);
diff --git a/content/public/common/resource_response.cc b/content/public/common/resource_response.cc
index 12773554..12f1dd7 100644
--- a/content/public/common/resource_response.cc
+++ b/content/public/common/resource_response.cc
@@ -19,8 +19,6 @@
   new_response->head.mime_type = head.mime_type;
   new_response->head.charset = head.charset;
   new_response->head.security_info = head.security_info;
-  new_response->head.has_major_certificate_errors =
-      head.has_major_certificate_errors;
   new_response->head.content_length = head.content_length;
   new_response->head.encoded_data_length = head.encoded_data_length;
   new_response->head.appcache_id = head.appcache_id;
diff --git a/content/public/common/resource_response_info.cc b/content/public/common/resource_response_info.cc
index f05ee19..1d4e304 100644
--- a/content/public/common/resource_response_info.cc
+++ b/content/public/common/resource_response_info.cc
@@ -10,8 +10,7 @@
 namespace content {
 
 ResourceResponseInfo::ResourceResponseInfo()
-    : has_major_certificate_errors(false),
-      content_length(-1),
+    : content_length(-1),
       encoded_data_length(-1),
       appcache_id(kAppCacheNoCacheId),
       was_fetched_via_spdy(false),
@@ -23,7 +22,8 @@
       was_fallback_required_by_service_worker(false),
       response_type_via_service_worker(
           blink::WebServiceWorkerResponseTypeDefault),
-      is_using_lofi(false) {}
+      is_using_lofi(false) {
+}
 
 ResourceResponseInfo::~ResourceResponseInfo() {
 }
diff --git a/content/public/common/resource_response_info.h b/content/public/common/resource_response_info.h
index 8b81f6d..1a0f126 100644
--- a/content/public/common/resource_response_info.h
+++ b/content/public/common/resource_response_info.h
@@ -50,9 +50,6 @@
   // response.  This may include information about the SSL connection used.
   std::string security_info;
 
-  // True if the resource was loaded in spite of certificate errors.
-  bool has_major_certificate_errors;
-
   // Content length if available. -1 if not available
   int64 content_length;
 
diff --git a/content/renderer/DEPS b/content/renderer/DEPS
index b070955..3a49854 100644
--- a/content/renderer/DEPS
+++ b/content/renderer/DEPS
@@ -29,5 +29,8 @@
   '.*_[a-z]*browsertest.*': [
     "+content/public/browser",
     "+content/shell",
+  ],

+  "render_thread_impl_browsertest\.cc": [

+    "+content/app/mojo/mojo_init.h",

   ],
 }
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 860e3d5..314fe7b 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -48,7 +48,6 @@
 #include "content/common/savable_subframe.h"
 #include "content/common/service_worker/service_worker_types.h"
 #include "content/common/site_isolation_policy.h"
-#include "content/common/ssl_status_serialization.h"
 #include "content/common/swapped_out_messages.h"
 #include "content/common/view_messages.h"
 #include "content/public/common/bindings_policy.h"
@@ -568,38 +567,6 @@
 
 void OnGotContentHandlerID(uint32_t content_handler_id) {}
 
-bool IsContentWithCertificateErrorsRelevantToUI(
-    const blink::WebURL& url,
-    const blink::WebCString& security_info,
-    const blink::WebURL& main_resource_url,
-    const blink::WebCString& main_resource_security_info) {
-  content::SSLStatus ssl_status;
-  content::SSLStatus main_resource_ssl_status;
-  CHECK(DeserializeSecurityInfo(security_info, &ssl_status));
-  CHECK(DeserializeSecurityInfo(main_resource_security_info,
-                                &main_resource_ssl_status));
-
-  if (!GURL(main_resource_url).SchemeIsCryptographic())
-    return false;
-
-  // Do not handle subresource certificate errors if they are the same
-  // as errors that occured during the main page load. This compares
-  // most, but not all, fields of SSLStatus. For example, this check
-  // does not compare |content_status| because the navigation entry
-  // might have mixed content but also have the exact same SSL
-  // connection properties as the subresource, thereby making the
-  // subresource errors duplicative.
-  return (!url::Origin(GURL(url))
-               .IsSameOriginWith(url::Origin(GURL(main_resource_url))) ||
-          main_resource_ssl_status.security_style !=
-              ssl_status.security_style ||
-          main_resource_ssl_status.cert_id != ssl_status.cert_id ||
-          main_resource_ssl_status.cert_status != ssl_status.cert_status ||
-          main_resource_ssl_status.security_bits != ssl_status.security_bits ||
-          main_resource_ssl_status.connection_status !=
-              ssl_status.connection_status);
-}
-
 }  // namespace
 
 // static
@@ -3706,38 +3673,12 @@
     const blink::WebSecurityOrigin& origin,
     const blink::WebURL& target) {
   Send(new FrameHostMsg_DidRunInsecureContent(
-      routing_id_, GURL(origin.toString().utf8()), target));
+      routing_id_, origin.toString().utf8(), target));
   GetContentClient()->renderer()->RecordRapporURL(
       "ContentSettings.MixedScript.RanMixedScript",
       GURL(origin.toString().utf8()));
 }
 
-void RenderFrameImpl::didDisplayContentWithCertificateErrors(
-    const blink::WebURL& url,
-    const blink::WebCString& security_info,
-    const blink::WebURL& main_resource_url,
-    const blink::WebCString& main_resource_security_info) {
-  if (!IsContentWithCertificateErrorsRelevantToUI(
-          url, security_info, main_resource_url, main_resource_security_info)) {
-    return;
-  }
-  Send(new FrameHostMsg_DidDisplayContentWithCertificateErrors(routing_id_, url,
-                                                               security_info));
-}
-
-void RenderFrameImpl::didRunContentWithCertificateErrors(
-    const blink::WebURL& url,
-    const blink::WebCString& security_info,
-    const blink::WebURL& main_resource_url,
-    const blink::WebCString& main_resource_security_info) {
-  if (!IsContentWithCertificateErrorsRelevantToUI(
-          url, security_info, main_resource_url, main_resource_security_info)) {
-    return;
-  }
-  Send(new FrameHostMsg_DidRunContentWithCertificateErrors(
-      routing_id_, GURL(main_resource_url).GetOrigin(), url, security_info));
-}
-
 void RenderFrameImpl::didChangePerformanceTiming() {
   FOR_EACH_OBSERVER(RenderFrameObserver,
                     observers_,
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index bae9b33..c357ff8 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -522,16 +522,6 @@
   void didDisplayInsecureContent() override;
   void didRunInsecureContent(const blink::WebSecurityOrigin& origin,
                              const blink::WebURL& target) override;
-  void didDisplayContentWithCertificateErrors(
-      const blink::WebURL& url,
-      const blink::WebCString& security_info,
-      const blink::WebURL& main_resource_url,
-      const blink::WebCString& main_resource_security_info) override;
-  void didRunContentWithCertificateErrors(
-      const blink::WebURL& url,
-      const blink::WebCString& security_info,
-      const blink::WebURL& main_resource_url,
-      const blink::WebCString& main_resource_security_info) override;
   void didChangePerformanceTiming() override;
   void didCreateScriptContext(blink::WebLocalFrame* frame,
                               v8::Local<v8::Context> context,
diff --git a/content/renderer/render_thread_impl_browsertest.cc b/content/renderer/render_thread_impl_browsertest.cc
index c31cc14..d814e56 100644
--- a/content/renderer/render_thread_impl_browsertest.cc
+++ b/content/renderer/render_thread_impl_browsertest.cc
@@ -9,7 +9,8 @@
 #include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/thread_task_runner_handle.h"
-#include "components/scheduler/renderer/renderer_scheduler.h"
+#include "components/scheduler/renderer/renderer_scheduler.h"

+#include "content/app/mojo/mojo_init.h"
 #include "content/common/in_process_child_thread_params.h"
 #include "content/common/resource_messages.h"
 #include "content/common/websocket_messages.h"
@@ -173,6 +174,7 @@
 
     scoped_ptr<scheduler::RendererScheduler> renderer_scheduler =
         scheduler::RendererScheduler::Create();
+    InitializeMojo();
     thread_ = new RenderThreadImplForTest(
         InProcessChildThreadParams(test_helper_->GetChannelId(),
                                    test_helper_->GetIOTaskRunner()),
diff --git a/content/shell/browser/shell_network_delegate.cc b/content/shell/browser/shell_network_delegate.cc
index c4cd0da..db264ab 100644
--- a/content/shell/browser/shell_network_delegate.cc
+++ b/content/shell/browser/shell_network_delegate.cc
@@ -5,6 +5,7 @@
 #include "content/shell/browser/shell_network_delegate.h"
 
 #include "base/command_line.h"
+#include "base/strings/string_util.h"
 #include "content/public/common/content_switches.h"
 #include "net/base/net_errors.h"
 #include "net/base/static_cookie_policy.h"
@@ -112,4 +113,8 @@
       switches::kEnableExperimentalWebPlatformFeatures);
 }
 
+bool ShellNetworkDelegate::OnAreStrictSecureCookiesEnabled() const {
+  return OnAreExperimentalCookieFeaturesEnabled();
+}
+
 }  // namespace content
diff --git a/content/shell/browser/shell_network_delegate.h b/content/shell/browser/shell_network_delegate.h
index cffc3b9f..cb8d656 100644
--- a/content/shell/browser/shell_network_delegate.h
+++ b/content/shell/browser/shell_network_delegate.h
@@ -53,6 +53,7 @@
   bool OnCanAccessFile(const net::URLRequest& request,
                        const base::FilePath& path) const override;
   bool OnAreExperimentalCookieFeaturesEnabled() const override;
+  bool OnAreStrictSecureCookiesEnabled() const override;
 
   DISALLOW_COPY_AND_ASSIGN(ShellNetworkDelegate);
 };
diff --git a/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothDevice.java b/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothDevice.java
index 6e20600..b11244e0 100644
--- a/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothDevice.java
+++ b/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothDevice.java
@@ -186,10 +186,15 @@
             ThreadUtils.runOnUiThread(new Runnable() {
                 @Override
                 public void run() {
-                    ChromeBluetoothRemoteGattCharacteristic
-                            chromeBluetoothRemoteGattCharacteristic =
-                                    mWrapperToChromeCharacteristicsMap.get(characteristic);
-                    chromeBluetoothRemoteGattCharacteristic.onCharacteristicRead(status);
+                    ChromeBluetoothRemoteGattCharacteristic chromeCharacteristic =
+                            mWrapperToChromeCharacteristicsMap.get(characteristic);
+                    if (chromeCharacteristic == null) {
+                        // Android events arriving with no Chrome object is expected rarely: only
+                        // when the event races object destruction.
+                        Log.v(TAG, "onCharacteristicRead when chromeCharacteristic == null.");
+                    } else {
+                        chromeCharacteristic.onCharacteristicRead(status);
+                    }
                 }
             });
         }
@@ -201,10 +206,15 @@
             ThreadUtils.runOnUiThread(new Runnable() {
                 @Override
                 public void run() {
-                    ChromeBluetoothRemoteGattCharacteristic
-                            chromeBluetoothRemoteGattCharacteristic =
-                                    mWrapperToChromeCharacteristicsMap.get(characteristic);
-                    chromeBluetoothRemoteGattCharacteristic.onCharacteristicWrite(status);
+                    ChromeBluetoothRemoteGattCharacteristic chromeCharacteristic =
+                            mWrapperToChromeCharacteristicsMap.get(characteristic);
+                    if (chromeCharacteristic == null) {
+                        // Android events arriving with no Chrome object is expected rarely: only
+                        // when the event races object destruction.
+                        Log.v(TAG, "onCharacteristicWrite when chromeCharacteristic == null.");
+                    } else {
+                        chromeCharacteristic.onCharacteristicWrite(status);
+                    }
                 }
             });
         }
diff --git a/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattCharacteristic.java b/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattCharacteristic.java
index dd0d2617..3b64681 100644
--- a/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattCharacteristic.java
+++ b/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattCharacteristic.java
@@ -42,6 +42,7 @@
      */
     @CalledByNative
     private void onBluetoothRemoteGattCharacteristicAndroidDestruction() {
+        Log.v(TAG, "ChromeBluetoothRemoteGattCharacteristic Destroyed.");
         mNativeBluetoothRemoteGattCharacteristicAndroid = 0;
         mChromeBluetoothDevice.mWrapperToChromeCharacteristicsMap.remove(mCharacteristic);
     }
diff --git a/device/bluetooth/bluetooth_gatt_characteristic_unittest.cc b/device/bluetooth/bluetooth_gatt_characteristic_unittest.cc
index 17e77e9..bbca500 100644
--- a/device/bluetooth/bluetooth_gatt_characteristic_unittest.cc
+++ b/device/bluetooth/bluetooth_gatt_characteristic_unittest.cc
@@ -214,6 +214,42 @@
 #endif  // defined(OS_ANDROID)
 
 #if defined(OS_ANDROID)
+// Tests ReadRemoteCharacteristic completing after Chrome objects are deleted.
+TEST_F(BluetoothGattCharacteristicTest, ReadRemoteCharacteristic_AfterDeleted) {
+  ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate());
+
+  characteristic1_->ReadRemoteCharacteristic(
+      GetReadValueCallback(Call::NOT_EXPECTED),
+      GetGattErrorCallback(Call::NOT_EXPECTED));
+
+  RememberCharacteristicForSubsequentAction(characteristic1_);
+  DeleteDevice(device_);
+
+  std::vector<uint8_t> empty_vector;
+  SimulateGattCharacteristicRead(/* use remembered characteristic */ nullptr,
+                                 empty_vector);
+}
+#endif  // defined(OS_ANDROID)
+
+#if defined(OS_ANDROID)
+// Tests WriteRemoteCharacteristic completing after Chrome objects are deleted.
+TEST_F(BluetoothGattCharacteristicTest,
+       WriteRemoteCharacteristic_AfterDeleted) {
+  ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate());
+
+  std::vector<uint8_t> empty_vector;
+  characteristic1_->WriteRemoteCharacteristic(
+      empty_vector, GetCallback(Call::NOT_EXPECTED),
+      GetGattErrorCallback(Call::NOT_EXPECTED));
+
+  RememberCharacteristicForSubsequentAction(characteristic1_);
+  DeleteDevice(device_);
+
+  SimulateGattCharacteristicWrite(/* use remembered characteristic */ nullptr);
+}
+#endif  // defined(OS_ANDROID)
+
+#if defined(OS_ANDROID)
 // Tests ReadRemoteCharacteristic and GetValue with non-empty value buffer.
 TEST_F(BluetoothGattCharacteristicTest, ReadRemoteCharacteristic) {
   ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate());
diff --git a/device/bluetooth/test/android/java/src/org/chromium/device/bluetooth/Fakes.java b/device/bluetooth/test/android/java/src/org/chromium/device/bluetooth/Fakes.java
index d01cc1e..e9485e58 100644
--- a/device/bluetooth/test/android/java/src/org/chromium/device/bluetooth/Fakes.java
+++ b/device/bluetooth/test/android/java/src/org/chromium/device/bluetooth/Fakes.java
@@ -428,6 +428,7 @@
         final int mProperties;
         final UUID mUuid;
         byte[] mValue;
+        static FakeBluetoothGattCharacteristic sRememberedCharacteristic;
 
         public FakeBluetoothGattCharacteristic(
                 FakeBluetoothGattService service, int instanceId, int properties, UUID uuid) {
@@ -441,10 +442,23 @@
 
         // Simulate a value being read from a characteristic.
         @CalledByNative("FakeBluetoothGattCharacteristic")
+        private static void rememberCharacteristic(
+                ChromeBluetoothRemoteGattCharacteristic chromeCharacteristic) {
+            sRememberedCharacteristic =
+                    (FakeBluetoothGattCharacteristic) chromeCharacteristic.mCharacteristic;
+        }
+
+        // Simulate a value being read from a characteristic.
+        @CalledByNative("FakeBluetoothGattCharacteristic")
         private static void valueRead(ChromeBluetoothRemoteGattCharacteristic chromeCharacteristic,
                 int status, byte[] value) {
-            FakeBluetoothGattCharacteristic fakeCharacteristic =
-                    (FakeBluetoothGattCharacteristic) chromeCharacteristic.mCharacteristic;
+            if (chromeCharacteristic == null && sRememberedCharacteristic == null)
+                throw new IllegalArgumentException(
+                        "rememberCharacteristic wasn't called previously.");
+
+            FakeBluetoothGattCharacteristic fakeCharacteristic = (chromeCharacteristic == null)
+                    ? sRememberedCharacteristic
+                    : (FakeBluetoothGattCharacteristic) chromeCharacteristic.mCharacteristic;
 
             fakeCharacteristic.mValue = value;
             fakeCharacteristic.mService.mDevice.mGattCallback.onCharacteristicRead(
@@ -455,8 +469,13 @@
         @CalledByNative("FakeBluetoothGattCharacteristic")
         private static void valueWrite(
                 ChromeBluetoothRemoteGattCharacteristic chromeCharacteristic, int status) {
-            FakeBluetoothGattCharacteristic fakeCharacteristic =
-                    (FakeBluetoothGattCharacteristic) chromeCharacteristic.mCharacteristic;
+            if (chromeCharacteristic == null && sRememberedCharacteristic == null)
+                throw new IllegalArgumentException(
+                        "rememberCharacteristic wasn't called previously.");
+
+            FakeBluetoothGattCharacteristic fakeCharacteristic = (chromeCharacteristic == null)
+                    ? sRememberedCharacteristic
+                    : (FakeBluetoothGattCharacteristic) chromeCharacteristic.mCharacteristic;
 
             fakeCharacteristic.mService.mDevice.mGattCallback.onCharacteristicWrite(
                     fakeCharacteristic, status);
diff --git a/device/bluetooth/test/bluetooth_test.h b/device/bluetooth/test/bluetooth_test.h
index a0066e9..3ddfec9 100644
--- a/device/bluetooth/test/bluetooth_test.h
+++ b/device/bluetooth/test/bluetooth_test.h
@@ -118,6 +118,14 @@
                                           const std::string& uuid,
                                           int properties) {}
 
+  // Remembers |characteristic|'s platform specific object to be used in a
+  // subsequent call to methods such as SimulateGattCharacteristicRead that
+  // accept a nullptr value to select this remembered characteristic. This
+  // enables tests where the platform attempts to reference characteristic
+  // objects after the Chrome objects have been deleted, e.g. with DeleteDevice.
+  virtual void RememberCharacteristicForSubsequentAction(
+      BluetoothGattCharacteristic* characteristic) {}
+
   // Simulates a Characteristic Set Notify success.
   virtual void SimulateGattNotifySessionStarted(
       BluetoothGattCharacteristic* characteristic) {}
@@ -128,6 +136,8 @@
       BluetoothGattCharacteristic* characteristic) {}
 
   // Simulates a Characteristic Read operation succeeding, returning |value|.
+  // If |characteristic| is null, acts upon the characteristic provided to
+  // RememberCharacteristicForSubsequentAction.
   virtual void SimulateGattCharacteristicRead(
       BluetoothGattCharacteristic* characteristic,
       const std::vector<uint8>& value) {}
@@ -143,6 +153,8 @@
       BluetoothGattCharacteristic* characteristic) {}
 
   // Simulates a Characteristic Write operation succeeding, returning |value|.
+  // If |characteristic| is null, acts upon the characteristic provided to
+  // RememberCharacteristicForSubsequentAction.
   virtual void SimulateGattCharacteristicWrite(
       BluetoothGattCharacteristic* characteristic) {}
 
@@ -156,7 +168,7 @@
   virtual void SimulateGattCharacteristicWriteWillFailSynchronouslyOnce(
       BluetoothGattCharacteristic* characteristic) {}
 
-  // Remove the device from the adapter and delete it.
+  // Removes the device from the adapter and deletes it.
   virtual void DeleteDevice(BluetoothDevice* device);
 
   // Callbacks that increment |callback_count_|, |error_callback_count_|:
diff --git a/device/bluetooth/test/bluetooth_test_android.cc b/device/bluetooth/test/bluetooth_test_android.cc
index bb55650..d822a7c 100644
--- a/device/bluetooth/test/bluetooth_test_android.cc
+++ b/device/bluetooth/test/bluetooth_test_android.cc
@@ -163,6 +163,16 @@
       base::android::ConvertUTF8ToJavaString(env, uuid).obj(), properties);
 }
 
+void BluetoothTestAndroid::RememberCharacteristicForSubsequentAction(
+    BluetoothGattCharacteristic* characteristic) {
+  BluetoothRemoteGattCharacteristicAndroid* characteristic_android =
+      static_cast<BluetoothRemoteGattCharacteristicAndroid*>(characteristic);
+
+  Java_FakeBluetoothGattCharacteristic_rememberCharacteristic(
+      base::android::AttachCurrentThread(),
+      characteristic_android->GetJavaObject().obj());
+}
+
 void BluetoothTestAndroid::SimulateGattNotifySessionStarted(
     BluetoothGattCharacteristic* characteristic) {
   // Android doesn't provide any sort of callback for when notifications have
@@ -190,7 +200,9 @@
   JNIEnv* env = base::android::AttachCurrentThread();
 
   Java_FakeBluetoothGattCharacteristic_valueRead(
-      env, characteristic_android->GetJavaObject().obj(),
+      env,
+      characteristic_android ? characteristic_android->GetJavaObject().obj()
+                             : nullptr,
       0,  // android.bluetooth.BluetoothGatt.GATT_SUCCESS
       base::android::ToJavaByteArray(env, value).obj());
 }
@@ -226,7 +238,8 @@
       static_cast<BluetoothRemoteGattCharacteristicAndroid*>(characteristic);
   Java_FakeBluetoothGattCharacteristic_valueWrite(
       base::android::AttachCurrentThread(),
-      characteristic_android->GetJavaObject().obj(),
+      characteristic_android ? characteristic_android->GetJavaObject().obj()
+                             : nullptr,
       0);  // android.bluetooth.BluetoothGatt.GATT_SUCCESS
 }
 
diff --git a/device/bluetooth/test/bluetooth_test_android.h b/device/bluetooth/test/bluetooth_test_android.h
index e4c1c82a..664863a3 100644
--- a/device/bluetooth/test/bluetooth_test_android.h
+++ b/device/bluetooth/test/bluetooth_test_android.h
@@ -39,6 +39,8 @@
   void SimulateGattCharacteristic(BluetoothGattService* service,
                                   const std::string& uuid,
                                   int properties) override;
+  void RememberCharacteristicForSubsequentAction(
+      BluetoothGattCharacteristic* characteristic) override;
   void SimulateGattNotifySessionStarted(
       BluetoothGattCharacteristic* characteristic) override;
   void SimulateGattCharacteristicSetNotifyWillFailSynchronouslyOnce(
diff --git a/mojo/edk/embedder/embedder.cc b/mojo/edk/embedder/embedder.cc
index eb572c57..35e55ba 100644
--- a/mojo/edk/embedder/embedder.cc
+++ b/mojo/edk/embedder/embedder.cc
@@ -65,15 +65,9 @@
 }
 
 ScopedPlatformHandle ChildProcessLaunched(base::ProcessHandle child_process) {
-#if defined(OS_WIN)
   PlatformChannelPair token_channel;
   new ChildBrokerHost(child_process, token_channel.PassServerHandle());
   return token_channel.PassClientHandle();
-#else
-  // TODO(jam): create this for POSIX. Need to implement channel reading first
-  // so we don't leak handles.
-  return ScopedPlatformHandle();
-#endif
 }
 
 void ChildProcessLaunched(base::ProcessHandle child_process,
@@ -165,9 +159,11 @@
 
 ScopedMessagePipeHandle CreateMessagePipe(
     ScopedPlatformHandle platform_handle) {
+  MojoCreateMessagePipeOptions options = {
+      static_cast<uint32_t>(sizeof(MojoCreateMessagePipeOptions)),
+      MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_TRANSFERABLE};
   scoped_refptr<MessagePipeDispatcher> dispatcher =
-      MessagePipeDispatcher::Create(
-          MessagePipeDispatcher::kDefaultCreateOptions);
+      MessagePipeDispatcher::Create(options);
 
   ScopedMessagePipeHandle rv(
       MessagePipeHandle(internal::g_core->AddDispatcher(dispatcher)));
diff --git a/mojo/edk/embedder/embedder_unittest.cc b/mojo/edk/embedder/embedder_unittest.cc
index 60a2b801..4f6493f 100644
--- a/mojo/edk/embedder/embedder_unittest.cc
+++ b/mojo/edk/embedder/embedder_unittest.cc
@@ -34,14 +34,7 @@
                                      MOJO_HANDLE_SIGNAL_WRITABLE |
                                      MOJO_HANDLE_SIGNAL_PEER_CLOSED;
 
-class EmbedderTest : public test::MojoSystemTest {
- public:
-  EmbedderTest() {}
-  ~EmbedderTest() override {}
-
- private:
-  MOJO_DISALLOW_COPY_AND_ASSIGN(EmbedderTest);
-};
+typedef testing::Test EmbedderTest;
 
 TEST_F(EmbedderTest, ChannelBasic) {
   MojoHandle server_mp, client_mp;
@@ -85,8 +78,11 @@
             MojoCreateMessagePipe(nullptr, &server_mp, &client_mp));
 
   MojoHandle server_mp2, client_mp2;
+  MojoCreateMessagePipeOptions options;
+  options.struct_size = sizeof(MojoCreateMessagePipeOptions);
+  options.flags = MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_TRANSFERABLE;
   ASSERT_EQ(MOJO_RESULT_OK,
-            MojoCreateMessagePipe(nullptr, &server_mp2, &client_mp2));
+            MojoCreateMessagePipe(&options, &server_mp2, &client_mp2));
 
   // Write to server2 and wait for client2 to be readable before sending it.
   // client2's MessagePipeDispatcher will have the message below in its
@@ -165,9 +161,12 @@
   ASSERT_EQ(MOJO_RESULT_OK,
             MojoCreateMessagePipe(nullptr, &server_mp, &client_mp));
 
+  MojoCreateMessagePipeOptions options;
+  options.struct_size = sizeof(MojoCreateMessagePipeOptions);
+  options.flags = MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_TRANSFERABLE;
   MojoHandle server_mp2, client_mp2;
   ASSERT_EQ(MOJO_RESULT_OK,
-            MojoCreateMessagePipe(nullptr, &server_mp2, &client_mp2));
+            MojoCreateMessagePipe(&options, &server_mp2, &client_mp2));
 
   static const size_t kNumMessages = 1001;
   for (size_t i = 0; i < kNumMessages; i++) {
@@ -465,114 +464,108 @@
 }
 
 MOJO_MULTIPROCESS_TEST_CHILD_TEST(MultiprocessChannelsClient) {
-  base::MessageLoop message_loop;
   ScopedPlatformHandle client_platform_handle =
       test::MultiprocessTestHelper::client_platform_handle.Pass();
   EXPECT_TRUE(client_platform_handle.is_valid());
 
-  base::TestIOThread test_io_thread(base::TestIOThread::kAutoStart);
+  MojoHandle client_mp = CreateMessagePipe(
+      client_platform_handle.Pass()).release().value();
 
-  {
-    test::ScopedIPCSupport ipc_support(test_io_thread.task_runner());
-    MojoHandle client_mp = CreateMessagePipe(
-        client_platform_handle.Pass()).release().value();
+  // 1. Read the first message from |client_mp|.
+  MojoHandleSignalsState state;
+  ASSERT_EQ(MOJO_RESULT_OK, MojoWait(client_mp, MOJO_HANDLE_SIGNAL_READABLE,
+                                      MOJO_DEADLINE_INDEFINITE, &state));
+  ASSERT_EQ(kSignalReadadableWritable, state.satisfied_signals);
+  ASSERT_EQ(kSignalAll, state.satisfiable_signals);
 
-    // 1. Read the first message from |client_mp|.
-    MojoHandleSignalsState state;
-    ASSERT_EQ(MOJO_RESULT_OK, MojoWait(client_mp, MOJO_HANDLE_SIGNAL_READABLE,
-                                       MOJO_DEADLINE_INDEFINITE, &state));
-    ASSERT_EQ(kSignalReadadableWritable, state.satisfied_signals);
-    ASSERT_EQ(kSignalAll, state.satisfiable_signals);
+  char buffer[1000] = {};
+  uint32_t num_bytes = static_cast<uint32_t>(sizeof(buffer));
+  ASSERT_EQ(MOJO_RESULT_OK,
+            MojoReadMessage(client_mp, buffer, &num_bytes, nullptr, nullptr,
+                            MOJO_READ_MESSAGE_FLAG_NONE));
+  const char kHello[] = "hello";
+  ASSERT_EQ(sizeof(kHello), num_bytes);
+  EXPECT_STREQ(kHello, buffer);
 
-    char buffer[1000] = {};
-    uint32_t num_bytes = static_cast<uint32_t>(sizeof(buffer));
-    ASSERT_EQ(MOJO_RESULT_OK,
-              MojoReadMessage(client_mp, buffer, &num_bytes, nullptr, nullptr,
-                              MOJO_READ_MESSAGE_FLAG_NONE));
-    const char kHello[] = "hello";
-    ASSERT_EQ(sizeof(kHello), num_bytes);
-    EXPECT_STREQ(kHello, buffer);
+  // 2. Write a message to |client_mp| (attaching nothing).
+  const char kWorld[] = "world!";
+  ASSERT_EQ(MOJO_RESULT_OK,
+            MojoWriteMessage(client_mp, kWorld,
+                              static_cast<uint32_t>(sizeof(kWorld)), nullptr,
+                              0, MOJO_WRITE_MESSAGE_FLAG_NONE));
 
-    // 2. Write a message to |client_mp| (attaching nothing).
-    const char kWorld[] = "world!";
-    ASSERT_EQ(MOJO_RESULT_OK,
-              MojoWriteMessage(client_mp, kWorld,
-                               static_cast<uint32_t>(sizeof(kWorld)), nullptr,
-                               0, MOJO_WRITE_MESSAGE_FLAG_NONE));
+  // 4. Read a message from |client_mp|, which should have |mp1| attached.
+  ASSERT_EQ(MOJO_RESULT_OK, MojoWait(client_mp, MOJO_HANDLE_SIGNAL_READABLE,
+                                      MOJO_DEADLINE_INDEFINITE, &state));
+  // The other end of the handle may or may not be closed at this point, so we
+  // can't test MOJO_HANDLE_SIGNAL_WRITABLE or MOJO_HANDLE_SIGNAL_PEER_CLOSED.
+  ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE,
+            state.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE);
+  ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE,
+            state.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE);
+  // TODO(vtl): If the scope were to end here (and |client_mp| closed), we'd
+  // die (again due to |Channel::HandleLocalError()|).
+  memset(buffer, 0, sizeof(buffer));
+  num_bytes = static_cast<uint32_t>(sizeof(buffer));
+  MojoHandle mp1 = MOJO_HANDLE_INVALID;
+  uint32_t num_handles = 1;
+  ASSERT_EQ(MOJO_RESULT_OK,
+            MojoReadMessage(client_mp, buffer, &num_bytes, &mp1, &num_handles,
+                            MOJO_READ_MESSAGE_FLAG_NONE));
+  const char kBar[] = "Bar";
+  ASSERT_EQ(sizeof(kBar), num_bytes);
+  EXPECT_STREQ(kBar, buffer);
+  ASSERT_EQ(1u, num_handles);
+  EXPECT_NE(mp1, MOJO_HANDLE_INVALID);
+  // TODO(vtl): If the scope were to end here (and the two handles closed),
+  // we'd die due to |Channel::RunRemoteMessagePipeEndpoint()| not handling
+  // write errors (assuming the parent had closed the pipe).
 
-    // 4. Read a message from |client_mp|, which should have |mp1| attached.
-    ASSERT_EQ(MOJO_RESULT_OK, MojoWait(client_mp, MOJO_HANDLE_SIGNAL_READABLE,
-                                       MOJO_DEADLINE_INDEFINITE, &state));
-    // The other end of the handle may or may not be closed at this point, so we
-    // can't test MOJO_HANDLE_SIGNAL_WRITABLE or MOJO_HANDLE_SIGNAL_PEER_CLOSED.
-    ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE,
-              state.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE);
-    ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE,
-              state.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE);
-    // TODO(vtl): If the scope were to end here (and |client_mp| closed), we'd
-    // die (again due to |Channel::HandleLocalError()|).
-    memset(buffer, 0, sizeof(buffer));
-    num_bytes = static_cast<uint32_t>(sizeof(buffer));
-    MojoHandle mp1 = MOJO_HANDLE_INVALID;
-    uint32_t num_handles = 1;
-    ASSERT_EQ(MOJO_RESULT_OK,
-              MojoReadMessage(client_mp, buffer, &num_bytes, &mp1, &num_handles,
-                              MOJO_READ_MESSAGE_FLAG_NONE));
-    const char kBar[] = "Bar";
-    ASSERT_EQ(sizeof(kBar), num_bytes);
-    EXPECT_STREQ(kBar, buffer);
-    ASSERT_EQ(1u, num_handles);
-    EXPECT_NE(mp1, MOJO_HANDLE_INVALID);
-    // TODO(vtl): If the scope were to end here (and the two handles closed),
-    // we'd die due to |Channel::RunRemoteMessagePipeEndpoint()| not handling
-    // write errors (assuming the parent had closed the pipe).
+  // 6. Close |client_mp|.
+  ASSERT_EQ(MOJO_RESULT_OK, MojoClose(client_mp));
 
-    // 6. Close |client_mp|.
-    ASSERT_EQ(MOJO_RESULT_OK, MojoClose(client_mp));
+  // Create a new message pipe (endpoints |mp2| and |mp3|).
+  MojoHandle mp2, mp3;
+  ASSERT_EQ(MOJO_RESULT_OK, MojoCreateMessagePipe(nullptr, &mp2, &mp3));
 
-    // Create a new message pipe (endpoints |mp2| and |mp3|).
-    MojoHandle mp2, mp3;
-    ASSERT_EQ(MOJO_RESULT_OK, MojoCreateMessagePipe(nullptr, &mp2, &mp3));
+  // 7. Write a message to |mp3|.
+  const char kBaz[] = "baz";
+  ASSERT_EQ(MOJO_RESULT_OK,
+            MojoWriteMessage(mp3, kBaz, static_cast<uint32_t>(sizeof(kBaz)),
+                              nullptr, 0, MOJO_WRITE_MESSAGE_FLAG_NONE));
 
-    // 7. Write a message to |mp3|.
-    const char kBaz[] = "baz";
-    ASSERT_EQ(MOJO_RESULT_OK,
-              MojoWriteMessage(mp3, kBaz, static_cast<uint32_t>(sizeof(kBaz)),
-                               nullptr, 0, MOJO_WRITE_MESSAGE_FLAG_NONE));
+  // 8. Close |mp3|.
+  ASSERT_EQ(MOJO_RESULT_OK, MojoClose(mp3));
 
-    // 8. Close |mp3|.
-    ASSERT_EQ(MOJO_RESULT_OK, MojoClose(mp3));
+  // 9. Write a message to |mp1|, attaching |mp2|.
+  const char kQuux[] = "quux";
+  ASSERT_EQ(MOJO_RESULT_OK,
+            MojoWriteMessage(mp1, kQuux, static_cast<uint32_t>(sizeof(kQuux)),
+                              &mp2, 1, MOJO_WRITE_MESSAGE_FLAG_NONE));
+  mp2 = MOJO_HANDLE_INVALID;
 
-    // 9. Write a message to |mp1|, attaching |mp2|.
-    const char kQuux[] = "quux";
-    ASSERT_EQ(MOJO_RESULT_OK,
-              MojoWriteMessage(mp1, kQuux, static_cast<uint32_t>(sizeof(kQuux)),
-                               &mp2, 1, MOJO_WRITE_MESSAGE_FLAG_NONE));
-    mp2 = MOJO_HANDLE_INVALID;
+  // 3. Read a message from |mp1|.
+  ASSERT_EQ(MOJO_RESULT_OK, MojoWait(mp1, MOJO_HANDLE_SIGNAL_READABLE,
+                                      MOJO_DEADLINE_INDEFINITE, &state));
+  ASSERT_EQ(kSignalReadadableWritable, state.satisfied_signals);
+  ASSERT_EQ(kSignalAll, state.satisfiable_signals);
 
-    // 3. Read a message from |mp1|.
-    ASSERT_EQ(MOJO_RESULT_OK, MojoWait(mp1, MOJO_HANDLE_SIGNAL_READABLE,
-                                       MOJO_DEADLINE_INDEFINITE, &state));
-    ASSERT_EQ(kSignalReadadableWritable, state.satisfied_signals);
-    ASSERT_EQ(kSignalAll, state.satisfiable_signals);
+  memset(buffer, 0, sizeof(buffer));
+  num_bytes = static_cast<uint32_t>(sizeof(buffer));
+  ASSERT_EQ(MOJO_RESULT_OK,
+            MojoReadMessage(mp1, buffer, &num_bytes, nullptr, nullptr,
+                            MOJO_READ_MESSAGE_FLAG_NONE));
+  const char kFoo[] = "FOO";
+  ASSERT_EQ(sizeof(kFoo), num_bytes);
+  EXPECT_STREQ(kFoo, buffer);
 
-    memset(buffer, 0, sizeof(buffer));
-    num_bytes = static_cast<uint32_t>(sizeof(buffer));
-    ASSERT_EQ(MOJO_RESULT_OK,
-              MojoReadMessage(mp1, buffer, &num_bytes, nullptr, nullptr,
-                              MOJO_READ_MESSAGE_FLAG_NONE));
-    const char kFoo[] = "FOO";
-    ASSERT_EQ(sizeof(kFoo), num_bytes);
-    EXPECT_STREQ(kFoo, buffer);
-
-    // 11. Wait on |mp1| (which should eventually fail) and then close it.
-    ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
-              MojoWait(mp1, MOJO_HANDLE_SIGNAL_READABLE,
-                       MOJO_DEADLINE_INDEFINITE, &state));
-    ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, state.satisfied_signals);
-    ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, state.satisfiable_signals);
-    ASSERT_EQ(MOJO_RESULT_OK, MojoClose(mp1));
-  }
+  // 11. Wait on |mp1| (which should eventually fail) and then close it.
+  ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
+            MojoWait(mp1, MOJO_HANDLE_SIGNAL_READABLE,
+                      MOJO_DEADLINE_INDEFINITE, &state));
+  ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, state.satisfied_signals);
+  ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, state.satisfiable_signals);
+  ASSERT_EQ(MOJO_RESULT_OK, MojoClose(mp1));
 }
 
 // TODO(vtl): Test immediate write & close.
diff --git a/mojo/edk/system/BUILD.gn b/mojo/edk/system/BUILD.gn
index fe113d2..54e3e3e 100644
--- a/mojo/edk/system/BUILD.gn
+++ b/mojo/edk/system/BUILD.gn
@@ -69,6 +69,8 @@
     "raw_channel.h",
     "raw_channel_posix.cc",
     "raw_channel_win.cc",
+    "routed_raw_channel.cc",
+    "routed_raw_channel.h",
     "shared_buffer_dispatcher.cc",
     "shared_buffer_dispatcher.h",
     "simple_dispatcher.cc",
diff --git a/mojo/edk/system/broker.h b/mojo/edk/system/broker.h
index ce4c9565..f78fff7 100644
--- a/mojo/edk/system/broker.h
+++ b/mojo/edk/system/broker.h
@@ -6,23 +6,26 @@
 #define MOJO_EDK_SYSTEM_BROKER_H_
 
 #include <stdint.h>
-#include <vector>
 
 #include "mojo/edk/embedder/scoped_platform_handle.h"
 
 namespace mojo {
 namespace edk {
+class MessagePipeDispatcher;
+class RawChannel;
 
 // An interface for communicating to a central "broker" process from each
-// process using the EDK. This is needed because child processes are sandboxed.
-// It is safe to call from any thread.
+// process using the EDK. It serves two purposes:
+// 1) Windows only: brokering to help child processes as they can't create
+//    named pipes or duplicate handles.
+// 2) All platforms: support multiplexed messages pipes.
+
 class MOJO_SYSTEM_IMPL_EXPORT Broker {
  public:
   virtual ~Broker() {}
 
 #if defined(OS_WIN)
-  // All these methods are needed because sandboxed Windows processes can't
-  // create named pipes or duplicate handles.
+  // It is safe to call these three methods from any thread.
 
   // Create a PlatformChannelPair.
   virtual void CreatePlatformChannelPair(ScopedPlatformHandle* server,
@@ -40,6 +43,20 @@
                              size_t count,
                              PlatformHandle* handles) = 0;
 #endif
+
+  // Multiplexing related methods. They are called from the IO thread only.
+
+  // Called by |message_pipe| so that it receives messages for the given
+  // globally unique |pipe_id|. When the connection is established,
+  // MessagePipeDispatcher::GotNonTransferableChannel is called with the channel
+  // that it can use for sending messages.
+  virtual void ConnectMessagePipe(uint64_t pipe_id,
+                                  MessagePipeDispatcher* message_pipe) = 0;
+
+  // Called by |message_pipe| when it's closing so that its route can be
+  // unregistered.
+  virtual void CloseMessagePipe(uint64_t pipe_id,
+                                MessagePipeDispatcher* message_pipe) = 0;
 };
 
 }  // namespace edk
diff --git a/mojo/edk/system/broker_messages.h b/mojo/edk/system/broker_messages.h
index 351cbe6..7d8946d 100644
--- a/mojo/edk/system/broker_messages.h
+++ b/mojo/edk/system/broker_messages.h
@@ -8,6 +8,7 @@
 #include <stdint.h>
 
 #include "base/compiler_specific.h"
+#include "base/process/process_handle.h"
 
 namespace mojo {
 namespace edk {
@@ -15,7 +16,11 @@
 // This header defines the message format between ChildBroker and
 // ChildBrokerHost.
 
-enum MessageId {
+#if defined(OS_WIN)
+// Windows only messages needed because sandboxed child processes need the
+// parent's help. They are sent synchronously from child to parent and each have
+// a response. They are sent over a raw pipe.
+enum WindowsSandboxMessages {
   // The reply is two HANDLEs.
   CREATE_PLATFORM_CHANNEL_PAIR = 0,
   // The reply is tokens of the same count of passed in handles.
@@ -28,17 +33,48 @@
 
 struct BrokerMessage {
   uint32_t size;
-  MessageId id;
+  WindowsSandboxMessages id;
   // Data, if any, follows.
   union {
-#if defined(OS_WIN)
     HANDLE handles[1];  // If HANDLE_TO_TOKEN.
     uint64_t tokens[1];  // If TOKEN_TO_HANDLE.
-#endif
   };
 };
 
-const int kBrokerMessageHeaderSize = sizeof(uint32_t) + sizeof(MessageId);
+const int kBrokerMessageHeaderSize =
+  sizeof(uint32_t) + sizeof(WindowsSandboxMessages);
+
+#endif
+
+// Multiplexing related messages. They are all asynchronous messages.
+// They are sent over RawChannel.
+enum MultiplexMessages {
+  // Messages from child to parent.
+  CONNECT_MESSAGE_PIPE = 0,
+  CANCEL_CONNECT_MESSAGE_PIPE,
+
+  // Messages from parent to child.
+  CONNECT_TO_PROCESS,
+  PEER_PIPE_CONNECTED,
+};
+
+struct ConnectMessagePipeMessage {
+  // CONNECT_MESSAGE_PIPE or CANCEL_CONNECT_MESSAGE_PIPE
+  MultiplexMessages type;
+  uint64_t pipe_id;
+};
+
+struct ConnectToProcessMessage {
+  MultiplexMessages type;  // CONNECT_TO_PROCESS
+  base::ProcessId process_id;
+  // Also has an attached platform handle.
+};
+
+struct PeerPipeConnectedMessage {
+  MultiplexMessages type;  // PEER_PIPE_CONNECTED
+  uint64_t pipe_id;
+  base::ProcessId process_id;
+};
 
 }  // namespace edk
 }  // namespace mojo
diff --git a/mojo/edk/system/broker_state.cc b/mojo/edk/system/broker_state.cc
index 6eb4ae9..b875b31 100644
--- a/mojo/edk/system/broker_state.cc
+++ b/mojo/edk/system/broker_state.cc
@@ -4,9 +4,13 @@
 
 #include "mojo/edk/system/broker_state.h"
 
+#include "base/bind.h"
 #include "base/rand_util.h"
 #include "mojo/edk/embedder/embedder_internal.h"
 #include "mojo/edk/embedder/platform_channel_pair.h"
+#include "mojo/edk/system/child_broker_host.h"
+#include "mojo/edk/system/message_pipe_dispatcher.h"
+#include "mojo/edk/system/routed_raw_channel.h"
 
 namespace mojo {
 namespace edk {
@@ -28,7 +32,7 @@
     const PlatformHandle* platform_handles,
     size_t count,
     uint64_t* tokens) {
-  base::AutoLock auto_locker(lock_);
+  base::AutoLock auto_locker(token_map_lock_);
   for (size_t i = 0; i < count; ++i) {
     if (platform_handles[i].is_valid()) {
       uint64_t token;
@@ -47,7 +51,7 @@
 void BrokerState::TokenToHandle(const uint64_t* tokens,
                                 size_t count,
                                 PlatformHandle* handles) {
-  base::AutoLock auto_locker(lock_);
+  base::AutoLock auto_locker(token_map_lock_);
   for (size_t i = 0; i < count; ++i) {
     auto it = token_map_.find(tokens[i]);
     if (it == token_map_.end()) {
@@ -60,9 +64,155 @@
 }
 #endif
 
-BrokerState::BrokerState() : broker_thread_("Mojo Broker Thread") {
-  base::Thread::Options options(base::MessageLoop::TYPE_IO, 0);
-  broker_thread_.StartWithOptions(options);
+void BrokerState::ConnectMessagePipe(uint64_t pipe_id,
+                                     MessagePipeDispatcher* message_pipe) {
+  DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread());
+  base::AutoLock auto_lock(lock_);
+  if (pending_connects_.find(pipe_id) != pending_connects_.end()) {
+    // Both ends of the message pipe are in this process.
+    if (!in_process_pipes_channel1_) {
+      PlatformChannelPair channel_pair;
+      in_process_pipes_channel1_ = new RoutedRawChannel(
+          channel_pair.PassServerHandle(),
+          base::Bind(&BrokerState::ChannelDestructed, base::Unretained(this)));
+      in_process_pipes_channel2_ = new RoutedRawChannel(
+          channel_pair.PassClientHandle(),
+          base::Bind(&BrokerState::ChannelDestructed, base::Unretained(this)));
+    }
+
+    connected_pipes_[pending_connects_[pipe_id]] = in_process_pipes_channel1_;
+    connected_pipes_[message_pipe] = in_process_pipes_channel2_;
+    in_process_pipes_channel1_->AddRoute(pipe_id, pending_connects_[pipe_id]);
+    in_process_pipes_channel2_->AddRoute(pipe_id, message_pipe);
+    pending_connects_[pipe_id]->GotNonTransferableChannel(
+        in_process_pipes_channel1_->channel());
+    message_pipe->GotNonTransferableChannel(
+        in_process_pipes_channel2_->channel());
+
+    pending_connects_.erase(pipe_id);
+    return;
+  }
+
+  if (pending_child_connects_.find(pipe_id) != pending_child_connects_.end()) {
+    // A child process has already tried to connect.
+    EnsureProcessesConnected(base::GetCurrentProcId(),
+                             pending_child_connects_[pipe_id]->GetProcessId());
+    pending_child_connects_[pipe_id]->ConnectMessagePipe(
+        pipe_id, base::GetCurrentProcId());
+    base::ProcessId peer_pid = pending_child_connects_[pipe_id]->GetProcessId();
+    pending_child_connects_.erase(pipe_id);
+    connected_pipes_[message_pipe] = child_channels_[peer_pid];
+    child_channels_[peer_pid]->AddRoute(pipe_id, message_pipe);
+    message_pipe->GotNonTransferableChannel(
+        child_channels_[peer_pid]->channel());
+    return;
+  }
+
+  pending_connects_[pipe_id] = message_pipe;
+}
+
+void BrokerState::CloseMessagePipe(uint64_t pipe_id,
+                                   MessagePipeDispatcher* message_pipe) {
+  DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread());
+  base::AutoLock auto_lock(lock_);
+
+  CHECK(connected_pipes_.find(message_pipe) != connected_pipes_.end());
+  connected_pipes_[message_pipe]->RemoveRoute(pipe_id, message_pipe);
+  connected_pipes_.erase(message_pipe);
+}
+
+void BrokerState::ChildBrokerHostCreated(ChildBrokerHost* child_broker_host) {
+  base::AutoLock auto_lock(lock_);
+  CHECK(child_processes_.find(child_broker_host->GetProcessId()) ==
+        child_processes_.end());
+  child_processes_[child_broker_host->GetProcessId()] = child_broker_host;
+}
+
+void BrokerState::ChildBrokerHostDestructed(
+    ChildBrokerHost* child_broker_host) {
+  DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread());
+  base::AutoLock auto_lock(lock_);
+
+  for (auto it = pending_child_connects_.begin();
+       it != pending_child_connects_.end();) {
+    if (it->second == child_broker_host) {
+      // Since we can't do it = pending_child_connects_.erase(it); until
+      // hash_map uses unordered_map on posix.
+      auto cur = it++;
+      pending_child_connects_.erase(cur);
+    } else {
+      it++;
+    }
+  }
+
+  base::ProcessId pid = child_broker_host->GetProcessId();
+  for (auto it = connected_processes_.begin();
+       it != connected_processes_.end();) {
+    if ((*it).first == pid || (*it).second == pid) {
+      // Since we can't do it = pending_child_connects_.erase(it); until
+      // hash_map uses unordered_map on posix.
+      auto cur = it++;
+      connected_processes_.erase(cur);
+    } else {
+      it++;
+    }
+  }
+
+  CHECK(child_processes_.find(pid) != child_processes_.end());
+  child_processes_.erase(pid);
+}
+
+void BrokerState::HandleConnectMessagePipe(ChildBrokerHost* pipe_process,
+                                           uint64_t pipe_id) {
+  DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread());
+  base::AutoLock auto_lock(lock_);
+  if (pending_child_connects_.find(pipe_id) != pending_child_connects_.end()) {
+    // Another child process is waiting to connect to the given pipe.
+    ChildBrokerHost* pending_pipe_process = pending_child_connects_[pipe_id];
+    EnsureProcessesConnected(pipe_process->GetProcessId(),
+                             pending_pipe_process->GetProcessId());
+    pending_pipe_process->ConnectMessagePipe(
+        pipe_id, pipe_process->GetProcessId());
+    pipe_process->ConnectMessagePipe(
+        pipe_id, pending_pipe_process->GetProcessId());
+    pending_child_connects_.erase(pipe_id);
+    return;
+  }
+
+  if (pending_connects_.find(pipe_id) != pending_connects_.end()) {
+    // This parent process is the other side of the given pipe.
+    EnsureProcessesConnected(base::GetCurrentProcId(),
+                             pipe_process->GetProcessId());
+    MessagePipeDispatcher* pending_pipe = pending_connects_[pipe_id];
+    connected_pipes_[pending_pipe] =
+        child_channels_[pipe_process->GetProcessId()];
+    child_channels_[pipe_process->GetProcessId()]->AddRoute(
+        pipe_id, pending_pipe);
+    pending_pipe->GotNonTransferableChannel(
+        child_channels_[pipe_process->GetProcessId()]->channel());
+    pipe_process->ConnectMessagePipe(
+        pipe_id, base::GetCurrentProcId());
+    pending_connects_.erase(pipe_id);
+    return;
+  }
+
+  // This is the first connection request for pipe_id to reach the parent.
+  pending_child_connects_[pipe_id] = pipe_process;
+}
+
+void BrokerState::HandleCancelConnectMessagePipe(uint64_t pipe_id) {
+  DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread());
+  base::AutoLock auto_lock(lock_);
+  if (pending_child_connects_.find(pipe_id) == pending_child_connects_.end()) {
+    NOTREACHED() << "Can't find entry for pipe_id " << pipe_id;
+  } else {
+    pending_child_connects_.erase(pipe_id);
+  }
+}
+
+BrokerState::BrokerState()
+    : in_process_pipes_channel1_(nullptr),
+      in_process_pipes_channel2_(nullptr) {
   DCHECK(!internal::g_broker);
   internal::g_broker = this;
 }
@@ -70,5 +220,49 @@
 BrokerState::~BrokerState() {
 }
 
+void BrokerState::EnsureProcessesConnected(base::ProcessId pid1,
+                                           base::ProcessId pid2) {
+  DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread());
+  lock_.AssertAcquired();
+  CHECK_NE(pid1, pid2);
+  CHECK_NE(pid2, base::GetCurrentProcId());
+  std::pair<base::ProcessId, base::ProcessId> processes;
+  processes.first = std::min(pid1, pid2);
+  processes.second = std::max(pid1, pid2);
+  if (connected_processes_.find(processes) != connected_processes_.end())
+    return;
+
+  connected_processes_.insert(processes);
+  PlatformChannelPair channel_pair;
+  if (pid1 == base::GetCurrentProcId()) {
+    CHECK(child_channels_.find(pid2) == child_channels_.end());
+    CHECK(child_processes_.find(pid2) != child_processes_.end());
+    child_channels_[pid2] = new RoutedRawChannel(
+        channel_pair.PassServerHandle(),
+        base::Bind(&BrokerState::ChannelDestructed, base::Unretained(this)));
+    child_processes_[pid2]->ConnectToProcess(base::GetCurrentProcId(),
+                                             channel_pair.PassClientHandle());
+    return;
+  }
+
+  CHECK(child_processes_.find(pid1) != child_processes_.end());
+  CHECK(child_processes_.find(pid2) != child_processes_.end());
+  child_processes_[pid1]->ConnectToProcess(pid2,
+                                           channel_pair.PassServerHandle());
+  child_processes_[pid2]->ConnectToProcess(pid1,
+                                           channel_pair.PassClientHandle());
+}
+
+void BrokerState::ChannelDestructed(RoutedRawChannel* channel) {
+  DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread());
+  base::AutoLock auto_lock(lock_);
+  for (auto it : child_channels_) {
+    if (it.second == channel) {
+      child_channels_.erase(it.first);
+      break;
+    }
+  }
+}
+
 }  // namespace edk
 }  // namespace mojo
diff --git a/mojo/edk/system/broker_state.h b/mojo/edk/system/broker_state.h
index cf982c7..29f3ffe 100644
--- a/mojo/edk/system/broker_state.h
+++ b/mojo/edk/system/broker_state.h
@@ -7,15 +7,18 @@
 
 #include "base/compiler_specific.h"
 #include "base/containers/hash_tables.h"
+#include "base/macros.h"
 #include "base/memory/singleton.h"
+#include "base/process/process_handle.h"
 #include "base/synchronization/lock.h"
-#include "base/threading/thread.h"
 #include "mojo/edk/embedder/scoped_platform_handle.h"
 #include "mojo/edk/system/broker.h"
 #include "mojo/edk/system/system_impl_export.h"
 
 namespace mojo {
 namespace edk {
+class ChildBrokerHost;
+class RoutedRawChannel;
 
 // Common broker state that has to live in a parent process. There is one
 // instance of this class in the parent process. This class implements the
@@ -24,7 +27,7 @@
  public:
   static BrokerState* GetInstance();
 
-  // Broker implementation.
+  // Broker implementation:
 #if defined(OS_WIN)
   void CreatePlatformChannelPair(ScopedPlatformHandle* server,
                                  ScopedPlatformHandle* client) override;
@@ -35,10 +38,20 @@
                      size_t count,
                      PlatformHandle* handles) override;
 #endif
+  void ConnectMessagePipe(uint64_t pipe_id,
+                          MessagePipeDispatcher* message_pipe) override;
+  void CloseMessagePipe(uint64_t pipe_id,
+                        MessagePipeDispatcher* message_pipe) override;
 
-  scoped_refptr<base::TaskRunner> broker_thread() {
-    return broker_thread_.task_runner();
-  }
+  // Called by ChildBrokerHost on construction and destruction.
+  void ChildBrokerHostCreated(ChildBrokerHost* child_broker_host);
+  void ChildBrokerHostDestructed(ChildBrokerHost* child_broker_host);
+
+  // These are called by ChildBrokerHost as they dispatch IPCs from ChildBroker.
+  // They are called on the IO thread.
+  void HandleConnectMessagePipe(ChildBrokerHost* pipe_process,
+                                uint64_t pipe_id);
+  void HandleCancelConnectMessagePipe(uint64_t pipe_id);
 
  private:
   friend struct base::DefaultSingletonTraits<BrokerState>;
@@ -46,20 +59,58 @@
   BrokerState();
   ~BrokerState() override;
 
-  // A separate thread to handle sync IPCs from child processes for exchanging
-  // platform handles with tokens. We use a separate thread because latency is
-  // very sensitive (since any time a pipe is created or sent, a child process
-  // makes a sync call to this class).
-  base::Thread broker_thread_;
+  // Checks if there's a direct channel between the two processes, and if not
+  // creates one and tells them about it.
+  // If one of the processes is the current one, it should be pid1.
+  // Called on the IO thread.
+  void EnsureProcessesConnected(base::ProcessId pid1, base::ProcessId pid2);
+
+  // Callback when a RoutedRawChannel is destroyed for cleanup.
+  // Called on the IO thread.
+  void ChannelDestructed(RoutedRawChannel* channel);
 
 #if defined(OS_WIN)
   // Used in the parent (unsandboxed) process to hold a mapping between HANDLES
   // and tokens. When a child process wants to send a HANDLE to another process,
   // it exchanges it to a token and then the other process exchanges that token
   // back to a HANDLE.
-  base::Lock lock_;  // Guards access to below.
+  base::Lock token_map_lock_;
   base::hash_map<uint64_t, HANDLE> token_map_;
 #endif
+
+  // For pending connects originiating in this process.
+  // Only accessed on the IO thread.
+  base::hash_map<uint64_t, MessagePipeDispatcher*> pending_connects_;
+
+  // For connected message pipes in this process. This is needed so that when a
+  // MessagePipeDispatcher is closed we can remove the route for the
+  // corresponding RoutedRawChannel.
+  // Only accessed on the IO thread.
+  base::hash_map<MessagePipeDispatcher*, RoutedRawChannel*> connected_pipes_;
+
+  base::Lock lock_;  // Guards access to below.
+
+  // Holds a map of all the RoutedRawChannel that connect this parent process to
+  // a child process. The key is the child process'd pid.
+  base::hash_map<base::ProcessId, RoutedRawChannel*> child_channels_;
+
+  base::hash_map<uint64_t, ChildBrokerHost*> pending_child_connects_;
+
+  // Each entry is an std::pair of ints of processe IDs that have
+  // RoutedRawChannel objects between them. The pair always has the smaller
+  // process id value first.
+  // For now, we don't reap connections if there are no more routes between two
+  // processes.
+  base::hash_set<std::pair<base::ProcessId, base::ProcessId>>
+      connected_processes_;
+
+  base::hash_map<base::ProcessId, ChildBrokerHost*> child_processes_;
+
+  // Used for message pipes in the same process.
+  RoutedRawChannel* in_process_pipes_channel1_;
+  RoutedRawChannel* in_process_pipes_channel2_;
+
+  DISALLOW_COPY_AND_ASSIGN(BrokerState);
 };
 
 }  // namespace edk
diff --git a/mojo/edk/system/child_broker.cc b/mojo/edk/system/child_broker.cc
index 7d7b4c6..fbfeb3d 100644
--- a/mojo/edk/system/child_broker.cc
+++ b/mojo/edk/system/child_broker.cc
@@ -4,9 +4,13 @@
 
 #include "mojo/edk/system/child_broker.h"
 
+#include "base/bind.h"
 #include "base/logging.h"
 #include "mojo/edk/embedder/embedder_internal.h"
+#include "mojo/edk/embedder/platform_channel_pair.h"
 #include "mojo/edk/system/broker_messages.h"
+#include "mojo/edk/system/message_pipe_dispatcher.h"
+#include "mojo/edk/system/routed_raw_channel.h"
 
 namespace mojo {
 namespace edk {
@@ -17,23 +21,41 @@
 }
 
 void ChildBroker::SetChildBrokerHostHandle(ScopedPlatformHandle handle)  {
-  handle_ = handle.Pass();
+  ScopedPlatformHandle parent_async_channel_handle;
+#if defined(OS_POSIX)
+  parent_async_channel_handle = handle.Pass();
+#else
+  // On Windows we have two pipes to the parent. The first is for the token
+  // exchange for creating and passing handles, since the child needs the
+  // parent's help if it is sandboxed. The second is the same as POSIX, which is
+  // used for multiplexing related messages. So on Windows, we send the second
+  // pipe as the first string over the first one.
+  parent_sync_channel_ = handle.Pass();
+
+  HANDLE parent_handle = INVALID_HANDLE_VALUE;
+  DWORD bytes_read = 0;
+  BOOL rv = ReadFile(parent_sync_channel_.get().handle, &parent_handle,
+                     sizeof(parent_handle), &bytes_read, NULL);
+  CHECK(rv);
+  parent_async_channel_handle.reset(PlatformHandle(parent_handle));
+#endif
+
+  parent_async_channel_ =
+      RawChannel::Create(parent_async_channel_handle.Pass());
+  internal::g_io_thread_task_runner->PostTask(
+      FROM_HERE,
+      base::Bind(&RawChannel::Init, base::Unretained(parent_async_channel_),
+                 this));
+
   lock_.Unlock();
 }
 
 #if defined(OS_WIN)
 void ChildBroker::CreatePlatformChannelPair(
     ScopedPlatformHandle* server, ScopedPlatformHandle* client) {
-  BrokerMessage message;
-  message.size = kBrokerMessageHeaderSize;
-  message.id = CREATE_PLATFORM_CHANNEL_PAIR;
-
-  uint32_t response_size = 2 * sizeof(HANDLE);
-  HANDLE handles[2];
-  if (WriteAndReadResponse(&message, handles, response_size)) {
-    server->reset(PlatformHandle(handles[0]));
-    client->reset(PlatformHandle(handles[1]));
-  }
+  lock_.Lock();
+  CreatePlatformChannelPairNoLock(server, client);
+  lock_.Unlock();
 }
 
 void ChildBroker::HandleToToken(const PlatformHandle* platform_handles,
@@ -49,7 +71,9 @@
     message->handles[i] = platform_handles[i].handle;
 
   uint32_t response_size = static_cast<int>(count) * sizeof(uint64_t);
+  lock_.Lock();
   WriteAndReadResponse(message, tokens, response_size);
+  lock_.Unlock();
 }
 
 void ChildBroker::TokenToHandle(const uint64_t* tokens,
@@ -67,14 +91,85 @@
   std::vector<HANDLE> handles_temp(count);
   uint32_t response_size =
       static_cast<uint32_t>(handles_temp.size()) * sizeof(HANDLE);
+  lock_.Lock();
   if (WriteAndReadResponse(message, &handles_temp[0], response_size)) {
     for (uint32_t i = 0; i < count; ++i)
       handles[i].handle = handles_temp[i];
+  lock_.Unlock();
   }
 }
 #endif
 
-ChildBroker::ChildBroker() {
+void ChildBroker::ConnectMessagePipe(uint64_t pipe_id,
+                                     MessagePipeDispatcher* message_pipe) {
+  DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread());
+  lock_.Lock();
+
+  ConnectMessagePipeMessage data;
+  data.pipe_id = pipe_id;
+  if (pending_connects_.find(pipe_id) != pending_connects_.end()) {
+    // Both ends of the message pipe are in the same process.
+    // First, tell the browser side that to remove its bookkeeping for a pending
+    // connect, since it'll never get the other side.
+
+    data.type = CANCEL_CONNECT_MESSAGE_PIPE;
+    scoped_ptr<MessageInTransit> message(new MessageInTransit(
+        MessageInTransit::Type::MESSAGE, sizeof(data), &data));
+    parent_async_channel_->WriteMessage(message.Pass());
+
+    if (!in_process_pipes_channel1_) {
+      ScopedPlatformHandle server_handle, client_handle;
+#if defined(OS_WIN)
+      CreatePlatformChannelPairNoLock(&server_handle, &client_handle);
+#else
+      PlatformChannelPair channel_pair;
+      server_handle = channel_pair.PassServerHandle();
+      client_handle = channel_pair.PassClientHandle();
+#endif
+      in_process_pipes_channel1_ = new RoutedRawChannel(
+          server_handle.Pass(),
+          base::Bind(&ChildBroker::ChannelDestructed, base::Unretained(this)));
+      in_process_pipes_channel2_ = new RoutedRawChannel(
+          client_handle.Pass(),
+          base::Bind(&ChildBroker::ChannelDestructed, base::Unretained(this)));
+    }
+
+    connected_pipes_[pending_connects_[pipe_id]] = in_process_pipes_channel1_;
+    connected_pipes_[message_pipe] = in_process_pipes_channel2_;
+    in_process_pipes_channel1_->AddRoute(pipe_id, pending_connects_[pipe_id]);
+    in_process_pipes_channel2_->AddRoute(pipe_id, message_pipe);
+    pending_connects_[pipe_id]->GotNonTransferableChannel(
+        in_process_pipes_channel1_->channel());
+    message_pipe->GotNonTransferableChannel(
+        in_process_pipes_channel2_->channel());
+
+    pending_connects_.erase(pipe_id);
+    lock_.Unlock();
+    return;
+  }
+
+  data.type = CONNECT_MESSAGE_PIPE;
+  scoped_ptr<MessageInTransit> message(new MessageInTransit(
+      MessageInTransit::Type::MESSAGE, sizeof(data), &data));
+  pending_connects_[pipe_id] = message_pipe;
+  parent_async_channel_->WriteMessage(message.Pass());
+
+  lock_.Unlock();
+}
+
+void ChildBroker::CloseMessagePipe(
+    uint64_t pipe_id, MessagePipeDispatcher* message_pipe) {
+  DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread());
+  lock_.Lock();
+  CHECK(connected_pipes_.find(message_pipe) != connected_pipes_.end());
+  connected_pipes_[message_pipe]->RemoveRoute(pipe_id, message_pipe);
+  connected_pipes_.erase(message_pipe);
+  lock_.Unlock();
+}
+
+ChildBroker::ChildBroker()
+    : in_process_pipes_channel1_(nullptr),
+      in_process_pipes_channel2_(nullptr) {
   DCHECK(!internal::g_broker);
   internal::g_broker = this;
   // Block any threads from calling this until we have a pipe to the parent.
@@ -84,18 +179,80 @@
 ChildBroker::~ChildBroker() {
 }
 
+void ChildBroker::OnReadMessage(
+    const MessageInTransit::View& message_view,
+    ScopedPlatformHandleVectorPtr platform_handles) {
+  DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread());
+  lock_.Lock();
+  MultiplexMessages type =
+      *static_cast<const MultiplexMessages*>(message_view.bytes());
+  if (type == CONNECT_TO_PROCESS) {
+    DCHECK_EQ(platform_handles->size(), 1u);
+    ScopedPlatformHandle handle((*platform_handles.get())[0]);
+    (*platform_handles.get())[0] = PlatformHandle();
+
+    const ConnectToProcessMessage* message =
+        static_cast<const ConnectToProcessMessage*>(message_view.bytes());
+
+    CHECK(channels_.find(message->process_id) == channels_.end());
+    channels_[message->process_id] = new RoutedRawChannel(
+        handle.Pass(),
+        base::Bind(&ChildBroker::ChannelDestructed, base::Unretained(this)));
+  } else if (type == PEER_PIPE_CONNECTED) {
+    DCHECK(!platform_handles);
+    const PeerPipeConnectedMessage* message =
+        static_cast<const PeerPipeConnectedMessage*>(message_view.bytes());
+
+    uint64_t pipe_id = message->pipe_id;
+    uint64_t peer_pid = message->process_id;
+
+    CHECK(pending_connects_.find(pipe_id) != pending_connects_.end());
+    MessagePipeDispatcher* pipe = pending_connects_[pipe_id];
+    pending_connects_.erase(pipe_id);
+    if (channels_.find(peer_pid) == channels_.end()) {
+      // We saw the peer process die before we got the reply from the parent.
+      pipe->OnError(ERROR_READ_SHUTDOWN);
+    } else {
+      CHECK(connected_pipes_.find(pipe) == connected_pipes_.end());
+      connected_pipes_[pipe] = channels_[peer_pid];
+      channels_[peer_pid]->AddRoute(pipe_id, pipe);
+      pipe->GotNonTransferableChannel(channels_[peer_pid]->channel());
+    }
+  } else {
+    NOTREACHED();
+  }
+
+  lock_.Unlock();
+}
+
+void ChildBroker::OnError(Error error) {
+  // The parent process shut down.
+}
+
+void ChildBroker::ChannelDestructed(RoutedRawChannel* channel) {
+  DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread());
+  lock_.Lock();
+  for (auto it : channels_) {
+    if (it.second == channel) {
+      channels_.erase(it.first);
+      break;
+    }
+  }
+  lock_.Unlock();
+}
+
+#if defined(OS_WIN)
+
 bool ChildBroker::WriteAndReadResponse(BrokerMessage* message,
                                        void* response,
                                        uint32_t response_size) {
-  lock_.Lock();
-  CHECK(handle_.is_valid());
+  CHECK(parent_sync_channel_.is_valid());
 
   bool result = true;
-#if defined(OS_WIN)
   DWORD bytes_written = 0;
   // This will always write in one chunk per
   // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365150.aspx.
-  BOOL rv = WriteFile(handle_.get().handle, message, message->size,
+  BOOL rv = WriteFile(parent_sync_channel_.get().handle, message, message->size,
                       &bytes_written, NULL);
   if (!rv || bytes_written != message->size) {
     LOG(ERROR) << "Child token serializer couldn't write message.";
@@ -103,8 +260,8 @@
   } else {
     while (response_size) {
       DWORD bytes_read = 0;
-      rv = ReadFile(handle_.get().handle, response, response_size, &bytes_read,
-                    NULL);
+      rv = ReadFile(parent_sync_channel_.get().handle, response, response_size,
+                    &bytes_read, NULL);
       if (!rv) {
         LOG(ERROR) << "Child token serializer couldn't read result.";
         result = false;
@@ -114,12 +271,25 @@
       response = static_cast<char*>(response) + bytes_read;
     }
   }
-#endif
-
-  lock_.Unlock();
 
   return result;
 }
 
+void ChildBroker::CreatePlatformChannelPairNoLock(
+    ScopedPlatformHandle* server, ScopedPlatformHandle* client) {
+  BrokerMessage message;
+  message.size = kBrokerMessageHeaderSize;
+  message.id = CREATE_PLATFORM_CHANNEL_PAIR;
+
+  uint32_t response_size = 2 * sizeof(HANDLE);
+  HANDLE handles[2];
+  if (WriteAndReadResponse(&message, handles, response_size)) {
+    server->reset(PlatformHandle(handles[0]));
+    client->reset(PlatformHandle(handles[1]));
+  }
+}
+
+#endif
+
 }  // namespace edk
 }  // namespace mojo
diff --git a/mojo/edk/system/child_broker.h b/mojo/edk/system/child_broker.h
index 689739a..366daa74 100644
--- a/mojo/edk/system/child_broker.h
+++ b/mojo/edk/system/child_broker.h
@@ -5,20 +5,28 @@
 #ifndef MOJO_EDK_SYSTEM_CHILD_BROKER_H_
 #define MOJO_EDK_SYSTEM_CHILD_BROKER_H_
 
+#include "base/compiler_specific.h"

+#include "base/containers/hash_tables.h"
+#include "base/macros.h"
 #include "base/memory/singleton.h"
+#include "base/process/process_handle.h"
 #include "base/synchronization/lock_impl.h"
 #include "mojo/edk/embedder/scoped_platform_handle.h"
 #include "mojo/edk/system/broker.h"
+#include "mojo/edk/system/raw_channel.h"
 #include "mojo/edk/system/system_impl_export.h"
 
 namespace mojo {
 namespace edk {
+class RoutedRawChannel;
 struct BrokerMessage;
 
 // An implementation of Broker used in (sandboxed) child processes. It talks
 // over sync IPCs to the (unsandboxed) parent process (specifically,
-// ParentBroker) to convert handles to tokens and vice versa.
-class MOJO_SYSTEM_IMPL_EXPORT ChildBroker : public Broker {
+// ChildBrokerHost) to convert handles to tokens and vice versa. It also sends
+// async messages to handle message pipe multiplexing.
+class MOJO_SYSTEM_IMPL_EXPORT ChildBroker
+    : public Broker, public RawChannel::Delegate {
  public:
   static ChildBroker* GetInstance();
 
@@ -36,6 +44,10 @@
                      size_t count,
                      PlatformHandle* handles) override;
 #endif
+  void ConnectMessagePipe(uint64_t pipe_id,
+                          MessagePipeDispatcher* message_pipe) override;
+  void CloseMessagePipe(uint64_t pipe_id,
+                        MessagePipeDispatcher* message_pipe) override;
 
  private:
   friend struct base::DefaultSingletonTraits<ChildBroker>;
@@ -43,17 +55,68 @@
   ChildBroker();
   ~ChildBroker() override;
 
+  // RawChannel::Delegate implementation:
+  void OnReadMessage(
+      const MessageInTransit::View& message_view,
+      ScopedPlatformHandleVectorPtr platform_handles) override;
+  void OnError(Error error) override;
+
+  // Callback for when a RoutedRawChannel is destroyed for cleanup.
+  void ChannelDestructed(RoutedRawChannel* channel);
+
+#if defined(OS_WIN)
   // Helper method to write the given message and read back the result.
   bool WriteAndReadResponse(BrokerMessage* message,
                             void* response,
                             uint32_t response_size);
 
+  void CreatePlatformChannelPairNoLock(ScopedPlatformHandle* server,
+                                       ScopedPlatformHandle* client);
+
+  // Pipe used for communication to the parent process. We use a pipe directly
+  // instead of bindings or RawChannel because we need to send synchronous
+  // messages with replies from any thread.
+  ScopedPlatformHandle parent_sync_channel_;
+#endif
+
   // Guards access to below.
   // We use LockImpl instead of Lock because the latter adds thread checking
   // that we don't want (since we lock in the constructor and unlock on another
   // thread.
   base::internal::LockImpl lock_;
-  ScopedPlatformHandle handle_;
+
+  // RawChannel used for asynchronous communication to and from the parent
+  // process. Since these messages are bidirectional, we can't use
+  // |parent_sync_channel_| which is only used for sync messages to the parent.
+  // However since the messages are asynchronous, we can use RawChannel for
+  // convenience instead of writing and reading from pipes manually. Although it
+  // would be convenient, we don't use Mojo IPC because it would be a layering
+  // violation (and cirular dependency) if the system layer depended on
+  // bindings.
+  RawChannel* parent_async_channel_;
+
+  // Maps from routing ids to the MessagePipeDispatcher that have requested to
+  // connect to them. When the parent replies with which process they should be
+  // connected to, they will migrate to |connected_pipes_|.
+  base::hash_map<uint64_t, MessagePipeDispatcher*> pending_connects_;
+
+  // Map from MessagePipeDispatcher to its RoutedRawChannel. This is needed so
+  // that when a MessagePipeDispatcher is closed we can remove the route for the
+  // corresponding RoutedRawChannel.
+  // Note the key is MessagePipeDispatcher*, instead of pipe_id, because when
+  // the two pipes are in the same process they will have one pipe_id but be
+  // connected to the two RoutedRawChannel objects below.
+  base::hash_map<MessagePipeDispatcher*, RoutedRawChannel*> connected_pipes_;
+
+  // Holds a map of all the RoutedRawChannel that connect this child process to
+  // any other process. The key is the peer process'd pid.
+  base::hash_map<base::ProcessId, RoutedRawChannel*> channels_;
+
+  // Used for message pipes in the same process.
+  RoutedRawChannel* in_process_pipes_channel1_;
+  RoutedRawChannel* in_process_pipes_channel2_;
+
+  DISALLOW_COPY_AND_ASSIGN(ChildBroker);
 };
 
 }  // namespace edk
diff --git a/mojo/edk/system/child_broker_host.cc b/mojo/edk/system/child_broker_host.cc
index b7f055a..ae7236f 100644
--- a/mojo/edk/system/child_broker_host.cc
+++ b/mojo/edk/system/child_broker_host.cc
@@ -6,77 +6,177 @@
 
 #include "base/bind.h"
 #include "base/lazy_instance.h"
+#include "mojo/edk/embedder/embedder_internal.h"
 #include "mojo/edk/embedder/platform_channel_pair.h"
 #include "mojo/edk/system/broker_messages.h"
 #include "mojo/edk/system/broker_state.h"
 #include "mojo/edk/system/configuration.h"
+#include "mojo/edk/system/core.h"
+#include "mojo/edk/system/platform_handle_dispatcher.h"
 
 namespace mojo {
 namespace edk {
 
 namespace {
+#if defined(OS_WIN)
 static const int kDefaultReadBufferSize = 256;
+#endif
 }
 
 ChildBrokerHost::ChildBrokerHost(base::ProcessHandle child_process,
                                  ScopedPlatformHandle pipe)
-    : child_process_(child_process),
-      pipe_(pipe.Pass()),
-      num_bytes_read_(0) {
-#if defined(OS_WIN)
+    : process_id_(base::GetProcId(child_process)) {
+  ScopedPlatformHandle parent_async_channel_handle;
+#if defined(OS_POSIX)
+  parent_async_channel_handle = pipe.Pass();
+#else
+  child_process_ = child_process;
+  sync_channel_ = pipe.Pass();
   memset(&read_context_.overlapped, 0, sizeof(read_context_.overlapped));
   read_context_.handler = this;
   memset(&write_context_.overlapped, 0, sizeof(write_context_.overlapped));
   write_context_.handler = this;
-#else
-  // TODO(jam)
-  (void)child_process_; // Suppress -Wunused-private-field.
-  (void)num_bytes_read_; // Suppress -Wunused-private-field.
-#endif
-
   read_data_.resize(kDefaultReadBufferSize);
-  BrokerState::GetInstance()->broker_thread()->PostTask(
+  num_bytes_read_ = 0;
+
+  // See comment in ChildBroker::SetChildBrokerHostHandle. Summary is we need
+  // two pipes on Windows, so send the second one over the first one.
+  PlatformChannelPair parent_pipe;
+  parent_async_channel_handle = parent_pipe.PassServerHandle();
+
+  HANDLE duplicated_child_handle =
+      DuplicateToChild(parent_pipe.PassClientHandle().release().handle);
+  BOOL rv = WriteFile(sync_channel_.get().handle,
+                      &duplicated_child_handle, sizeof(duplicated_child_handle),
+                      NULL, &write_context_.overlapped);
+  DCHECK(rv || GetLastError() == ERROR_IO_PENDING);
+
+  internal::g_io_thread_task_runner->PostTask(
       FROM_HERE,
       base::Bind(&ChildBrokerHost::RegisterIOHandler, base::Unretained(this)));
+#endif
+
+  child_channel_ = RawChannel::Create(parent_async_channel_handle.Pass());
+  internal::g_io_thread_task_runner->PostTask(
+      FROM_HERE,
+      base::Bind(&RawChannel::Init, base::Unretained(child_channel_), this));
+  internal::g_io_thread_task_runner->PostTask(
+      FROM_HERE,
+      base::Bind(&RawChannel::EnsureLazyInitialized,
+                  base::Unretained(child_channel_)));
+
+  BrokerState::GetInstance()->ChildBrokerHostCreated(this);
+}
+
+base::ProcessId ChildBrokerHost::GetProcessId() {
+  return process_id_;
+}
+
+void ChildBrokerHost::ConnectToProcess(base::ProcessId process_id,
+                                       ScopedPlatformHandle pipe) {
+  if (!child_channel_)
+    return;  // Can happen at process shutdown on Windows.
+  ConnectToProcessMessage data;
+  data.type = CONNECT_TO_PROCESS;
+  data.process_id = process_id;
+  scoped_ptr<MessageInTransit> message(new MessageInTransit(
+      MessageInTransit::Type::MESSAGE, sizeof(data), &data));
+  scoped_refptr<Dispatcher> dispatcher =
+      PlatformHandleDispatcher::Create(pipe.Pass());
+  internal::g_core->AddDispatcher(dispatcher);
+  scoped_ptr<DispatcherVector> dispatchers(new DispatcherVector);
+  dispatchers->push_back(dispatcher);
+  message->SetDispatchers(dispatchers.Pass());
+  message->SerializeAndCloseDispatchers();
+  child_channel_->WriteMessage(message.Pass());
+}
+
+void ChildBrokerHost::ConnectMessagePipe(uint64_t pipe_id,
+                                         base::ProcessId process_id) {
+  if (!child_channel_)
+    return;  // Can happen at process shutdown on Windows.
+  PeerPipeConnectedMessage data;
+  data.type = PEER_PIPE_CONNECTED;
+  data.pipe_id = pipe_id;
+  data.process_id = process_id;
+  scoped_ptr<MessageInTransit> message(new MessageInTransit(
+      MessageInTransit::Type::MESSAGE, sizeof(data), &data));
+  child_channel_->WriteMessage(message.Pass());
 }
 
 ChildBrokerHost::~ChildBrokerHost() {
+  DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread());
+  BrokerState::GetInstance()->ChildBrokerHostDestructed(this);
+  if (child_channel_)
+    child_channel_->Shutdown();
 }
 
-void ChildBrokerHost::RegisterIOHandler() {
-#if defined(OS_WIN)
-  base::MessageLoopForIO::current()->RegisterIOHandler(
-      pipe_.get().handle, this);
-  BeginRead();
-#elif defined(OS_POSIX)
-  // TOOD(jam): setup
+void ChildBrokerHost::OnReadMessage(
+    const MessageInTransit::View& message_view,
+    ScopedPlatformHandleVectorPtr platform_handles) {
+  DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread());
+  CHECK(!platform_handles);
+  if (message_view.num_bytes() !=
+      static_cast<uint32_t>(sizeof(ConnectMessagePipeMessage))) {
+    NOTREACHED();
+    delete this;
+  }
+
+  const ConnectMessagePipeMessage* message =
+      static_cast<const ConnectMessagePipeMessage*>(message_view.bytes());
+  switch(message->type) {
+    case CONNECT_MESSAGE_PIPE:
+      BrokerState::GetInstance()->HandleConnectMessagePipe(this,
+                                                           message->pipe_id);
+      break;
+    case CANCEL_CONNECT_MESSAGE_PIPE:
+      BrokerState::GetInstance()->HandleCancelConnectMessagePipe(
+          message->pipe_id);
+      break;
+    default:
+      NOTREACHED();
+      delete this;
+  }
+}
+
+void ChildBrokerHost::OnError(Error error) {
+  DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread());
+  child_channel_->Shutdown();
+  child_channel_ = nullptr;
+  // On Windows, we have two pipes to the child process. It's easier to wait
+  // until we get the error from the pipe that uses asynchronous I/O.
+#if !defined(OS_WIN)
+  delete this;
 #endif
 }
 
-void ChildBrokerHost::BeginRead() {
 #if defined(OS_WIN)
-  BOOL rv = ReadFile(pipe_.get().handle, &read_data_[num_bytes_read_],
+void ChildBrokerHost::RegisterIOHandler() {
+  base::MessageLoopForIO::current()->RegisterIOHandler(
+      sync_channel_.get().handle, this);
+  BeginRead();
+}
+
+void ChildBrokerHost::BeginRead() {
+  BOOL rv = ReadFile(sync_channel_.get().handle,
+                     &read_data_[num_bytes_read_],
                      static_cast<int>(read_data_.size() - num_bytes_read_),
                      nullptr, &read_context_.overlapped);
   if (rv || GetLastError() == ERROR_IO_PENDING)
     return;
 
-  if (rv == ERROR_BROKEN_PIPE) {
+  if (GetLastError() == ERROR_BROKEN_PIPE) {
     delete this;
     return;
   }
 
   NOTREACHED() << "Unknown error in ChildBrokerHost " << rv;
-#endif
 }
 
-#if defined(OS_WIN)
 void ChildBrokerHost::OnIOCompleted(base::MessageLoopForIO::IOContext* context,
                                     DWORD bytes_transferred,
                                     DWORD error) {
-  if (context != &read_context_)
-    return;
-
+  DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread());
   if (error == ERROR_BROKEN_PIPE) {
     delete this;
     return;  // Child process exited or crashed.
@@ -88,6 +188,11 @@
     return;
   }
 
+  if (context == &write_context_) {
+    write_data_.clear();
+    return;
+  }
+
   num_bytes_read_ += bytes_transferred;
   CHECK_GE(num_bytes_read_, sizeof(uint32_t));
   BrokerMessage* message = reinterpret_cast<BrokerMessage*>(&read_data_[0]);
@@ -97,6 +202,15 @@
     return;
   }
 
+  // This should never fire because we only get new requests from a child
+  // process after it has read all the previous data we wrote.
+  if (!write_data_.empty()) {
+    NOTREACHED() << "ChildBrokerHost shouldn't have data to write when it gets "
+                 << " a new request";
+    delete this;
+    return;
+  }
+
   if (message->id == CREATE_PLATFORM_CHANNEL_PAIR) {
     PlatformChannelPair channel_pair;
     uint32_t response_size = 2 * sizeof(HANDLE);
@@ -152,7 +266,7 @@
     return;
   }
 
-  BOOL rv = WriteFile(pipe_.get().handle, &write_data_[0],
+  BOOL rv = WriteFile(sync_channel_.get().handle, &write_data_[0],
                       static_cast<int>(write_data_.size()), NULL,
                       &write_context_.overlapped);
   DCHECK(rv || GetLastError() == ERROR_IO_PENDING);
diff --git a/mojo/edk/system/child_broker_host.h b/mojo/edk/system/child_broker_host.h
index 7f4bc61..a91218a 100644
--- a/mojo/edk/system/child_broker_host.h
+++ b/mojo/edk/system/child_broker_host.h
@@ -8,20 +8,24 @@
 #include <vector>
 
 #include "base/compiler_specific.h"
+#include "base/macros.h"
 #include "base/message_loop/message_loop.h"
 #include "base/process/process_handle.h"
 #include "mojo/edk/embedder/scoped_platform_handle.h"
+#include "mojo/edk/system/raw_channel.h"
 #include "mojo/edk/system/system_impl_export.h"
 
 namespace mojo {
 namespace edk {
 
-// Responds to requests from a child process to exchange handles to tokens and
-// vice versa. There is one object of this class per child process host object.
+// Responds to requests from ChildBroker. This is used to handle message pipe
+// multiplexing and Windows sandbox messages. There is one object of this class
+// per child process host object.
 // This object will delete itself when it notices that the pipe is broken.
 class MOJO_SYSTEM_IMPL_EXPORT ChildBrokerHost
+    : public RawChannel::Delegate
 #if defined(OS_WIN)
-    : NON_EXPORTED_BASE(public base::MessageLoopForIO::IOHandler) {
+      , NON_EXPORTED_BASE(public base::MessageLoopForIO::IOHandler) {
 #else
     {
 #endif
@@ -33,17 +37,29 @@
   // this class.
   ChildBrokerHost(base::ProcessHandle child_process, ScopedPlatformHandle pipe);
 
- private:
-#if defined(OS_WIN)
-  ~ChildBrokerHost() override;
-#else
-  ~ChildBrokerHost();
-#endif
+  base::ProcessId GetProcessId();
 
+  // Sends a message to the child process to connect to |process_id| via |pipe|.
+  void ConnectToProcess(base::ProcessId process_id, ScopedPlatformHandle pipe);
+
+  // Sends a message to the child process that |pipe_id|'s other end is in
+  // |process_id|.
+  void ConnectMessagePipe(uint64_t pipe_id, base::ProcessId process_id);
+
+ private:
+  ~ChildBrokerHost() override;
+
+  // RawChannel::Delegate implementation:
+  void OnReadMessage(
+      const MessageInTransit::View& message_view,
+      ScopedPlatformHandleVectorPtr platform_handles) override;
+  void OnError(Error error) override;
+
+#if defined(OS_WIN)
   void RegisterIOHandler();
   void BeginRead();
 
-#if defined(OS_WIN)
+  // base::MessageLoopForIO::IOHandler implementation:
   void OnIOCompleted(base::MessageLoopForIO::IOContext* context,
                      DWORD bytes_transferred,
                      DWORD error) override;
@@ -53,18 +69,29 @@
   HANDLE DuplicateFromChild(HANDLE handle);
 #endif
 
-  base::ProcessHandle child_process_;
-  ScopedPlatformHandle pipe_;
+  base::ProcessId process_id_;
+
+  // Channel used to receive and send multiplexing related messages.
+  RawChannel* child_channel_;
 
 #if defined(OS_WIN)
+  // Handle to the child process, used for duplication of handles.
+  base::ProcessHandle child_process_;
+
+  // Pipe used for synchronous messages from the child. Responses are written to
+  // it as well.
+  ScopedPlatformHandle sync_channel_;
+
   base::MessageLoopForIO::IOContext read_context_;
   base::MessageLoopForIO::IOContext write_context_;
-#endif
 
   std::vector<char> read_data_;
   // How many bytes in read_data_ we already read.
   uint32_t num_bytes_read_;
   std::vector<char> write_data_;
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(ChildBrokerHost);
 };
 
 }  // namespace edk
diff --git a/mojo/edk/system/core.cc b/mojo/edk/system/core.cc
index 77b06f0cc..454b487 100644
--- a/mojo/edk/system/core.cc
+++ b/mojo/edk/system/core.cc
@@ -7,6 +7,7 @@
 #include <vector>
 
 #include "base/logging.h"
+#include "base/rand_util.h"
 #include "base/time/time.h"
 #include "mojo/edk/embedder/embedder_internal.h"
 #include "mojo/edk/embedder/platform_channel_pair.h"
@@ -206,18 +207,28 @@
     return MOJO_RESULT_RESOURCE_EXHAUSTED;
   }
 
-  ScopedPlatformHandle server_handle, client_handle;
+  if (validated_options.flags &
+          MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_TRANSFERABLE) {
+    ScopedPlatformHandle server_handle, client_handle;
 #if defined(OS_WIN)
-  internal::g_broker->CreatePlatformChannelPair(&server_handle, &client_handle);
+    internal::g_broker->CreatePlatformChannelPair(&server_handle,
+                                                  &client_handle);
 #else
-  PlatformChannelPair channel_pair;
-  server_handle = channel_pair.PassServerHandle();
-  client_handle = channel_pair.PassClientHandle();
+    PlatformChannelPair channel_pair;
+    server_handle = channel_pair.PassServerHandle();
+    client_handle = channel_pair.PassClientHandle();
 #endif
-  dispatcher0->Init(server_handle.Pass(), nullptr, 0u, nullptr, 0u, nullptr,
-                    nullptr);
-  dispatcher1->Init(client_handle.Pass(), nullptr, 0u, nullptr, 0u, nullptr,
-                    nullptr);
+    dispatcher0->Init(server_handle.Pass(), nullptr, 0u, nullptr, 0u, nullptr,
+                      nullptr);
+    dispatcher1->Init(client_handle.Pass(), nullptr, 0u, nullptr, 0u, nullptr,
+                      nullptr);
+  } else {
+    uint64_t pipe_id = 0;
+    while (pipe_id == 0)
+      pipe_id = base::RandUint64();
+    dispatcher0->InitNonTransferable(pipe_id);
+    dispatcher1->InitNonTransferable(pipe_id);
+  }
 
   *message_pipe_handle0 = handle_pair.first;
   *message_pipe_handle1 = handle_pair.second;
diff --git a/mojo/edk/system/core_test_base.h b/mojo/edk/system/core_test_base.h
index 774dc95..7ed8a7a 100644
--- a/mojo/edk/system/core_test_base.h
+++ b/mojo/edk/system/core_test_base.h
@@ -22,7 +22,7 @@
 
 class CoreTestBase_MockHandleInfo;
 
-class CoreTestBase : public MojoSystemTest {
+class CoreTestBase : public testing::Test {
  public:
   using MockHandleInfo = CoreTestBase_MockHandleInfo;
 
diff --git a/mojo/edk/system/core_unittest.cc b/mojo/edk/system/core_unittest.cc
index cbbd905..9604bbd 100644
--- a/mojo/edk/system/core_unittest.cc
+++ b/mojo/edk/system/core_unittest.cc
@@ -730,8 +730,11 @@
 #endif
 
   MojoHandle h_passed[2];
+  MojoCreateMessagePipeOptions options;
+  options.struct_size = sizeof(MojoCreateMessagePipeOptions);
+  options.flags = MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_TRANSFERABLE;
   ASSERT_EQ(MOJO_RESULT_OK,
-            core()->CreateMessagePipe(nullptr, &h_passed[0], &h_passed[1]));
+            core()->CreateMessagePipe(&options, &h_passed[0], &h_passed[1]));
 
   // Make sure that |h_passed[]| work properly.
   ASSERT_EQ(MOJO_RESULT_OK,
diff --git a/mojo/edk/system/data_pipe_unittest.cc b/mojo/edk/system/data_pipe_unittest.cc
index 5c8f0f8..0880f6084 100644
--- a/mojo/edk/system/data_pipe_unittest.cc
+++ b/mojo/edk/system/data_pipe_unittest.cc
@@ -32,7 +32,7 @@
 // TODO(vtl): Get rid of this.
 const size_t kMaxPoll = 100;
 
-class DataPipeTest : public test::MojoSystemTest {
+class DataPipeTest : public testing::Test {
  public:
   DataPipeTest() : producer_(MOJO_HANDLE_INVALID),
                    consumer_(MOJO_HANDLE_INVALID) {}
diff --git a/mojo/edk/system/dispatcher.h b/mojo/edk/system/dispatcher.h
index fb757c7..d1c7b1f6 100644
--- a/mojo/edk/system/dispatcher.h
+++ b/mojo/edk/system/dispatcher.h
@@ -300,6 +300,7 @@
   // Available to subclasses. (Note: Returns a non-const reference, just like
   // |base::AutoLock|'s constructor takes a non-const reference.)
   base::Lock& lock() const { return lock_; }
+  bool is_closed() const { return is_closed_; }
 
  private:
   friend class DispatcherTransport;
diff --git a/mojo/edk/system/message_in_transit.cc b/mojo/edk/system/message_in_transit.cc
index b85efc7..05fd98f 100644
--- a/mojo/edk/system/message_in_transit.cc
+++ b/mojo/edk/system/message_in_transit.cc
@@ -166,6 +166,7 @@
   header()->type = type;
   header()->num_bytes = num_bytes;
   header()->unused = 0;
+  header()->route_id = 0;
   // Note: If dispatchers are subsequently attached, then |total_size| will have
   // to be adjusted.
   UpdateTotalSize();
diff --git a/mojo/edk/system/message_in_transit.h b/mojo/edk/system/message_in_transit.h
index 78dc40a..bebaaf7 100644
--- a/mojo/edk/system/message_in_transit.h
+++ b/mojo/edk/system/message_in_transit.h
@@ -103,6 +103,7 @@
       return static_cast<const char*>(buffer_) + sizeof(Header);
     }
     Type type() const { return header()->type; }
+    uint64_t route_id() const { return header()->route_id; }
 
    private:
     const Header* header() const { return static_cast<const Header*>(buffer_); }
@@ -171,6 +172,9 @@
 
   Type type() const { return header()->type; }
 
+  void set_route_id(uint64_t route_id) { header()->route_id = route_id; }
+  uint64_t route_id() const { return header()->route_id; }
+
   // Gets the dispatchers attached to this message; this may return null if
   // there are none. Note that the caller may mutate the set of dispatchers
   // (e.g., take ownership of all the dispatchers, leaving the vector empty).
@@ -200,9 +204,10 @@
     // |SerializeAndCloseDispatchers()| has not been called.
     uint32_t total_size;
     Type type;                         // 2 bytes.
-    Type unusedforalignment;           // 2 bytes.
+    uint16_t unusedforalignment;       // 2 bytes.
     uint32_t num_bytes;
     uint32_t unused;
+    uint64_t route_id;
   };
 
   const Header* header() const {
diff --git a/mojo/edk/system/message_pipe_dispatcher.cc b/mojo/edk/system/message_pipe_dispatcher.cc
index 6ebab748..55e03fa 100644
--- a/mojo/edk/system/message_pipe_dispatcher.cc
+++ b/mojo/edk/system/message_pipe_dispatcher.cc
@@ -25,10 +25,13 @@
 const size_t kInvalidMessagePipeHandleIndex = static_cast<size_t>(-1);
 
 struct MOJO_ALIGNAS(8) SerializedMessagePipeHandleDispatcher {
+  bool transferable;
+  bool write_error;
+  uint64_t pipe_id;  // If transferable is false.
+  // The following members are only set if transferable is true.
   // Could be |kInvalidMessagePipeHandleIndex| if the other endpoint of the MP
   // was closed.
   size_t platform_handle_index;
-  bool write_error;
 
   size_t shared_memory_handle_index;  // (Or |kInvalidMessagePipeHandleIndex|.)
   uint32_t shared_memory_size;
@@ -90,7 +93,8 @@
     const MojoCreateMessagePipeOptions* in_options,
     MojoCreateMessagePipeOptions* out_options) {
   const MojoCreateMessagePipeOptionsFlags kKnownFlags =
-      MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE;
+      MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE |
+      MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_TRANSFERABLE;
 
   *out_options = kDefaultCreateOptions;
   if (!in_options)
@@ -119,6 +123,7 @@
     char* serialized_write_buffer, size_t serialized_write_buffer_size,
     std::vector<int>* serialized_read_fds,
     std::vector<int>* serialized_write_fds) {
+  CHECK(transferable_);
   if (message_pipe.get().is_valid()) {
     channel_ = RawChannel::Create(message_pipe.Pass());
 
@@ -132,8 +137,14 @@
   }
 }
 
+void MessagePipeDispatcher::InitNonTransferable(uint64_t pipe_id) {
+  CHECK(!transferable_);
+  pipe_id_ = pipe_id;
+}
+
 void MessagePipeDispatcher::InitOnIO() {
   base::AutoLock locker(lock());
+  CHECK(transferable_);
   calling_init_ = true;
   if (channel_)
     channel_->Init(this);
@@ -142,10 +153,28 @@
 
 void MessagePipeDispatcher::CloseOnIO() {
   base::AutoLock locker(lock());
+  if (transferable_) {
+    if (channel_) {
+      channel_->Shutdown();
+      channel_ = nullptr;
+    }
+  } else {
+    if (non_transferable_state_ == CONNECT_CALLED ||
+        non_transferable_state_ == WAITING_FOR_READ_OR_WRITE) {
+      if (non_transferable_state_ == WAITING_FOR_READ_OR_WRITE)
+        RequestNontransferableChannel();
 
-  if (channel_) {
-    channel_->Shutdown();
-    channel_ = nullptr;
+      // We can't cancel the pending request yet, since the other side of the
+      // message pipe would want to get pending outgoing messages (if any) or
+      // at least know that this end was closed. So keep this object alive until
+      // then.
+      non_transferable_state_ = WAITING_FOR_CONNECT_TO_CLOSE;
+      AddRef();
+    } else if (non_transferable_state_ == CONNECTED) {
+      internal::g_broker->CloseMessagePipe(pipe_id_, this);
+      non_transferable_state_ = CLOSED;
+      channel_ = nullptr;
+    }
   }
 }
 
@@ -153,6 +182,30 @@
   return Type::MESSAGE_PIPE;
 }
 
+void MessagePipeDispatcher::GotNonTransferableChannel(RawChannel* channel) {
+  base::AutoLock locker(lock());
+  channel_ = channel;
+  while (!non_transferable_outgoing_message_queue_.IsEmpty()) {
+    channel_->WriteMessage(
+        non_transferable_outgoing_message_queue_.GetMessage());
+  }
+
+  if (non_transferable_state_ == WAITING_FOR_CONNECT_TO_CLOSE) {
+    // We kept this object alive until it's connected, we can release it now.
+    // Since we're in a callback from the Broker, call it asynchronously.
+    internal::g_io_thread_task_runner->PostTask(
+        FROM_HERE,
+        base::Bind(&Broker::CloseMessagePipe,
+                   base::Unretained(internal::g_broker), pipe_id_,
+                   base::Unretained(this)));
+    non_transferable_state_ = CLOSED;
+    channel_ = nullptr;
+    base::MessageLoop::current()->ReleaseSoon(FROM_HERE, this);
+  } else {
+    non_transferable_state_ = CONNECTED;
+  }
+}
+
 #if defined(OS_WIN)
 // TODO(jam): this is copied from RawChannelWin till I figure out what's the
 // best way we want to share this.
@@ -186,6 +239,14 @@
 
   const SerializedMessagePipeHandleDispatcher* serialization =
       static_cast<const SerializedMessagePipeHandleDispatcher*>(source);
+
+  scoped_refptr<MessagePipeDispatcher> rv(
+      new MessagePipeDispatcher(serialization->transferable));
+  if (!rv->transferable_) {
+    rv->InitNonTransferable(serialization->pipe_id);
+    return rv;
+  }
+
   if (serialization->shared_memory_size !=
       (serialization->serialized_read_buffer_size +
        serialization->serialized_write_buffer_size +
@@ -233,8 +294,6 @@
     }
   }
 
-  scoped_refptr<MessagePipeDispatcher> rv(
-      Create(MessagePipeDispatcher::kDefaultCreateOptions));
   rv->write_error_ = serialization->write_error;
 
   std::vector<int> serialized_read_fds;
@@ -269,8 +328,15 @@
 
   while (message_queue_size) {
     size_t message_size;
-    CHECK(MessageInTransit::GetNextMessageSize(
-              message_queue_data, message_queue_size, &message_size));
+    if (!MessageInTransit::GetNextMessageSize(
+            message_queue_data, message_queue_size, &message_size)) {
+      NOTREACHED() << "Couldn't read message size from serialized data.";
+      return nullptr;
+    }
+    if (message_size > message_queue_size) {
+      NOTREACHED() << "Invalid serialized message size.";
+      return nullptr;
+    }
     MessageInTransit::View message_view(message_size, message_queue_data);
     message_queue_size -= message_size;
     message_queue_data += message_size;
@@ -333,14 +399,17 @@
   return rv;
 }
 
-MessagePipeDispatcher::MessagePipeDispatcher()
+MessagePipeDispatcher::MessagePipeDispatcher(bool transferable)
     : channel_(nullptr),
-      serialized_(false),
       serialized_read_fds_length_(0u),
       serialized_write_fds_length_(0u),
       serialized_message_fds_length_(0u),
+      pipe_id_(0),
+      non_transferable_state_(WAITING_FOR_READ_OR_WRITE),
+      serialized_(false),
       calling_init_(false),
-      write_error_(false) {
+      write_error_(false),
+      transferable_(transferable) {
 }
 
 MessagePipeDispatcher::~MessagePipeDispatcher() {
@@ -369,6 +438,16 @@
 }
 
 void MessagePipeDispatcher::SerializeInternal() {
+  serialized_ = true;
+  if (!transferable_) {
+    CHECK(non_transferable_state_ == WAITING_FOR_READ_OR_WRITE)
+        << "Non transferable message pipe being sent after read/write. "
+        << "MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_TRANSFERABLE must be used if "
+        << "the pipe can be sent after it's read or written.";
+    non_transferable_state_ = SERIALISED;
+    return;
+  }
+
   // We need to stop watching handle immediately, even though not on IO thread,
   // so that other messages aren't read after this.
   std::vector<int> serialized_read_fds, serialized_write_fds;
@@ -385,8 +464,6 @@
                           serialized_write_fds.end());
     serialized_write_fds_length_ = serialized_write_fds.size();
     channel_ = nullptr;
-    if (write_error)
-      write_error = true;
   } else {
     // It's valid that the other side wrote some data and closed its end.
   }
@@ -441,20 +518,18 @@
           all_platform_handles->at(i) = PlatformHandle();
         }
 #endif
+      }
 
       serialized_message_queue_.insert(
           serialized_message_queue_.end(),
           static_cast<const char*>(message->transport_data()->buffer()),
           static_cast<const char*>(message->transport_data()->buffer()) +
               transport_data_buffer_size);
-      }
     }
 
     for (size_t i = 0; i < dispatchers.size(); ++i)
       dispatchers[i]->TransportEnded();
   }
-
-  serialized_ = true;
 }
 
 scoped_refptr<Dispatcher>
@@ -463,21 +538,24 @@
 
   SerializeInternal();
 
-  // TODO(vtl): Currently, there are no options, so we just use
-  // |kDefaultCreateOptions|. Eventually, we'll have to duplicate the options
-  // too.
-  scoped_refptr<MessagePipeDispatcher> rv = Create(kDefaultCreateOptions);
-  rv->serialized_platform_handle_ = serialized_platform_handle_.Pass();
-  serialized_message_queue_.swap(rv->serialized_message_queue_);
-  serialized_read_buffer_.swap(rv->serialized_read_buffer_);
-  serialized_write_buffer_.swap(rv->serialized_write_buffer_);
-  serialized_fds_.swap(rv->serialized_fds_);
-  rv->serialized_read_fds_length_ = serialized_read_fds_length_;
-  rv->serialized_write_fds_length_ = serialized_write_fds_length_;
-  rv->serialized_message_fds_length_ = serialized_message_fds_length_;
+  scoped_refptr<MessagePipeDispatcher> rv(
+      new MessagePipeDispatcher(transferable_));
   rv->serialized_ = true;
-  rv->write_error_ = write_error_;
-  return scoped_refptr<Dispatcher>(rv.get());
+  if (transferable_) {
+    rv->serialized_platform_handle_ = serialized_platform_handle_.Pass();
+    serialized_message_queue_.swap(rv->serialized_message_queue_);
+    serialized_read_buffer_.swap(rv->serialized_read_buffer_);
+    serialized_write_buffer_.swap(rv->serialized_write_buffer_);
+    serialized_fds_.swap(rv->serialized_fds_);
+    rv->serialized_read_fds_length_ = serialized_read_fds_length_;
+    rv->serialized_write_fds_length_ = serialized_write_fds_length_;
+    rv->serialized_message_fds_length_ = serialized_message_fds_length_;
+    rv->write_error_ = write_error_;
+  } else {
+    rv->pipe_id_ = pipe_id_;
+    rv->non_transferable_state_ = non_transferable_state_;
+  }
+  return rv;
 }
 
 MojoResult MessagePipeDispatcher::WriteMessageImplNoLock(
@@ -485,15 +563,17 @@
     uint32_t num_bytes,
     std::vector<DispatcherTransport>* transports,
     MojoWriteMessageFlags flags) {
+  lock().AssertAcquired();
 
   DCHECK(!transports ||
          (transports->size() > 0 &&
           transports->size() <= GetConfiguration().max_message_num_handles));
 
-  lock().AssertAcquired();
-
-  if (!channel_ || write_error_)
+  if (write_error_ ||
+      (transferable_ && !channel_) ||
+      (!transferable_ && non_transferable_state_ == CLOSED)) {
     return MOJO_RESULT_FAILED_PRECONDITION;
+  }
 
   if (num_bytes > GetConfiguration().max_message_num_bytes)
     return MOJO_RESULT_RESOURCE_EXHAUSTED;
@@ -506,7 +586,17 @@
   }
 
   message->SerializeAndCloseDispatchers();
-  channel_->WriteMessage(message.Pass());
+  if (!transferable_)
+    message->set_route_id(pipe_id_);
+  if (!transferable_ &&
+      (non_transferable_state_ == WAITING_FOR_READ_OR_WRITE ||
+       non_transferable_state_ == CONNECT_CALLED)) {
+    if (non_transferable_state_ == WAITING_FOR_READ_OR_WRITE)
+      RequestNontransferableChannel();
+    non_transferable_outgoing_message_queue_.AddMessage(message.Pass());
+  } else {
+    channel_->WriteMessage(message.Pass());
+  }
 
   return MOJO_RESULT_OK;
 }
@@ -518,8 +608,17 @@
     uint32_t* num_dispatchers,
     MojoReadMessageFlags flags) {
   lock().AssertAcquired();
-  if (channel_)
+  if (channel_) {
     channel_->EnsureLazyInitialized();
+  } else if (!transferable_) {
+      if (non_transferable_state_ == WAITING_FOR_READ_OR_WRITE) {
+        RequestNontransferableChannel();
+        return MOJO_RESULT_SHOULD_WAIT;
+      } else if (non_transferable_state_ == CONNECT_CALLED) {
+        return MOJO_RESULT_SHOULD_WAIT;
+      }
+  }
+
   DCHECK(!dispatchers || dispatchers->empty());
 
   const uint32_t max_bytes = !num_bytes ? 0 : *num_bytes;
@@ -583,14 +682,22 @@
   HandleSignalsState rv;
   if (!message_queue_.IsEmpty())
     rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_READABLE;
-  if (channel_ || !message_queue_.IsEmpty())
+  if (!message_queue_.IsEmpty() ||
+      (transferable_ && channel_) ||
+      (!transferable_ && non_transferable_state_ != CLOSED))
     rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_READABLE;
-  if (channel_ && !write_error_) {
+  if (!write_error_ &&
+      ((transferable_ && channel_) ||
+       (!transferable_ && non_transferable_state_ != CLOSED))) {
     rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_WRITABLE;
     rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_WRITABLE;
   }
-  if (!channel_ || write_error_)
+  if (write_error_ ||
+      (transferable_ && !channel_) ||
+       (!transferable_ &&
+        ((non_transferable_state_ == CLOSED) || is_closed()))) {
     rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_PEER_CLOSED;
+  }
   rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_PEER_CLOSED;
   return rv;
 }
@@ -601,8 +708,13 @@
     uintptr_t context,
     HandleSignalsState* signals_state) {
   lock().AssertAcquired();
-  if (channel_)
+  if (channel_) {
     channel_->EnsureLazyInitialized();
+  } else if (!transferable_ &&
+             non_transferable_state_ == WAITING_FOR_READ_OR_WRITE) {
+    RequestNontransferableChannel();
+  }
+
   HandleSignalsState state = GetHandleSignalsStateImplNoLock();
   if (state.satisfies(signals)) {
     if (signals_state)
@@ -653,6 +765,8 @@
   CloseImplNoLock();
   SerializedMessagePipeHandleDispatcher* serialization =
       static_cast<SerializedMessagePipeHandleDispatcher*>(destination);
+  serialization->transferable = transferable_;
+  serialization->pipe_id = pipe_id_;
   if (serialized_platform_handle_.is_valid()) {
     serialization->platform_handle_index = platform_handles->size();
     platform_handles->push_back(serialized_platform_handle_.release());
@@ -796,7 +910,18 @@
     // called, that is safe since this class always does a PostTask to the IO
     // thread to self destruct.
     if (channel_ && error != ERROR_WRITE) {
-      channel_->Shutdown();
+      if (transferable_) {
+        channel_->Shutdown();
+      } else {
+        CHECK_NE(non_transferable_state_, CLOSED);
+        // Since we're in a callback from the Broker, call it asynchronously.
+        internal::g_io_thread_task_runner->PostTask(
+            FROM_HERE,
+            base::Bind(&Broker::CloseMessagePipe,
+                       base::Unretained(internal::g_broker), pipe_id_,
+                       base::Unretained(this)));
+        non_transferable_state_ = CLOSED;
+      }
       channel_ = nullptr;
     }
     awakable_list_.AwakeForStateChange(GetHandleSignalsStateImplNoLock());
@@ -824,10 +949,14 @@
     if ((*transports)[i].GetType() == Dispatcher::Type::MESSAGE_PIPE) {
       MessagePipeDispatcher* mp =
           static_cast<MessagePipeDispatcher*>(((*transports)[i]).dispatcher());
-      if (channel_ && mp->channel_ && channel_->IsOtherEndOf(mp->channel_)) {
+      if (transferable_ && mp->transferable_ &&
+          channel_ && mp->channel_ && channel_->IsOtherEndOf(mp->channel_)) {
         // The other case should have been disallowed by |Core|. (Note: |port|
         // is the peer port of the handle given to |WriteMessage()|.)
         return MOJO_RESULT_INVALID_ARGUMENT;
+      } else if (!transferable_ && !mp->transferable_ &&
+                 pipe_id_ == mp->pipe_id_) {
+        return MOJO_RESULT_INVALID_ARGUMENT;
       }
     }
   }
@@ -849,5 +978,19 @@
   return MOJO_RESULT_OK;
 }
 
+void MessagePipeDispatcher::RequestNontransferableChannel() {
+  lock().AssertAcquired();
+  CHECK(!transferable_);
+  CHECK_EQ(non_transferable_state_, WAITING_FOR_READ_OR_WRITE);
+  non_transferable_state_ = CONNECT_CALLED;
+
+  // PostTask since the broker can call us back synchronously.
+  internal::g_io_thread_task_runner->PostTask(
+      FROM_HERE,
+      base::Bind(&Broker::ConnectMessagePipe,
+                 base::Unretained(internal::g_broker), pipe_id_,
+                 base::Unretained(this)));
+}
+
 }  // namespace edk
 }  // namespace mojo
diff --git a/mojo/edk/system/message_pipe_dispatcher.h b/mojo/edk/system/message_pipe_dispatcher.h
index 5248583..d70d3bc 100644
--- a/mojo/edk/system/message_pipe_dispatcher.h
+++ b/mojo/edk/system/message_pipe_dispatcher.h
@@ -9,6 +9,7 @@
 #include "mojo/edk/embedder/platform_channel_pair.h"
 #include "mojo/edk/system/awakable_list.h"
 #include "mojo/edk/system/dispatcher.h"
+#include "mojo/edk/system/message_in_transit_queue.h"
 #include "mojo/edk/system/raw_channel.h"
 #include "mojo/edk/system/system_impl_export.h"
 #include "mojo/public/cpp/system/macros.h"
@@ -27,8 +28,10 @@
   static const MojoCreateMessagePipeOptions kDefaultCreateOptions;
 
   static scoped_refptr<MessagePipeDispatcher> Create(
-      const MojoCreateMessagePipeOptions& /*validated_options*/) {
-    return make_scoped_refptr(new MessagePipeDispatcher());
+      const MojoCreateMessagePipeOptions& validated_options) {
+    return make_scoped_refptr(new MessagePipeDispatcher(
+        !!(validated_options.flags &
+           MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_TRANSFERABLE)));
   }
 
   // Validates and/or sets default options for |MojoCreateMessagePipeOptions|.
@@ -40,6 +43,7 @@
       const MojoCreateMessagePipeOptions* in_options,
       MojoCreateMessagePipeOptions* out_options);
 
+  // Initializes a transferable message pipe.
   // Must be called before any other methods. (This method is not thread-safe.)
   void Init(
       ScopedPlatformHandle message_pipe,
@@ -48,9 +52,24 @@
       std::vector<int>* serialized_read_fds,
       std::vector<int>* serialized_write_fds);
 
+  // Initializes a nontransferable message pipe.
+  void InitNonTransferable(uint64_t pipe_id);
+
   // |Dispatcher| public methods:
   Type GetType() const override;
 
+  // RawChannel::Delegate methods:
+  void OnReadMessage(
+      const MessageInTransit::View& message_view,
+      ScopedPlatformHandleVectorPtr platform_handles) override;
+  void OnError(Error error) override;
+
+  // Called by broker when a route is established between this
+  // MessagePipeDispatcher and another one. This object will receive messages
+  // sent to its pipe_id. It should tag all outgoing messages by calling
+  // MessageInTransit::set_route_id with pipe_id_.
+  void GotNonTransferableChannel(RawChannel* channel);
+
   // The "opposite" of |SerializeAndClose()|. (Typically this is called by
   // |Dispatcher::Deserialize()|.)
   static scoped_refptr<MessagePipeDispatcher> Deserialize(
@@ -59,7 +78,9 @@
       PlatformHandleVector* platform_handles);
 
  private:
-  MessagePipeDispatcher();
+  // See MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_TRANSFERABLE's definition for an
+  // explanation of what is a transferable pipe.
+  explicit MessagePipeDispatcher(bool transferable);
   ~MessagePipeDispatcher() override;
 
   void InitOnIO();
@@ -96,12 +117,6 @@
   void TransportStarted() override;
   void TransportEnded() override;
 
-  // |RawChannel::Delegate methods:
-  void OnReadMessage(
-    const MessageInTransit::View& message_view,
-    ScopedPlatformHandleVectorPtr platform_handles) override;
-  void OnError(Error error) override;
-
   // Calls ReleaseHandle and serializes the raw channel. This is split into a
   // function because it's called in two different ways:
   // 1) When serializing "live" dispatchers that are passed to MojoWriteMessage,
@@ -115,14 +130,20 @@
       MessageInTransit* message,
       std::vector<DispatcherTransport>* transports);
 
+  // Called whenever a read or write is done on a non-transferable pipe, which
+  // "binds" the pipe id to this object.
+  void RequestNontransferableChannel();
+
   // Protected by |lock()|:
   RawChannel* channel_;
 
   // Queue of incoming messages that we read from RawChannel but haven't been
   // consumed through MojoReadMessage yet.
   MessageInTransitQueue message_queue_;
+
+  // The following members are only used when transferable_ is false;
+
   // When sending MP, contains serialized message_queue_.
-  bool serialized_;
   std::vector<char> serialized_message_queue_;
   std::vector<char> serialized_read_buffer_;
   std::vector<char> serialized_write_buffer_;
@@ -133,14 +154,40 @@
   size_t serialized_write_fds_length_;
   size_t serialized_message_fds_length_;
   ScopedPlatformHandle serialized_platform_handle_;
+
+  // The following members are only used when transferable_ is true;
+
+  // The unique id shared by both ends of a non-transferable message pipe. This
+  // is held on until a read or write are done, and at that point it's used to
+  // get a RawChannel.
+  uint64_t pipe_id_;
+  enum NonTransferableState {
+    WAITING_FOR_READ_OR_WRITE,
+    CONNECT_CALLED,
+    CONNECTED,
+    WAITING_FOR_CONNECT_TO_CLOSE,
+    CLOSED,
+    SERIALISED,
+  };
+
+  NonTransferableState non_transferable_state_;
+  // Messages that were written while we were waiting to get a RawChannel.
+  MessageInTransitQueue non_transferable_outgoing_message_queue_;
+
+
+  // The following members are used for both modes of transferable_.
+
   AwakableList awakable_list_;
 
   // If DispatcherTransport is created. Must be set before lock() is called to
   // avoid deadlocks with RawChannel calling us.
   base::Lock started_transport_;
 
+  bool serialized_;
   bool calling_init_;
   bool write_error_;
+  // Whether it can be sent after read or write.
+  bool transferable_;
 
   MOJO_DISALLOW_COPY_AND_ASSIGN(MessagePipeDispatcher);
 };
diff --git a/mojo/edk/system/message_pipe_perftest.cc b/mojo/edk/system/message_pipe_perftest.cc
index 5d59e656..e89143b9 100644
--- a/mojo/edk/system/message_pipe_perftest.cc
+++ b/mojo/edk/system/message_pipe_perftest.cc
@@ -24,8 +24,7 @@
     : public test::MultiprocessMessagePipeTestBase {
  public:
   MultiprocessMessagePipePerfTest()
-      : test::MultiprocessMessagePipeTestBase(base::MessageLoop::TYPE_IO),
-        message_count_(0),
+      : message_count_(0),
         message_size_(0) {}
 
   void SetUpMeasurement(int message_count, size_t message_size) {
@@ -86,11 +85,6 @@
 // (which it doesn't reply to). It'll return the number of messages received,
 // not including any "quitquitquit" message, modulo 100.
 MOJO_MULTIPROCESS_TEST_CHILD_MAIN(PingPongClient) {
-  SimplePlatformSupport platform_support;
-  base::MessageLoop message_loop(base::MessageLoop::TYPE_IO);
-  base::TestIOThread test_io_thread(base::TestIOThread::kAutoStart);
-  test::ScopedIPCSupport ipc_support(test_io_thread.task_runner());
-
   ScopedPlatformHandle client_platform_handle =
       test::MultiprocessTestHelper::client_platform_handle.Pass();
   CHECK(client_platform_handle.is_valid());
diff --git a/mojo/edk/system/message_pipe_test_utils.cc b/mojo/edk/system/message_pipe_test_utils.cc
index 1e337fb..c752abc 100644
--- a/mojo/edk/system/message_pipe_test_utils.cc
+++ b/mojo/edk/system/message_pipe_test_utils.cc
@@ -11,16 +11,7 @@
 namespace test {
 
 #if !defined(OS_IOS)
-MultiprocessMessagePipeTestBase::MultiprocessMessagePipeTestBase()
-    : test_io_thread_(base::TestIOThread::kAutoStart),
-      ipc_support_(test_io_thread_.task_runner()) {
-}
-
-MultiprocessMessagePipeTestBase::MultiprocessMessagePipeTestBase(
-    base::MessageLoop::Type main_message_loop_type)
-    : message_loop_(main_message_loop_type),
-      test_io_thread_(base::TestIOThread::kAutoStart),
-      ipc_support_(test_io_thread_.task_runner()) {
+MultiprocessMessagePipeTestBase::MultiprocessMessagePipeTestBase() {
 }
 
 MultiprocessMessagePipeTestBase::~MultiprocessMessagePipeTestBase() {
diff --git a/mojo/edk/system/message_pipe_test_utils.h b/mojo/edk/system/message_pipe_test_utils.h
index e067329d..837d534a6 100644
--- a/mojo/edk/system/message_pipe_test_utils.h
+++ b/mojo/edk/system/message_pipe_test_utils.h
@@ -5,12 +5,7 @@
 #ifndef MOJO_EDK_SYSTEM_MESSAGE_PIPE_TEST_UTILS_H_
 #define MOJO_EDK_SYSTEM_MESSAGE_PIPE_TEST_UTILS_H_
 
-#include "base/message_loop/message_loop.h"
-#include "base/test/test_io_thread.h"
-#include "mojo/edk/embedder/simple_platform_support.h"
-#include "mojo/edk/system/test_utils.h"
 #include "mojo/edk/test/multiprocess_test_helper.h"
-#include "mojo/edk/test/scoped_ipc_support.h"
 #include "mojo/public/cpp/system/macros.h"
 
 namespace mojo {
@@ -25,19 +20,12 @@
 class MultiprocessMessagePipeTestBase : public testing::Test {
  public:
   MultiprocessMessagePipeTestBase();
-  MultiprocessMessagePipeTestBase(
-      base::MessageLoop::Type main_message_loop_type);
   ~MultiprocessMessagePipeTestBase() override;
 
  protected:
-  PlatformSupport* platform_support() { return &platform_support_; }
   test::MultiprocessTestHelper* helper() { return &helper_; }
 
  private:
-  SimplePlatformSupport platform_support_;
-  base::MessageLoop message_loop_;
-  base::TestIOThread test_io_thread_;
-  test::ScopedIPCSupport ipc_support_;
   test::MultiprocessTestHelper helper_;
 
   MOJO_DISALLOW_COPY_AND_ASSIGN(MultiprocessMessagePipeTestBase);
diff --git a/mojo/edk/system/message_pipe_unittest.cc b/mojo/edk/system/message_pipe_unittest.cc
index 9283acc..0498b55 100644
--- a/mojo/edk/system/message_pipe_unittest.cc
+++ b/mojo/edk/system/message_pipe_unittest.cc
@@ -16,7 +16,7 @@
                                       MOJO_HANDLE_SIGNAL_PEER_CLOSED;
 static const char kHelloWorld[] = "hello world";
 
-class MessagePipeTest : public test::MojoSystemTest {
+class MessagePipeTest : public testing::Test {
  public:
   MessagePipeTest() {
     CHECK_EQ(MOJO_RESULT_OK, MojoCreateMessagePipe(nullptr, &pipe0_, &pipe1_));
diff --git a/mojo/edk/system/multiprocess_message_pipe_unittest.cc b/mojo/edk/system/multiprocess_message_pipe_unittest.cc
index 4bb3f133..f1afa0e1 100644
--- a/mojo/edk/system/multiprocess_message_pipe_unittest.cc
+++ b/mojo/edk/system/multiprocess_message_pipe_unittest.cc
@@ -16,8 +16,7 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/location.h"
 #include "base/logging.h"
-#include "base/test/test_io_thread.h"
-#include "build/build_config.h"  // TODO(vtl): Remove this.
+#include "build/build_config.h"
 #include "mojo/edk/embedder/embedder.h"
 #include "mojo/edk/embedder/platform_channel_pair.h"
 #include "mojo/edk/embedder/platform_shared_buffer.h"
@@ -44,11 +43,6 @@
 // (which it doesn't reply to). It'll return the number of messages received,
 // not including any "quitquitquit" message, modulo 100.
 MOJO_MULTIPROCESS_TEST_CHILD_MAIN(EchoEcho) {
-  SimplePlatformSupport platform_support;
-  base::MessageLoop message_loop;
-  base::TestIOThread test_io_thread(base::TestIOThread::kAutoStart);
-  test::ScopedIPCSupport ipc_support(test_io_thread.task_runner());
-
   ScopedPlatformHandle client_platform_handle =
       test::MultiprocessTestHelper::client_platform_handle.Pass();
   CHECK(client_platform_handle.is_valid());
@@ -208,11 +202,6 @@
 }
 
 MOJO_MULTIPROCESS_TEST_CHILD_MAIN(CheckSharedBuffer) {
-  SimplePlatformSupport platform_support;
-  base::MessageLoop message_loop;
-  base::TestIOThread test_io_thread(base::TestIOThread::kAutoStart);
-  test::ScopedIPCSupport ipc_support(test_io_thread.task_runner());
-
   ScopedPlatformHandle client_platform_handle =
       test::MultiprocessTestHelper::client_platform_handle.Pass();
   CHECK(client_platform_handle.is_valid());
@@ -382,11 +371,6 @@
 }
 
 MOJO_MULTIPROCESS_TEST_CHILD_MAIN(CheckPlatformHandleFile) {
-  SimplePlatformSupport platform_support;
-  base::MessageLoop message_loop;
-  base::TestIOThread test_io_thread(base::TestIOThread::kAutoStart);
-  test::ScopedIPCSupport ipc_support(test_io_thread.task_runner());
-
   ScopedPlatformHandle client_platform_handle =
       test::MultiprocessTestHelper::client_platform_handle.Pass();
   CHECK(client_platform_handle.is_valid());
@@ -501,11 +485,6 @@
 #endif
 
 MOJO_MULTIPROCESS_TEST_CHILD_MAIN(CheckMessagePipe) {
-  SimplePlatformSupport platform_support;
-  base::MessageLoop message_loop;
-  base::TestIOThread test_io_thread(base::TestIOThread::kAutoStart);
-  test::ScopedIPCSupport ipc_support(test_io_thread.task_runner());
-
   ScopedPlatformHandle client_platform_handle =
       test::MultiprocessTestHelper::client_platform_handle.Pass();
   CHECK(client_platform_handle.is_valid());
@@ -666,11 +645,6 @@
 }
 
 MOJO_MULTIPROCESS_TEST_CHILD_MAIN(DataPipeConsumer) {
-  SimplePlatformSupport platform_support;
-  base::MessageLoop message_loop;
-  base::TestIOThread test_io_thread(base::TestIOThread::kAutoStart);
-  test::ScopedIPCSupport ipc_support(test_io_thread.task_runner());
-
   ScopedPlatformHandle client_platform_handle =
       test::MultiprocessTestHelper::client_platform_handle.Pass();
   CHECK(client_platform_handle.is_valid());
diff --git a/mojo/edk/system/raw_channel_unittest.cc b/mojo/edk/system/raw_channel_unittest.cc
index fdc77d8..c2298d6 100644
--- a/mojo/edk/system/raw_channel_unittest.cc
+++ b/mojo/edk/system/raw_channel_unittest.cc
@@ -23,7 +23,9 @@
 #include "base/synchronization/waitable_event.h"
 #include "base/test/test_io_thread.h"
 #include "base/threading/simple_thread.h"
-#include "build/build_config.h"  // TODO(vtl): Remove this.
+#include "build/build_config.h"
+#include "mojo/edk/embedder/embedder.h"
+#include "mojo/edk/embedder/embedder_internal.h"
 #include "mojo/edk/embedder/platform_channel_pair.h"
 #include "mojo/edk/embedder/platform_handle.h"
 #include "mojo/edk/embedder/scoped_platform_handle.h"
@@ -73,7 +75,7 @@
 
 // -----------------------------------------------------------------------------
 
-class RawChannelTest : public test::MojoSystemTest {
+class RawChannelTest : public testing::Test {
  public:
   RawChannelTest() {}
   ~RawChannelTest() override {}
@@ -89,6 +91,14 @@
     handles[1].reset();
   }
 
+  void FlushIOThread() {
+    base::WaitableEvent event(false, false);
+    internal::g_io_thread_task_runner->PostTask(
+        FROM_HERE,
+        base::Bind(&base::WaitableEvent::Signal, base::Unretained(&event)));
+    event.Wait();
+  }
+
  protected:
   ScopedPlatformHandle handles[2];
 
@@ -189,7 +199,7 @@
   WriteOnlyRawChannelDelegate delegate;
   RawChannel* rc = RawChannel::Create(handles[0].Pass());
   TestMessageReaderAndChecker checker(handles[1].get());
-  test_io_thread()->PostTaskAndWait(
+  internal::g_io_thread_task_runner->PostTask(
       FROM_HERE,
       base::Bind(&InitOnIOThread, rc, base::Unretained(&delegate)));
 
@@ -205,7 +215,7 @@
   for (uint32_t size = 1; size < 5 * 1000 * 1000; size += size / 2 + 1)
     EXPECT_TRUE(checker.ReadAndCheckNextMessage(size)) << size;
 
-  test_io_thread()->PostTaskAndWait(
+  internal::g_io_thread_task_runner->PostTask(
       FROM_HERE, base::Bind(&RawChannel::Shutdown, base::Unretained(rc)));
 }
 
@@ -274,7 +284,7 @@
 TEST_F(RawChannelTest, OnReadMessage) {
   ReadCheckerRawChannelDelegate delegate;
   RawChannel* rc = RawChannel::Create(handles[0].Pass());
-  test_io_thread()->PostTaskAndWait(
+  internal::g_io_thread_task_runner->PostTask(
       FROM_HERE,
       base::Bind(&InitOnIOThread, rc, base::Unretained(&delegate)));
 
@@ -297,7 +307,7 @@
     EXPECT_TRUE(WriteTestMessageToHandle(handles[1].get(), size));
   delegate.Wait();
 
-  test_io_thread()->PostTaskAndWait(
+  internal::g_io_thread_task_runner->PostTask(
       FROM_HERE, base::Bind(&RawChannel::Shutdown, base::Unretained(rc)));
 }
 
@@ -371,7 +381,7 @@
 
   WriteOnlyRawChannelDelegate writer_delegate;
   RawChannel* writer_rc = RawChannel::Create(handles[0].Pass());
-  test_io_thread()->PostTaskAndWait(
+  internal::g_io_thread_task_runner->PostTask(
     FROM_HERE,
     base::Bind(&InitOnIOThread, writer_rc,
                base::Unretained(&writer_delegate)));
@@ -379,7 +389,7 @@
   ReadCountdownRawChannelDelegate reader_delegate(kNumWriterThreads *
                                                   kNumWriteMessagesPerThread);
   RawChannel* reader_rc = RawChannel::Create(handles[1].Pass());
-  test_io_thread()->PostTaskAndWait(
+  internal::g_io_thread_task_runner->PostTask(
     FROM_HERE,
     base::Bind(&InitOnIOThread, reader_rc,
                base::Unretained(&reader_delegate)));
@@ -401,11 +411,11 @@
   // Wait for reading to finish.
   reader_delegate.Wait();
 
-  test_io_thread()->PostTaskAndWait(
+  internal::g_io_thread_task_runner->PostTask(
       FROM_HERE,
       base::Bind(&RawChannel::Shutdown, base::Unretained(reader_rc)));
 
-  test_io_thread()->PostTaskAndWait(
+  internal::g_io_thread_task_runner->PostTask(
       FROM_HERE,
       base::Bind(&RawChannel::Shutdown, base::Unretained(writer_rc)));
 }
@@ -470,9 +480,10 @@
 TEST_F(RawChannelTest, OnError) {
   ErrorRecordingRawChannelDelegate delegate(0, true, true);
   RawChannel* rc = RawChannel::Create(handles[0].Pass());
-  test_io_thread()->PostTaskAndWait(
+  internal::g_io_thread_task_runner->PostTask(
       FROM_HERE,
       base::Bind(&InitOnIOThread, rc, base::Unretained(&delegate)));
+  FlushIOThread();
 
   // Close the handle of the other end, which should make writing fail.
   handles[1].reset();
@@ -491,7 +502,7 @@
   // notification. (If we actually get another one, |OnError()| crashes.)
   test::Sleep(test::DeadlineFromMilliseconds(20));
 
-  test_io_thread()->PostTaskAndWait(
+  internal::g_io_thread_task_runner->PostTask(
       FROM_HERE, base::Bind(&RawChannel::Shutdown, base::Unretained(rc)));
 }
 
@@ -513,9 +524,10 @@
   // messages that were written.
   ErrorRecordingRawChannelDelegate delegate(kMessageCount, true, true);
   RawChannel* rc = RawChannel::Create(handles[0].Pass());
-  test_io_thread()->PostTaskAndWait(
+  internal::g_io_thread_task_runner->PostTask(
       FROM_HERE,
       base::Bind(&InitOnIOThread, rc, base::Unretained(&delegate)));
+  FlushIOThread();
 
   EXPECT_FALSE(rc->WriteMessage(MakeTestMessage(1)));
 
@@ -528,7 +540,7 @@
   // And then we should get a read error.
   delegate.WaitForReadError();
 
-  test_io_thread()->PostTaskAndWait(
+  internal::g_io_thread_task_runner->PostTask(
       FROM_HERE, base::Bind(&RawChannel::Shutdown, base::Unretained(rc)));
 }
 
@@ -597,13 +609,13 @@
 
   WriteOnlyRawChannelDelegate write_delegate;
   RawChannel* rc_write = RawChannel::Create(handles[0].Pass());
-  test_io_thread()->PostTaskAndWait(
+  internal::g_io_thread_task_runner->PostTask(
       FROM_HERE,
       base::Bind(&InitOnIOThread, rc_write, base::Unretained(&write_delegate)));
 
   ReadPlatformHandlesCheckerRawChannelDelegate read_delegate;
   RawChannel* rc_read = RawChannel::Create(handles[1].Pass());
-  test_io_thread()->PostTaskAndWait(
+  internal::g_io_thread_task_runner->PostTask(
       FROM_HERE,
       base::Bind(&InitOnIOThread, rc_read, base::Unretained(&read_delegate)));
 
@@ -633,10 +645,10 @@
 
   read_delegate.Wait();
 
-  test_io_thread()->PostTaskAndWait(
+  internal::g_io_thread_task_runner->PostTask(
       FROM_HERE,
       base::Bind(&RawChannel::Shutdown, base::Unretained(rc_read)));
-  test_io_thread()->PostTaskAndWait(
+  internal::g_io_thread_task_runner->PostTask(
       FROM_HERE,
       base::Bind(&RawChannel::Shutdown, base::Unretained(rc_write)));
 }
diff --git a/mojo/edk/system/routed_raw_channel.cc b/mojo/edk/system/routed_raw_channel.cc
new file mode 100644
index 0000000..e2fe67e
--- /dev/null
+++ b/mojo/edk/system/routed_raw_channel.cc
@@ -0,0 +1,168 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "mojo/edk/system/routed_raw_channel.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "mojo/edk/embedder/embedder_internal.h"
+#include "mojo/edk/system/message_pipe_dispatcher.h"
+
+namespace mojo {
+namespace edk {
+
+namespace {
+const uint64_t kInternalRoutingId = 0;
+
+// These are messages sent over our internal routing id above, meant for the
+// other side's RoutedRawChannel to dispatch.
+enum InternalMessages {
+  ROUTE_CLOSED = 0,
+};
+}
+
+RoutedRawChannel::PendingMessage::PendingMessage() {

+}

+

+RoutedRawChannel::PendingMessage::~PendingMessage() {

+}
+
+RoutedRawChannel::RoutedRawChannel(
+    ScopedPlatformHandle handle,
+    const base::Callback<void(RoutedRawChannel*)>& destruct_callback)
+    : channel_(RawChannel::Create(handle.Pass())),
+      destruct_callback_(destruct_callback) {
+  internal::g_io_thread_task_runner->PostTask(
+      FROM_HERE,
+      base::Bind(&RawChannel::Init, base::Unretained(channel_), this));
+  internal::g_io_thread_task_runner->PostTask(
+      FROM_HERE,
+      base::Bind(&RawChannel::EnsureLazyInitialized,
+                  base::Unretained(channel_)));
+}
+
+void RoutedRawChannel::AddRoute(uint64_t pipe_id, MessagePipeDispatcher* pipe) {
+  CHECK_NE(pipe_id, kInternalRoutingId) << kInternalRoutingId << " is reserved";
+  base::AutoLock auto_lock(lock_);
+  CHECK(routes_.find(pipe_id) == routes_.end());
+  routes_[pipe_id] = pipe;
+
+  for (size_t i = 0; i < pending_messages_.size();) {
+    MessageInTransit::View view(pending_messages_[i]->message.size(),
+                                &pending_messages_[i]->message[0]);
+    if (view.route_id() == pipe_id) {
+      pipe->OnReadMessage(view, pending_messages_[i]->handles.Pass());
+      pending_messages_.erase(pending_messages_.begin() + i);
+    } else {
+      ++i;
+    }
+  }
+
+  if (close_routes_.find(pipe_id) != close_routes_.end())
+    pipe->OnError(ERROR_READ_SHUTDOWN);
+}
+
+void RoutedRawChannel::RemoveRoute(uint64_t pipe_id,
+                                   MessagePipeDispatcher* pipe) {
+  base::AutoLock auto_lock(lock_);
+  CHECK(routes_.find(pipe_id) != routes_.end());
+  CHECK_EQ(routes_[pipe_id], pipe);
+  routes_.erase(pipe_id);
+
+  // Only send a message to the other side to close the route if we hadn't
+  // received a close route message. Otherwise they would keep going back and
+  // forth.
+  if (close_routes_.find(pipe_id) != close_routes_.end()) {
+    close_routes_.erase(pipe_id);
+  } else if (channel_) {
+    // Default route id of 0 to reach the other side's RoutedRawChannel.
+    char message_data[sizeof(char) + sizeof(uint64_t)];
+    message_data[0] = ROUTE_CLOSED;
+    memcpy(&message_data[1], &pipe_id, sizeof(uint64_t));
+    scoped_ptr<MessageInTransit> message(new MessageInTransit(
+        MessageInTransit::Type::MESSAGE, arraysize(message_data),
+          message_data));
+    message->set_route_id(kInternalRoutingId);
+    channel_->WriteMessage(message.Pass());
+  }
+
+  if (!channel_ && routes_.empty()) {
+    // PostTask to avoid reentrancy since the broker might be calling us.
+    base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
+  }
+}
+
+RoutedRawChannel::~RoutedRawChannel() {
+  destruct_callback_.Run(this);
+}
+
+void RoutedRawChannel::OnReadMessage(
+    const MessageInTransit::View& message_view,
+    ScopedPlatformHandleVectorPtr platform_handles) {
+  DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread());
+  // Note: normally, when a message arrives here we should find a corresponding
+  // entry for the MessagePipeDispatcher with the given route_id. However it is
+  // possible that they just connected, and due to race conditions one side has
+  // connected and sent a message (and even closed) before the other side had a
+  // chance to register with this RoutedRawChannel. In that case, we must buffer
+  // all messages.
+  base::AutoLock auto_lock(lock_);
+  uint64_t route_id = message_view.route_id();
+  if (route_id == kInternalRoutingId) {
+    if (message_view.num_bytes() != sizeof(char) + sizeof(uint64_t)) {
+      NOTREACHED() << "Invalid internal message in RoutedRawChannel.";
+      return;
+    }
+    const char* bytes = static_cast<const char*>(message_view.bytes());
+    if (bytes[0] != ROUTE_CLOSED) {
+      NOTREACHED() << "Unknown internal message in RoutedRawChannel.";
+      return;
+    }
+    uint64_t closed_route = *reinterpret_cast<const uint64_t*>(&bytes[1]);
+    if (close_routes_.find(closed_route) != close_routes_.end()) {
+      NOTREACHED() << "Should only receive one ROUTE_CLOSED per route.";
+      return;
+    }
+    close_routes_.insert(closed_route);
+    if (routes_.find(closed_route) == routes_.end())
+      return;  // This side hasn't connected yet.
+
+    routes_[closed_route]->OnError(ERROR_READ_SHUTDOWN);
+    return;
+  }
+
+  if (routes_.find(route_id) != routes_.end()) {
+    routes_[route_id]->OnReadMessage(message_view, platform_handles.Pass());
+  } else {
+    scoped_ptr<PendingMessage> msg(new PendingMessage);
+    msg->message.resize(message_view.total_size());
+    memcpy(&msg->message[0], message_view.main_buffer(),
+           message_view.total_size());
+    msg->handles = platform_handles.Pass();
+    pending_messages_.push_back(msg.Pass());
+  }
+}
+
+void RoutedRawChannel::OnError(Error error) {
+  DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread());
+  bool destruct = false;
+  {
+    base::AutoLock auto_lock(lock_);
+
+    channel_->Shutdown();
+    channel_ = nullptr;
+    if (routes_.empty()) {
+      destruct = true;
+    } else {
+      for (auto it = routes_.begin(); it != routes_.end(); ++it)
+        it->second->OnError(error);
+    }
+  }
+
+  if (destruct)
+    delete this;
+}
+
+}  // namespace edk
+}  // namespace mojo
diff --git a/mojo/edk/system/routed_raw_channel.h b/mojo/edk/system/routed_raw_channel.h
new file mode 100644
index 0000000..c27b86c
--- /dev/null
+++ b/mojo/edk/system/routed_raw_channel.h
@@ -0,0 +1,78 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_EDK_SYSTEM_ROUTED_RAW_CHANNEL_H_
+#define MOJO_EDK_SYSTEM_ROUTED_RAW_CHANNEL_H_
+

+#include "base/callback.h"

+#include "base/containers/hash_tables.h"
+#include "base/macros.h"
+#include "base/synchronization/lock.h"
+#include "mojo/edk/embedder/platform_handle_vector.h"
+#include "mojo/edk/embedder/scoped_platform_handle.h"
+#include "mojo/edk/system/broker.h"
+#include "mojo/edk/system/raw_channel.h"
+#include "mojo/edk/system/system_impl_export.h"
+
+namespace mojo {
+namespace edk {
+class RawChannel;
+
+// This class wraps a RawChannel and adds routing on top of it.
+// Non-transferable MessagePipeDispatchers call here, indirectly through the
+// Broker interface, to associate with their pipe_id.
+class RoutedRawChannel : public RawChannel::Delegate {
+ public:
+  RoutedRawChannel(
+      ScopedPlatformHandle handle,
+      const base::Callback<void(RoutedRawChannel*)>& destruct_callback);
+
+  // Connect the given |pipe| with the pipe_id route. Only non-transferable
+  // message pipes can call this, and they can only call it once.
+  void AddRoute(uint64_t pipe_id, MessagePipeDispatcher* pipe);
+
+  // Called when the MessagePipeDispatcher is going away.
+  void RemoveRoute(uint64_t pipe_id, MessagePipeDispatcher* pipe);
+
+  RawChannel* channel() { return channel_; }
+
+ private:
+  friend class base::DeleteHelper<RoutedRawChannel>;
+  ~RoutedRawChannel() override;
+
+  // RawChannel::Delegate implementation:
+  void OnReadMessage(
+        const MessageInTransit::View& message_view,
+        ScopedPlatformHandleVectorPtr platform_handles) override;
+  void OnError(Error error) override;
+
+  RawChannel* channel_;
+
+  base::Lock lock_;  // Guards access to below.
+  base::hash_map<uint64_t, MessagePipeDispatcher*> routes_;
+
+  // If we got messages before the route was added (due to race conditions
+  // between different channels), this is used to buffer them.
+  struct PendingMessage {
+    PendingMessage();

+    ~PendingMessage();
+    std::vector<char> message;
+    ScopedPlatformHandleVectorPtr handles;
+  };
+  std::vector<scoped_ptr<PendingMessage>> pending_messages_;
+
+  // If we got a ROUTE_CLOSED message for a route before it registered with us,
+  // we need to hold on to this information so that we can tell it that the
+  // connetion is closed when it does connect.
+  base::hash_set<uint64_t> close_routes_;
+
+  base::Callback<void(RoutedRawChannel*)> destruct_callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(RoutedRawChannel);
+};
+
+}  // namespace edk
+}  // namespace mojo
+
+#endif  // MOJO_EDK_SYSTEM_ROUTED_RAW_CHANNEL_H_
diff --git a/mojo/edk/system/run_all_unittests.cc b/mojo/edk/system/run_all_unittests.cc
index b68fd83..4421aa6 100644
--- a/mojo/edk/system/run_all_unittests.cc
+++ b/mojo/edk/system/run_all_unittests.cc
@@ -5,9 +5,11 @@
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/test/launcher/unit_test_launcher.h"
+#include "base/test/test_io_thread.h"
 #include "base/test/test_suite.h"
 #include "mojo/edk/embedder/embedder.h"
 #include "mojo/edk/test/multiprocess_test_helper.h"
+#include "mojo/edk/test/scoped_ipc_support.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 int main(int argc, char** argv) {
@@ -31,6 +33,12 @@
 
   mojo::edk::Init();
 
+  base::TestIOThread test_io_thread(base::TestIOThread::kAutoStart);
+  // Leak this because its destructor calls mojo::edk::ShutdownIPCSupport which
+  // really does nothing in the new EDK but does depend on the current message
+  // loop, which is destructed inside base::LaunchUnitTests.
+  new mojo::edk::test::ScopedIPCSupport(test_io_thread.task_runner());
+
   return base::LaunchUnitTests(
       argc, argv,
       base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite)));
diff --git a/mojo/edk/system/test_utils.cc b/mojo/edk/system/test_utils.cc
index 49e346b..0549f86 100644
--- a/mojo/edk/system/test_utils.cc
+++ b/mojo/edk/system/test_utils.cc
@@ -69,15 +69,6 @@
   return static_cast<MojoDeadline>(result);
 }
 
-
-MojoSystemTest::MojoSystemTest()
-    : test_io_thread_(base::TestIOThread::kAutoStart),
-      ipc_support_(test_io_thread_.task_runner()) {
-}
-
-MojoSystemTest::~MojoSystemTest() {
-}
-
 }  // namespace test
 }  // namespace edk
 }  // namespace mojo
diff --git a/mojo/edk/system/test_utils.h b/mojo/edk/system/test_utils.h
index cf244b3..46398d9 100644
--- a/mojo/edk/system/test_utils.h
+++ b/mojo/edk/system/test_utils.h
@@ -5,9 +5,7 @@
 #ifndef MOJO_EDK_SYSTEM_TEST_UTILS_H_
 #define MOJO_EDK_SYSTEM_TEST_UTILS_H_
 
-#include "base/test/test_io_thread.h"
 #include "base/time/time.h"
-#include "mojo/edk/test/scoped_ipc_support.h"
 #include "mojo/public/c/system/types.h"
 #include "mojo/public/cpp/system/macros.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -54,23 +52,6 @@
   MOJO_DISALLOW_COPY_AND_ASSIGN(Stopwatch);
 };
 
-// A base class which initializes and shuts down the necessary objects so that
-// Mojo system calls can be made.
-class MojoSystemTest : public testing::Test {
- public:
-  MojoSystemTest();
-  ~MojoSystemTest() override;
-
-  base::TestIOThread* test_io_thread() { return &test_io_thread_; }
-
- private:
-  base::MessageLoop message_loop_;
-  base::TestIOThread test_io_thread_;
-  test::ScopedIPCSupport ipc_support_;
-
-  MOJO_DISALLOW_COPY_AND_ASSIGN(MojoSystemTest);
-};
-
 }  // namespace test
 }  // namespace edk
 }  // namespace mojo
diff --git a/mojo/edk/test/BUILD.gn b/mojo/edk/test/BUILD.gn
index 9a52c99..a77373b 100644
--- a/mojo/edk/test/BUILD.gn
+++ b/mojo/edk/test/BUILD.gn
@@ -54,6 +54,7 @@
     ":test_support_impl",
     "//base",
     "//base/test:test_support",
+    "//mojo/edk/test:test_support",
     "//mojo/public/c/test_support",
 
     # TODO(use_chrome_edk): temporary since the Mojo wrapper primitives are
diff --git a/mojo/edk/test/multiprocess_test_helper_unittest.cc b/mojo/edk/test/multiprocess_test_helper_unittest.cc
index b3ae11d..7e99fb27a 100644
--- a/mojo/edk/test/multiprocess_test_helper_unittest.cc
+++ b/mojo/edk/test/multiprocess_test_helper_unittest.cc
@@ -7,6 +7,7 @@
 #include "base/logging.h"
 #include "build/build_config.h"
 #include "mojo/edk/embedder/scoped_platform_handle.h"
+#include "mojo/edk/system/test_utils.h"
 #include "mojo/edk/test/test_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/mojo/edk/test/run_all_perftests.cc b/mojo/edk/test/run_all_perftests.cc
index d700bc3..c277a38 100644
--- a/mojo/edk/test/run_all_perftests.cc
+++ b/mojo/edk/test/run_all_perftests.cc
@@ -4,17 +4,32 @@
 
 #include "base/command_line.h"
 #include "base/test/perf_test_suite.h"
+#include "base/test/test_io_thread.h"
 #include "mojo/edk/embedder/embedder.h"
+#include "mojo/edk/test/multiprocess_test_helper.h"
+#include "mojo/edk/test/scoped_ipc_support.h"
 #include "mojo/edk/test/test_support_impl.h"
 #include "mojo/public/tests/test_support_private.h"
 
 int main(int argc, char** argv) {
-  mojo::edk::Init();
-  mojo::test::TestSupport::Init(new mojo::edk::test::TestSupportImpl());
+  base::PerfTestSuite test(argc, argv);
+
+  // Must be run before mojo::edk::Init.
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          mojo::edk::test::kBrokerHandleSwitch)) {
+    mojo::edk::PreInitializeChildProcess();
+  }
 
   // TODO(use_chrome_edk): temporary to force new EDK.
-  base::PerfTestSuite test(argc, argv);
   base::CommandLine::ForCurrentProcess()->AppendSwitch("--use-new-edk");
 
+  mojo::edk::Init();
+  base::TestIOThread test_io_thread(base::TestIOThread::kAutoStart);
+  // Leak this because its destructor calls mojo::edk::ShutdownIPCSupport which
+  // really does nothing in the new EDK but does depend on the current message
+  // loop, which is destructed inside base::LaunchUnitTests.
+  new mojo::edk::test::ScopedIPCSupport(test_io_thread.task_runner());
+  mojo::test::TestSupport::Init(new mojo::edk::test::TestSupportImpl());
+
   return test.Run();
 }
diff --git a/mojo/mojo_edk.gyp b/mojo/mojo_edk.gyp
index 07edb34..a8cbc82 100644
--- a/mojo/mojo_edk.gyp
+++ b/mojo/mojo_edk.gyp
@@ -105,6 +105,8 @@
         'edk/system/raw_channel.h',
         'edk/system/raw_channel_posix.cc',
         'edk/system/raw_channel_win.cc',
+        'edk/system/routed_raw_channel.cc',
+        'edk/system/routed_raw_channel.h',
         'edk/system/shared_buffer_dispatcher.cc',
         'edk/system/shared_buffer_dispatcher.h',
         'edk/system/simple_dispatcher.cc',
diff --git a/mojo/public/c/system/message_pipe.h b/mojo/public/c/system/message_pipe.h
index d42c3fc..4f5d4c78 100644
--- a/mojo/public/c/system/message_pipe.h
+++ b/mojo/public/c/system/message_pipe.h
@@ -18,17 +18,26 @@
 //   |uint32_t struct_size|: Set to the size of the
 //       |MojoCreateMessagePipeOptions| struct. (Used to allow for future
 //       extensions.)
-//   |MojoCreateMessagePipeOptionsFlags flags|: Reserved for future use.
+//   |MojoCreateMessagePipeOptionsFlags flags|: Used to specify different modes
+//       of operation.
 //       |MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE|: No flags; default mode.
+//       |MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_TRANSFERABLE|: The message pipe
+//           can be sent over another pipe after it's been read, written or
+//           waited. This mode makes message pipes use more resources (one OS
+//           pipe each), so only specify if this functionality is required.
 
 typedef uint32_t MojoCreateMessagePipeOptionsFlags;
 
 #ifdef __cplusplus
 const MojoCreateMessagePipeOptionsFlags
     MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE = 0;
+const MojoCreateMessagePipeOptionsFlags
+    MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_TRANSFERABLE = 1;
 #else
 #define MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE \
   ((MojoCreateMessagePipeOptionsFlags)0)
+#define MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_TRANSFERABLE \
+  ((MojoCreateMessagePipeOptionsFlags)1)
 #endif
 
 MOJO_STATIC_ASSERT(MOJO_ALIGNOF(int64_t) == 8, "int64_t has weird alignment");
diff --git a/mojo/runner/host/child_process.cc b/mojo/runner/host/child_process.cc
index 0dd6d84..a9f07bb 100644
--- a/mojo/runner/host/child_process.cc
+++ b/mojo/runner/host/child_process.cc
@@ -124,7 +124,9 @@
     // create a message pipe which requires this code to be run first.
     embedder::InitIPCSupport(embedder::ProcessType::NONE, this, io_runner_,
                              embedder::ScopedPlatformHandle());
+  }
 
+  void StartControllerThread() {
     // Create and start our controller thread.
     base::Thread::Options controller_thread_options;
     controller_thread_options.message_loop_type =
@@ -305,7 +307,6 @@
   ScopedMessagePipeHandle host_message_pipe(embedder::CreateChannel(
       platform_channel.Pass(), base::Bind(&DidCreateChannel), io_task_runner));
 
-#if defined(OS_WIN)
   if (base::CommandLine::ForCurrentProcess()->HasSwitch("use-new-edk")) {
     // When using the new Mojo EDK, each message pipe is backed by a platform
     // handle. The one platform handle that comes on the command line is used
@@ -339,9 +340,6 @@
 #endif
             )));
   }
-#else
-  // TODO(jam): hook up on POSIX
-#endif
 
   return host_message_pipe.Pass();
 }
@@ -385,6 +383,7 @@
   app_context.Init();
   ScopedMessagePipeHandle host_message_pipe = InitializeHostMessagePipe(
       platform_channel.Pass(), app_context.io_runner());
+  app_context.StartControllerThread();
   Blocker blocker;
   app_context.controller_runner()->PostTask(
       FROM_HERE,
diff --git a/mojo/runner/host/child_process_host.cc b/mojo/runner/host/child_process_host.cc
index cb106933..770afb9 100644
--- a/mojo/runner/host/child_process_host.cc
+++ b/mojo/runner/host/child_process_host.cc
@@ -39,11 +39,8 @@
       channel_info_(nullptr),
       start_child_process_event_(false, false),
       weak_factory_(this) {
-#if defined(OS_WIN)
-  // TODO(jam): enable on POSIX
   if (base::CommandLine::ForCurrentProcess()->HasSwitch("use-new-edk"))
     serializer_platform_channel_pair_.reset(new edk::PlatformChannelPair(true));
-#endif
 
   child_message_pipe_ = embedder::CreateChannel(
       platform_channel_pair_.PassServerHandle(),
@@ -71,7 +68,6 @@
   DCHECK(!child_process_.IsValid());
   DCHECK(child_message_pipe_.is_valid());
 
-#if defined(OS_WIN)
   if (base::CommandLine::ForCurrentProcess()->HasSwitch("use-new-edk")) {
     std::string client_handle_as_string =
         serializer_platform_channel_pair_
@@ -86,7 +82,6 @@
         MOJO_WRITE_MESSAGE_FLAG_NONE);
     DCHECK_EQ(rv, MOJO_RESULT_OK);
   }
-#endif
 
   controller_.Bind(
       InterfacePtrInfo<ChildController>(child_message_pipe_.Pass(), 0u));
@@ -206,7 +201,6 @@
 
   if (child_process_.IsValid()) {
     platform_channel_pair_.ChildProcessLaunched();
-#if defined(OS_WIN)
     if (serializer_platform_channel_pair_.get()) {
       serializer_platform_channel_pair_->ChildProcessLaunched();
       mojo::embedder::ChildProcessLaunched(
@@ -220,7 +214,6 @@
 #endif
             )));
     }
-#endif
   }
   start_child_process_event_.Signal();
 }
diff --git a/net/base/layered_network_delegate.cc b/net/base/layered_network_delegate.cc
index e64019c0..265fa426 100644
--- a/net/base/layered_network_delegate.cc
+++ b/net/base/layered_network_delegate.cc
@@ -256,9 +256,16 @@
   return nested_network_delegate_->AreExperimentalCookieFeaturesEnabled();
 }
 
+bool LayeredNetworkDelegate::OnAreStrictSecureCookiesEnabled() const {
+  OnAreStrictSecureCookiesEnabledInternal();
+  return nested_network_delegate_->AreStrictSecureCookiesEnabled();
+}
+
 void LayeredNetworkDelegate::OnAreExperimentalCookieFeaturesEnabledInternal()
     const {}
 
+void LayeredNetworkDelegate::OnAreStrictSecureCookiesEnabledInternal() const {}
+
 bool LayeredNetworkDelegate::
     OnCancelURLRequestWithPolicyViolatingReferrerHeader(
         const URLRequest& request,
diff --git a/net/base/layered_network_delegate.h b/net/base/layered_network_delegate.h
index 9446043..9f0928e7 100644
--- a/net/base/layered_network_delegate.h
+++ b/net/base/layered_network_delegate.h
@@ -84,6 +84,7 @@
   bool OnCanEnablePrivacyMode(const GURL& url,
                               const GURL& first_party_for_cookies) const final;
   bool OnAreExperimentalCookieFeaturesEnabled() const final;
+  bool OnAreStrictSecureCookiesEnabled() const final;
   bool OnCancelURLRequestWithPolicyViolatingReferrerHeader(
       const URLRequest& request,
       const GURL& target_url,
@@ -158,6 +159,7 @@
       const GURL& first_party_for_cookies) const;
 
   virtual void OnAreExperimentalCookieFeaturesEnabledInternal() const;
+  virtual void OnAreStrictSecureCookiesEnabledInternal() const;
 
   virtual void OnCancelURLRequestWithPolicyViolatingReferrerHeaderInternal(
       const URLRequest& request,
diff --git a/net/base/network_delegate.cc b/net/base/network_delegate.cc
index 200905ec..ff4ee88f 100644
--- a/net/base/network_delegate.cc
+++ b/net/base/network_delegate.cc
@@ -172,6 +172,10 @@
   return OnAreExperimentalCookieFeaturesEnabled();
 }
 
+bool NetworkDelegate::AreStrictSecureCookiesEnabled() const {
+  return OnAreStrictSecureCookiesEnabled();
+}
+
 bool NetworkDelegate::CancelURLRequestWithPolicyViolatingReferrerHeader(
     const URLRequest& request,
     const GURL& target_url,
diff --git a/net/base/network_delegate.h b/net/base/network_delegate.h
index 0636f4e..979d3ec 100644
--- a/net/base/network_delegate.h
+++ b/net/base/network_delegate.h
@@ -111,6 +111,8 @@
   // secure scheme. https://crbug.com/459154, https://crbug.com/541511,
   // https://crbug.com/546820
   bool AreExperimentalCookieFeaturesEnabled() const;
+  // TODO(jww): Remove this once we ship strict secure cookies.
+  bool AreStrictSecureCookiesEnabled() const;
 
   bool CancelURLRequestWithPolicyViolatingReferrerHeader(
       const URLRequest& request,
@@ -295,6 +297,12 @@
   // https://crbug.com/546820
   virtual bool OnAreExperimentalCookieFeaturesEnabled() const = 0;
 
+  // Returns true if the embedder has enabled experimental features or
+  // specifically strict secure cookies, and false otherwise.
+  //
+  // TODO(jww): Remove this once we ship strict secure cookies.
+  virtual bool OnAreStrictSecureCookiesEnabled() const = 0;
+
   // Called when the |referrer_url| for requesting |target_url| during handling
   // of the |request| is does not comply with the referrer policy (e.g. a
   // secure referrer for an insecure initial target).
diff --git a/net/base/network_delegate_impl.cc b/net/base/network_delegate_impl.cc
index 7548f616..5e94543b 100644
--- a/net/base/network_delegate_impl.cc
+++ b/net/base/network_delegate_impl.cc
@@ -106,6 +106,10 @@
   return false;
 }
 
+bool NetworkDelegateImpl::OnAreStrictSecureCookiesEnabled() const {
+  return false;
+}
+
 bool NetworkDelegateImpl::OnCancelURLRequestWithPolicyViolatingReferrerHeader(
     const URLRequest& request,
     const GURL& target_url,
diff --git a/net/base/network_delegate_impl.h b/net/base/network_delegate_impl.h
index 7e9db65..8a0b007f 100644
--- a/net/base/network_delegate_impl.h
+++ b/net/base/network_delegate_impl.h
@@ -205,6 +205,7 @@
   // first-party cookies and cookie prefixes. https://crbug.com/459154,
   // https://crbug.com/541511
   bool OnAreExperimentalCookieFeaturesEnabled() const override;
+  bool OnAreStrictSecureCookiesEnabled() const override;
 
   // Called when the |referrer_url| for requesting |target_url| during handling
   // of the |request| is does not comply with the referrer policy (e.g. a
diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc
index 5c4ddd1..bf9f63b 100644
--- a/net/url_request/url_request_http_job.cc
+++ b/net/url_request/url_request_http_job.cc
@@ -746,11 +746,17 @@
     CookieOptions options;
     options.set_include_httponly();
     options.set_server_time(response_date_);
+
     if (network_delegate() &&
         network_delegate()->AreExperimentalCookieFeaturesEnabled()) {
       options.set_enforce_prefixes();
     }
 
+    if (network_delegate() &&
+        network_delegate()->AreStrictSecureCookiesEnabled()) {
+      options.set_enforce_strict_secure();
+    }
+
     CookieStore::SetCookiesCallback callback(base::Bind(
         &URLRequestHttpJob::OnCookieSaved, weak_factory_.GetWeakPtr(),
         save_next_cookie_running, callback_pending));
diff --git a/net/url_request/url_request_test_util.cc b/net/url_request/url_request_test_util.cc
index 31450c1..3bd6ece3 100644
--- a/net/url_request/url_request_test_util.cc
+++ b/net/url_request/url_request_test_util.cc
@@ -626,6 +626,10 @@
   return experimental_cookie_features_enabled_;
 }
 
+bool TestNetworkDelegate::OnAreStrictSecureCookiesEnabled() const {
+  return experimental_cookie_features_enabled_;
+}
+
 bool TestNetworkDelegate::OnCancelURLRequestWithPolicyViolatingReferrerHeader(
     const URLRequest& request,
     const GURL& target_url,
diff --git a/net/url_request/url_request_test_util.h b/net/url_request/url_request_test_util.h
index 07728cbd..3369c881 100644
--- a/net/url_request/url_request_test_util.h
+++ b/net/url_request/url_request_test_util.h
@@ -340,6 +340,7 @@
   bool OnCanAccessFile(const URLRequest& request,
                        const base::FilePath& path) const override;
   bool OnAreExperimentalCookieFeaturesEnabled() const override;
+  bool OnAreStrictSecureCookiesEnabled() const override;
   bool OnCancelURLRequestWithPolicyViolatingReferrerHeader(
       const URLRequest& request,
       const GURL& target_url,
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index 939a6c61..6567c6d 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -669,6 +669,7 @@
 class TestExperimentalFeaturesNetworkDelegate : public TestNetworkDelegate {
  public:
   bool OnAreExperimentalCookieFeaturesEnabled() const override { return true; }
+  bool OnAreStrictSecureCookiesEnabled() const override { return true; }
 };
 
 }  // namespace
@@ -2725,8 +2726,8 @@
     req->Start();
     base::RunLoop().Run();
 
-    EXPECT_TRUE(d.data_received().find("FirstPartyCookieToSet=1") !=
-                std::string::npos);
+    EXPECT_NE(d.data_received().find("FirstPartyCookieToSet=1"),
+              std::string::npos);
     EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
     EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
   }
@@ -2769,8 +2770,8 @@
     req->Start();
     base::RunLoop().Run();
 
-    EXPECT_TRUE(d.data_received().find("__Secure-nonsecure-origin=1") ==
-                std::string::npos);
+    EXPECT_EQ(d.data_received().find("__Secure-nonsecure-origin=1"),
+              std::string::npos);
     EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
     EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
   }
@@ -2825,11 +2826,10 @@
     req->Start();
     base::RunLoop().Run();
 
-    EXPECT_TRUE(d.data_received().find("__Secure-secure-not-experimental=1") !=
-                std::string::npos);
-    EXPECT_TRUE(
-        d.data_received().find("__Secure-nonsecure-not-experimental=1") !=
-        std::string::npos);
+    EXPECT_NE(d.data_received().find("__Secure-secure-not-experimental=1"),
+              std::string::npos);
+    EXPECT_NE(d.data_received().find("__Secure-nonsecure-not-experimental=1"),
+              std::string::npos);
     EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
     EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
   }
@@ -2867,7 +2867,7 @@
     req->Start();
     base::RunLoop().Run();
 
-    EXPECT_TRUE(d.data_received().find("__Secure-foo=1") == std::string::npos);
+    EXPECT_EQ(d.data_received().find("__Secure-foo=1"), std::string::npos);
     EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
     EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
   }
@@ -2905,7 +2905,89 @@
     req->Start();
     base::RunLoop().Run();
 
-    EXPECT_TRUE(d.data_received().find("__Secure-bar=1") != std::string::npos);
+    EXPECT_NE(d.data_received().find("__Secure-bar=1"), std::string::npos);
+    EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
+    EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
+  }
+}
+
+// Tests that secure cookies can't be set on non-secure origins if strict secure
+// cookies are enabled.
+TEST_F(URLRequestTest, StrictSecureCookiesOnNonsecureOrigin) {
+  EmbeddedTestServer http_server;
+  http_server.AddDefaultHandlers(
+      base::FilePath(FILE_PATH_LITERAL("net/data/ssl")));
+  EmbeddedTestServer https_server(EmbeddedTestServer::TYPE_HTTPS);
+  https_server.AddDefaultHandlers(
+      base::FilePath(FILE_PATH_LITERAL("net/data/ssl")));
+  ASSERT_TRUE(http_server.Start());
+  ASSERT_TRUE(https_server.Start());
+
+  TestExperimentalFeaturesNetworkDelegate network_delegate;
+  TestURLRequestContext context(true);
+  context.set_network_delegate(&network_delegate);
+  context.Init();
+
+  // Try to set a Secure cookie, with experimental features enabled.
+  {
+    TestDelegate d;
+    scoped_ptr<URLRequest> req(context.CreateRequest(
+        http_server.GetURL("/set-cookie?nonsecure-origin=1;Secure"),
+        DEFAULT_PRIORITY, &d));
+    req->Start();
+    base::RunLoop().Run();
+    EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
+    EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
+  }
+
+  // Verify that the cookie is not set.
+  {
+    TestDelegate d;
+    scoped_ptr<URLRequest> req(context.CreateRequest(
+        https_server.GetURL("/echoheader?Cookie"), DEFAULT_PRIORITY, &d));
+    req->Start();
+    base::RunLoop().Run();
+
+    EXPECT_EQ(d.data_received().find("nonsecure-origin=1"), std::string::npos);
+    EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
+    EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
+  }
+}
+
+// Tests that secure cookies can be set on secure origins even if strict secure
+// cookies are enabled.
+TEST_F(URLRequestTest, StrictSecureCookiesOnSecureOrigin) {
+  EmbeddedTestServer https_server(EmbeddedTestServer::TYPE_HTTPS);
+  https_server.AddDefaultHandlers(
+      base::FilePath(FILE_PATH_LITERAL("net/data/ssl")));
+  ASSERT_TRUE(https_server.Start());
+
+  TestExperimentalFeaturesNetworkDelegate network_delegate;
+  TestURLRequestContext context(true);
+  context.set_network_delegate(&network_delegate);
+  context.Init();
+
+  // Try to set a Secure cookie, with experimental features enabled.
+  {
+    TestDelegate d;
+    scoped_ptr<URLRequest> req(context.CreateRequest(
+        https_server.GetURL("/set-cookie?secure-origin=1;Secure"),
+        DEFAULT_PRIORITY, &d));
+    req->Start();
+    base::RunLoop().Run();
+    EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
+    EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
+  }
+
+  // Verify that the cookie is not set.
+  {
+    TestDelegate d;
+    scoped_ptr<URLRequest> req(context.CreateRequest(
+        https_server.GetURL("/echoheader?Cookie"), DEFAULT_PRIORITY, &d));
+    req->Start();
+    base::RunLoop().Run();
+
+    EXPECT_NE(d.data_received().find("secure-origin=1"), std::string::npos);
     EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
     EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
   }
diff --git a/third_party/WebKit/LayoutTests/fast/block/float/containing-block-change-compositing-expected.html b/third_party/WebKit/LayoutTests/fast/block/float/containing-block-change-compositing-expected.html
new file mode 100644
index 0000000..02acf717
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/block/float/containing-block-change-compositing-expected.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<body style="margin: 0">
+  <div style="height: 100px">
+  Tests layout and repaint of floating descendants of a container changing 3D transform. Passes if there is no red.
+  </div>
+  <div style="position: absolute; top: 100px; left: 100px; width: 100px; height: 100px; background-color: green"></div>
+</body>
diff --git a/third_party/WebKit/LayoutTests/fast/block/float/containing-block-change-compositing.html b/third_party/WebKit/LayoutTests/fast/block/float/containing-block-change-compositing.html
new file mode 100644
index 0000000..ae00ac4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/block/float/containing-block-change-compositing.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<script src="../../../resources/run-after-layout-and-paint.js"></script>
+<script>
+runAfterLayoutAndPaint(function() {
+  document.getElementById('container').style.transform = 'translateZ(0) translateX(100px)';
+}, true);
+</script>
+<body style="margin: 0">
+  <div style="height: 100px">
+  Tests layout and repaint of floating descendants of a container changing 3D transform. Passes if there is no red.
+  </div>
+  <div id="indicator" style="position: absolute; top: 100px; left: 100px; width: 100px; height: 100px; background-color: red"></div>
+  <div>
+    <div id="container" style="width: 0; height: 0">
+      <div style="float: left; width: 100px; height: 100px; background-color: green"></div>
+    </div>
+  </div>
+</body>
diff --git a/third_party/WebKit/LayoutTests/fast/repaint/content-into-overflow-expected.txt b/third_party/WebKit/LayoutTests/fast/repaint/content-into-overflow-expected.txt
index c95c4459..88f27de 100644
--- a/third_party/WebKit/LayoutTests/fast/repaint/content-into-overflow-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/repaint/content-into-overflow-expected.txt
@@ -9,7 +9,6 @@
         [111, 8, 3, 106],
         [61, 8, 53, 106],
         [8, 388, 100, 20],
-        [8, 388, 100, 20],
         [8, 308, 100, 100],
         [8, 261, 106, 3],
         [8, 211, 106, 53]
diff --git a/third_party/WebKit/LayoutTests/fast/repaint/float-in-new-block-with-layout-delta-expected.txt b/third_party/WebKit/LayoutTests/fast/repaint/float-in-new-block-with-layout-delta-expected.txt
index 2aa40ce..a52c833 100644
--- a/third_party/WebKit/LayoutTests/fast/repaint/float-in-new-block-with-layout-delta-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/repaint/float-in-new-block-with-layout-delta-expected.txt
@@ -6,7 +6,6 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "repaintRects": [
-        [8, 108, 784, 100],
         [8, 108, 100, 100]
       ],
       "paintInvalidationClients": [
diff --git a/third_party/WebKit/LayoutTests/fast/repaint/float-move-during-layout-expected.txt b/third_party/WebKit/LayoutTests/fast/repaint/float-move-during-layout-expected.txt
index ac5ce61..f659019 100644
--- a/third_party/WebKit/LayoutTests/fast/repaint/float-move-during-layout-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/repaint/float-move-during-layout-expected.txt
@@ -6,10 +6,8 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "repaintRects": [
-        [8, 204, 784, 100],
         [8, 204, 100, 100],
         [8, 104, 784, 100],
-        [8, 104, 784, 100],
         [8, 104, 100, 100]
       ],
       "paintInvalidationClients": [
diff --git a/third_party/WebKit/LayoutTests/fast/repaint/float-new-in-block-expected.txt b/third_party/WebKit/LayoutTests/fast/repaint/float-new-in-block-expected.txt
index 21fb5ba..94bc8dd 100644
--- a/third_party/WebKit/LayoutTests/fast/repaint/float-new-in-block-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/repaint/float-new-in-block-expected.txt
@@ -6,11 +6,9 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "repaintRects": [
-        [8, 28, 784, 80],
         [8, 8, 100, 100]
       ],
       "paintInvalidationClients": [
-        "LayoutBlockFlow DIV",
         "LayoutBlockFlow (floating) DIV id='target'"
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/fast/repaint/overflow-into-content-expected.txt b/third_party/WebKit/LayoutTests/fast/repaint/overflow-into-content-expected.txt
index b31309c..f887412 100644
--- a/third_party/WebKit/LayoutTests/fast/repaint/overflow-into-content-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/repaint/overflow-into-content-expected.txt
@@ -9,7 +9,6 @@
         [111, 8, 3, 106],
         [61, 8, 53, 106],
         [8, 388, 100, 20],
-        [8, 388, 100, 20],
         [8, 308, 100, 100],
         [8, 261, 106, 3],
         [8, 211, 106, 53]
diff --git a/third_party/WebKit/LayoutTests/fast/repaint/overhanging-float-detach-repaint-expected.txt b/third_party/WebKit/LayoutTests/fast/repaint/overhanging-float-detach-repaint-expected.txt
index e3825e6..72fda62 100644
--- a/third_party/WebKit/LayoutTests/fast/repaint/overhanging-float-detach-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/repaint/overhanging-float-detach-repaint-expected.txt
@@ -6,7 +6,6 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "repaintRects": [
-        [8, 62, 784, 100],
         [8, 62, 100, 100]
       ],
       "paintInvalidationClients": [
diff --git a/third_party/WebKit/LayoutTests/fast/repaint/inline-focus-expected.txt b/third_party/WebKit/LayoutTests/platform/android/fast/repaint/inline-focus-expected.txt
similarity index 83%
copy from third_party/WebKit/LayoutTests/fast/repaint/inline-focus-expected.txt
copy to third_party/WebKit/LayoutTests/platform/android/fast/repaint/inline-focus-expected.txt
index 278e4ab3..13b7752 100644
--- a/third_party/WebKit/LayoutTests/fast/repaint/inline-focus-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/android/fast/repaint/inline-focus-expected.txt
@@ -6,14 +6,14 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "repaintRects": [
-        [0, 34, 800, 18],
+        [0, 36, 800, 19],
         [0, 0, 800, 232],
         [0, 0, 800, 232],
         [0, 0, 800, 232],
-        [-5, -5, 810, 242],
-        [-5, -5, 805, 237],
-        [-5, -5, 805, 237],
-        [-5, -5, 805, 237]
+        [-1, -1, 802, 234],
+        [-1, -1, 801, 233],
+        [-1, -1, 801, 233],
+        [-1, -1, 801, 233]
       ],
       "paintInvalidationClients": [
         "InlineFlowBox",
diff --git a/third_party/WebKit/LayoutTests/fast/repaint/inline-focus-expected.txt b/third_party/WebKit/LayoutTests/platform/android/virtual/syncpaint/fast/repaint/inline-focus-expected.txt
similarity index 83%
copy from third_party/WebKit/LayoutTests/fast/repaint/inline-focus-expected.txt
copy to third_party/WebKit/LayoutTests/platform/android/virtual/syncpaint/fast/repaint/inline-focus-expected.txt
index 278e4ab3..13b7752 100644
--- a/third_party/WebKit/LayoutTests/fast/repaint/inline-focus-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/android/virtual/syncpaint/fast/repaint/inline-focus-expected.txt
@@ -6,14 +6,14 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "repaintRects": [
-        [0, 34, 800, 18],
+        [0, 36, 800, 19],
         [0, 0, 800, 232],
         [0, 0, 800, 232],
         [0, 0, 800, 232],
-        [-5, -5, 810, 242],
-        [-5, -5, 805, 237],
-        [-5, -5, 805, 237],
-        [-5, -5, 805, 237]
+        [-1, -1, 802, 234],
+        [-1, -1, 801, 233],
+        [-1, -1, 801, 233],
+        [-1, -1, 801, 233]
       ],
       "paintInvalidationClients": [
         "InlineFlowBox",
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/float-move-during-layout-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/float-move-during-layout-expected.txt
index 50540ba3..90a8e14 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/float-move-during-layout-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/float-move-during-layout-expected.txt
@@ -6,10 +6,8 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "repaintRects": [
-        [8, 210, 784, 100],
         [8, 210, 100, 100],
         [8, 110, 784, 100],
-        [8, 110, 784, 100],
         [8, 110, 100, 100]
       ],
       "paintInvalidationClients": [
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/inline-focus-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/inline-focus-expected.txt
index 13b7752..c284e7fd 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/inline-focus-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/inline-focus-expected.txt
@@ -8,12 +8,12 @@
       "repaintRects": [
         [0, 36, 800, 19],
         [0, 0, 800, 232],
-        [0, 0, 800, 232],
-        [0, 0, 800, 232],
+        [0, 0, 800, 56],
+        [0, 0, 800, 20],
         [-1, -1, 802, 234],
         [-1, -1, 801, 233],
-        [-1, -1, 801, 233],
-        [-1, -1, 801, 233]
+        [-1, -1, 801, 57],
+        [-1, -1, 801, 21]
       ],
       "paintInvalidationClients": [
         "InlineFlowBox",
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/overhanging-float-detach-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/overhanging-float-detach-repaint-expected.txt
index 72fa722d8..ea81d43a 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/overhanging-float-detach-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/overhanging-float-detach-repaint-expected.txt
@@ -6,7 +6,6 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "repaintRects": [
-        [8, 68, 784, 100],
         [8, 68, 100, 100]
       ],
       "paintInvalidationClients": [
diff --git a/third_party/WebKit/LayoutTests/fast/repaint/inline-focus-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/syncpaint/fast/repaint/inline-focus-expected.txt
similarity index 77%
copy from third_party/WebKit/LayoutTests/fast/repaint/inline-focus-expected.txt
copy to third_party/WebKit/LayoutTests/platform/linux/virtual/syncpaint/fast/repaint/inline-focus-expected.txt
index 278e4ab3..c284e7fd 100644
--- a/third_party/WebKit/LayoutTests/fast/repaint/inline-focus-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/syncpaint/fast/repaint/inline-focus-expected.txt
@@ -6,14 +6,14 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "repaintRects": [
-        [0, 34, 800, 18],
+        [0, 36, 800, 19],
         [0, 0, 800, 232],
-        [0, 0, 800, 232],
-        [0, 0, 800, 232],
-        [-5, -5, 810, 242],
-        [-5, -5, 805, 237],
-        [-5, -5, 805, 237],
-        [-5, -5, 805, 237]
+        [0, 0, 800, 56],
+        [0, 0, 800, 20],
+        [-1, -1, 802, 234],
+        [-1, -1, 801, 233],
+        [-1, -1, 801, 57],
+        [-1, -1, 801, 21]
       ],
       "paintInvalidationClients": [
         "InlineFlowBox",
diff --git a/third_party/WebKit/LayoutTests/fast/repaint/inline-focus-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/inline-focus-expected.txt
similarity index 87%
rename from third_party/WebKit/LayoutTests/fast/repaint/inline-focus-expected.txt
rename to third_party/WebKit/LayoutTests/platform/mac/fast/repaint/inline-focus-expected.txt
index 278e4ab3..80b72b5 100644
--- a/third_party/WebKit/LayoutTests/fast/repaint/inline-focus-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/inline-focus-expected.txt
@@ -8,12 +8,12 @@
       "repaintRects": [
         [0, 34, 800, 18],
         [0, 0, 800, 232],
-        [0, 0, 800, 232],
-        [0, 0, 800, 232],
+        [0, 0, 800, 52],
+        [0, 0, 800, 18],
         [-5, -5, 810, 242],
         [-5, -5, 805, 237],
-        [-5, -5, 805, 237],
-        [-5, -5, 805, 237]
+        [-5, -5, 805, 57],
+        [-5, -5, 805, 28]
       ],
       "paintInvalidationClients": [
         "InlineFlowBox",
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/float-move-during-layout-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/float-move-during-layout-expected.txt
index 50540ba3..90a8e14 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/float-move-during-layout-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/float-move-during-layout-expected.txt
@@ -6,10 +6,8 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "repaintRects": [
-        [8, 210, 784, 100],
         [8, 210, 100, 100],
         [8, 110, 784, 100],
-        [8, 110, 784, 100],
         [8, 110, 100, 100]
       ],
       "paintInvalidationClients": [
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/inline-focus-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/inline-focus-expected.txt
index 13b7752..c284e7fd 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/inline-focus-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/inline-focus-expected.txt
@@ -8,12 +8,12 @@
       "repaintRects": [
         [0, 36, 800, 19],
         [0, 0, 800, 232],
-        [0, 0, 800, 232],
-        [0, 0, 800, 232],
+        [0, 0, 800, 56],
+        [0, 0, 800, 20],
         [-1, -1, 802, 234],
         [-1, -1, 801, 233],
-        [-1, -1, 801, 233],
-        [-1, -1, 801, 233]
+        [-1, -1, 801, 57],
+        [-1, -1, 801, 21]
       ],
       "paintInvalidationClients": [
         "InlineFlowBox",
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/overhanging-float-detach-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/overhanging-float-detach-repaint-expected.txt
index 72fa722d8..ea81d43a 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/overhanging-float-detach-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/overhanging-float-detach-repaint-expected.txt
@@ -6,7 +6,6 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "repaintRects": [
-        [8, 68, 784, 100],
         [8, 68, 100, 100]
       ],
       "paintInvalidationClients": [
diff --git a/third_party/WebKit/LayoutTests/fast/repaint/inline-focus-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/syncpaint/fast/repaint/inline-focus-expected.txt
similarity index 83%
copy from third_party/WebKit/LayoutTests/fast/repaint/inline-focus-expected.txt
copy to third_party/WebKit/LayoutTests/platform/win-xp/virtual/syncpaint/fast/repaint/inline-focus-expected.txt
index 278e4ab3..13b7752 100644
--- a/third_party/WebKit/LayoutTests/fast/repaint/inline-focus-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/syncpaint/fast/repaint/inline-focus-expected.txt
@@ -6,14 +6,14 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "repaintRects": [
-        [0, 34, 800, 18],
+        [0, 36, 800, 19],
         [0, 0, 800, 232],
         [0, 0, 800, 232],
         [0, 0, 800, 232],
-        [-5, -5, 810, 242],
-        [-5, -5, 805, 237],
-        [-5, -5, 805, 237],
-        [-5, -5, 805, 237]
+        [-1, -1, 802, 234],
+        [-1, -1, 801, 233],
+        [-1, -1, 801, 233],
+        [-1, -1, 801, 233]
       ],
       "paintInvalidationClients": [
         "InlineFlowBox",
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/inline-focus-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/inline-focus-expected.txt
index 566e953..5ce0844 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/inline-focus-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/inline-focus-expected.txt
@@ -8,12 +8,12 @@
       "repaintRects": [
         [0, 34, 800, 18],
         [0, 0, 800, 232],
-        [0, 0, 800, 232],
-        [0, 0, 800, 232],
+        [0, 0, 800, 52],
+        [0, 0, 800, 18],
         [-1, -1, 802, 234],
         [-1, -1, 801, 233],
-        [-1, -1, 801, 233],
-        [-1, -1, 801, 233]
+        [-1, -1, 801, 53],
+        [-1, -1, 801, 19]
       ],
       "paintInvalidationClients": [
         "InlineFlowBox",
diff --git a/third_party/WebKit/LayoutTests/fast/repaint/inline-focus-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/syncpaint/fast/repaint/inline-focus-expected.txt
similarity index 80%
copy from third_party/WebKit/LayoutTests/fast/repaint/inline-focus-expected.txt
copy to third_party/WebKit/LayoutTests/platform/win/virtual/syncpaint/fast/repaint/inline-focus-expected.txt
index 278e4ab3..5ce0844 100644
--- a/third_party/WebKit/LayoutTests/fast/repaint/inline-focus-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/syncpaint/fast/repaint/inline-focus-expected.txt
@@ -8,12 +8,12 @@
       "repaintRects": [
         [0, 34, 800, 18],
         [0, 0, 800, 232],
-        [0, 0, 800, 232],
-        [0, 0, 800, 232],
-        [-5, -5, 810, 242],
-        [-5, -5, 805, 237],
-        [-5, -5, 805, 237],
-        [-5, -5, 805, 237]
+        [0, 0, 800, 52],
+        [0, 0, 800, 18],
+        [-1, -1, 802, 234],
+        [-1, -1, 801, 233],
+        [-1, -1, 801, 53],
+        [-1, -1, 801, 19]
       ],
       "paintInvalidationClients": [
         "InlineFlowBox",
diff --git a/third_party/WebKit/Source/core/css/CSSGridTemplateAreasValue.cpp b/third_party/WebKit/Source/core/css/CSSGridTemplateAreasValue.cpp
index 0fefa43..cf311f0b 100644
--- a/third_party/WebKit/Source/core/css/CSSGridTemplateAreasValue.cpp
+++ b/third_party/WebKit/Source/core/css/CSSGridTemplateAreasValue.cpp
@@ -51,13 +51,13 @@
 
     for (const auto& item : gridAreaMap) {
         const GridCoordinate& coordinate = item.value;
-        if (row >= coordinate.rows.resolvedInitialPosition().toInt() && row < coordinate.rows.resolvedFinalPosition().toInt())
+        if (row >= coordinate.rows.resolvedInitialPosition() && row < coordinate.rows.resolvedFinalPosition())
             candidates.append(item.key);
     }
 
     for (const auto& item : gridAreaMap) {
         const GridCoordinate& coordinate = item.value;
-        if (column >= coordinate.columns.resolvedInitialPosition().toInt() && column < coordinate.columns.resolvedFinalPosition().toInt() && candidates.contains(item.key))
+        if (column >= coordinate.columns.resolvedInitialPosition() && column < coordinate.columns.resolvedFinalPosition() && candidates.contains(item.key))
             return item.key;
     }
 
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
index 671cabf..9168952 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
@@ -2177,7 +2177,7 @@
     return consumeLengthOrPercent(range, SVGAttributeMode, ValueRangeAll, UnitlessQuirk::Forbid);
 }
 
-PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::consumeImageSet(CSSParserTokenRange& range)
+static PassRefPtrWillBeRawPtr<CSSValue> consumeImageSet(CSSParserTokenRange& range, CSSParserContext context)
 {
     CSSParserTokenRange rangeCopy = range;
     CSSParserTokenRange args = consumeFunction(rangeCopy);
@@ -2187,7 +2187,7 @@
         if (urlValue.isNull())
             return nullptr;
 
-        RefPtrWillBeRawPtr<CSSValue> image = createCSSImageValueWithReferrer(urlValue, completeURL(urlValue));
+        RefPtrWillBeRawPtr<CSSValue> image = CSSPropertyParser::createCSSImageValueWithReferrer(urlValue, context);
         imageSet->append(image);
 
         const CSSParserToken& token = args.consumeIncludingWhitespace();
@@ -2207,16 +2207,16 @@
     return imageSet.release();
 }
 
-PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::consumeCursor(CSSParserTokenRange& range)
+static PassRefPtrWillBeRawPtr<CSSValue> consumeCursor(CSSParserTokenRange& range, CSSParserContext context, bool inQuirksMode)
 {
     RefPtrWillBeRawPtr<CSSValueList> list = nullptr;
     while (!range.atEnd()) {
         RefPtrWillBeRawPtr<CSSValue> image = nullptr;
         AtomicString uri(consumeUrl(range));
         if (!uri.isNull()) {
-            image = createCSSImageValueWithReferrer(uri, completeURL(uri));
+            image = CSSPropertyParser::createCSSImageValueWithReferrer(uri, context);
         } else if (range.peek().type() == FunctionToken && range.peek().functionId() == CSSValueWebkitImageSet) {
-            image = consumeImageSet(range);
+            image = consumeImageSet(range, context);
             if (!image)
                 return nullptr;
         } else {
@@ -2243,15 +2243,15 @@
     }
 
     CSSValueID id = range.peek().id();
-    if (!range.atEnd() && m_context.useCounter()) {
+    if (!range.atEnd() && context.useCounter()) {
         if (id == CSSValueWebkitZoomIn)
-            m_context.useCounter()->count(UseCounter::PrefixedCursorZoomIn);
+            context.useCounter()->count(UseCounter::PrefixedCursorZoomIn);
         else if (id == CSSValueWebkitZoomOut)
-            m_context.useCounter()->count(UseCounter::PrefixedCursorZoomOut);
+            context.useCounter()->count(UseCounter::PrefixedCursorZoomOut);
     }
     RefPtrWillBeRawPtr<CSSValue> cursorType = nullptr;
     if (id == CSSValueHand) {
-        if (inQuirksMode()) // Non-standard behavior
+        if (inQuirksMode) // Non-standard behavior
             cursorType = cssValuePool().createIdentifierValue(CSSValuePointer);
         range.consumeIncludingWhitespace();
     } else if ((id >= CSSValueAuto && id <= CSSValueWebkitZoomOut) || id == CSSValueCopy || id == CSSValueNone) {
@@ -2481,7 +2481,7 @@
     case CSSPropertyRy:
         return consumeLengthOrPercent(m_range, SVGAttributeMode, ValueRangeAll, UnitlessQuirk::Forbid);
     case CSSPropertyCursor:
-        return consumeCursor(m_range);
+        return consumeCursor(m_range, m_context, inQuirksMode());
     case CSSPropertyContain:
         return consumeContain(m_range);
     case CSSPropertyTransformOrigin:
@@ -2515,7 +2515,7 @@
     String url = consumeUrl(m_range);
     if (url.isNull())
         return nullptr;
-    RefPtrWillBeRawPtr<CSSFontFaceSrcValue> uriValue(CSSFontFaceSrcValue::create(completeURL(url), m_context.shouldCheckContentSecurityPolicy()));
+    RefPtrWillBeRawPtr<CSSFontFaceSrcValue> uriValue(CSSFontFaceSrcValue::create(m_context.completeURL(url), m_context.shouldCheckContentSecurityPolicy()));
     uriValue->setReferrer(m_context.referrer());
 
     if (m_range.peek().functionId() != CSSValueFormat)
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h
index d815869..0b856039 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h
@@ -92,6 +92,14 @@
     static bool isColorKeyword(CSSValueID);
     static bool isValidNumericValue(double);
 
+    // TODO(rwlbuis): move to CSSPropertyParser.cpp once CSSParserToken conversion is done.
+    static PassRefPtrWillBeRawPtr<CSSValue> createCSSImageValueWithReferrer(const AtomicString& rawValue, const CSSParserContext& context)
+    {
+        RefPtrWillBeRawPtr<CSSValue> imageValue = CSSImageValue::create(rawValue, context.completeURL(rawValue));
+        toCSSImageValue(imageValue.get())->setReferrer(context.referrer());
+        return imageValue;
+    }
+
 private:
     CSSPropertyParser(const CSSParserTokenRange&, const CSSParserContext&,
         WillBeHeapVector<CSSProperty, 256>&);
@@ -109,8 +117,6 @@
     bool parseViewportDescriptor(CSSPropertyID propId, bool important);
     bool parseFontFaceDescriptor(CSSPropertyID);
 
-    KURL completeURL(const String& url) const;
-
     void addProperty(CSSPropertyID, PassRefPtrWillBeRawPtr<CSSValue>, bool important, bool implicit = false);
     void rollbackLastProperties(int num);
     void addExpandedPropertyForValue(CSSPropertyID propId, PassRefPtrWillBeRawPtr<CSSValue>, bool);
@@ -155,8 +161,6 @@
 
     bool consumeColumns(bool important);
 
-    PassRefPtrWillBeRawPtr<CSSValue> consumeCursor(CSSParserTokenRange&);
-
     PassRefPtrWillBeRawPtr<CSSValue> parseGridPosition();
     bool parseIntegerOrCustomIdentFromGridPosition(RefPtrWillBeRawPtr<CSSPrimitiveValue>& numericValue, RefPtrWillBeRawPtr<CSSCustomIdentValue>& gridLineName);
     bool parseGridItemPositionShorthand(CSSPropertyID, bool important);
@@ -230,7 +234,6 @@
     bool parseCrossfade(CSSParserValueList*, RefPtrWillBeRawPtr<CSSValue>&);
 
     PassRefPtrWillBeRawPtr<CSSValue> parseImageSet(CSSParserValueList*);
-    PassRefPtrWillBeRawPtr<CSSValue> consumeImageSet(CSSParserTokenRange&);
 
     PassRefPtrWillBeRawPtr<CSSValueList> parseFilter();
     PassRefPtrWillBeRawPtr<CSSFunctionValue> parseBuiltinFilterArguments(CSSParserValueList*, CSSValueID);
@@ -243,14 +246,6 @@
     PassRefPtrWillBeRawPtr<CSSStringValue> createPrimitiveStringValue(CSSParserValue*);
     PassRefPtrWillBeRawPtr<CSSCustomIdentValue> createPrimitiveCustomIdentValue(CSSParserValue*);
 
-    // TODO(rwlbuis): move to CSSPropertyParser.cpp once CSSParserToken conversion is done.
-    inline PassRefPtrWillBeRawPtr<CSSValue> createCSSImageValueWithReferrer(const AtomicString& rawValue, const KURL& url)
-    {
-        RefPtrWillBeRawPtr<CSSValue> imageValue = CSSImageValue::create(rawValue, url);
-        toCSSImageValue(imageValue.get())->setReferrer(m_context.referrer());
-        return imageValue;
-    }
-
     PassRefPtrWillBeRawPtr<CSSBasicShapeInsetValue> parseInsetRoundedCorners(PassRefPtrWillBeRawPtr<CSSBasicShapeInsetValue>, CSSParserValueList*);
 
     PassRefPtrWillBeRawPtr<CSSValue> consumeFontFaceSrcURI();
diff --git a/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp
index 033b23d..e0392a5 100644
--- a/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp
+++ b/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp
@@ -93,11 +93,6 @@
     m_parsedProperties.shrink(m_parsedProperties.size() - num);
 }
 
-KURL CSSPropertyParser::completeURL(const String& url) const
-{
-    return m_context.completeURL(url);
-}
-
 bool CSSPropertyParser::validCalculationUnit(CSSParserValue* value, Units unitflags, ReleaseParsedCalcValueCondition releaseCalc)
 {
     bool mustBeNonNegative = unitflags & (FNonNeg | FPositiveInteger);
@@ -1305,7 +1300,7 @@
         RefPtrWillBeRawPtr<CSSValue> parsedValue = nullptr;
         if (val->m_unit == CSSParserValue::URI) {
             // url
-            parsedValue = createCSSImageValueWithReferrer(val->string, completeURL(val->string));
+            parsedValue = createCSSImageValueWithReferrer(val->string, m_context);
         } else if (val->m_unit == CSSParserValue::Function) {
             // attr(X) | counter(X [,Y]) | counters(X, Y, [,Z]) | -webkit-gradient(...)
             CSSParserValueList* args = val->function->args.get();
@@ -1424,7 +1419,7 @@
         return true;
     }
     if (valueList->current()->m_unit == CSSParserValue::URI) {
-        value = createCSSImageValueWithReferrer(valueList->current()->string, completeURL(valueList->current()->string));
+        value = createCSSImageValueWithReferrer(valueList->current()->string, m_context);
         return true;
     }
 
@@ -2720,18 +2715,18 @@
 
             // The following checks test that the grid area is a single filled-in rectangle.
             // 1. The new row is adjacent to the previously parsed row.
-            if (rowCount != gridCoordinate.rows.resolvedFinalPosition().toInt())
+            if (rowCount != gridCoordinate.rows.resolvedFinalPosition())
                 return false;
 
             // 2. The new area starts at the same position as the previously parsed area.
-            if (currentCol != gridCoordinate.columns.resolvedInitialPosition().toInt())
+            if (currentCol != gridCoordinate.columns.resolvedInitialPosition())
                 return false;
 
             // 3. The new area ends at the same position as the previously parsed area.
-            if (lookAheadCol != gridCoordinate.columns.resolvedFinalPosition().toInt())
+            if (lookAheadCol != gridCoordinate.columns.resolvedFinalPosition())
                 return false;
 
-            gridCoordinate.rows = GridSpan::definiteGridSpan(gridCoordinate.rows.resolvedInitialPosition(), gridCoordinate.rows.resolvedFinalPosition().next());
+            gridCoordinate.rows = GridSpan::definiteGridSpan(gridCoordinate.rows.resolvedInitialPosition(), gridCoordinate.rows.resolvedFinalPosition() + 1);
         }
         currentCol = lookAheadCol - 1;
     }
@@ -3767,7 +3762,7 @@
 
         if (!context.canAdvance() && context.allowImage()) {
             if (val->m_unit == CSSParserValue::URI) {
-                context.commitImage(createCSSImageValueWithReferrer(val->string, m_context.completeURL(val->string)));
+                context.commitImage(createCSSImageValueWithReferrer(val->string, m_context));
             } else if (val->m_unit == CSSParserValue::Function) {
                 if (isGeneratedImageValue(val->function->id)) {
                     RefPtrWillBeRawPtr<CSSValue> value = nullptr;
@@ -4952,7 +4947,7 @@
         if (arg->m_unit != CSSParserValue::URI)
             return nullptr;
 
-        RefPtrWillBeRawPtr<CSSValue> image = createCSSImageValueWithReferrer(arg->string, completeURL(arg->string));
+        RefPtrWillBeRawPtr<CSSValue> image = createCSSImageValueWithReferrer(arg->string, m_context);
         imageSet->append(image);
 
         arg = functionArgs->next();
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.cpp b/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.cpp
index 91cb9ea..4ed7a7c8 100644
--- a/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.cpp
+++ b/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.cpp
@@ -521,12 +521,12 @@
         GridSpan areaSpan = direction == ForRows ? namedGridAreaEntry.value.rows : namedGridAreaEntry.value.columns;
         {
             NamedGridLinesMap::AddResult startResult = namedGridLines.add(namedGridAreaEntry.key + "-start", Vector<size_t>());
-            startResult.storedValue->value.append(areaSpan.resolvedInitialPosition().toInt());
+            startResult.storedValue->value.append(areaSpan.resolvedInitialPosition());
             std::sort(startResult.storedValue->value.begin(), startResult.storedValue->value.end());
         }
         {
             NamedGridLinesMap::AddResult endResult = namedGridLines.add(namedGridAreaEntry.key + "-end", Vector<size_t>());
-            endResult.storedValue->value.append(areaSpan.resolvedFinalPosition().toInt());
+            endResult.storedValue->value.append(areaSpan.resolvedFinalPosition());
             std::sort(endResult.storedValue->value.begin(), endResult.storedValue->value.end());
         }
     }
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlock.cpp b/third_party/WebKit/Source/core/layout/LayoutBlock.cpp
index c4299e3..29128938 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlock.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBlock.cpp
@@ -943,7 +943,7 @@
         addOverflowFromBlockChildren();
 }
 
-void LayoutBlock::computeOverflow(LayoutUnit oldClientAfterEdge)
+void LayoutBlock::computeOverflow(LayoutUnit oldClientAfterEdge, bool)
 {
     m_overflow.clear();
 
@@ -1109,7 +1109,7 @@
         // computeOverflow expects the bottom edge before we clamp our height. Since this information isn't available during
         // simplifiedLayout, we cache the value in m_overflow.
         LayoutUnit oldClientAfterEdge = hasOverflowModel() ? m_overflow->layoutClientAfterEdge() : clientLogicalBottom();
-        computeOverflow(oldClientAfterEdge);
+        computeOverflow(oldClientAfterEdge, true);
     }
 
     updateLayerTransformAfterLayout();
@@ -2844,7 +2844,7 @@
         return false;
 
     LayoutUnit oldClientAfterEdge = hasOverflowModel() ? m_overflow->layoutClientAfterEdge() : clientLogicalBottom();
-    computeOverflow(oldClientAfterEdge);
+    computeOverflow(oldClientAfterEdge, true);
 
     if (hasOverflowClip())
         layer()->scrollableArea()->updateAfterOverflowRecalc();
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlock.h b/third_party/WebKit/Source/core/layout/LayoutBlock.h
index d0e54ae..f3cfe100 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlock.h
+++ b/third_party/WebKit/Source/core/layout/LayoutBlock.h
@@ -342,7 +342,7 @@
     virtual void simplifiedNormalFlowLayout();
 
 public:
-    virtual void computeOverflow(LayoutUnit oldClientAfterEdge);
+    virtual void computeOverflow(LayoutUnit oldClientAfterEdge, bool = false);
 protected:
     virtual void addOverflowFromChildren();
     void addOverflowFromPositionedObjects();
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
index b83ced6..d819092 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
@@ -1723,10 +1723,11 @@
     }
 }
 
-void LayoutBlockFlow::computeOverflow(LayoutUnit oldClientAfterEdge)
+void LayoutBlockFlow::computeOverflow(LayoutUnit oldClientAfterEdge, bool recomputeFloats)
 {
-    LayoutBlock::computeOverflow(oldClientAfterEdge);
-    addOverflowFromFloats();
+    LayoutBlock::computeOverflow(oldClientAfterEdge, recomputeFloats);
+    if (recomputeFloats || createsNewFormattingContext() || hasSelfPaintingLayer())
+        addOverflowFromFloats();
 }
 
 RootInlineBox* LayoutBlockFlow::createAndAppendRootInlineBox()
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h
index 61057fe8..3382e89 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h
+++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h
@@ -93,7 +93,7 @@
 
     void layoutBlock(bool relayoutChildren) override;
 
-    void computeOverflow(LayoutUnit oldClientAfterEdge) override;
+    void computeOverflow(LayoutUnit oldClientAfterEdge, bool recomputeFloats = false) override;
 
     void deleteLineBoxTree() final;
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutGrid.cpp b/third_party/WebKit/Source/core/layout/LayoutGrid.cpp
index e5cccec..d39d0b7 100644
--- a/third_party/WebKit/Source/core/layout/LayoutGrid.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutGrid.cpp
@@ -547,7 +547,7 @@
                 const GridSpan span = cachedGridSpan(*gridItem, direction);
 
                 // Do not include already processed items.
-                if (i > 0 && span.resolvedInitialPosition().toInt() <= flexibleSizedTracksIndex[i - 1])
+                if (i > 0 && span.resolvedInitialPosition() <= flexibleSizedTracksIndex[i - 1])
                     continue;
 
                 flexFraction = std::max(flexFraction, findFlexFactorUnitSize(tracks, span, direction, maxContentForChild(*gridItem, direction, sizingData.columnTracks)));
@@ -631,8 +631,7 @@
 
     double flexFactorSum = 0;
     Vector<size_t, 8> flexibleTracksIndexes;
-    for (const auto& resolvedPosition : tracksSpan) {
-        size_t trackIndex = resolvedPosition.toInt();
+    for (const auto& trackIndex : tracksSpan) {
         GridTrackSize trackSize = gridTrackSize(direction, trackIndex);
         if (!trackSize.maxTrackBreadth().isFlex()) {
             leftOverSpace -= tracks[trackIndex].baseSize();
@@ -785,7 +784,7 @@
 bool LayoutGrid::spanningItemCrossesFlexibleSizedTracks(const GridSpan& span, GridTrackSizingDirection direction) const
 {
     for (const auto& trackPosition : span) {
-        const GridTrackSize& trackSize = gridTrackSize(direction, trackPosition.toInt());
+        const GridTrackSize& trackSize = gridTrackSize(direction, trackPosition);
         if (trackSize.minTrackBreadth().isFlex() || trackSize.maxTrackBreadth().isFlex())
             return true;
     }
@@ -834,8 +833,8 @@
 
 void LayoutGrid::resolveContentBasedTrackSizingFunctionsForNonSpanningItems(GridTrackSizingDirection direction, const GridSpan& span, LayoutBox& gridItem, GridTrack& track, Vector<GridTrack>& columnTracks)
 {
-    const GridResolvedPosition trackPosition = span.resolvedInitialPosition();
-    GridTrackSize trackSize = gridTrackSize(direction, trackPosition.toInt());
+    const size_t trackPosition = span.resolvedInitialPosition();
+    GridTrackSize trackSize = gridTrackSize(direction, trackPosition);
 
     if (trackSize.hasMinContentMinTrackBreadth())
         track.setBaseSize(std::max(track.baseSize(), minContentForChild(gridItem, direction, columnTracks)));
@@ -993,8 +992,8 @@
         sizingData.filteredTracks.shrink(0);
         LayoutUnit spanningTracksSize;
         for (const auto& trackPosition : itemSpan) {
-            GridTrackSize trackSize = gridTrackSize(direction, trackPosition.toInt());
-            GridTrack& track = (direction == ForColumns) ? sizingData.columnTracks[trackPosition.toInt()] : sizingData.rowTracks[trackPosition.toInt()];
+            GridTrackSize trackSize = gridTrackSize(direction, trackPosition);
+            GridTrack& track = (direction == ForColumns) ? sizingData.columnTracks[trackPosition] : sizingData.rowTracks[trackPosition];
             spanningTracksSize += trackSizeForTrackSizeComputationPhase(phase, track, ForbidInfinity);
             if (!shouldProcessTrackForTrackSizeComputationPhase(phase, trackSize))
                 continue;
@@ -1106,11 +1105,11 @@
 void LayoutGrid::insertItemIntoGrid(LayoutBox& child, const GridCoordinate& coordinate)
 {
     RELEASE_ASSERT(coordinate.rows.isDefinite() && coordinate.columns.isDefinite());
-    ensureGridSize(coordinate.rows.resolvedFinalPosition().toInt(), coordinate.columns.resolvedFinalPosition().toInt());
+    ensureGridSize(coordinate.rows.resolvedFinalPosition(), coordinate.columns.resolvedFinalPosition());
 
-    for (GridSpan::iterator row = coordinate.rows.begin(); row != coordinate.rows.end(); ++row) {
-        for (GridSpan::iterator column = coordinate.columns.begin(); column != coordinate.columns.end(); ++column)
-            m_grid[row.toInt()][column.toInt()].append(&child);
+    for (const auto& row : coordinate.rows) {
+        for (const auto& column: coordinate.columns)
+            m_grid[row][column].append(&child);
     }
 }
 
@@ -1186,19 +1185,19 @@
 
         // |positions| is 0 if we need to run the auto-placement algorithm.
         if (rowPositions.isDefinite()) {
-            maximumRowIndex = std::max<size_t>(maximumRowIndex, rowPositions.resolvedFinalPosition().toInt());
+            maximumRowIndex = std::max<size_t>(maximumRowIndex, rowPositions.resolvedFinalPosition());
         } else {
             // Grow the grid for items with a definite row span, getting the largest such span.
-            GridSpan positions = GridResolvedPosition::resolveGridPositionsFromAutoPlacementPosition(*style(), *child, ForRows, GridResolvedPosition(0));
-            maximumRowIndex = std::max<size_t>(maximumRowIndex, positions.resolvedFinalPosition().toInt());
+            GridSpan positions = GridResolvedPosition::resolveGridPositionsFromAutoPlacementPosition(*style(), *child, ForRows, 0);
+            maximumRowIndex = std::max<size_t>(maximumRowIndex, positions.resolvedFinalPosition());
         }
 
         if (columnPositions.isDefinite()) {
-            maximumColumnIndex = std::max<size_t>(maximumColumnIndex, columnPositions.resolvedFinalPosition().toInt());
+            maximumColumnIndex = std::max<size_t>(maximumColumnIndex, columnPositions.resolvedFinalPosition());
         } else {
             // Grow the grid for items with a definite column span, getting the largest such span.
-            GridSpan positions = GridResolvedPosition::resolveGridPositionsFromAutoPlacementPosition(*style(), *child, ForColumns, GridResolvedPosition(0));
-            maximumColumnIndex = std::max<size_t>(maximumColumnIndex, positions.resolvedFinalPosition().toInt());
+            GridSpan positions = GridResolvedPosition::resolveGridPositionsFromAutoPlacementPosition(*style(), *child, ForColumns, 0);
+            maximumColumnIndex = std::max<size_t>(maximumColumnIndex, positions.resolvedFinalPosition());
         }
     }
 
@@ -1211,7 +1210,7 @@
 {
     GridTrackSizingDirection crossDirection = specifiedDirection == ForColumns ? ForRows : ForColumns;
     const size_t endOfCrossDirection = crossDirection == ForColumns ? gridColumnCount() : gridRowCount();
-    GridSpan crossDirectionPositions = GridResolvedPosition::resolveGridPositionsFromAutoPlacementPosition(*style(), gridItem, crossDirection, GridResolvedPosition(endOfCrossDirection));
+    GridSpan crossDirectionPositions = GridResolvedPosition::resolveGridPositionsFromAutoPlacementPosition(*style(), gridItem, crossDirection, endOfCrossDirection);
     return adoptPtr(new GridCoordinate(specifiedDirection == ForColumns ? crossDirectionPositions : specifiedPositions, specifiedDirection == ForColumns ? specifiedPositions : crossDirectionPositions));
 }
 
@@ -1229,10 +1228,10 @@
         GridSpan majorAxisPositions = cachedGridSpan(*autoGridItem, autoPlacementMajorAxisDirection());
         ASSERT(majorAxisPositions.isDefinite());
         ASSERT(!cachedGridSpan(*autoGridItem, autoPlacementMinorAxisDirection()).isDefinite());
-        GridSpan minorAxisPositions = GridResolvedPosition::resolveGridPositionsFromAutoPlacementPosition(*style(), *autoGridItem, autoPlacementMinorAxisDirection(), GridResolvedPosition(0));
-        unsigned majorAxisInitialPosition = majorAxisPositions.resolvedInitialPosition().toInt();
+        GridSpan minorAxisPositions = GridResolvedPosition::resolveGridPositionsFromAutoPlacementPosition(*style(), *autoGridItem, autoPlacementMinorAxisDirection(), 0);
+        unsigned majorAxisInitialPosition = majorAxisPositions.resolvedInitialPosition();
 
-        GridIterator iterator(m_grid, autoPlacementMajorAxisDirection(), majorAxisPositions.resolvedInitialPosition().toInt(), isGridAutoFlowDense ? 0 : minorAxisCursors.get(majorAxisInitialPosition));
+        GridIterator iterator(m_grid, autoPlacementMajorAxisDirection(), majorAxisPositions.resolvedInitialPosition(), isGridAutoFlowDense ? 0 : minorAxisCursors.get(majorAxisInitialPosition));
         OwnPtr<GridCoordinate> emptyGridArea = iterator.nextEmptyGridArea(majorAxisPositions.integerSpan(), minorAxisPositions.integerSpan());
         if (!emptyGridArea)
             emptyGridArea = createEmptyGridAreaAtSpecifiedPositionsOutsideGrid(*autoGridItem, autoPlacementMajorAxisDirection(), majorAxisPositions);
@@ -1241,7 +1240,7 @@
         insertItemIntoGrid(*autoGridItem, *emptyGridArea);
 
         if (!isGridAutoFlowDense)
-            minorAxisCursors.set(majorAxisInitialPosition, isForColumns ? emptyGridArea->rows.resolvedInitialPosition().toInt() : emptyGridArea->columns.resolvedInitialPosition().toInt());
+            minorAxisCursors.set(majorAxisInitialPosition, isForColumns ? emptyGridArea->rows.resolvedInitialPosition() : emptyGridArea->columns.resolvedInitialPosition());
     }
 }
 
@@ -1265,7 +1264,7 @@
 {
     GridSpan minorAxisPositions = cachedGridSpan(gridItem, autoPlacementMinorAxisDirection());
     ASSERT(!cachedGridSpan(gridItem, autoPlacementMajorAxisDirection()).isDefinite());
-    GridSpan majorAxisPositions = GridResolvedPosition::resolveGridPositionsFromAutoPlacementPosition(*style(), gridItem, autoPlacementMajorAxisDirection(), GridResolvedPosition(0));
+    GridSpan majorAxisPositions = GridResolvedPosition::resolveGridPositionsFromAutoPlacementPosition(*style(), gridItem, autoPlacementMajorAxisDirection(), 0);
 
     const size_t endOfMajorAxis = (autoPlacementMajorAxisDirection() == ForColumns) ? gridColumnCount() : gridRowCount();
     size_t majorAxisAutoPlacementCursor = autoPlacementMajorAxisDirection() == ForColumns ? autoPlacementCursor.second : autoPlacementCursor.first;
@@ -1274,18 +1273,18 @@
     OwnPtr<GridCoordinate> emptyGridArea;
     if (minorAxisPositions.isDefinite()) {
         // Move to the next track in major axis if initial position in minor axis is before auto-placement cursor.
-        if (minorAxisPositions.resolvedInitialPosition().toInt() < minorAxisAutoPlacementCursor)
+        if (minorAxisPositions.resolvedInitialPosition() < minorAxisAutoPlacementCursor)
             majorAxisAutoPlacementCursor++;
 
         if (majorAxisAutoPlacementCursor < endOfMajorAxis) {
-            GridIterator iterator(m_grid, autoPlacementMinorAxisDirection(), minorAxisPositions.resolvedInitialPosition().toInt(), majorAxisAutoPlacementCursor);
+            GridIterator iterator(m_grid, autoPlacementMinorAxisDirection(), minorAxisPositions.resolvedInitialPosition(), majorAxisAutoPlacementCursor);
             emptyGridArea = iterator.nextEmptyGridArea(minorAxisPositions.integerSpan(), majorAxisPositions.integerSpan());
         }
 
         if (!emptyGridArea)
             emptyGridArea = createEmptyGridAreaAtSpecifiedPositionsOutsideGrid(gridItem, autoPlacementMinorAxisDirection(), minorAxisPositions);
     } else {
-        GridSpan minorAxisPositions = GridResolvedPosition::resolveGridPositionsFromAutoPlacementPosition(*style(), gridItem, autoPlacementMinorAxisDirection(), GridResolvedPosition(0));
+        GridSpan minorAxisPositions = GridResolvedPosition::resolveGridPositionsFromAutoPlacementPosition(*style(), gridItem, autoPlacementMinorAxisDirection(), 0);
 
         for (size_t majorAxisIndex = majorAxisAutoPlacementCursor; majorAxisIndex < endOfMajorAxis; ++majorAxisIndex) {
             GridIterator iterator(m_grid, autoPlacementMajorAxisDirection(), majorAxisIndex, minorAxisAutoPlacementCursor);
@@ -1293,9 +1292,9 @@
 
             if (emptyGridArea) {
                 // Check that it fits in the minor axis direction, as we shouldn't grow in that direction here (it was already managed in populateExplicitGridAndOrderIterator()).
-                GridResolvedPosition minorAxisFinalPositionIndex = autoPlacementMinorAxisDirection() == ForColumns ? emptyGridArea->columns.resolvedFinalPosition() : emptyGridArea->rows.resolvedFinalPosition();
+                size_t minorAxisFinalPositionIndex = autoPlacementMinorAxisDirection() == ForColumns ? emptyGridArea->columns.resolvedFinalPosition() : emptyGridArea->rows.resolvedFinalPosition();
                 const size_t endOfMinorAxis = autoPlacementMinorAxisDirection() == ForColumns ? gridColumnCount() : gridRowCount();
-                if (minorAxisFinalPositionIndex.toInt() <= endOfMinorAxis)
+                if (minorAxisFinalPositionIndex <= endOfMinorAxis)
                     break;
 
                 // Discard empty grid area as it does not fit in the minor axis direction.
@@ -1314,8 +1313,8 @@
     m_gridItemCoordinate.set(&gridItem, *emptyGridArea);
     insertItemIntoGrid(gridItem, *emptyGridArea);
     // Move auto-placement cursor to the new position.
-    autoPlacementCursor.first = emptyGridArea->rows.resolvedInitialPosition().toInt();
-    autoPlacementCursor.second = emptyGridArea->columns.resolvedInitialPosition().toInt();
+    autoPlacementCursor.first = emptyGridArea->rows.resolvedInitialPosition();
+    autoPlacementCursor.second = emptyGridArea->columns.resolvedInitialPosition();
 }
 
 GridTrackSizingDirection LayoutGrid::autoPlacementMajorAxisDirection() const
@@ -1418,8 +1417,8 @@
 
 #if ENABLE(ASSERT)
         const GridCoordinate& coordinate = cachedGridCoordinate(*child);
-        ASSERT(coordinate.columns.resolvedInitialPosition().toInt() < sizingData.columnTracks.size());
-        ASSERT(coordinate.rows.resolvedInitialPosition().toInt() < sizingData.rowTracks.size());
+        ASSERT(coordinate.columns.resolvedInitialPosition() < sizingData.columnTracks.size());
+        ASSERT(coordinate.rows.resolvedInitialPosition() < sizingData.rowTracks.size());
 #endif
         child->setLogicalLocation(findChildLogicalPosition(*child, sizingData));
 
@@ -1488,22 +1487,22 @@
 
     bool startIsAuto = startPosition.isAuto()
         || (startPosition.isNamedGridArea() && !GridResolvedPosition::isValidNamedLineOrArea(startPosition.namedGridLine(), styleRef(), GridResolvedPosition::initialPositionSide(direction)))
-        || (positions.resolvedInitialPosition().toInt() > lastTrackIndex);
+        || (positions.resolvedInitialPosition() > lastTrackIndex);
     bool endIsAuto = endPosition.isAuto()
         || (endPosition.isNamedGridArea() && !GridResolvedPosition::isValidNamedLineOrArea(endPosition.namedGridLine(), styleRef(), GridResolvedPosition::finalPositionSide(direction)))
-        || (positions.resolvedFinalPosition().prev().toInt() > lastTrackIndex);
+        || (positions.resolvedFinalPosition() - 1 > lastTrackIndex);
 
-    GridResolvedPosition firstPosition = GridResolvedPosition(0);
-    GridResolvedPosition initialPosition = startIsAuto ? firstPosition : positions.resolvedInitialPosition();
-    GridResolvedPosition lastPosition = GridResolvedPosition(lastTrackIndex);
-    GridResolvedPosition finalPosition = endIsAuto ? lastPosition : positions.resolvedFinalPosition().prev();
+    size_t firstPosition = 0;
+    size_t initialPosition = startIsAuto ? firstPosition : positions.resolvedInitialPosition();
+    size_t lastPosition = lastTrackIndex;
+    size_t finalPosition = endIsAuto ? lastPosition : positions.resolvedFinalPosition() - 1;
 
     // Positioned children do not grow the grid, so we need to clamp the positions to avoid ending up outside of it.
-    initialPosition = std::min<GridResolvedPosition>(initialPosition, lastPosition);
-    finalPosition = std::min<GridResolvedPosition>(finalPosition, lastPosition);
+    initialPosition = std::min(initialPosition, lastPosition);
+    finalPosition = std::min(finalPosition, lastPosition);
 
-    LayoutUnit start = startIsAuto ? LayoutUnit() : (direction == ForColumns) ?  m_columnPositions[initialPosition.toInt()] : m_rowPositions[initialPosition.toInt()];
-    LayoutUnit end = endIsAuto ? (direction == ForColumns) ? logicalWidth() : logicalHeight() : (direction == ForColumns) ?  m_columnPositions[finalPosition.next().toInt()] : m_rowPositions[finalPosition.next().toInt()];
+    LayoutUnit start = startIsAuto ? LayoutUnit() : (direction == ForColumns) ?  m_columnPositions[initialPosition] : m_rowPositions[initialPosition];
+    LayoutUnit end = endIsAuto ? (direction == ForColumns) ? logicalWidth() : logicalHeight() : (direction == ForColumns) ?  m_columnPositions[finalPosition + 1] : m_rowPositions[finalPosition + 1];
 
     breadth = end - start;
 
@@ -1545,8 +1544,8 @@
 {
     const GridSpan& span = cachedGridSpan(child, direction);
     LayoutUnit gridAreaBreadth = 0;
-    for (GridSpan::iterator trackPosition = span.begin(); trackPosition != span.end(); ++trackPosition)
-        gridAreaBreadth += tracks[trackPosition.toInt()].baseSize();
+    for (const auto& trackPosition : span)
+        gridAreaBreadth += tracks[trackPosition].baseSize();
 
     gridAreaBreadth += guttersSize(direction, span.integerSpan());
 
@@ -1560,10 +1559,10 @@
     const Vector<GridTrack>& tracks = (direction == ForColumns) ? sizingData.columnTracks : sizingData.rowTracks;
     const GridSpan& span = cachedGridSpan(child, direction);
     const Vector<LayoutUnit>& linePositions = (direction == ForColumns) ? m_columnPositions : m_rowPositions;
-    LayoutUnit initialTrackPosition = linePositions[span.resolvedInitialPosition().toInt()];
-    LayoutUnit finalTrackPosition = linePositions[span.resolvedFinalPosition().prev().toInt()];
+    LayoutUnit initialTrackPosition = linePositions[span.resolvedInitialPosition()];
+    LayoutUnit finalTrackPosition = linePositions[span.resolvedFinalPosition() - 1];
     // Track Positions vector stores the 'start' grid line of each track, so w have to add last track's baseSize.
-    return finalTrackPosition - initialTrackPosition + tracks[span.resolvedFinalPosition().prev().toInt()].baseSize();
+    return finalTrackPosition - initialTrackPosition + tracks[span.resolvedFinalPosition() - 1].baseSize();
 }
 
 void LayoutGrid::populateGridPositions(GridSizingData& sizingData)
@@ -1870,7 +1869,7 @@
 LayoutUnit LayoutGrid::columnAxisOffsetForChild(const LayoutBox& child) const
 {
     const GridSpan& rowsSpan = cachedGridSpan(child, ForRows);
-    size_t childStartLine = rowsSpan.resolvedInitialPosition().toInt();
+    size_t childStartLine = rowsSpan.resolvedInitialPosition();
     LayoutUnit startOfRow = m_rowPositions[childStartLine];
     LayoutUnit startPosition = startOfRow + marginBeforeForChild(child);
     if (hasAutoMarginsInColumnAxis(child))
@@ -1881,7 +1880,7 @@
         return startPosition;
     case GridAxisEnd:
     case GridAxisCenter: {
-        size_t childEndLine = rowsSpan.resolvedFinalPosition().toInt();
+        size_t childEndLine = rowsSpan.resolvedFinalPosition();
         LayoutUnit endOfRow = m_rowPositions[childEndLine];
         // m_rowPositions include gutters so we need to substract them to get the actual end position for a given
         // row (this does not have to be done for the last track as there are no more m_rowPositions after it)
@@ -1902,7 +1901,7 @@
 LayoutUnit LayoutGrid::rowAxisOffsetForChild(const LayoutBox& child) const
 {
     const GridSpan& columnsSpan = cachedGridSpan(child, ForColumns);
-    size_t childStartLine = columnsSpan.resolvedInitialPosition().toInt();
+    size_t childStartLine = columnsSpan.resolvedInitialPosition();
     LayoutUnit startOfColumn = m_columnPositions[childStartLine];
     LayoutUnit startPosition = startOfColumn + marginStartForChild(child);
     if (hasAutoMarginsInRowAxis(child))
@@ -1913,7 +1912,7 @@
         return startPosition;
     case GridAxisEnd:
     case GridAxisCenter: {
-        size_t childEndLine = columnsSpan.resolvedFinalPosition().toInt();
+        size_t childEndLine = columnsSpan.resolvedFinalPosition();
         LayoutUnit endOfColumn = m_columnPositions[childEndLine];
         // m_columnPositions include gutters so we need to substract them to get the actual end position for a given
         // column (this does not have to be done for the last track as there are no more m_columnPositions after it)
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableSection.cpp b/third_party/WebKit/Source/core/layout/LayoutTableSection.cpp
index 74b9964..4a9a6ab 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTableSection.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutTableSection.cpp
@@ -1094,7 +1094,7 @@
                 if (oldLogicalHeight > rHeight)
                     rowHeightIncreaseForPagination = std::max<int>(rowHeightIncreaseForPagination, oldLogicalHeight - rHeight);
                 cell->setLogicalHeight(rHeight);
-                cell->computeOverflow(oldLogicalHeight);
+                cell->computeOverflow(oldLogicalHeight, false);
             }
 
             if (rowLayoutObject)
@@ -1117,7 +1117,7 @@
                 for (size_t i = 0; i < cells.size(); ++i) {
                     LayoutUnit oldLogicalHeight = cells[i]->logicalHeight();
                     cells[i]->setLogicalHeight(oldLogicalHeight + rowHeightIncreaseForPagination);
-                    cells[i]->computeOverflow(oldLogicalHeight);
+                    cells[i]->computeOverflow(oldLogicalHeight, false);
                 }
             }
         }
diff --git a/third_party/WebKit/Source/core/loader/EmptyClients.h b/third_party/WebKit/Source/core/loader/EmptyClients.h
index a0ae2774..9f4f7bd 100644
--- a/third_party/WebKit/Source/core/loader/EmptyClients.h
+++ b/third_party/WebKit/Source/core/loader/EmptyClients.h
@@ -234,8 +234,6 @@
     void didRunInsecureContent(SecurityOrigin*, const KURL&) override {}
     void didDetectXSS(const KURL&, bool) override {}
     void didDispatchPingLoader(const KURL&) override {}
-    void didDisplayContentWithCertificateErrors(const KURL&, const CString&, const WebURL& mainResourceUrl, const CString& mainResourceSecurityInfo) override {}
-    void didRunContentWithCertificateErrors(const KURL&, const CString&, const WebURL& mainResourceUrl, const CString& mainResourceSecurityInfo) override {}
     void selectorMatchChanged(const Vector<String>&, const Vector<String>&) override {}
     PassRefPtrWillBeRawPtr<LocalFrame> createFrame(const FrameLoadRequest&, const AtomicString&, HTMLFrameOwnerElement*) override;
     PassRefPtrWillBeRawPtr<Widget> createPlugin(HTMLPlugInElement*, const KURL&, const Vector<String>&, const Vector<String>&, const String&, bool, DetachedPluginPolicy) override;
diff --git a/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp b/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
index 41bed10..6be16e9e 100644
--- a/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
+++ b/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
@@ -34,7 +34,6 @@
 #include "bindings/core/v8/ScriptController.h"
 #include "core/dom/Document.h"
 #include "core/fetch/ClientHintsPreferences.h"
-#include "core/fetch/ResourceLoader.h"
 #include "core/fetch/UniqueIdentifier.h"
 #include "core/frame/FrameConsole.h"
 #include "core/frame/FrameHost.h"
@@ -240,9 +239,6 @@
         m_documentLoader->clientHintsPreferences().updateFromAcceptClientHintsHeader(response.httpHeaderField("accept-ch"), fetcher);
     }
 
-    if (response.hasMajorCertificateErrors() && resourceLoader)
-        MixedContentChecker::handleCertificateError(frame(), resourceLoader->originalRequest(), response);
-
     frame()->loader().progress().incrementProgress(identifier, response);
     frame()->loader().client()->dispatchDidReceiveResponse(m_documentLoader, identifier, response);
     TRACE_EVENT_INSTANT1("devtools.timeline", "ResourceReceiveResponse", TRACE_EVENT_SCOPE_THREAD, "data", InspectorReceiveResponseEvent::data(identifier, frame(), response));
diff --git a/third_party/WebKit/Source/core/loader/FrameLoaderClient.h b/third_party/WebKit/Source/core/loader/FrameLoaderClient.h
index 42e507db..b492489 100644
--- a/third_party/WebKit/Source/core/loader/FrameLoaderClient.h
+++ b/third_party/WebKit/Source/core/loader/FrameLoaderClient.h
@@ -129,13 +129,6 @@
     virtual void didDetectXSS(const KURL&, bool didBlockEntirePage) = 0;
     virtual void didDispatchPingLoader(const KURL&) = 0;
 
-    // The given main resource displayed content with certificate errors
-    // with the given URL and security info.
-    virtual void didDisplayContentWithCertificateErrors(const KURL&, const CString& securityInfo, const WebURL& mainResourceUrl, const CString& mainResourceSecurityInfo) = 0;
-    // The given main resource ran content with certificate errors with
-    // the given URL and security info.
-    virtual void didRunContentWithCertificateErrors(const KURL&, const CString& securityInfo, const WebURL& mainResourceUrl, const CString& mainResourceSecurityInfo) = 0;
-
     // Will be called when |PerformanceTiming| events are updated
     virtual void didChangePerformanceTiming() { }
 
diff --git a/third_party/WebKit/Source/core/loader/MixedContentChecker.cpp b/third_party/WebKit/Source/core/loader/MixedContentChecker.cpp
index f525cda..fdcc09b 100644
--- a/third_party/WebKit/Source/core/loader/MixedContentChecker.cpp
+++ b/third_party/WebKit/Source/core/loader/MixedContentChecker.cpp
@@ -458,27 +458,6 @@
     return effectiveFrame;
 }
 
-void MixedContentChecker::handleCertificateError(LocalFrame* frame, const ResourceRequest& request, const ResourceResponse& response)
-{
-    WebURLRequest::FrameType frameType = request.frameType();
-    LocalFrame* effectiveFrame = effectiveFrameForFrameType(frame, frameType);
-    if (frameType == WebURLRequest::FrameTypeTopLevel || !effectiveFrame)
-        return;
-
-    FrameLoaderClient* client = effectiveFrame->loader().client();
-    WebURLRequest::RequestContext requestContext = request.requestContext();
-    ContextType contextType = MixedContentChecker::contextTypeFromContext(requestContext, frame);
-    if (contextType == ContextTypeBlockable) {
-        client->didRunContentWithCertificateErrors(response.url(), response.getSecurityInfo(), effectiveFrame->document()->url(), effectiveFrame->loader().documentLoader()->response().getSecurityInfo());
-    } else {
-        // contextTypeFromContext() never returns NotMixedContent (it
-        // computes the type of mixed content, given that the content is
-        // mixed).
-        ASSERT(contextType != ContextTypeNotMixedContent);
-        client->didDisplayContentWithCertificateErrors(response.url(), response.getSecurityInfo(), effectiveFrame->document()->url(), effectiveFrame->loader().documentLoader()->response().getSecurityInfo());
-    }
-}
-
 MixedContentChecker::ContextType MixedContentChecker::contextTypeForInspector(LocalFrame* frame, const ResourceRequest& request)
 {
     LocalFrame* effectiveFrame = effectiveFrameForFrameType(frame, request.frameType());
diff --git a/third_party/WebKit/Source/core/loader/MixedContentChecker.h b/third_party/WebKit/Source/core/loader/MixedContentChecker.h
index e2e50c4..d88780bd 100644
--- a/third_party/WebKit/Source/core/loader/MixedContentChecker.h
+++ b/third_party/WebKit/Source/core/loader/MixedContentChecker.h
@@ -31,7 +31,6 @@
 #ifndef MixedContentChecker_h
 #define MixedContentChecker_h
 
-#include "base/gtest_prod_util.h"
 #include "core/CoreExport.h"
 #include "platform/heap/Handle.h"
 #include "platform/network/ResourceRequest.h"
@@ -43,7 +42,6 @@
 class FrameLoaderClient;
 class LocalFrame;
 class KURL;
-class ResourceResponse;
 class SecurityOrigin;
 
 class CORE_EXPORT MixedContentChecker final {
@@ -77,10 +75,7 @@
     // for a mixed content check for the given frame type.
     static LocalFrame* effectiveFrameForFrameType(LocalFrame*, WebURLRequest::FrameType);
 
-    static void handleCertificateError(LocalFrame*, const ResourceRequest&, const ResourceResponse&);
-
 private:
-    FRIEND_TEST_ALL_PREFIXES(MixedContentCheckerTest, HandleCertificateError);
     enum MixedContentType {
         Display,
         Execution,
diff --git a/third_party/WebKit/Source/core/loader/MixedContentCheckerTest.cpp b/third_party/WebKit/Source/core/loader/MixedContentCheckerTest.cpp
index 8b4cb217..4291c0a 100644
--- a/third_party/WebKit/Source/core/loader/MixedContentCheckerTest.cpp
+++ b/third_party/WebKit/Source/core/loader/MixedContentCheckerTest.cpp
@@ -5,12 +5,9 @@
 #include "config.h"
 #include "core/loader/MixedContentChecker.h"
 
-#include "core/loader/EmptyClients.h"
 #include "core/testing/DummyPageHolder.h"
-#include "platform/network/ResourceResponse.h"
 #include "platform/weborigin/KURL.h"
 #include "platform/weborigin/SecurityOrigin.h"
-#include "testing/gmock/include/gmock/gmock-generated-function-mockers.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "wtf/RefPtr.h"
 #include <base/macros.h>
@@ -70,48 +67,4 @@
     EXPECT_EQ(MixedContentChecker::ContextTypeOptionallyBlockable, MixedContentChecker::contextTypeForInspector(&dummyPageHolder->frame(), blockableMixedContent));
 }
 
-namespace {
-
-    class MockFrameLoaderClient : public EmptyFrameLoaderClient {
-    public:
-        MockFrameLoaderClient()
-            : EmptyFrameLoaderClient()
-        {
-        }
-        MOCK_METHOD4(didDisplayContentWithCertificateErrors, void(const KURL&, const CString&, const WebURL&, const CString&));
-        MOCK_METHOD4(didRunContentWithCertificateErrors, void(const KURL&, const CString&, const WebURL&, const CString&));
-    };
-
-} // namespace
-
-TEST(MixedContentCheckerTest, HandleCertificateError)
-{
-    MockFrameLoaderClient* client = new MockFrameLoaderClient;
-    OwnPtr<DummyPageHolder> dummyPageHolder = DummyPageHolder::create(IntSize(1, 1), nullptr, adoptPtrWillBeNoop(client));
-
-    KURL mainResourceUrl(KURL(), "https://example.test");
-    KURL displayedUrl(KURL(), "https://example-displayed.test");
-    KURL ranUrl(KURL(), "https://example-ran.test");
-
-    dummyPageHolder->frame().document()->setURL(mainResourceUrl);
-    ResourceRequest request1(ranUrl);
-    request1.setRequestContext(WebURLRequest::RequestContextScript);
-    request1.setFrameType(WebURLRequest::FrameTypeNone);
-    ResourceResponse response1;
-    response1.setURL(ranUrl);
-    response1.setSecurityInfo("security info1");
-    EXPECT_CALL(*client, didRunContentWithCertificateErrors(ranUrl, response1.getSecurityInfo(), WebURL(mainResourceUrl), CString()));
-    MixedContentChecker::handleCertificateError(&dummyPageHolder->frame(), request1, response1);
-
-    ResourceRequest request2(displayedUrl);
-    request2.setRequestContext(WebURLRequest::RequestContextImage);
-    request2.setFrameType(WebURLRequest::FrameTypeNone);
-    ResourceResponse response2;
-    ASSERT_EQ(MixedContentChecker::ContextTypeOptionallyBlockable, MixedContentChecker::contextTypeFromContext(request2.requestContext(), &dummyPageHolder->frame()));
-    response2.setURL(displayedUrl);
-    response2.setSecurityInfo("security info2");
-    EXPECT_CALL(*client, didDisplayContentWithCertificateErrors(displayedUrl, response2.getSecurityInfo(), WebURL(mainResourceUrl), CString()));
-    MixedContentChecker::handleCertificateError(&dummyPageHolder->frame(), request2, response2);
-}
-
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/paint/GridPainter.cpp b/third_party/WebKit/Source/core/paint/GridPainter.cpp
index 3fa13c8..d25a196 100644
--- a/third_party/WebKit/Source/core/paint/GridPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/GridPainter.cpp
@@ -51,9 +51,9 @@
 
     Vector<std::pair<LayoutBox*, size_t>> gridItemsToBePainted;
 
-    for (GridSpan::iterator row = dirtiedRows.begin(); row != dirtiedRows.end(); ++row) {
-        for (GridSpan::iterator column = dirtiedColumns.begin(); column != dirtiedColumns.end(); ++column) {
-            const Vector<LayoutBox*, 1>& children = m_layoutGrid.gridCell(row.toInt(), column.toInt());
+    for (const auto& row : dirtiedRows) {
+        for (const auto& column : dirtiedColumns) {
+            const Vector<LayoutBox*, 1>& children = m_layoutGrid.gridCell(row, column);
             for (auto* child : children)
                 gridItemsToBePainted.append(std::make_pair(child, m_layoutGrid.paintIndexForGridItem(child)));
         }
diff --git a/third_party/WebKit/Source/core/style/GridCoordinate.h b/third_party/WebKit/Source/core/style/GridCoordinate.h
index 9287de3..bd1592f 100644
--- a/third_party/WebKit/Source/core/style/GridCoordinate.h
+++ b/third_party/WebKit/Source/core/style/GridCoordinate.h
@@ -50,7 +50,7 @@
     USING_FAST_MALLOC(GridSpan);
 public:
 
-    static GridSpan definiteGridSpan(const GridResolvedPosition& resolvedInitialPosition, const GridResolvedPosition& resolvedFinalPosition)
+    static GridSpan definiteGridSpan(size_t resolvedInitialPosition, size_t resolvedFinalPosition)
     {
         return GridSpan(resolvedInitialPosition, resolvedFinalPosition, Definite);
     }
@@ -68,30 +68,40 @@
     size_t integerSpan() const
     {
         ASSERT(isDefinite());
-        return m_resolvedFinalPosition.toInt() - m_resolvedInitialPosition.toInt();
+        ASSERT(m_resolvedFinalPosition > m_resolvedInitialPosition);
+        return m_resolvedFinalPosition - m_resolvedInitialPosition;
     }
 
-    const GridResolvedPosition& resolvedInitialPosition() const
+    size_t resolvedInitialPosition() const
     {
         ASSERT(isDefinite());
         return m_resolvedInitialPosition;
     }
 
-    const GridResolvedPosition& resolvedFinalPosition() const
+    size_t resolvedFinalPosition() const
     {
         ASSERT(isDefinite());
+        ASSERT(m_resolvedFinalPosition);
         return m_resolvedFinalPosition;
     }
 
-    typedef GridResolvedPosition iterator;
+    struct GridSpanIterator {
+        GridSpanIterator(size_t v) : value(v) {}
 
-    iterator begin() const
+        size_t operator*() const { return value; }
+        size_t operator++() { return value++; }
+        bool operator!=(GridSpanIterator other) const { return value != other.value; }
+
+        size_t value;
+    };
+
+    GridSpanIterator begin() const
     {
         ASSERT(isDefinite());
         return m_resolvedInitialPosition;
     }
 
-    iterator end() const
+    GridSpanIterator end() const
     {
         ASSERT(isDefinite());
         return m_resolvedFinalPosition;
@@ -106,16 +116,16 @@
 
     enum GridSpanType {Definite, Indefinite};
 
-    GridSpan(const GridResolvedPosition& resolvedInitialPosition, const GridResolvedPosition& resolvedFinalPosition, GridSpanType type)
-        : m_resolvedInitialPosition(std::min(resolvedInitialPosition.toInt(), kGridMaxTracks - 1))
-        , m_resolvedFinalPosition(std::min(resolvedFinalPosition.toInt(), kGridMaxTracks))
+    GridSpan(size_t resolvedInitialPosition, size_t resolvedFinalPosition, GridSpanType type)
+        : m_resolvedInitialPosition(std::min(resolvedInitialPosition, kGridMaxTracks - 1))
+        , m_resolvedFinalPosition(std::min(resolvedFinalPosition, kGridMaxTracks))
         , m_type(type)
     {
         ASSERT(resolvedInitialPosition < resolvedFinalPosition);
     }
 
-    GridResolvedPosition m_resolvedInitialPosition;
-    GridResolvedPosition m_resolvedFinalPosition;
+    size_t m_resolvedInitialPosition;
+    size_t m_resolvedFinalPosition;
     GridSpanType m_type;
 };
 
diff --git a/third_party/WebKit/Source/core/style/GridResolvedPosition.cpp b/third_party/WebKit/Source/core/style/GridResolvedPosition.cpp
index 6b8dc94..b80e5fa 100644
--- a/third_party/WebKit/Source/core/style/GridResolvedPosition.cpp
+++ b/third_party/WebKit/Source/core/style/GridResolvedPosition.cpp
@@ -62,37 +62,38 @@
         initialPosition.setSpanPosition(1, String());
 }
 
-static GridSpan definiteGridSpanWithInitialNamedSpanAgainstOpposite(const GridResolvedPosition& resolvedOppositePosition, const GridPosition& position, const Vector<size_t>& gridLines)
+static GridSpan definiteGridSpanWithInitialNamedSpanAgainstOpposite(size_t resolvedOppositePosition, const GridPosition& position, const Vector<size_t>& gridLines)
 {
     if (resolvedOppositePosition == 0)
-        return GridSpan::definiteGridSpan(resolvedOppositePosition, resolvedOppositePosition.next());
+        return GridSpan::definiteGridSpan(resolvedOppositePosition, resolvedOppositePosition + 1);
 
     size_t firstLineBeforeOppositePositionIndex = 0;
-    const size_t* firstLineBeforeOppositePosition = std::lower_bound(gridLines.begin(), gridLines.end(), resolvedOppositePosition.toInt());
+    const size_t* firstLineBeforeOppositePosition = std::lower_bound(gridLines.begin(), gridLines.end(), resolvedOppositePosition);
     if (firstLineBeforeOppositePosition != gridLines.end())
         firstLineBeforeOppositePositionIndex = firstLineBeforeOppositePosition - gridLines.begin();
     size_t gridLineIndex = std::max<int>(0, firstLineBeforeOppositePositionIndex - position.spanPosition());
-    GridResolvedPosition resolvedGridLinePosition = GridResolvedPosition(gridLines[gridLineIndex]);
+    size_t resolvedGridLinePosition = gridLines[gridLineIndex];
     if (resolvedGridLinePosition >= resolvedOppositePosition)
-        resolvedGridLinePosition = resolvedOppositePosition.prev();
+        resolvedGridLinePosition = resolvedOppositePosition - 1;
     return GridSpan::definiteGridSpan(resolvedGridLinePosition, resolvedOppositePosition);
 }
 
-static GridSpan definiteGridSpanWithFinalNamedSpanAgainstOpposite(const GridResolvedPosition& resolvedOppositePosition, const GridPosition& position, const Vector<size_t>& gridLines)
+static GridSpan definiteGridSpanWithFinalNamedSpanAgainstOpposite(size_t resolvedOppositePosition, const GridPosition& position, const Vector<size_t>& gridLines)
 {
+    ASSERT(gridLines.size());
     size_t firstLineAfterOppositePositionIndex = gridLines.size() - 1;
-    const size_t* firstLineAfterOppositePosition = std::upper_bound(gridLines.begin(), gridLines.end(), resolvedOppositePosition.toInt());
+    const size_t* firstLineAfterOppositePosition = std::upper_bound(gridLines.begin(), gridLines.end(), resolvedOppositePosition);
     if (firstLineAfterOppositePosition != gridLines.end())
         firstLineAfterOppositePositionIndex = firstLineAfterOppositePosition - gridLines.begin();
     size_t gridLineIndex = std::min(gridLines.size() - 1, firstLineAfterOppositePositionIndex + position.spanPosition() - 1);
-    GridResolvedPosition resolvedGridLinePosition = gridLines[gridLineIndex];
+    size_t resolvedGridLinePosition = gridLines[gridLineIndex];
     if (resolvedGridLinePosition <= resolvedOppositePosition)
-        resolvedGridLinePosition = resolvedOppositePosition.next();
+        resolvedGridLinePosition = resolvedOppositePosition + 1;
 
     return GridSpan::definiteGridSpan(resolvedOppositePosition, resolvedGridLinePosition);
 }
 
-static GridSpan definiteGridSpanWithNamedSpanAgainstOpposite(const GridResolvedPosition& resolvedOppositePosition, const GridPosition& position, GridPositionSide side, const Vector<size_t>& gridLines)
+static GridSpan definiteGridSpanWithNamedSpanAgainstOpposite(size_t resolvedOppositePosition, const GridPosition& position, GridPositionSide side, const Vector<size_t>& gridLines)
 {
     if (side == RowStartSide || side == ColumnStartSide)
         return definiteGridSpanWithInitialNamedSpanAgainstOpposite(resolvedOppositePosition, position, gridLines);
@@ -100,7 +101,7 @@
     return definiteGridSpanWithFinalNamedSpanAgainstOpposite(resolvedOppositePosition, position, gridLines);
 }
 
-static GridSpan resolveNamedGridLinePositionAgainstOppositePosition(const ComputedStyle& gridContainerStyle, const GridResolvedPosition& resolvedOppositePosition, const GridPosition& position, GridPositionSide side)
+static GridSpan resolveNamedGridLinePositionAgainstOppositePosition(const ComputedStyle& gridContainerStyle, size_t resolvedOppositePosition, const GridPosition& position, GridPositionSide side)
 {
     ASSERT(position.isSpan());
     ASSERT(!position.namedGridLine().isNull());
@@ -113,34 +114,34 @@
     // If there is no named grid line of that name, we resolve the position to 'auto' (which is equivalent to 'span 1' in this case).
     // See http://lists.w3.org/Archives/Public/www-style/2013Jun/0394.html.
     if (it == gridLinesNames.end()) {
-        if ((side == ColumnStartSide || side == RowStartSide) && resolvedOppositePosition.toInt())
-            return GridSpan::definiteGridSpan(resolvedOppositePosition.prev(), resolvedOppositePosition);
-        return GridSpan::definiteGridSpan(resolvedOppositePosition, resolvedOppositePosition.next());
+        if ((side == ColumnStartSide || side == RowStartSide) && resolvedOppositePosition)
+            return GridSpan::definiteGridSpan(resolvedOppositePosition - 1, resolvedOppositePosition);
+        return GridSpan::definiteGridSpan(resolvedOppositePosition, resolvedOppositePosition + 1);
     }
 
     return definiteGridSpanWithNamedSpanAgainstOpposite(resolvedOppositePosition, position, side, it->value);
 }
 
-static GridSpan definiteGridSpanWithSpanAgainstOpposite(const GridResolvedPosition& resolvedOppositePosition, const GridPosition& position, GridPositionSide side)
+static GridSpan definiteGridSpanWithSpanAgainstOpposite(size_t resolvedOppositePosition, const GridPosition& position, GridPositionSide side)
 {
     size_t positionOffset = position.spanPosition();
     if (side == ColumnStartSide || side == RowStartSide) {
         if (resolvedOppositePosition == 0)
-            return GridSpan::definiteGridSpan(resolvedOppositePosition, resolvedOppositePosition.next());
+            return GridSpan::definiteGridSpan(resolvedOppositePosition, resolvedOppositePosition + 1);
 
-        GridResolvedPosition initialResolvedPosition = GridResolvedPosition(std::max<int>(0, resolvedOppositePosition.toInt() - positionOffset));
+        size_t initialResolvedPosition = std::max<int>(0, resolvedOppositePosition - positionOffset);
         return GridSpan::definiteGridSpan(initialResolvedPosition, resolvedOppositePosition);
     }
 
-    return GridSpan::definiteGridSpan(resolvedOppositePosition, GridResolvedPosition(resolvedOppositePosition.toInt() + positionOffset));
+    return GridSpan::definiteGridSpan(resolvedOppositePosition, resolvedOppositePosition + positionOffset);
 }
 
-static GridSpan resolveGridPositionAgainstOppositePosition(const ComputedStyle& gridContainerStyle, const GridResolvedPosition& resolvedOppositePosition, const GridPosition& position, GridPositionSide side)
+static GridSpan resolveGridPositionAgainstOppositePosition(const ComputedStyle& gridContainerStyle, size_t resolvedOppositePosition, const GridPosition& position, GridPositionSide side)
 {
     if (position.isAuto()) {
-        if ((side == ColumnStartSide || side == RowStartSide) && resolvedOppositePosition.toInt())
-            return GridSpan::definiteGridSpan(resolvedOppositePosition.prev(), resolvedOppositePosition);
-        return GridSpan::definiteGridSpan(resolvedOppositePosition, resolvedOppositePosition.next());
+        if ((side == ColumnStartSide || side == RowStartSide) && resolvedOppositePosition)
+            return GridSpan::definiteGridSpan(resolvedOppositePosition - 1, resolvedOppositePosition);
+        return GridSpan::definiteGridSpan(resolvedOppositePosition, resolvedOppositePosition + 1);
     }
 
     ASSERT(position.isSpan());
@@ -154,7 +155,7 @@
     return definiteGridSpanWithSpanAgainstOpposite(resolvedOppositePosition, position, side);
 }
 
-GridSpan GridResolvedPosition::resolveGridPositionsFromAutoPlacementPosition(const ComputedStyle& gridContainerStyle, const LayoutBox& gridItem, GridTrackSizingDirection direction, const GridResolvedPosition& resolvedInitialPosition)
+GridSpan GridResolvedPosition::resolveGridPositionsFromAutoPlacementPosition(const ComputedStyle& gridContainerStyle, const LayoutBox& gridItem, GridTrackSizingDirection direction, size_t resolvedInitialPosition)
 {
     GridPosition initialPosition, finalPosition;
     initialAndFinalPositionsFromStyle(gridContainerStyle, gridItem, direction, initialPosition, finalPosition);
@@ -164,7 +165,7 @@
     // This method will only be used when both positions need to be resolved against the opposite one.
     ASSERT(initialPosition.shouldBeResolvedAgainstOppositePosition() && finalPosition.shouldBeResolvedAgainstOppositePosition());
 
-    GridResolvedPosition resolvedFinalPosition = resolvedInitialPosition.next();
+    size_t resolvedFinalPosition = resolvedInitialPosition + 1;
 
     if (initialPosition.isSpan())
         return resolveGridPositionAgainstOppositePosition(gridContainerStyle, resolvedInitialPosition, initialPosition, finalSide);
@@ -189,7 +190,7 @@
     return (side == ColumnStartSide || side == ColumnEndSide) ? GridResolvedPosition::explicitGridColumnCount(gridContainerStyle) : GridResolvedPosition::explicitGridRowCount(gridContainerStyle);
 }
 
-static GridResolvedPosition resolveNamedGridLinePositionFromStyle(const ComputedStyle& gridContainerStyle, const GridPosition& position, GridPositionSide side)
+static size_t resolveNamedGridLinePositionFromStyle(const ComputedStyle& gridContainerStyle, const GridPosition& position, GridPositionSide side)
 {
     ASSERT(!position.namedGridLine().isNull());
 
@@ -197,8 +198,8 @@
     NamedGridLinesMap::const_iterator it = gridLinesNames.find(position.namedGridLine());
     if (it == gridLinesNames.end()) {
         if (position.isPositive())
-            return GridResolvedPosition(0);
-        const size_t lastLine = explicitGridSizeForSide(gridContainerStyle, side);
+            return 0;
+        size_t lastLine = explicitGridSizeForSide(gridContainerStyle, side);
         return lastLine;
     }
 
@@ -210,7 +211,7 @@
     return it->value[namedGridLineIndex];
 }
 
-static GridResolvedPosition resolveGridPositionFromStyle(const ComputedStyle& gridContainerStyle, const GridPosition& position, GridPositionSide side)
+static size_t resolveGridPositionFromStyle(const ComputedStyle& gridContainerStyle, const GridPosition& position, GridPositionSide side)
 {
     switch (position.type()) {
     case ExplicitPosition: {
@@ -224,11 +225,11 @@
             return position.integerPosition() - 1;
 
         size_t resolvedPosition = abs(position.integerPosition()) - 1;
-        const size_t endOfTrack = explicitGridSizeForSide(gridContainerStyle, side);
+        size_t endOfTrack = explicitGridSizeForSide(gridContainerStyle, side);
 
         // Per http://lists.w3.org/Archives/Public/www-style/2013Mar/0589.html, we clamp negative value to the first line.
         if (endOfTrack < resolvedPosition)
-            return GridResolvedPosition(0);
+            return 0;
 
         return endOfTrack - resolvedPosition;
     }
@@ -255,16 +256,16 @@
         // this function in GridResolvedPosition::resolveGridPositionsFromStyle(). We should be also covered by the
         // ASSERT at the beginning of this block.
         ASSERT_NOT_REACHED();
-        return GridResolvedPosition(0);
+        return 0;
     }
     case AutoPosition:
     case SpanPosition:
         // 'auto' and span depend on the opposite position for resolution (e.g. grid-row: auto / 1 or grid-column: span 3 / "myHeader").
         ASSERT_NOT_REACHED();
-        return GridResolvedPosition(0);
+        return 0;
     }
     ASSERT_NOT_REACHED();
-    return GridResolvedPosition(0);
+    return 0;
 }
 
 GridSpan GridResolvedPosition::resolveGridPositionsFromStyle(const ComputedStyle& gridContainerStyle, const LayoutBox& gridItem, GridTrackSizingDirection direction)
@@ -282,23 +283,23 @@
 
     if (initialPosition.shouldBeResolvedAgainstOppositePosition()) {
         // Infer the position from the final position ('auto / 1' or 'span 2 / 3' case).
-        GridResolvedPosition finalResolvedPosition = resolveGridPositionFromStyle(gridContainerStyle, finalPosition, finalSide);
+        size_t finalResolvedPosition = resolveGridPositionFromStyle(gridContainerStyle, finalPosition, finalSide);
         return resolveGridPositionAgainstOppositePosition(gridContainerStyle, finalResolvedPosition, initialPosition, initialSide);
     }
 
     if (finalPosition.shouldBeResolvedAgainstOppositePosition()) {
         // Infer our position from the initial position ('1 / auto' or '3 / span 2' case).
-        GridResolvedPosition initialResolvedPosition = resolveGridPositionFromStyle(gridContainerStyle, initialPosition, initialSide);
+        size_t initialResolvedPosition = resolveGridPositionFromStyle(gridContainerStyle, initialPosition, initialSide);
         return resolveGridPositionAgainstOppositePosition(gridContainerStyle, initialResolvedPosition, finalPosition, finalSide);
     }
 
-    GridResolvedPosition resolvedInitialPosition = resolveGridPositionFromStyle(gridContainerStyle, initialPosition, initialSide);
-    GridResolvedPosition resolvedFinalPosition = resolveGridPositionFromStyle(gridContainerStyle, finalPosition, finalSide);
+    size_t resolvedInitialPosition = resolveGridPositionFromStyle(gridContainerStyle, initialPosition, initialSide);
+    size_t resolvedFinalPosition = resolveGridPositionFromStyle(gridContainerStyle, finalPosition, finalSide);
 
     if (resolvedFinalPosition < resolvedInitialPosition)
         std::swap(resolvedFinalPosition, resolvedInitialPosition);
     else if (resolvedFinalPosition == resolvedInitialPosition)
-        resolvedFinalPosition = resolvedInitialPosition.next();
+        resolvedFinalPosition = resolvedInitialPosition + 1;
 
     return GridSpan::definiteGridSpan(resolvedInitialPosition, resolvedFinalPosition);
 }
diff --git a/third_party/WebKit/Source/core/style/GridResolvedPosition.h b/third_party/WebKit/Source/core/style/GridResolvedPosition.h
index add326d..6d4a77e 100644
--- a/third_party/WebKit/Source/core/style/GridResolvedPosition.h
+++ b/third_party/WebKit/Source/core/style/GridResolvedPosition.h
@@ -26,73 +26,12 @@
     ForRows
 };
 
-// This class represents a line index into one of the dimensions of the grid array.
-// Wraps a size_t integer just for the purpose of knowing what we manipulate in the grid code.
+// This is a utility class with all the code related to grid items positions resolution.
+// TODO(rego): Rename class to GridPositionsResolver.
 class GridResolvedPosition {
     DISALLOW_NEW();
 public:
 
-    GridResolvedPosition(size_t position)
-        : m_integerPosition(position)
-    {
-    }
-
-    GridResolvedPosition& operator*()
-    {
-        return *this;
-    }
-
-    GridResolvedPosition& operator++()
-    {
-        m_integerPosition++;
-        return *this;
-    }
-
-    bool operator==(const GridResolvedPosition& other) const
-    {
-        return m_integerPosition == other.m_integerPosition;
-    }
-
-    bool operator!=(const GridResolvedPosition& other) const
-    {
-        return m_integerPosition != other.m_integerPosition;
-    }
-
-    bool operator<(const GridResolvedPosition& other) const
-    {
-        return m_integerPosition < other.m_integerPosition;
-    }
-
-    bool operator>(const GridResolvedPosition& other) const
-    {
-        return m_integerPosition > other.m_integerPosition;
-    }
-
-    bool operator<=(const GridResolvedPosition& other) const
-    {
-        return m_integerPosition <= other.m_integerPosition;
-    }
-
-    bool operator>=(const GridResolvedPosition& other) const
-    {
-        return m_integerPosition >= other.m_integerPosition;
-    }
-
-    size_t toInt() const
-    {
-        return m_integerPosition;
-    }
-
-    GridResolvedPosition next() const
-    {
-        return GridResolvedPosition(m_integerPosition + 1);
-    }
-
-    GridResolvedPosition prev() const
-    {
-        return GridResolvedPosition(m_integerPosition > 0 ? m_integerPosition - 1 : 0);
-    }
-
     static size_t explicitGridColumnCount(const ComputedStyle&);
     static size_t explicitGridRowCount(const ComputedStyle&);
 
@@ -101,12 +40,9 @@
     static GridPositionSide initialPositionSide(GridTrackSizingDirection);
     static GridPositionSide finalPositionSide(GridTrackSizingDirection);
 
-    static GridSpan resolveGridPositionsFromAutoPlacementPosition(const ComputedStyle&, const LayoutBox&, GridTrackSizingDirection, const GridResolvedPosition&);
+    static GridSpan resolveGridPositionsFromAutoPlacementPosition(const ComputedStyle&, const LayoutBox&, GridTrackSizingDirection, size_t resolvedInitialPosition);
     static GridSpan resolveGridPositionsFromStyle(const ComputedStyle&, const LayoutBox&, GridTrackSizingDirection);
 
-private:
-
-    size_t m_integerPosition;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/svg/SVGElement.cpp b/third_party/WebKit/Source/core/svg/SVGElement.cpp
index be63df4..f98217d3 100644
--- a/third_party/WebKit/Source/core/svg/SVGElement.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGElement.cpp
@@ -989,9 +989,6 @@
     }
 
     svgRareData()->elementInstances().clear();
-
-    if (inDocument())
-        document().updateLayoutTreeIfNeeded();
 }
 
 SVGElement::InstanceUpdateBlocker::InstanceUpdateBlocker(SVGElement* targetElement)
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineEventOverview.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineEventOverview.js
index 6280071..bbafd2e6 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineEventOverview.js
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineEventOverview.js
@@ -40,10 +40,8 @@
     WebInspector.TimelineOverviewBase.call(this);
     this.element.id = "timeline-overview-" + id;
     this.element.classList.add("overview-strip");
-    if (title) {
-        this._placeholder = this.element.createChild("div", "timeline-overview-strip-placeholder");
-        this._placeholder.textContent = title;
-    }
+    if (title)
+        this.element.createChild("div", "timeline-overview-strip-title").textContent = title;
     this._model = model;
 }
 
@@ -442,11 +440,13 @@
  */
 WebInspector.TimelineFilmStripOverview = function(model, tracingModel)
 {
-    WebInspector.TimelineEventOverview.call(this, "filmstrip", "Screenshots", model);
+    WebInspector.TimelineEventOverview.call(this, "filmstrip", null, model);
     this._tracingModel = tracingModel;
     this.reset();
 }
 
+WebInspector.TimelineFilmStripOverview.Padding = 2;
+
 WebInspector.TimelineFilmStripOverview.prototype = {
     /**
      * @override
@@ -479,8 +479,8 @@
             if (!naturalHeight)
                 return;
             var naturalWidth = image.naturalWidth;
-            this._imageHeight = this._canvas.height - 10
-            this._imageWidth = Math.floor(this._imageHeight * naturalWidth / naturalHeight);
+            this._imageHeight = this._canvas.height - 2 * WebInspector.TimelineFilmStripOverview.Padding;
+            this._imageWidth = Math.ceil(this._imageHeight * naturalWidth / naturalHeight);
         }
     },
 
@@ -516,7 +516,10 @@
             return;
         if (!this._filmStripModel.frames().length)
             return;
+        var padding = WebInspector.TimelineFilmStripOverview.Padding;
         var width = this._canvas.width;
+        var imageWidth = this._imageWidth;
+        var imageHeight = this._imageHeight;
         var zeroTime = this._tracingModel.minimumRecordTime();
         var spanTime = this._tracingModel.maximumRecordTime() - zeroTime;
         var scale = spanTime / width;
@@ -525,28 +528,26 @@
         this._lastDrawGeneration = currentDrawGeneration;
 
         context.beginPath();
-        for (var x = 0; x < width; x += this._imageWidth + 5) {
-            var time = zeroTime + (x + this._imageWidth / 2) * scale;
+        for (var x = padding; x < width; x += imageWidth + 2 * padding) {
+            var time = zeroTime + (x + imageWidth / 2) * scale;
             var frame = this._frameByTime(time);
-            context.rect(x + 0.5, 3.5, this._imageWidth + 1, this._imageHeight + 1);
-            this._imageByFrame(frame).then(drawFrameImage.bind(this, x, this._imageWidth, this._imageHeight));
+            context.rect(x - 0.5, 0.5, imageWidth + 1, imageHeight + 1);
+            this._imageByFrame(frame).then(drawFrameImage.bind(this, x));
         }
         context.strokeStyle = "#ddd";
         context.stroke();
 
         /**
          * @param {number} x
-         * @param {number} width
-         * @param {number} height
          * @param {!HTMLImageElement} image
          * @this {WebInspector.TimelineFilmStripOverview}
          */
-        function drawFrameImage(x, width, height, image)
+        function drawFrameImage(x, image)
         {
             // Ignore draws deferred from a previous update call.
             if (this._lastDrawGeneration !== currentDrawGeneration)
                 return;
-            context.drawImage(image, x + 1, 4, width, height);
+            context.drawImage(image, x, 1, imageWidth, imageHeight);
         }
     },
 
@@ -691,7 +692,7 @@
  */
 WebInspector.TimelineEventOverview.Memory = function(model)
 {
-    WebInspector.TimelineEventOverview.call(this, "memory", "Memory", model);
+    WebInspector.TimelineEventOverview.call(this, "memory", WebInspector.UIString("HEAP"), model);
     this._heapSizeLabel = this.element.createChild("div", "memory-graph-label");
 }
 
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineTreeView.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineTreeView.js
index 1c35c2e..4d078be7 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineTreeView.js
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineTreeView.js
@@ -300,7 +300,7 @@
         this._detailsView.element.removeChildren();
         if (!selectedNode || !this._showDetailsForNode(selectedNode)) {
             var banner = this._detailsView.element.createChild("div", "banner");
-            banner.createTextChild(WebInspector.UIString("No details are available for current selection."));
+            banner.createTextChild(WebInspector.UIString("Select item for details."));
         }
     },
 
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js
index fd8ece2..465a300 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js
@@ -740,6 +740,9 @@
     case recordTypes.CancelIdleCallback:
         contentHelper.appendTextRow(WebInspector.UIString("Callback ID"), eventData["id"]);
         break;
+    case recordTypes.EventDispatch:
+        contentHelper.appendTextRow(WebInspector.UIString("Type"), eventData["type"]);
+        break;
 
     default:
         var detailsNode = WebInspector.TimelineUIUtils.buildDetailsNodeForTraceEvent(event, model.target(), linkifier);
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/timelinePanel.css b/third_party/WebKit/Source/devtools/front_end/timeline/timelinePanel.css
index 0c70f73..1641e3e8 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/timelinePanel.css
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/timelinePanel.css
@@ -41,7 +41,6 @@
 .panel.layers .banner {
     color: #777;
     background-color: white;
-    font-size: 14px;
     display: flex;
     justify-content: center;
     align-items: center;
@@ -287,15 +286,15 @@
     justify-content: center;
 }
 
-#timeline-overview-panel .overview-strip .timeline-overview-strip-placeholder {
+#timeline-overview-panel .overview-strip .timeline-overview-strip-title {
     color: #666;
     font-size: 10px;
     font-weight: bold;
     z-index: 100;
     background-color: rgba(255, 255, 255, 0.7);
-    padding: 1px 4px;
+    padding: 0 4px;
     position: absolute;
-    top: 0px;
+    top: 0;
     right: 0;
 }
 
@@ -304,26 +303,24 @@
 }
 
 #timeline-overview-network,
-#timeline-overview-framerate,
-#timeline-overview-memory {
+#timeline-overview-framerate {
     flex-basis: 20px;
 }
 
 #timeline-overview-filmstrip {
-    flex-basis: 81px;
+    flex-basis: 40px;
+}
+
+#timeline-overview-memory {
+    flex-basis: 22px;
 }
 
 .overview-strip::before {
     content: "";
     position: absolute;
-    right: 0;
-    top: 0;
-    bottom: 0;
     left: 0;
-    color: #888;
-    text-align: right;
-    padding: 1px 4px;
-    font-size: 9px;
+    right: 0;
+    bottom: 0;
     border-bottom: 1px solid hsla(0, 0%, 0%, 0.06);
     z-index: -200;
 }
@@ -332,10 +329,6 @@
     display: none;
 }
 
-#timeline-overview-cpu-activity .background {
-    z-index: -10;
-}
-
 #timeline-overview-responsiveness {
     flex-basis: 6px;
     margin-top: 1px !important;
@@ -441,7 +434,7 @@
 .memory-graph-label {
     position: absolute;
     right: 0;
-    top: 0;
+    bottom: 0;
     font-size: 9px;
     color: #888;
     white-space: nowrap;
@@ -676,14 +669,15 @@
 
 .timeline-details-view-row {
     display: flex;
-    border-bottom: 1px solid #e1e1e1;
+    box-shadow: #ccc 1px 1px 3px;
+    flex-direction: column;
+    background-color: white;
+    margin: 4px 4px 5px 4px;
 }
 
 .timeline-details-view-row-title {
-    font-weight: bold;
-    color: rgb(48, 57, 66);
-    width: 170px;
-    line-height: 24px;
+    color: rgb(152, 152, 152);
+    line-height: 21px;
     padding-left: 10px;
     flex: none;
     position: relative;
@@ -708,11 +702,14 @@
 }
 
 .timeline-details-view-row-value {
-    padding-left: 10px;
-    border-left: 1px solid #e1e1e1;
+    padding-left: 30px;
     min-height: 24px;
     line-height: 24px;
     -webkit-user-select: text;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+    overflow: hidden;
+    margin-right: 5px;
 }
 
 .timeline-details-view-row-value .stack-preview-container {
@@ -731,7 +728,6 @@
 
 .timeline-details-view-pie-chart-wrapper {
     margin: 8px 10px 8px 0;
-    min-height: 144px;
 }
 
 .timeline-details-view-pie-chart {
@@ -1018,6 +1014,7 @@
     text-align: right;
     overflow: hidden;
     text-overflow: ellipsis;
+    margin-left: 5px;
 }
 
 .timeline-tree-view .data-grid .background-bar-container {
@@ -1045,3 +1042,16 @@
 .timeline-details #filter-input-field {
     width: 120px;
 }
+
+.timeline-tree-view .data-grid .header-container {
+    height: 21px;
+}
+
+.timeline-tree-view .data-grid .data-container {
+    top: 21px;
+}
+
+.timeline-tree-view .data-grid th {
+    border-bottom: 1px solid #ddd;
+    background-color: #f3f3f3
+}
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/UIUtils.js b/third_party/WebKit/Source/devtools/front_end/ui/UIUtils.js
index 68aff2e..85d1212 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/UIUtils.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/UIUtils.js
@@ -1368,8 +1368,10 @@
              */
             function toggleCheckbox(event)
             {
-                if (event.target !== checkboxElement && event.target !== this)
+                if (event.target !== checkboxElement && event.target !== this) {
+                    event.consume();
                     checkboxElement.click();
+                }
             }
 
             this._root.createChild("content");
diff --git a/third_party/WebKit/Source/platform/exported/WebURLResponse.cpp b/third_party/WebKit/Source/platform/exported/WebURLResponse.cpp
index 6998d9a..46f5dbf 100644
--- a/third_party/WebKit/Source/platform/exported/WebURLResponse.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebURLResponse.cpp
@@ -305,11 +305,6 @@
     m_private->m_resourceResponse->setSecurityInfo(securityInfo);
 }
 
-void WebURLResponse::setHasMajorCertificateErrors(bool value)
-{
-    m_private->m_resourceResponse->setHasMajorCertificateErrors(value);
-}
-
 WebURLResponse::SecurityStyle WebURLResponse::securityStyle() const
 {
     return static_cast<SecurityStyle>(m_private->m_resourceResponse->securityStyle());
diff --git a/third_party/WebKit/Source/platform/network/ResourceResponse.cpp b/third_party/WebKit/Source/platform/network/ResourceResponse.cpp
index 1ba750e5..37de0b6 100644
--- a/third_party/WebKit/Source/platform/network/ResourceResponse.cpp
+++ b/third_party/WebKit/Source/platform/network/ResourceResponse.cpp
@@ -48,7 +48,6 @@
     , m_date(0.0)
     , m_expires(0.0)
     , m_lastModified(0.0)
-    , m_hasMajorCertificateErrors(false)
     , m_securityStyle(SecurityStyleUnknown)
     , m_httpVersion(HTTPVersionUnknown)
     , m_appCacheID(0)
@@ -85,7 +84,6 @@
     , m_date(0.0)
     , m_expires(0.0)
     , m_lastModified(0.0)
-    , m_hasMajorCertificateErrors(false)
     , m_securityStyle(SecurityStyleUnknown)
     , m_httpVersion(HTTPVersionUnknown)
     , m_appCacheID(0)
@@ -118,7 +116,6 @@
     response->setLastModifiedDate(data->m_lastModifiedDate);
     response->setResourceLoadTiming(data->m_resourceLoadTiming.release());
     response->m_securityInfo = data->m_securityInfo;
-    response->m_hasMajorCertificateErrors = data->m_hasMajorCertificateErrors;
     response->m_securityStyle = data->m_securityStyle;
     response->m_securityDetails.protocol = data->m_securityDetails.protocol;
     response->m_securityDetails.cipher = data->m_securityDetails.cipher;
@@ -164,7 +161,6 @@
     if (m_resourceLoadTiming)
         data->m_resourceLoadTiming = m_resourceLoadTiming->deepCopy();
     data->m_securityInfo = CString(m_securityInfo.data(), m_securityInfo.length());
-    data->m_hasMajorCertificateErrors = m_hasMajorCertificateErrors;
     data->m_securityStyle = m_securityStyle;
     data->m_securityDetails.protocol = m_securityDetails.protocol.isolatedCopy();
     data->m_securityDetails.cipher = m_securityDetails.cipher.isolatedCopy();
diff --git a/third_party/WebKit/Source/platform/network/ResourceResponse.h b/third_party/WebKit/Source/platform/network/ResourceResponse.h
index 9c19606..58080de3 100644
--- a/third_party/WebKit/Source/platform/network/ResourceResponse.h
+++ b/third_party/WebKit/Source/platform/network/ResourceResponse.h
@@ -160,9 +160,6 @@
     const CString& getSecurityInfo() const { return m_securityInfo; }
     void setSecurityInfo(const CString& securityInfo) { m_securityInfo = securityInfo; }
 
-    bool hasMajorCertificateErrors() const { return m_hasMajorCertificateErrors; }
-    void setHasMajorCertificateErrors(bool hasMajorCertificateErrors) { m_hasMajorCertificateErrors = hasMajorCertificateErrors; }
-
     SecurityStyle securityStyle() const { return m_securityStyle; }
     void setSecurityStyle(SecurityStyle securityStyle) { m_securityStyle = securityStyle; }
 
@@ -271,10 +268,6 @@
     // string if not over HTTPS).
     CString m_securityInfo;
 
-    // True if the resource was retrieved by the embedder in spite of
-    // certificate errors.
-    bool m_hasMajorCertificateErrors;
-
     // The security style of the resource.
     // This only contains a valid value when the DevTools Network domain is
     // enabled. (Otherwise, it contains a default value of Unknown.)
@@ -364,7 +357,6 @@
     time_t m_lastModifiedDate;
     RefPtr<ResourceLoadTiming> m_resourceLoadTiming;
     CString m_securityInfo;
-    bool m_hasMajorCertificateErrors;
     ResourceResponse::SecurityStyle m_securityStyle;
     ResourceResponse::SecurityDetails m_securityDetails;
     ResourceResponse::HTTPVersion m_httpVersion;
diff --git a/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp b/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp
index 19de8ca..df4026a 100644
--- a/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp
+++ b/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp
@@ -677,18 +677,6 @@
         m_webFrame->client()->didDispatchPingLoader(m_webFrame, url);
 }
 
-void FrameLoaderClientImpl::didDisplayContentWithCertificateErrors(const KURL& url, const CString& securityInfo, const WebURL& mainResourceUrl, const CString& mainResourceSecurityInfo)
-{
-    if (m_webFrame->client())
-        m_webFrame->client()->didDisplayContentWithCertificateErrors(url, securityInfo, mainResourceUrl, mainResourceSecurityInfo);
-}
-
-void FrameLoaderClientImpl::didRunContentWithCertificateErrors(const KURL& url, const CString& securityInfo, const WebURL& mainResourceUrl, const CString& mainResourceSecurityInfo)
-{
-    if (m_webFrame->client())
-        m_webFrame->client()->didRunContentWithCertificateErrors(url, securityInfo, mainResourceUrl, mainResourceSecurityInfo);
-}
-
 void FrameLoaderClientImpl::didChangePerformanceTiming()
 {
     if (m_webFrame->client())
diff --git a/third_party/WebKit/Source/web/FrameLoaderClientImpl.h b/third_party/WebKit/Source/web/FrameLoaderClientImpl.h
index 360f5b00..518325b 100644
--- a/third_party/WebKit/Source/web/FrameLoaderClientImpl.h
+++ b/third_party/WebKit/Source/web/FrameLoaderClientImpl.h
@@ -113,8 +113,6 @@
     void didRunInsecureContent(SecurityOrigin*, const KURL& insecureURL) override;
     void didDetectXSS(const KURL&, bool didBlockEntirePage) override;
     void didDispatchPingLoader(const KURL&) override;
-    void didDisplayContentWithCertificateErrors(const KURL&, const CString& securityInfo, const WebURL& mainResourceUrl, const CString& mainResourceSecurityInfo) override;
-    void didRunContentWithCertificateErrors(const KURL&, const CString& securityInfo, const WebURL& mainResourceUrl, const CString& mainResourceSecurityInfo) override;
     void didChangePerformanceTiming() override;
     void selectorMatchChanged(const Vector<String>& addedSelectors, const Vector<String>& removedSelectors) override;
     PassRefPtrWillBeRawPtr<DocumentLoader> createDocumentLoader(LocalFrame*, const ResourceRequest&, const SubstituteData&) override;
diff --git a/third_party/WebKit/public/platform/WebURLResponse.h b/third_party/WebKit/public/platform/WebURLResponse.h
index 3a64468..c7a5b0b 100644
--- a/third_party/WebKit/public/platform/WebURLResponse.h
+++ b/third_party/WebKit/public/platform/WebURLResponse.h
@@ -146,8 +146,6 @@
     BLINK_PLATFORM_EXPORT WebCString securityInfo() const;
     BLINK_PLATFORM_EXPORT void setSecurityInfo(const WebCString&);
 
-    BLINK_PLATFORM_EXPORT void setHasMajorCertificateErrors(bool);
-
     BLINK_PLATFORM_EXPORT SecurityStyle securityStyle() const;
     BLINK_PLATFORM_EXPORT void setSecurityStyle(SecurityStyle);
 
diff --git a/third_party/WebKit/public/web/WebFrameClient.h b/third_party/WebKit/public/web/WebFrameClient.h
index 89f2cef..e603a05 100644
--- a/third_party/WebKit/public/web/WebFrameClient.h
+++ b/third_party/WebKit/public/web/WebFrameClient.h
@@ -67,7 +67,6 @@
 class WebColorChooserClient;
 class WebContentDecryptionModule;
 class WebCookieJar;
-class WebCString;
 class WebDataSource;
 class WebEncryptedMediaClient;
 class WebExternalPopupMenu;
@@ -450,13 +449,6 @@
     // A PingLoader was created, and a request dispatched to a URL.
     virtual void didDispatchPingLoader(WebLocalFrame*, const WebURL&) { }
 
-    // This frame has displayed inactive content (such as an image) from
-    // a connection with certificate errors.
-    virtual void didDisplayContentWithCertificateErrors(const WebURL& url, const WebCString& securityInfo, const WebURL& mainResourceUrl, const WebCString& mainResourceSecurityInfo) {}
-    // This frame has run active content (such as a script) from a
-    // connection with certificate errors.
-    virtual void didRunContentWithCertificateErrors(const WebURL& url, const WebCString& securityInfo, const WebURL& mainResourceUrl, const WebCString& mainResourceSecurityInfo) {}
-
     // A performance timing event (e.g. first paint) occurred
     virtual void didChangePerformanceTiming() { }
 
diff --git a/third_party/mojo/src/mojo/edk/embedder/embedder.cc b/third_party/mojo/src/mojo/edk/embedder/embedder.cc
index 692547ac..00c48ea 100644
--- a/third_party/mojo/src/mojo/edk/embedder/embedder.cc
+++ b/third_party/mojo/src/mojo/edk/embedder/embedder.cc
@@ -65,6 +65,7 @@
 
   void OnShutdownComplete() {
     passed_in_delegate_->OnShutdownComplete();
+    delete this;
   }
 
  private:
@@ -248,6 +249,8 @@
   internal::g_ipc_support->ShutdownOnIOThread();
   delete internal::g_ipc_support;
   internal::g_ipc_support = nullptr;
+  delete g_wrapper_process_delegate;
+  g_wrapper_process_delegate = nullptr;
 }
 
 void ShutdownIPCSupport() {
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 5ea6df9..389e013 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -367,16 +367,6 @@
   </summary>
 </histogram>
 
-<histogram name="AppBanners.MinutesFromFirstVisitToBannerShown" units="minutes">
-  <owner>dominickn@chromium.org</owner>
-  <summary>
-    App banners promote an application related to the current website, and are
-    requested specifically through the current page's HTML.  This stat tracks
-    the number of minutes between the first recorded visit to an origin and the
-    time when the banner is actually shown.
-  </summary>
-</histogram>
-
 <histogram name="AppBanners.UserResponse" enum="AppBannersUserResponse">
   <owner>dominickn@chromium.org</owner>
   <summary>
@@ -79775,6 +79765,9 @@
   <suffix name="ContentLength_Image_WEBP"
       label="for each carrier, number of WebP image responses whose
              Content-Length header has been tampered with"/>
+  <suffix name="ContentLength_Video"
+      label="for each carrier, number of video responses whose Content-Length
+             header has been tampered with"/>
   <suffix name="CompressionRatio_Image"
       label="the histogram of compression ratio of images"/>
   <suffix name="CompressionRatio_Image_GIF"
@@ -79785,6 +79778,8 @@
       label="the histogram of compression ratio of PNG images"/>
   <suffix name="CompressionRatio_Image_WEBP"
       label="the histogram of compression ratio of WEBP images"/>
+  <suffix name="CompressionRatio_Video"
+      label="the histogram of compression ratio of videos"/>
   <suffix name="CompressionRatio_Image_0_10KB"
       label="the histogram of compression ratio of images whose sizes are in
              the range of 0-10KB"/>
@@ -79838,6 +79833,8 @@
   <affected-histogram
       name="DataReductionProxy.HeaderTamperDetectionHTTP_Image_WEBP"/>
   <affected-histogram name="DataReductionProxy.HeaderTamperDetectionHTTP_JS"/>
+  <affected-histogram
+      name="DataReductionProxy.HeaderTamperDetectionHTTP_Video"/>
   <affected-histogram name="DataReductionProxy.HeaderTamperDetectionHTTPS"/>
   <affected-histogram name="DataReductionProxy.HeaderTamperDetectionHTTPS_CSS"/>
   <affected-histogram
@@ -79859,6 +79856,8 @@
   <affected-histogram
       name="DataReductionProxy.HeaderTamperDetectionHTTPS_Image_WEBP"/>
   <affected-histogram name="DataReductionProxy.HeaderTamperDetectionHTTPS_JS"/>
+  <affected-histogram
+      name="DataReductionProxy.HeaderTamperDetectionHTTPS_Video"/>
   <affected-histogram name="DataReductionProxy.HeaderTamperDetectionPassHTTP"/>
   <affected-histogram name="DataReductionProxy.HeaderTamperDetectionPassHTTPS"/>
   <affected-histogram name="DataReductionProxy.HeaderTamperedHTTP_ChromeProxy"/>
@@ -79903,6 +79902,7 @@
   <suffix name="Image_JPG" label="JPG image count"/>
   <suffix name="Image_PNG" label="PNG image count"/>
   <suffix name="Image_WEBP" label="WEBP image count"/>
+  <suffix name="Video" label="Video count"/>
   <suffix name="Image_0_10KB" label="image counts of 0-10KB"/>
   <suffix name="Image_10_100KB" label="image counts of 10-100KB"/>
   <suffix name="Image_100_500KB" label="image counts of 100-500KB"/>
diff --git a/tools/telemetry/telemetry/record_wpr.py b/tools/telemetry/telemetry/record_wpr.py
index 0cd8241..c53f35a 100644
--- a/tools/telemetry/telemetry/record_wpr.py
+++ b/tools/telemetry/telemetry/record_wpr.py
@@ -17,6 +17,8 @@
 from telemetry.internal.util import command_line
 from telemetry.page import page_test
 from telemetry.util import wpr_modes
+from telemetry.web_perf import timeline_based_measurement
+from telemetry.web_perf import timeline_based_page_test
 
 
 class RecorderPageTest(page_test.PageTest):
@@ -128,9 +130,11 @@
     self._ParseArgs(args)
     self._ProcessCommandLineArgs()
     if self._benchmark is not None:
+      test = self._benchmark.CreatePageTest(self.options)
+      if isinstance(test, timeline_based_measurement.TimelineBasedMeasurement):
+        test = timeline_based_page_test.TimelineBasedPageTest(test)
       # This must be called after the command line args are added.
-      self._record_page_test.page_test = self._benchmark.CreatePageTest(
-          self.options)
+      self._record_page_test.page_test = test
 
     self._page_set_base_dir = (
         self._options.page_set_base_dir if self._options.page_set_base_dir
diff --git a/tools/telemetry/telemetry/record_wpr_unittest.py b/tools/telemetry/telemetry/record_wpr_unittest.py
index e313679..471584f 100644
--- a/tools/telemetry/telemetry/record_wpr_unittest.py
+++ b/tools/telemetry/telemetry/record_wpr_unittest.py
@@ -67,7 +67,28 @@
 
 class MockBenchmark(benchmark.Benchmark):
   test = MockPageTest
-  mock_story_set = None
+
+  def __init__(self):
+    super(MockBenchmark, self).__init__()
+    self.mock_story_set = None
+
+  @classmethod
+  def AddBenchmarkCommandLineArgs(cls, group):
+    group.add_option('', '--mock-benchmark-url', action='store', type='string')
+
+  def CreateStorySet(self, options):
+    kwargs = {}
+    if options.mock_benchmark_url:
+      kwargs['url'] = options.mock_benchmark_url
+    self.mock_story_set = MockStorySet(**kwargs)
+    return self.mock_story_set
+
+
+class MockTimelineBasedMeasurementBenchmark(benchmark.Benchmark):
+
+  def __init__(self):
+    super(MockTimelineBasedMeasurementBenchmark, self).__init__()
+    self.mock_story_set = None
 
   @classmethod
   def AddBenchmarkCommandLineArgs(cls, group):
@@ -148,6 +169,17 @@
     self.assertEqual(set(mock_benchmark.mock_story_set.stories),
                      results.pages_that_succeeded)
 
+  def testWprRecorderWithTimelineBasedMeasurementBenchmark(self):
+    flags = self.GetBrowserDeviceFlags()
+    flags.extend(['--mock-benchmark-url', self._url])
+    mock_benchmark = MockTimelineBasedMeasurementBenchmark()
+    wpr_recorder = record_wpr.WprRecorder(self._test_data_dir, mock_benchmark,
+                                          flags)
+    results = wpr_recorder.CreateResults()
+    wpr_recorder.Record(results)
+    self.assertEqual(set(mock_benchmark.mock_story_set.stories),
+                     results.pages_that_succeeded)
+
   def testPageSetBaseDirFlag(self):
     flags = self.GetBrowserDeviceFlags()
     flags.extend(['--page-set-base-dir', self._test_data_dir,