diff --git a/DEPS b/DEPS
index 0fca891..fc0213b 100644
--- a/DEPS
+++ b/DEPS
@@ -78,7 +78,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': 'fb9e2b3a47879f6347907045d5c86b6bcf242280',
+  'v8_revision': 'f5d857d30b6d37becadd73b3cb046b86b8d0cfb9',
   # 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.
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
index 57ca2c00..13de1a2 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
@@ -1223,6 +1223,39 @@
   EXPECT_TRUE(tester.HistoryContainsURL(kOrigin2));
 }
 
+TEST_F(ChromeBrowsingDataRemoverDelegateTest, RemoveHistoryForOlderThan30Days) {
+  RemoveHistoryTester tester;
+  ASSERT_TRUE(tester.Init(GetProfile()));
+
+  base::Time older_than_29days =
+      base::Time::Now() - base::TimeDelta::FromDays(29);
+  base::Time older_than_30days =
+      base::Time::Now() - base::TimeDelta::FromDays(30);
+  base::Time older_than_31days =
+      base::Time::Now() - base::TimeDelta::FromDays(31);
+
+  tester.AddHistory(kOrigin1, base::Time::Now());
+  tester.AddHistory(kOrigin2, older_than_29days);
+  tester.AddHistory(kOrigin3, older_than_31days);
+
+  ASSERT_TRUE(tester.HistoryContainsURL(kOrigin1));
+  ASSERT_TRUE(tester.HistoryContainsURL(kOrigin2));
+  ASSERT_TRUE(tester.HistoryContainsURL(kOrigin3));
+
+  BlockUntilBrowsingDataRemoved(
+      base::Time(), older_than_30days,
+      ChromeBrowsingDataRemoverDelegate::DATA_TYPE_HISTORY, false);
+
+  EXPECT_EQ(ChromeBrowsingDataRemoverDelegate::DATA_TYPE_HISTORY,
+            GetRemovalMask());
+  EXPECT_EQ(content::BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB,
+            GetOriginTypeMask());
+
+  EXPECT_TRUE(tester.HistoryContainsURL(kOrigin1));
+  EXPECT_TRUE(tester.HistoryContainsURL(kOrigin2));
+  EXPECT_FALSE(tester.HistoryContainsURL(kOrigin3));
+}
+
 // This should crash (DCHECK) in Debug, but death tests don't work properly
 // here.
 // TODO(msramek): To make this testable, the refusal to delete history should
diff --git a/chrome/browser/browsing_data/history_counter_browsertest.cc b/chrome/browser/browsing_data/history_counter_browsertest.cc
index 7379b9b..dfe8a5c1 100644
--- a/chrome/browser/browsing_data/history_counter_browsertest.cc
+++ b/chrome/browser/browsing_data/history_counter_browsertest.cc
@@ -240,6 +240,11 @@
   AddVisit("https://www.example.com");
   AddVisit("https://www.example.com");
 
+  RevertTimeInDays(100);
+  AddVisit("https://www.google.com");
+  AddVisit("https://www.example.com");
+  AddVisit("https://www.example.com");
+
   Profile* profile = browser()->profile();
 
   HistoryCounter counter(
@@ -270,7 +275,11 @@
 
   SetDeletionPeriodPref(browsing_data::TimePeriod::ALL_TIME);
   WaitForCounting();
-  EXPECT_EQ(9u, GetLocalResult());
+  EXPECT_EQ(11u, GetLocalResult());
+
+  SetDeletionPeriodPref(browsing_data::TimePeriod::OLDER_THAN_30_DAYS);
+  WaitForCounting();
+  EXPECT_EQ(3u, GetLocalResult());
 }
 
 // Test the behavior for a profile that syncs history.
diff --git a/chrome/browser/media/webrtc/webrtc_rtp_browsertest.cc b/chrome/browser/media/webrtc/webrtc_rtp_browsertest.cc
index a24908b..41dec54 100644
--- a/chrome/browser/media/webrtc/webrtc_rtp_browsertest.cc
+++ b/chrome/browser/media/webrtc/webrtc_rtp_browsertest.cc
@@ -22,8 +22,6 @@
 
   void SetUpCommandLine(base::CommandLine* command_line) override {
     command_line->AppendSwitch(switches::kUseFakeDeviceForMediaStream);
-    command_line->AppendSwitchASCII(switches::kEnableBlinkFeatures,
-                                    "RTCRtpSender");
     // Required by |CollectGarbage|.
     command_line->AppendSwitchASCII(switches::kJavaScriptFlags, "--expose-gc");
   }
@@ -78,8 +76,7 @@
   VerifyRtpReceivers(right_tab_, 6);
 }
 
-IN_PROC_BROWSER_TEST_F(WebRtcRtpBrowserTest,
-                       DISABLED_AddAndRemoveTracksWithoutStream) {
+IN_PROC_BROWSER_TEST_F(WebRtcRtpBrowserTest, AddAndRemoveTracksWithoutStream) {
   StartServerAndOpenTabs();
 
   SetupPeerconnectionWithoutLocalStream(left_tab_);
@@ -275,7 +272,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(WebRtcRtpBrowserTest,
-                       DISABLED_AddAndRemoveTracksWithIndividualStreams) {
+                       AddAndRemoveTracksWithIndividualStreams) {
   StartServerAndOpenTabs();
 
   SetupPeerconnectionWithoutLocalStream(left_tab_);
diff --git a/chrome/browser/sync/test/integration/single_client_user_events_sync_test.cc b/chrome/browser/sync/test/integration/single_client_user_events_sync_test.cc
index 8638fac..c31485e 100644
--- a/chrome/browser/sync/test/integration/single_client_user_events_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_user_events_sync_test.cc
@@ -23,7 +23,7 @@
 
 namespace {
 
-UserEventSpecifics CreateEvent(int microseconds) {
+UserEventSpecifics CreateTestEvent(int microseconds) {
   UserEventSpecifics specifics;
   specifics.set_event_time_usec(microseconds);
   specifics.set_navigation_id(microseconds);
@@ -31,6 +31,13 @@
   return specifics;
 }
 
+UserEventSpecifics CreateUserConsent(int microseconds) {
+  UserEventSpecifics specifics;
+  specifics.set_event_time_usec(microseconds);
+  specifics.mutable_user_consent();
+  return specifics;
+}
+
 CommitResponse::ResponseType BounceType(
     CommitResponse::ResponseType type,
     const syncer::LoopbackServerEntity& entity) {
@@ -163,6 +170,12 @@
     DisableVerifier();
   }
 
+  bool ExpectUserEvents(std::vector<UserEventSpecifics> expected_specifics) {
+    return UserEventEqualityChecker(GetSyncService(0), GetFakeServer(),
+                                    expected_specifics)
+        .Wait();
+  }
+
  private:
   DISALLOW_COPY_AND_ASSIGN(SingleClientUserEventsSyncTest);
 };
@@ -174,16 +187,15 @@
       GetFakeServer()->GetSyncEntitiesByModelType(syncer::USER_EVENTS).size());
   syncer::UserEventService* event_service =
       browser_sync::UserEventServiceFactory::GetForProfile(GetProfile(0));
-  const UserEventSpecifics specifics = CreateEvent(0);
+  const UserEventSpecifics specifics = CreateTestEvent(0);
   event_service->RecordUserEvent(specifics);
-  UserEventEqualityChecker(GetSyncService(0), GetFakeServer(), {specifics})
-      .Wait();
+  EXPECT_TRUE(ExpectUserEvents({specifics}));
 }
 
 IN_PROC_BROWSER_TEST_F(SingleClientUserEventsSyncTest, RetrySequential) {
   ASSERT_TRUE(SetupSync());
-  const UserEventSpecifics specifics1 = CreateEvent(1);
-  const UserEventSpecifics specifics2 = CreateEvent(2);
+  const UserEventSpecifics specifics1 = CreateTestEvent(1);
+  const UserEventSpecifics specifics2 = CreateTestEvent(2);
   syncer::UserEventService* event_service =
       browser_sync::UserEventServiceFactory::GetForProfile(GetProfile(0));
 
@@ -193,29 +205,24 @@
 
   // This will block until we hit a TRANSIENT_ERROR, at which point we will
   // regain control and can switch back to SUCCESS.
-  UserEventEqualityChecker(GetSyncService(0), GetFakeServer(), {specifics1})
-      .Wait();
+  EXPECT_TRUE(ExpectUserEvents({specifics1}));
   GetFakeServer()->OverrideResponseType(
       base::Bind(&BounceType, CommitResponse::SUCCESS));
   // Because the fake server records commits even on failure, we are able to
   // verify that the commit for this event reached the server twice.
-  UserEventEqualityChecker(GetSyncService(0), GetFakeServer(),
-                           {specifics1, specifics1})
-      .Wait();
+  EXPECT_TRUE(ExpectUserEvents({specifics1, specifics1}));
 
   // Only record |specifics2| after |specifics1| was successful to avoid race
   // conditions.
   event_service->RecordUserEvent(specifics2);
-  UserEventEqualityChecker(GetSyncService(0), GetFakeServer(),
-                           {specifics1, specifics1, specifics2})
-      .Wait();
+  EXPECT_TRUE(ExpectUserEvents({specifics1, specifics1, specifics2}));
 }
 
 IN_PROC_BROWSER_TEST_F(SingleClientUserEventsSyncTest, RetryParallel) {
   ASSERT_TRUE(SetupSync());
   bool first = true;
-  const UserEventSpecifics specifics1 = CreateEvent(1);
-  const UserEventSpecifics specifics2 = CreateEvent(2);
+  const UserEventSpecifics specifics1 = CreateTestEvent(1);
+  const UserEventSpecifics specifics2 = CreateTestEvent(2);
   UserEventSpecifics retry_specifics;
 
   syncer::UserEventService* event_service =
@@ -229,36 +236,35 @@
 
   event_service->RecordUserEvent(specifics2);
   event_service->RecordUserEvent(specifics1);
-  UserEventEqualityChecker(GetSyncService(0), GetFakeServer(),
-                           {specifics1, specifics2})
-      .Wait();
-  UserEventEqualityChecker(GetSyncService(0), GetFakeServer(),
-                           {specifics1, specifics2, retry_specifics})
-      .Wait();
+  EXPECT_TRUE(ExpectUserEvents({specifics1, specifics2}));
+  EXPECT_TRUE(ExpectUserEvents({specifics1, specifics2, retry_specifics}));
 }
 
 IN_PROC_BROWSER_TEST_F(SingleClientUserEventsSyncTest, NoHistory) {
-  const UserEventSpecifics specifics1 = CreateEvent(1);
-  const UserEventSpecifics specifics2 = CreateEvent(2);
-  const UserEventSpecifics specifics3 = CreateEvent(3);
+  const UserEventSpecifics testEvent1 = CreateTestEvent(1);
+  const UserEventSpecifics testEvent2 = CreateTestEvent(2);
+  const UserEventSpecifics testEvent3 = CreateTestEvent(3);
+  const UserEventSpecifics consent1 = CreateUserConsent(4);
+  const UserEventSpecifics consent2 = CreateUserConsent(5);
+
   ASSERT_TRUE(SetupSync());
   syncer::UserEventService* event_service =
       browser_sync::UserEventServiceFactory::GetForProfile(GetProfile(0));
 
-  event_service->RecordUserEvent(specifics1);
+  event_service->RecordUserEvent(testEvent1);
+  event_service->RecordUserEvent(consent1);
   ASSERT_TRUE(GetClient(0)->DisableSyncForDatatype(syncer::TYPED_URLS));
-  event_service->RecordUserEvent(specifics2);
+  event_service->RecordUserEvent(testEvent2);
+  event_service->RecordUserEvent(consent2);
   ASSERT_TRUE(GetClient(0)->EnableSyncForDatatype(syncer::TYPED_URLS));
-  event_service->RecordUserEvent(specifics3);
+  event_service->RecordUserEvent(testEvent3);
 
-  // No |specifics2| because it was recorded while history was disabled.
-  UserEventEqualityChecker(GetSyncService(0), GetFakeServer(),
-                           {specifics1, specifics3})
-      .Wait();
+  // No |testEvent2| because it was recorded while history was disabled.
+  EXPECT_TRUE(ExpectUserEvents({testEvent1, consent1, consent2, testEvent3}));
 }
 
 IN_PROC_BROWSER_TEST_F(SingleClientUserEventsSyncTest, NoSessions) {
-  const UserEventSpecifics specifics = CreateEvent(1);
+  const UserEventSpecifics specifics = CreateTestEvent(1);
   ASSERT_TRUE(SetupSync());
   ASSERT_TRUE(GetClient(0)->DisableSyncForDatatype(syncer::PROXY_TABS));
   syncer::UserEventService* event_service =
@@ -267,32 +273,33 @@
   event_service->RecordUserEvent(specifics);
 
   // PROXY_TABS shouldn't affect us in any way.
-  UserEventEqualityChecker(GetSyncService(0), GetFakeServer(), {specifics})
-      .Wait();
+  EXPECT_TRUE(ExpectUserEvents({specifics}));
 }
 
 IN_PROC_BROWSER_TEST_F(SingleClientUserEventsSyncTest, Encryption) {
-  const UserEventSpecifics specifics1 = CreateEvent(1);
-  const UserEventSpecifics specifics2 = CreateEvent(2);
+  const UserEventSpecifics testEvent1 = CreateTestEvent(1);
+  const UserEventSpecifics testEvent2 = CreateTestEvent(2);
+  const UserEventSpecifics consent1 = CreateUserConsent(3);
+  const UserEventSpecifics consent2 = CreateUserConsent(4);
 
   ASSERT_TRUE(SetupSync());
   syncer::UserEventService* event_service =
       browser_sync::UserEventServiceFactory::GetForProfile(GetProfile(0));
-  event_service->RecordUserEvent(specifics1);
+  event_service->RecordUserEvent(testEvent1);
+  event_service->RecordUserEvent(consent1);
   ASSERT_TRUE(EnableEncryption(0));
-  UserEventEqualityChecker(GetSyncService(0), GetFakeServer(), {specifics1})
-      .Wait();
-  event_service->RecordUserEvent(specifics2);
+  EXPECT_TRUE(ExpectUserEvents({testEvent1, consent1}));
+  event_service->RecordUserEvent(testEvent2);
+  event_service->RecordUserEvent(consent2);
 
-  // Just checking that we don't see specifics2 isn't very convincing yet,
+  // Just checking that we don't see testEvent2 isn't very convincing yet,
   // because it may simply not have reached the server yet. So lets send
   // something else through the system that we can wait on before checking.
   // Tab/SESSIONS data was picked fairly arbitrarily, note that we expect 2
   // entries, one for the window/header and one for the tab.
   sessions_helper::OpenTab(0, GURL("http://www.one.com/"));
-  ServerCountMatchStatusChecker(syncer::SESSIONS, 2);
-  UserEventEqualityChecker(GetSyncService(0), GetFakeServer(), {specifics1})
-      .Wait();
+  EXPECT_TRUE(ServerCountMatchStatusChecker(syncer::SESSIONS, 2).Wait());
+  EXPECT_TRUE(ExpectUserEvents({testEvent1, consent1, consent2}));
 }
 
 IN_PROC_BROWSER_TEST_F(SingleClientUserEventsSyncTest, FieldTrial) {
diff --git a/components/browsing_data/core/counters/history_counter.cc b/components/browsing_data/core/counters/history_counter.cc
index 376e5e8..cf1f746 100644
--- a/components/browsing_data/core/counters/history_counter.cc
+++ b/components/browsing_data/core/counters/history_counter.cc
@@ -66,7 +66,7 @@
   local_counting_finished_ = false;
 
   history_service_->GetHistoryCount(
-      GetPeriodStart(), base::Time::Max(),
+      GetPeriodStart(), GetPeriodEnd(),
       base::Bind(&HistoryCounter::OnGetLocalHistoryCount,
                  weak_ptr_factory_.GetWeakPtr()),
       &cancelable_task_tracker_);
diff --git a/components/consent_auditor/BUILD.gn b/components/consent_auditor/BUILD.gn
index bd2ecc4f..d308cef 100644
--- a/components/consent_auditor/BUILD.gn
+++ b/components/consent_auditor/BUILD.gn
@@ -25,6 +25,7 @@
 
   deps = [
     ":consent_auditor",
+    "//base/test:test_support",
     "//components/prefs:test_support",
     "//components/sync",
     "//testing/gtest",
diff --git a/components/consent_auditor/consent_auditor.cc b/components/consent_auditor/consent_auditor.cc
index 1dad158..d9da1af5 100644
--- a/components/consent_auditor/consent_auditor.cc
+++ b/components/consent_auditor/consent_auditor.cc
@@ -12,8 +12,11 @@
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 #include "components/prefs/scoped_user_pref_update.h"
+#include "components/sync/driver/sync_driver_switches.h"
 #include "components/sync/user_events/user_event_service.h"
 
+using UserEventSpecifics = sync_pb::UserEventSpecifics;
+
 namespace consent_auditor {
 
 namespace {
@@ -23,6 +26,18 @@
 const char kLocalConsentVersionKey[] = "version";
 const char kLocalConsentLocaleKey[] = "locale";
 
+UserEventSpecifics::UserConsent::ConsentStatus ToProtoEnum(
+    ConsentAuditor::ConsentStatus status) {
+  switch (status) {
+    case ConsentAuditor::ConsentStatus::REVOKED:
+      return UserEventSpecifics::UserConsent::REVOKED;
+    case ConsentAuditor::ConsentStatus::GIVEN:
+      return UserEventSpecifics::UserConsent::GIVEN;
+  }
+  NOTREACHED();
+  return UserEventSpecifics::UserConsent::GIVEN;
+}
+
 }  // namespace
 
 ConsentAuditor::ConsentAuditor(PrefService* pref_service,
@@ -53,8 +68,33 @@
     const std::vector<int>& consent_grd_ids,
     const std::vector<std::string>& placeholder_replacements,
     ConsentStatus status) {
-  // TODO(crbug.com/781765): Implement consent recording.
-  NOTIMPLEMENTED();
+  if (!base::FeatureList::IsEnabled(switches::kSyncUserConsentEvents))
+    return;
+  std::unique_ptr<sync_pb::UserEventSpecifics> specifics = ConstructUserConsent(
+      feature, consent_grd_ids, placeholder_replacements, status);
+  user_event_service_->RecordUserEvent(std::move(specifics));
+}
+
+std::unique_ptr<sync_pb::UserEventSpecifics>
+ConsentAuditor::ConstructUserConsent(
+    const std::string& feature,
+    const std::vector<int>& consent_grd_ids,
+    const std::vector<std::string>& placeholder_replacements,
+    ConsentStatus status) {
+  auto specifics = base::MakeUnique<sync_pb::UserEventSpecifics>();
+  specifics->set_event_time_usec(
+      base::Time::Now().since_origin().InMicroseconds());
+  auto* consent = specifics->mutable_user_consent();
+  consent->set_feature(feature);
+  for (int id : consent_grd_ids) {
+    consent->add_consent_grd_ids(id);
+  }
+  for (const auto& string : placeholder_replacements) {
+    consent->add_placeholder_replacements(string);
+  }
+  consent->set_locale(app_locale_);
+  consent->set_status(ToProtoEnum(status));
+  return specifics;
 }
 
 void ConsentAuditor::RecordLocalConsent(const std::string& feature,
diff --git a/components/consent_auditor/consent_auditor.h b/components/consent_auditor/consent_auditor.h
index 43d800f..672a8a94 100644
--- a/components/consent_auditor/consent_auditor.h
+++ b/components/consent_auditor/consent_auditor.h
@@ -5,6 +5,7 @@
 #ifndef COMPONENTS_CONSENT_AUDITOR_CONSENT_AUDITOR_H_
 #define COMPONENTS_CONSENT_AUDITOR_CONSENT_AUDITOR_H_
 
+#include <memory>
 #include <string>
 #include <vector>
 
@@ -15,6 +16,10 @@
 class UserEventService;
 }
 
+namespace sync_pb {
+class UserEventSpecifics;
+}
+
 class PrefService;
 class PrefRegistrySimple;
 
@@ -56,6 +61,12 @@
                           const std::string& confirmation_text);
 
  private:
+  std::unique_ptr<sync_pb::UserEventSpecifics> ConstructUserConsent(
+      const std::string& feature,
+      const std::vector<int>& consent_grd_ids,
+      const std::vector<std::string>& placeholder_replacements,
+      ConsentAuditor::ConsentStatus status);
+
   PrefService* pref_service_;
   syncer::UserEventService* user_event_service_;
   std::string app_version_;
diff --git a/components/consent_auditor/consent_auditor_unittest.cc b/components/consent_auditor/consent_auditor_unittest.cc
index 09581bf..a2a7e66e 100644
--- a/components/consent_auditor/consent_auditor_unittest.cc
+++ b/components/consent_auditor/consent_auditor_unittest.cc
@@ -6,11 +6,15 @@
 
 #include <memory>
 
+#include "base/test/scoped_feature_list.h"
 #include "components/consent_auditor/pref_names.h"
 #include "components/prefs/testing_pref_service.h"
+#include "components/sync/driver/sync_driver_switches.h"
 #include "components/sync/user_events/fake_user_event_service.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using sync_pb::UserEventSpecifics;
+
 namespace consent_auditor {
 
 namespace {
@@ -85,6 +89,10 @@
 
   PrefService* pref_service() const { return pref_service_.get(); }
 
+  syncer::FakeUserEventService* user_event_service() {
+    return user_event_service_.get();
+  }
+
  private:
   std::unique_ptr<ConsentAuditor> consent_auditor_;
   std::unique_ptr<TestingPrefServiceSimple> pref_service_;
@@ -152,4 +160,45 @@
   EXPECT_EQ(2u, consents->size());
 }
 
+TEST_F(ConsentAuditorTest, RecordingEnabled) {
+  consent_auditor()->RecordGaiaConsent("feature1", {}, {},
+                                       ConsentAuditor::ConsentStatus::GIVEN);
+  auto& events = user_event_service()->GetRecordedUserEvents();
+  EXPECT_EQ(1U, events.size());
+}
+
+TEST_F(ConsentAuditorTest, RecordingDisabled) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndDisableFeature(switches::kSyncUserConsentEvents);
+  consent_auditor()->RecordGaiaConsent("feature1", {}, {},
+                                       ConsentAuditor::ConsentStatus::GIVEN);
+  auto& events = user_event_service()->GetRecordedUserEvents();
+  EXPECT_EQ(0U, events.size());
+}
+
+TEST_F(ConsentAuditorTest, RecordGaiaConsent) {
+  std::vector<int> kMessageIds = {12, 37, 42};
+  std::vector<std::string> kPlaceholders = {"OK.", "user@example.com"};
+  base::Time t1 = base::Time::Now();
+  consent_auditor()->RecordGaiaConsent("feature1", kMessageIds, kPlaceholders,
+                                       ConsentAuditor::ConsentStatus::GIVEN);
+  base::Time t2 = base::Time::Now();
+  auto& events = user_event_service()->GetRecordedUserEvents();
+  EXPECT_EQ(1U, events.size());
+  EXPECT_LE(t1.since_origin().InMicroseconds(), events[0].event_time_usec());
+  EXPECT_GE(t2.since_origin().InMicroseconds(), events[0].event_time_usec());
+  EXPECT_FALSE(events[0].has_navigation_id());
+  EXPECT_TRUE(events[0].has_user_consent());
+  auto& consent = events[0].user_consent();
+  EXPECT_EQ("feature1", consent.feature());
+  EXPECT_EQ(3, consent.consent_grd_ids_size());
+  EXPECT_EQ(12, consent.consent_grd_ids(0));
+  EXPECT_EQ(37, consent.consent_grd_ids(1));
+  EXPECT_EQ(42, consent.consent_grd_ids(2));
+  EXPECT_EQ(2, consent.placeholder_replacements_size());
+  EXPECT_EQ("OK.", consent.placeholder_replacements(0));
+  EXPECT_EQ("user@example.com", consent.placeholder_replacements(1));
+  EXPECT_EQ(kCurrentAppLocale, consent.locale());
+}
+
 }  // namespace consent_auditor
diff --git a/components/history/core/browser/expire_history_backend_unittest.cc b/components/history/core/browser/expire_history_backend_unittest.cc
index 46a4615e..73c83041 100644
--- a/components/history/core/browser/expire_history_backend_unittest.cc
+++ b/components/history/core/browser/expire_history_backend_unittest.cc
@@ -630,6 +630,145 @@
   EXPECT_FALSE(HasFavicon(favicon_id2));
 }
 
+// Expires all URLs visited between two given times, with no starred items.
+TEST_F(ExpireHistoryTest, FlushURLsUnstarredBetweenTwoTimestamps) {
+  URLID url_ids[3];
+  base::Time visit_times[4];
+  AddExampleData(url_ids, visit_times);
+
+  URLRow url_row0, url_row1, url_row2;
+  ASSERT_TRUE(main_db_->GetURLRow(url_ids[0], &url_row0));
+  ASSERT_TRUE(main_db_->GetURLRow(url_ids[1], &url_row1));
+  ASSERT_TRUE(main_db_->GetURLRow(url_ids[2], &url_row2));
+
+  VisitVector visits;
+  main_db_->GetVisitsForURL(url_ids[0], &visits);
+  ASSERT_EQ(1U, visits.size());
+  main_db_->GetVisitsForURL(url_ids[1], &visits);
+  ASSERT_EQ(2U, visits.size());
+  main_db_->GetVisitsForURL(url_ids[2], &visits);
+  ASSERT_EQ(1U, visits.size());
+
+  // This should delete the two visits of the url_ids[1].
+  std::set<GURL> restrict_urls;
+  expirer_.ExpireHistoryBetween(restrict_urls, visit_times[1], visit_times[3]);
+
+  main_db_->GetVisitsForURL(url_ids[0], &visits);
+  EXPECT_EQ(1U, visits.size());
+  main_db_->GetVisitsForURL(url_ids[1], &visits);
+  EXPECT_EQ(0U, visits.size());
+  main_db_->GetVisitsForURL(url_ids[2], &visits);
+  EXPECT_EQ(1U, visits.size());
+
+  // Verify that the url_ids[1] was deleted.
+  favicon_base::FaviconID favicon_id1 =
+      GetFavicon(url_row1.url(), favicon_base::IconType::kFavicon);
+  EnsureURLInfoGone(url_row1, false);
+  EXPECT_FALSE(HasFavicon(favicon_id1));
+
+  // Verify that the url_ids[0]'s favicon and thumbnail are still there.
+  favicon_base::FaviconID favicon_id0 =
+      GetFavicon(url_row0.url(), favicon_base::IconType::kFavicon);
+  EXPECT_TRUE(HasFavicon(favicon_id0));
+  // TODO(sky): fix this, see comment in HasThumbnail.
+  // EXPECT_TRUE(HasThumbnail(url_row0.id()));
+
+  // Verify that the url_ids[2]'s favicon and thumbnail are still there.
+  favicon_base::FaviconID favicon_id2 =
+      GetFavicon(url_row2.url(), favicon_base::IconType::kFavicon);
+  EXPECT_TRUE(HasFavicon(favicon_id2));
+  // TODO(sky): fix this, see comment in HasThumbnail.
+  // EXPECT_TRUE(HasThumbnail(url_row2.id()));
+}
+
+// Expires all URLs more recent than a given time, with no starred items.
+// Same as FlushRecentURLsUnstarred test but with base::Time::Max() as end_time.
+TEST_F(ExpireHistoryTest, FlushRecentURLsUnstarredWithMaxTime) {
+  URLID url_ids[3];
+  base::Time visit_times[4];
+  AddExampleData(url_ids, visit_times);
+
+  URLRow url_row1, url_row2;
+  ASSERT_TRUE(main_db_->GetURLRow(url_ids[1], &url_row1));
+  ASSERT_TRUE(main_db_->GetURLRow(url_ids[2], &url_row2));
+
+  VisitVector visits;
+  main_db_->GetVisitsForURL(url_ids[2], &visits);
+  ASSERT_EQ(1U, visits.size());
+
+  // Use base::Time::Max() instead of base::Time().
+  // This should delete the last two visits.
+  std::set<GURL> restrict_urls;
+  expirer_.ExpireHistoryBetween(restrict_urls, visit_times[2],
+                                base::Time::Max());
+
+  // Verify that the middle URL had its last visit deleted only.
+  visits.clear();
+  main_db_->GetVisitsForURL(url_ids[1], &visits);
+  EXPECT_EQ(1U, visits.size());
+
+  // Verify that the middle URL visit time and visit counts were updated.
+  EXPECT_TRUE(ModifiedNotificationSent(url_row1.url()));
+  URLRow temp_row;
+  ASSERT_TRUE(main_db_->GetURLRow(url_ids[1], &temp_row));
+  EXPECT_TRUE(visit_times[2] == url_row1.last_visit());  // Previous value.
+  EXPECT_TRUE(visit_times[1] == temp_row.last_visit());  // New value.
+  EXPECT_EQ(2, url_row1.visit_count());
+  EXPECT_EQ(1, temp_row.visit_count());
+  EXPECT_EQ(1, url_row1.typed_count());
+  EXPECT_EQ(0, temp_row.typed_count());
+
+  // Verify that the middle URL's favicon and thumbnail is still there.
+  favicon_base::FaviconID favicon_id =
+      GetFavicon(url_row1.url(), favicon_base::IconType::kFavicon);
+  EXPECT_TRUE(HasFavicon(favicon_id));
+  // TODO(sky): fix this, see comment in HasThumbnail.
+  // EXPECT_TRUE(HasThumbnail(url_row1.id()));
+
+  // Verify that the last URL was deleted.
+  favicon_base::FaviconID favicon_id2 =
+      GetFavicon(url_row2.url(), favicon_base::IconType::kFavicon);
+  EnsureURLInfoGone(url_row2, false);
+  EXPECT_FALSE(HasFavicon(favicon_id2));
+}
+
+// Expires all URLs with no starred items.
+TEST_F(ExpireHistoryTest, FlushAllURLsUnstarred) {
+  URLID url_ids[3];
+  base::Time visit_times[4];
+  AddExampleData(url_ids, visit_times);
+
+  URLRow url_row1, url_row2;
+  ASSERT_TRUE(main_db_->GetURLRow(url_ids[1], &url_row1));
+  ASSERT_TRUE(main_db_->GetURLRow(url_ids[2], &url_row2));
+
+  VisitVector visits;
+  main_db_->GetVisitsForURL(url_ids[2], &visits);
+  ASSERT_EQ(1U, visits.size());
+
+  // This should delete all URL visits.
+  std::set<GURL> restrict_urls;
+  expirer_.ExpireHistoryBetween(restrict_urls, base::Time(), base::Time::Max());
+
+  // Verify that all URL visits deleted.
+  visits.clear();
+  main_db_->GetVisitsForURL(url_ids[1], &visits);
+  EXPECT_EQ(0U, visits.size());
+  main_db_->GetVisitsForURL(url_ids[2], &visits);
+  EXPECT_EQ(0U, visits.size());
+
+  // Verify that all URLs were deleted.
+  favicon_base::FaviconID favicon_id1 =
+      GetFavicon(url_row1.url(), favicon_base::IconType::kFavicon);
+  EnsureURLInfoGone(url_row1, false);
+  EXPECT_FALSE(HasFavicon(favicon_id1));
+
+  favicon_base::FaviconID favicon_id2 =
+      GetFavicon(url_row2.url(), favicon_base::IconType::kFavicon);
+  EnsureURLInfoGone(url_row2, false);
+  EXPECT_FALSE(HasFavicon(favicon_id2));
+}
+
 // Expires all URLs with times in a given set.
 TEST_F(ExpireHistoryTest, FlushURLsForTimes) {
   URLID url_ids[3];
diff --git a/components/sync/driver/sync_driver_switches.cc b/components/sync/driver/sync_driver_switches.cc
index 0000438..6c08056 100644
--- a/components/sync/driver/sync_driver_switches.cc
+++ b/components/sync/driver/sync_driver_switches.cc
@@ -45,6 +45,10 @@
 const base::Feature kSyncUserFieldTrialEvents{"SyncUserFieldTrialEvents",
                                               base::FEATURE_ENABLED_BY_DEFAULT};
 
+// Gates emission of UserConsent events.
+const base::Feature kSyncUserConsentEvents{"SyncUserConsentEvents",
+                                           base::FEATURE_ENABLED_BY_DEFAULT};
+
 // Gates registration for user language detection events.
 const base::Feature kSyncUserLanguageDetectionEvents{
     "SyncUserLanguageDetectionEvents", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/components/sync/driver/sync_driver_switches.h b/components/sync/driver/sync_driver_switches.h
index c618736..36d0a68 100644
--- a/components/sync/driver/sync_driver_switches.h
+++ b/components/sync/driver/sync_driver_switches.h
@@ -22,6 +22,7 @@
 extern const base::Feature kSyncClearDataOnPassphraseEncryption;
 extern const base::Feature kSyncUserEvents;
 extern const base::Feature kSyncUserFieldTrialEvents;
+extern const base::Feature kSyncUserConsentEvents;
 extern const base::Feature kSyncUserLanguageDetectionEvents;
 extern const base::Feature kSyncUserTranslationEvents;
 extern const base::Feature kSyncUSSAutocomplete;
diff --git a/components/sync/user_events/user_event_service_impl_unittest.cc b/components/sync/user_events/user_event_service_impl_unittest.cc
index 47fc9c4d..98808f00 100644
--- a/components/sync/user_events/user_event_service_impl_unittest.cc
+++ b/components/sync/user_events/user_event_service_impl_unittest.cc
@@ -4,6 +4,8 @@
 
 #include "components/sync/user_events/user_event_service_impl.h"
 
+#include <utility>
+
 #include "base/message_loop/message_loop.h"
 #include "base/metrics/field_trial.h"
 #include "base/test/scoped_feature_list.h"
@@ -46,6 +48,12 @@
   return specifics;
 }
 
+std::unique_ptr<UserEventSpecifics> AsConsent(
+    std::unique_ptr<UserEventSpecifics> specifics) {
+  specifics->mutable_user_consent();
+  return specifics;
+}
+
 std::unique_ptr<UserEventSpecifics> WithNav(
     std::unique_ptr<UserEventSpecifics> specifics,
     int64_t navigation_id = 1) {
@@ -136,6 +144,13 @@
   service.RecordUserEvent(WithNav(AsTest(Event())));
   EXPECT_EQ(0u, processor().put_multimap().size());
   service.RecordUserEvent(AsTest(Event()));
+}
+
+TEST_F(UserEventServiceImplTest, ShouldRecordUserConsentNoHistory) {
+  TestSyncService no_history_sync_service(true, false, ModelTypeSet());
+  UserEventServiceImpl service(&no_history_sync_service, MakeBridge());
+  service.RecordUserEvent(AsConsent(Event()));
+  // UserConsent recording doesn't need history sync to be enabled.
   EXPECT_EQ(1u, processor().put_multimap().size());
 }
 
diff --git a/content/browser/webrtc/webrtc_getusermedia_browsertest.cc b/content/browser/webrtc/webrtc_getusermedia_browsertest.cc
index d262d20..6164c4b 100644
--- a/content/browser/webrtc/webrtc_getusermedia_browsertest.cc
+++ b/content/browser/webrtc/webrtc_getusermedia_browsertest.cc
@@ -435,27 +435,6 @@
                                                   expected_result);
 }
 
-// Test fails under MSan, http://crbug.com/445745.
-// Flaky everywhere: https://crbug.com/789121.
-IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
-                       DISABLED_TwoGetUserMediaAndVerifyFrameRate) {
-  ASSERT_TRUE(embedded_test_server()->Start());
-
-  GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
-  NavigateToURL(shell(), url);
-
-  std::string constraints1 =
-      "{video: {mandatory: {minWidth:640 , minHeight: 480, "
-      "minFrameRate : 15, maxFrameRate : 15}}}";
-  std::string constraints2 =
-      "{video: {mandatory: {maxWidth:320 , maxHeight: 240,"
-      "minFrameRate : 7, maxFrameRate : 7}}}";
-
-  std::string command = "twoGetUserMediaAndVerifyFrameRate(" +
-      constraints1 + ',' + constraints2 + ", 15, 7)";
-  ExecuteJavascriptAndWaitForOk(command);
-}
-
 IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
                        GetUserMediaWithTooHighVideoConstraintsValues) {
   ASSERT_TRUE(embedded_test_server()->Start());
diff --git a/content/test/data/media/getusermedia.html b/content/test/data/media/getusermedia.html
index 373b8f3..6c7e820 100644
--- a/content/test/data/media/getusermedia.html
+++ b/content/test/data/media/getusermedia.html
@@ -279,42 +279,6 @@
     }
   }
 
-  // Calls GetUserMedia twice and verify that the frame rate is as expected for
-  // both streams.
-  function twoGetUserMediaAndVerifyFrameRate(constraints1,
-                                             constraints2,
-                                             expectedFrameRate1,
-                                             expectedFrameRate2) {
-    function frameRateValid(videoElementName, expectedFrameRate) {
-      return detectVideoPlaying(videoElementName)
-          .then(() => {
-            return validateFrameRate(videoElementName, expectedFrameRate)
-          });
-    }
-
-    navigator.mediaDevices.getUserMedia(constraints1)
-        .then(stream1 => {
-          $('local-view-1').srcObject = stream1;
-        })
-        .then(() => {
-          return navigator.mediaDevices.getUserMedia(constraints2)
-              .then(stream2 => {
-                $('local-view-2').srcObject = stream2;
-              });
-        })
-        .catch(failTest)
-        .then(() => {
-          return Promise.all([
-            frameRateValid('local-view-1', expectedFrameRate1),
-            frameRateValid('local-view-2', expectedFrameRate2),
-          ])
-        })
-        .catch(unexpectedFrameRateMsg => {
-          failTest(unexpectedFrameRateMsg);
-        })
-        .then(reportTestSuccess);
-  }
-
   function getUserMediaInIframeAndCloseInSuccessCb(constraints) {
     var iframe = document.createElement('iframe');
     iframe.onload = onIframeLoaded;
diff --git a/content/test/data/media/webrtc_test_utilities.js b/content/test/data/media/webrtc_test_utilities.js
index 3cd8ea7..fe52640 100644
--- a/content/test/data/media/webrtc_test_utilities.js
+++ b/content/test/data/media/webrtc_test_utilities.js
@@ -111,47 +111,6 @@
   });
 }
 
-// Calculates the current frame rate and compares to |expectedFrameRate|
-// The promise is resolved with value |true| if the calculated frame rate
-// is +-1 the expected or rejected with an error message if five calculations
-// fail to match |expectedFrameRate|.
-function validateFrameRate(videoElementName, expectedFrameRate) {
-  return new Promise((resolve, reject) => {
-    var videoElement = $(videoElementName);
-    var startTime = new Date().getTime();
-    var decodedFrames = videoElement.webkitDecodedFrameCount;
-    var attempts = 0;
-
-    if (videoElement.readyState <= HTMLMediaElement.HAVE_CURRENT_DATA ||
-            videoElement.paused || videoElement.ended) {
-      reject("getFrameRate - " + videoElementName + " is not plaing.");
-      return;
-    }
-
-    var waitVideo = setInterval(function() {
-      attempts++;
-      currentTime = new Date().getTime();
-      deltaTime = (currentTime - startTime) / 1000;
-      startTime = currentTime;
-
-      // Calculate decoded frames per sec.
-      var fps =
-          (videoElement.webkitDecodedFrameCount - decodedFrames) / deltaTime;
-      decodedFrames = videoElement.webkitDecodedFrameCount;
-
-      console.log('FrameRate in ' + videoElementName + ' is ' + fps);
-      if (fps < expectedFrameRate + 1  && fps > expectedFrameRate - 1) {
-        clearInterval(waitVideo);
-        resolve(true);
-      } else if (attempts == 5) {
-        clearInterval(waitVideo);
-        reject('Expected frame rate ' + expectedFrameRate + ' for ' +
-               'element ' + videoElementName + ', but got ' + fps);
-      }
-    }, 1000);
-  });
-}
-
 function waitForConnectionToStabilize(peerConnection) {
   return new Promise((resolve, reject) => {
     peerConnection.onsignalingstatechange = function(event) {
diff --git a/ios/chrome/browser/passwords/password_controller.mm b/ios/chrome/browser/passwords/password_controller.mm
index 1ac3016..39fb483 100644
--- a/ios/chrome/browser/passwords/password_controller.mm
+++ b/ios/chrome/browser/passwords/password_controller.mm
@@ -478,7 +478,8 @@
   // TODO(crbug.com/418827): Fix this by passing in more data from the JS side.
   id completionHandler = ^(BOOL found, const autofill::PasswordForm& form) {
     PasswordController* strongSelf = weakSelf;
-    if (strongSelf && ![strongSelf isWebStateDestroyed]) {
+    if (strongSelf && ![strongSelf isWebStateDestroyed] &&
+        strongSelf.passwordManager) {
       strongSelf.passwordManager->OnPasswordFormSubmitted(
           strongSelf.passwordManagerDriver, form);
     }
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 732a865..b03b6a1 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -2433,7 +2433,6 @@
 crbug.com/788337 external/wpt/css/css-multicol/multicol-count-computed-003.xht [ Failure ]
 crbug.com/788337 external/wpt/css/css-multicol/multicol-count-computed-005.xht [ Failure ]
 crbug.com/788337 external/wpt/css/css-multicol/multicol-height-block-child-001.xht [ Failure ]
-crbug.com/788337 external/wpt/css/css-multicol/multicol-nested-column-rule-001.xht [ Failure ]
 crbug.com/788337 external/wpt/css/css-multicol/multicol-rule-004.xht [ Failure ]
 crbug.com/788337 external/wpt/css/css-multicol/multicol-rule-fraction-003.xht [ Failure ]
 crbug.com/788337 external/wpt/css/css-multicol/multicol-rule-inset-000.xht [ Failure ]
@@ -2906,10 +2905,6 @@
 # ====== Begin of display: contents tests ======
 
 crbug.com/181374 external/wpt/css/css-display/display-contents-dynamic-table-001-inline.html [ Failure ]
-crbug.com/717460 external/wpt/css/css-display/display-contents-first-letter-002.html [ Failure ]
-crbug.com/706316 external/wpt/css/css-display/display-contents-first-line-002.html [ Failure ]
-crbug.com/713019 external/wpt/css/css-display/display-contents-line-height.html [ Failure ]
-crbug.com/709808 external/wpt/css/css-display/display-contents-text-inherit.html [ Failure ]
 
 # ====== End of display: contents tests ======
 
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
index c741647c6..0ac223c8 100644
--- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
+++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
@@ -66501,6 +66501,78 @@
      {}
     ]
    ],
+   "css/css-variables/css-vars-custom-property-case-sensitive-001.html": [
+    [
+     "/css/css-variables/css-vars-custom-property-case-sensitive-001.html",
+     [
+      [
+       "/css/css-variables/reference/css-vars-custom-property-case-sensitive-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-variables/css-vars-custom-property-inheritance.html": [
+    [
+     "/css/css-variables/css-vars-custom-property-inheritance.html",
+     [
+      [
+       "/css/css-variables/reference/css-vars-custom-property-inheritance-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-variables/variable-generated-content-dynamic-001.html": [
+    [
+     "/css/css-variables/variable-generated-content-dynamic-001.html",
+     [
+      [
+       "/css/css-variables/variable-generated-content-dynamic-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-variables/variable-reference-without-whitespace.html": [
+    [
+     "/css/css-variables/variable-reference-without-whitespace.html",
+     [
+      [
+       "/css/css-variables/reference/variable-reference-without-whitespace-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-variables/vars-background-shorthand-001.html": [
+    [
+     "/css/css-variables/vars-background-shorthand-001.html",
+     [
+      [
+       "/css/css-variables/reference/vars-background-shorthand-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-variables/vars-font-shorthand-001.html": [
+    [
+     "/css/css-variables/vars-font-shorthand-001.html",
+     [
+      [
+       "/css/css-variables/reference/vars-font-shorthand-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-writing-modes/abs-pos-non-replaced-icb-vlr-003.xht": [
     [
      "/css/css-writing-modes/abs-pos-non-replaced-icb-vlr-003.xht",
@@ -116369,6 +116441,96 @@
      {}
     ]
    ],
+   "css/css-variables/OWNERS": [
+    [
+     {}
+    ]
+   ],
+   "css/css-variables/reference/css-vars-custom-property-case-sensitive-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-variables/reference/css-vars-custom-property-inheritance-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-variables/reference/variable-reference-without-whitespace-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-variables/reference/vars-background-shorthand-001-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-variables/reference/vars-font-shorthand-001-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-variables/resources/variable-reference-refresh-iframe.css": [
+    [
+     {}
+    ]
+   ],
+   "css/css-variables/resources/variable-reference-refresh-iframe.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-variables/variable-cssText-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "css/css-variables/variable-definition-border-shorthand-serialize-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "css/css-variables/variable-definition-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "css/css-variables/variable-first-letter-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "css/css-variables/variable-first-line-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "css/css-variables/variable-generated-content-dynamic-001-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-variables/variable-invalidation-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "css/css-variables/variable-presentation-attribute-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "css/css-variables/variable-substitution-shadow-properties-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "css/css-variables/vars-border-shorthand-serialize-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "css/css-writing-modes/OWNERS": [
     [
      {}
@@ -168233,6 +168395,264 @@
      {}
     ]
    ],
+   "css/css-variables/test_variable_legal_values.html": [
+    [
+     "/css/css-variables/test_variable_legal_values.html",
+     {}
+    ]
+   ],
+   "css/css-variables/variable-animation-from-to.html": [
+    [
+     "/css/css-variables/variable-animation-from-to.html",
+     {}
+    ]
+   ],
+   "css/css-variables/variable-animation-over-transition.html": [
+    [
+     "/css/css-variables/variable-animation-over-transition.html",
+     {}
+    ]
+   ],
+   "css/css-variables/variable-animation-substitute-into-keyframe-shorthand.html": [
+    [
+     "/css/css-variables/variable-animation-substitute-into-keyframe-shorthand.html",
+     {}
+    ]
+   ],
+   "css/css-variables/variable-animation-substitute-into-keyframe-transform.html": [
+    [
+     "/css/css-variables/variable-animation-substitute-into-keyframe-transform.html",
+     {}
+    ]
+   ],
+   "css/css-variables/variable-animation-substitute-into-keyframe.html": [
+    [
+     "/css/css-variables/variable-animation-substitute-into-keyframe.html",
+     {}
+    ]
+   ],
+   "css/css-variables/variable-animation-substitute-within-keyframe-fallback.html": [
+    [
+     "/css/css-variables/variable-animation-substitute-within-keyframe-fallback.html",
+     {}
+    ]
+   ],
+   "css/css-variables/variable-animation-substitute-within-keyframe-multiple.html": [
+    [
+     "/css/css-variables/variable-animation-substitute-within-keyframe-multiple.html",
+     {}
+    ]
+   ],
+   "css/css-variables/variable-animation-substitute-within-keyframe.html": [
+    [
+     "/css/css-variables/variable-animation-substitute-within-keyframe.html",
+     {}
+    ]
+   ],
+   "css/css-variables/variable-animation-to-only.html": [
+    [
+     "/css/css-variables/variable-animation-to-only.html",
+     {}
+    ]
+   ],
+   "css/css-variables/variable-created-document.html": [
+    [
+     "/css/css-variables/variable-created-document.html",
+     {}
+    ]
+   ],
+   "css/css-variables/variable-created-element.html": [
+    [
+     "/css/css-variables/variable-created-element.html",
+     {}
+    ]
+   ],
+   "css/css-variables/variable-cssText.html": [
+    [
+     "/css/css-variables/variable-cssText.html",
+     {}
+    ]
+   ],
+   "css/css-variables/variable-definition-border-shorthand-serialize.html": [
+    [
+     "/css/css-variables/variable-definition-border-shorthand-serialize.html",
+     {}
+    ]
+   ],
+   "css/css-variables/variable-definition-cascading.html": [
+    [
+     "/css/css-variables/variable-definition-cascading.html",
+     {}
+    ]
+   ],
+   "css/css-variables/variable-definition-keywords.html": [
+    [
+     "/css/css-variables/variable-definition-keywords.html",
+     {}
+    ]
+   ],
+   "css/css-variables/variable-definition.html": [
+    [
+     "/css/css-variables/variable-definition.html",
+     {}
+    ]
+   ],
+   "css/css-variables/variable-first-letter.html": [
+    [
+     "/css/css-variables/variable-first-letter.html",
+     {}
+    ]
+   ],
+   "css/css-variables/variable-first-line.html": [
+    [
+     "/css/css-variables/variable-first-line.html",
+     {}
+    ]
+   ],
+   "css/css-variables/variable-invalidation.html": [
+    [
+     "/css/css-variables/variable-invalidation.html",
+     {}
+    ]
+   ],
+   "css/css-variables/variable-presentation-attribute.html": [
+    [
+     "/css/css-variables/variable-presentation-attribute.html",
+     {}
+    ]
+   ],
+   "css/css-variables/variable-pseudo-element.html": [
+    [
+     "/css/css-variables/variable-pseudo-element.html",
+     {}
+    ]
+   ],
+   "css/css-variables/variable-reference-cssom.html": [
+    [
+     "/css/css-variables/variable-reference-cssom.html",
+     {}
+    ]
+   ],
+   "css/css-variables/variable-reference-refresh.html": [
+    [
+     "/css/css-variables/variable-reference-refresh.html",
+     {}
+    ]
+   ],
+   "css/css-variables/variable-reference-shorthands-cssom.html": [
+    [
+     "/css/css-variables/variable-reference-shorthands-cssom.html",
+     {}
+    ]
+   ],
+   "css/css-variables/variable-reference-shorthands.html": [
+    [
+     "/css/css-variables/variable-reference-shorthands.html",
+     {}
+    ]
+   ],
+   "css/css-variables/variable-reference-variable.html": [
+    [
+     "/css/css-variables/variable-reference-variable.html",
+     {}
+    ]
+   ],
+   "css/css-variables/variable-reference.html": [
+    [
+     "/css/css-variables/variable-reference.html",
+     {}
+    ]
+   ],
+   "css/css-variables/variable-substitution-background-properties.html": [
+    [
+     "/css/css-variables/variable-substitution-background-properties.html",
+     {}
+    ]
+   ],
+   "css/css-variables/variable-substitution-basic.html": [
+    [
+     "/css/css-variables/variable-substitution-basic.html",
+     {}
+    ]
+   ],
+   "css/css-variables/variable-substitution-filters.html": [
+    [
+     "/css/css-variables/variable-substitution-filters.html",
+     {}
+    ]
+   ],
+   "css/css-variables/variable-substitution-plus-box-shadow.html": [
+    [
+     "/css/css-variables/variable-substitution-plus-box-shadow.html",
+     {}
+    ]
+   ],
+   "css/css-variables/variable-substitution-replaced-size.html": [
+    [
+     "/css/css-variables/variable-substitution-replaced-size.html",
+     {}
+    ]
+   ],
+   "css/css-variables/variable-substitution-shadow-properties.html": [
+    [
+     "/css/css-variables/variable-substitution-shadow-properties.html",
+     {}
+    ]
+   ],
+   "css/css-variables/variable-substitution-shorthands.html": [
+    [
+     "/css/css-variables/variable-substitution-shorthands.html",
+     {}
+    ]
+   ],
+   "css/css-variables/variable-substitution-variable-declaration.html": [
+    [
+     "/css/css-variables/variable-substitution-variable-declaration.html",
+     {}
+    ]
+   ],
+   "css/css-variables/variable-transitions-from-no-value.html": [
+    [
+     "/css/css-variables/variable-transitions-from-no-value.html",
+     {}
+    ]
+   ],
+   "css/css-variables/variable-transitions-to-no-value.html": [
+    [
+     "/css/css-variables/variable-transitions-to-no-value.html",
+     {}
+    ]
+   ],
+   "css/css-variables/variable-transitions-transition-property-all-before-value.html": [
+    [
+     "/css/css-variables/variable-transitions-transition-property-all-before-value.html",
+     {}
+    ]
+   ],
+   "css/css-variables/variable-transitions-transition-property-variable-before-value.html": [
+    [
+     "/css/css-variables/variable-transitions-transition-property-variable-before-value.html",
+     {}
+    ]
+   ],
+   "css/css-variables/variable-transitions-value-before-transition-property-all.html": [
+    [
+     "/css/css-variables/variable-transitions-value-before-transition-property-all.html",
+     {}
+    ]
+   ],
+   "css/css-variables/variable-transitions-value-before-transition-property-variable.html": [
+    [
+     "/css/css-variables/variable-transitions-value-before-transition-property-variable.html",
+     {}
+    ]
+   ],
+   "css/css-variables/vars-border-shorthand-serialize.html": [
+    [
+     "/css/css-variables/vars-border-shorthand-serialize.html",
+     {}
+    ]
+   ],
    "css/css-writing-modes/orthogonal-parent-shrink-to-fit-001.html": [
     [
      "/css/css-writing-modes/orthogonal-parent-shrink-to-fit-001.html",
@@ -227055,11 +227475,11 @@
    "testharness"
   ],
   "FileAPI/blob/Blob-constructor-expected.txt": [
-   "06583e06651d742c663df18fd31340912fe04f66",
+   "bb753161fd7480a13a745dcdd42c78bedb5110b7",
    "support"
   ],
   "FileAPI/blob/Blob-constructor.html": [
-   "5fb9efaf6f8ea446d13f4c7172a26cfeac3ab55f",
+   "96eb93bd23ec6b1f1faf5b7ba617fdf5f0eb75f7",
    "testharness"
   ],
   "FileAPI/blob/Blob-in-worker.worker.js": [
@@ -227079,11 +227499,11 @@
    "testharness"
   ],
   "FileAPI/file/File-constructor-expected.txt": [
-   "29b53561f6aa678e147b6ef25f4b6faa454e477f",
+   "588431d9ea28f035b3f95ad163cdcef609bc0218",
    "support"
   ],
   "FileAPI/file/File-constructor.html": [
-   "052ea42d7c68ca7d1d2f84de88e747c37e5deb10",
+   "95198c8156dadc851d279a863b883c8befdc3930",
    "testharness"
   ],
   "FileAPI/file/Worker-read-file-constructor.worker.js": [
@@ -281254,6 +281674,274 @@
    "b3831f028e6c576b809e3a6d8eed8b8d62614d23",
    "testharness"
   ],
+  "css/css-variables/OWNERS": [
+   "495f99b874611fd8f82f2e33bc4b7d930cc60fde",
+   "support"
+  ],
+  "css/css-variables/css-vars-custom-property-case-sensitive-001.html": [
+   "bf952986ea848345b87d235ceb28758c47d54ec9",
+   "reftest"
+  ],
+  "css/css-variables/css-vars-custom-property-inheritance.html": [
+   "cca07110cb5f216f4df014186a0851a0d7bceb58",
+   "reftest"
+  ],
+  "css/css-variables/reference/css-vars-custom-property-case-sensitive-ref.html": [
+   "735e9262cb275cf72cf481d9cf0dc3dbd0c15e48",
+   "support"
+  ],
+  "css/css-variables/reference/css-vars-custom-property-inheritance-ref.html": [
+   "24241528d71b7d134783be10f948ff35270f84b6",
+   "support"
+  ],
+  "css/css-variables/reference/variable-reference-without-whitespace-ref.html": [
+   "d331445aab176cac82756b84ed11266ecd1c48cc",
+   "support"
+  ],
+  "css/css-variables/reference/vars-background-shorthand-001-ref.html": [
+   "5c710d750189bd05ea12a42a9a922df4c6d00cd1",
+   "support"
+  ],
+  "css/css-variables/reference/vars-font-shorthand-001-ref.html": [
+   "5e0ab512c788c78ed24ae2610e134149ae7ee8fa",
+   "support"
+  ],
+  "css/css-variables/resources/variable-reference-refresh-iframe.css": [
+   "50eec760578accdbb2a9471918f458b7adb2525e",
+   "support"
+  ],
+  "css/css-variables/resources/variable-reference-refresh-iframe.html": [
+   "64f4f7be1a341dcda14547bc9c59c8ae914607a8",
+   "support"
+  ],
+  "css/css-variables/test_variable_legal_values.html": [
+   "a6ffd6e1e3479aad164dcf678e7382b365473448",
+   "testharness"
+  ],
+  "css/css-variables/variable-animation-from-to.html": [
+   "b01ee8e5cc18a84eedb0026c18569e0de5eaae11",
+   "testharness"
+  ],
+  "css/css-variables/variable-animation-over-transition.html": [
+   "cfe9fc33ac567d4c2c613b135ed85ec25e712f32",
+   "testharness"
+  ],
+  "css/css-variables/variable-animation-substitute-into-keyframe-shorthand.html": [
+   "c5c2783e0b0da82ae7b68e2516781ef742c128da",
+   "testharness"
+  ],
+  "css/css-variables/variable-animation-substitute-into-keyframe-transform.html": [
+   "aa5bd94faf68430e5f9dd00c8388e89d903d644f",
+   "testharness"
+  ],
+  "css/css-variables/variable-animation-substitute-into-keyframe.html": [
+   "40fc0bbe92be5de7c66ec808a71109290af7c9cd",
+   "testharness"
+  ],
+  "css/css-variables/variable-animation-substitute-within-keyframe-fallback.html": [
+   "7bb1c1c9f5cd2a65867d9158a8b6297f85d7361d",
+   "testharness"
+  ],
+  "css/css-variables/variable-animation-substitute-within-keyframe-multiple.html": [
+   "7a7ec6c1f19f52e71d80a90ee7743c665ed7797e",
+   "testharness"
+  ],
+  "css/css-variables/variable-animation-substitute-within-keyframe.html": [
+   "fa1814b333fc6105f0bc35d096cd921be5f7c968",
+   "testharness"
+  ],
+  "css/css-variables/variable-animation-to-only.html": [
+   "805429b0e860d20fa19e01d40be94bc1767ae5a6",
+   "testharness"
+  ],
+  "css/css-variables/variable-created-document.html": [
+   "50b1ab1f4ce2b77f852af113818b94d03d74732e",
+   "testharness"
+  ],
+  "css/css-variables/variable-created-element.html": [
+   "e2c135317f9b78c0fa4f90dbb751b73f3d988b7e",
+   "testharness"
+  ],
+  "css/css-variables/variable-cssText-expected.txt": [
+   "5b396970b06ee100ff566838666f1a413e3ec87b",
+   "support"
+  ],
+  "css/css-variables/variable-cssText.html": [
+   "601a35a06498f52982dbce18531fb8e12ab292ba",
+   "testharness"
+  ],
+  "css/css-variables/variable-definition-border-shorthand-serialize-expected.txt": [
+   "9ed9b959cdbfa8923544ad73b3e05b56821bc656",
+   "support"
+  ],
+  "css/css-variables/variable-definition-border-shorthand-serialize.html": [
+   "be7f736f5909ef11ec11466bb81da8cdc4095df3",
+   "testharness"
+  ],
+  "css/css-variables/variable-definition-cascading.html": [
+   "0be93185a6f1ef0c380a692c051db4e66a82b333",
+   "testharness"
+  ],
+  "css/css-variables/variable-definition-expected.txt": [
+   "37b01a69f36ae10e073306c0a697dc5e145386cb",
+   "support"
+  ],
+  "css/css-variables/variable-definition-keywords.html": [
+   "eef27787c48ec2b6c9849bfc2e9caf2b2e6eba29",
+   "testharness"
+  ],
+  "css/css-variables/variable-definition.html": [
+   "78682dc5f85a471147adb6fcfb56b39c616ba976",
+   "testharness"
+  ],
+  "css/css-variables/variable-first-letter-expected.txt": [
+   "b21396b68a4051433ff44fbbf518add1e2a7d6dc",
+   "support"
+  ],
+  "css/css-variables/variable-first-letter.html": [
+   "91e97471b4470918b6477994f8ed0f39ad761a84",
+   "testharness"
+  ],
+  "css/css-variables/variable-first-line-expected.txt": [
+   "d5e69ca37aef993c17a88c40602d9d504d3ad2ce",
+   "support"
+  ],
+  "css/css-variables/variable-first-line.html": [
+   "13085879fd567a224901d142cee05a96836ff749",
+   "testharness"
+  ],
+  "css/css-variables/variable-generated-content-dynamic-001-ref.html": [
+   "f1a7e50f8c66bd18ad4e94f494f0cf31c8511093",
+   "support"
+  ],
+  "css/css-variables/variable-generated-content-dynamic-001.html": [
+   "b0374a1825f8dae8c03768cc1eec5297e0a05c71",
+   "reftest"
+  ],
+  "css/css-variables/variable-invalidation-expected.txt": [
+   "a6c66510f72b41d94b1b44981717cb9ad01daa8c",
+   "support"
+  ],
+  "css/css-variables/variable-invalidation.html": [
+   "11106961651b3920aa302bd42695af7fe1b7484a",
+   "testharness"
+  ],
+  "css/css-variables/variable-presentation-attribute-expected.txt": [
+   "8a92d08d911528411d8add626a58f41e7c64e3e4",
+   "support"
+  ],
+  "css/css-variables/variable-presentation-attribute.html": [
+   "6c32dad5317f2b0b3ac71e41c90816603c7e6249",
+   "testharness"
+  ],
+  "css/css-variables/variable-pseudo-element.html": [
+   "342a14cfb0ffca8ce1d9a98c035407762e73f0f1",
+   "testharness"
+  ],
+  "css/css-variables/variable-reference-cssom.html": [
+   "bef60020890df3a16812c6c00a694d86c75d18ab",
+   "testharness"
+  ],
+  "css/css-variables/variable-reference-refresh.html": [
+   "58b278fc4f78f3a22ae373dce2009e4ecce36e3a",
+   "testharness"
+  ],
+  "css/css-variables/variable-reference-shorthands-cssom.html": [
+   "568ef4aeda575c70c74e4b5b59aa53063c98a71c",
+   "testharness"
+  ],
+  "css/css-variables/variable-reference-shorthands.html": [
+   "c1b689e7189cf45789d3ee25c01b00d4dec4bb52",
+   "testharness"
+  ],
+  "css/css-variables/variable-reference-variable.html": [
+   "40a2984bac072b5b0ee6dec9b37a23acf7be8336",
+   "testharness"
+  ],
+  "css/css-variables/variable-reference-without-whitespace.html": [
+   "731f3f5d0f5900f296bfdd545b0c4dff95576daa",
+   "reftest"
+  ],
+  "css/css-variables/variable-reference.html": [
+   "9e4be802fc956e801ed055835ea57e65d3bc18a1",
+   "testharness"
+  ],
+  "css/css-variables/variable-substitution-background-properties.html": [
+   "1999e763c54cc6fdcfc2c218876ab438a55f608a",
+   "testharness"
+  ],
+  "css/css-variables/variable-substitution-basic.html": [
+   "4dfbb8442da7180763bf184bebd7d663ed56d174",
+   "testharness"
+  ],
+  "css/css-variables/variable-substitution-filters.html": [
+   "48151be36bd6fa4d8358f15df3f2d70c538506b7",
+   "testharness"
+  ],
+  "css/css-variables/variable-substitution-plus-box-shadow.html": [
+   "db543bb540e8d9fe4490dd9e97ca94392194ae18",
+   "testharness"
+  ],
+  "css/css-variables/variable-substitution-replaced-size.html": [
+   "c72105fc2018b020125ad860b964f5a78910ed5b",
+   "testharness"
+  ],
+  "css/css-variables/variable-substitution-shadow-properties-expected.txt": [
+   "7944c97889a6ad50ca50329b99ca104ad508eba3",
+   "support"
+  ],
+  "css/css-variables/variable-substitution-shadow-properties.html": [
+   "0febbaa27e8692583fa2cc29fc8a1523eea9be43",
+   "testharness"
+  ],
+  "css/css-variables/variable-substitution-shorthands.html": [
+   "fc3c70235d28761659937cab5ae18e3e2b04d747",
+   "testharness"
+  ],
+  "css/css-variables/variable-substitution-variable-declaration.html": [
+   "561e824ad190c1859826dbf10989d5c4d343b71f",
+   "testharness"
+  ],
+  "css/css-variables/variable-transitions-from-no-value.html": [
+   "f4123d6500891731b3d70d49a1d15ed8484bc619",
+   "testharness"
+  ],
+  "css/css-variables/variable-transitions-to-no-value.html": [
+   "a4fb263a72fa90aec14f88681c0276e81a0fa6a9",
+   "testharness"
+  ],
+  "css/css-variables/variable-transitions-transition-property-all-before-value.html": [
+   "6cd18d2c18375980036fe8dd65a781965e9bcc4f",
+   "testharness"
+  ],
+  "css/css-variables/variable-transitions-transition-property-variable-before-value.html": [
+   "2efbc1ffe66ccf3b5f60baae4f7ad9ed447d60fd",
+   "testharness"
+  ],
+  "css/css-variables/variable-transitions-value-before-transition-property-all.html": [
+   "75df32eb1cee6f2c0dca55cd9c7daba6c6476aae",
+   "testharness"
+  ],
+  "css/css-variables/variable-transitions-value-before-transition-property-variable.html": [
+   "a083618c3caf3636a6133ae5c1a06b71bafcfe43",
+   "testharness"
+  ],
+  "css/css-variables/vars-background-shorthand-001.html": [
+   "3c49d366fb429f9f563e293f96abc32ec42d8c7a",
+   "reftest"
+  ],
+  "css/css-variables/vars-border-shorthand-serialize-expected.txt": [
+   "0f333f9c1a63f23bd2afe673a8af3632f3089d55",
+   "support"
+  ],
+  "css/css-variables/vars-border-shorthand-serialize.html": [
+   "86d6b0278d5256b4e9e83bc76455bc31d0d8f586",
+   "testharness"
+  ],
+  "css/css-variables/vars-font-shorthand-001.html": [
+   "ac2c476205ffb2c2f985c44cb5e4acada01b0093",
+   "reftest"
+  ],
   "css/css-writing-modes/OWNERS": [
    "73bd9fcf99edecee437d90873f66e2698c20778a",
    "support"
@@ -341855,7 +342543,7 @@
    "support"
   ],
   "url/setters_tests.json": [
-   "4b01281c0f8811cf57f261f9328d7916c52f3619",
+   "8d58bd1c98f4d987e6abe66659c812591b197e60",
    "support"
   ],
   "url/toascii.json": [
@@ -341943,7 +342631,7 @@
    "testharness"
   ],
   "url/urltestdata.json": [
-   "d93eea5fddec950368ce502e2f895174b2b847f5",
+   "59d1f7c678f29a70df885bdfbf9d491899f0038c",
    "support"
   ],
   "user-timing/OWNERS": [
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-multicol/multicol-nested-column-rule-001-ref.xht b/third_party/WebKit/LayoutTests/external/wpt/css/css-multicol/multicol-nested-column-rule-001-ref.xht
index 8d86b42..e373c9a6 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-multicol/multicol-nested-column-rule-001-ref.xht
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-multicol/multicol-nested-column-rule-001-ref.xht
@@ -5,41 +5,8 @@
   <link rel="author" title="Opera Software ASA" href="http://www.opera.com/" />
   <link rel="reviewer" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" /> <!-- 2013-08-09 -->
   <meta name="flags" content="" />
-  <style type="text/css"><![CDATA[
-  div#rel-pos-wrapper
-  {
-  font: 1.25em/1 serif;
-  position: relative;
-  }
-
-  div#rel-pos-wrapper > div
-  {
-  background-color: blue;
-  font-size: 1em;
-  height: 3em;
-  position: absolute;
-  width: 1em;
-  }
-
-  div#first-column-rule
-  {
-  left: 14em;
-  top: auto;
-  }
-
-  div#second-column-rule
-  {
-  left: 29em;
-  top: auto;
-  }
-   ]]></style>
  </head>
  <body>
-
-  <div id="rel-pos-wrapper">
-	<div id="first-column-rule"></div>
-	<div id="second-column-rule"></div>
-  </div>
-
+   <div style="font: 1.25em/1 Ahem; width:12em; height:3em; margin-left:12em; border-left:1em solid blue; border-right:1em solid blue;"></div>
  </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-multicol/multicol-nested-column-rule-001.xht b/third_party/WebKit/LayoutTests/external/wpt/css/css-multicol/multicol-nested-column-rule-001.xht
index 11a44f4..322551e1 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-multicol/multicol-nested-column-rule-001.xht
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-multicol/multicol-nested-column-rule-001.xht
@@ -18,7 +18,7 @@
   {
   column-rule: blue solid 1em;
   font: 1.25em/1 Ahem;
-  width: 42em;
+  width: 36em;
   }
 
   /*
diff --git a/third_party/WebKit/LayoutTests/external/wpt/url/setters_tests.json b/third_party/WebKit/LayoutTests/external/wpt/url/setters_tests.json
index f35db16..714bd5e7 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/url/setters_tests.json
+++ b/third_party/WebKit/LayoutTests/external/wpt/url/setters_tests.json
@@ -1786,12 +1786,52 @@
             }
         },
         {
+            "href": "http://example.net",
+            "new_value": "#foo bar",
+            "expected": {
+                "href": "http://example.net/#foo%20bar",
+                "hash": "#foo%20bar"
+            }
+        },
+        {
+            "href": "http://example.net",
+            "new_value": "#foo\"bar",
+            "expected": {
+                "href": "http://example.net/#foo%22bar",
+                "hash": "#foo%22bar"
+            }
+        },
+        {
+            "href": "http://example.net",
+            "new_value": "#foo<bar",
+            "expected": {
+                "href": "http://example.net/#foo%3Cbar",
+                "hash": "#foo%3Cbar"
+            }
+        },
+        {
+            "href": "http://example.net",
+            "new_value": "#foo>bar",
+            "expected": {
+                "href": "http://example.net/#foo%3Ebar",
+                "hash": "#foo%3Ebar"
+            }
+        },
+        {
+            "href": "http://example.net",
+            "new_value": "#foo`bar",
+            "expected": {
+                "href": "http://example.net/#foo%60bar",
+                "hash": "#foo%60bar"
+            }
+        },
+        {
             "comment": "Simple percent-encoding; nuls, tabs, and newlines are removed",
             "href": "a:/",
             "new_value": "\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé",
             "expected": {
-                "href": "a:/#%01%1F !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9",
-                "hash": "#%01%1F !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9"
+                "href": "a:/#%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9",
+                "hash": "#%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9"
             }
         },
         {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/url/urltestdata.json b/third_party/WebKit/LayoutTests/external/wpt/url/urltestdata.json
index 0691761..8670566 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/url/urltestdata.json
+++ b/third_party/WebKit/LayoutTests/external/wpt/url/urltestdata.json
@@ -153,7 +153,7 @@
   {
     "input": "http://f:21/ b ? d # e ",
     "base": "http://example.org/foo/bar",
-    "href": "http://f:21/%20b%20?%20d%20# e",
+    "href": "http://f:21/%20b%20?%20d%20#%20e",
     "origin": "http://f:21",
     "protocol": "http:",
     "username": "",
@@ -163,12 +163,12 @@
     "port": "21",
     "pathname": "/%20b%20",
     "search": "?%20d%20",
-    "hash": "# e"
+    "hash": "#%20e"
   },
   {
     "input": "lolscheme:x x#x x",
     "base": "about:blank",
-    "href": "lolscheme:x x#x x",
+    "href": "lolscheme:x x#x%20x",
     "protocol": "lolscheme:",
     "username": "",
     "password": "",
@@ -177,7 +177,7 @@
     "port": "",
     "pathname": "x x",
     "search": "",
-    "hash": "#x x"
+    "hash": "#x%20x"
   },
   {
     "input": "http://f:/c",
@@ -2260,7 +2260,7 @@
   {
     "input": "http://www.google.com/foo?bar=baz# »",
     "base": "about:blank",
-    "href": "http://www.google.com/foo?bar=baz# %C2%BB",
+    "href": "http://www.google.com/foo?bar=baz#%20%C2%BB",
     "origin": "http://www.google.com",
     "protocol": "http:",
     "username": "",
@@ -2270,12 +2270,12 @@
     "port": "",
     "pathname": "/foo",
     "search": "?bar=baz",
-    "hash": "# %C2%BB"
+    "hash": "#%20%C2%BB"
   },
   {
     "input": "data:test# »",
     "base": "about:blank",
-    "href": "data:test# %C2%BB",
+    "href": "data:test#%20%C2%BB",
     "origin": "null",
     "protocol": "data:",
     "username": "",
@@ -2285,7 +2285,7 @@
     "port": "",
     "pathname": "test",
     "search": "",
-    "hash": "# %C2%BB"
+    "hash": "#%20%C2%BB"
   },
   {
     "input": "http://www.google.com",
@@ -4787,6 +4787,70 @@
     "searchParams": "qux=",
     "hash": "#foo%08bar"
   },
+  {
+    "input": "http://foo.bar/baz?qux#foo\"bar",
+    "base": "about:blank",
+    "href": "http://foo.bar/baz?qux#foo%22bar",
+    "origin": "http://foo.bar",
+    "protocol": "http:",
+    "username": "",
+    "password": "",
+    "host": "foo.bar",
+    "hostname": "foo.bar",
+    "port": "",
+    "pathname": "/baz",
+    "search": "?qux",
+    "searchParams": "qux=",
+    "hash": "#foo%22bar"
+  },
+  {
+    "input": "http://foo.bar/baz?qux#foo<bar",
+    "base": "about:blank",
+    "href": "http://foo.bar/baz?qux#foo%3Cbar",
+    "origin": "http://foo.bar",
+    "protocol": "http:",
+    "username": "",
+    "password": "",
+    "host": "foo.bar",
+    "hostname": "foo.bar",
+    "port": "",
+    "pathname": "/baz",
+    "search": "?qux",
+    "searchParams": "qux=",
+    "hash": "#foo%3Cbar"
+  },
+  {
+    "input": "http://foo.bar/baz?qux#foo>bar",
+    "base": "about:blank",
+    "href": "http://foo.bar/baz?qux#foo%3Ebar",
+    "origin": "http://foo.bar",
+    "protocol": "http:",
+    "username": "",
+    "password": "",
+    "host": "foo.bar",
+    "hostname": "foo.bar",
+    "port": "",
+    "pathname": "/baz",
+    "search": "?qux",
+    "searchParams": "qux=",
+    "hash": "#foo%3Ebar"
+  },
+  {
+    "input": "http://foo.bar/baz?qux#foo`bar",
+    "base": "about:blank",
+    "href": "http://foo.bar/baz?qux#foo%60bar",
+    "origin": "http://foo.bar",
+    "protocol": "http:",
+    "username": "",
+    "password": "",
+    "host": "foo.bar",
+    "hostname": "foo.bar",
+    "port": "",
+    "pathname": "/baz",
+    "search": "?qux",
+    "searchParams": "qux=",
+    "hash": "#foo%60bar"
+  },
   "# IPv4 parsing (via https://github.com/nodejs/node/pull/10317)",
   {
     "input": "http://192.168.257",
diff --git a/third_party/WebKit/LayoutTests/platform/linux/external/wpt/url/a-element-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/external/wpt/url/a-element-expected.txt
index 2ef0ed9..0b7c3db 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/external/wpt/url/a-element-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/external/wpt/url/a-element-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 509 tests; 331 PASS, 178 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 513 tests; 327 PASS, 186 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS Parsing: <http://example	.
 org> against <http://example.org/foo/bar>
@@ -13,8 +13,8 @@
 > against <http://example.org/foo/bar>
 PASS Parsing: < foo.com  > against <http://example.org/foo/bar>
 PASS Parsing: <a:	 foo.com> against <http://example.org/foo/bar>
-PASS Parsing: <http://f:21/ b ? d # e > against <http://example.org/foo/bar>
-PASS Parsing: <lolscheme:x x#x x> against <about:blank>
+FAIL Parsing: <http://f:21/ b ? d # e > against <http://example.org/foo/bar> assert_equals: href expected "http://f:21/%20b%20?%20d%20#%20e" but got "http://f:21/%20b%20?%20d%20# e"
+FAIL Parsing: <lolscheme:x x#x x> against <about:blank> assert_equals: href expected "lolscheme:x x#x%20x" but got "lolscheme:x x#x x"
 PASS Parsing: <http://f:/c> against <http://example.org/foo/bar>
 PASS Parsing: <http://f:0/c> against <http://example.org/foo/bar>
 PASS Parsing: <http://f:00000000000000/c> against <http://example.org/foo/bar>
@@ -165,8 +165,8 @@
 PASS Parsing: <http://example.com//foo> against <about:blank>
 PASS Parsing: <http://example.com/‮/foo/‭/bar> against <about:blank>
 PASS Parsing: <http://www.google.com/foo?bar=baz#> against <about:blank>
-PASS Parsing: <http://www.google.com/foo?bar=baz# »> against <about:blank>
-PASS Parsing: <data:test# »> against <about:blank>
+FAIL Parsing: <http://www.google.com/foo?bar=baz# »> against <about:blank> assert_equals: href expected "http://www.google.com/foo?bar=baz#%20%C2%BB" but got "http://www.google.com/foo?bar=baz# %C2%BB"
+FAIL Parsing: <data:test# »> against <about:blank> assert_equals: href expected "data:test#%20%C2%BB" but got "data:test# %C2%BB"
 PASS Parsing: <http://www.google.com> against <about:blank>
 PASS Parsing: <http://192.0x00A80001> against <about:blank>
 FAIL Parsing: <http://www/foo%2Ehtml> against <about:blank> assert_equals: href expected "http://www/foo%2Ehtml" but got "http://www/foo.html"
@@ -379,6 +379,10 @@
 PASS Parsing: <http:> against <https://example.org/foo/bar>
 PASS Parsing: <sc:> against <https://example.org/foo/bar>
 PASS Parsing: <http://foo.bar/baz?qux#foobar> against <about:blank>
+FAIL Parsing: <http://foo.bar/baz?qux#foo"bar> against <about:blank> assert_equals: href expected "http://foo.bar/baz?qux#foo%22bar" but got "http://foo.bar/baz?qux#foo\"bar"
+FAIL Parsing: <http://foo.bar/baz?qux#foo<bar> against <about:blank> assert_equals: href expected "http://foo.bar/baz?qux#foo%3Cbar" but got "http://foo.bar/baz?qux#foo<bar"
+FAIL Parsing: <http://foo.bar/baz?qux#foo>bar> against <about:blank> assert_equals: href expected "http://foo.bar/baz?qux#foo%3Ebar" but got "http://foo.bar/baz?qux#foo>bar"
+FAIL Parsing: <http://foo.bar/baz?qux#foo`bar> against <about:blank> assert_equals: href expected "http://foo.bar/baz?qux#foo%60bar" but got "http://foo.bar/baz?qux#foo`bar"
 PASS Parsing: <http://192.168.257> against <http://other.com/>
 PASS Parsing: <http://192.168.257.com> against <http://other.com/>
 PASS Parsing: <http://256> against <http://other.com/>
diff --git a/third_party/WebKit/LayoutTests/platform/linux/external/wpt/url/a-element-origin-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/external/wpt/url/a-element-origin-expected.txt
index 424ca1b..c64d484 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/external/wpt/url/a-element-origin-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/external/wpt/url/a-element-origin-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 296 tests; 223 PASS, 73 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 300 tests; 227 PASS, 73 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS Parsing origin: <http://example	.
 org> against <http://example.org/foo/bar>
@@ -276,6 +276,10 @@
 PASS Parsing origin: <http:> against <http://example.org/foo/bar>
 FAIL Parsing origin: <sc:> against <https://example.org/foo/bar> assert_equals: origin expected "null" but got "sc://"
 PASS Parsing origin: <http://foo.bar/baz?qux#foobar> against <about:blank>
+PASS Parsing origin: <http://foo.bar/baz?qux#foo"bar> against <about:blank>
+PASS Parsing origin: <http://foo.bar/baz?qux#foo<bar> against <about:blank>
+PASS Parsing origin: <http://foo.bar/baz?qux#foo>bar> against <about:blank>
+PASS Parsing origin: <http://foo.bar/baz?qux#foo`bar> against <about:blank>
 PASS Parsing origin: <http://192.168.257> against <http://other.com/>
 PASS Parsing origin: <http://192.168.257.com> against <http://other.com/>
 PASS Parsing origin: <http://256> against <http://other.com/>
diff --git a/third_party/WebKit/LayoutTests/platform/linux/external/wpt/url/a-element-origin-xhtml-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/external/wpt/url/a-element-origin-xhtml-expected.txt
index 424ca1b..c64d484 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/external/wpt/url/a-element-origin-xhtml-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/external/wpt/url/a-element-origin-xhtml-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 296 tests; 223 PASS, 73 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 300 tests; 227 PASS, 73 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS Parsing origin: <http://example	.
 org> against <http://example.org/foo/bar>
@@ -276,6 +276,10 @@
 PASS Parsing origin: <http:> against <http://example.org/foo/bar>
 FAIL Parsing origin: <sc:> against <https://example.org/foo/bar> assert_equals: origin expected "null" but got "sc://"
 PASS Parsing origin: <http://foo.bar/baz?qux#foobar> against <about:blank>
+PASS Parsing origin: <http://foo.bar/baz?qux#foo"bar> against <about:blank>
+PASS Parsing origin: <http://foo.bar/baz?qux#foo<bar> against <about:blank>
+PASS Parsing origin: <http://foo.bar/baz?qux#foo>bar> against <about:blank>
+PASS Parsing origin: <http://foo.bar/baz?qux#foo`bar> against <about:blank>
 PASS Parsing origin: <http://192.168.257> against <http://other.com/>
 PASS Parsing origin: <http://192.168.257.com> against <http://other.com/>
 PASS Parsing origin: <http://256> against <http://other.com/>
diff --git a/third_party/WebKit/LayoutTests/platform/linux/external/wpt/url/a-element-xhtml-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/external/wpt/url/a-element-xhtml-expected.txt
index 2ef0ed9..0b7c3db 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/external/wpt/url/a-element-xhtml-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/external/wpt/url/a-element-xhtml-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 509 tests; 331 PASS, 178 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 513 tests; 327 PASS, 186 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS Parsing: <http://example	.
 org> against <http://example.org/foo/bar>
@@ -13,8 +13,8 @@
 > against <http://example.org/foo/bar>
 PASS Parsing: < foo.com  > against <http://example.org/foo/bar>
 PASS Parsing: <a:	 foo.com> against <http://example.org/foo/bar>
-PASS Parsing: <http://f:21/ b ? d # e > against <http://example.org/foo/bar>
-PASS Parsing: <lolscheme:x x#x x> against <about:blank>
+FAIL Parsing: <http://f:21/ b ? d # e > against <http://example.org/foo/bar> assert_equals: href expected "http://f:21/%20b%20?%20d%20#%20e" but got "http://f:21/%20b%20?%20d%20# e"
+FAIL Parsing: <lolscheme:x x#x x> against <about:blank> assert_equals: href expected "lolscheme:x x#x%20x" but got "lolscheme:x x#x x"
 PASS Parsing: <http://f:/c> against <http://example.org/foo/bar>
 PASS Parsing: <http://f:0/c> against <http://example.org/foo/bar>
 PASS Parsing: <http://f:00000000000000/c> against <http://example.org/foo/bar>
@@ -165,8 +165,8 @@
 PASS Parsing: <http://example.com//foo> against <about:blank>
 PASS Parsing: <http://example.com/‮/foo/‭/bar> against <about:blank>
 PASS Parsing: <http://www.google.com/foo?bar=baz#> against <about:blank>
-PASS Parsing: <http://www.google.com/foo?bar=baz# »> against <about:blank>
-PASS Parsing: <data:test# »> against <about:blank>
+FAIL Parsing: <http://www.google.com/foo?bar=baz# »> against <about:blank> assert_equals: href expected "http://www.google.com/foo?bar=baz#%20%C2%BB" but got "http://www.google.com/foo?bar=baz# %C2%BB"
+FAIL Parsing: <data:test# »> against <about:blank> assert_equals: href expected "data:test#%20%C2%BB" but got "data:test# %C2%BB"
 PASS Parsing: <http://www.google.com> against <about:blank>
 PASS Parsing: <http://192.0x00A80001> against <about:blank>
 FAIL Parsing: <http://www/foo%2Ehtml> against <about:blank> assert_equals: href expected "http://www/foo%2Ehtml" but got "http://www/foo.html"
@@ -379,6 +379,10 @@
 PASS Parsing: <http:> against <https://example.org/foo/bar>
 PASS Parsing: <sc:> against <https://example.org/foo/bar>
 PASS Parsing: <http://foo.bar/baz?qux#foobar> against <about:blank>
+FAIL Parsing: <http://foo.bar/baz?qux#foo"bar> against <about:blank> assert_equals: href expected "http://foo.bar/baz?qux#foo%22bar" but got "http://foo.bar/baz?qux#foo\"bar"
+FAIL Parsing: <http://foo.bar/baz?qux#foo<bar> against <about:blank> assert_equals: href expected "http://foo.bar/baz?qux#foo%3Cbar" but got "http://foo.bar/baz?qux#foo<bar"
+FAIL Parsing: <http://foo.bar/baz?qux#foo>bar> against <about:blank> assert_equals: href expected "http://foo.bar/baz?qux#foo%3Ebar" but got "http://foo.bar/baz?qux#foo>bar"
+FAIL Parsing: <http://foo.bar/baz?qux#foo`bar> against <about:blank> assert_equals: href expected "http://foo.bar/baz?qux#foo%60bar" but got "http://foo.bar/baz?qux#foo`bar"
 PASS Parsing: <http://192.168.257> against <http://other.com/>
 PASS Parsing: <http://192.168.257.com> against <http://other.com/>
 PASS Parsing: <http://256> against <http://other.com/>
diff --git a/third_party/WebKit/LayoutTests/platform/linux/external/wpt/url/url-constructor-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/external/wpt/url/url-constructor-expected.txt
index b57016a..a42dbef 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/external/wpt/url/url-constructor-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/external/wpt/url/url-constructor-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 513 tests; 401 PASS, 112 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 517 tests; 397 PASS, 120 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS URL.searchParams getter
 PASS URL.searchParams updating, clearing
 PASS URL.searchParams setter, invalid values
@@ -17,8 +17,8 @@
 > against <http://example.org/foo/bar>
 PASS Parsing: < foo.com  > against <http://example.org/foo/bar>
 PASS Parsing: <a:	 foo.com> against <http://example.org/foo/bar>
-PASS Parsing: <http://f:21/ b ? d # e > against <http://example.org/foo/bar>
-PASS Parsing: <lolscheme:x x#x x> against <about:blank>
+FAIL Parsing: <http://f:21/ b ? d # e > against <http://example.org/foo/bar> assert_equals: href expected "http://f:21/%20b%20?%20d%20#%20e" but got "http://f:21/%20b%20?%20d%20# e"
+FAIL Parsing: <lolscheme:x x#x x> against <about:blank> assert_equals: href expected "lolscheme:x x#x%20x" but got "lolscheme:x x#x x"
 PASS Parsing: <http://f:/c> against <http://example.org/foo/bar>
 PASS Parsing: <http://f:0/c> against <http://example.org/foo/bar>
 PASS Parsing: <http://f:00000000000000/c> against <http://example.org/foo/bar>
@@ -171,8 +171,8 @@
 PASS Parsing: <http://example.com//foo> against <about:blank>
 PASS Parsing: <http://example.com/‮/foo/‭/bar> against <about:blank>
 PASS Parsing: <http://www.google.com/foo?bar=baz#> against <about:blank>
-PASS Parsing: <http://www.google.com/foo?bar=baz# »> against <about:blank>
-PASS Parsing: <data:test# »> against <about:blank>
+FAIL Parsing: <http://www.google.com/foo?bar=baz# »> against <about:blank> assert_equals: href expected "http://www.google.com/foo?bar=baz#%20%C2%BB" but got "http://www.google.com/foo?bar=baz# %C2%BB"
+FAIL Parsing: <data:test# »> against <about:blank> assert_equals: href expected "data:test#%20%C2%BB" but got "data:test# %C2%BB"
 PASS Parsing: <http://www.google.com> against <about:blank>
 PASS Parsing: <http://192.0x00A80001> against <about:blank>
 FAIL Parsing: <http://www/foo%2Ehtml> against <about:blank> assert_equals: href expected "http://www/foo%2Ehtml" but got "http://www/foo.html"
@@ -423,6 +423,10 @@
 PASS Parsing: <http:> against <https://example.org/foo/bar>
 PASS Parsing: <sc:> against <https://example.org/foo/bar>
 PASS Parsing: <http://foo.bar/baz?qux#foobar> against <about:blank>
+FAIL Parsing: <http://foo.bar/baz?qux#foo"bar> against <about:blank> assert_equals: href expected "http://foo.bar/baz?qux#foo%22bar" but got "http://foo.bar/baz?qux#foo\"bar"
+FAIL Parsing: <http://foo.bar/baz?qux#foo<bar> against <about:blank> assert_equals: href expected "http://foo.bar/baz?qux#foo%3Cbar" but got "http://foo.bar/baz?qux#foo<bar"
+FAIL Parsing: <http://foo.bar/baz?qux#foo>bar> against <about:blank> assert_equals: href expected "http://foo.bar/baz?qux#foo%3Ebar" but got "http://foo.bar/baz?qux#foo>bar"
+FAIL Parsing: <http://foo.bar/baz?qux#foo`bar> against <about:blank> assert_equals: href expected "http://foo.bar/baz?qux#foo%60bar" but got "http://foo.bar/baz?qux#foo`bar"
 PASS Parsing: <http://192.168.257> against <http://other.com/>
 PASS Parsing: <http://192.168.257.com> against <http://other.com/>
 PASS Parsing: <http://256> against <http://other.com/>
diff --git a/third_party/WebKit/LayoutTests/platform/linux/external/wpt/url/url-origin-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/external/wpt/url/url-origin-expected.txt
index a42955a..46cafc0 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/external/wpt/url/url-origin-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/external/wpt/url/url-origin-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 296 tests; 221 PASS, 75 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 300 tests; 225 PASS, 75 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS Origin parsing: <http://example	.
 org> against <http://example.org/foo/bar>
@@ -276,6 +276,10 @@
 PASS Origin parsing: <http:> against <http://example.org/foo/bar>
 FAIL Origin parsing: <sc:> against <https://example.org/foo/bar> assert_equals: origin expected "null" but got "sc://"
 PASS Origin parsing: <http://foo.bar/baz?qux#foobar> against <about:blank>
+PASS Origin parsing: <http://foo.bar/baz?qux#foo"bar> against <about:blank>
+PASS Origin parsing: <http://foo.bar/baz?qux#foo<bar> against <about:blank>
+PASS Origin parsing: <http://foo.bar/baz?qux#foo>bar> against <about:blank>
+PASS Origin parsing: <http://foo.bar/baz?qux#foo`bar> against <about:blank>
 PASS Origin parsing: <http://192.168.257> against <http://other.com/>
 PASS Origin parsing: <http://192.168.257.com> against <http://other.com/>
 PASS Origin parsing: <http://256> against <http://other.com/>
diff --git a/third_party/WebKit/LayoutTests/platform/linux/external/wpt/url/url-setters-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/external/wpt/url/url-setters-expected.txt
index 8d9d78f..8bfc0cb 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/external/wpt/url/url-setters-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/external/wpt/url/url-setters-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 574 tests; 278 PASS, 296 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 589 tests; 278 PASS, 311 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS URL: Setting <a://example.net>.protocol = '' The empty string is not a valid scheme. Setter leaves the URL unchanged.
 PASS <a>: Setting <a://example.net>.protocol = '' The empty string is not a valid scheme. Setter leaves the URL unchanged.
@@ -583,12 +583,27 @@
 PASS URL: Setting <https://example.net?lang=en-US#nav>.hash = ''
 PASS <a>: Setting <https://example.net?lang=en-US#nav>.hash = ''
 PASS <area>: Setting <https://example.net?lang=en-US#nav>.hash = ''
+FAIL URL: Setting <http://example.net>.hash = '#foo bar' assert_equals: expected "http://example.net/#foo%20bar" but got "http://example.net/#foo bar"
+FAIL <a>: Setting <http://example.net>.hash = '#foo bar' assert_equals: expected "http://example.net/#foo%20bar" but got "http://example.net/#foo bar"
+FAIL <area>: Setting <http://example.net>.hash = '#foo bar' assert_equals: expected "http://example.net/#foo%20bar" but got "http://example.net/#foo bar"
+FAIL URL: Setting <http://example.net>.hash = '#foo"bar' assert_equals: expected "http://example.net/#foo%22bar" but got "http://example.net/#foo\"bar"
+FAIL <a>: Setting <http://example.net>.hash = '#foo"bar' assert_equals: expected "http://example.net/#foo%22bar" but got "http://example.net/#foo\"bar"
+FAIL <area>: Setting <http://example.net>.hash = '#foo"bar' assert_equals: expected "http://example.net/#foo%22bar" but got "http://example.net/#foo\"bar"
+FAIL URL: Setting <http://example.net>.hash = '#foo<bar' assert_equals: expected "http://example.net/#foo%3Cbar" but got "http://example.net/#foo<bar"
+FAIL <a>: Setting <http://example.net>.hash = '#foo<bar' assert_equals: expected "http://example.net/#foo%3Cbar" but got "http://example.net/#foo<bar"
+FAIL <area>: Setting <http://example.net>.hash = '#foo<bar' assert_equals: expected "http://example.net/#foo%3Cbar" but got "http://example.net/#foo<bar"
+FAIL URL: Setting <http://example.net>.hash = '#foo>bar' assert_equals: expected "http://example.net/#foo%3Ebar" but got "http://example.net/#foo>bar"
+FAIL <a>: Setting <http://example.net>.hash = '#foo>bar' assert_equals: expected "http://example.net/#foo%3Ebar" but got "http://example.net/#foo>bar"
+FAIL <area>: Setting <http://example.net>.hash = '#foo>bar' assert_equals: expected "http://example.net/#foo%3Ebar" but got "http://example.net/#foo>bar"
+FAIL URL: Setting <http://example.net>.hash = '#foo`bar' assert_equals: expected "http://example.net/#foo%60bar" but got "http://example.net/#foo`bar"
+FAIL <a>: Setting <http://example.net>.hash = '#foo`bar' assert_equals: expected "http://example.net/#foo%60bar" but got "http://example.net/#foo`bar"
+FAIL <area>: Setting <http://example.net>.hash = '#foo`bar' assert_equals: expected "http://example.net/#foo%60bar" but got "http://example.net/#foo`bar"
 FAIL URL: Setting <a:/>.hash = '\0	
-\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~€Éé' Simple percent-encoding; nuls, tabs, and newlines are removed assert_equals: expected "a:/#%01%1F !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/#%00%01%09%0A%0D%1F !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~%C2%80%C2%81%C3%89%C3%A9"
+\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~€Éé' Simple percent-encoding; nuls, tabs, and newlines are removed assert_equals: expected "a:/#%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/#%00%01%09%0A%0D%1F !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~%C2%80%C2%81%C3%89%C3%A9"
 FAIL <a>: Setting <a:/>.hash = '\0	
-\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~€Éé' Simple percent-encoding; nuls, tabs, and newlines are removed assert_equals: expected "a:/#%01%1F !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/#%00%01%09%0A%0D%1F !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~%C2%80%C2%81%C3%89%C3%A9"
+\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~€Éé' Simple percent-encoding; nuls, tabs, and newlines are removed assert_equals: expected "a:/#%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/#%00%01%09%0A%0D%1F !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~%C2%80%C2%81%C3%89%C3%A9"
 FAIL <area>: Setting <a:/>.hash = '\0	
-\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~€Éé' Simple percent-encoding; nuls, tabs, and newlines are removed assert_equals: expected "a:/#%01%1F !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/#%00%01%09%0A%0D%1F !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~%C2%80%C2%81%C3%89%C3%A9"
+\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~€Éé' Simple percent-encoding; nuls, tabs, and newlines are removed assert_equals: expected "a:/#%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/#%00%01%09%0A%0D%1F !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~%C2%80%C2%81%C3%89%C3%A9"
 PASS URL: Setting <http://example.net>.hash = '%c3%89té' Bytes already percent-encoded are left as-is
 PASS <a>: Setting <http://example.net>.hash = '%c3%89té' Bytes already percent-encoded are left as-is
 PASS <area>: Setting <http://example.net>.hash = '%c3%89té' Bytes already percent-encoded are left as-is
diff --git a/third_party/WebKit/LayoutTests/platform/mac/external/wpt/url/a-element-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/external/wpt/url/a-element-expected.txt
index 2ef0ed9..0b7c3db 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/external/wpt/url/a-element-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/external/wpt/url/a-element-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 509 tests; 331 PASS, 178 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 513 tests; 327 PASS, 186 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS Parsing: <http://example	.
 org> against <http://example.org/foo/bar>
@@ -13,8 +13,8 @@
 > against <http://example.org/foo/bar>
 PASS Parsing: < foo.com  > against <http://example.org/foo/bar>
 PASS Parsing: <a:	 foo.com> against <http://example.org/foo/bar>
-PASS Parsing: <http://f:21/ b ? d # e > against <http://example.org/foo/bar>
-PASS Parsing: <lolscheme:x x#x x> against <about:blank>
+FAIL Parsing: <http://f:21/ b ? d # e > against <http://example.org/foo/bar> assert_equals: href expected "http://f:21/%20b%20?%20d%20#%20e" but got "http://f:21/%20b%20?%20d%20# e"
+FAIL Parsing: <lolscheme:x x#x x> against <about:blank> assert_equals: href expected "lolscheme:x x#x%20x" but got "lolscheme:x x#x x"
 PASS Parsing: <http://f:/c> against <http://example.org/foo/bar>
 PASS Parsing: <http://f:0/c> against <http://example.org/foo/bar>
 PASS Parsing: <http://f:00000000000000/c> against <http://example.org/foo/bar>
@@ -165,8 +165,8 @@
 PASS Parsing: <http://example.com//foo> against <about:blank>
 PASS Parsing: <http://example.com/‮/foo/‭/bar> against <about:blank>
 PASS Parsing: <http://www.google.com/foo?bar=baz#> against <about:blank>
-PASS Parsing: <http://www.google.com/foo?bar=baz# »> against <about:blank>
-PASS Parsing: <data:test# »> against <about:blank>
+FAIL Parsing: <http://www.google.com/foo?bar=baz# »> against <about:blank> assert_equals: href expected "http://www.google.com/foo?bar=baz#%20%C2%BB" but got "http://www.google.com/foo?bar=baz# %C2%BB"
+FAIL Parsing: <data:test# »> against <about:blank> assert_equals: href expected "data:test#%20%C2%BB" but got "data:test# %C2%BB"
 PASS Parsing: <http://www.google.com> against <about:blank>
 PASS Parsing: <http://192.0x00A80001> against <about:blank>
 FAIL Parsing: <http://www/foo%2Ehtml> against <about:blank> assert_equals: href expected "http://www/foo%2Ehtml" but got "http://www/foo.html"
@@ -379,6 +379,10 @@
 PASS Parsing: <http:> against <https://example.org/foo/bar>
 PASS Parsing: <sc:> against <https://example.org/foo/bar>
 PASS Parsing: <http://foo.bar/baz?qux#foobar> against <about:blank>
+FAIL Parsing: <http://foo.bar/baz?qux#foo"bar> against <about:blank> assert_equals: href expected "http://foo.bar/baz?qux#foo%22bar" but got "http://foo.bar/baz?qux#foo\"bar"
+FAIL Parsing: <http://foo.bar/baz?qux#foo<bar> against <about:blank> assert_equals: href expected "http://foo.bar/baz?qux#foo%3Cbar" but got "http://foo.bar/baz?qux#foo<bar"
+FAIL Parsing: <http://foo.bar/baz?qux#foo>bar> against <about:blank> assert_equals: href expected "http://foo.bar/baz?qux#foo%3Ebar" but got "http://foo.bar/baz?qux#foo>bar"
+FAIL Parsing: <http://foo.bar/baz?qux#foo`bar> against <about:blank> assert_equals: href expected "http://foo.bar/baz?qux#foo%60bar" but got "http://foo.bar/baz?qux#foo`bar"
 PASS Parsing: <http://192.168.257> against <http://other.com/>
 PASS Parsing: <http://192.168.257.com> against <http://other.com/>
 PASS Parsing: <http://256> against <http://other.com/>
diff --git a/third_party/WebKit/LayoutTests/platform/mac/external/wpt/url/a-element-origin-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/external/wpt/url/a-element-origin-expected.txt
index 424ca1b..c64d484 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/external/wpt/url/a-element-origin-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/external/wpt/url/a-element-origin-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 296 tests; 223 PASS, 73 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 300 tests; 227 PASS, 73 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS Parsing origin: <http://example	.
 org> against <http://example.org/foo/bar>
@@ -276,6 +276,10 @@
 PASS Parsing origin: <http:> against <http://example.org/foo/bar>
 FAIL Parsing origin: <sc:> against <https://example.org/foo/bar> assert_equals: origin expected "null" but got "sc://"
 PASS Parsing origin: <http://foo.bar/baz?qux#foobar> against <about:blank>
+PASS Parsing origin: <http://foo.bar/baz?qux#foo"bar> against <about:blank>
+PASS Parsing origin: <http://foo.bar/baz?qux#foo<bar> against <about:blank>
+PASS Parsing origin: <http://foo.bar/baz?qux#foo>bar> against <about:blank>
+PASS Parsing origin: <http://foo.bar/baz?qux#foo`bar> against <about:blank>
 PASS Parsing origin: <http://192.168.257> against <http://other.com/>
 PASS Parsing origin: <http://192.168.257.com> against <http://other.com/>
 PASS Parsing origin: <http://256> against <http://other.com/>
diff --git a/third_party/WebKit/LayoutTests/platform/mac/external/wpt/url/a-element-origin-xhtml-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/external/wpt/url/a-element-origin-xhtml-expected.txt
index 424ca1b..c64d484 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/external/wpt/url/a-element-origin-xhtml-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/external/wpt/url/a-element-origin-xhtml-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 296 tests; 223 PASS, 73 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 300 tests; 227 PASS, 73 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS Parsing origin: <http://example	.
 org> against <http://example.org/foo/bar>
@@ -276,6 +276,10 @@
 PASS Parsing origin: <http:> against <http://example.org/foo/bar>
 FAIL Parsing origin: <sc:> against <https://example.org/foo/bar> assert_equals: origin expected "null" but got "sc://"
 PASS Parsing origin: <http://foo.bar/baz?qux#foobar> against <about:blank>
+PASS Parsing origin: <http://foo.bar/baz?qux#foo"bar> against <about:blank>
+PASS Parsing origin: <http://foo.bar/baz?qux#foo<bar> against <about:blank>
+PASS Parsing origin: <http://foo.bar/baz?qux#foo>bar> against <about:blank>
+PASS Parsing origin: <http://foo.bar/baz?qux#foo`bar> against <about:blank>
 PASS Parsing origin: <http://192.168.257> against <http://other.com/>
 PASS Parsing origin: <http://192.168.257.com> against <http://other.com/>
 PASS Parsing origin: <http://256> against <http://other.com/>
diff --git a/third_party/WebKit/LayoutTests/platform/mac/external/wpt/url/a-element-xhtml-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/external/wpt/url/a-element-xhtml-expected.txt
index 2ef0ed9..0b7c3db 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/external/wpt/url/a-element-xhtml-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/external/wpt/url/a-element-xhtml-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 509 tests; 331 PASS, 178 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 513 tests; 327 PASS, 186 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS Parsing: <http://example	.
 org> against <http://example.org/foo/bar>
@@ -13,8 +13,8 @@
 > against <http://example.org/foo/bar>
 PASS Parsing: < foo.com  > against <http://example.org/foo/bar>
 PASS Parsing: <a:	 foo.com> against <http://example.org/foo/bar>
-PASS Parsing: <http://f:21/ b ? d # e > against <http://example.org/foo/bar>
-PASS Parsing: <lolscheme:x x#x x> against <about:blank>
+FAIL Parsing: <http://f:21/ b ? d # e > against <http://example.org/foo/bar> assert_equals: href expected "http://f:21/%20b%20?%20d%20#%20e" but got "http://f:21/%20b%20?%20d%20# e"
+FAIL Parsing: <lolscheme:x x#x x> against <about:blank> assert_equals: href expected "lolscheme:x x#x%20x" but got "lolscheme:x x#x x"
 PASS Parsing: <http://f:/c> against <http://example.org/foo/bar>
 PASS Parsing: <http://f:0/c> against <http://example.org/foo/bar>
 PASS Parsing: <http://f:00000000000000/c> against <http://example.org/foo/bar>
@@ -165,8 +165,8 @@
 PASS Parsing: <http://example.com//foo> against <about:blank>
 PASS Parsing: <http://example.com/‮/foo/‭/bar> against <about:blank>
 PASS Parsing: <http://www.google.com/foo?bar=baz#> against <about:blank>
-PASS Parsing: <http://www.google.com/foo?bar=baz# »> against <about:blank>
-PASS Parsing: <data:test# »> against <about:blank>
+FAIL Parsing: <http://www.google.com/foo?bar=baz# »> against <about:blank> assert_equals: href expected "http://www.google.com/foo?bar=baz#%20%C2%BB" but got "http://www.google.com/foo?bar=baz# %C2%BB"
+FAIL Parsing: <data:test# »> against <about:blank> assert_equals: href expected "data:test#%20%C2%BB" but got "data:test# %C2%BB"
 PASS Parsing: <http://www.google.com> against <about:blank>
 PASS Parsing: <http://192.0x00A80001> against <about:blank>
 FAIL Parsing: <http://www/foo%2Ehtml> against <about:blank> assert_equals: href expected "http://www/foo%2Ehtml" but got "http://www/foo.html"
@@ -379,6 +379,10 @@
 PASS Parsing: <http:> against <https://example.org/foo/bar>
 PASS Parsing: <sc:> against <https://example.org/foo/bar>
 PASS Parsing: <http://foo.bar/baz?qux#foobar> against <about:blank>
+FAIL Parsing: <http://foo.bar/baz?qux#foo"bar> against <about:blank> assert_equals: href expected "http://foo.bar/baz?qux#foo%22bar" but got "http://foo.bar/baz?qux#foo\"bar"
+FAIL Parsing: <http://foo.bar/baz?qux#foo<bar> against <about:blank> assert_equals: href expected "http://foo.bar/baz?qux#foo%3Cbar" but got "http://foo.bar/baz?qux#foo<bar"
+FAIL Parsing: <http://foo.bar/baz?qux#foo>bar> against <about:blank> assert_equals: href expected "http://foo.bar/baz?qux#foo%3Ebar" but got "http://foo.bar/baz?qux#foo>bar"
+FAIL Parsing: <http://foo.bar/baz?qux#foo`bar> against <about:blank> assert_equals: href expected "http://foo.bar/baz?qux#foo%60bar" but got "http://foo.bar/baz?qux#foo`bar"
 PASS Parsing: <http://192.168.257> against <http://other.com/>
 PASS Parsing: <http://192.168.257.com> against <http://other.com/>
 PASS Parsing: <http://256> against <http://other.com/>
diff --git a/third_party/WebKit/LayoutTests/platform/mac/external/wpt/url/url-constructor-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/external/wpt/url/url-constructor-expected.txt
index b57016a..a42dbef 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/external/wpt/url/url-constructor-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/external/wpt/url/url-constructor-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 513 tests; 401 PASS, 112 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 517 tests; 397 PASS, 120 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS URL.searchParams getter
 PASS URL.searchParams updating, clearing
 PASS URL.searchParams setter, invalid values
@@ -17,8 +17,8 @@
 > against <http://example.org/foo/bar>
 PASS Parsing: < foo.com  > against <http://example.org/foo/bar>
 PASS Parsing: <a:	 foo.com> against <http://example.org/foo/bar>
-PASS Parsing: <http://f:21/ b ? d # e > against <http://example.org/foo/bar>
-PASS Parsing: <lolscheme:x x#x x> against <about:blank>
+FAIL Parsing: <http://f:21/ b ? d # e > against <http://example.org/foo/bar> assert_equals: href expected "http://f:21/%20b%20?%20d%20#%20e" but got "http://f:21/%20b%20?%20d%20# e"
+FAIL Parsing: <lolscheme:x x#x x> against <about:blank> assert_equals: href expected "lolscheme:x x#x%20x" but got "lolscheme:x x#x x"
 PASS Parsing: <http://f:/c> against <http://example.org/foo/bar>
 PASS Parsing: <http://f:0/c> against <http://example.org/foo/bar>
 PASS Parsing: <http://f:00000000000000/c> against <http://example.org/foo/bar>
@@ -171,8 +171,8 @@
 PASS Parsing: <http://example.com//foo> against <about:blank>
 PASS Parsing: <http://example.com/‮/foo/‭/bar> against <about:blank>
 PASS Parsing: <http://www.google.com/foo?bar=baz#> against <about:blank>
-PASS Parsing: <http://www.google.com/foo?bar=baz# »> against <about:blank>
-PASS Parsing: <data:test# »> against <about:blank>
+FAIL Parsing: <http://www.google.com/foo?bar=baz# »> against <about:blank> assert_equals: href expected "http://www.google.com/foo?bar=baz#%20%C2%BB" but got "http://www.google.com/foo?bar=baz# %C2%BB"
+FAIL Parsing: <data:test# »> against <about:blank> assert_equals: href expected "data:test#%20%C2%BB" but got "data:test# %C2%BB"
 PASS Parsing: <http://www.google.com> against <about:blank>
 PASS Parsing: <http://192.0x00A80001> against <about:blank>
 FAIL Parsing: <http://www/foo%2Ehtml> against <about:blank> assert_equals: href expected "http://www/foo%2Ehtml" but got "http://www/foo.html"
@@ -423,6 +423,10 @@
 PASS Parsing: <http:> against <https://example.org/foo/bar>
 PASS Parsing: <sc:> against <https://example.org/foo/bar>
 PASS Parsing: <http://foo.bar/baz?qux#foobar> against <about:blank>
+FAIL Parsing: <http://foo.bar/baz?qux#foo"bar> against <about:blank> assert_equals: href expected "http://foo.bar/baz?qux#foo%22bar" but got "http://foo.bar/baz?qux#foo\"bar"
+FAIL Parsing: <http://foo.bar/baz?qux#foo<bar> against <about:blank> assert_equals: href expected "http://foo.bar/baz?qux#foo%3Cbar" but got "http://foo.bar/baz?qux#foo<bar"
+FAIL Parsing: <http://foo.bar/baz?qux#foo>bar> against <about:blank> assert_equals: href expected "http://foo.bar/baz?qux#foo%3Ebar" but got "http://foo.bar/baz?qux#foo>bar"
+FAIL Parsing: <http://foo.bar/baz?qux#foo`bar> against <about:blank> assert_equals: href expected "http://foo.bar/baz?qux#foo%60bar" but got "http://foo.bar/baz?qux#foo`bar"
 PASS Parsing: <http://192.168.257> against <http://other.com/>
 PASS Parsing: <http://192.168.257.com> against <http://other.com/>
 PASS Parsing: <http://256> against <http://other.com/>
diff --git a/third_party/WebKit/LayoutTests/platform/mac/external/wpt/url/url-origin-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/external/wpt/url/url-origin-expected.txt
index a42955a..46cafc0 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/external/wpt/url/url-origin-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/external/wpt/url/url-origin-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 296 tests; 221 PASS, 75 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 300 tests; 225 PASS, 75 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS Origin parsing: <http://example	.
 org> against <http://example.org/foo/bar>
@@ -276,6 +276,10 @@
 PASS Origin parsing: <http:> against <http://example.org/foo/bar>
 FAIL Origin parsing: <sc:> against <https://example.org/foo/bar> assert_equals: origin expected "null" but got "sc://"
 PASS Origin parsing: <http://foo.bar/baz?qux#foobar> against <about:blank>
+PASS Origin parsing: <http://foo.bar/baz?qux#foo"bar> against <about:blank>
+PASS Origin parsing: <http://foo.bar/baz?qux#foo<bar> against <about:blank>
+PASS Origin parsing: <http://foo.bar/baz?qux#foo>bar> against <about:blank>
+PASS Origin parsing: <http://foo.bar/baz?qux#foo`bar> against <about:blank>
 PASS Origin parsing: <http://192.168.257> against <http://other.com/>
 PASS Origin parsing: <http://192.168.257.com> against <http://other.com/>
 PASS Origin parsing: <http://256> against <http://other.com/>
diff --git a/third_party/WebKit/LayoutTests/platform/mac/external/wpt/url/url-setters-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/external/wpt/url/url-setters-expected.txt
index 8d9d78f..8bfc0cb 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/external/wpt/url/url-setters-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/external/wpt/url/url-setters-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 574 tests; 278 PASS, 296 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 589 tests; 278 PASS, 311 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS URL: Setting <a://example.net>.protocol = '' The empty string is not a valid scheme. Setter leaves the URL unchanged.
 PASS <a>: Setting <a://example.net>.protocol = '' The empty string is not a valid scheme. Setter leaves the URL unchanged.
@@ -583,12 +583,27 @@
 PASS URL: Setting <https://example.net?lang=en-US#nav>.hash = ''
 PASS <a>: Setting <https://example.net?lang=en-US#nav>.hash = ''
 PASS <area>: Setting <https://example.net?lang=en-US#nav>.hash = ''
+FAIL URL: Setting <http://example.net>.hash = '#foo bar' assert_equals: expected "http://example.net/#foo%20bar" but got "http://example.net/#foo bar"
+FAIL <a>: Setting <http://example.net>.hash = '#foo bar' assert_equals: expected "http://example.net/#foo%20bar" but got "http://example.net/#foo bar"
+FAIL <area>: Setting <http://example.net>.hash = '#foo bar' assert_equals: expected "http://example.net/#foo%20bar" but got "http://example.net/#foo bar"
+FAIL URL: Setting <http://example.net>.hash = '#foo"bar' assert_equals: expected "http://example.net/#foo%22bar" but got "http://example.net/#foo\"bar"
+FAIL <a>: Setting <http://example.net>.hash = '#foo"bar' assert_equals: expected "http://example.net/#foo%22bar" but got "http://example.net/#foo\"bar"
+FAIL <area>: Setting <http://example.net>.hash = '#foo"bar' assert_equals: expected "http://example.net/#foo%22bar" but got "http://example.net/#foo\"bar"
+FAIL URL: Setting <http://example.net>.hash = '#foo<bar' assert_equals: expected "http://example.net/#foo%3Cbar" but got "http://example.net/#foo<bar"
+FAIL <a>: Setting <http://example.net>.hash = '#foo<bar' assert_equals: expected "http://example.net/#foo%3Cbar" but got "http://example.net/#foo<bar"
+FAIL <area>: Setting <http://example.net>.hash = '#foo<bar' assert_equals: expected "http://example.net/#foo%3Cbar" but got "http://example.net/#foo<bar"
+FAIL URL: Setting <http://example.net>.hash = '#foo>bar' assert_equals: expected "http://example.net/#foo%3Ebar" but got "http://example.net/#foo>bar"
+FAIL <a>: Setting <http://example.net>.hash = '#foo>bar' assert_equals: expected "http://example.net/#foo%3Ebar" but got "http://example.net/#foo>bar"
+FAIL <area>: Setting <http://example.net>.hash = '#foo>bar' assert_equals: expected "http://example.net/#foo%3Ebar" but got "http://example.net/#foo>bar"
+FAIL URL: Setting <http://example.net>.hash = '#foo`bar' assert_equals: expected "http://example.net/#foo%60bar" but got "http://example.net/#foo`bar"
+FAIL <a>: Setting <http://example.net>.hash = '#foo`bar' assert_equals: expected "http://example.net/#foo%60bar" but got "http://example.net/#foo`bar"
+FAIL <area>: Setting <http://example.net>.hash = '#foo`bar' assert_equals: expected "http://example.net/#foo%60bar" but got "http://example.net/#foo`bar"
 FAIL URL: Setting <a:/>.hash = '\0	
-\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~€Éé' Simple percent-encoding; nuls, tabs, and newlines are removed assert_equals: expected "a:/#%01%1F !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/#%00%01%09%0A%0D%1F !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~%C2%80%C2%81%C3%89%C3%A9"
+\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~€Éé' Simple percent-encoding; nuls, tabs, and newlines are removed assert_equals: expected "a:/#%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/#%00%01%09%0A%0D%1F !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~%C2%80%C2%81%C3%89%C3%A9"
 FAIL <a>: Setting <a:/>.hash = '\0	
-\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~€Éé' Simple percent-encoding; nuls, tabs, and newlines are removed assert_equals: expected "a:/#%01%1F !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/#%00%01%09%0A%0D%1F !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~%C2%80%C2%81%C3%89%C3%A9"
+\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~€Éé' Simple percent-encoding; nuls, tabs, and newlines are removed assert_equals: expected "a:/#%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/#%00%01%09%0A%0D%1F !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~%C2%80%C2%81%C3%89%C3%A9"
 FAIL <area>: Setting <a:/>.hash = '\0	
-\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~€Éé' Simple percent-encoding; nuls, tabs, and newlines are removed assert_equals: expected "a:/#%01%1F !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/#%00%01%09%0A%0D%1F !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~%C2%80%C2%81%C3%89%C3%A9"
+\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~€Éé' Simple percent-encoding; nuls, tabs, and newlines are removed assert_equals: expected "a:/#%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/#%00%01%09%0A%0D%1F !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~%C2%80%C2%81%C3%89%C3%A9"
 PASS URL: Setting <http://example.net>.hash = '%c3%89té' Bytes already percent-encoded are left as-is
 PASS <a>: Setting <http://example.net>.hash = '%c3%89té' Bytes already percent-encoded are left as-is
 PASS <area>: Setting <http://example.net>.hash = '%c3%89té' Bytes already percent-encoded are left as-is
diff --git a/third_party/WebKit/LayoutTests/platform/win/external/wpt/url/a-element-expected.txt b/third_party/WebKit/LayoutTests/platform/win/external/wpt/url/a-element-expected.txt
index 2d69047..57675b3a 100644
--- a/third_party/WebKit/LayoutTests/platform/win/external/wpt/url/a-element-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/external/wpt/url/a-element-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 509 tests; 327 PASS, 182 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 513 tests; 323 PASS, 190 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS Parsing: <http://example	.
 org> against <http://example.org/foo/bar>
@@ -13,8 +13,8 @@
 > against <http://example.org/foo/bar>
 PASS Parsing: < foo.com  > against <http://example.org/foo/bar>
 FAIL Parsing: <a:	 foo.com> against <http://example.org/foo/bar> assert_equals: href expected "a: foo.com" but got "file:///A:/%20foo.com"
-PASS Parsing: <http://f:21/ b ? d # e > against <http://example.org/foo/bar>
-PASS Parsing: <lolscheme:x x#x x> against <about:blank>
+FAIL Parsing: <http://f:21/ b ? d # e > against <http://example.org/foo/bar> assert_equals: href expected "http://f:21/%20b%20?%20d%20#%20e" but got "http://f:21/%20b%20?%20d%20# e"
+FAIL Parsing: <lolscheme:x x#x x> against <about:blank> assert_equals: href expected "lolscheme:x x#x%20x" but got "lolscheme:x x#x x"
 PASS Parsing: <http://f:/c> against <http://example.org/foo/bar>
 PASS Parsing: <http://f:0/c> against <http://example.org/foo/bar>
 PASS Parsing: <http://f:00000000000000/c> against <http://example.org/foo/bar>
@@ -165,8 +165,8 @@
 PASS Parsing: <http://example.com//foo> against <about:blank>
 PASS Parsing: <http://example.com/‮/foo/‭/bar> against <about:blank>
 PASS Parsing: <http://www.google.com/foo?bar=baz#> against <about:blank>
-PASS Parsing: <http://www.google.com/foo?bar=baz# »> against <about:blank>
-PASS Parsing: <data:test# »> against <about:blank>
+FAIL Parsing: <http://www.google.com/foo?bar=baz# »> against <about:blank> assert_equals: href expected "http://www.google.com/foo?bar=baz#%20%C2%BB" but got "http://www.google.com/foo?bar=baz# %C2%BB"
+FAIL Parsing: <data:test# »> against <about:blank> assert_equals: href expected "data:test#%20%C2%BB" but got "data:test# %C2%BB"
 PASS Parsing: <http://www.google.com> against <about:blank>
 PASS Parsing: <http://192.0x00A80001> against <about:blank>
 FAIL Parsing: <http://www/foo%2Ehtml> against <about:blank> assert_equals: href expected "http://www/foo%2Ehtml" but got "http://www/foo.html"
@@ -379,6 +379,10 @@
 PASS Parsing: <http:> against <https://example.org/foo/bar>
 PASS Parsing: <sc:> against <https://example.org/foo/bar>
 PASS Parsing: <http://foo.bar/baz?qux#foobar> against <about:blank>
+FAIL Parsing: <http://foo.bar/baz?qux#foo"bar> against <about:blank> assert_equals: href expected "http://foo.bar/baz?qux#foo%22bar" but got "http://foo.bar/baz?qux#foo\"bar"
+FAIL Parsing: <http://foo.bar/baz?qux#foo<bar> against <about:blank> assert_equals: href expected "http://foo.bar/baz?qux#foo%3Cbar" but got "http://foo.bar/baz?qux#foo<bar"
+FAIL Parsing: <http://foo.bar/baz?qux#foo>bar> against <about:blank> assert_equals: href expected "http://foo.bar/baz?qux#foo%3Ebar" but got "http://foo.bar/baz?qux#foo>bar"
+FAIL Parsing: <http://foo.bar/baz?qux#foo`bar> against <about:blank> assert_equals: href expected "http://foo.bar/baz?qux#foo%60bar" but got "http://foo.bar/baz?qux#foo`bar"
 PASS Parsing: <http://192.168.257> against <http://other.com/>
 PASS Parsing: <http://192.168.257.com> against <http://other.com/>
 PASS Parsing: <http://256> against <http://other.com/>
diff --git a/third_party/WebKit/LayoutTests/platform/win/external/wpt/url/a-element-origin-expected.txt b/third_party/WebKit/LayoutTests/platform/win/external/wpt/url/a-element-origin-expected.txt
index 4ca56afb..56e7c0f 100644
--- a/third_party/WebKit/LayoutTests/platform/win/external/wpt/url/a-element-origin-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/external/wpt/url/a-element-origin-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 296 tests; 223 PASS, 73 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 300 tests; 227 PASS, 73 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS Parsing origin: <http://example	.
 org> against <http://example.org/foo/bar>
@@ -276,6 +276,10 @@
 PASS Parsing origin: <http:> against <http://example.org/foo/bar>
 FAIL Parsing origin: <sc:> against <https://example.org/foo/bar> assert_equals: origin expected "null" but got "sc://"
 PASS Parsing origin: <http://foo.bar/baz?qux#foobar> against <about:blank>
+PASS Parsing origin: <http://foo.bar/baz?qux#foo"bar> against <about:blank>
+PASS Parsing origin: <http://foo.bar/baz?qux#foo<bar> against <about:blank>
+PASS Parsing origin: <http://foo.bar/baz?qux#foo>bar> against <about:blank>
+PASS Parsing origin: <http://foo.bar/baz?qux#foo`bar> against <about:blank>
 PASS Parsing origin: <http://192.168.257> against <http://other.com/>
 PASS Parsing origin: <http://192.168.257.com> against <http://other.com/>
 PASS Parsing origin: <http://256> against <http://other.com/>
diff --git a/third_party/WebKit/LayoutTests/platform/win/external/wpt/url/a-element-origin-xhtml-expected.txt b/third_party/WebKit/LayoutTests/platform/win/external/wpt/url/a-element-origin-xhtml-expected.txt
index 4ca56afb..56e7c0f 100644
--- a/third_party/WebKit/LayoutTests/platform/win/external/wpt/url/a-element-origin-xhtml-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/external/wpt/url/a-element-origin-xhtml-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 296 tests; 223 PASS, 73 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 300 tests; 227 PASS, 73 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS Parsing origin: <http://example	.
 org> against <http://example.org/foo/bar>
@@ -276,6 +276,10 @@
 PASS Parsing origin: <http:> against <http://example.org/foo/bar>
 FAIL Parsing origin: <sc:> against <https://example.org/foo/bar> assert_equals: origin expected "null" but got "sc://"
 PASS Parsing origin: <http://foo.bar/baz?qux#foobar> against <about:blank>
+PASS Parsing origin: <http://foo.bar/baz?qux#foo"bar> against <about:blank>
+PASS Parsing origin: <http://foo.bar/baz?qux#foo<bar> against <about:blank>
+PASS Parsing origin: <http://foo.bar/baz?qux#foo>bar> against <about:blank>
+PASS Parsing origin: <http://foo.bar/baz?qux#foo`bar> against <about:blank>
 PASS Parsing origin: <http://192.168.257> against <http://other.com/>
 PASS Parsing origin: <http://192.168.257.com> against <http://other.com/>
 PASS Parsing origin: <http://256> against <http://other.com/>
diff --git a/third_party/WebKit/LayoutTests/platform/win/external/wpt/url/a-element-xhtml-expected.txt b/third_party/WebKit/LayoutTests/platform/win/external/wpt/url/a-element-xhtml-expected.txt
index 2d69047..57675b3a 100644
--- a/third_party/WebKit/LayoutTests/platform/win/external/wpt/url/a-element-xhtml-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/external/wpt/url/a-element-xhtml-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 509 tests; 327 PASS, 182 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 513 tests; 323 PASS, 190 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS Parsing: <http://example	.
 org> against <http://example.org/foo/bar>
@@ -13,8 +13,8 @@
 > against <http://example.org/foo/bar>
 PASS Parsing: < foo.com  > against <http://example.org/foo/bar>
 FAIL Parsing: <a:	 foo.com> against <http://example.org/foo/bar> assert_equals: href expected "a: foo.com" but got "file:///A:/%20foo.com"
-PASS Parsing: <http://f:21/ b ? d # e > against <http://example.org/foo/bar>
-PASS Parsing: <lolscheme:x x#x x> against <about:blank>
+FAIL Parsing: <http://f:21/ b ? d # e > against <http://example.org/foo/bar> assert_equals: href expected "http://f:21/%20b%20?%20d%20#%20e" but got "http://f:21/%20b%20?%20d%20# e"
+FAIL Parsing: <lolscheme:x x#x x> against <about:blank> assert_equals: href expected "lolscheme:x x#x%20x" but got "lolscheme:x x#x x"
 PASS Parsing: <http://f:/c> against <http://example.org/foo/bar>
 PASS Parsing: <http://f:0/c> against <http://example.org/foo/bar>
 PASS Parsing: <http://f:00000000000000/c> against <http://example.org/foo/bar>
@@ -165,8 +165,8 @@
 PASS Parsing: <http://example.com//foo> against <about:blank>
 PASS Parsing: <http://example.com/‮/foo/‭/bar> against <about:blank>
 PASS Parsing: <http://www.google.com/foo?bar=baz#> against <about:blank>
-PASS Parsing: <http://www.google.com/foo?bar=baz# »> against <about:blank>
-PASS Parsing: <data:test# »> against <about:blank>
+FAIL Parsing: <http://www.google.com/foo?bar=baz# »> against <about:blank> assert_equals: href expected "http://www.google.com/foo?bar=baz#%20%C2%BB" but got "http://www.google.com/foo?bar=baz# %C2%BB"
+FAIL Parsing: <data:test# »> against <about:blank> assert_equals: href expected "data:test#%20%C2%BB" but got "data:test# %C2%BB"
 PASS Parsing: <http://www.google.com> against <about:blank>
 PASS Parsing: <http://192.0x00A80001> against <about:blank>
 FAIL Parsing: <http://www/foo%2Ehtml> against <about:blank> assert_equals: href expected "http://www/foo%2Ehtml" but got "http://www/foo.html"
@@ -379,6 +379,10 @@
 PASS Parsing: <http:> against <https://example.org/foo/bar>
 PASS Parsing: <sc:> against <https://example.org/foo/bar>
 PASS Parsing: <http://foo.bar/baz?qux#foobar> against <about:blank>
+FAIL Parsing: <http://foo.bar/baz?qux#foo"bar> against <about:blank> assert_equals: href expected "http://foo.bar/baz?qux#foo%22bar" but got "http://foo.bar/baz?qux#foo\"bar"
+FAIL Parsing: <http://foo.bar/baz?qux#foo<bar> against <about:blank> assert_equals: href expected "http://foo.bar/baz?qux#foo%3Cbar" but got "http://foo.bar/baz?qux#foo<bar"
+FAIL Parsing: <http://foo.bar/baz?qux#foo>bar> against <about:blank> assert_equals: href expected "http://foo.bar/baz?qux#foo%3Ebar" but got "http://foo.bar/baz?qux#foo>bar"
+FAIL Parsing: <http://foo.bar/baz?qux#foo`bar> against <about:blank> assert_equals: href expected "http://foo.bar/baz?qux#foo%60bar" but got "http://foo.bar/baz?qux#foo`bar"
 PASS Parsing: <http://192.168.257> against <http://other.com/>
 PASS Parsing: <http://192.168.257.com> against <http://other.com/>
 PASS Parsing: <http://256> against <http://other.com/>
diff --git a/third_party/WebKit/LayoutTests/platform/win/external/wpt/url/url-constructor-expected.txt b/third_party/WebKit/LayoutTests/platform/win/external/wpt/url/url-constructor-expected.txt
index 29fe94a..d6f70d85 100644
--- a/third_party/WebKit/LayoutTests/platform/win/external/wpt/url/url-constructor-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/external/wpt/url/url-constructor-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 513 tests; 395 PASS, 118 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 517 tests; 391 PASS, 126 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS URL.searchParams getter
 PASS URL.searchParams updating, clearing
 PASS URL.searchParams setter, invalid values
@@ -17,8 +17,8 @@
 > against <http://example.org/foo/bar>
 PASS Parsing: < foo.com  > against <http://example.org/foo/bar>
 FAIL Parsing: <a:	 foo.com> against <http://example.org/foo/bar> assert_equals: href expected "a: foo.com" but got "file:///A:/%20foo.com"
-PASS Parsing: <http://f:21/ b ? d # e > against <http://example.org/foo/bar>
-PASS Parsing: <lolscheme:x x#x x> against <about:blank>
+FAIL Parsing: <http://f:21/ b ? d # e > against <http://example.org/foo/bar> assert_equals: href expected "http://f:21/%20b%20?%20d%20#%20e" but got "http://f:21/%20b%20?%20d%20# e"
+FAIL Parsing: <lolscheme:x x#x x> against <about:blank> assert_equals: href expected "lolscheme:x x#x%20x" but got "lolscheme:x x#x x"
 PASS Parsing: <http://f:/c> against <http://example.org/foo/bar>
 PASS Parsing: <http://f:0/c> against <http://example.org/foo/bar>
 PASS Parsing: <http://f:00000000000000/c> against <http://example.org/foo/bar>
@@ -171,8 +171,8 @@
 PASS Parsing: <http://example.com//foo> against <about:blank>
 PASS Parsing: <http://example.com/‮/foo/‭/bar> against <about:blank>
 PASS Parsing: <http://www.google.com/foo?bar=baz#> against <about:blank>
-PASS Parsing: <http://www.google.com/foo?bar=baz# »> against <about:blank>
-PASS Parsing: <data:test# »> against <about:blank>
+FAIL Parsing: <http://www.google.com/foo?bar=baz# »> against <about:blank> assert_equals: href expected "http://www.google.com/foo?bar=baz#%20%C2%BB" but got "http://www.google.com/foo?bar=baz# %C2%BB"
+FAIL Parsing: <data:test# »> against <about:blank> assert_equals: href expected "data:test#%20%C2%BB" but got "data:test# %C2%BB"
 PASS Parsing: <http://www.google.com> against <about:blank>
 PASS Parsing: <http://192.0x00A80001> against <about:blank>
 FAIL Parsing: <http://www/foo%2Ehtml> against <about:blank> assert_equals: href expected "http://www/foo%2Ehtml" but got "http://www/foo.html"
@@ -423,6 +423,10 @@
 PASS Parsing: <http:> against <https://example.org/foo/bar>
 PASS Parsing: <sc:> against <https://example.org/foo/bar>
 PASS Parsing: <http://foo.bar/baz?qux#foobar> against <about:blank>
+FAIL Parsing: <http://foo.bar/baz?qux#foo"bar> against <about:blank> assert_equals: href expected "http://foo.bar/baz?qux#foo%22bar" but got "http://foo.bar/baz?qux#foo\"bar"
+FAIL Parsing: <http://foo.bar/baz?qux#foo<bar> against <about:blank> assert_equals: href expected "http://foo.bar/baz?qux#foo%3Cbar" but got "http://foo.bar/baz?qux#foo<bar"
+FAIL Parsing: <http://foo.bar/baz?qux#foo>bar> against <about:blank> assert_equals: href expected "http://foo.bar/baz?qux#foo%3Ebar" but got "http://foo.bar/baz?qux#foo>bar"
+FAIL Parsing: <http://foo.bar/baz?qux#foo`bar> against <about:blank> assert_equals: href expected "http://foo.bar/baz?qux#foo%60bar" but got "http://foo.bar/baz?qux#foo`bar"
 PASS Parsing: <http://192.168.257> against <http://other.com/>
 PASS Parsing: <http://192.168.257.com> against <http://other.com/>
 PASS Parsing: <http://256> against <http://other.com/>
diff --git a/third_party/WebKit/LayoutTests/platform/win/external/wpt/url/url-origin-expected.txt b/third_party/WebKit/LayoutTests/platform/win/external/wpt/url/url-origin-expected.txt
index 2d0fecc..cb43db3 100644
--- a/third_party/WebKit/LayoutTests/platform/win/external/wpt/url/url-origin-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/external/wpt/url/url-origin-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 296 tests; 221 PASS, 75 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 300 tests; 225 PASS, 75 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS Origin parsing: <http://example	.
 org> against <http://example.org/foo/bar>
@@ -276,6 +276,10 @@
 PASS Origin parsing: <http:> against <http://example.org/foo/bar>
 FAIL Origin parsing: <sc:> against <https://example.org/foo/bar> assert_equals: origin expected "null" but got "sc://"
 PASS Origin parsing: <http://foo.bar/baz?qux#foobar> against <about:blank>
+PASS Origin parsing: <http://foo.bar/baz?qux#foo"bar> against <about:blank>
+PASS Origin parsing: <http://foo.bar/baz?qux#foo<bar> against <about:blank>
+PASS Origin parsing: <http://foo.bar/baz?qux#foo>bar> against <about:blank>
+PASS Origin parsing: <http://foo.bar/baz?qux#foo`bar> against <about:blank>
 PASS Origin parsing: <http://192.168.257> against <http://other.com/>
 PASS Origin parsing: <http://192.168.257.com> against <http://other.com/>
 PASS Origin parsing: <http://256> against <http://other.com/>
diff --git a/third_party/WebKit/LayoutTests/platform/win/external/wpt/url/url-setters-expected.txt b/third_party/WebKit/LayoutTests/platform/win/external/wpt/url/url-setters-expected.txt
index cbdef1a..e641f22 100644
--- a/third_party/WebKit/LayoutTests/platform/win/external/wpt/url/url-setters-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/external/wpt/url/url-setters-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 574 tests; 251 PASS, 323 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 589 tests; 251 PASS, 338 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 FAIL URL: Setting <a://example.net>.protocol = '' The empty string is not a valid scheme. Setter leaves the URL unchanged. assert_equals: expected "a://example.net" but got "file:///A://example.net"
 FAIL <a>: Setting <a://example.net>.protocol = '' The empty string is not a valid scheme. Setter leaves the URL unchanged. assert_equals: expected "a://example.net" but got "file:///A://example.net"
@@ -583,12 +583,27 @@
 PASS URL: Setting <https://example.net?lang=en-US#nav>.hash = ''
 PASS <a>: Setting <https://example.net?lang=en-US#nav>.hash = ''
 PASS <area>: Setting <https://example.net?lang=en-US#nav>.hash = ''
+FAIL URL: Setting <http://example.net>.hash = '#foo bar' assert_equals: expected "http://example.net/#foo%20bar" but got "http://example.net/#foo bar"
+FAIL <a>: Setting <http://example.net>.hash = '#foo bar' assert_equals: expected "http://example.net/#foo%20bar" but got "http://example.net/#foo bar"
+FAIL <area>: Setting <http://example.net>.hash = '#foo bar' assert_equals: expected "http://example.net/#foo%20bar" but got "http://example.net/#foo bar"
+FAIL URL: Setting <http://example.net>.hash = '#foo"bar' assert_equals: expected "http://example.net/#foo%22bar" but got "http://example.net/#foo\"bar"
+FAIL <a>: Setting <http://example.net>.hash = '#foo"bar' assert_equals: expected "http://example.net/#foo%22bar" but got "http://example.net/#foo\"bar"
+FAIL <area>: Setting <http://example.net>.hash = '#foo"bar' assert_equals: expected "http://example.net/#foo%22bar" but got "http://example.net/#foo\"bar"
+FAIL URL: Setting <http://example.net>.hash = '#foo<bar' assert_equals: expected "http://example.net/#foo%3Cbar" but got "http://example.net/#foo<bar"
+FAIL <a>: Setting <http://example.net>.hash = '#foo<bar' assert_equals: expected "http://example.net/#foo%3Cbar" but got "http://example.net/#foo<bar"
+FAIL <area>: Setting <http://example.net>.hash = '#foo<bar' assert_equals: expected "http://example.net/#foo%3Cbar" but got "http://example.net/#foo<bar"
+FAIL URL: Setting <http://example.net>.hash = '#foo>bar' assert_equals: expected "http://example.net/#foo%3Ebar" but got "http://example.net/#foo>bar"
+FAIL <a>: Setting <http://example.net>.hash = '#foo>bar' assert_equals: expected "http://example.net/#foo%3Ebar" but got "http://example.net/#foo>bar"
+FAIL <area>: Setting <http://example.net>.hash = '#foo>bar' assert_equals: expected "http://example.net/#foo%3Ebar" but got "http://example.net/#foo>bar"
+FAIL URL: Setting <http://example.net>.hash = '#foo`bar' assert_equals: expected "http://example.net/#foo%60bar" but got "http://example.net/#foo`bar"
+FAIL <a>: Setting <http://example.net>.hash = '#foo`bar' assert_equals: expected "http://example.net/#foo%60bar" but got "http://example.net/#foo`bar"
+FAIL <area>: Setting <http://example.net>.hash = '#foo`bar' assert_equals: expected "http://example.net/#foo%60bar" but got "http://example.net/#foo`bar"
 FAIL URL: Setting <a:/>.hash = '\0	
-\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~€Éé' Simple percent-encoding; nuls, tabs, and newlines are removed assert_equals: expected "a:/#%01%1F !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "file:///A:/#%01%09%0A%0D%1F !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~%C2%80%C2%81%C3%89%C3%A9"
+\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~€Éé' Simple percent-encoding; nuls, tabs, and newlines are removed assert_equals: expected "a:/#%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "file:///A:/#%01%09%0A%0D%1F !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~%C2%80%C2%81%C3%89%C3%A9"
 FAIL <a>: Setting <a:/>.hash = '\0	
-\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~€Éé' Simple percent-encoding; nuls, tabs, and newlines are removed assert_equals: expected "a:/#%01%1F !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "file:///A:/#%01%09%0A%0D%1F !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~%C2%80%C2%81%C3%89%C3%A9"
+\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~€Éé' Simple percent-encoding; nuls, tabs, and newlines are removed assert_equals: expected "a:/#%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "file:///A:/#%01%09%0A%0D%1F !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~%C2%80%C2%81%C3%89%C3%A9"
 FAIL <area>: Setting <a:/>.hash = '\0	
-\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~€Éé' Simple percent-encoding; nuls, tabs, and newlines are removed assert_equals: expected "a:/#%01%1F !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "file:///A:/#%01%09%0A%0D%1F !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~%C2%80%C2%81%C3%89%C3%A9"
+\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~€Éé' Simple percent-encoding; nuls, tabs, and newlines are removed assert_equals: expected "a:/#%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "file:///A:/#%01%09%0A%0D%1F !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~%C2%80%C2%81%C3%89%C3%A9"
 PASS URL: Setting <http://example.net>.hash = '%c3%89té' Bytes already percent-encoded are left as-is
 PASS <a>: Setting <http://example.net>.hash = '%c3%89té' Bytes already percent-encoded are left as-is
 PASS <area>: Setting <http://example.net>.hash = '%c3%89té' Bytes already percent-encoded are left as-is
diff --git a/third_party/WebKit/Source/core/dom/LayoutTreeBuilder.cpp b/third_party/WebKit/Source/core/dom/LayoutTreeBuilder.cpp
index e5ccc5b4..5bb1589 100644
--- a/third_party/WebKit/Source/core/dom/LayoutTreeBuilder.cpp
+++ b/third_party/WebKit/Source/core/dom/LayoutTreeBuilder.cpp
@@ -36,6 +36,7 @@
 #include "core/fullscreen/Fullscreen.h"
 #include "core/html_names.h"
 #include "core/layout/LayoutFullScreen.h"
+#include "core/layout/LayoutInline.h"
 #include "core/layout/LayoutObject.h"
 #include "core/layout/LayoutText.h"
 #include "core/layout/LayoutView.h"
@@ -48,7 +49,7 @@
                                                          ComputedStyle* style)
     : LayoutTreeBuilder(element, nullptr), style_(style) {
   DCHECK(!element.IsActiveSlotOrActiveV0InsertionPoint());
-  // TODO(ecobos): Move the first-letter logic inside parentLayoutObject too?
+  // TODO(ecobos): Move the first-letter logic inside ParentLayoutObject too?
   // It's an extra (unnecessary) check for text nodes, though.
   if (element.IsFirstLetterPseudoElement()) {
     if (LayoutObject* next_layout_object =
@@ -74,7 +75,7 @@
 
 LayoutObject* LayoutTreeBuilderForElement::ParentLayoutObject() const {
   if (layout_object_parent_) {
-    // FIXME: Guarding this by parentLayoutObject isn't quite right as the spec
+    // FIXME: Guarding this by ParentLayoutObject isn't quite right as the spec
     // for top layer only talks about display: none ancestors so putting a
     // <dialog> inside an <optgroup> seems like it should still work even though
     // this check will prevent it.
@@ -123,7 +124,7 @@
 
   // Make sure the LayoutObject already knows it is going to be added to a
   // LayoutFlowThread before we set the style for the first time. Otherwise code
-  // using inLayoutFlowThread() in the styleWillChange and styleDidChange will
+  // using IsInsideFlowThread() in the StyleWillChange and StyleDidChange will
   // fail.
   new_layout_object->SetIsInsideFlowThread(
       parent_layout_object->IsInsideFlowThread());
@@ -131,7 +132,7 @@
   LayoutObject* next_layout_object = NextLayoutObject();
   node_->SetLayoutObject(new_layout_object);
   new_layout_object->SetStyle(
-      &style);  // setStyle() can depend on layoutObject() already being set.
+      &style);  // SetStyle() can depend on LayoutObject() already being set.
 
   if (Fullscreen::IsFullscreenElement(*node_)) {
     new_layout_object = LayoutFullScreen::WrapLayoutObject(
@@ -140,11 +141,34 @@
       return;
   }
 
-  // Note: Adding newLayoutObject instead of layoutObject(). layoutObject() may
-  // be a child of newLayoutObject.
+  // Note: Adding new_layout_object instead of LayoutObject(). LayoutObject()
+  // may be a child of new_layout_object.
   parent_layout_object->AddChild(new_layout_object, next_layout_object);
 }
 
+LayoutObject*
+LayoutTreeBuilderForText::CreateInlineWrapperForDisplayContentsIfNeeded() {
+  scoped_refptr<ComputedStyle> wrapper_style =
+      ComputedStyle::CreateInheritedDisplayContentsStyleIfNeeded(
+          *style_, layout_object_parent_->StyleRef());
+  if (!wrapper_style)
+    return nullptr;
+
+  // Text nodes which are children of display:contents element which modifies
+  // inherited properties, need to have an anonymous inline wrapper having those
+  // inherited properties because the layout code expects the LayoutObject
+  // parent of text nodes to have the same inherited properties.
+  LayoutObject* inline_wrapper =
+      LayoutInline::CreateAnonymous(&node_->GetDocument());
+  inline_wrapper->SetStyle(wrapper_style);
+  if (!layout_object_parent_->IsChildAllowed(inline_wrapper, *wrapper_style)) {
+    inline_wrapper->Destroy();
+    return nullptr;
+  }
+  layout_object_parent_->AddChild(inline_wrapper, NextLayoutObject());
+  return inline_wrapper;
+}
+
 void LayoutTreeBuilderForText::CreateLayoutObject() {
   ComputedStyle& style = *style_;
 
@@ -152,6 +176,14 @@
          ToElement(LayoutTreeBuilderTraversal::Parent(*node_))
              ->HasDisplayContentsStyle());
 
+  LayoutObject* next_layout_object;
+  if (LayoutObject* wrapper = CreateInlineWrapperForDisplayContentsIfNeeded()) {
+    layout_object_parent_ = wrapper;
+    next_layout_object = nullptr;
+  } else {
+    next_layout_object = NextLayoutObject();
+  }
+
   LayoutText* new_layout_object = node_->CreateTextLayoutObject(style);
   if (!layout_object_parent_->IsChildAllowed(new_layout_object, style)) {
     new_layout_object->Destroy();
@@ -160,14 +192,12 @@
 
   // Make sure the LayoutObject already knows it is going to be added to a
   // LayoutFlowThread before we set the style for the first time. Otherwise code
-  // using inLayoutFlowThread() in the styleWillChange and styleDidChange will
+  // using IsInsideFlowThread() in the StyleWillChange and StyleDidChange will
   // fail.
   new_layout_object->SetIsInsideFlowThread(
       layout_object_parent_->IsInsideFlowThread());
 
-  LayoutObject* next_layout_object = NextLayoutObject();
   node_->SetLayoutObject(new_layout_object);
-  // Parent takes care of the animations, no need to call setAnimatableStyle.
   new_layout_object->SetStyle(&style);
   layout_object_parent_->AddChild(new_layout_object, next_layout_object);
 }
diff --git a/third_party/WebKit/Source/core/dom/LayoutTreeBuilder.h b/third_party/WebKit/Source/core/dom/LayoutTreeBuilder.h
index 16b61b0..fd95182 100644
--- a/third_party/WebKit/Source/core/dom/LayoutTreeBuilder.h
+++ b/third_party/WebKit/Source/core/dom/LayoutTreeBuilder.h
@@ -75,7 +75,19 @@
         layout_object_parent_->GetNode()->NeedsAttach())
       return nullptr;
 
-    return LayoutTreeBuilderTraversal::NextSiblingLayoutObject(*node_);
+    LayoutObject* next =
+        LayoutTreeBuilderTraversal::NextSiblingLayoutObject(*node_);
+
+    // If a text node is wrapped in an anonymous inline for display:contents
+    // (see CreateInlineWrapperForDisplayContents()), use the wrapper as the
+    // next layout object. Otherwise we would need to add code to various
+    // AddChild() implementations to walk up the tree to find the correct
+    // layout tree parent/siblings.
+    if (next && next->IsText() && next->Parent()->IsAnonymous() &&
+        next->Parent()->IsInline()) {
+      return next->Parent();
+    }
+    return next;
   }
 
   Member<NodeType> node_;
@@ -110,8 +122,12 @@
                            ComputedStyle* style_from_parent)
       : LayoutTreeBuilder(text, layout_parent), style_(style_from_parent) {}
 
-  scoped_refptr<ComputedStyle> style_;
   void CreateLayoutObject();
+
+ private:
+  LayoutObject* CreateInlineWrapperForDisplayContentsIfNeeded();
+
+  scoped_refptr<ComputedStyle> style_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/dom/Text.cpp b/third_party/WebKit/Source/core/dom/Text.cpp
index 03a10c8..7fab404a 100644
--- a/third_party/WebKit/Source/core/dom/Text.cpp
+++ b/third_party/WebKit/Source/core/dom/Text.cpp
@@ -384,9 +384,20 @@
 
 void Text::RecalcTextStyle(StyleRecalcChange change) {
   if (LayoutTextItem layout_item = LayoutTextItem(GetLayoutObject())) {
-    if (change != kNoChange || NeedsStyleRecalc())
-      layout_item.SetStyle(
-          GetDocument().EnsureStyleResolver().StyleForText(this));
+    if (change != kNoChange || NeedsStyleRecalc()) {
+      scoped_refptr<ComputedStyle> new_style =
+          GetDocument().EnsureStyleResolver().StyleForText(this);
+      const ComputedStyle* layout_parent_style =
+          GetLayoutObject()->Parent()->Style();
+      if (new_style != layout_parent_style &&
+          !new_style->InheritedEqual(*layout_parent_style)) {
+        // The computed style or the need for an anonymous inline wrapper for a
+        // display:contents text child changed.
+        SetNeedsReattachLayoutTree();
+        return;
+      }
+      layout_item.SetStyle(std::move(new_style));
+    }
     if (NeedsStyleRecalc())
       layout_item.SetText(DataImpl());
     ClearNeedsStyleRecalc();
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlock.cpp b/third_party/WebKit/Source/core/layout/LayoutBlock.cpp
index bceab76..74baabe 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlock.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBlock.cpp
@@ -314,7 +314,7 @@
     // Insert the child into the anonymous block box instead of here.
     if (new_child->IsInline() || new_child->IsFloatingOrOutOfFlowPositioned() ||
         before_descendant->Parent()->SlowFirstChild() != before_descendant)
-      before_descendant->Parent()->AddChild(new_child, before_descendant);
+      before_descendant_container->AddChild(new_child, before_descendant);
     else
       AddChild(new_child, before_descendant->Parent());
     return;
diff --git a/third_party/WebKit/Source/core/layout/LayoutInline.cpp b/third_party/WebKit/Source/core/layout/LayoutInline.cpp
index 7d24eee..8b1d6ce 100644
--- a/third_party/WebKit/Source/core/layout/LayoutInline.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutInline.cpp
@@ -408,6 +408,7 @@
 
 LayoutInline* LayoutInline::Clone() const {
   LayoutInline* clone_inline = new LayoutInline(GetNode());
+  DCHECK(!IsAnonymous());
   clone_inline->SetStyle(MutableStyle());
   clone_inline->SetIsInsideFlowThread(IsInsideFlowThread());
   return clone_inline;
@@ -416,6 +417,8 @@
 void LayoutInline::MoveChildrenToIgnoringContinuation(
     LayoutInline* to,
     LayoutObject* start_child) {
+  DCHECK(!IsAnonymous());
+  DCHECK(!to->IsAnonymous());
   LayoutObject* child = start_child;
   while (child) {
     LayoutObject* current_child = child;
@@ -431,6 +434,7 @@
                                 LayoutObject* before_child,
                                 LayoutBoxModelObject* old_cont) {
   DCHECK(IsDescendantOf(from_block));
+  DCHECK(!IsAnonymous());
 
   // If we're splitting the inline containing the fullscreened element,
   // |beforeChild| may be the layoutObject for the fullscreened element.
diff --git a/third_party/WebKit/Source/core/layout/LayoutObjectTest.cpp b/third_party/WebKit/Source/core/layout/LayoutObjectTest.cpp
index a3ec15e7..50c645a7 100644
--- a/third_party/WebKit/Source/core/layout/LayoutObjectTest.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutObjectTest.cpp
@@ -21,8 +21,28 @@
 class LayoutObjectTest : public RenderingTest {
  public:
   LayoutObjectTest() : RenderingTest(EmptyLocalFrameClient::Create()) {}
+
+ protected:
+  template <bool should_have_wrapper>
+  void ExpectAnonymousInlineWrapperFor(Node*);
 };
 
+template <bool should_have_wrapper>
+void LayoutObjectTest::ExpectAnonymousInlineWrapperFor(Node* node) {
+  ASSERT_TRUE(node);
+  EXPECT_TRUE(node->IsTextNode());
+  LayoutObject* text_layout = node->GetLayoutObject();
+  ASSERT_TRUE(text_layout);
+  LayoutObject* text_parent = text_layout->Parent();
+  ASSERT_TRUE(text_parent);
+  if (should_have_wrapper) {
+    EXPECT_TRUE(text_parent->IsAnonymous());
+    EXPECT_TRUE(text_parent->IsInline());
+  } else {
+    EXPECT_FALSE(text_parent->IsAnonymous());
+  }
+}
+
 TEST_F(LayoutObjectTest, LayoutDecoratedNameCalledWithPositionedObject) {
   SetBodyInnerHTML("<div id='div' style='position: fixed'>test</div>");
   Element* div = GetDocument().getElementById(AtomicString("div"));
@@ -439,4 +459,70 @@
   EXPECT_EQ(LayoutRect(), object->SelectionVisualRect());
 }
 
+TEST_F(LayoutObjectTest, DisplayContentsInlineWrapper) {
+  SetBodyInnerHTML("<div id='div' style='display:contents;color:pink'>A</div>");
+  Element* div = GetDocument().getElementById("div");
+  ASSERT_TRUE(div);
+  Node* text = div->firstChild();
+  ASSERT_TRUE(text);
+  ExpectAnonymousInlineWrapperFor<true>(text);
+}
+
+TEST_F(LayoutObjectTest, DisplayContentsNoInlineWrapper) {
+  SetBodyInnerHTML("<div id='div' style='display:contents'>A</div>");
+  Element* div = GetDocument().getElementById("div");
+  ASSERT_TRUE(div);
+  Node* text = div->firstChild();
+  ASSERT_TRUE(text);
+  ExpectAnonymousInlineWrapperFor<false>(text);
+}
+
+TEST_F(LayoutObjectTest, DisplayContentsAddInlineWrapper) {
+  SetBodyInnerHTML("<div id='div' style='display:contents'>A</div>");
+  Element* div = GetDocument().getElementById("div");
+  ASSERT_TRUE(div);
+  Node* text = div->firstChild();
+  ASSERT_TRUE(text);
+  ExpectAnonymousInlineWrapperFor<false>(text);
+
+  div->SetInlineStyleProperty(CSSPropertyColor, "pink");
+  GetDocument().View()->UpdateAllLifecyclePhases();
+  ExpectAnonymousInlineWrapperFor<true>(text);
+}
+
+TEST_F(LayoutObjectTest, DisplayContentsRemoveInlineWrapper) {
+  SetBodyInnerHTML("<div id='div' style='display:contents;color:pink'>A</div>");
+  Element* div = GetDocument().getElementById("div");
+  ASSERT_TRUE(div);
+  Node* text = div->firstChild();
+  ASSERT_TRUE(text);
+  ExpectAnonymousInlineWrapperFor<true>(text);
+
+  div->RemoveInlineStyleProperty(CSSPropertyColor);
+  GetDocument().View()->UpdateAllLifecyclePhases();
+  ExpectAnonymousInlineWrapperFor<false>(text);
+}
+
+TEST_F(LayoutObjectTest, DisplayContentsWrapperPerTextNode) {
+  // This test checks the current implementation; that text node siblings do not
+  // share inline wrappers. Doing so requires code to handle all situations
+  // where text nodes are no longer layout tree siblings by splitting wrappers,
+  // and merge wrappers when text nodes become layout tree siblings.
+  SetBodyInnerHTML(
+      "<div id='div' style='display:contents;color:pink'>A<!-- -->B</div>");
+  Element* div = GetDocument().getElementById("div");
+  ASSERT_TRUE(div);
+  Node* text1 = div->firstChild();
+  ASSERT_TRUE(text1);
+  Node* text2 = div->lastChild();
+  ASSERT_TRUE(text2);
+  EXPECT_NE(text1, text2);
+
+  ExpectAnonymousInlineWrapperFor<true>(text1);
+  ExpectAnonymousInlineWrapperFor<true>(text2);
+
+  EXPECT_NE(text1->GetLayoutObject()->Parent(),
+            text2->GetLayoutObject()->Parent());
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.cpp b/third_party/WebKit/Source/core/style/ComputedStyle.cpp
index f3ea190..c7ffc19e 100644
--- a/third_party/WebKit/Source/core/style/ComputedStyle.cpp
+++ b/third_party/WebKit/Source/core/style/ComputedStyle.cpp
@@ -122,6 +122,18 @@
   return new_style;
 }
 
+scoped_refptr<ComputedStyle>
+ComputedStyle::CreateInheritedDisplayContentsStyleIfNeeded(
+    const ComputedStyle& parent_style,
+    const ComputedStyle& layout_parent_style) {
+  if (&parent_style == &layout_parent_style)
+    return nullptr;
+  if (parent_style.InheritedEqual(layout_parent_style))
+    return nullptr;
+  return ComputedStyle::CreateAnonymousStyleWithDisplay(parent_style,
+                                                        EDisplay::kInline);
+}
+
 scoped_refptr<ComputedStyle> ComputedStyle::Clone(const ComputedStyle& other) {
   return base::AdoptRef(new ComputedStyle(other));
 }
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.h b/third_party/WebKit/Source/core/style/ComputedStyle.h
index eea9544f..7338a6c 100644
--- a/third_party/WebKit/Source/core/style/ComputedStyle.h
+++ b/third_party/WebKit/Source/core/style/ComputedStyle.h
@@ -195,6 +195,10 @@
   static scoped_refptr<ComputedStyle> CreateAnonymousStyleWithDisplay(
       const ComputedStyle& parent_style,
       EDisplay);
+  static scoped_refptr<ComputedStyle>
+  CreateInheritedDisplayContentsStyleIfNeeded(
+      const ComputedStyle& parent_style,
+      const ComputedStyle& layout_parent_style);
   CORE_EXPORT static scoped_refptr<ComputedStyle> Clone(const ComputedStyle&);
   static const ComputedStyle& InitialStyle() { return MutableInitialStyle(); }
   static void InvalidateInitialStyle();