diff --git a/DEPS b/DEPS
index 37e0f28..94a562b9 100644
--- a/DEPS
+++ b/DEPS
@@ -40,7 +40,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '892af1ec7bb0deb5f40557a0d4838df9dd74a0b6',
+  'skia_revision': '05814de6ba5087ad71f189d6413246ef1d518e4b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -96,7 +96,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': 'a263e5566dcc7ea2e520c9f237ca21a556d10eaf',
+  'catapult_revision': 'b8a441daccc8d76c07e9a9374220695f2aba24bc',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
diff --git a/base/values.cc b/base/values.cc
index 768e3f79..5bed467 100644
--- a/base/values.cc
+++ b/base/values.cc
@@ -49,7 +49,7 @@
     std::unique_ptr<Value> child_copy = CopyWithoutEmptyChildren(it.value());
     if (child_copy) {
       if (!copy)
-        copy.reset(new DictionaryValue);
+        copy = MakeUnique<DictionaryValue>();
       copy->SetWithoutPathExpansion(it.key(), std::move(child_copy));
     }
   }
@@ -624,9 +624,8 @@
     StringPiece key = current_path.substr(0, delimiter_position);
     DictionaryValue* child_dictionary = nullptr;
     if (!current_dictionary->GetDictionary(key, &child_dictionary)) {
-      child_dictionary = new DictionaryValue;
-      current_dictionary->SetWithoutPathExpansion(
-          key, base::WrapUnique(child_dictionary));
+      child_dictionary = current_dictionary->SetDictionaryWithoutPathExpansion(
+          key, MakeUnique<DictionaryValue>());
     }
 
     current_dictionary = child_dictionary;
@@ -642,23 +641,23 @@
 }
 
 Value* DictionaryValue::SetBoolean(StringPiece path, bool in_value) {
-  return Set(path, new Value(in_value));
+  return Set(path, MakeUnique<Value>(in_value));
 }
 
 Value* DictionaryValue::SetInteger(StringPiece path, int in_value) {
-  return Set(path, new Value(in_value));
+  return Set(path, MakeUnique<Value>(in_value));
 }
 
 Value* DictionaryValue::SetDouble(StringPiece path, double in_value) {
-  return Set(path, new Value(in_value));
+  return Set(path, MakeUnique<Value>(in_value));
 }
 
 Value* DictionaryValue::SetString(StringPiece path, StringPiece in_value) {
-  return Set(path, new Value(in_value));
+  return Set(path, MakeUnique<Value>(in_value));
 }
 
 Value* DictionaryValue::SetString(StringPiece path, const string16& in_value) {
-  return Set(path, new Value(in_value));
+  return Set(path, MakeUnique<Value>(in_value));
 }
 
 DictionaryValue* DictionaryValue::SetDictionary(
@@ -685,28 +684,28 @@
 
 Value* DictionaryValue::SetBooleanWithoutPathExpansion(StringPiece path,
                                                        bool in_value) {
-  return SetWithoutPathExpansion(path, base::MakeUnique<base::Value>(in_value));
+  return SetWithoutPathExpansion(path, MakeUnique<Value>(in_value));
 }
 
 Value* DictionaryValue::SetIntegerWithoutPathExpansion(StringPiece path,
                                                        int in_value) {
-  return SetWithoutPathExpansion(path, base::MakeUnique<base::Value>(in_value));
+  return SetWithoutPathExpansion(path, MakeUnique<Value>(in_value));
 }
 
 Value* DictionaryValue::SetDoubleWithoutPathExpansion(StringPiece path,
                                                       double in_value) {
-  return SetWithoutPathExpansion(path, base::MakeUnique<base::Value>(in_value));
+  return SetWithoutPathExpansion(path, MakeUnique<Value>(in_value));
 }
 
 Value* DictionaryValue::SetStringWithoutPathExpansion(StringPiece path,
                                                       StringPiece in_value) {
-  return SetWithoutPathExpansion(path, base::MakeUnique<base::Value>(in_value));
+  return SetWithoutPathExpansion(path, MakeUnique<Value>(in_value));
 }
 
 Value* DictionaryValue::SetStringWithoutPathExpansion(
     StringPiece path,
     const string16& in_value) {
-  return SetWithoutPathExpansion(path, base::MakeUnique<base::Value>(in_value));
+  return SetWithoutPathExpansion(path, MakeUnique<Value>(in_value));
 }
 
 DictionaryValue* DictionaryValue::SetDictionaryWithoutPathExpansion(
@@ -1030,7 +1029,7 @@
   std::unique_ptr<DictionaryValue> copy =
       CopyDictionaryWithoutEmptyChildren(*this);
   if (!copy)
-    copy.reset(new DictionaryValue);
+    copy = MakeUnique<DictionaryValue>();
   return copy;
 }
 
diff --git a/build/config/freetype/BUILD.gn b/build/config/freetype/BUILD.gn
index 4f052646..976661a 100644
--- a/build/config/freetype/BUILD.gn
+++ b/build/config/freetype/BUILD.gn
@@ -4,8 +4,19 @@
 
 import("//build/config/features.gni")
 
+declare_args() {
+  # Blink needs a recent and properly build-configured FreeType version to
+  # support OpenType variations, color emoji and avoid security bugs. By default
+  # we ship and link such a version as part of Chrome. For distributions that
+  # prefer to keep linking to the version the system, FreeType must be newer
+  # than version 2.7.1 and have color bitmap support compiled in. WARNING:
+  # System FreeType configurations other than as described WILL INTRODUCE TEXT
+  # RENDERING AND SECURITY REGRESSIONS.
+  use_system_freetype = false
+}
+
 group("freetype") {
-  if (is_linux && !is_chromecast) {
+  if (use_system_freetype) {
     public_configs = [ "//build/linux:freetype_from_pkgconfig" ]
   } else {
     public_deps = [
diff --git a/build/config/linux/pangocairo/BUILD.gn b/build/config/linux/pangocairo/BUILD.gn
index 727b52d5..d0d506a9 100644
--- a/build/config/linux/pangocairo/BUILD.gn
+++ b/build/config/linux/pangocairo/BUILD.gn
@@ -6,4 +6,11 @@
 
 pkg_config("pangocairo") {
   packages = [ "pangocairo" ]
+
+  # We don't want pkgconfig for pangocairo to explicitly request FreeType to get
+  # linked, because we control which FreeType to link to.
+  extra_args = [
+    "-v",
+    "freetype",
+  ]
 }
diff --git a/build/linux/BUILD.gn b/build/linux/BUILD.gn
index e36b6943..0449f82 100644
--- a/build/linux/BUILD.gn
+++ b/build/linux/BUILD.gn
@@ -49,9 +49,10 @@
 }
 
 if (!is_chromecast) {
+  # Only provided for distributions which prefer to keep linking to FreeType on
+  # the system, use with caution,for details see build/config/freetype/BUILD.gn.
   pkg_config("freetype_from_pkgconfig") {
     visibility = [ ":freetype2" ]
     packages = [ "freetype2" ]
   }
 }
-
diff --git a/chrome/android/java/res/drawable/ic_tv_options_input_settings_rotated_grey.xml b/chrome/android/java/res/drawable/ic_tv_options_input_settings_rotated_grey.xml
new file mode 100644
index 0000000..af909ff
--- /dev/null
+++ b/chrome/android/java/res/drawable/ic_tv_options_input_settings_rotated_grey.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2017 The Chromium Authors. All rights reserved.
+     Use of this source code is governed by a BSD-style license that can be
+     found in the LICENSE file. -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:tools="http://schemas.android.com/tools"
+        tools:targetApi="21"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:pathData="M7.17,13.63L8.17,15.36C8.23,15.47 8.36,15.51 8.48,15.47L9.72,14.97C9.98,15.17 10.26,15.34 10.57,15.46L10.76,16.78C10.77,16.91 10.88,17 11,17L13,17C13.12,17 13.23,16.91 13.25,16.79L13.44,15.47C13.74,15.34 14.03,15.18 14.28,14.98L15.53,15.48C15.64,15.52 15.77,15.48 15.84,15.37L16.84,13.64C16.9,13.53 16.87,13.4 16.78,13.32L15.72,12.49C15.74,12.33 15.76,12.17 15.76,12C15.76,11.83 15.75,11.67 15.72,11.51L16.78,10.68C16.87,10.6 16.9,10.47 16.84,10.36L15.84,8.63C15.78,8.52 15.65,8.48 15.53,8.52L14.29,9.02C14.03,8.82 13.75,8.65 13.45,8.53L13.26,7.21C13.23,7.09 13.12,7 13,7L11,7C10.88,7 10.77,7.09 10.75,7.21L10.56,8.53C10.26,8.66 9.97,8.82 9.71,9.02L8.47,8.52C8.36,8.48 8.23,8.52 8.16,8.63L7.16,10.36C7.1,10.47 7.12,10.6 7.22,10.68L8.28,11.51C8.26,11.67 8.25,11.83 8.25,12C8.25,12.17 8.26,12.33 8.29,12.49L7.23,13.32C7.13,13.39 7.11,13.53 7.17,13.63L7.17,13.63ZM12,10C13.1,10 14,10.9 14,12C14,13.1 13.1,14 12,14C10.9,14 10,13.1 10,12C10,10.9 10.9,10 12,10ZM21,21L21,3C21,1.9 20.1,1 19,1L5,1C3.9,1 3,1.9 3,3L3,21C3,22.1 3.9,23 5,23L19,23C20.1,23 21,22.1 21,21ZM4.99,21L4.99,3L19.01,3L19.01,21L4.99,21L4.99,21Z"
+        android:fillColor="@color/google_grey_600"/>
+</vector>
diff --git a/chrome/android/java/res/xml/clear_browsing_data_preferences.xml b/chrome/android/java/res/xml/clear_browsing_data_preferences.xml
index 6e9c43db..712dc6c 100644
--- a/chrome/android/java/res/xml/clear_browsing_data_preferences.xml
+++ b/chrome/android/java/res/xml/clear_browsing_data_preferences.xml
@@ -38,6 +38,11 @@
         android:persistent="false"
         android:title="@string/clear_form_data_title" />
 
+    <org.chromium.chrome.browser.preferences.ClearBrowsingDataCheckBoxPreference
+        android:key="clear_site_settings_checkbox"
+        android:persistent="false"
+        android:title="@string/prefs_site_settings" />
+
     <org.chromium.chrome.browser.preferences.ButtonPreference
         android:key="clear_button"
         android:title="@string/clear_data_delete" />
diff --git a/chrome/android/java/res/xml/clear_browsing_data_preferences_tab.xml b/chrome/android/java/res/xml/clear_browsing_data_preferences_tab.xml
index 62a72a60..c30f067 100644
--- a/chrome/android/java/res/xml/clear_browsing_data_preferences_tab.xml
+++ b/chrome/android/java/res/xml/clear_browsing_data_preferences_tab.xml
@@ -44,4 +44,8 @@
         android:persistent="false"
         android:title="@string/clear_form_data_title" />
 
+    <org.chromium.chrome.browser.preferences.ClearBrowsingDataTabCheckBoxPreference
+        android:key="clear_site_settings_checkbox"
+        android:persistent="false"
+        android:title="@string/prefs_site_settings" />
 </PreferenceScreen>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataPreferences.java
index d4f077f..5e7efcef 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataPreferences.java
@@ -153,6 +153,7 @@
     private static final String PREF_CACHE = "clear_cache_checkbox";
     private static final String PREF_PASSWORDS = "clear_passwords_checkbox";
     private static final String PREF_FORM_DATA = "clear_form_data_checkbox";
+    private static final String PREF_SITE_SETTINGS = "clear_site_settings_checkbox";
 
     @VisibleForTesting
     public static final String PREF_GOOGLE_SUMMARY = "google_summary";
@@ -195,7 +196,9 @@
         CLEAR_PASSWORDS(
                 BrowsingDataType.PASSWORDS, PREF_PASSWORDS, R.drawable.ic_vpn_key_grey, false),
         CLEAR_FORM_DATA(
-                BrowsingDataType.FORM_DATA, PREF_FORM_DATA, R.drawable.bookmark_edit_normal, true);
+                BrowsingDataType.FORM_DATA, PREF_FORM_DATA, R.drawable.bookmark_edit_normal, true),
+        CLEAR_SITE_SETTINGS(BrowsingDataType.SITE_SETTINGS, PREF_SITE_SETTINGS,
+                R.drawable.ic_tv_options_input_settings_rotated_grey, false);
 
         private final int mDataType;
         private final String mPreferenceKey;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataPreferencesAdvanced.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataPreferencesAdvanced.java
index 708bc62..68ed1acb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataPreferencesAdvanced.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataPreferencesAdvanced.java
@@ -17,4 +17,12 @@
     protected int getPreferenceType() {
         return ClearBrowsingDataTab.ADVANCED;
     }
+
+    @Override
+    protected DialogOption[] getDialogOptions() {
+        return new DialogOption[] {DialogOption.CLEAR_HISTORY,
+                DialogOption.CLEAR_COOKIES_AND_SITE_DATA, DialogOption.CLEAR_CACHE,
+                DialogOption.CLEAR_PASSWORDS, DialogOption.CLEAR_FORM_DATA,
+                DialogOption.CLEAR_SITE_SETTINGS};
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferences.java
index 4f922c6..d91b9520 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferences.java
@@ -23,6 +23,7 @@
 import org.chromium.chrome.browser.preferences.ChromeBaseCheckBoxPreference;
 import org.chromium.chrome.browser.preferences.ManagedPreferenceDelegate;
 import org.chromium.chrome.browser.preferences.PrefServiceBridge;
+import org.chromium.chrome.browser.preferences.PreferenceUtils;
 import org.chromium.chrome.browser.profiles.Profile;
 
 /**
@@ -51,7 +52,7 @@
         super.onCreate(savedInstanceState);
         PrivacyPreferencesManager privacyPrefManager = PrivacyPreferencesManager.getInstance();
         privacyPrefManager.migrateNetworkPredictionPreferences();
-        addPreferencesFromResource(R.xml.privacy_preferences);
+        PreferenceUtils.addPreferencesFromResource(this, R.xml.privacy_preferences);
         getActivity().setTitle(R.string.prefs_privacy);
         setHasOptionsMenu(true);
         PrefServiceBridge prefServiceBridge = PrefServiceBridge.getInstance();
diff --git a/chrome/browser/android/browsing_data/browsing_data_bridge.cc b/chrome/browser/android/browsing_data/browsing_data_bridge.cc
index 5cf8c81..c690af1 100644
--- a/chrome/browser/android/browsing_data/browsing_data_bridge.cc
+++ b/chrome/browser/android/browsing_data/browsing_data_bridge.cc
@@ -131,6 +131,10 @@
         // Bookmarks are deleted separately on the Java side.
         NOTREACHED();
         break;
+      case browsing_data::BrowsingDataType::SITE_SETTINGS:
+        remove_mask |=
+            ChromeBrowsingDataRemoverDelegate::DATA_TYPE_CONTENT_SETTINGS;
+        break;
       case browsing_data::BrowsingDataType::NUM_TYPES:
         NOTREACHED();
     }
diff --git a/chrome/browser/browsing_data/browsing_data_counter_factory.cc b/chrome/browser/browsing_data/browsing_data_counter_factory.cc
index 2b9f452..41216b8 100644
--- a/chrome/browser/browsing_data/browsing_data_counter_factory.cc
+++ b/chrome/browser/browsing_data/browsing_data_counter_factory.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/browsing_data/downloads_counter.h"
 #include "chrome/browser/browsing_data/media_licenses_counter.h"
 #include "chrome/browser/browsing_data/site_data_counter.h"
+#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/history/web_history_service_factory.h"
 #include "chrome/browser/password_manager/password_store_factory.h"
@@ -23,6 +24,7 @@
 #include "components/browsing_data/core/counters/browsing_data_counter.h"
 #include "components/browsing_data/core/counters/history_counter.h"
 #include "components/browsing_data/core/counters/passwords_counter.h"
+#include "components/browsing_data/core/counters/site_settings_counter.h"
 #include "components/browsing_data/core/pref_names.h"
 #include "components/history/core/browser/web_history_service.h"
 #include "components/password_manager/core/browser/password_store.h"
@@ -94,6 +96,11 @@
   if (pref_name == browsing_data::prefs::kDeleteMediaLicenses)
     return base::MakeUnique<MediaLicensesCounter>(profile);
 
+  if (pref_name == browsing_data::prefs::kDeleteSiteSettings) {
+    return base::MakeUnique<browsing_data::SiteSettingsCounter>(
+        HostContentSettingsMapFactory::GetForProfile(profile));
+  }
+
 #if BUILDFLAG(ENABLE_EXTENSIONS)
   if (pref_name == browsing_data::prefs::kDeleteHostedAppsData)
     return base::MakeUnique<HostedAppsCounter>(profile);
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
index bf8feab..601de50 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
@@ -47,6 +47,7 @@
 #include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
 #include "components/bookmarks/browser/bookmark_model.h"
+#include "components/content_settings/core/browser/content_settings_registry.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/content_settings/core/common/content_settings.h"
 #include "components/content_settings/core/common/content_settings_pattern.h"
@@ -725,6 +726,19 @@
   }
 
   //////////////////////////////////////////////////////////////////////////////
+  // DATA_TYPE_CONTENT_SETTINGS
+  if (remove_mask & DATA_TYPE_CONTENT_SETTINGS) {
+    const auto* registry =
+        content_settings::ContentSettingsRegistry::GetInstance();
+    auto* map = HostContentSettingsMapFactory::GetForProfile(profile_);
+    for (const content_settings::ContentSettingsInfo* info : *registry) {
+      map->ClearSettingsForOneTypeWithPredicate(
+          info->website_settings_info()->type(), delete_begin_,
+          base::Bind(&WebsiteSettingsFilterAdapter, filter));
+    }
+  }
+
+  //////////////////////////////////////////////////////////////////////////////
   // DATA_TYPE_DURABLE_PERMISSION
   if (remove_mask & DATA_TYPE_DURABLE_PERMISSION) {
     HostContentSettingsMapFactory::GetForProfile(profile_)
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h
index 1313de6..90747b0 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h
@@ -72,6 +72,7 @@
     DATA_TYPE_DURABLE_PERMISSION = DATA_TYPE_EMBEDDER_BEGIN << 6,
     DATA_TYPE_EXTERNAL_PROTOCOL_DATA = DATA_TYPE_EMBEDDER_BEGIN << 7,
     DATA_TYPE_HOSTED_APP_DATA_TEST_ONLY = DATA_TYPE_EMBEDDER_BEGIN << 8,
+    DATA_TYPE_CONTENT_SETTINGS = DATA_TYPE_EMBEDDER_BEGIN << 9,
 
     // Group datatypes.
 
@@ -103,7 +104,8 @@
     // whichever makes sense.
     FILTERABLE_DATA_TYPES = DATA_TYPE_SITE_DATA |
                             content::BrowsingDataRemover::DATA_TYPE_CACHE |
-                            content::BrowsingDataRemover::DATA_TYPE_DOWNLOADS,
+                            content::BrowsingDataRemover::DATA_TYPE_DOWNLOADS |
+                            DATA_TYPE_CONTENT_SETTINGS,
 
     // Includes all the available remove options. Meant to be used by clients
     // that wish to wipe as much data as possible from a Profile, to make it
@@ -114,7 +116,8 @@
                      DATA_TYPE_FORM_DATA |
                      DATA_TYPE_HISTORY |
                      DATA_TYPE_PASSWORDS |
-                     content::BrowsingDataRemover::DATA_TYPE_MEDIA_LICENSES,
+                     content::BrowsingDataRemover::DATA_TYPE_MEDIA_LICENSES |
+                     DATA_TYPE_CONTENT_SETTINGS,
 
     // Includes all available remove options. Meant to be used when the Profile
     // is scheduled to be deleted, and all possible data should be wiped from
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 0ed1fb1..097f602 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
@@ -1676,6 +1676,88 @@
       << host_settings[2].primary_pattern.ToString();
 }
 
+TEST_F(ChromeBrowsingDataRemoverDelegateTest, RemoveContentSettings) {
+  auto* map = HostContentSettingsMapFactory::GetForProfile(GetProfile());
+  map->SetContentSettingDefaultScope(kOrigin1, kOrigin1,
+                                     CONTENT_SETTINGS_TYPE_GEOLOCATION,
+                                     std::string(), CONTENT_SETTING_ALLOW);
+  map->SetContentSettingDefaultScope(kOrigin2, kOrigin2,
+                                     CONTENT_SETTINGS_TYPE_GEOLOCATION,
+                                     std::string(), CONTENT_SETTING_ALLOW);
+  map->SetContentSettingDefaultScope(kOrigin2, kOrigin2,
+                                     CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
+                                     std::string(), CONTENT_SETTING_ALLOW);
+  map->SetContentSettingDefaultScope(kOrigin3, kOrigin3,
+                                     CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
+                                     std::string(), CONTENT_SETTING_ALLOW);
+
+  // Clear all except for origin1 and origin3.
+  std::unique_ptr<BrowsingDataFilterBuilder> filter(
+      BrowsingDataFilterBuilder::Create(BrowsingDataFilterBuilder::BLACKLIST));
+  filter->AddRegisterableDomain(kTestRegisterableDomain1);
+  filter->AddRegisterableDomain(kTestRegisterableDomain3);
+  BlockUntilOriginDataRemoved(
+      base::Time(), base::Time::Max(),
+      ChromeBrowsingDataRemoverDelegate::DATA_TYPE_CONTENT_SETTINGS,
+      std::move(filter));
+
+  EXPECT_EQ(ChromeBrowsingDataRemoverDelegate::DATA_TYPE_CONTENT_SETTINGS,
+            GetRemovalMask());
+  EXPECT_EQ(content::BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB,
+            GetOriginTypeMask());
+
+  // Verify we still have the allow setting for origin1.
+  ContentSettingsForOneType host_settings;
+  map->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_GEOLOCATION, std::string(),
+                             &host_settings);
+  ASSERT_EQ(2u, host_settings.size());
+  EXPECT_EQ(ContentSettingsPattern::FromURLNoWildcard(kOrigin1),
+            host_settings[0].primary_pattern)
+      << host_settings[0].primary_pattern.ToString();
+  EXPECT_EQ(CONTENT_SETTING_ALLOW, host_settings[0].setting);
+  // And the wildcard.
+  EXPECT_EQ(ContentSettingsPattern::Wildcard(),
+            host_settings[1].primary_pattern)
+      << host_settings[1].primary_pattern.ToString();
+  EXPECT_EQ(CONTENT_SETTING_ASK, host_settings[1].setting);
+
+  // There should also only be one setting for origin3
+  map->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_NOTIFICATIONS, std::string(),
+                             &host_settings);
+  ASSERT_EQ(2u, host_settings.size());
+  EXPECT_EQ(ContentSettingsPattern::FromURLNoWildcard(kOrigin3),
+            host_settings[0].primary_pattern)
+      << host_settings[0].primary_pattern.ToString();
+  EXPECT_EQ(CONTENT_SETTING_ALLOW, host_settings[0].setting);
+  // And the wildcard.
+  EXPECT_EQ(ContentSettingsPattern::Wildcard(),
+            host_settings[1].primary_pattern)
+      << host_settings[1].primary_pattern.ToString();
+  EXPECT_EQ(CONTENT_SETTING_ASK, host_settings[1].setting);
+
+  BlockUntilOriginDataRemoved(
+      base::Time(), base::Time::Max(),
+      ChromeBrowsingDataRemoverDelegate::DATA_TYPE_CONTENT_SETTINGS,
+      BrowsingDataFilterBuilder::Create(BrowsingDataFilterBuilder::BLACKLIST));
+
+  // Everything except the wildcard should be deleted now.
+  map->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_GEOLOCATION, std::string(),
+                             &host_settings);
+  ASSERT_EQ(1u, host_settings.size());
+  EXPECT_EQ(ContentSettingsPattern::Wildcard(),
+            host_settings[0].primary_pattern)
+      << host_settings[0].primary_pattern.ToString();
+  EXPECT_EQ(CONTENT_SETTING_ASK, host_settings[0].setting);
+
+  map->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_NOTIFICATIONS, std::string(),
+                             &host_settings);
+  ASSERT_EQ(1u, host_settings.size());
+  EXPECT_EQ(ContentSettingsPattern::Wildcard(),
+            host_settings[0].primary_pattern)
+      << host_settings[0].primary_pattern.ToString();
+  EXPECT_EQ(CONTENT_SETTING_ASK, host_settings[0].setting);
+}
+
 TEST_F(ChromeBrowsingDataRemoverDelegateTest, RemoveDurablePermission) {
   // Add our settings.
   HostContentSettingsMap* host_content_settings_map =
diff --git a/chrome/browser/browsing_data/site_settings_counter_unittest.cc b/chrome/browser/browsing_data/site_settings_counter_unittest.cc
new file mode 100644
index 0000000..ef9d6be
--- /dev/null
+++ b/chrome/browser/browsing_data/site_settings_counter_unittest.cc
@@ -0,0 +1,186 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/browsing_data/core/counters/site_settings_counter.h"
+
+#include "base/test/scoped_feature_list.h"
+#include "base/test/simple_test_clock.h"
+#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
+#include "chrome/common/chrome_features.h"
+#include "chrome/test/base/testing_profile.h"
+#include "components/browsing_data/core/browsing_data_utils.h"
+#include "components/browsing_data/core/pref_names.h"
+#include "components/prefs/pref_service.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class SiteSettingsCounterTest : public testing::Test {
+ public:
+  SiteSettingsCounterTest() {
+    base::test::ScopedFeatureList feature_list;
+    // Enable tabsInCbd to activate timestamp recording for content-settings.
+    feature_list.InitAndEnableFeature(features::kTabsInCbd);
+    profile_ = base::MakeUnique<TestingProfile>();
+    map_ = HostContentSettingsMapFactory::GetForProfile(profile());
+  }
+
+  Profile* profile() { return profile_.get(); }
+
+  HostContentSettingsMap* map() { return map_.get(); }
+
+  void SetSiteSettingsDeletionPref(bool value) {
+    profile()->GetPrefs()->SetBoolean(browsing_data::prefs::kDeleteSiteSettings,
+                                      value);
+  }
+
+  void SetDeletionPeriodPref(browsing_data::TimePeriod period) {
+    profile()->GetPrefs()->SetInteger(browsing_data::prefs::kDeleteTimePeriod,
+                                      static_cast<int>(period));
+  }
+
+  browsing_data::BrowsingDataCounter::ResultInt GetResult() {
+    DCHECK(finished_);
+    return result_;
+  }
+
+  void Callback(
+      std::unique_ptr<browsing_data::BrowsingDataCounter::Result> result) {
+    DCHECK(result->Finished());
+    finished_ = result->Finished();
+
+    result_ = static_cast<browsing_data::BrowsingDataCounter::FinishedResult*>(
+                  result.get())
+                  ->Value();
+  }
+
+ private:
+  content::TestBrowserThreadBundle thread_bundle_;
+  std::unique_ptr<TestingProfile> profile_;
+
+  scoped_refptr<HostContentSettingsMap> map_;
+  bool finished_;
+  browsing_data::BrowsingDataCounter::ResultInt result_;
+};
+
+// Tests that the counter correctly counts each setting.
+TEST_F(SiteSettingsCounterTest, Count) {
+  map()->SetContentSettingDefaultScope(
+      GURL("http://www.google.com"), GURL("http://www.google.com"),
+      CONTENT_SETTINGS_TYPE_POPUPS, std::string(), CONTENT_SETTING_ALLOW);
+  map()->SetContentSettingDefaultScope(
+      GURL("http://maps.google.com"), GURL("http://maps.google.com"),
+      CONTENT_SETTINGS_TYPE_GEOLOCATION, std::string(), CONTENT_SETTING_ALLOW);
+
+  browsing_data::SiteSettingsCounter counter(map());
+  counter.Init(
+      profile()->GetPrefs(), browsing_data::ClearBrowsingDataTab::ADVANCED,
+      base::Bind(&SiteSettingsCounterTest::Callback, base::Unretained(this)));
+  counter.Restart();
+
+  EXPECT_EQ(2, GetResult());
+}
+
+// Test that the counter counts correctly when using a time period.
+TEST_F(SiteSettingsCounterTest, CountWithTimePeriod) {
+  auto test_clock = base::MakeUnique<base::SimpleTestClock>();
+  base::SimpleTestClock* clock = test_clock.get();
+  map()->SetClockForTesting(std::move(test_clock));
+
+  // Create a setting at Now()-90min.
+  clock->SetNow(base::Time::Now() - base::TimeDelta::FromMinutes(90));
+  map()->SetContentSettingDefaultScope(
+      GURL("http://www.google.com"), GURL("http://www.google.com"),
+      CONTENT_SETTINGS_TYPE_POPUPS, std::string(), CONTENT_SETTING_ALLOW);
+
+  // Create a setting at Now()-30min.
+  clock->SetNow(base::Time::Now() - base::TimeDelta::FromMinutes(30));
+  map()->SetContentSettingDefaultScope(
+      GURL("http://maps.google.com"), GURL("http://maps.google.com"),
+      CONTENT_SETTINGS_TYPE_GEOLOCATION, std::string(), CONTENT_SETTING_ALLOW);
+
+  clock->SetNow(base::Time::Now());
+  browsing_data::SiteSettingsCounter counter(map());
+  counter.Init(
+      profile()->GetPrefs(), browsing_data::ClearBrowsingDataTab::ADVANCED,
+      base::Bind(&SiteSettingsCounterTest::Callback, base::Unretained(this)));
+  // Only one of the settings was created in the last hour.
+  SetDeletionPeriodPref(browsing_data::TimePeriod::LAST_HOUR);
+  EXPECT_EQ(1, GetResult());
+  // Both settings were created during the last day.
+  SetDeletionPeriodPref(browsing_data::TimePeriod::LAST_DAY);
+  EXPECT_EQ(2, GetResult());
+}
+
+// Tests that the counter doesn't count website settings
+TEST_F(SiteSettingsCounterTest, OnlyCountContentSettings) {
+  map()->SetContentSettingDefaultScope(
+      GURL("http://www.google.com"), GURL("http://www.google.com"),
+      CONTENT_SETTINGS_TYPE_POPUPS, std::string(), CONTENT_SETTING_ALLOW);
+  map()->SetWebsiteSettingDefaultScope(
+      GURL("http://maps.google.com"), GURL(),
+      CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT, std::string(),
+      base::MakeUnique<base::DictionaryValue>());
+
+  browsing_data::SiteSettingsCounter counter(map());
+  counter.Init(
+      profile()->GetPrefs(), browsing_data::ClearBrowsingDataTab::ADVANCED,
+      base::Bind(&SiteSettingsCounterTest::Callback, base::Unretained(this)));
+  counter.Restart();
+
+  EXPECT_EQ(1, GetResult());
+}
+
+// Tests that the counter counts settings with the same pattern only
+// once.
+TEST_F(SiteSettingsCounterTest, OnlyCountPatternOnce) {
+  map()->SetContentSettingDefaultScope(
+      GURL("http://www.google.com"), GURL("http://www.google.com"),
+      CONTENT_SETTINGS_TYPE_POPUPS, std::string(), CONTENT_SETTING_ALLOW);
+  map()->SetContentSettingDefaultScope(
+      GURL("http://www.google.com"), GURL("http://www.google.com"),
+      CONTENT_SETTINGS_TYPE_GEOLOCATION, std::string(), CONTENT_SETTING_ALLOW);
+
+  browsing_data::SiteSettingsCounter counter(map());
+  counter.Init(
+      profile()->GetPrefs(), browsing_data::ClearBrowsingDataTab::ADVANCED,
+      base::Bind(&SiteSettingsCounterTest::Callback, base::Unretained(this)));
+  counter.Restart();
+
+  EXPECT_EQ(1, GetResult());
+}
+
+// Tests that the counter starts counting automatically when the deletion
+// pref changes to true.
+TEST_F(SiteSettingsCounterTest, PrefChanged) {
+  SetSiteSettingsDeletionPref(false);
+  map()->SetContentSettingDefaultScope(
+      GURL("http://www.google.com"), GURL("http://www.google.com"),
+      CONTENT_SETTINGS_TYPE_POPUPS, std::string(), CONTENT_SETTING_ALLOW);
+
+  browsing_data::SiteSettingsCounter counter(map());
+  counter.Init(
+      profile()->GetPrefs(), browsing_data::ClearBrowsingDataTab::ADVANCED,
+      base::Bind(&SiteSettingsCounterTest::Callback, base::Unretained(this)));
+  SetSiteSettingsDeletionPref(true);
+  EXPECT_EQ(1, GetResult());
+}
+
+// Tests that changing the deletion period restarts the counting.
+TEST_F(SiteSettingsCounterTest, PeriodChanged) {
+  map()->SetContentSettingDefaultScope(
+      GURL("http://www.google.com"), GURL("http://www.google.com"),
+      CONTENT_SETTINGS_TYPE_POPUPS, std::string(), CONTENT_SETTING_ALLOW);
+
+  browsing_data::SiteSettingsCounter counter(map());
+  counter.Init(
+      profile()->GetPrefs(), browsing_data::ClearBrowsingDataTab::ADVANCED,
+      base::Bind(&SiteSettingsCounterTest::Callback, base::Unretained(this)));
+
+  SetDeletionPeriodPref(browsing_data::TimePeriod::LAST_HOUR);
+  EXPECT_EQ(1, GetResult());
+}
+
+}  // namespace
diff --git a/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc b/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc
index afc58b3..27c015d3 100644
--- a/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc
+++ b/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc
@@ -11,8 +11,7 @@
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
-#include "base/test/test_timeouts.h"
-#include "base/threading/platform_thread.h"
+#include "base/test/simple_test_clock.h"
 #include "base/values.h"
 #include "chrome/browser/content_settings/content_settings_mock_observer.h"
 #include "chrome/browser/prefs/browser_prefs.h"
@@ -620,11 +619,16 @@
       ContentSettingsPattern::FromString("www.google.com");
   auto value = base::MakeUnique<base::Value>(CONTENT_SETTING_ALLOW);
 
-  base::Time t1 = base::Time::Now();
-
   // Create a  provider and set a few settings.
   PrefProvider provider(&prefs, false /* incognito */,
                         true /* store_last_modified */);
+  auto test_clock = base::MakeUnique<base::SimpleTestClock>();
+  test_clock->SetNow(base::Time::Now());
+  base::SimpleTestClock* clock = test_clock.get();
+  provider.SetClockForTesting(std::move(test_clock));
+
+  base::Time t1 = clock->Now();
+
   provider.SetWebsiteSetting(pattern_1, ContentSettingsPattern::Wildcard(),
                              CONTENT_SETTINGS_TYPE_COOKIES, std::string(),
                              value->DeepCopy());
@@ -632,19 +636,17 @@
                              CONTENT_SETTINGS_TYPE_COOKIES, std::string(),
                              value->DeepCopy());
   // Make sure that the timestamps for pattern_1 and patter_2 are before |t2|.
-  base::PlatformThread::Sleep(TestTimeouts::tiny_timeout());
-  base::Time t2 = base::Time::Now();
+  clock->Advance(base::TimeDelta::FromSeconds(1));
+  base::Time t2 = clock->Now();
 
   base::Time last_modified = provider.GetWebsiteSettingLastModified(
       pattern_1, ContentSettingsPattern::Wildcard(),
       CONTENT_SETTINGS_TYPE_COOKIES, std::string());
-  EXPECT_GE(last_modified, t1);
-  EXPECT_LT(last_modified, t2);
+  EXPECT_EQ(last_modified, t1);
   last_modified = provider.GetWebsiteSettingLastModified(
       pattern_2, ContentSettingsPattern::Wildcard(),
       CONTENT_SETTINGS_TYPE_COOKIES, std::string());
-  EXPECT_GE(last_modified, t1);
-  EXPECT_LT(last_modified, t2);
+  EXPECT_EQ(last_modified, t1);
 
   // A change for pattern_1, which will update the last_modified timestamp.
   auto value2 = base::MakeUnique<base::Value>(CONTENT_SETTING_BLOCK);
@@ -655,14 +657,13 @@
   last_modified = provider.GetWebsiteSettingLastModified(
       pattern_1, ContentSettingsPattern::Wildcard(),
       CONTENT_SETTINGS_TYPE_COOKIES, std::string());
-  EXPECT_GE(last_modified, t2);
+  EXPECT_EQ(last_modified, t2);
 
   // The timestamp of pattern_2 shouldn't change.
   last_modified = provider.GetWebsiteSettingLastModified(
       pattern_2, ContentSettingsPattern::Wildcard(),
       CONTENT_SETTINGS_TYPE_COOKIES, std::string());
-  EXPECT_GE(last_modified, t1);
-  EXPECT_LT(last_modified, t2);
+  EXPECT_EQ(last_modified, t1);
 
   provider.ShutdownOnUIThread();
 }
diff --git a/chrome/browser/content_settings/host_content_settings_map_unittest.cc b/chrome/browser/content_settings/host_content_settings_map_unittest.cc
index ac80c529..3ea4c75 100644
--- a/chrome/browser/content_settings/host_content_settings_map_unittest.cc
+++ b/chrome/browser/content_settings/host_content_settings_map_unittest.cc
@@ -12,8 +12,7 @@
 #include "base/json/json_writer.h"
 #include "base/memory/ptr_util.h"
 #include "base/test/scoped_feature_list.h"
-#include "base/test/test_timeouts.h"
-#include "base/threading/platform_thread.h"
+#include "base/test/simple_test_clock.h"
 #include "chrome/browser/content_settings/content_settings_mock_observer.h"
 #include "chrome/browser/content_settings/cookie_settings_factory.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
@@ -1744,60 +1743,129 @@
 
 TEST_F(HostContentSettingsMapTest, ClearSettingsWithTimePredicate) {
   base::test::ScopedFeatureList feature_list;
+  // Enable kTabsInCbd to activate last_modified timestmap recording.
   feature_list.InitAndEnableFeature(features::kTabsInCbd);
 
   TestingProfile profile;
-  HostContentSettingsMap* host_content_settings_map =
-      HostContentSettingsMapFactory::GetForProfile(&profile);
+  auto* map = HostContentSettingsMapFactory::GetForProfile(&profile);
+
+  auto test_clock = base::MakeUnique<base::SimpleTestClock>();
+  test_clock->SetNow(base::Time::Now());
+  base::SimpleTestClock* clock = test_clock.get();
+  map->SetClockForTesting(std::move(test_clock));
+
   ContentSettingsForOneType host_settings;
 
   GURL url1("https://www.google.com/");
   GURL url2("https://maps.google.com/");
 
   // Add setting for url1.
-  host_content_settings_map->SetContentSettingDefaultScope(
-      url1, GURL(), CONTENT_SETTINGS_TYPE_POPUPS, std::string(),
-      CONTENT_SETTING_BLOCK);
+  map->SetContentSettingDefaultScope(url1, GURL(), CONTENT_SETTINGS_TYPE_POPUPS,
+                                     std::string(), CONTENT_SETTING_BLOCK);
 
   // Make sure that the timestamp for url1 is different from |t|.
-  base::PlatformThread::Sleep(TestTimeouts::tiny_timeout());
-  base::Time t = base::Time::Now();
+  clock->Advance(base::TimeDelta::FromSeconds(1));
+  base::Time t = clock->Now();
 
   // Add setting for url2.
-  host_content_settings_map->SetContentSettingDefaultScope(
-      url2, GURL(), CONTENT_SETTINGS_TYPE_POPUPS, std::string(),
-      CONTENT_SETTING_BLOCK);
+  map->SetContentSettingDefaultScope(url2, GURL(), CONTENT_SETTINGS_TYPE_POPUPS,
+                                     std::string(), CONTENT_SETTING_BLOCK);
 
   // Verify we have two pattern and the default.
-  host_content_settings_map->GetSettingsForOneType(
-      CONTENT_SETTINGS_TYPE_POPUPS, std::string(), &host_settings);
+  map->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_POPUPS, std::string(),
+                             &host_settings);
   EXPECT_EQ(3u, host_settings.size());
 
   // Clear all settings since |t|.
-  host_content_settings_map->ClearSettingsForOneTypeWithPredicate(
+  map->ClearSettingsForOneTypeWithPredicate(
       CONTENT_SETTINGS_TYPE_POPUPS, t,
       HostContentSettingsMap::PatternSourcePredicate());
 
   // Verify we only have one pattern (url1) and the default.
-  host_content_settings_map->GetSettingsForOneType(
-      CONTENT_SETTINGS_TYPE_POPUPS, std::string(), &host_settings);
+  map->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_POPUPS, std::string(),
+                             &host_settings);
   EXPECT_EQ(2u, host_settings.size());
   EXPECT_EQ("https://www.google.com:443",
             host_settings[0].primary_pattern.ToString());
   EXPECT_EQ("*", host_settings[1].primary_pattern.ToString());
 
   // Clear all settings since the beginning of time.
-  host_content_settings_map->ClearSettingsForOneTypeWithPredicate(
+  map->ClearSettingsForOneTypeWithPredicate(
       CONTENT_SETTINGS_TYPE_POPUPS, base::Time(),
       HostContentSettingsMap::PatternSourcePredicate());
 
   // Verify we only have the default setting.
-  host_content_settings_map->GetSettingsForOneType(
-      CONTENT_SETTINGS_TYPE_POPUPS, std::string(), &host_settings);
+  map->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_POPUPS, std::string(),
+                             &host_settings);
   EXPECT_EQ(1u, host_settings.size());
   EXPECT_EQ("*", host_settings[0].primary_pattern.ToString());
 }
 
+TEST_F(HostContentSettingsMapTest, GetSettingLastModified) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(features::kTabsInCbd);
+
+  TestingProfile profile;
+  auto* map = HostContentSettingsMapFactory::GetForProfile(&profile);
+
+  auto test_clock = base::MakeUnique<base::SimpleTestClock>();
+  test_clock->SetNow(base::Time::Now());
+  base::SimpleTestClock* clock = test_clock.get();
+  map->SetClockForTesting(std::move(test_clock));
+
+  ContentSettingsForOneType host_settings;
+
+  GURL url("https://www.google.com/");
+  ContentSettingsPattern pattern =
+      ContentSettingsPattern::FromURLNoWildcard(url);
+
+  // Last modified date for non existant settings should be base::Time().
+  base::Time t = map->GetSettingLastModifiedDate(
+      pattern, ContentSettingsPattern::Wildcard(),
+      CONTENT_SETTINGS_TYPE_POPUPS);
+  EXPECT_EQ(base::Time(), t);
+
+  // Add setting for url.
+  map->SetContentSettingDefaultScope(url, GURL(), CONTENT_SETTINGS_TYPE_POPUPS,
+                                     std::string(), CONTENT_SETTING_BLOCK);
+  t = map->GetSettingLastModifiedDate(pattern,
+                                      ContentSettingsPattern::Wildcard(),
+                                      CONTENT_SETTINGS_TYPE_POPUPS);
+  EXPECT_EQ(t, clock->Now());
+
+  clock->Advance(base::TimeDelta::FromSeconds(1));
+  // Modify setting.
+  map->SetContentSettingDefaultScope(url, GURL(), CONTENT_SETTINGS_TYPE_POPUPS,
+                                     std::string(), CONTENT_SETTING_ALLOW);
+
+  t = map->GetSettingLastModifiedDate(pattern,
+                                      ContentSettingsPattern::Wildcard(),
+                                      CONTENT_SETTINGS_TYPE_POPUPS);
+  EXPECT_EQ(t, clock->Now());
+}
+
+TEST_F(HostContentSettingsMapTest, LastModifiedIsNotRecordedWhenDisabled) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndDisableFeature(features::kTabsInCbd);
+
+  TestingProfile profile;
+  auto* map = HostContentSettingsMapFactory::GetForProfile(&profile);
+  ContentSettingsForOneType host_settings;
+
+  GURL url("https://www.google.com/");
+  ContentSettingsPattern pattern =
+      ContentSettingsPattern::FromURLNoWildcard(url);
+
+  // Add setting for url.
+  map->SetContentSettingDefaultScope(url, GURL(), CONTENT_SETTINGS_TYPE_POPUPS,
+                                     std::string(), CONTENT_SETTING_BLOCK);
+
+  base::Time t = map->GetSettingLastModifiedDate(
+      pattern, ContentSettingsPattern::Wildcard(),
+      CONTENT_SETTINGS_TYPE_POPUPS);
+  EXPECT_EQ(base::Time(), t);
+}
+
 TEST_F(HostContentSettingsMapTest, CanSetNarrowestSetting) {
   TestingProfile profile;
   const auto* map = HostContentSettingsMapFactory::GetForProfile(&profile);
diff --git a/chrome/browser/ui/views/frame/minimize_button_metrics_win.cc b/chrome/browser/ui/views/frame/minimize_button_metrics_win.cc
index 095f2574..93080cd 100644
--- a/chrome/browser/ui/views/frame/minimize_button_metrics_win.cc
+++ b/chrome/browser/ui/views/frame/minimize_button_metrics_win.cc
@@ -4,11 +4,12 @@
 
 #include "chrome/browser/ui/views/frame/minimize_button_metrics_win.h"
 
-#include "base/logging.h"
 #include "base/i18n/rtl.h"
+#include "base/logging.h"
 #include "base/win/windows_version.h"
 #include "dwmapi.h"
 #include "ui/base/win/shell.h"
+#include "ui/display/display.h"
 #include "ui/display/win/dpi.h"
 #include "ui/display/win/screen_win.h"
 #include "ui/gfx/geometry/point.h"
@@ -52,6 +53,29 @@
 MinimizeButtonMetrics::~MinimizeButtonMetrics() {
 }
 
+// static
+int MinimizeButtonMetrics::GetCaptionButtonHeightInDIPs() {
+  // At DPI scaling settings other than 100% the result won't be exactly right.
+  // TODO: return a more accurate approximation [http://crbug.com/716365]
+
+  // SM_CYSIZE returns the caption button height, but to get the full height
+  // from the top of the window we add SM_CYSIZEFRAME.
+  const int caption_height = GetSystemMetrics(SM_CYSIZE);
+  const int frame_thickness = GetSystemMetrics(SM_CYSIZEFRAME);
+
+  // The result of GetSystemMetrics depends on the scale factor of the primary
+  // display. Divide the sum by that to convert to DIPs. (Converting SM_CYSIZE
+  // and SM_CYSIZEFRAME to DIPs individually adds a bigger rounding error.)
+  float primary_device_scale_factor =
+      display::Screen::GetScreen()->GetPrimaryDisplay().device_scale_factor();
+  float height_dips =
+      (caption_height + frame_thickness) / primary_device_scale_factor;
+
+  // Testing shows that floor() gives a more accurate approximation than
+  // round() here.
+  return std::floor(height_dips);
+}
+
 void MinimizeButtonMetrics::Init(HWND hwnd) {
   DCHECK(!hwnd_);
   hwnd_ = hwnd;
@@ -123,7 +147,7 @@
     TITLEBARINFOEX titlebar_info = {0};
     titlebar_info.cbSize = sizeof(TITLEBARINFOEX);
     SendMessage(hwnd_, WM_GETTITLEBARINFOEX, 0,
-                reinterpret_cast<WPARAM>(&titlebar_info));
+                reinterpret_cast<LPARAM>(&titlebar_info));
 
     // Under DWM WM_GETTITLEBARINFOEX won't return the right thing until after
     // WM_NCACTIVATE (maybe it returns classic values?). In an attempt to
diff --git a/chrome/browser/ui/views/frame/minimize_button_metrics_win.h b/chrome/browser/ui/views/frame/minimize_button_metrics_win.h
index c3a6d3f3..86d08a4b 100644
--- a/chrome/browser/ui/views/frame/minimize_button_metrics_win.h
+++ b/chrome/browser/ui/views/frame/minimize_button_metrics_win.h
@@ -18,6 +18,9 @@
   MinimizeButtonMetrics();
   ~MinimizeButtonMetrics();
 
+  // Returns the height of the native caption buttons in DIPs.
+  static int GetCaptionButtonHeightInDIPs();
+
   void Init(HWND hwnd);
 
   // Obtain the X offset of the native minimize button. Since Windows can lie
@@ -48,7 +51,7 @@
   // Static cache of |cached_minimize_button_x_delta_|.
   static int last_cached_minimize_button_x_delta_;
 
-  // Static cache of offset value representing the different between
+  // Static cache of offset value representing the difference between
   // DWMWA_CAPTION_BUTTON_BOUNDS and WM_GETTITLEBARINFOEX
   static int button_bounds_position_offset_;
 
diff --git a/chrome/installer/linux/debian/expected_deps_ia32_jessie b/chrome/installer/linux/debian/expected_deps_ia32_jessie
index 8b472b1..a35407e 100644
--- a/chrome/installer/linux/debian/expected_deps_ia32_jessie
+++ b/chrome/installer/linux/debian/expected_deps_ia32_jessie
@@ -8,7 +8,6 @@
 libdbus-1-3 (>= 1.2.14)
 libexpat1 (>= 2.0.1)
 libfontconfig1 (>= 2.11)
-libfreetype6 (>= 2.4.2)
 libgcc1 (>= 1:4.1.1)
 libgconf-2-4 (>= 3.2.5)
 libgdk-pixbuf2.0-0 (>= 2.22.0)
diff --git a/chrome/installer/linux/debian/expected_deps_x64_jessie b/chrome/installer/linux/debian/expected_deps_x64_jessie
index 3f76b8ac..e88b1fd 100644
--- a/chrome/installer/linux/debian/expected_deps_x64_jessie
+++ b/chrome/installer/linux/debian/expected_deps_x64_jessie
@@ -7,7 +7,6 @@
 libdbus-1-3 (>= 1.1.4)
 libexpat1 (>= 2.0.1)
 libfontconfig1 (>= 2.11)
-libfreetype6 (>= 2.3.9)
 libgcc1 (>= 1:4.1.1)
 libgconf-2-4 (>= 3.2.5)
 libgdk-pixbuf2.0-0 (>= 2.22.0)
diff --git a/chrome/installer/linux/rpm/expected_deps_i386 b/chrome/installer/linux/rpm/expected_deps_i386
index 1d5f54d..72004fb 100644
--- a/chrome/installer/linux/rpm/expected_deps_i386
+++ b/chrome/installer/linux/rpm/expected_deps_i386
@@ -36,7 +36,6 @@
 libdl.so.2(GLIBC_2.1)
 libexpat.so.1
 libfontconfig.so.1
-libfreetype.so.6
 libgcc_s.so.1
 libgcc_s.so.1(GCC_4.0.0)
 libgcc_s.so.1(GLIBC_2.0)
diff --git a/chrome/installer/linux/rpm/expected_deps_x86_64 b/chrome/installer/linux/rpm/expected_deps_x86_64
index da09bcc..e3c3556 100644
--- a/chrome/installer/linux/rpm/expected_deps_x86_64
+++ b/chrome/installer/linux/rpm/expected_deps_x86_64
@@ -33,7 +33,6 @@
 libdl.so.2(GLIBC_2.2.5)(64bit)
 libexpat.so.1()(64bit)
 libfontconfig.so.1()(64bit)
-libfreetype.so.6()(64bit)
 libgcc_s.so.1()(64bit)
 libgcc_s.so.1(GCC_3.0)(64bit)
 libgcc_s.so.1(GCC_4.0.0)(64bit)
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 82a31d18..0cf7abb 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -2939,6 +2939,7 @@
     "../browser/browsing_data/cookies_tree_model_unittest.cc",
     "../browser/browsing_data/site_data_counting_helper_unittest.cc",
     "../browser/browsing_data/site_data_size_collector_unittest.cc",
+    "../browser/browsing_data/site_settings_counter_unittest.cc",
     "../browser/budget_service/budget_database_unittest.cc",
     "../browser/budget_service/budget_manager_unittest.cc",
     "../browser/chrome_content_browser_client_unittest.cc",
diff --git a/components/browsing_data/core/BUILD.gn b/components/browsing_data/core/BUILD.gn
index 365cbabe..c2761d7 100644
--- a/components/browsing_data/core/BUILD.gn
+++ b/components/browsing_data/core/BUILD.gn
@@ -19,6 +19,8 @@
     "counters/history_counter.h",
     "counters/passwords_counter.cc",
     "counters/passwords_counter.h",
+    "counters/site_settings_counter.cc",
+    "counters/site_settings_counter.h",
     "history_notice_utils.cc",
     "history_notice_utils.h",
     "pref_names.cc",
@@ -28,6 +30,8 @@
   deps = [
     "//base",
     "//components/autofill/core/browser",
+    "//components/content_settings/core/browser:browser",
+    "//components/content_settings/core/common:common",
     "//components/history/core/browser",
     "//components/password_manager/core/browser",
     "//components/pref_registry:pref_registry",
diff --git a/components/browsing_data/core/DEPS b/components/browsing_data/core/DEPS
index a28b230..c8a900d 100644
--- a/components/browsing_data/core/DEPS
+++ b/components/browsing_data/core/DEPS
@@ -1,6 +1,7 @@
 include_rules = [
   "+components/autofill/core/browser",
   "+components/browser_sync",
+  "+components/content_settings",
   "+components/history/core/browser",
   "+components/history/core/test",
   "+components/password_manager/core/browser",
diff --git a/components/browsing_data/core/browsing_data_utils.cc b/components/browsing_data/core/browsing_data_utils.cc
index 15fd762..12fd8ae 100644
--- a/components/browsing_data/core/browsing_data_utils.cc
+++ b/components/browsing_data/core/browsing_data_utils.cc
@@ -90,6 +90,12 @@
         static_cast<const BrowsingDataCounter::FinishedResult*>(result)
             ->Value();
     text = l10n_util::GetPluralStringFUTF16(IDS_DEL_DOWNLOADS_COUNTER, count);
+  } else if (pref_name == prefs::kDeleteSiteSettings) {
+    BrowsingDataCounter::ResultInt count =
+        static_cast<const BrowsingDataCounter::FinishedResult*>(result)
+            ->Value();
+    text =
+        l10n_util::GetPluralStringFUTF16(IDS_DEL_SITE_SETTINGS_COUNTER, count);
   } else if (pref_name == prefs::kDeleteBrowsingHistoryBasic) {
     // The basic tab doesn't show history counter results.
     NOTREACHED();
@@ -226,6 +232,9 @@
       // Bookmarks are deleted on the Android side. No corresponding deletion
       // preference.
       return false;
+    case BrowsingDataType::SITE_SETTINGS:
+      *out_pref = prefs::kDeleteSiteSettings;
+      return true;
     case BrowsingDataType::NUM_TYPES:
       // This is not an actual type.
       NOTREACHED();
diff --git a/components/browsing_data/core/browsing_data_utils.h b/components/browsing_data/core/browsing_data_utils.h
index 97cc7b1..133e744 100644
--- a/components/browsing_data/core/browsing_data_utils.h
+++ b/components/browsing_data/core/browsing_data_utils.h
@@ -25,6 +25,7 @@
   PASSWORDS,
   FORM_DATA,
   BOOKMARKS,
+  SITE_SETTINGS,
   NUM_TYPES
 };
 
diff --git a/components/browsing_data/core/counters/site_settings_counter.cc b/components/browsing_data/core/counters/site_settings_counter.cc
new file mode 100644
index 0000000..fc6ecd6
--- /dev/null
+++ b/components/browsing_data/core/counters/site_settings_counter.cc
@@ -0,0 +1,50 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/browsing_data/core/counters/site_settings_counter.h"
+
+#include <set>
+#include "components/browsing_data/core/pref_names.h"
+#include "components/content_settings/core/browser/content_settings_registry.h"
+#include "components/content_settings/core/common/content_settings_pattern.h"
+
+namespace browsing_data {
+
+SiteSettingsCounter::SiteSettingsCounter(HostContentSettingsMap* map)
+    : map_(map) {
+  DCHECK(map_);
+}
+
+SiteSettingsCounter::~SiteSettingsCounter() {}
+
+void SiteSettingsCounter::OnInitialized() {}
+
+const char* SiteSettingsCounter::GetPrefName() const {
+  return browsing_data::prefs::kDeleteSiteSettings;
+}
+
+void SiteSettingsCounter::Count() {
+  std::set<ContentSettingsPattern> patterns;
+  base::Time period_start = GetPeriodStart();
+  auto* registry = content_settings::ContentSettingsRegistry::GetInstance();
+  for (const content_settings::ContentSettingsInfo* info : *registry) {
+    ContentSettingsType type = info->website_settings_info()->type();
+    ContentSettingsForOneType content_settings_list;
+    map_->GetSettingsForOneType(type, content_settings::ResourceIdentifier(),
+                                &content_settings_list);
+    for (const auto& content_setting : content_settings_list) {
+      if (content_setting.source == "preference") {
+        base::Time last_modified = map_->GetSettingLastModifiedDate(
+            content_setting.primary_pattern, content_setting.secondary_pattern,
+            type);
+        if (last_modified >= period_start) {
+          patterns.insert(content_setting.primary_pattern);
+        }
+      }
+    }
+  }
+  ReportResult(patterns.size());
+}
+
+}  // namespace browsing_data
diff --git a/components/browsing_data/core/counters/site_settings_counter.h b/components/browsing_data/core/counters/site_settings_counter.h
new file mode 100644
index 0000000..bab835b
--- /dev/null
+++ b/components/browsing_data/core/counters/site_settings_counter.h
@@ -0,0 +1,30 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_BROWSING_DATA_CORE_COUNTERS_SITE_SETTINGS_COUNTER_H_
+#define COMPONENTS_BROWSING_DATA_CORE_COUNTERS_SITE_SETTINGS_COUNTER_H_
+
+#include "components/browsing_data/core/counters/browsing_data_counter.h"
+#include "components/content_settings/core/browser/host_content_settings_map.h"
+
+namespace browsing_data {
+
+class SiteSettingsCounter : public browsing_data::BrowsingDataCounter {
+ public:
+  explicit SiteSettingsCounter(HostContentSettingsMap* hcsm);
+  ~SiteSettingsCounter() override;
+
+  const char* GetPrefName() const override;
+
+ private:
+  void OnInitialized() override;
+
+  void Count() override;
+
+  scoped_refptr<HostContentSettingsMap> map_;
+};
+
+}  // namespace browsing_data
+
+#endif  // COMPONENTS_BROWSING_DATA_CORE_COUNTERS_SITE_SETTINGS_COUNTER_H_
diff --git a/components/browsing_data/core/pref_names.cc b/components/browsing_data/core/pref_names.cc
index 59113a8..26830381 100644
--- a/components/browsing_data/core/pref_names.cc
+++ b/components/browsing_data/core/pref_names.cc
@@ -27,6 +27,7 @@
 const char kDeleteFormData[] = "browser.clear_data.form_data";
 const char kDeleteHostedAppsData[] = "browser.clear_data.hosted_apps_data";
 const char kDeleteMediaLicenses[] = "browser.clear_data.media_licenses";
+const char kDeleteSiteSettings[] = "browser.clear_data.site_settings";
 
 // Other Clear Browsing Data preferences.
 const char kLastClearBrowsingDataTime[] =
@@ -76,6 +77,9 @@
   registry->RegisterBooleanPref(
       kDeleteMediaLicenses, false,
       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+  registry->RegisterBooleanPref(
+      kDeleteSiteSettings, false,
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
   registry->RegisterInt64Pref(prefs::kLastClearBrowsingDataTime, 0);
 #endif  // !defined(OS_IOS)
 
diff --git a/components/browsing_data/core/pref_names.h b/components/browsing_data/core/pref_names.h
index a8af566..fd25225a 100644
--- a/components/browsing_data/core/pref_names.h
+++ b/components/browsing_data/core/pref_names.h
@@ -27,6 +27,7 @@
 extern const char kDeleteFormData[];
 extern const char kDeleteHostedAppsData[];
 extern const char kDeleteMediaLicenses[];
+extern const char kDeleteSiteSettings[];
 
 extern const char kLastClearBrowsingDataTime[];
 extern const char kClearBrowsingDataHistoryNoticeShownTimes[];
diff --git a/components/browsing_data_strings.grdp b/components/browsing_data_strings.grdp
index fef13a8..67110ee 100644
--- a/components/browsing_data_strings.grdp
+++ b/components/browsing_data_strings.grdp
@@ -37,6 +37,12 @@
      =1 {1 password (synced)}
      other {# passwords (synced)}}
   </message>
+  <message name="IDS_DEL_SITE_SETTINGS_COUNTER" desc="A counter showing how many sites with site settings the user has.">
+    {COUNT, plural,
+     =0 {none}
+     =1 {1 site}
+     other {# sites}}
+  </message>
   <message name="IDS_DEL_AUTOFILL_COUNTER_EMPTY" desc="A counter showing that the user has no form data stored.">
     none
   </message>
diff --git a/components/content_settings/core/browser/content_settings_pref.cc b/components/content_settings/core/browser/content_settings_pref.cc
index d26b155..9d09c30 100644
--- a/components/content_settings/core/browser/content_settings_pref.cc
+++ b/components/content_settings/core/browser/content_settings_pref.cc
@@ -77,14 +77,12 @@
     PrefChangeRegistrar* registrar,
     const std::string& pref_name,
     bool incognito,
-    bool store_last_modified,
     NotifyObserversCallback notify_callback)
     : content_type_(content_type),
       prefs_(prefs),
       registrar_(registrar),
       pref_name_(pref_name),
       is_incognito_(incognito),
-      store_last_modified_(store_last_modified),
       updating_preferences_(false),
       notify_callback_(notify_callback) {
   DCHECK(prefs_);
@@ -113,6 +111,7 @@
     const ContentSettingsPattern& primary_pattern,
     const ContentSettingsPattern& secondary_pattern,
     const ResourceIdentifier& resource_identifier,
+    base::Time modified_time,
     base::Value* in_value) {
   DCHECK(!in_value || IsValueAllowedForType(in_value, content_type_));
   DCHECK(thread_checker_.CalledOnValidThread());
@@ -129,9 +128,6 @@
   if (!is_incognito_)
     map_to_modify = &value_map_;
 
-  base::Time modified_time =
-      store_last_modified_ ? base::Time::Now() : base::Time();
-
   {
     base::AutoLock auto_lock(lock_);
     if (value.get()) {
diff --git a/components/content_settings/core/browser/content_settings_pref.h b/components/content_settings/core/browser/content_settings_pref.h
index 697425d4..3139fc4 100644
--- a/components/content_settings/core/browser/content_settings_pref.h
+++ b/components/content_settings/core/browser/content_settings_pref.h
@@ -44,7 +44,6 @@
                       PrefChangeRegistrar* registrar,
                       const std::string& pref_name,
                       bool incognito,
-                      bool store_last_modified,
                       NotifyObserversCallback notify_callback);
   ~ContentSettingsPref();
 
@@ -56,6 +55,7 @@
   bool SetWebsiteSetting(const ContentSettingsPattern& primary_pattern,
                          const ContentSettingsPattern& secondary_pattern,
                          const ResourceIdentifier& resource_identifier,
+                         base::Time modified_time,
                          base::Value* value);
 
   // Returns the |last_modified| date of a setting.
@@ -113,8 +113,6 @@
 
   bool is_incognito_;
 
-  bool store_last_modified_;
-
   // Whether we are currently updating preferences, this is used to ignore
   // notifications from the preferences service that we triggered ourself.
   bool updating_preferences_;
diff --git a/components/content_settings/core/browser/content_settings_pref_provider.cc b/components/content_settings/core/browser/content_settings_pref_provider.cc
index e7ac35f3c..fc1d59bb 100644
--- a/components/content_settings/core/browser/content_settings_pref_provider.cc
+++ b/components/content_settings/core/browser/content_settings_pref_provider.cc
@@ -15,6 +15,7 @@
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/time/default_clock.h"
 #include "components/content_settings/core/browser/content_settings_pref.h"
 #include "components/content_settings/core/browser/content_settings_rule.h"
 #include "components/content_settings/core/browser/content_settings_utils.h"
@@ -85,7 +86,10 @@
 PrefProvider::PrefProvider(PrefService* prefs,
                            bool incognito,
                            bool store_last_modified)
-    : prefs_(prefs), is_incognito_(incognito) {
+    : prefs_(prefs),
+      is_incognito_(incognito),
+      store_last_modified_(store_last_modified),
+      clock_(new base::DefaultClock) {
   DCHECK(prefs_);
   // Verify preferences version.
   if (!prefs_->HasPrefPath(prefs::kContentSettingsVersion)) {
@@ -108,7 +112,7 @@
         info->type(),
         base::MakeUnique<ContentSettingsPref>(
             info->type(), prefs_, &pref_change_registrar_, info->pref_name(),
-            is_incognito_, store_last_modified,
+            is_incognito_,
             base::Bind(&PrefProvider::Notify, base::Unretained(this)))));
   }
 
@@ -153,9 +157,12 @@
     return false;
   }
 
+  base::Time modified_time =
+      store_last_modified_ ? clock_->Now() : base::Time();
+
   return GetPref(content_type)
       ->SetWebsiteSetting(primary_pattern, secondary_pattern,
-                          resource_identifier, in_value);
+                          resource_identifier, modified_time, in_value);
 }
 
 base::Time PrefProvider::GetWebsiteSettingLastModified(
@@ -276,4 +283,8 @@
   }
 }
 
+void PrefProvider::SetClockForTesting(std::unique_ptr<base::Clock> clock) {
+  clock_ = std::move(clock);
+}
+
 }  // namespace content_settings
diff --git a/components/content_settings/core/browser/content_settings_pref_provider.h b/components/content_settings/core/browser/content_settings_pref_provider.h
index e8520260..124ac9b 100644
--- a/components/content_settings/core/browser/content_settings_pref_provider.h
+++ b/components/content_settings/core/browser/content_settings_pref_provider.h
@@ -18,6 +18,10 @@
 
 class PrefService;
 
+namespace base {
+class Clock;
+}
+
 namespace user_prefs {
 class PrefRegistrySyncable;
 }
@@ -62,6 +66,8 @@
 
   ContentSettingsPref* GetPref(ContentSettingsType type) const;
 
+  void SetClockForTesting(std::unique_ptr<base::Clock> clock);
+
  private:
   friend class DeadlockCheckerObserver;  // For testing.
 
@@ -78,6 +84,8 @@
 
   const bool is_incognito_;
 
+  bool store_last_modified_;
+
   PrefChangeRegistrar pref_change_registrar_;
 
   std::map<ContentSettingsType, std::unique_ptr<ContentSettingsPref>>
@@ -85,6 +93,8 @@
 
   base::ThreadChecker thread_checker_;
 
+  std::unique_ptr<base::Clock> clock_;
+
   DISALLOW_COPY_AND_ASSIGN(PrefProvider);
 };
 
diff --git a/components/content_settings/core/browser/host_content_settings_map.cc b/components/content_settings/core/browser/host_content_settings_map.cc
index 3c6d765..358a1bc 100644
--- a/components/content_settings/core/browser/host_content_settings_map.cc
+++ b/components/content_settings/core/browser/host_content_settings_map.cc
@@ -658,6 +658,14 @@
   FlushLossyWebsiteSettings();
 }
 
+base::Time HostContentSettingsMap::GetSettingLastModifiedDate(
+    const ContentSettingsPattern& primary_pattern,
+    const ContentSettingsPattern& secondary_pattern,
+    ContentSettingsType content_type) const {
+  return pref_provider_->GetWebsiteSettingLastModified(
+      primary_pattern, secondary_pattern, content_type, std::string());
+}
+
 void HostContentSettingsMap::ClearSettingsForOneTypeWithPredicate(
     ContentSettingsType content_type,
     base::Time begin_time,
@@ -928,3 +936,8 @@
   }
   return std::unique_ptr<base::Value>();
 }
+
+void HostContentSettingsMap::SetClockForTesting(
+    std::unique_ptr<base::Clock> clock) {
+  pref_provider_->SetClockForTesting(std::move(clock));
+}
\ No newline at end of file
diff --git a/components/content_settings/core/browser/host_content_settings_map.h b/components/content_settings/core/browser/host_content_settings_map.h
index 63c23d59..5111937 100644
--- a/components/content_settings/core/browser/host_content_settings_map.h
+++ b/components/content_settings/core/browser/host_content_settings_map.h
@@ -31,6 +31,7 @@
 
 namespace base {
 class Value;
+class Clock;
 }
 
 namespace content_settings {
@@ -218,6 +219,16 @@
   // This should only be called on the UI thread.
   void ClearSettingsForOneType(ContentSettingsType content_type);
 
+  // Return the |last_modified| date of a content setting. This will only return
+  // valid values for settings from the PreferenceProvider. Settings from other
+  // providers will return base::Time().
+  //
+  // This may be called on any thread.
+  base::Time GetSettingLastModifiedDate(
+      const ContentSettingsPattern& primary_pattern,
+      const ContentSettingsPattern& secondary_pattern,
+      ContentSettingsType content_type) const;
+
   using PatternSourcePredicate =
       base::Callback<bool(const ContentSettingsPattern& primary_pattern,
                           const ContentSettingsPattern& secondary_pattern)>;
@@ -272,6 +283,10 @@
 
   base::WeakPtr<HostContentSettingsMap> GetWeakPtr();
 
+  // Injects a clock into the PrefProvider to allow control over the
+  // |last_modified| timestamp.
+  void SetClockForTesting(std::unique_ptr<base::Clock> clock);
+
  private:
   friend class base::RefCountedThreadSafe<HostContentSettingsMap>;
 
diff --git a/components/favicon/core/large_icon_service.cc b/components/favicon/core/large_icon_service.cc
index bf94e5b..dbed2ddb 100644
--- a/components/favicon/core/large_icon_service.cc
+++ b/components/favicon/core/large_icon_service.cc
@@ -40,10 +40,18 @@
 
 const char kGoogleServerV2RequestFormat[] =
     "https://t0.gstatic.com/faviconV2?"
-    "client=chrome&drop_404_icon=true&size=32&min_size=%d&max_size=64&"
-    "fallback_opts=TYPE,SIZE,URL&url=%s";
+    "client=chrome&drop_404_icon=true&check_firsttimes=true&"
+    "size=%d&min_size=%d&max_size=%d&fallback_opts=TYPE,SIZE,URL&url=%s";
 const char kGoogleServerV2RequestFormatParam[] = "request_format";
 
+const int kGoogleServerV2EnforcedMinSizeInPixel = 32;
+const char kGoogleServerV2EnforcedMinSizeInPixelParam[] =
+    "enforced_min_size_in_pixel";
+
+const double kGoogleServerV2DesiredToMaxSizeFactor = 2.0;
+const char kGoogleServerV2DesiredToMaxSizeFactorParam[] =
+    "desired_to_max_size_factor";
+
 GURL TrimPageUrlForGoogleServer(const GURL& page_url) {
   if (!page_url.SchemeIsHTTPOrHTTPS() || page_url.HostIsIPAddress())
     return GURL();
@@ -57,13 +65,29 @@
 }
 
 GURL GetRequestUrlForGoogleServerV2(const GURL& page_url,
-                                    int min_source_size_in_pixel) {
+                                    int min_source_size_in_pixel,
+                                    int desired_size_in_pixel) {
   std::string url_format = base::GetFieldTrialParamValueByFeature(
       kLargeIconServiceFetchingFeature, kGoogleServerV2RequestFormatParam);
+  double desired_to_max_size_factor = base::GetFieldTrialParamByFeatureAsDouble(
+      kLargeIconServiceFetchingFeature,
+      kGoogleServerV2DesiredToMaxSizeFactorParam,
+      kGoogleServerV2DesiredToMaxSizeFactor);
+
+  min_source_size_in_pixel = std::max(
+      min_source_size_in_pixel, base::GetFieldTrialParamByFeatureAsInt(
+                                    kLargeIconServiceFetchingFeature,
+                                    kGoogleServerV2EnforcedMinSizeInPixelParam,
+                                    kGoogleServerV2EnforcedMinSizeInPixel));
+  desired_size_in_pixel =
+      std::max(desired_size_in_pixel, min_source_size_in_pixel);
+  int max_size_in_pixel =
+      static_cast<int>(desired_size_in_pixel * desired_to_max_size_factor);
 
   return GURL(base::StringPrintf(
       url_format.empty() ? kGoogleServerV2RequestFormat : url_format.c_str(),
-      min_source_size_in_pixel, page_url.spec().c_str()));
+      desired_size_in_pixel, min_source_size_in_pixel, max_size_in_pixel,
+      page_url.spec().c_str()));
 }
 
 bool IsDbResultAdequate(const favicon_base::FaviconRawBitmapResult& db_result,
@@ -320,12 +344,13 @@
     GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
         const GURL& page_url,
         int min_source_size_in_pixel,
+        int desired_size_in_pixel,
         const base::Callback<void(bool success)>& callback) {
   DCHECK_LE(0, min_source_size_in_pixel);
 
   const GURL trimmed_page_url = TrimPageUrlForGoogleServer(page_url);
   const GURL server_request_url = GetRequestUrlForGoogleServerV2(
-      trimmed_page_url, min_source_size_in_pixel);
+      trimmed_page_url, min_source_size_in_pixel, desired_size_in_pixel);
 
   // Do not download if the URL is invalid after trimming, or there is a
   // previous cache miss recorded for |server_request_url|.
diff --git a/components/favicon/core/large_icon_service.h b/components/favicon/core/large_icon_service.h
index 7207e605..bfea676 100644
--- a/components/favicon/core/large_icon_service.h
+++ b/components/favicon/core/large_icon_service.h
@@ -72,6 +72,8 @@
   // encouraged to use GetLargeIconOrFallbackStyle() first.
   //
   // A minimum size |min_source_size_in_pixel| can be specified as a constraint.
+  // |desired_size_in_pixel| serves only as a hint to the service, no guarantees
+  // on the fetched size are provided.
   //
   // The callback is triggered when the operation finishes, where |success|
   // tells whether the fetch actually managed to database a new icon in the
@@ -83,6 +85,7 @@
   void GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
       const GURL& page_url,
       int min_source_size_in_pixel,
+      int desired_size_in_pixel,
       const base::Callback<void(bool success)>& callback);
 
  private:
diff --git a/components/favicon/core/large_icon_service_unittest.cc b/components/favicon/core/large_icon_service_unittest.cc
index 67fcdd7a..4542e630 100644
--- a/components/favicon/core/large_icon_service_unittest.cc
+++ b/components/favicon/core/large_icon_service_unittest.cc
@@ -140,8 +140,8 @@
 TEST_F(LargeIconServiceTest, ShouldGetFromGoogleServer) {
   const GURL kExpectedServerUrl(
       "https://t0.gstatic.com/faviconV2?client=chrome&drop_404_icon=true"
-      "&size=32&min_size=42&max_size=64&fallback_opts=TYPE,SIZE,URL"
-      "&url=http://www.example.com/");
+      "&check_firsttimes=true&size=61&min_size=42&max_size=122"
+      "&fallback_opts=TYPE,SIZE,URL&url=http://www.example.com/");
 
   EXPECT_CALL(mock_favicon_service_, UnableToDownloadFavicon(_)).Times(0);
 
@@ -157,7 +157,8 @@
 
   large_icon_service_
       .GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
-          GURL(kDummyUrl), /*min_source_size_in_pixel=*/42, callback.Get());
+          GURL(kDummyUrl), /*min_source_size_in_pixel=*/42,
+          /*desired_size_in_pixel=*/61, callback.Get());
 
   EXPECT_CALL(callback, Run(true));
   base::RunLoop().RunUntilIdle();
@@ -168,10 +169,15 @@
 TEST_F(LargeIconServiceTest, ShouldGetFromGoogleServerWithCustomUrl) {
   variations::testing::VariationParamsManager variation_params(
       "LargeIconServiceFetching",
-      {{"request_format", "https://t0.gstatic.com/faviconV2?size=%d&url=%s"}},
+      {{"request_format",
+        "https://t0.gstatic.com/"
+        "faviconV2?size=%d&min_size=%d&max_size=%d&url=%s"},
+       {"enforced_min_size_in_pixel", "43"},
+       {"desired_to_max_size_factor", "1.5"}},
       {"LargeIconServiceFetching"});
   const GURL kExpectedServerUrl(
-      "https://t0.gstatic.com/faviconV2?size=42&url=http://www.example.com/");
+      "https://t0.gstatic.com/"
+      "faviconV2?size=61&min_size=43&max_size=91&url=http://www.example.com/");
 
   EXPECT_CALL(mock_favicon_service_, UnableToDownloadFavicon(_)).Times(0);
 
@@ -187,7 +193,8 @@
 
   large_icon_service_
       .GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
-          GURL(kDummyUrl), /*min_source_size_in_pixel=*/42, callback.Get());
+          GURL(kDummyUrl), /*min_source_size_in_pixel=*/42,
+          /*desired_size_in_pixel=*/61, callback.Get());
 
   EXPECT_CALL(callback, Run(true));
   base::RunLoop().RunUntilIdle();
@@ -196,8 +203,8 @@
 TEST_F(LargeIconServiceTest, ShouldGetFromGoogleServerWithOriginalUrl) {
   const GURL kExpectedServerUrl(
       "https://t0.gstatic.com/faviconV2?client=chrome&drop_404_icon=true"
-      "&size=32&min_size=42&max_size=64&fallback_opts=TYPE,SIZE,URL"
-      "&url=http://www.example.com/");
+      "&check_firsttimes=true&size=61&min_size=42&max_size=122"
+      "&fallback_opts=TYPE,SIZE,URL&url=http://www.example.com/");
   const GURL kExpectedOriginalUrl("http://www.example.com/favicon.png");
 
   image_fetcher::RequestMetadata expected_metadata;
@@ -216,7 +223,8 @@
   base::MockCallback<base::Callback<void(bool success)>> callback;
   large_icon_service_
       .GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
-          GURL(kDummyUrl), /*min_source_size_in_pixel=*/42, callback.Get());
+          GURL(kDummyUrl), /*min_source_size_in_pixel=*/42,
+          /*desired_size_in_pixel=*/61, callback.Get());
 
   EXPECT_CALL(callback, Run(true));
   base::RunLoop().RunUntilIdle();
@@ -226,8 +234,8 @@
   const GURL kDummyUrlWithQuery("http://www.example.com?foo=1");
   const GURL kExpectedServerUrl(
       "https://t0.gstatic.com/faviconV2?client=chrome&drop_404_icon=true"
-      "&size=32&min_size=42&max_size=64&fallback_opts=TYPE,SIZE,URL"
-      "&url=http://www.example.com/");
+      "&check_firsttimes=true&size=61&min_size=42&max_size=122"
+      "&fallback_opts=TYPE,SIZE,URL&url=http://www.example.com/");
 
   EXPECT_CALL(*mock_image_fetcher_,
               StartOrQueueNetworkRequest(_, kExpectedServerUrl, _))
@@ -240,7 +248,7 @@
   large_icon_service_
       .GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
           GURL(kDummyUrlWithQuery), /*min_source_size_in_pixel=*/42,
-          base::Callback<void(bool success)>());
+          /*desired_size_in_pixel=*/61, base::Callback<void(bool success)>());
 
   base::RunLoop().RunUntilIdle();
 }
@@ -255,7 +263,8 @@
 
   large_icon_service_
       .GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
-          GURL(kDummyFtpUrl), /*min_source_size_in_pixel=*/42, callback.Get());
+          GURL(kDummyFtpUrl), /*min_source_size_in_pixel=*/42,
+          /*desired_size_in_pixel=*/61, callback.Get());
 
   EXPECT_CALL(callback, Run(false));
   base::RunLoop().RunUntilIdle();
@@ -268,8 +277,8 @@
   const GURL kDummyUrlWithQuery("http://www.example.com?foo=1");
   const GURL kExpectedServerUrl(
       "https://t0.gstatic.com/faviconV2?client=chrome&drop_404_icon=true"
-      "&size=32&min_size=42&max_size=64&fallback_opts=TYPE,SIZE,URL"
-      "&url=http://www.example.com/");
+      "&check_firsttimes=true&size=61&min_size=42&max_size=122"
+      "&fallback_opts=TYPE,SIZE,URL&url=http://www.example.com/");
 
   EXPECT_CALL(mock_favicon_service_, SetLastResortFavicons(_, _, _, _, _))
       .Times(0);
@@ -283,7 +292,8 @@
 
   large_icon_service_
       .GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
-          kDummyUrlWithQuery, /*min_source_size_in_pixel=*/42, callback.Get());
+          kDummyUrlWithQuery, /*min_source_size_in_pixel=*/42,
+          /*desired_size_in_pixel=*/61, callback.Get());
 
   EXPECT_CALL(callback, Run(false));
   base::RunLoop().RunUntilIdle();
@@ -297,8 +307,8 @@
       mock_favicon_service_,
       WasUnableToDownloadFavicon(GURL(
           "https://t0.gstatic.com/faviconV2?client=chrome&drop_404_icon=true"
-          "&size=32&min_size=42&max_size=64&fallback_opts=TYPE,SIZE,URL"
-          "&url=http://www.example.com/")))
+          "&check_firsttimes=true&size=61&min_size=42&max_size=122"
+          "&fallback_opts=TYPE,SIZE,URL&url=http://www.example.com/")))
       .WillByDefault(Return(true));
 
   EXPECT_CALL(mock_favicon_service_, UnableToDownloadFavicon(_)).Times(0);
@@ -310,7 +320,8 @@
   base::MockCallback<base::Callback<void(bool success)>> callback;
   large_icon_service_
       .GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
-          GURL(kDummyUrl), /*min_source_size_in_pixel=*/42, callback.Get());
+          GURL(kDummyUrl), /*min_source_size_in_pixel=*/42,
+          /*desired_size_in_pixel=*/61, callback.Get());
 
   EXPECT_CALL(callback, Run(false));
   base::RunLoop().RunUntilIdle();
diff --git a/components/ntp_snippets/content_suggestions_service.cc b/components/ntp_snippets/content_suggestions_service.cc
index de7ab3f..c31a72e 100644
--- a/components/ntp_snippets/content_suggestions_service.cc
+++ b/components/ntp_snippets/content_suggestions_service.cc
@@ -235,7 +235,7 @@
   // Try to fetch the favicon from a Google favicon server.
   large_icon_service_
       ->GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
-          publisher_url, minimum_size_in_pixel,
+          publisher_url, minimum_size_in_pixel, desired_size_in_pixel,
           base::Bind(
               &ContentSuggestionsService::OnGetFaviconFromGoogleServerFinished,
               base::Unretained(this), publisher_url, minimum_size_in_pixel,
diff --git a/device/bluetooth/bluetooth_remote_gatt_descriptor_mac.mm b/device/bluetooth/bluetooth_remote_gatt_descriptor_mac.mm
index d7c5d6c7..a8ede9c 100644
--- a/device/bluetooth/bluetooth_remote_gatt_descriptor_mac.mm
+++ b/device/bluetooth/bluetooth_remote_gatt_descriptor_mac.mm
@@ -189,7 +189,7 @@
   const BluetoothRemoteGattCharacteristicMac* characteristic_mac =
       static_cast<const BluetoothRemoteGattCharacteristicMac*>(
           descriptor.GetCharacteristic());
-  return out << "<BluetoothRemoteGattServiceMac "
+  return out << "<BluetoothRemoteGattDescriptorMac "
              << descriptor.GetUUID().canonical_value() << "/" << &descriptor
              << ", characteristic: "
              << characteristic_mac->GetUUID().canonical_value() << "/"
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.mm
index a148916..cc7a811 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.mm
@@ -14,6 +14,8 @@
 #import "ios/chrome/browser/ui/collection_view/collection_view_model.h"
 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_article_item.h"
 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_footer_item.h"
+#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited.h"
+#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.h"
 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_reading_list_item.h"
 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_text_item.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestion.h"
@@ -236,16 +238,19 @@
     return [NSArray array];
   }
 
+  NSMutableArray<ContentSuggestionsMostVisited*>* mostVisitedToAdd =
+      [NSMutableArray array];
+
+  CSCollectionViewModel* model =
+      self.collectionViewController.collectionViewModel;
   NSMutableArray<NSIndexPath*>* indexPaths = [NSMutableArray array];
   for (ContentSuggestion* suggestion in suggestions) {
     ContentSuggestionsSectionInformation* sectionInfo =
         suggestion.suggestionIdentifier.sectionInfo;
     NSInteger sectionIdentifier = SectionIdentifierForInfo(sectionInfo);
-    CSCollectionViewModel* model =
-        self.collectionViewController.collectionViewModel;
 
     if (![model hasSectionForSectionIdentifier:sectionIdentifier])
-      return [NSArray array];
+      continue;
 
     NSInteger section = [model sectionForSectionIdentifier:sectionIdentifier];
     NSIndexPath* indexPath = [NSIndexPath indexPathForItem:0 inSection:section];
@@ -288,12 +293,37 @@
         break;
       }
       case ContentSuggestionTypeMostVisited: {
-        // TODO(crbug.com/707754): Add the most visited item.
+        NSInteger section =
+            [model sectionForSectionIdentifier:SectionIdentifierMostVisited];
+        NSIndexPath* indexPath =
+            [NSIndexPath indexPathForItem:0 inSection:section];
+
+        if ([model numberOfItemsInSection:section] == 0) {
+          [model addItem:[[ContentSuggestionsMostVisitedItem alloc]
+                             initWithType:ItemTypeMostVisited]
+              toSectionWithIdentifier:SectionIdentifierMostVisited];
+          [indexPaths addObject:indexPath];
+        }
+
+        ContentSuggestionsMostVisited* mostVisited =
+            [ContentSuggestionsMostVisited mostVisitedWithTitle:suggestion.title
+                                                     attributes:nil];
+        [mostVisitedToAdd addObject:mostVisited];
         break;
       }
     }
   }
 
+  if ([model hasSectionForSectionIdentifier:SectionIdentifierMostVisited]) {
+    NSInteger section =
+        [model sectionForSectionIdentifier:SectionIdentifierMostVisited];
+    NSIndexPath* indexPath = [NSIndexPath indexPathForItem:0 inSection:section];
+    ContentSuggestionsMostVisitedItem* item =
+        base::mac::ObjCCast<ContentSuggestionsMostVisitedItem>(
+            [model itemAtIndexPath:indexPath]);
+    item.suggestions = mostVisitedToAdd;
+  }
+
   return indexPaths;
 }
 
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index dbaa7468..663b455b 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -63,11 +63,6 @@
 
 crbug.com/627844 virtual/gpu/fast/canvas/canvas-createImageBitmap-colorClamping.html [ Failure ]
 
-crbug.com/626748 paint/invalidation/table/cached-change-row-border-color.html [ Failure ]
-crbug.com/626748 paint/invalidation/table/cached-change-tbody-border-color.html [ Failure ]
-crbug.com/626748 virtual/disable-spinvalidation/paint/invalidation/table/cached-change-row-border-color.html [ Failure ]
-crbug.com/626748 virtual/disable-spinvalidation/paint/invalidation/table/cached-change-tbody-border-color.html [ Failure ]
-
 # Scanlines off by 1, but code path should be the same
 crbug.com/644433 virtual/gpu/fast/canvas/OffscreenCanvas-2d-pattern-in-worker.html [ Failure ]
 
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/table-outer-border-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/table-outer-border-expected.txt
index 1180387..1eb1c11 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/table-outer-border-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/table-outer-border-expected.txt
@@ -17,38 +17,28 @@
           "reason": "layoutObject insertion"
         },
         {
-          "object": "LayoutTableCell TD",
-          "rect": [8, 75, 132, 82],
-          "reason": "layoutObject insertion"
-        },
-        {
-          "object": "LayoutTableCell TD",
-          "rect": [8, 75, 132, 82],
-          "reason": "layoutObject removal"
-        },
-        {
-          "object": "LayoutTableCell TD",
-          "rect": [8, 8, 132, 82],
-          "reason": "layoutObject insertion"
-        },
-        {
-          "object": "LayoutTableCell TD",
-          "rect": [8, 8, 132, 82],
-          "reason": "layoutObject removal"
-        },
-        {
           "object": "LayoutTableSection TBODY",
-          "rect": [15, 15, 117, 134],
+          "rect": [8, 8, 132, 149],
+          "reason": "layoutObject removal"
+        },
+        {
+          "object": "LayoutTableCell TD",
+          "rect": [8, 75, 132, 82],
           "reason": "layoutObject removal"
         },
         {
           "object": "LayoutTableRow TR",
-          "rect": [15, 82, 117, 67],
+          "rect": [8, 75, 132, 82],
+          "reason": "layoutObject removal"
+        },
+        {
+          "object": "LayoutTableCell TD",
+          "rect": [8, 8, 132, 82],
           "reason": "layoutObject removal"
         },
         {
           "object": "LayoutTableRow TR",
-          "rect": [15, 15, 117, 67],
+          "rect": [8, 8, 132, 82],
           "reason": "layoutObject removal"
         }
       ]
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/table/border-collapse-change-collapse-to-separate-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/table/border-collapse-change-collapse-to-separate-expected.txt
index ad713c61..1ee92c8 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/table/border-collapse-change-collapse-to-separate-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/table/border-collapse-change-collapse-to-separate-expected.txt
@@ -10,16 +10,6 @@
           "object": "LayoutTable TABLE id='table'",
           "rect": [8, 8, 220, 112],
           "reason": "style change"
-        },
-        {
-          "object": "LayoutTableCell TD",
-          "rect": [112, 8, 108, 108],
-          "reason": "style change"
-        },
-        {
-          "object": "LayoutTableCell TD",
-          "rect": [8, 8, 107, 108],
-          "reason": "style change"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/table/border-collapse-change-separate-to-collapse-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/table/border-collapse-change-separate-to-collapse-expected.txt
index 8efc456..bb5003b8 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/table/border-collapse-change-separate-to-collapse-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/table/border-collapse-change-separate-to-collapse-expected.txt
@@ -10,16 +10,6 @@
           "object": "LayoutTable TABLE id='table'",
           "rect": [8, 8, 220, 112],
           "reason": "style change"
-        },
-        {
-          "object": "LayoutTableCell TD",
-          "rect": [112, 8, 108, 108],
-          "reason": "style change"
-        },
-        {
-          "object": "LayoutTableCell TD",
-          "rect": [8, 8, 107, 108],
-          "reason": "style change"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/table/cached-69296-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/table/cached-69296-expected.txt
index a591684..e194c1a 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/table/cached-69296-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/table/cached-69296-expected.txt
@@ -8,12 +8,12 @@
       "paintInvalidations": [
         {
           "object": "LayoutTableRow TR id='row1'",
-          "rect": [20, 20, 159, 50],
+          "rect": [20, 20, 160, 51],
           "reason": "style change"
         },
         {
           "object": "LayoutTableRow TR id='row1'",
-          "rect": [20, 20, 159, 50],
+          "rect": [20, 20, 160, 51],
           "reason": "style change"
         }
       ]
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/table/cached-change-col-border-width-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/table/cached-change-col-border-width-expected.txt
index e40dba10..3c8c4e39 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/table/cached-change-col-border-width-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/table/cached-change-col-border-width-expected.txt
@@ -12,21 +12,16 @@
           "reason": "style change"
         },
         {
+          "object": "LayoutTableSection TBODY",
+          "rect": [8, 8, 113, 104],
+          "reason": "location change"
+        },
+        {
           "object": "LayoutTable TABLE",
           "rect": [8, 108, 113, 4],
           "reason": "incremental"
         },
         {
-          "object": "LayoutTableSection TBODY",
-          "rect": [10, 10, 110, 100],
-          "reason": "bounds change"
-        },
-        {
-          "object": "LayoutTableSection TBODY",
-          "rect": [9, 9, 107, 100],
-          "reason": "bounds change"
-        },
-        {
           "object": "LayoutTableCell TD",
           "rect": [8, 59, 60, 53],
           "reason": "bounds change"
@@ -96,7 +91,7 @@
     },
     {
       "object": "LayoutTableSection TBODY",
-      "reason": "bounds change"
+      "reason": "location change"
     },
     {
       "object": "LayoutTableRow TR",
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/table/cached-change-colgroup-border-width-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/table/cached-change-colgroup-border-width-expected.txt
index b741bca..81ee962 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/table/cached-change-colgroup-border-width-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/table/cached-change-colgroup-border-width-expected.txt
@@ -7,6 +7,11 @@
       "drawsContent": true,
       "paintInvalidations": [
         {
+          "object": "LayoutTableSection TBODY",
+          "rect": [7, 7, 167, 104],
+          "reason": "bounds change"
+        },
+        {
           "object": "LayoutTableCol COLGROUP id='colgroup'",
           "rect": [8, 8, 166, 102],
           "reason": "style change"
@@ -65,11 +70,6 @@
           "object": "LayoutTable TABLE",
           "rect": [169, 8, 5, 102],
           "reason": "incremental"
-        },
-        {
-          "object": "LayoutTableSection TBODY",
-          "rect": [169, 9, 4, 100],
-          "reason": "incremental"
         }
       ]
     }
@@ -109,7 +109,7 @@
     },
     {
       "object": "LayoutTableSection TBODY",
-      "reason": "incremental"
+      "reason": "bounds change"
     },
     {
       "object": "LayoutTableCell TD",
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/table/cached-change-row-border-color-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/table/cached-change-row-border-color-expected.txt
index a9bfbd6..3454bb7 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/table/cached-change-row-border-color-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/table/cached-change-row-border-color-expected.txt
@@ -1,26 +1,32 @@
 {
-  "bounds": [800, 600],
-  "children": [
+  "layers": [
     {
+      "name": "LayoutView #document",
       "bounds": [800, 600],
       "contentsOpaque": true,
       "drawsContent": true,
       "paintInvalidations": [
         {
           "object": "LayoutTableRow TR id='row'",
-          "rect": [10, 10, 56, 50],
+          "rect": [8, 8, 60, 54],
           "reason": "style change"
-        },
-        {
-          "object": "LayoutTableCell TD",
-          "reason": "full"
-        },
-        {
-          "object": "LayoutTableCell TD",
-          "reason": "full"
         }
       ]
     }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutTableCell TD",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutTableCell TD",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutTableRow TR id='row'",
+      "reason": "style change"
+    }
   ]
 }
 
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/table/cached-change-row-border-width-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/table/cached-change-row-border-width-expected.txt
index 4013197..9dafb32 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/table/cached-change-row-border-width-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/table/cached-change-row-border-width-expected.txt
@@ -7,9 +7,9 @@
       "drawsContent": true,
       "paintInvalidations": [
         {
-          "object": "LayoutTableCell TD",
+          "object": "LayoutTableRow TR id='row'",
           "rect": [8, 8, 60, 54],
-          "reason": "forced by layout"
+          "reason": "style change"
         },
         {
           "object": "LayoutTableCell TD",
@@ -22,16 +22,6 @@
           "reason": "incremental"
         },
         {
-          "object": "LayoutTableRow TR id='row'",
-          "rect": [10, 10, 56, 50],
-          "reason": "style change"
-        },
-        {
-          "object": "LayoutTableRow TR id='row'",
-          "rect": [9, 9, 54, 50],
-          "reason": "style change"
-        },
-        {
           "object": "LayoutTable TABLE",
           "rect": [62, 8, 6, 103],
           "reason": "incremental"
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/table/cached-change-tbody-border-color-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/table/cached-change-tbody-border-color-expected.txt
index 2c2fe355..a133750 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/table/cached-change-tbody-border-color-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/table/cached-change-tbody-border-color-expected.txt
@@ -1,42 +1,48 @@
 {
-  "bounds": [800, 600],
-  "children": [
+  "layers": [
     {
+      "name": "LayoutView #document",
       "bounds": [800, 600],
       "contentsOpaque": true,
       "drawsContent": true,
       "paintInvalidations": [
         {
           "object": "LayoutTableSection TBODY id='tbody'",
-          "rect": [10, 10, 110, 100],
+          "rect": [8, 8, 114, 104],
           "reason": "style change"
-        },
-        {
-          "object": "LayoutTableCell TD",
-          "reason": "full"
-        },
-        {
-          "object": "LayoutTableCell TD",
-          "reason": "full"
-        },
-        {
-          "object": "LayoutTableCell TD",
-          "reason": "full"
-        },
-        {
-          "object": "LayoutTableCell TD",
-          "reason": "full"
-        },
-        {
-          "object": "LayoutTableCell TD",
-          "reason": "full"
-        },
-        {
-          "object": "LayoutTableCell TD",
-          "reason": "full"
         }
       ]
     }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutTableCell TD",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutTableCell TD",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutTableCell TD",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutTableCell TD",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutTableCell TD",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutTableCell TD",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutTableSection TBODY id='tbody'",
+      "reason": "style change"
+    }
   ]
 }
 
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/table/cached-change-tbody-border-width-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/table/cached-change-tbody-border-width-expected.txt
index 2b0dc2a..8367932 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/table/cached-change-tbody-border-width-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/table/cached-change-tbody-border-width-expected.txt
@@ -7,21 +7,16 @@
       "drawsContent": true,
       "paintInvalidations": [
         {
+          "object": "LayoutTableSection TBODY id='tbody'",
+          "rect": [8, 8, 114, 104],
+          "reason": "style change"
+        },
+        {
           "object": "LayoutTable TABLE",
           "rect": [8, 159, 114, 2],
           "reason": "incremental"
         },
         {
-          "object": "LayoutTableSection TBODY id='tbody'",
-          "rect": [10, 10, 110, 100],
-          "reason": "style change"
-        },
-        {
-          "object": "LayoutTableSection TBODY id='tbody'",
-          "rect": [9, 9, 107, 100],
-          "reason": "style change"
-        },
-        {
           "object": "LayoutTableCell TD",
           "rect": [64, 8, 58, 53],
           "reason": "bounds change"
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/composited-table-row-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/composited-table-row-expected.txt
index af4d847..93d226b 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/composited-table-row-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/composited-table-row-expected.txt
@@ -9,7 +9,8 @@
     {
       "name": "LayoutTableRow TR",
       "position": [8, 8],
-      "bounds": [73, 23],
+      "transformOrigin": [36.5, 11.5],
+      "bounds": [74, 24],
       "drawsContent": true,
       "backgroundColor": "#FF0000",
       "paintInvalidations": [
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/composited-table-row-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/composited-table-row-expected.txt
index af4d847..93d226b 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/composited-table-row-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/composited-table-row-expected.txt
@@ -9,7 +9,8 @@
     {
       "name": "LayoutTableRow TR",
       "position": [8, 8],
-      "bounds": [73, 23],
+      "transformOrigin": [36.5, 11.5],
+      "bounds": [74, 24],
       "drawsContent": true,
       "backgroundColor": "#FF0000",
       "paintInvalidations": [
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/table-collapsed-border-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/table-collapsed-border-expected.txt
index e4c78fb..4a7af60 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/table-collapsed-border-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/table-collapsed-border-expected.txt
@@ -13,7 +13,7 @@
         },
         {
           "object": "LayoutTableSection TBODY",
-          "rect": [12, 198, 100, 74],
+          "rect": [8, 194, 108, 82],
           "reason": "forced by layout"
         },
         {
@@ -22,6 +22,11 @@
           "reason": "full"
         },
         {
+          "object": "LayoutTableSection TBODY",
+          "rect": [8, 102, 99, 82],
+          "reason": "forced by layout"
+        },
+        {
           "object": "LayoutTable TABLE id='t'",
           "rect": [8, 10, 95, 82],
           "reason": "style change"
@@ -32,11 +37,6 @@
           "reason": "layoutObject removal"
         },
         {
-          "object": "LayoutTableSection TBODY",
-          "rect": [12, 106, 91, 74],
-          "reason": "forced by layout"
-        },
-        {
           "object": "LayoutTableCell TD",
           "rect": [22, 338, 85, 30],
           "reason": "forced by layout"
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/composited-table-row-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/composited-table-row-expected.txt
similarity index 91%
rename from third_party/WebKit/LayoutTests/paint/invalidation/composited-table-row-expected.txt
rename to third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/composited-table-row-expected.txt
index 5a65d0f..cc01d5d1 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/composited-table-row-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/composited-table-row-expected.txt
@@ -9,7 +9,8 @@
     {
       "name": "LayoutTableRow TR",
       "position": [8, 8],
-      "bounds": [75, 21],
+      "transformOrigin": [37.5, 10.5],
+      "bounds": [76, 22],
       "drawsContent": true,
       "backgroundColor": "#FF0000",
       "paintInvalidations": [
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/composited-table-row-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/composited-table-row-expected.txt
similarity index 91%
copy from third_party/WebKit/LayoutTests/paint/invalidation/composited-table-row-expected.txt
copy to third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/composited-table-row-expected.txt
index 5a65d0f..cc01d5d1 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/composited-table-row-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/composited-table-row-expected.txt
@@ -9,7 +9,8 @@
     {
       "name": "LayoutTableRow TR",
       "position": [8, 8],
-      "bounds": [75, 21],
+      "transformOrigin": [37.5, 10.5],
+      "bounds": [76, 22],
       "drawsContent": true,
       "backgroundColor": "#FF0000",
       "paintInvalidations": [
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/table-collapsed-border-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/table-collapsed-border-expected.txt
index d64d6549..7f21b45 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/table-collapsed-border-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/table-collapsed-border-expected.txt
@@ -13,7 +13,7 @@
         },
         {
           "object": "LayoutTableSection TBODY",
-          "rect": [12, 186, 102, 68],
+          "rect": [8, 182, 110, 76],
           "reason": "forced by layout"
         },
         {
@@ -22,6 +22,11 @@
           "reason": "full"
         },
         {
+          "object": "LayoutTableSection TBODY",
+          "rect": [8, 96, 101, 76],
+          "reason": "forced by layout"
+        },
+        {
           "object": "LayoutTable TABLE id='t'",
           "rect": [8, 10, 97, 76],
           "reason": "style change"
@@ -32,11 +37,6 @@
           "reason": "layoutObject removal"
         },
         {
-          "object": "LayoutTableSection TBODY",
-          "rect": [12, 100, 93, 68],
-          "reason": "forced by layout"
-        },
-        {
           "object": "LayoutTableCell TD",
           "rect": [22, 316, 87, 28],
           "reason": "forced by layout"
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/composited-table-row-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/composited-table-row-expected.txt
index 844c0f92..b517c3b 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/composited-table-row-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/composited-table-row-expected.txt
@@ -9,7 +9,8 @@
     {
       "name": "LayoutTableRow TR",
       "position": [8, 8],
-      "bounds": [69, 23],
+      "transformOrigin": [34.5, 11.5],
+      "bounds": [70, 24],
       "drawsContent": true,
       "backgroundColor": "#FF0000",
       "paintInvalidations": [
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/composited-table-row-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/composited-table-row-expected.txt
index 844c0f92..b517c3b 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/composited-table-row-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/composited-table-row-expected.txt
@@ -9,7 +9,8 @@
     {
       "name": "LayoutTableRow TR",
       "position": [8, 8],
-      "bounds": [69, 23],
+      "transformOrigin": [34.5, 11.5],
+      "bounds": [70, 24],
       "drawsContent": true,
       "backgroundColor": "#FF0000",
       "paintInvalidations": [
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/table-collapsed-border-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/table-collapsed-border-expected.txt
index 71fa8da..76a6ff45 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/table-collapsed-border-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/table-collapsed-border-expected.txt
@@ -12,13 +12,18 @@
           "reason": "full"
         },
         {
+          "object": "LayoutTableSection TBODY",
+          "rect": [8, 194, 103, 82],
+          "reason": "forced by layout"
+        },
+        {
           "object": "LayoutTable TABLE",
           "rect": [8, 102, 95, 82],
           "reason": "full"
         },
         {
           "object": "LayoutTableSection TBODY",
-          "rect": [12, 198, 95, 74],
+          "rect": [8, 102, 95, 82],
           "reason": "forced by layout"
         },
         {
@@ -32,11 +37,6 @@
           "reason": "layoutObject removal"
         },
         {
-          "object": "LayoutTableSection TBODY",
-          "rect": [12, 106, 87, 74],
-          "reason": "forced by layout"
-        },
-        {
           "object": "LayoutTableCell TD",
           "rect": [22, 338, 81, 30],
           "reason": "forced by layout"
diff --git a/third_party/WebKit/LayoutTests/virtual/disable-spinvalidation/paint/invalidation/table-outer-border-expected.txt b/third_party/WebKit/LayoutTests/virtual/disable-spinvalidation/paint/invalidation/table-outer-border-expected.txt
index b06d1cb..1b78350 100644
--- a/third_party/WebKit/LayoutTests/virtual/disable-spinvalidation/paint/invalidation/table-outer-border-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/disable-spinvalidation/paint/invalidation/table-outer-border-expected.txt
@@ -17,6 +17,16 @@
           "reason": "layoutObject insertion"
         },
         {
+          "object": "LayoutTableSection TBODY",
+          "rect": [8, 8, 132, 149],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutTableSection TBODY",
+          "rect": [8, 8, 132, 149],
+          "reason": "layoutObject removal"
+        },
+        {
           "object": "LayoutTableCell TD",
           "rect": [8, 75, 132, 82],
           "reason": "layoutObject insertion"
@@ -27,6 +37,16 @@
           "reason": "layoutObject removal"
         },
         {
+          "object": "LayoutTableRow TR",
+          "rect": [8, 75, 132, 82],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutTableRow TR",
+          "rect": [8, 75, 132, 82],
+          "reason": "layoutObject removal"
+        },
+        {
           "object": "LayoutTableCell TD",
           "rect": [8, 8, 132, 82],
           "reason": "layoutObject insertion"
@@ -37,33 +57,13 @@
           "reason": "layoutObject removal"
         },
         {
-          "object": "LayoutTableSection TBODY",
-          "rect": [15, 15, 117, 134],
-          "reason": "layoutObject insertion"
-        },
-        {
-          "object": "LayoutTableSection TBODY",
-          "rect": [15, 15, 117, 134],
-          "reason": "layoutObject removal"
-        },
-        {
           "object": "LayoutTableRow TR",
-          "rect": [15, 82, 117, 67],
+          "rect": [8, 8, 132, 82],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutTableRow TR",
-          "rect": [15, 82, 117, 67],
-          "reason": "layoutObject removal"
-        },
-        {
-          "object": "LayoutTableRow TR",
-          "rect": [15, 15, 117, 67],
-          "reason": "layoutObject insertion"
-        },
-        {
-          "object": "LayoutTableRow TR",
-          "rect": [15, 15, 117, 67],
+          "rect": [8, 8, 132, 82],
           "reason": "layoutObject removal"
         }
       ]
diff --git a/third_party/WebKit/LayoutTests/virtual/disable-spinvalidation/paint/invalidation/table/border-collapse-change-collapse-to-separate-expected.txt b/third_party/WebKit/LayoutTests/virtual/disable-spinvalidation/paint/invalidation/table/border-collapse-change-collapse-to-separate-expected.txt
index ba69534..8b232b70 100644
--- a/third_party/WebKit/LayoutTests/virtual/disable-spinvalidation/paint/invalidation/table/border-collapse-change-collapse-to-separate-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/disable-spinvalidation/paint/invalidation/table/border-collapse-change-collapse-to-separate-expected.txt
@@ -23,7 +23,7 @@
         },
         {
           "object": "LayoutTableRow TR",
-          "rect": [9, 9, 209, 105],
+          "rect": [8, 8, 212, 108],
           "reason": "style change"
         },
         {
diff --git a/third_party/WebKit/LayoutTests/virtual/disable-spinvalidation/paint/invalidation/table/border-collapse-change-separate-to-collapse-expected.txt b/third_party/WebKit/LayoutTests/virtual/disable-spinvalidation/paint/invalidation/table/border-collapse-change-separate-to-collapse-expected.txt
index 18cc801..357e9b4 100644
--- a/third_party/WebKit/LayoutTests/virtual/disable-spinvalidation/paint/invalidation/table/border-collapse-change-separate-to-collapse-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/disable-spinvalidation/paint/invalidation/table/border-collapse-change-separate-to-collapse-expected.txt
@@ -23,7 +23,7 @@
         },
         {
           "object": "LayoutTableRow TR",
-          "rect": [9, 9, 209, 105],
+          "rect": [8, 8, 212, 108],
           "reason": "style change"
         },
         {
diff --git a/third_party/WebKit/LayoutTests/virtual/disable-spinvalidation/paint/invalidation/table/cached-change-row-border-width-expected.txt b/third_party/WebKit/LayoutTests/virtual/disable-spinvalidation/paint/invalidation/table/cached-change-row-border-width-expected.txt
new file mode 100644
index 0000000..d41b0e0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/disable-spinvalidation/paint/invalidation/table/cached-change-row-border-width-expected.txt
@@ -0,0 +1,68 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "paintInvalidations": [
+        {
+          "object": "LayoutTableCell TD",
+          "rect": [8, 8, 60, 54],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutTableRow TR id='row'",
+          "rect": [8, 8, 60, 54],
+          "reason": "style change"
+        },
+        {
+          "object": "LayoutTableCell TD",
+          "rect": [8, 58, 60, 53],
+          "reason": "location change"
+        },
+        {
+          "object": "LayoutTable TABLE",
+          "rect": [8, 109, 60, 2],
+          "reason": "incremental"
+        },
+        {
+          "object": "LayoutTable TABLE",
+          "rect": [62, 8, 6, 103],
+          "reason": "incremental"
+        }
+      ]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutTableCell TD",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutTableCell TD",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutTable TABLE",
+      "reason": "incremental"
+    },
+    {
+      "object": "LayoutTableRow TR id='row'",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutTableCell TD",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "LayoutTableRow TR",
+      "reason": "location change"
+    },
+    {
+      "object": "LayoutTableCell TD",
+      "reason": "location change"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/Source/build/scripts/make_computed_style_base.py b/third_party/WebKit/Source/build/scripts/make_computed_style_base.py
index 6a09efd..a181350f 100755
--- a/third_party/WebKit/Source/build/scripts/make_computed_style_base.py
+++ b/third_party/WebKit/Source/build/scripts/make_computed_style_base.py
@@ -349,8 +349,6 @@
         for property_ in css_properties:
             # All CSS properties that are generated do not have custom comparison and copy logic.
             property_['has_custom_compare_and_copy'] = False
-            # CSS properties are not allowed to explicitly specify their field_size.
-            property_['field_size'] = None
 
         # Read extra fields using the parameter specification from the CSS properties file.
         extra_fields = json5_generator.Json5File.load_from_files(
diff --git a/third_party/WebKit/Source/build/scripts/templates/ComputedStyleBase.cpp.tmpl b/third_party/WebKit/Source/build/scripts/templates/ComputedStyleBase.cpp.tmpl
index 22a1a3e..3bcd438 100644
--- a/third_party/WebKit/Source/build/scripts/templates/ComputedStyleBase.cpp.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/ComputedStyleBase.cpp.tmpl
@@ -12,7 +12,7 @@
   void* dataRefs[{{computed_style.subgroups|length}}];
   {% endif %}
   {% for field in computed_style.fields|rejectattr("is_bit_field") %}
-  {{field.type_name}} {{field.name}}};
+  {{field.type_name}} {{field.name}};
   {% endfor %}
   unsigned m_bit_fields[{{computed_style.num_32_bit_words_for_bit_fields}}];
 };
diff --git a/third_party/WebKit/Source/build/scripts/templates/ComputedStyleBase.h.tmpl b/third_party/WebKit/Source/build/scripts/templates/ComputedStyleBase.h.tmpl
index 5956fd1..2757340 100644
--- a/third_party/WebKit/Source/build/scripts/templates/ComputedStyleBase.h.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/ComputedStyleBase.h.tmpl
@@ -138,6 +138,12 @@
   DataRef<{{subgroup.type_name}}> {{subgroup.member_name}};
   {% endfor %}
 
+  static unsigned WidthToFixedPoint(float width) {
+    DCHECK_GE(width, 0);
+    return static_cast<unsigned>(std::min<float>(width, kMaxForBorderWidth) *
+                                 kBorderWidthDenominator);
+  }
+
  private:
   {% for field in computed_style.fields %}
   {{declare_storage(field)}}
diff --git a/third_party/WebKit/Source/core/css/CSSProperties.json5 b/third_party/WebKit/Source/core/css/CSSProperties.json5
index e16dbde3..7f007488 100644
--- a/third_party/WebKit/Source/core/css/CSSProperties.json5
+++ b/third_party/WebKit/Source/core/css/CSSProperties.json5
@@ -69,6 +69,14 @@
       value_type: "str"
     },
 
+    // - field_size
+    // Number of bits needed to store this field. Only used for storage_only
+    // fields. If specified, the field will be stored as bit field. Otherwise
+    // it will be stored as a normal data member.
+    field_size: {
+      valid_type: "int",
+    },
+
     // - field_template
     // Affects how the interface to this field is generated.
     // TODO(sashab, meade): Remove this once TypedOM types are specified for
@@ -686,6 +694,11 @@
       interpolable: true,
       keywords: ["thin", "medium", "thick"],
       typedom_types: ["Length"],
+      field_template: "storage_only",
+      type_name: "unsigned",
+      field_size : 26,
+      default_value: "WidthToFixedPoint(3)",
+      field_group: "surround",
     },
     {
       name: "border-collapse",
@@ -747,6 +760,11 @@
       interpolable: true,
       keywords: ["thin", "medium", "thick"],
       typedom_types: ["Length"],
+      field_template: "storage_only",
+      type_name: "unsigned",
+      field_size : 26,
+      default_value: "WidthToFixedPoint(3)",
+      field_group: "surround",
     },
     {
       name: "border-right-color",
@@ -768,6 +786,11 @@
       interpolable: true,
       keywords: ["thin", "medium", "thick"],
       typedom_types: ["Length"],
+      field_template: "storage_only",
+      type_name: "unsigned",
+      field_size : 26,
+      default_value: "WidthToFixedPoint(3)",
+      field_group: "surround",
     },
     {
       name: "border-top-color",
@@ -812,6 +835,11 @@
       keywords: ["thin", "medium", "thick"],
       supports_percentage: true,
       typedom_types: ["Length"],
+      field_template: "storage_only",
+      type_name: "unsigned",
+      field_size : 26,
+      default_value: "WidthToFixedPoint(3)",
+      field_group: "surround",
     },
     {
       name: "bottom",
diff --git a/third_party/WebKit/Source/core/css/ComputedStyleExtraFields.json5 b/third_party/WebKit/Source/core/css/ComputedStyleExtraFields.json5
index 5e7fae35..827674e 100644
--- a/third_party/WebKit/Source/core/css/ComputedStyleExtraFields.json5
+++ b/third_party/WebKit/Source/core/css/ComputedStyleExtraFields.json5
@@ -3,14 +3,6 @@
 // generate, but are not CSS properties.
 
   parameters: {
-    // - field_size
-    // Number of bits needed to store this field. Only used for storage_only
-    // fields. If specified, the field will be stored as bit field. Otherwise
-    // it will be stored as a normal data member.
-    field_size: {
-      valid_type: "int",
-    },
-
     // If the field has_custom_compare_and_copy, then it does not appear in
     // ComputedStyle::operator== and ComputedStyle::CopyNonInheritedFromCached.
     has_custom_compare_and_copy: {
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp b/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp
index b772c04..64a30c8 100644
--- a/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp
+++ b/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp
@@ -1957,6 +1957,14 @@
   const CachedUAStyle* cached_ua_style = state.GetCachedUAStyle();
   return cached_ua_style &&
          (cached_ua_style->border != state.Style()->Border() ||
+          (cached_ua_style->border_left_width !=
+               state.Style()->BorderLeftWidth() ||
+           cached_ua_style->border_right_width !=
+               state.Style()->BorderRightWidth() ||
+           cached_ua_style->border_top_width !=
+               state.Style()->BorderTopWidth() ||
+           cached_ua_style->border_bottom_width !=
+               state.Style()->BorderBottomWidth()) ||
           !(cached_ua_style->top_left_ ==
                 state.Style()->BorderTopLeftRadius() &&
             cached_ua_style->top_right_ ==
diff --git a/third_party/WebKit/Source/core/editing/FrameSelection.cpp b/third_party/WebKit/Source/core/editing/FrameSelection.cpp
index 498a59b..c22bf0d 100644
--- a/third_party/WebKit/Source/core/editing/FrameSelection.cpp
+++ b/third_party/WebKit/Source/core/editing/FrameSelection.cpp
@@ -983,7 +983,7 @@
       break;
   }
 
-  Position start = ComputeVisibleSelectionInDOMTreeDeprecated().Start();
+  Position start = ComputeVisibleSelectionInDOMTree().Start();
   DCHECK(start.AnchorNode());
   if (start.AnchorNode() && start.AnchorNode()->GetLayoutObject()) {
     // FIXME: This code only handles scrolling the startContainer's layer, but
diff --git a/third_party/WebKit/Source/core/layout/LayoutBox.cpp b/third_party/WebKit/Source/core/layout/LayoutBox.cpp
index 7d03f24c..5ac9de0d 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBox.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBox.cpp
@@ -334,7 +334,7 @@
       // The overflow clip paint property depends on border sizes through
       // overflowClipRect(), and border radii, so we update properties on
       // border size or radii change.
-      if (!old_style->Border().SizeEquals(new_style.Border()) ||
+      if (!old_style->BorderSizeEquals(new_style) ||
           !old_style->RadiiEqual(new_style))
         SetNeedsPaintPropertyUpdate();
     }
diff --git a/third_party/WebKit/Source/core/layout/LayoutTable.cpp b/third_party/WebKit/Source/core/layout/LayoutTable.cpp
index e7dfbd5..78d34f8 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTable.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutTable.cpp
@@ -539,7 +539,7 @@
        section = SectionBelow(section)) {
     section->LayoutIfNeeded();
     section->LayoutRows();
-    section->ComputeOverflowFromCells();
+    section->ComputeOverflowFromDescendants();
     section->UpdateAfterLayout();
     section->AddVisualEffectOverflow();
   }
@@ -1697,7 +1697,7 @@
   return new_table;
 }
 
-const BorderValue& LayoutTable::TableStartBorderAdjoiningCell(
+BorderValue LayoutTable::TableStartBorderAdjoiningCell(
     const LayoutTableCell* cell) const {
 #if DCHECK_IS_ON()
   DCHECK(cell->IsFirstOrLastCellInRow());
@@ -1708,7 +1708,7 @@
   return Style()->BorderEnd();
 }
 
-const BorderValue& LayoutTable::TableEndBorderAdjoiningCell(
+BorderValue LayoutTable::TableEndBorderAdjoiningCell(
     const LayoutTableCell* cell) const {
 #if DCHECK_IS_ON()
   DCHECK(cell->IsFirstOrLastCellInRow());
diff --git a/third_party/WebKit/Source/core/layout/LayoutTable.h b/third_party/WebKit/Source/core/layout/LayoutTable.h
index fe3b67a..335eea3 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTable.h
+++ b/third_party/WebKit/Source/core/layout/LayoutTable.h
@@ -431,9 +431,8 @@
     return CreateAnonymousWithParent(parent);
   }
 
-  const BorderValue& TableStartBorderAdjoiningCell(
-      const LayoutTableCell*) const;
-  const BorderValue& TableEndBorderAdjoiningCell(const LayoutTableCell*) const;
+  BorderValue TableStartBorderAdjoiningCell(const LayoutTableCell*) const;
+  BorderValue TableEndBorderAdjoiningCell(const LayoutTableCell*) const;
 
   void AddCaption(const LayoutTableCaption*);
   void RemoveCaption(const LayoutTableCaption*);
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableBoxComponent.cpp b/third_party/WebKit/Source/core/layout/LayoutTableBoxComponent.cpp
index 923dc90..b8c5b92 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTableBoxComponent.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutTableBoxComponent.cpp
@@ -19,6 +19,7 @@
     return;
   if (old_style.Border() != table_part.StyleRef().Border() ||
       !old_style.RadiiEqual(table_part.StyleRef()) ||
+      !old_style.BorderSizeEquals(table_part.StyleRef()) ||
       (diff.TextDecorationOrColorChanged() &&
        table_part.StyleRef().HasBorderColorReferencingCurrentColor()))
     table.InvalidateCollapsedBorders();
@@ -37,7 +38,7 @@
   // tablePart.needsLayout().
   return diff.NeedsFullLayout() && table_part.NeedsLayout() &&
          table.ShouldCollapseBorders() &&
-         !old_style.Border().SizeEquals(table_part.Style()->Border());
+         !old_style.BorderSizeEquals(*table_part.Style());
 }
 
 void LayoutTableBoxComponent::MutableForPainting::UpdatePaintResult(
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableCell.cpp b/third_party/WebKit/Source/core/layout/LayoutTableCell.cpp
index d6b7298..db958548 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTableCell.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutTableCell.cpp
@@ -409,21 +409,26 @@
   return offset;
 }
 
-LayoutRect LayoutTableCell::LocalVisualRect() const {
-  // If the table grid is dirty, we cannot get reliable information about
-  // adjoining cells, so we ignore outside borders. This should not be a problem
-  // because it means that the table is going to recalculate the grid, relayout
-  // and issue a paint invalidation of its current rect, which includes any
-  // outside borders of this cell.
-  if (!Table()->ShouldCollapseBorders() || Table()->NeedsSectionRecalc())
-    return LayoutBlockFlow::LocalVisualRect();
+void LayoutTableCell::ComputeOverflow(LayoutUnit old_client_after_edge,
+                                      bool recompute_floats) {
+  LayoutBlockFlow::ComputeOverflow(old_client_after_edge, recompute_floats);
 
+  UpdateCollapsedBorderValues();
+  if (!collapsed_border_values_)
+    return;
+
+  // Calculate local visual rect of collapsed borders.
+  // Our border rect already includes the inner halves of the collapsed borders,
+  // so here we get the outer halves.
   bool rtl = !StyleForCellFlow().IsLeftToRightDirection();
-  LayoutUnit outline_outset(Style()->OutlineOutsetExtent());
-  LayoutUnit left(std::max(CollapsedBorderHalfLeft(true), outline_outset));
-  LayoutUnit right(std::max(CollapsedBorderHalfRight(true), outline_outset));
-  LayoutUnit top(std::max(CollapsedBorderHalfTop(true), outline_outset));
-  LayoutUnit bottom(std::max(CollapsedBorderHalfBottom(true), outline_outset));
+  LayoutUnit left = CollapsedBorderHalfLeft(true);
+  LayoutUnit right = CollapsedBorderHalfRight(true);
+  LayoutUnit top = CollapsedBorderHalfTop(true);
+  LayoutUnit bottom = CollapsedBorderHalfBottom(true);
+
+  // This cell's borders may be lengthened to match the widths of orthogonal
+  // borders of adjacent cells. Expand visual overflow to cover the lengthened
+  // parts.
   if ((left && !rtl) || (right && rtl)) {
     if (LayoutTableCell* before = Table()->CellBefore(this)) {
       top = std::max(top, before->CollapsedBorderHalfTop(true));
@@ -449,15 +454,16 @@
     }
   }
 
-  LayoutRect self_visual_overflow_rect = this->SelfVisualOverflowRect();
-  LayoutPoint location(
-      std::max(LayoutUnit(left), -self_visual_overflow_rect.X()),
-      std::max(LayoutUnit(top), -self_visual_overflow_rect.Y()));
-  return LayoutRect(-location.X(), -location.Y(),
-                    location.X() + std::max(Size().Width() + right,
-                                            self_visual_overflow_rect.MaxX()),
-                    location.Y() + std::max(Size().Height() + bottom,
-                                            self_visual_overflow_rect.MaxY()));
+  LayoutRect rect = BorderBoxRect();
+  rect.ExpandEdges(top, right, bottom, left);
+  collapsed_border_values_->SetLocalVisualRect(rect);
+}
+
+LayoutRect LayoutTableCell::LocalVisualRect() const {
+  LayoutRect rect = SelfVisualOverflowRect();
+  if (collapsed_border_values_)
+    rect.Unite(collapsed_border_values_->LocalVisualRect());
+  return rect;
 }
 
 int LayoutTableCell::CellBaselinePosition() const {
@@ -1262,12 +1268,6 @@
 }
 
 void LayoutTableCell::UpdateCollapsedBorderValues() const {
-  Table()->InvalidateCollapsedBordersForAllCellsIfNeeded();
-  if (collapsed_border_values_valid_)
-    return;
-
-  collapsed_border_values_valid_ = true;
-
   if (!Table()->ShouldCollapseBorders()) {
     if (collapsed_border_values_) {
       collapsed_borders_visually_changed_ = true;
@@ -1276,6 +1276,12 @@
     return;
   }
 
+  Table()->InvalidateCollapsedBordersForAllCellsIfNeeded();
+  if (collapsed_border_values_valid_)
+    return;
+
+  collapsed_border_values_valid_ = true;
+
   CollapsedBorderValues new_values(
       *this, ComputeCollapsedStartBorder(), ComputeCollapsedEndBorder(),
       ComputeCollapsedBeforeBorder(), ComputeCollapsedAfterBorder());
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableCell.h b/third_party/WebKit/Source/core/layout/LayoutTableCell.h
index f420854..2733782 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTableCell.h
+++ b/third_party/WebKit/Source/core/layout/LayoutTableCell.h
@@ -251,7 +251,7 @@
   // direction on all table parts and writing-mode on cells.
   const ComputedStyle& StyleForCellFlow() const { return Row()->StyleRef(); }
 
-  const BorderValue& BorderAdjoiningTableStart() const {
+  BorderValue BorderAdjoiningTableStart() const {
 #if DCHECK_IS_ON()
     DCHECK(IsFirstOrLastCellInRow());
 #endif
@@ -261,7 +261,7 @@
     return Style()->BorderEnd();
   }
 
-  const BorderValue& BorderAdjoiningTableEnd() const {
+  BorderValue BorderAdjoiningTableEnd() const {
 #if DCHECK_IS_ON()
     DCHECK(IsFirstOrLastCellInRow());
 #endif
@@ -271,14 +271,14 @@
     return Style()->BorderStart();
   }
 
-  const BorderValue& BorderAdjoiningCellBefore(const LayoutTableCell* cell) {
+  BorderValue BorderAdjoiningCellBefore(const LayoutTableCell* cell) {
     DCHECK_EQ(Table()->CellAfter(cell), this);
     // FIXME: https://webkit.org/b/79272 - Add support for mixed directionality
     // at the cell level.
     return Style()->BorderStart();
   }
 
-  const BorderValue& BorderAdjoiningCellAfter(const LayoutTableCell* cell) {
+  BorderValue BorderAdjoiningCellAfter(const LayoutTableCell* cell) {
     DCHECK_EQ(Table()->CellBefore(cell), this);
     // FIXME: https://webkit.org/b/79272 - Add support for mixed directionality
     // at the cell level.
@@ -317,17 +317,21 @@
     String DebugName() const;
     LayoutRect VisualRect() const;
 
+    LayoutRect LocalVisualRect() const { return local_visual_rect_; }
+    void SetLocalVisualRect(const LayoutRect& r) { local_visual_rect_ = r; }
+
    private:
     const LayoutTableCell& layout_table_cell_;
     CollapsedBorderValue start_border_;
     CollapsedBorderValue end_border_;
     CollapsedBorderValue before_border_;
     CollapsedBorderValue after_border_;
+    LayoutRect local_visual_rect_;
   };
 
   bool UsesCompositedCellDisplayItemClients() const;
   const CollapsedBorderValues* GetCollapsedBorderValues() const {
-    DCHECK(collapsed_border_values_valid_);
+    UpdateCollapsedBorderValues();
     return collapsed_border_values_.get();
   }
   void InvalidateCollapsedBorderValues() {
@@ -371,6 +375,9 @@
   void PaintMask(const PaintInfo&, const LayoutPoint&) const override;
 
   LayoutSize OffsetFromContainer(const LayoutObject*) const override;
+
+  void ComputeOverflow(LayoutUnit old_client_after_edge,
+                       bool recompute_floats = false) override;
   LayoutRect LocalVisualRect() const override;
 
   LayoutUnit CollapsedBorderHalfLeft(bool outer) const;
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableCellTest.cpp b/third_party/WebKit/Source/core/layout/LayoutTableCellTest.cpp
index 99b80a6cf..62f879c 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTableCellTest.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutTableCellTest.cpp
@@ -79,6 +79,9 @@
   bool HasEndBorderAdjoiningTable(const LayoutTableCell* cell) {
     return cell->HasEndBorderAdjoiningTable();
   }
+  LayoutRect LocalVisualRect(const LayoutTableCell* cell) {
+    return cell->LocalVisualRect();
+  }
 
   LayoutTableCell* GetCellByElementId(const char* id) {
     return ToLayoutTableCell(GetLayoutObjectByElementId(id));
@@ -251,4 +254,47 @@
   EXPECT_FALSE(HasEndBorderAdjoiningTable(cell32));
 }
 
+TEST_F(LayoutTableCellTest, LocalVisualRectWithCollapsedBorders) {
+  SetBodyInnerHTML(
+      "<style>"
+      "  table { border-collapse: collapse }"
+      "  td { border: 0px solid blue; padding: 0 }"
+      "  div { width: 100px; height: 100px }"
+      "</style>"
+      "<table>"
+      "  <tr>"
+      "    <td id='cell1' style='border-bottom-width: 10px;"
+      "        outline: 3px solid blue'><div></div></td>"
+      "    <td id='cell2' style='border-width: 3px 15px'><div></div></td>"
+      "  </tr>"
+      "</table>");
+
+  auto* cell1 = GetCellByElementId("cell1");
+  auto* cell2 = GetCellByElementId("cell2");
+  EXPECT_TRUE(cell1->Table()->ShouldCollapseBorders());
+
+  EXPECT_EQ(0, cell1->BorderLeft());
+  EXPECT_EQ(7, cell1->BorderRight());
+  EXPECT_EQ(0, cell1->BorderTop());
+  EXPECT_EQ(5, cell1->BorderBottom());
+  EXPECT_EQ(8, cell2->BorderLeft());
+  EXPECT_EQ(7, cell2->BorderRight());
+  EXPECT_EQ(2, cell2->BorderTop());
+  EXPECT_EQ(1, cell2->BorderBottom());
+
+  LayoutRect expected_visual_rect1 = cell1->BorderBoxRect();
+  // Expand top, left for outline, right and bottom for collapsed border.
+  expected_visual_rect1.ExpandEdges(LayoutUnit(3), LayoutUnit(8), LayoutUnit(5),
+                                    LayoutUnit(3));
+  EXPECT_EQ(expected_visual_rect1, LocalVisualRect(cell1));
+
+  LayoutRect expected_visual_rect2 = cell2->BorderBoxRect();
+  // Expand outer half border width at each side. For the bottom side, expand
+  // more because the left border is lengthened to cover the joint with the
+  // bottom border of the cell to the left.
+  expected_visual_rect2.ExpandEdges(LayoutUnit(1), LayoutUnit(8), LayoutUnit(5),
+                                    LayoutUnit(7));
+  EXPECT_EQ(expected_visual_rect2, LocalVisualRect(cell2));
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableCol.cpp b/third_party/WebKit/Source/core/layout/LayoutTableCol.cpp
index 36ce08cb..c951224 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTableCol.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutTableCol.cpp
@@ -167,17 +167,17 @@
   return ToLayoutTableCol(next);
 }
 
-const BorderValue& LayoutTableCol::BorderAdjoiningCellStartBorder(
+BorderValue LayoutTableCol::BorderAdjoiningCellStartBorder(
     const LayoutTableCell*) const {
   return Style()->BorderStart();
 }
 
-const BorderValue& LayoutTableCol::BorderAdjoiningCellEndBorder(
+BorderValue LayoutTableCol::BorderAdjoiningCellEndBorder(
     const LayoutTableCell*) const {
   return Style()->BorderEnd();
 }
 
-const BorderValue& LayoutTableCol::BorderAdjoiningCellBefore(
+BorderValue LayoutTableCol::BorderAdjoiningCellBefore(
     const LayoutTableCell* cell) const {
   DCHECK_EQ(Table()
                 ->ColElementAtAbsoluteColumn(cell->AbsoluteColumnIndex() +
@@ -187,7 +187,7 @@
   return Style()->BorderStart();
 }
 
-const BorderValue& LayoutTableCol::BorderAdjoiningCellAfter(
+BorderValue LayoutTableCol::BorderAdjoiningCellAfter(
     const LayoutTableCell* cell) const {
   DCHECK_EQ(Table()
                 ->ColElementAtAbsoluteColumn(cell->AbsoluteColumnIndex() - 1)
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableCol.h b/third_party/WebKit/Source/core/layout/LayoutTableCol.h
index c9c54ed..f564635 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTableCol.h
+++ b/third_party/WebKit/Source/core/layout/LayoutTableCol.h
@@ -80,11 +80,10 @@
   // Returns the next column or column-group.
   LayoutTableCol* NextColumn() const;
 
-  const BorderValue& BorderAdjoiningCellStartBorder(
-      const LayoutTableCell*) const;
-  const BorderValue& BorderAdjoiningCellEndBorder(const LayoutTableCell*) const;
-  const BorderValue& BorderAdjoiningCellBefore(const LayoutTableCell*) const;
-  const BorderValue& BorderAdjoiningCellAfter(const LayoutTableCell*) const;
+  BorderValue BorderAdjoiningCellStartBorder(const LayoutTableCell*) const;
+  BorderValue BorderAdjoiningCellEndBorder(const LayoutTableCell*) const;
+  BorderValue BorderAdjoiningCellBefore(const LayoutTableCell*) const;
+  BorderValue BorderAdjoiningCellAfter(const LayoutTableCell*) const;
 
   const char* GetName() const override { return "LayoutTableCol"; }
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableRow.cpp b/third_party/WebKit/Source/core/layout/LayoutTableRow.cpp
index 440f7a2..9f89aaa 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTableRow.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutTableRow.cpp
@@ -98,7 +98,7 @@
   }
 }
 
-const BorderValue& LayoutTableRow::BorderAdjoiningStartCell(
+BorderValue LayoutTableRow::BorderAdjoiningStartCell(
     const LayoutTableCell* cell) const {
 #if DCHECK_IS_ON()
   DCHECK(cell->IsFirstOrLastCellInRow());
@@ -108,7 +108,7 @@
   return Style()->BorderStart();
 }
 
-const BorderValue& LayoutTableRow::BorderAdjoiningEndCell(
+BorderValue LayoutTableRow::BorderAdjoiningEndCell(
     const LayoutTableCell* cell) const {
 #if DCHECK_IS_ON()
   DCHECK(cell->IsFirstOrLastCellInRow());
@@ -302,16 +302,26 @@
     AddSelfVisualOverflow(cell_background_rect);
   }
 
-  // Should propagate cell's overflow to row if the cell has row span or has
-  // overflow.
-  if (cell->RowSpan() == 1 && !cell->HasOverflowModel())
-    return;
-
   // The cell and the row share the section's coordinate system. However
   // the visual overflow should be determined in the coordinate system of
   // the row, that's why we shift the rects by cell_row_offset below.
   LayoutSize cell_row_offset = cell->Location() - Location();
 
+  // Let the row's self visual overflow cover the cell's whole collapsed
+  // borders. This ensures correct raster invalidation on row border style
+  // change.
+  if (const auto* collapsed_borders = cell->GetCollapsedBorderValues()) {
+    LayoutRect collapsed_border_rect =
+        cell->RectForOverflowPropagation(collapsed_borders->LocalVisualRect());
+    collapsed_border_rect.Move(cell_row_offset);
+    AddSelfVisualOverflow(collapsed_border_rect);
+  }
+
+  // Should propagate cell's overflow to row if the cell has row span or has
+  // overflow.
+  if (cell->RowSpan() == 1 && !cell->HasOverflowModel())
+    return;
+
   LayoutRect cell_visual_overflow_rect =
       cell->VisualOverflowRectForPropagation();
   cell_visual_overflow_rect.Move(cell_row_offset);
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableRow.h b/third_party/WebKit/Source/core/layout/LayoutTableRow.h
index 38c748d3..9f81f4c 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTableRow.h
+++ b/third_party/WebKit/Source/core/layout/LayoutTableRow.h
@@ -101,22 +101,22 @@
     return row_index_;
   }
 
-  const BorderValue& BorderAdjoiningTableStart() const {
+  BorderValue BorderAdjoiningTableStart() const {
     if (Section()->HasSameDirectionAs(Table()))
       return Style()->BorderStart();
 
     return Style()->BorderEnd();
   }
 
-  const BorderValue& BorderAdjoiningTableEnd() const {
+  BorderValue BorderAdjoiningTableEnd() const {
     if (Section()->HasSameDirectionAs(Table()))
       return Style()->BorderEnd();
 
     return Style()->BorderStart();
   }
 
-  const BorderValue& BorderAdjoiningStartCell(const LayoutTableCell*) const;
-  const BorderValue& BorderAdjoiningEndCell(const LayoutTableCell*) const;
+  BorderValue BorderAdjoiningStartCell(const LayoutTableCell*) const;
+  BorderValue BorderAdjoiningEndCell(const LayoutTableCell*) const;
 
   bool NodeAtPoint(HitTestResult&,
                    const HitTestLocation& location_in_container,
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableRowTest.cpp b/third_party/WebKit/Source/core/layout/LayoutTableRowTest.cpp
index f5bf70d..211e8178 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTableRowTest.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutTableRowTest.cpp
@@ -153,6 +153,37 @@
   EXPECT_EQ(LayoutRect(0, 0, 450, 100), row3->SelfVisualOverflowRect());
 }
 
+TEST_F(LayoutTableRowTest, VisualOverflowWithCollapsedBorders) {
+  SetBodyInnerHTML(
+      "<style>"
+      "  table { border-collapse: collapse }"
+      "  td { border: 0px solid blue; padding: 0 }"
+      "  div { width: 100px; height: 100px }"
+      "</style>"
+      "<table>"
+      "  <tr id='row'>"
+      "    <td style='border-bottom-width: 10px;"
+      "        outline: 3px solid blue'><div></div></td>"
+      "    <td style='border-width: 3px 15px'><div></div></td>"
+      "  </tr>"
+      "</table>");
+
+  auto* row = GetRowByElementId("row");
+
+  // The row's self visual overflow covers the collapsed borders.
+  LayoutRect expected_self_visual_overflow = row->BorderBoxRect();
+  expected_self_visual_overflow.ExpandEdges(LayoutUnit(1), LayoutUnit(8),
+                                            LayoutUnit(5), LayoutUnit(0));
+  EXPECT_EQ(expected_self_visual_overflow, row->SelfVisualOverflowRect());
+
+  // The row's visual overflow covers self visual overflow and visual overflows
+  // of all cells.
+  LayoutRect expected_visual_overflow = row->BorderBoxRect();
+  expected_visual_overflow.ExpandEdges(LayoutUnit(3), LayoutUnit(8),
+                                       LayoutUnit(5), LayoutUnit(3));
+  EXPECT_EQ(expected_visual_overflow, row->VisualOverflowRect());
+}
+
 TEST_F(LayoutTableRowTest, LayoutOverflow) {
   SetBodyInnerHTML(
       "<table style='border-spacing: 0'>"
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableSection.cpp b/third_party/WebKit/Source/core/layout/LayoutTableSection.cpp
index 275532b..df573ab 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTableSection.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutTableSection.cpp
@@ -1238,7 +1238,7 @@
 
   SetLogicalHeight(LayoutUnit(row_pos_[total_rows]));
 
-  ComputeOverflowFromCells(total_rows, Table()->NumEffectiveColumns());
+  ComputeOverflowFromDescendants();
 }
 
 int LayoutTableSection::PaginationStrutForRow(LayoutTableRow* row,
@@ -1272,15 +1272,8 @@
   return pagination_strut.Ceil();
 }
 
-void LayoutTableSection::ComputeOverflowFromCells() {
-  unsigned total_rows = grid_.size();
-  unsigned n_eff_cols = Table()->NumEffectiveColumns();
-  ComputeOverflowFromCells(total_rows, n_eff_cols);
-}
-
-void LayoutTableSection::ComputeOverflowFromCells(unsigned total_rows,
-                                                  unsigned n_eff_cols) {
-  unsigned total_cells_count = n_eff_cols * total_rows;
+void LayoutTableSection::ComputeOverflowFromDescendants() {
+  unsigned total_cells_count = NumRows() * Table()->NumEffectiveColumns();
   unsigned max_allowed_overflowing_cells_count =
       total_cells_count <
               g_min_table_size_to_use_fast_paint_path_with_overflowing_cell
@@ -1294,29 +1287,43 @@
 #if DCHECK_IS_ON()
   bool has_overflowing_cell = false;
 #endif
-  // Now that our height has been determined, add in overflow from cells.
-  for (unsigned r = 0; r < total_rows; r++) {
-    unsigned n_cols = NumCols(r);
-    for (unsigned c = 0; c < n_cols; c++) {
-      const auto* cell = OriginatingCellAt(r, c);
-      if (!cell)
-        continue;
-      AddOverflowFromChild(*cell);
-#if DCHECK_IS_ON()
-      has_overflowing_cell |= cell->HasVisualOverflow();
-#endif
-      if (cell->HasVisualOverflow() &&
-          !force_slow_paint_path_with_overflowing_cell_) {
-        overflowing_cells_.insert(cell);
-        if (overflowing_cells_.size() > max_allowed_overflowing_cells_count) {
-          // We need to set m_forcesSlowPaintPath only if there is a least one
-          // overflowing cells as the hit testing code rely on this information.
-          force_slow_paint_path_with_overflowing_cell_ = true;
-          // The slow path does not make any use of the overflowing cells info,
-          // don't hold on to the memory.
-          overflowing_cells_.clear();
-        }
+
+  for (auto* row = FirstRow(); row; row = row->NextRow()) {
+    AddOverflowFromChild(*row);
+
+    for (auto* cell = row->FirstCell(); cell; cell = cell->NextCell()) {
+      // Let the section's self visual overflow cover the cell's whole collapsed
+      // borders. This ensures correct raster invalidation on section border
+      // style change.
+      // TODO(wangxianzhu): When implementing row as DisplayItemClient of
+      // collapsed borders, the following logic should be replaced by
+      // invalidation of rows on section border style change. crbug.com/663208.
+      if (const auto* collapsed_borders = cell->GetCollapsedBorderValues()) {
+        LayoutRect rect = cell->RectForOverflowPropagation(
+            collapsed_borders->LocalVisualRect());
+        rect.MoveBy(cell->Location());
+        AddSelfVisualOverflow(rect);
       }
+
+      if (force_slow_paint_path_with_overflowing_cell_ ||
+          !cell->HasVisualOverflow())
+        continue;
+
+#if DCHECK_IS_ON()
+      has_overflowing_cell = true;
+#endif
+      if (overflowing_cells_.size() >= max_allowed_overflowing_cells_count) {
+        // We need to set force_slow_paint_path_with_overflowing_cell_ only if
+        // there is at least one overflowing cell as the hit testing code relies
+        // on this information.
+        force_slow_paint_path_with_overflowing_cell_ = true;
+        // The slow path does not make any use of the overflowing cells info,
+        // don't hold on to the memory.
+        overflowing_cells_.clear();
+        continue;
+      }
+
+      overflowing_cells_.insert(cell);
     }
   }
 
@@ -1348,9 +1355,8 @@
       row_layouter->ComputeOverflow();
     children_overflow_changed |= row_children_overflow_changed;
   }
-  // TODO(crbug.com/604136): Add visual overflow from rows too.
   if (children_overflow_changed)
-    ComputeOverflowFromCells(total_rows, Table()->NumEffectiveColumns());
+    ComputeOverflowFromDescendants();
   return children_overflow_changed;
 }
 
@@ -1757,7 +1763,7 @@
   return result + 1;
 }
 
-const BorderValue& LayoutTableSection::BorderAdjoiningStartCell(
+BorderValue LayoutTableSection::BorderAdjoiningStartCell(
     const LayoutTableCell* cell) const {
 #if DCHECK_IS_ON()
   DCHECK(cell->IsFirstOrLastCellInRow());
@@ -1766,7 +1772,7 @@
                                   : Style()->BorderEnd();
 }
 
-const BorderValue& LayoutTableSection::BorderAdjoiningEndCell(
+BorderValue LayoutTableSection::BorderAdjoiningEndCell(
     const LayoutTableCell* cell) const {
 #if DCHECK_IS_ON()
   DCHECK(cell->IsFirstOrLastCellInRow());
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableSection.h b/third_party/WebKit/Source/core/layout/LayoutTableSection.h
index 8586c498..5b6ebb9 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTableSection.h
+++ b/third_party/WebKit/Source/core/layout/LayoutTableSection.h
@@ -121,7 +121,7 @@
   int VBorderSpacingBeforeFirstRow() const;
   int CalcRowLogicalHeight();
   void LayoutRows();
-  void ComputeOverflowFromCells();
+  void ComputeOverflowFromDescendants();
   bool RecalcChildOverflowAfterStyleChange();
 
   void MarkAllCellsWidthsDirtyAndOrNeedsLayout(LayoutTable::WhatToMarkAllCells);
@@ -201,22 +201,22 @@
     bool is_any_row_with_only_spanning_cells;
   };
 
-  const BorderValue& BorderAdjoiningTableStart() const {
+  BorderValue BorderAdjoiningTableStart() const {
     if (HasSameDirectionAs(Table()))
       return Style()->BorderStart();
 
     return Style()->BorderEnd();
   }
 
-  const BorderValue& BorderAdjoiningTableEnd() const {
+  BorderValue BorderAdjoiningTableEnd() const {
     if (HasSameDirectionAs(Table()))
       return Style()->BorderEnd();
 
     return Style()->BorderStart();
   }
 
-  const BorderValue& BorderAdjoiningStartCell(const LayoutTableCell*) const;
-  const BorderValue& BorderAdjoiningEndCell(const LayoutTableCell*) const;
+  BorderValue BorderAdjoiningStartCell(const LayoutTableCell*) const;
+  BorderValue BorderAdjoiningEndCell(const LayoutTableCell*) const;
 
   const LayoutTableCell* FirstRowCellAdjoiningTableStart() const;
   const LayoutTableCell* FirstRowCellAdjoiningTableEnd() const;
@@ -432,8 +432,6 @@
            force_slow_paint_path_with_overflowing_cell_;
   }
 
-  void ComputeOverflowFromCells(unsigned total_rows, unsigned n_eff_cols);
-
   // These two functions take a rectangle as input that has been flipped by
   // logicalRectForWritingModeAndDirection.
   // The returned span of rows or columns is end-exclusive, and empty if
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableSectionTest.cpp b/third_party/WebKit/Source/core/layout/LayoutTableSectionTest.cpp
index 905b8a12..8367f6c 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTableSectionTest.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutTableSectionTest.cpp
@@ -11,7 +11,12 @@
 
 namespace {
 
-using LayoutTableSectionTest = RenderingTest;
+class LayoutTableSectionTest : public RenderingTest {
+ protected:
+  LayoutTableSection* GetSectionByElementId(const char* id) {
+    return ToLayoutTableSection(GetLayoutObjectByElementId(id));
+  }
+};
 
 TEST_F(LayoutTableSectionTest,
        BackgroundIsKnownToBeOpaqueWithLayerAndCollapsedBorder) {
@@ -23,8 +28,7 @@
       "  </thead>"
       "</table>");
 
-  LayoutTableSection* section =
-      ToLayoutTableSection(GetLayoutObjectByElementId("section"));
+  auto* section = GetSectionByElementId("section");
   EXPECT_TRUE(section);
   EXPECT_FALSE(
       section->BackgroundIsKnownToBeOpaqueInRect(LayoutRect(0, 0, 1, 1)));
@@ -38,8 +42,7 @@
       "  </thead>"
       "</table>");
 
-  LayoutTableSection* section =
-      ToLayoutTableSection(GetLayoutObjectByElementId("section"));
+  auto* section = GetSectionByElementId("section");
   EXPECT_TRUE(section);
   EXPECT_FALSE(
       section->BackgroundIsKnownToBeOpaqueInRect(LayoutRect(0, 0, 1, 1)));
@@ -54,8 +57,7 @@
       "  </thead>"
       "</table>");
 
-  LayoutTableSection* section =
-      ToLayoutTableSection(GetLayoutObjectByElementId("section"));
+  auto* section = GetSectionByElementId("section");
   EXPECT_TRUE(section);
   EXPECT_FALSE(
       section->BackgroundIsKnownToBeOpaqueInRect(LayoutRect(0, 0, 1, 1)));
@@ -67,8 +69,7 @@
       "  <thead id='section'></thead>"
       "</table>");
 
-  LayoutTableSection* section =
-      ToLayoutTableSection(GetLayoutObjectByElementId("section"));
+  auto* section = GetSectionByElementId("section");
   EXPECT_TRUE(section);
   CellSpan cell_span = section->DirtiedRows(LayoutRect(50, 50, 100, 100));
   EXPECT_EQ(0u, cell_span.Start());
@@ -81,8 +82,7 @@
       "  <thead id='section'></thead>"
       "</table>");
 
-  LayoutTableSection* section =
-      ToLayoutTableSection(GetLayoutObjectByElementId("section"));
+  auto* section = GetSectionByElementId("section");
   EXPECT_TRUE(section);
   CellSpan cell_span =
       section->DirtiedEffectiveColumns(LayoutRect(50, 50, 100, 100));
@@ -111,7 +111,7 @@
   //       0         1
   // 0   0,0(O)    0,1(O)
   // 1   1,0(O)    1,0/0,1(S)
-  auto* section = ToLayoutTableSection(GetLayoutObjectByElementId("section"));
+  auto* section = GetSectionByElementId("section");
   auto* cell00 = GetLayoutObjectByElementId("cell00");
   auto* cell01 = GetLayoutObjectByElementId("cell01");
   auto* cell10 = GetLayoutObjectByElementId("cell10");
@@ -154,7 +154,7 @@
   // 0  0,0(O)    0,1(O)      0,2(O)
   // 1  1,0(O)    1,0/0,1(S)  0,2(S)
   // 2  2,0(O)    2,0(S)      2,0(S)
-  auto* section = ToLayoutTableSection(GetLayoutObjectByElementId("section"));
+  auto* section = GetSectionByElementId("section");
 
   // Cell 0,0 only.
   auto span = section->DirtiedRows(LayoutRect(5, 5, 90, 90));
@@ -211,6 +211,40 @@
   EXPECT_EQ(3u, span.end());
 }
 
+TEST_F(LayoutTableSectionTest, VisualOverflowWithCollapsedBorders) {
+  SetBodyInnerHTML(
+      "<style>"
+      "  table { border-collapse: collapse }"
+      "  td { border: 0px solid blue; padding: 0 }"
+      "  div { width: 100px; height: 100px }"
+      "</style>"
+      "<table>"
+      "  <tbody id='section'>"
+      "    <tr>"
+      "      <td style='border-bottom-width: 10px;"
+      "          outline: 3px solid blue'><div></div></td>"
+      "      <td style='border-width: 3px 15px'><div></div></td>"
+      "    </tr>"
+      "    <tr style='outline: 8px solid green'><td><div></div></td></tr>"
+      "  </tbody>"
+      "</table>");
+
+  auto* section = GetSectionByElementId("section");
+
+  // The section's self visual overflow covers the collapsed borders.
+  LayoutRect expected_self_visual_overflow = section->BorderBoxRect();
+  expected_self_visual_overflow.ExpandEdges(LayoutUnit(1), LayoutUnit(8),
+                                            LayoutUnit(0), LayoutUnit(0));
+  EXPECT_EQ(expected_self_visual_overflow, section->SelfVisualOverflowRect());
+
+  // The section's visual overflow covers self visual overflow and visual
+  // overflows rows.
+  LayoutRect expected_visual_overflow = section->BorderBoxRect();
+  expected_visual_overflow.ExpandEdges(LayoutUnit(3), LayoutUnit(8),
+                                       LayoutUnit(8), LayoutUnit(8));
+  EXPECT_EQ(expected_visual_overflow, section->VisualOverflowRect());
+}
+
 }  // anonymous namespace
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/style/BUILD.gn b/third_party/WebKit/Source/core/style/BUILD.gn
index 1458f9a..d4a8df6 100644
--- a/third_party/WebKit/Source/core/style/BUILD.gn
+++ b/third_party/WebKit/Source/core/style/BUILD.gn
@@ -12,6 +12,7 @@
     "AppliedTextDecoration.h",
     "BasicShapes.cpp",
     "BasicShapes.h",
+    "BorderColorAndStyle.h",
     "BorderData.h",
     "BorderEdge.cpp",
     "BorderEdge.h",
diff --git a/third_party/WebKit/Source/core/style/BorderColorAndStyle.h b/third_party/WebKit/Source/core/style/BorderColorAndStyle.h
new file mode 100644
index 0000000..757254f2
--- /dev/null
+++ b/third_party/WebKit/Source/core/style/BorderColorAndStyle.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
+ *           (C) 2000 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef BorderColorAndStyle_h
+#define BorderColorAndStyle_h
+
+#include "core/css/StyleColor.h"
+#include "core/style/ComputedStyleConstants.h"
+#include "platform/graphics/Color.h"
+#include "platform/wtf/Allocator.h"
+
+namespace blink {
+
+class BorderColorAndStyle {
+  DISALLOW_NEW();
+  friend class ComputedStyle;
+
+ public:
+  BorderColorAndStyle()
+      : color_(0),
+        color_is_current_color_(true),
+        style_(kBorderStyleNone),
+        is_auto_(kOutlineIsAutoOff) {}
+
+  bool NonZero() const { return (style_ != kBorderStyleNone); }
+
+  bool IsTransparent() const {
+    return !color_is_current_color_ && !color_.Alpha();
+  }
+
+  bool operator==(const BorderColorAndStyle& o) const {
+    return style_ == o.style_ && color_ == o.color_ &&
+           color_is_current_color_ == o.color_is_current_color_;
+  }
+
+  // The default width is 3px, but if the style is none we compute a value of 0
+  // (in ComputedStyle itself)
+  bool VisuallyEqual(const BorderColorAndStyle& o) const {
+    if (style_ == kBorderStyleNone && o.style_ == kBorderStyleNone)
+      return true;
+    if (style_ == kBorderStyleHidden && o.style_ == kBorderStyleHidden)
+      return true;
+    return *this == o;
+  }
+
+  bool operator!=(const BorderColorAndStyle& o) const { return !(*this == o); }
+
+  void SetColor(const StyleColor& color) {
+    color_ = color.Resolve(Color());
+    color_is_current_color_ = color.IsCurrentColor();
+  }
+
+  StyleColor GetColor() const {
+    return color_is_current_color_ ? StyleColor::CurrentColor()
+                                   : StyleColor(color_);
+  }
+
+  EBorderStyle Style() const { return static_cast<EBorderStyle>(style_); }
+  void SetStyle(EBorderStyle style) { style_ = style; }
+
+  OutlineIsAuto IsAuto() const { return static_cast<OutlineIsAuto>(is_auto_); }
+  void SetIsAuto(OutlineIsAuto is_auto) { is_auto_ = is_auto; }
+
+  bool ColorIsCurrentColor() const { return color_is_current_color_; }
+  void SetColorIsCurrentColor(bool color_is_current_color) {
+    color_is_current_color_ = static_cast<unsigned>(color_is_current_color);
+  }
+
+ protected:
+  Color color_;
+  unsigned color_is_current_color_ : 1;
+
+  unsigned style_ : 4;  // EBorderStyle
+
+  // This is only used by OutlineValue but moved here to keep the bits packed.
+  unsigned is_auto_ : 1;  // OutlineIsAuto
+};
+
+}  // namespace blink
+
+#endif  // BorderColorAndStyle_h
diff --git a/third_party/WebKit/Source/core/style/BorderData.h b/third_party/WebKit/Source/core/style/BorderData.h
index 91af0da..c6d1888 100644
--- a/third_party/WebKit/Source/core/style/BorderData.h
+++ b/third_party/WebKit/Source/core/style/BorderData.h
@@ -25,7 +25,7 @@
 #ifndef BorderData_h
 #define BorderData_h
 
-#include "core/style/BorderValue.h"
+#include "core/style/BorderColorAndStyle.h"
 #include "core/style/NinePieceImage.h"
 #include "platform/LengthSize.h"
 #include "platform/geometry/IntRect.h"
@@ -54,33 +54,6 @@
            (bottom_.NonZero() && bottom_.GetColor().IsCurrentColor());
   }
 
-  float BorderLeftWidth() const {
-    if (left_.Style() == kBorderStyleNone ||
-        left_.Style() == kBorderStyleHidden)
-      return 0;
-    return left_.Width();
-  }
-
-  float BorderRightWidth() const {
-    if (right_.Style() == kBorderStyleNone ||
-        right_.Style() == kBorderStyleHidden)
-      return 0;
-    return right_.Width();
-  }
-
-  float BorderTopWidth() const {
-    if (top_.Style() == kBorderStyleNone || top_.Style() == kBorderStyleHidden)
-      return 0;
-    return top_.Width();
-  }
-
-  float BorderBottomWidth() const {
-    if (bottom_.Style() == kBorderStyleNone ||
-        bottom_.Style() == kBorderStyleHidden)
-      return 0;
-    return bottom_.Width();
-  }
-
   bool operator==(const BorderData& o) const {
     return left_ == o.left_ && right_ == o.right_ && top_ == o.top_ &&
            bottom_ == o.bottom_ && image_ == o.image_;
@@ -98,25 +71,18 @@
 
   bool operator!=(const BorderData& o) const { return !(*this == o); }
 
-  bool SizeEquals(const BorderData& o) const {
-    return BorderLeftWidth() == o.BorderLeftWidth() &&
-           BorderTopWidth() == o.BorderTopWidth() &&
-           BorderRightWidth() == o.BorderRightWidth() &&
-           BorderBottomWidth() == o.BorderBottomWidth();
-  }
-
-  const BorderValue& Left() const { return left_; }
-  const BorderValue& Right() const { return right_; }
-  const BorderValue& Top() const { return top_; }
-  const BorderValue& Bottom() const { return bottom_; }
+  const BorderColorAndStyle& Left() const { return left_; }
+  const BorderColorAndStyle& Right() const { return right_; }
+  const BorderColorAndStyle& Top() const { return top_; }
+  const BorderColorAndStyle& Bottom() const { return bottom_; }
 
   const NinePieceImage& GetImage() const { return image_; }
 
  private:
-  BorderValue left_;
-  BorderValue right_;
-  BorderValue top_;
-  BorderValue bottom_;
+  BorderColorAndStyle left_;
+  BorderColorAndStyle right_;
+  BorderColorAndStyle top_;
+  BorderColorAndStyle bottom_;
 
   NinePieceImage image_;
 };
diff --git a/third_party/WebKit/Source/core/style/BorderValue.h b/third_party/WebKit/Source/core/style/BorderValue.h
index 58a2616..0c71ba0 100644
--- a/third_party/WebKit/Source/core/style/BorderValue.h
+++ b/third_party/WebKit/Source/core/style/BorderValue.h
@@ -26,22 +26,13 @@
 #define BorderValue_h
 
 #include "core/css/StyleColor.h"
+#include "core/style/BorderColorAndStyle.h"
 #include "core/style/ComputedStyleConstants.h"
 #include "platform/graphics/Color.h"
 #include "platform/wtf/Allocator.h"
 
 namespace blink {
 
-// In order to conserve memory, the border width uses fixed point,
-// which can be bitpacked.  This fixed point implementation is
-// essentially the same as in LayoutUnit.  Six bits are used for the
-// fraction, which leaves 20 bits for the integer part, making 1048575
-// the largest number.
-
-static const int kBorderWidthFractionalBits = 6;
-static const int kBorderWidthDenominator = 1 << kBorderWidthFractionalBits;
-static const int kMaxForBorderWidth = ((1 << 26) - 1) / kBorderWidthDenominator;
-
 class BorderValue {
   DISALLOW_NEW();
   friend class ComputedStyle;
@@ -55,6 +46,14 @@
     SetWidth(3);
   }
 
+  BorderValue(const BorderColorAndStyle& data, float width) {
+    SetColor(data.GetColor());
+    SetColorIsCurrentColor(ColorIsCurrentColor());
+    SetStyle(data.Style());
+    SetIsAuto(data.IsAuto());
+    SetWidth(width);
+  }
+
   bool NonZero() const { return Width() && (style_ != kBorderStyleNone); }
 
   bool IsTransparent() const {
@@ -102,6 +101,14 @@
   EBorderStyle Style() const { return static_cast<EBorderStyle>(style_); }
   void SetStyle(EBorderStyle style) { style_ = style; }
 
+  OutlineIsAuto IsAuto() const { return static_cast<OutlineIsAuto>(is_auto_); }
+  void SetIsAuto(OutlineIsAuto is_auto) { is_auto_ = is_auto; }
+
+  bool ColorIsCurrentColor() const { return color_is_current_color_; }
+  void SetColorIsCurrentColor(bool color_is_current_color) {
+    color_is_current_color_ = static_cast<unsigned>(color_is_current_color);
+  }
+
  protected:
   static unsigned WidthToFixedPoint(float width) {
     DCHECK_GE(width, 0);
diff --git a/third_party/WebKit/Source/core/style/CachedUAStyle.h b/third_party/WebKit/Source/core/style/CachedUAStyle.h
index 4134418..1f8c095 100644
--- a/third_party/WebKit/Source/core/style/CachedUAStyle.h
+++ b/third_party/WebKit/Source/core/style/CachedUAStyle.h
@@ -49,6 +49,10 @@
   LengthSize top_right_;
   LengthSize bottom_left_;
   LengthSize bottom_right_;
+  float border_left_width;
+  float border_right_width;
+  float border_top_width;
+  float border_bottom_width;
   FillLayer background_layers;
   StyleColor background_color;
 
@@ -59,6 +63,10 @@
         top_right_(style->BorderTopRightRadius()),
         bottom_left_(style->BorderBottomLeftRadius()),
         bottom_right_(style->BorderBottomRightRadius()),
+        border_left_width(style->BorderLeftWidth()),
+        border_right_width(style->BorderRightWidth()),
+        border_top_width(style->BorderTopWidth()),
+        border_bottom_width(style->BorderBottomWidth()),
         background_layers(style->BackgroundLayers()),
         background_color(style->BackgroundColor()) {}
 };
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.cpp b/third_party/WebKit/Source/core/style/ComputedStyle.cpp
index 73ee14e..76494dc 100644
--- a/third_party/WebKit/Source/core/style/ComputedStyle.cpp
+++ b/third_party/WebKit/Source/core/style/ComputedStyle.cpp
@@ -592,10 +592,10 @@
   if (surround_data_.Get() != other.surround_data_.Get()) {
     // If our border widths change, then we need to layout. Other changes to
     // borders only necessitate a paint invalidation.
-    if (BorderLeftWidth() != other.BorderLeftWidth() ||
-        BorderTopWidth() != other.BorderTopWidth() ||
-        BorderBottomWidth() != other.BorderBottomWidth() ||
-        BorderRightWidth() != other.BorderRightWidth())
+    if (!(BorderWidthEquals(BorderLeftWidth(), other.BorderLeftWidth())) ||
+        !(BorderWidthEquals(BorderTopWidth(), other.BorderTopWidth())) ||
+        !(BorderWidthEquals(BorderBottomWidth(), other.BorderBottomWidth())) ||
+        !(BorderWidthEquals(BorderRightWidth(), other.BorderRightWidth())))
       return true;
   }
 
@@ -886,7 +886,7 @@
       PrintColorAdjust() != other.PrintColorAdjust() ||
       InsideLink() != other.InsideLink() ||
       !Border().VisuallyEqual(other.Border()) || !RadiiEqual(other) ||
-      *background_data_ != *other.background_data_)
+      !BorderSizeEquals(other) || *background_data_ != *other.background_data_)
     return true;
 
   if (rare_inherited_data_.Get() != other.rare_inherited_data_.Get()) {
@@ -2227,7 +2227,7 @@
                unvisited_color.Alpha());
 }
 
-const BorderValue& ComputedStyle::BorderBefore() const {
+const BorderValue ComputedStyle::BorderBefore() const {
   switch (GetWritingMode()) {
     case WritingMode::kHorizontalTb:
       return BorderTop();
@@ -2240,7 +2240,7 @@
   return BorderTop();
 }
 
-const BorderValue& ComputedStyle::BorderAfter() const {
+const BorderValue ComputedStyle::BorderAfter() const {
   switch (GetWritingMode()) {
     case WritingMode::kHorizontalTb:
       return BorderBottom();
@@ -2253,13 +2253,13 @@
   return BorderBottom();
 }
 
-const BorderValue& ComputedStyle::BorderStart() const {
+const BorderValue ComputedStyle::BorderStart() const {
   if (IsHorizontalWritingMode())
     return IsLeftToRightDirection() ? BorderLeft() : BorderRight();
   return IsLeftToRightDirection() ? BorderTop() : BorderBottom();
 }
 
-const BorderValue& ComputedStyle::BorderEnd() const {
+const BorderValue ComputedStyle::BorderEnd() const {
   if (IsHorizontalWritingMode())
     return IsLeftToRightDirection() ? BorderRight() : BorderLeft();
   return IsLeftToRightDirection() ? BorderBottom() : BorderTop();
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.h b/third_party/WebKit/Source/core/style/ComputedStyle.h
index ab0afd03..cdbd480a 100644
--- a/third_party/WebKit/Source/core/style/ComputedStyle.h
+++ b/third_party/WebKit/Source/core/style/ComputedStyle.h
@@ -262,6 +262,12 @@
     return cached_pseudo_styles_.get();
   }
 
+  bool BorderWidthEquals(float border_width_first,
+                         float border_width_second) const {
+    return WidthToFixedPoint(border_width_first) ==
+           WidthToFixedPoint(border_width_second);
+  }
+
   /**
      * ComputedStyle properties
      *
@@ -468,36 +474,53 @@
   // Border width properties.
   static float InitialBorderWidth() { return 3; }
 
+  // TODO(nainar): Move all fixed point logic to a separate class.
   // border-top-width
   float BorderTopWidth() const {
-    return surround_data_->border_.BorderTopWidth();
+    if (surround_data_->border_.top_.Style() == kBorderStyleNone ||
+        surround_data_->border_.top_.Style() == kBorderStyleHidden)
+      return 0;
+    return static_cast<float>(BorderTopWidthInternal()) /
+           kBorderWidthDenominator;
   }
   void SetBorderTopWidth(float v) {
-    SET_BORDER_WIDTH(surround_data_, border_.top_, v);
+    surround_data_.Access()->border_top_width_ = WidthToFixedPoint(v);
   }
 
   // border-bottom-width
   float BorderBottomWidth() const {
-    return surround_data_->border_.BorderBottomWidth();
+    if (surround_data_->border_.bottom_.Style() == kBorderStyleNone ||
+        surround_data_->border_.bottom_.Style() == kBorderStyleHidden)
+      return 0;
+    return static_cast<float>(BorderBottomWidthInternal()) /
+           kBorderWidthDenominator;
   }
   void SetBorderBottomWidth(float v) {
-    SET_BORDER_WIDTH(surround_data_, border_.bottom_, v);
+    surround_data_.Access()->border_bottom_width_ = WidthToFixedPoint(v);
   }
 
   // border-left-width
   float BorderLeftWidth() const {
-    return surround_data_->border_.BorderLeftWidth();
+    if (surround_data_->border_.left_.Style() == kBorderStyleNone ||
+        surround_data_->border_.left_.Style() == kBorderStyleHidden)
+      return 0;
+    return static_cast<float>(BorderLeftWidthInternal()) /
+           kBorderWidthDenominator;
   }
   void SetBorderLeftWidth(float v) {
-    SET_BORDER_WIDTH(surround_data_, border_.left_, v);
+    surround_data_.Access()->border_left_width_ = WidthToFixedPoint(v);
   }
 
   // border-right-width
   float BorderRightWidth() const {
-    return surround_data_->border_.BorderRightWidth();
+    if (surround_data_->border_.right_.Style() == kBorderStyleNone ||
+        surround_data_->border_.right_.Style() == kBorderStyleHidden)
+      return 0;
+    return static_cast<float>(BorderRightWidthInternal()) /
+           kBorderWidthDenominator;
   }
   void SetBorderRightWidth(float v) {
-    SET_BORDER_WIDTH(surround_data_, border_.right_, v);
+    surround_data_.Access()->border_right_width_ = WidthToFixedPoint(v);
   }
 
   // Border style properties.
@@ -2821,20 +2844,28 @@
 
   void SetBorderImageSlicesFill(bool);
   const BorderData& Border() const { return surround_data_->border_; }
-  const BorderValue& BorderLeft() const {
-    return surround_data_->border_.Left();
+  const BorderValue BorderLeft() const {
+    return BorderValue(surround_data_->border_.Left(), BorderLeftWidth());
   }
-  const BorderValue& BorderRight() const {
-    return surround_data_->border_.Right();
+  const BorderValue BorderRight() const {
+    return BorderValue(surround_data_->border_.Right(), BorderRightWidth());
   }
-  const BorderValue& BorderTop() const { return surround_data_->border_.Top(); }
-  const BorderValue& BorderBottom() const {
-    return surround_data_->border_.Bottom();
+  const BorderValue BorderTop() const {
+    return BorderValue(surround_data_->border_.Top(), BorderTopWidth());
   }
-  const BorderValue& BorderBefore() const;
-  const BorderValue& BorderAfter() const;
-  const BorderValue& BorderStart() const;
-  const BorderValue& BorderEnd() const;
+  const BorderValue BorderBottom() const {
+    return BorderValue(surround_data_->border_.Bottom(), BorderBottomWidth());
+  }
+  bool BorderSizeEquals(const ComputedStyle& o) const {
+    return BorderWidthEquals(BorderLeftWidth(), o.BorderLeftWidth()) &&
+           BorderWidthEquals(BorderTopWidth(), o.BorderTopWidth()) &&
+           BorderWidthEquals(BorderRightWidth(), o.BorderRightWidth()) &&
+           BorderWidthEquals(BorderBottomWidth(), o.BorderBottomWidth());
+  }
+  const BorderValue BorderBefore() const;
+  const BorderValue BorderAfter() const;
+  const BorderValue BorderStart() const;
+  const BorderValue BorderEnd() const;
   float BorderAfterWidth() const;
   float BorderBeforeWidth() const;
   float BorderEndWidth() const;
@@ -2843,7 +2874,10 @@
   float BorderUnderWidth() const;
 
   bool HasBorderFill() const { return Border().HasBorderFill(); }
-  bool HasBorder() const { return Border().HasBorder(); }
+  bool HasBorder() const {
+    return Border().HasBorder() || BorderLeftWidth() || BorderRightWidth() ||
+           BorderTopWidth() || BorderBottomWidth();
+  }
   bool HasBorderDecoration() const { return HasBorder() || HasBorderFill(); }
   bool HasBorderRadius() const {
     if (!BorderTopLeftRadius().Width().IsZero())
@@ -2879,16 +2913,20 @@
     ResetBorderBottomRightRadius();
   }
   void ResetBorderTop() {
-    SET_VAR(surround_data_, border_.top_, BorderValue());
+    SET_VAR(surround_data_, border_.top_, BorderColorAndStyle());
+    SetBorderTopWidth(3);
   }
   void ResetBorderRight() {
-    SET_VAR(surround_data_, border_.right_, BorderValue());
+    SET_VAR(surround_data_, border_.right_, BorderColorAndStyle());
+    SetBorderRightWidth(3);
   }
   void ResetBorderBottom() {
-    SET_VAR(surround_data_, border_.bottom_, BorderValue());
+    SET_VAR(surround_data_, border_.bottom_, BorderColorAndStyle());
+    SetBorderBottomWidth(3);
   }
   void ResetBorderLeft() {
-    SET_VAR(surround_data_, border_.left_, BorderValue());
+    SET_VAR(surround_data_, border_.left_, BorderColorAndStyle());
+    SetBorderLeftWidth(3);
   }
   void ResetBorderImage() {
     SET_VAR(surround_data_, border_.image_, NinePieceImage());
diff --git a/third_party/WebKit/Source/core/style/ComputedStyleConstants.h b/third_party/WebKit/Source/core/style/ComputedStyleConstants.h
index ae5e07ab..8fd1c06 100644
--- a/third_party/WebKit/Source/core/style/ComputedStyleConstants.h
+++ b/third_party/WebKit/Source/core/style/ComputedStyleConstants.h
@@ -499,6 +499,16 @@
 
 enum AutoRepeatType { kNoAutoRepeat, kAutoFill, kAutoFit };
 
+// In order to conserve memory, the border width uses fixed point,
+// which can be bitpacked.  This fixed point implementation is
+// essentially the same as in LayoutUnit.  Six bits are used for the
+// fraction, which leaves 20 bits for the integer part, making 1048575
+// the largest number.
+
+static const int kBorderWidthFractionalBits = 6;
+static const int kBorderWidthDenominator = 1 << kBorderWidthFractionalBits;
+static const int kMaxForBorderWidth = ((1 << 26) - 1) / kBorderWidthDenominator;
+
 }  // namespace blink
 
 #endif  // ComputedStyleConstants_h
diff --git a/third_party/WebKit/Source/core/style/OutlineValue.h b/third_party/WebKit/Source/core/style/OutlineValue.h
index f26b9ba0..5cbc5aa 100644
--- a/third_party/WebKit/Source/core/style/OutlineValue.h
+++ b/third_party/WebKit/Source/core/style/OutlineValue.h
@@ -53,9 +53,6 @@
   int Offset() const { return offset_; }
   void SetOffset(int offset) { offset_ = offset; }
 
-  OutlineIsAuto IsAuto() const { return static_cast<OutlineIsAuto>(is_auto_); }
-  void SetIsAuto(OutlineIsAuto is_auto) { is_auto_ = is_auto; }
-
  private:
   int offset_;
 };
diff --git a/third_party/freetype/README.chromium b/third_party/freetype/README.chromium
index 971087d..e3197167 100644
--- a/third_party/freetype/README.chromium
+++ b/third_party/freetype/README.chromium
@@ -9,9 +9,9 @@
 License Android Compatible: yes
 
 Description:
-This package tracks upstream FreeType, but the build files and configuration
-are based on the Android source tree. This package is only used for Android
-and Chromecast. For other platforms the system FreeType library is used.
+This package tracks upstream FreeType. It is shipped as part of Chrome on all
+platforms. FreeType is needed on Windows and Mac for PDFium as well for enabling
+font format support for OpenType Variations on older OS versions.
 
 How to update:
 1. Find the desired commit in
@@ -19,10 +19,9 @@
    If such a commit does not yet exist, branch from the appropriate point with
    a branch name like "chromium/android/VER-X-X-X-updates" depending on the
    FreeType tag being branched and commit changes there.
-2. Update BUILD.gn to reflect any changes. This build should be kept
-   in sync with the Android.mk for FreeType in Android as possible.
+2. Update BUILD.gn to reflect any changes.
 3. Merge the new src/include/freetype/config/ftoption.h into
-   include/freetype-android-config/ftoption.h .
+   include/freetype-custom-config/ftoption.h .
 4. Update this file.
-5. Commit build changes while rolling Chromium's freetype-android DEPS to the
+5. Commit build changes while rolling Chromium's freetype DEPS to the
    new commit.
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index f76bc4b4..47a14ff1 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -7228,10 +7228,16 @@
 </enum>
 
 <enum name="DircryptoMigrationEndStatus" type="int">
-  <int value="1" label="New migration failed"/>
+  <int value="1" label="New migration failed (generic failure)"/>
   <int value="2" label="New migration succeeded"/>
-  <int value="3" label="Resumed migration failed"/>
+  <int value="3" label="Resumed migration failed (generic failure)"/>
   <int value="4" label="Resumed migration succeeded"/>
+  <int value="5" label="New migration failed (low disk space)"/>
+  <int value="6" label="Resumed migration failed (low disk space)"/>
+  <int value="7" label="New migration failed (file error)"/>
+  <int value="8" label="Resumed migration failed (file error)"/>
+  <int value="9" label="New migration failed (file error EIO on open)"/>
+  <int value="10" label="Resumed migration failed (file error EIO on open)"/>
 </enum>
 
 <enum name="DircryptoMigrationStartStatus" type="int">
diff --git a/tools/perf/benchmarks/blink_perf.py b/tools/perf/benchmarks/blink_perf.py
index 65eb3815..7491f125 100644
--- a/tools/perf/benchmarks/blink_perf.py
+++ b/tools/perf/benchmarks/blink_perf.py
@@ -303,10 +303,7 @@
   @classmethod
   def ShouldDisable(cls, possible_browser):
     # http://crbug.com/563979
-    return (cls.IsSvelte(possible_browser)
-      # http://crbug.com/653970
-      or (possible_browser.browser_type == 'reference' and
-        possible_browser.platform.GetOSName() == 'android'))
+    return cls.IsSvelte(possible_browser)
 
 
 @benchmark.Enabled('content-shell')
@@ -322,8 +319,7 @@
 
 
 @benchmark.Disabled('android', # http://crbug.com/685320
-                    'android-webview', # http://crbug.com/593200
-                    'reference')  # http://crbug.com/576779
+                    'android-webview') # http://crbug.com/593200
 @benchmark.Owner(emails=['junov@chromium.org'])
 class BlinkPerfCanvas(_BlinkPerfBenchmark):
   tag = 'canvas'
diff --git a/ui/native_theme/native_theme_win.cc b/ui/native_theme/native_theme_win.cc
index 4cc3341..70c83cd 100644
--- a/ui/native_theme/native_theme_win.cc
+++ b/ui/native_theme/native_theme_win.cc
@@ -166,49 +166,6 @@
   instance()->CloseHandlesInternal();
 }
 
-HRESULT NativeThemeWin::GetThemeColor(ThemeName theme,
-                                      int part_id,
-                                      int state_id,
-                                      int prop_id,
-                                      SkColor* color) const {
-  HANDLE handle = GetThemeHandle(theme);
-  if (!handle || !get_theme_color_)
-    return E_NOTIMPL;
-  COLORREF color_ref;
-  if (get_theme_color_(handle, part_id, state_id, prop_id, &color_ref) != S_OK)
-    return E_NOTIMPL;
-  *color = skia::COLORREFToSkColor(color_ref);
-  return S_OK;
-}
-
-SkColor NativeThemeWin::GetThemeColorWithDefault(ThemeName theme,
-                                                 int part_id,
-                                                 int state_id,
-                                                 int prop_id,
-                                                 int default_sys_color) const {
-  SkColor color;
-  return (GetThemeColor(theme, part_id, state_id, prop_id, &color) == S_OK) ?
-      color : color_utils::GetSysSkColor(default_sys_color);
-}
-
-gfx::Size NativeThemeWin::GetThemeBorderSize(ThemeName theme) const {
-  // For simplicity use the wildcard state==0, part==0, since it works
-  // for the cases we currently depend on.
-  int border;
-  return (GetThemeInt(theme, 0, 0, TMT_BORDERSIZE, &border) == S_OK) ?
-      gfx::Size(border, border) :
-      gfx::Size(GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE));
-}
-
-void NativeThemeWin::DisableTheming() const {
-  if (set_theme_properties_)
-    set_theme_properties_(0);
-}
-
-bool NativeThemeWin::IsClassicTheme(ThemeName name) const {
-  return !theme_dll_ || !GetThemeHandle(name);
-}
-
 // static
 NativeThemeWin* NativeThemeWin::instance() {
   CR_DEFINE_STATIC_LOCAL(NativeThemeWin, s_native_theme, ());
@@ -285,13 +242,10 @@
 NativeThemeWin::NativeThemeWin()
     : draw_theme_(NULL),
       draw_theme_ex_(NULL),
-      get_theme_color_(NULL),
       get_theme_content_rect_(NULL),
       get_theme_part_size_(NULL),
       open_theme_(NULL),
       close_theme_(NULL),
-      set_theme_properties_(NULL),
-      get_theme_int_(NULL),
       theme_dll_(LoadLibrary(L"uxtheme.dll")),
       color_change_listener_(this),
       is_using_high_contrast_(false),
@@ -301,8 +255,6 @@
         GetProcAddress(theme_dll_, "DrawThemeBackground"));
     draw_theme_ex_ = reinterpret_cast<DrawThemeBackgroundExPtr>(
         GetProcAddress(theme_dll_, "DrawThemeBackgroundEx"));
-    get_theme_color_ = reinterpret_cast<GetThemeColorPtr>(
-        GetProcAddress(theme_dll_, "GetThemeColor"));
     get_theme_content_rect_ = reinterpret_cast<GetThemeContentRectPtr>(
         GetProcAddress(theme_dll_, "GetThemeBackgroundContentRect"));
     get_theme_part_size_ = reinterpret_cast<GetThemePartSizePtr>(
@@ -311,10 +263,6 @@
         GetProcAddress(theme_dll_, "OpenThemeData"));
     close_theme_ = reinterpret_cast<CloseThemeDataPtr>(
         GetProcAddress(theme_dll_, "CloseThemeData"));
-    set_theme_properties_ = reinterpret_cast<SetThemeAppPropertiesPtr>(
-        GetProcAddress(theme_dll_, "SetThemeAppProperties"));
-    get_theme_int_ = reinterpret_cast<GetThemeIntPtr>(
-        GetProcAddress(theme_dll_, "GetThemeInt"));
   }
   memset(theme_handles_, 0, sizeof(theme_handles_));
 
@@ -1928,16 +1876,6 @@
   return 0;
 }
 
-HRESULT NativeThemeWin::GetThemeInt(ThemeName theme,
-                                    int part_id,
-                                    int state_id,
-                                    int prop_id,
-                                    int *value) const {
-  HANDLE handle = GetThemeHandle(theme);
-  return (handle && get_theme_int_) ?
-      get_theme_int_(handle, part_id, state_id, prop_id, value) : E_NOTIMPL;
-}
-
 HRESULT NativeThemeWin::PaintFrameControl(HDC hdc,
                                           const gfx::Rect& rect,
                                           UINT type,
diff --git a/ui/native_theme/native_theme_win.h b/ui/native_theme/native_theme_win.h
index 716a4133..d69d731d 100644
--- a/ui/native_theme/native_theme_win.h
+++ b/ui/native_theme/native_theme_win.h
@@ -59,36 +59,6 @@
   // for a theme change.
   static void CloseHandles();
 
-  HRESULT GetThemeColor(ThemeName theme,
-                        int part_id,
-                        int state_id,
-                        int prop_id,
-                        SkColor* color) const;
-
-  // Get the theme color if theming is enabled.  If theming is unsupported
-  // for this part, use Win32's GetSysColor to find the color specified
-  // by default_sys_color.
-  SkColor GetThemeColorWithDefault(ThemeName theme,
-                                   int part_id,
-                                   int state_id,
-                                   int prop_id,
-                                   int default_sys_color) const;
-
-  // Get the thickness of the border associated with the specified theme,
-  // defaulting to GetSystemMetrics edge size if themes are disabled.
-  // In Classic Windows, borders are typically 2px; on XP+, they are 1px.
-  gfx::Size GetThemeBorderSize(ThemeName theme) const;
-
-  // Disables all theming for top-level windows in the entire process, from
-  // when this method is called until the process exits.  All the other
-  // methods in this class will continue to work, but their output will ignore
-  // the user's theme. This is meant for use when running tests that require
-  // consistent visual results.
-  void DisableTheming() const;
-
-  // Returns true if classic theme is in use.
-  bool IsClassicTheme(ThemeName name) const;
-
   HRESULT PaintTextField(HDC hdc,
                          int part_id,
                          int state_id,
@@ -281,12 +251,6 @@
   static int GetWindowsPart(Part part, State state, const ExtraParams& extra);
   static int GetWindowsState(Part part, State state, const ExtraParams& extra);
 
-  HRESULT GetThemeInt(ThemeName theme,
-                      int part_id,
-                      int state_id,
-                      int prop_id,
-                      int *result) const;
-
   HRESULT PaintFrameControl(HDC hdc,
                             const gfx::Rect& rect,
                             UINT type,
@@ -347,8 +311,6 @@
   GetThemePartSizePtr get_theme_part_size_;
   OpenThemeDataPtr open_theme_;
   CloseThemeDataPtr close_theme_;
-  SetThemeAppPropertiesPtr set_theme_properties_;
-  GetThemeIntPtr get_theme_int_;
 
   // Handle to uxtheme.dll.
   HMODULE theme_dll_;