diff --git a/DEPS b/DEPS
index 2a5bab4..8766d07a0 100644
--- a/DEPS
+++ b/DEPS
@@ -40,11 +40,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '255607f094dac0f1c075a5b718005e7bd4d03e3d',
+  'skia_revision': 'fba26ea9b7fc7ed45d80ba0bd923d1824fd49534',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '43bd6d3ffbe85d6e20c7ba4e4dcd839891689759',
+  'v8_revision': '19f1033a265556dec3fdd575526c6fa48e240974',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -60,7 +60,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
-  'swiftshader_revision': '8aa07683f555dd02e2c7cae2d3e28c53385cc504',
+  'swiftshader_revision': '4d3efedb10ce60bdb7847336eba0360fdc9af9d3',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
@@ -92,7 +92,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
-  'freetype_revision': '38bdf22bfe68432aebdd33c198a0bd11b4ebb96f',
+  'freetype_revision': '7e50824288fac5a36c2938fdb3e1c949ea53f982',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
diff --git a/WATCHLISTS b/WATCHLISTS
index 51d20d74..22f11d3 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -2178,7 +2178,8 @@
     'permissions': ['dominickn+watch@chromium.org',
                     'hanxi+watch@chromium.org',
                     'mlamouri+watch-permissions@chromium.org',
-                    'raymes+watch@chromium.org'],
+                    'raymes+watch@chromium.org',
+                    'timloh+watch@chromium.org'],
     'plugin': ['jam@chromium.org'],
     'polymer': ['michaelpg+watch-polymer@chromium.org'],
     'precache': ['wifiprefetch-reviews@google.com'],
diff --git a/cc/raster/playback_image_provider.cc b/cc/raster/playback_image_provider.cc
index 46e4d2c9..f820378 100644
--- a/cc/raster/playback_image_provider.cc
+++ b/cc/raster/playback_image_provider.cc
@@ -18,8 +18,7 @@
 void UnrefImageFromCache(DrawImage draw_image,
                          ImageDecodeCache* cache,
                          DecodedDrawImage decoded_draw_image) {
-  if (decoded_draw_image.image())
-    cache->DrawWithImageFinished(draw_image, decoded_draw_image);
+  cache->DrawWithImageFinished(draw_image, decoded_draw_image);
 }
 
 }  // namespace
diff --git a/chrome/browser/background_sync/OWNERS b/chrome/browser/background_sync/OWNERS
index f6372cb..e28d427 100644
--- a/chrome/browser/background_sync/OWNERS
+++ b/chrome/browser/background_sync/OWNERS
@@ -1,7 +1,6 @@
 iclelland@chromium.org
 jkarlin@chromium.org
 
-per-file *permission_context*=set noparent
 per-file *permission_context*=file://chrome/browser/permissions/PERMISSIONS_OWNERS
 
 # COMPONENT: Blink>BackgroundSync
diff --git a/chrome/browser/generic_sensor/OWNERS b/chrome/browser/generic_sensor/OWNERS
index 8abe7701..da9be96 100644
--- a/chrome/browser/generic_sensor/OWNERS
+++ b/chrome/browser/generic_sensor/OWNERS
@@ -1,6 +1,5 @@
 file://services/device/generic_sensor/OWNERS
 
-per-file *permission_context*=set noparent
 per-file *permission_context*=file://chrome/browser/permissions/PERMISSIONS_OWNERS
 
 # COMPONENT: Blink>Sensor
diff --git a/chrome/browser/geolocation/OWNERS b/chrome/browser/geolocation/OWNERS
index 3ba48c1d..26f730da 100644
--- a/chrome/browser/geolocation/OWNERS
+++ b/chrome/browser/geolocation/OWNERS
@@ -2,7 +2,6 @@
 raymes@chromium.org
 timvolodine@chromium.org
 
-per-file *permission_context*=set noparent
 per-file *permission_context*=file://chrome/browser/permissions/PERMISSIONS_OWNERS
 
 # COMPONENT: Internals>Permissions
diff --git a/chrome/browser/media/OWNERS b/chrome/browser/media/OWNERS
index c5eec594..9c6c9f8 100644
--- a/chrome/browser/media/OWNERS
+++ b/chrome/browser/media/OWNERS
@@ -13,7 +13,6 @@
 per-file *.mojom=set noparent
 per-file *.mojom=file://ipc/SECURITY_OWNERS
 
-per-file *permission_context*=set noparent
 per-file *permission_context*=file://chrome/browser/permissions/PERMISSIONS_OWNERS
 
 # COMPONENT: Blink>Media
diff --git a/chrome/browser/media/webrtc/OWNERS b/chrome/browser/media/webrtc/OWNERS
index a618805..dfc87da 100644
--- a/chrome/browser/media/webrtc/OWNERS
+++ b/chrome/browser/media/webrtc/OWNERS
@@ -15,7 +15,6 @@
 # For WebRTC desktop capturer related changes only
 per-file native_desktop_media_list*=zijiehe@chromium.org
 
-per-file *permission_context*=set noparent
 per-file *permission_context*=file://chrome/browser/permissions/PERMISSIONS_OWNERS
 
 # COMPONENT: Blink>WebRTC
diff --git a/chrome/browser/notifications/OWNERS b/chrome/browser/notifications/OWNERS
index 0d30063..62fa249 100644
--- a/chrome/browser/notifications/OWNERS
+++ b/chrome/browser/notifications/OWNERS
@@ -8,7 +8,6 @@
 # Mac files
 per-file *_mac*=rsesek@chromium.org
 
-per-file *permission_context*=set noparent
 per-file *permission_context*=file://chrome/browser/permissions/PERMISSIONS_OWNERS
 
 # TEAM: platform-capabilities@chromium.org
diff --git a/chrome/browser/plugins/OWNERS b/chrome/browser/plugins/OWNERS
index 7724296..0566231 100644
--- a/chrome/browser/plugins/OWNERS
+++ b/chrome/browser/plugins/OWNERS
@@ -3,5 +3,4 @@
 per-file flash*=tommycli@chromium.org
 per-file plugin_power_saver*=tommycli@chromium.org
 
-per-file *permission_context*=set noparent
 per-file *permission_context*=file://chrome/browser/permissions/PERMISSIONS_OWNERS
diff --git a/chrome/browser/resources/chromeos/login/images/welcome_illustration_1x.png b/chrome/browser/resources/chromeos/login/images/welcome_illustration_1x.png
index ca7191a..a5631ee 100644
--- a/chrome/browser/resources/chromeos/login/images/welcome_illustration_1x.png
+++ b/chrome/browser/resources/chromeos/login/images/welcome_illustration_1x.png
Binary files differ
diff --git a/chrome/browser/resources/chromeos/login/images/welcome_illustration_2x.png b/chrome/browser/resources/chromeos/login/images/welcome_illustration_2x.png
index 1e317af..e1bed2c9 100644
--- a/chrome/browser/resources/chromeos/login/images/welcome_illustration_2x.png
+++ b/chrome/browser/resources/chromeos/login/images/welcome_illustration_2x.png
Binary files differ
diff --git a/chrome/browser/resources/snippets_internals.css b/chrome/browser/resources/snippets_internals.css
index e84d84cc..f5fbe25 100644
--- a/chrome/browser/resources/snippets_internals.css
+++ b/chrome/browser/resources/snippets_internals.css
@@ -89,3 +89,9 @@
   max-width: 100px;
   min-height: 40px;
 }
+
+#contextual-suggestions-section input {
+  box-sizing: border-box;
+  display: block;
+  width: 100%;
+}
diff --git a/chrome/browser/resources/snippets_internals.html b/chrome/browser/resources/snippets_internals.html
index c704187..b2cb674 100644
--- a/chrome/browser/resources/snippets_internals.html
+++ b/chrome/browser/resources/snippets_internals.html
@@ -12,9 +12,11 @@
 <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
 <link rel="stylesheet" href="snippets_internals.css">
 <script src="chrome://resources/js/cr.js"></script>
+<script src="chrome://resources/js/load_time_data.js"></script>
 <script src="chrome://resources/js/jstemplate_compiled.js"></script>
 <script src="chrome://resources/js/util.js"></script>
 <script src="snippets_internals.js"></script>
+<script src="strings.js"></script>
 
 <div id="info">
    <div>
@@ -224,4 +226,49 @@
     </div>
     <div class="detail" id="content-suggestions-empty"></div>
   </div>
+
+  <div id="contextual-suggestions-section" class="hidden">
+    <h2>Contextual Suggestions</h2>
+    <h3>Request for URL</h3>
+    <input type="url" id="contextual-url"
+        value="https://en.wikipedia.org/wiki/Persian_language"></input>
+    <button id="fetch-contextual-suggestions-button">
+      Fetch Contextual Suggestions
+    </button>
+
+    <h3>Response status</h3>
+    <div id="contextual-suggestions-request-result">
+      No request sent yet.
+    </div>
+
+    <h3>Contextual Suggestions response</h3>
+    <div id="contextual-suggestions">
+      <table class="section-details">
+        <tr jsselect="list" style="display:none">
+          <td class="title-link">
+            <span class="contextual-hidden-toggler content-suggestion-title"
+                jsvalues="hidden-id:id">
+              <span jscontent="title"></span>&gt;&gt;
+            </span>
+            <div jsvalues="id:id" class="content-suggestion-detail hidden">
+              <table>
+                <tr>
+                  <td>ID
+                  <td jscontent="idWithinCategory">
+                <tr>
+                  <td>URL
+                  <td><a class="url" jsvalues="href:url" jscontent="url"></a>
+                <tr>
+                  <td>URL with favicon
+                  <td>
+                    <a class="url" jsvalues="href:urlWithFavicon"
+                        jscontent="urlWithFavicon"></a>
+                <tr>
+                  <td>Publisher name
+                  <td jscontent="publisherName">
+              </table>
+            </div>
+      </table>
+    </div>
+  </div>
 </div>
diff --git a/chrome/browser/resources/snippets_internals.js b/chrome/browser/resources/snippets_internals.js
index e5a737f..73a7b6da 100644
--- a/chrome/browser/resources/snippets_internals.js
+++ b/chrome/browser/resources/snippets_internals.js
@@ -44,6 +44,19 @@
           event.preventDefault();
         });
 
+    if (loadTimeData.getBoolean('contextualSuggestionsEnabled')) {
+      $('contextual-suggestions-section').classList.remove('hidden');
+    }
+
+    $('fetch-contextual-suggestions-button')
+        .addEventListener('click', function(event) {
+          let url = $('contextual-url').value;
+          $('contextual-suggestions-request-result').textContent =
+              'Fetching contextual suggestions for ' + url;
+          chrome.send('fetchContextualSuggestions', [url]);
+          event.preventDefault();
+        });
+
     window.addEventListener('focus', refreshContent);
     window.setInterval(refreshContent, 1000);
 
@@ -54,6 +67,12 @@
     $(propertyId).textContent = value;
   }
 
+  function receiveContextualSuggestions(suggestions, status_msg) {
+    $('contextual-suggestions-request-result').textContent = status_msg;
+    displayList(
+        suggestions, 'contextual-suggestions', 'contextual-hidden-toggler');
+  }
+
   function receiveContentSuggestions(categoriesList) {
     lastSuggestions = categoriesList;
     displayList(categoriesList, 'content-suggestions', 'hidden-toggler');
@@ -184,6 +203,7 @@
     receiveRankerDebugData: receiveRankerDebugData,
     receiveLastRemoteSuggestionsBackgroundFetchTime:
         receiveLastRemoteSuggestionsBackgroundFetchTime,
+    receiveContextualSuggestions: receiveContextualSuggestions,
   };
 });
 
diff --git a/chrome/browser/storage/OWNERS b/chrome/browser/storage/OWNERS
index 558b9a17a..ca88a4f 100644
--- a/chrome/browser/storage/OWNERS
+++ b/chrome/browser/storage/OWNERS
@@ -4,7 +4,6 @@
 
 per-file storage_info_fetcher.*=finnur@chromium.org
 
-per-file *permission_context*=set noparent
 per-file *permission_context*=file://chrome/browser/permissions/PERMISSIONS_OWNERS
 
 # TEAM: storage-dev@chromium.org
diff --git a/chrome/browser/ui/webui/snippets_internals_message_handler.cc b/chrome/browser/ui/webui/snippets_internals_message_handler.cc
index 399751b..441232f6 100644
--- a/chrome/browser/ui/webui/snippets_internals_message_handler.cc
+++ b/chrome/browser/ui/webui/snippets_internals_message_handler.cc
@@ -33,6 +33,7 @@
 #include "components/ntp_snippets/category.h"
 #include "components/ntp_snippets/category_info.h"
 #include "components/ntp_snippets/category_rankers/category_ranker.h"
+#include "components/ntp_snippets/contextual_suggestions_source.h"
 #include "components/ntp_snippets/features.h"
 #include "components/ntp_snippets/pref_names.h"
 #include "components/ntp_snippets/remote/remote_suggestions_fetcher.h"
@@ -43,6 +44,7 @@
 #include "components/prefs/pref_service.h"
 #include "components/variations/variations_associated_data.h"
 #include "content/public/browser/web_ui.h"
+#include "url/gurl.h"
 
 using ntp_snippets::Category;
 using ntp_snippets::CategoryInfo;
@@ -186,7 +188,7 @@
 
   web_ui()->RegisterMessageCallback(
       "clearClassification",
-      base::Bind(&SnippetsInternalsMessageHandler::ClearClassification,
+      base::Bind(&SnippetsInternalsMessageHandler::HandleClearClassification,
                  base::Unretained(this)));
 
   web_ui()->RegisterMessageCallback(
@@ -202,10 +204,16 @@
   web_ui()->RegisterMessageCallback(
       "fetchRemoteSuggestionsInTheBackground",
       base::Bind(&SnippetsInternalsMessageHandler::
-                     FetchRemoteSuggestionsInTheBackground,
+                     HandleFetchRemoteSuggestionsInTheBackground,
                  base::Unretained(this)));
 
   web_ui()->RegisterMessageCallback(
+      "fetchContextualSuggestions",
+      base::Bind(
+          &SnippetsInternalsMessageHandler::HandleFetchContextualSuggestions,
+          base::Unretained(this)));
+
+  web_ui()->RegisterMessageCallback(
       "pushDummySuggestionIn10Seconds",
       base::Bind(&SnippetsInternalsMessageHandler::
                      HandlePushDummySuggestionIn10Seconds,
@@ -352,7 +360,7 @@
   }
 }
 
-void SnippetsInternalsMessageHandler::ClearClassification(
+void SnippetsInternalsMessageHandler::HandleClearClassification(
     const base::ListValue* args) {
   DCHECK_EQ(0u, args->GetSize());
   content_suggestions_service_->user_classifier()
@@ -360,13 +368,43 @@
   SendClassification();
 }
 
-void SnippetsInternalsMessageHandler::FetchRemoteSuggestionsInTheBackground(
-    const base::ListValue* args) {
+void SnippetsInternalsMessageHandler::
+    HandleFetchRemoteSuggestionsInTheBackground(const base::ListValue* args) {
   DCHECK_EQ(0u, args->GetSize());
   remote_suggestions_provider_->RefetchInTheBackground(
       RemoteSuggestionsProvider::FetchStatusCallback());
 }
 
+void SnippetsInternalsMessageHandler::HandleFetchContextualSuggestions(
+    const base::ListValue* args) {
+  DCHECK_EQ(1u, args->GetSize());
+  std::string url_str;
+  args->GetString(0, &url_str);
+  content_suggestions_service_->contextual_suggestions_source()
+      ->FetchContextualSuggestions(
+          GURL(url_str),
+          base::BindOnce(
+              &SnippetsInternalsMessageHandler::OnContextualSuggestionsFetched,
+              weak_ptr_factory_.GetWeakPtr()));
+}
+
+void SnippetsInternalsMessageHandler::OnContextualSuggestionsFetched(
+    ntp_snippets::Status status,
+    const GURL& url,
+    std::vector<ntp_snippets::ContentSuggestion> suggestions) {
+  // Ids start in a range distinct from those created by SendContentSuggestions.
+  int id = 10000;
+  auto suggestions_list = base::MakeUnique<base::ListValue>();
+  for (const ContentSuggestion& suggestion : suggestions) {
+    suggestions_list->Append(PrepareSuggestion(suggestion, id++));
+  }
+  base::DictionaryValue result;
+  result.Set("list", std::move(suggestions_list));
+  web_ui()->CallJavascriptFunctionUnsafe(
+      "chrome.SnippetsInternals.receiveContextualSuggestions", result,
+      base::Value(static_cast<int>(status.code)));
+}
+
 void SnippetsInternalsMessageHandler::HandlePushDummySuggestionIn10Seconds(
     const base::ListValue* args) {
   suggestion_push_timer_.Start(
diff --git a/chrome/browser/ui/webui/snippets_internals_message_handler.h b/chrome/browser/ui/webui/snippets_internals_message_handler.h
index 900ab2d..57808361 100644
--- a/chrome/browser/ui/webui/snippets_internals_message_handler.h
+++ b/chrome/browser/ui/webui/snippets_internals_message_handler.h
@@ -15,8 +15,10 @@
 #include "base/timer/timer.h"
 #include "components/ntp_snippets/category.h"
 #include "components/ntp_snippets/category_status.h"
+#include "components/ntp_snippets/content_suggestion.h"
 #include "components/ntp_snippets/content_suggestions_service.h"
 #include "components/ntp_snippets/remote/remote_suggestions_provider.h"
+#include "components/ntp_snippets/status.h"
 #include "content/public/browser/web_ui_message_handler.h"
 
 namespace base {
@@ -60,8 +62,13 @@
   void HandleClearCachedSuggestions(const base::ListValue* args);
   void HandleClearDismissedSuggestions(const base::ListValue* args);
   void HandleToggleDismissedSuggestions(const base::ListValue* args);
-  void ClearClassification(const base::ListValue* args);
-  void FetchRemoteSuggestionsInTheBackground(const base::ListValue* args);
+  void HandleClearClassification(const base::ListValue* args);
+  void HandleFetchRemoteSuggestionsInTheBackground(const base::ListValue* args);
+  void HandleFetchContextualSuggestions(const base::ListValue* args);
+  void OnContextualSuggestionsFetched(
+      ntp_snippets::Status status_code,
+      const GURL& url,
+      std::vector<ntp_snippets::ContentSuggestion> suggestions);
   void HandlePushDummySuggestionIn10Seconds(const base::ListValue* args);
 
   void SendAllContent();
diff --git a/chrome/browser/ui/webui/snippets_internals_ui.cc b/chrome/browser/ui/webui/snippets_internals_ui.cc
index a8f475d..26eb311 100644
--- a/chrome/browser/ui/webui/snippets_internals_ui.cc
+++ b/chrome/browser/ui/webui/snippets_internals_ui.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/webui/snippets_internals_ui.h"
 
 #include "base/memory/ptr_util.h"
+#include "build/build_config.h"
 #include "chrome/browser/ntp_snippets/content_suggestions_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/snippets_internals_message_handler.h"
@@ -13,12 +14,24 @@
 #include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_data_source.h"
 
+#if defined(OS_ANDROID)
+#include "chrome/browser/android/chrome_feature_list.h"
+#endif
+
 namespace {
 
 content::WebUIDataSource* CreateSnippetsInternalsHTMLSource() {
   content::WebUIDataSource* source =
       content::WebUIDataSource::Create(chrome::kChromeUISnippetsInternalsHost);
 
+#if defined(OS_ANDROID)
+  source->AddBoolean("contextualSuggestionsEnabled",
+                     base::FeatureList::IsEnabled(
+                         chrome::android::kContextualSuggestionsCarousel));
+#else
+  source->AddBoolean("contextualSuggestionsEnabled", false);
+#endif
+  source->SetJsonPath("strings.js");
   source->AddResourcePath("snippets_internals.js", IDR_SNIPPETS_INTERNALS_JS);
   source->AddResourcePath("snippets_internals.css", IDR_SNIPPETS_INTERNALS_CSS);
   source->SetDefaultResource(IDR_SNIPPETS_INTERNALS_HTML);
diff --git a/chrome/browser/ui/webui/webui_webview_browsertest.cc b/chrome/browser/ui/webui/webui_webview_browsertest.cc
index 636e059a..d97dc154 100644
--- a/chrome/browser/ui/webui/webui_webview_browsertest.cc
+++ b/chrome/browser/ui/webui/webui_webview_browsertest.cc
@@ -158,6 +158,12 @@
       base::Value(GetTestUrl("empty.html").spec())));
 }
 
+// TODO(crbug.com/751907) Flaky on CrOS trybots.
+#if defined(OS_CHROMEOS)
+#define MAYBE_AddContentScript DISABLED_AddContentScript
+#else
+#define MAYBE_AddContentScript AddContentScript
+#endif
 IN_PROC_BROWSER_TEST_F(WebUIWebViewBrowserTest, AddContentScript) {
   ui_test_utils::NavigateToURL(browser(), GetWebViewEnabledWebUIURL());
 
@@ -165,6 +171,12 @@
       "testAddContentScript", base::Value(GetTestUrl("empty.html").spec())));
 }
 
+// TODO(crbug.com/751907) Flaky on CrOS trybots.
+#if defined(OS_CHROMEOS)
+#define MAYBE_AddMultiContentScripts DISABLED_AddMultiContentScripts
+#else
+#define MAYBE_AddMultiContentScripts AddMultiContentScripts
+#endif
 IN_PROC_BROWSER_TEST_F(WebUIWebViewBrowserTest, AddMultiContentScripts) {
   ui_test_utils::NavigateToURL(browser(), GetWebViewEnabledWebUIURL());
 
@@ -173,9 +185,17 @@
       base::Value(GetTestUrl("empty.html").spec())));
 }
 
+// TODO(crbug.com/751907) Flaky on CrOS trybots.
+#if defined(OS_CHROMEOS)
+#define MAYBE_AddContentScriptWithSameNameShouldOverwriteTheExistingOne \
+  DISABLED_AddContentScriptWithSameNameShouldOverwriteTheExistingOne
+#else
+#define MAYBE_AddContentScriptWithSameNameShouldOverwriteTheExistingOne \
+  AddContentScriptWithSameNameShouldOverwriteTheExistingOne
+#endif
 IN_PROC_BROWSER_TEST_F(
     WebUIWebViewBrowserTest,
-    AddContentScriptWithSameNameShouldOverwriteTheExistingOne) {
+    MAYBE_AddContentScriptWithSameNameShouldOverwriteTheExistingOne) {
   ui_test_utils::NavigateToURL(browser(), GetWebViewEnabledWebUIURL());
 
   ASSERT_TRUE(WebUIBrowserTest::RunJavascriptAsyncTest(
@@ -193,7 +213,14 @@
       base::Value(GetTestUrl("empty.html").spec())));
 }
 
-IN_PROC_BROWSER_TEST_F(WebUIWebViewBrowserTest, AddAndRemoveContentScripts) {
+// TODO(crbug.com/751907) Flaky on CrOS trybots.
+#if defined(OS_CHROMEOS)
+#define MAYBE_AddAndRemoveContentScripts DISABLED_AddAndRemoveContentScripts
+#else
+#define MAYBE_AddAndRemoveContentScripts AddAndRemoveContentScripts
+#endif
+IN_PROC_BROWSER_TEST_F(WebUIWebViewBrowserTest,
+                       MAYBE_AddAndRemoveContentScripts) {
   ui_test_utils::NavigateToURL(browser(), GetWebViewEnabledWebUIURL());
 
   ASSERT_TRUE(WebUIBrowserTest::RunJavascriptAsyncTest(
@@ -247,9 +274,12 @@
 }
 
 #if defined(OS_CHROMEOS)
+// TODO(crbug.com/662673) Flaky on CrOS trybots.
+#define MAYBE_AddContentScriptIncognito AddContentScriptIncognito
 // Right now we only have incognito WebUI on CrOS, but this should
 // theoretically work for all platforms.
-IN_PROC_BROWSER_TEST_F(WebUIWebViewBrowserTest, AddContentScriptIncognito) {
+IN_PROC_BROWSER_TEST_F(WebUIWebViewBrowserTest,
+                       MAYBE_AddContentScriptIncognito) {
   Browser* incognito_browser =
       OpenURLOffTheRecord(browser()->profile(), GetWebViewEnabledWebUIURL());
 
diff --git a/components/autofill/content/common/autofill_types_struct_traits.cc b/components/autofill/content/common/autofill_types_struct_traits.cc
index ed4c5c4..d76e5b0 100644
--- a/components/autofill/content/common/autofill_types_struct_traits.cc
+++ b/components/autofill/content/common/autofill_types_struct_traits.cc
@@ -604,25 +604,24 @@
 }
 
 // static
-std::vector<autofill::FormFieldData> StructTraits<
-    mojom::PasswordFormFieldPredictionMapDataView,
-    PasswordFormFieldPredictionMap>::keys(const PasswordFormFieldPredictionMap&
-                                              r) {
-  std::vector<autofill::FormFieldData> data;
-  for (const auto& i : r)
-    data.push_back(i.first);
-  return data;
+void* StructTraits<mojom::PasswordFormFieldPredictionMapDataView,
+                   PasswordFormFieldPredictionMap>::
+    SetUpContext(const PasswordFormFieldPredictionMap& r) {
+  // Extracts keys vector and values vector from the map, saves them as a pair.
+  auto* pair = new KeysValuesPair();
+  for (const auto& i : r) {
+    pair->first.push_back(i.first);
+    pair->second.push_back(i.second);
+  }
+
+  return pair;
 }
 
 // static
-std::vector<autofill::PasswordFormFieldPredictionType>
-StructTraits<mojom::PasswordFormFieldPredictionMapDataView,
-             PasswordFormFieldPredictionMap>::
-    values(const PasswordFormFieldPredictionMap& r) {
-  std::vector<autofill::PasswordFormFieldPredictionType> types;
-  for (const auto& i : r)
-    types.push_back(i.second);
-  return types;
+void StructTraits<mojom::PasswordFormFieldPredictionMapDataView,
+                  PasswordFormFieldPredictionMap>::
+    TearDownContext(const PasswordFormFieldPredictionMap& r, void* context) {
+  delete static_cast<KeysValuesPair*>(context);
 }
 
 // static
@@ -647,23 +646,23 @@
 }
 
 // static
-std::vector<autofill::FormData>
-StructTraits<mojom::FormsPredictionsMapDataView, FormsPredictionsMap>::keys(
-    const FormsPredictionsMap& r) {
-  std::vector<autofill::FormData> data;
-  for (const auto& i : r)
-    data.push_back(i.first);
-  return data;
+void* StructTraits<mojom::FormsPredictionsMapDataView,
+                   FormsPredictionsMap>::SetUpContext(const FormsPredictionsMap&
+                                                          r) {
+  // Extracts keys vector and values vector from the map, saves them as a pair.
+  auto* pair = new KeysValuesPair();
+  for (const auto& i : r) {
+    pair->first.push_back(i.first);
+    pair->second.push_back(i.second);
+  }
+
+  return pair;
 }
 
 // static
-std::vector<autofill::PasswordFormFieldPredictionMap>
-StructTraits<mojom::FormsPredictionsMapDataView, FormsPredictionsMap>::values(
-    const FormsPredictionsMap& r) {
-  std::vector<autofill::PasswordFormFieldPredictionMap> maps;
-  for (const auto& i : r)
-    maps.push_back(i.second);
-  return maps;
+void StructTraits<mojom::FormsPredictionsMapDataView, FormsPredictionsMap>::
+    TearDownContext(const FormsPredictionsMap& r, void* context) {
+  delete static_cast<KeysValuesPair*>(context);
 }
 
 // static
diff --git a/components/autofill/content/common/autofill_types_struct_traits.h b/components/autofill/content/common/autofill_types_struct_traits.h
index b98c9dc..0c51ed5 100644
--- a/components/autofill/content/common/autofill_types_struct_traits.h
+++ b/components/autofill/content/common/autofill_types_struct_traits.h
@@ -519,11 +519,26 @@
 template <>
 struct StructTraits<autofill::mojom::PasswordFormFieldPredictionMapDataView,
                     autofill::PasswordFormFieldPredictionMap> {
-  static std::vector<autofill::FormFieldData> keys(
-      const autofill::PasswordFormFieldPredictionMap& r);
+  using KeysValuesPair =
+      std::pair<std::vector<autofill::FormFieldData>,
+                std::vector<autofill::PasswordFormFieldPredictionType>>;
 
-  static std::vector<autofill::PasswordFormFieldPredictionType> values(
-      const autofill::PasswordFormFieldPredictionMap& r);
+  static void* SetUpContext(const autofill::PasswordFormFieldPredictionMap& r);
+
+  static void TearDownContext(const autofill::PasswordFormFieldPredictionMap& r,
+                              void* context);
+
+  static const std::vector<autofill::FormFieldData>& keys(
+      const autofill::PasswordFormFieldPredictionMap& r,
+      void* context) {
+    return static_cast<KeysValuesPair*>(context)->first;
+  }
+
+  static const std::vector<autofill::PasswordFormFieldPredictionType>& values(
+      const autofill::PasswordFormFieldPredictionMap& r,
+      void* context) {
+    return static_cast<KeysValuesPair*>(context)->second;
+  }
 
   static bool Read(autofill::mojom::PasswordFormFieldPredictionMapDataView data,
                    autofill::PasswordFormFieldPredictionMap* out);
@@ -532,11 +547,26 @@
 template <>
 struct StructTraits<autofill::mojom::FormsPredictionsMapDataView,
                     autofill::FormsPredictionsMap> {
-  static std::vector<autofill::FormData> keys(
-      const autofill::FormsPredictionsMap& r);
+  using KeysValuesPair =
+      std::pair<std::vector<autofill::FormData>,
+                std::vector<autofill::PasswordFormFieldPredictionMap>>;
 
-  static std::vector<autofill::PasswordFormFieldPredictionMap> values(
-      const autofill::FormsPredictionsMap& r);
+  static void* SetUpContext(const autofill::FormsPredictionsMap& r);
+
+  static void TearDownContext(const autofill::FormsPredictionsMap& r,
+                              void* context);
+
+  static const std::vector<autofill::FormData>& keys(
+      const autofill::FormsPredictionsMap& r,
+      void* context) {
+    return static_cast<KeysValuesPair*>(context)->first;
+  }
+
+  static const std::vector<autofill::PasswordFormFieldPredictionMap>& values(
+      const autofill::FormsPredictionsMap& r,
+      void* context) {
+    return static_cast<KeysValuesPair*>(context)->second;
+  }
 
   static bool Read(autofill::mojom::FormsPredictionsMapDataView data,
                    autofill::FormsPredictionsMap* out);
diff --git a/components/metrics/metrics_log.cc b/components/metrics/metrics_log.cc
index 7fc04fc..e6215d799 100644
--- a/components/metrics/metrics_log.cc
+++ b/components/metrics/metrics_log.cc
@@ -27,7 +27,6 @@
 #include "components/metrics/metrics_pref_names.h"
 #include "components/metrics/metrics_provider.h"
 #include "components/metrics/metrics_service_client.h"
-#include "components/metrics/persistent_system_profile.h"
 #include "components/metrics/proto/histogram_event.pb.h"
 #include "components/metrics/proto/system_profile.pb.h"
 #include "components/metrics/proto/user_action_event.pb.h"
@@ -88,13 +87,11 @@
 MetricsLog::MetricsLog(const std::string& client_id,
                        int session_id,
                        LogType log_type,
-                       MetricsServiceClient* client,
-                       PrefService* local_state)
+                       MetricsServiceClient* client)
     : closed_(false),
       log_type_(log_type),
       client_(client),
-      creation_time_(base::TimeTicks::Now()),
-      local_state_(local_state) {
+      creation_time_(base::TimeTicks::Now()) {
   if (IsTestingID(client_id))
     uma_proto_.set_client_id(0);
   else
@@ -109,10 +106,6 @@
 
   SystemProfileProto* system_profile = uma_proto()->mutable_system_profile();
   RecordCoreSystemProfile(client_, system_profile);
-  if (log_type_ == ONGOING_LOG) {
-    GlobalPersistentSystemProfile::GetInstance()->SetSystemProfile(
-        *system_profile, /*complete=*/false);
-  }
 }
 
 MetricsLog::~MetricsLog() {
@@ -217,9 +210,6 @@
   // uma log upload, just as we send histogram data.
   WriteRealtimeStabilityAttributes(incremental_uptime, uptime);
 
-  if (local_state_->GetBoolean(prefs::kMetricsResetIds))
-    UMA_HISTOGRAM_BOOLEAN("UMA.IsClonedInstall", true);
-
   delegating_provider->ProvideCurrentSessionData(uma_proto());
 }
 
@@ -269,7 +259,7 @@
     stability->set_uptime_sec(uptime_sec);
 }
 
-std::string MetricsLog::RecordEnvironment(
+const SystemProfileProto& MetricsLog::RecordEnvironment(
     DelegatingProvider* delegating_provider,
     int64_t install_date,
     int64_t metrics_reporting_enabled_date) {
@@ -300,16 +290,7 @@
 
   delegating_provider->ProvideSystemProfileMetrics(system_profile);
 
-  EnvironmentRecorder recorder(local_state_);
-  std::string serialized_proto =
-      recorder.SerializeAndRecordEnvironmentToPrefs(*system_profile);
-
-  if (log_type_ == ONGOING_LOG) {
-    GlobalPersistentSystemProfile::GetInstance()->SetSystemProfile(
-        serialized_proto, /*complete=*/true);
-  }
-
-  return serialized_proto;
+  return *system_profile;
 }
 
 bool MetricsLog::LoadIndependentMetrics(MetricsProvider* metrics_provider) {
@@ -321,12 +302,13 @@
                                                      &snapshot_manager);
 }
 
-bool MetricsLog::LoadSavedEnvironmentFromPrefs(std::string* app_version) {
+bool MetricsLog::LoadSavedEnvironmentFromPrefs(PrefService* local_state,
+                                               std::string* app_version) {
   DCHECK(app_version);
   app_version->clear();
 
   SystemProfileProto* system_profile = uma_proto()->mutable_system_profile();
-  EnvironmentRecorder recorder(local_state_);
+  EnvironmentRecorder recorder(local_state);
   bool success = recorder.LoadEnvironmentFromPrefs(system_profile);
   if (success)
     *app_version = system_profile->app_version();
diff --git a/components/metrics/metrics_log.h b/components/metrics/metrics_log.h
index d113e06..af30a57 100644
--- a/components/metrics/metrics_log.h
+++ b/components/metrics/metrics_log.h
@@ -55,8 +55,7 @@
   MetricsLog(const std::string& client_id,
              int session_id,
              LogType log_type,
-             MetricsServiceClient* client,
-             PrefService* local_state);
+             MetricsServiceClient* client);
   virtual ~MetricsLog();
 
   // Registers local state prefs used by this class.
@@ -91,14 +90,12 @@
   // TODO(rkaplow): I think this can be a little refactored as it currently
   // records a pretty arbitrary set of things.
   // Records the current operating environment, including metrics provided by
-  // the specified |delegating_provider|.  Takes the list of synthetic
-  // trial IDs as a parameter. A synthetic trial is one that is set up
-  // dynamically by code in Chrome. For example, a pref may be mapped to a
-  // synthetic trial such that the group is determined by the pref value. The
-  // current environment is returned serialized as a string.
-  std::string RecordEnvironment(DelegatingProvider* delegating_provider,
-                                int64_t install_date,
-                                int64_t metrics_reporting_enabled_date);
+  // the specified |delegating_provider|. The current environment is
+  // returned as a SystemProfileProto.
+  const SystemProfileProto& RecordEnvironment(
+      DelegatingProvider* delegating_provider,
+      int64_t install_date,
+      int64_t metrics_reporting_enabled_date);
 
   // Loads a saved system profile and the associated metrics into the log.
   // Returns true on success. Keep calling it with fresh logs until it returns
@@ -109,7 +106,8 @@
   // call from prefs. On success, returns true and |app_version| contains the
   // recovered version. Otherwise (if there was no saved environment in prefs
   // or it could not be decoded), returns false and |app_version| is empty.
-  bool LoadSavedEnvironmentFromPrefs(std::string* app_version);
+  bool LoadSavedEnvironmentFromPrefs(PrefService* local_state,
+                                     std::string* app_version);
 
   // Record data from providers about the previous session into the log.
   void RecordPreviousSessionData(DelegatingProvider* delegating_provider);
@@ -181,8 +179,6 @@
   // The time when the current log was created.
   const base::TimeTicks creation_time_;
 
-  PrefService* local_state_;
-
   DISALLOW_COPY_AND_ASSIGN(MetricsLog);
 };
 
diff --git a/components/metrics/metrics_log_manager_unittest.cc b/components/metrics/metrics_log_manager_unittest.cc
index 3dafa34..4857a99 100644
--- a/components/metrics/metrics_log_manager_unittest.cc
+++ b/components/metrics/metrics_log_manager_unittest.cc
@@ -35,7 +35,7 @@
   MetricsLogStore* log_store() { return &log_store_; }
 
   MetricsLog* CreateLog(MetricsLog::LogType log_type) {
-    return new MetricsLog("id", 0, log_type, &client_, &pref_service_);
+    return new MetricsLog("id", 0, log_type, &client_);
   }
 
  private:
diff --git a/components/metrics/metrics_log_store_unittest.cc b/components/metrics/metrics_log_store_unittest.cc
index 5c35274..50b78c7 100644
--- a/components/metrics/metrics_log_store_unittest.cc
+++ b/components/metrics/metrics_log_store_unittest.cc
@@ -21,7 +21,7 @@
   ~MetricsLogStoreTest() override {}
 
   MetricsLog* CreateLog(MetricsLog::LogType log_type) {
-    return new MetricsLog("id", 0, log_type, &client_, &pref_service_);
+    return new MetricsLog("id", 0, log_type, &client_);
   }
 
   // Returns the stored number of logs of the given type.
diff --git a/components/metrics/metrics_log_unittest.cc b/components/metrics/metrics_log_unittest.cc
index 58160a0e7..3a91d46 100644
--- a/components/metrics/metrics_log_unittest.cc
+++ b/components/metrics/metrics_log_unittest.cc
@@ -55,8 +55,7 @@
                  LogType log_type,
                  MetricsServiceClient* client,
                  TestingPrefServiceSimple* prefs)
-      : MetricsLog(client_id, session_id, log_type, client, prefs),
-        prefs_(prefs) {
+      : MetricsLog(client_id, session_id, log_type, client), prefs_(prefs) {
     InitPrefs();
   }
 
@@ -130,10 +129,10 @@
   TestMetricsServiceClient client;
   TestingPrefServiceSimple prefs;
 
-  MetricsLog log1("id", 0, MetricsLog::ONGOING_LOG, &client, &prefs);
+  MetricsLog log1("id", 0, MetricsLog::ONGOING_LOG, &client);
   EXPECT_EQ(MetricsLog::ONGOING_LOG, log1.log_type());
 
-  MetricsLog log2("id", 0, MetricsLog::INITIAL_STABILITY_LOG, &client, &prefs);
+  MetricsLog log2("id", 0, MetricsLog::INITIAL_STABILITY_LOG, &client);
   EXPECT_EQ(MetricsLog::INITIAL_STABILITY_LOG, log2.log_type());
 }
 
@@ -142,7 +141,7 @@
   client.set_version_string("bogus version");
   TestingPrefServiceSimple prefs;
   MetricsLog log("totally bogus client ID", 137, MetricsLog::ONGOING_LOG,
-                 &client, &prefs);
+                 &client);
   log.CloseLog();
 
   std::string encoded;
@@ -257,14 +256,17 @@
       kClientId, kSessionId, MetricsLog::ONGOING_LOG, &client, &prefs_);
 
   DelegatingProvider delegating_provider;
-  log.RecordEnvironment(&delegating_provider, kInstallDate, kEnabledDate);
+  const SystemProfileProto& system_profile =
+      log.RecordEnvironment(&delegating_provider, kInstallDate, kEnabledDate);
+  EnvironmentRecorder writer(&prefs_);
+  writer.SerializeAndRecordEnvironmentToPrefs(system_profile);
   // Check that the system profile on the log has the correct values set.
   CheckSystemProfile(log.system_profile());
 
   // Check that the system profile has also been written to prefs.
   SystemProfileProto decoded_system_profile;
-  EnvironmentRecorder recorder(&prefs_);
-  EXPECT_TRUE(recorder.LoadEnvironmentFromPrefs(&decoded_system_profile));
+  EnvironmentRecorder reader(&prefs_);
+  EXPECT_TRUE(reader.LoadEnvironmentFromPrefs(&decoded_system_profile));
   CheckSystemProfile(decoded_system_profile);
 }
 
diff --git a/components/metrics/metrics_service.cc b/components/metrics/metrics_service.cc
index 5a93e5b..a3aa510 100644
--- a/components/metrics/metrics_service.cc
+++ b/components/metrics/metrics_service.cc
@@ -154,6 +154,7 @@
 #include "components/metrics/metrics_rotation_scheduler.h"
 #include "components/metrics/metrics_service_client.h"
 #include "components/metrics/metrics_state_manager.h"
+#include "components/metrics/persistent_system_profile.h"
 #include "components/metrics/stability_metrics_provider.h"
 #include "components/metrics/url_constants.h"
 #include "components/prefs/pref_registry_simple.h"
@@ -236,6 +237,8 @@
   RegisterMetricsProvider(
       base::MakeUnique<StabilityMetricsProvider>(local_state_));
 
+  RegisterMetricsProvider(state_manager_->GetProvider());
+
   RegisterMetricsProvider(base::MakeUnique<variations::FieldTrialsProvider>(
       &synthetic_trial_registry_, base::StringPiece()));
 }
@@ -316,6 +319,12 @@
 
   state_manager_->ForceClientIdCreation();
   client_->SetMetricsClientId(state_manager_->client_id());
+
+  SystemProfileProto system_profile;
+  MetricsLog::RecordCoreSystemProfile(client_, &system_profile);
+  GlobalPersistentSystemProfile::GetInstance()->SetSystemProfile(
+      system_profile, /*complete=*/false);
+
   if (!log_manager_.current_log())
     OpenNewLog();
 
@@ -733,7 +742,7 @@
   // log describes stats from the _previous_ session.
   std::string system_profile_app_version;
   if (!initial_stability_log->LoadSavedEnvironmentFromPrefs(
-          &system_profile_app_version)) {
+          local_state_, &system_profile_app_version)) {
     return false;
   }
   if (system_profile_app_version != prefs_previous_version)
@@ -812,15 +821,29 @@
 std::unique_ptr<MetricsLog> MetricsService::CreateLog(
     MetricsLog::LogType log_type) {
   return base::MakeUnique<MetricsLog>(state_manager_->client_id(), session_id_,
-                                      log_type, client_, local_state_);
+                                      log_type, client_);
+}
+
+std::string MetricsService::RecordCurrentEnvironmentHelper(
+    MetricsLog* log,
+    PrefService* local_state,
+    DelegatingProvider* delegating_provider,
+    int64_t install_date,
+    int64_t enable_date) {
+  const SystemProfileProto& system_profile =
+      log->RecordEnvironment(delegating_provider, install_date, enable_date);
+  EnvironmentRecorder recorder(local_state);
+  return recorder.SerializeAndRecordEnvironmentToPrefs(system_profile);
 }
 
 void MetricsService::RecordCurrentEnvironment(MetricsLog* log) {
   DCHECK(client_);
-  std::string serialized_environment =
-      log->RecordEnvironment(&delegating_provider_, GetInstallDate(),
-                             GetMetricsReportingEnabledDate());
-  client_->OnEnvironmentUpdate(&serialized_environment);
+  std::string serialized_proto = RecordCurrentEnvironmentHelper(
+      log, local_state_, &delegating_provider_, GetInstallDate(),
+      GetMetricsReportingEnabledDate());
+  GlobalPersistentSystemProfile::GetInstance()->SetSystemProfile(
+      serialized_proto, /*complete=*/true);
+  client_->OnEnvironmentUpdate(&serialized_proto);
 }
 
 void MetricsService::RecordCurrentHistograms() {
diff --git a/components/metrics/metrics_service.h b/components/metrics/metrics_service.h
index cbb53e15..2dfe686 100644
--- a/components/metrics/metrics_service.h
+++ b/components/metrics/metrics_service.h
@@ -183,6 +183,16 @@
     return reporting_service_.metrics_log_store();
   }
 
+  // Records the current environment (system profile) in |log|, and persists
+  // the results in prefs.
+  // Exposed for testing.
+  static std::string RecordCurrentEnvironmentHelper(
+      MetricsLog* log,
+      PrefService* local_state,
+      DelegatingProvider* delegating_provider,
+      int64_t install_date,
+      int64_t enable_date);
+
  private:
   // The MetricsService has a lifecycle that is stored as a state.
   // See metrics_service.cc for description of this lifecycle.
@@ -284,7 +294,9 @@
   // Creates a new MetricsLog instance with the given |log_type|.
   std::unique_ptr<MetricsLog> CreateLog(MetricsLog::LogType log_type);
 
-  // Records the current environment (system profile) in |log|.
+  // Records the current environment (system profile) in |log|, and persists
+  // the results in prefs and GlobalPersistentSystemProfile.
+  // Exposed for testing.
   void RecordCurrentEnvironment(MetricsLog* log);
 
   // Record complete list of histograms into the current log.
diff --git a/components/metrics/metrics_service_unittest.cc b/components/metrics/metrics_service_unittest.cc
index 30d64a7d..bcf85090 100644
--- a/components/metrics/metrics_service_unittest.cc
+++ b/components/metrics/metrics_service_unittest.cc
@@ -56,6 +56,7 @@
 
   using MetricsService::log_manager;
   using MetricsService::log_store;
+  using MetricsService::RecordCurrentEnvironmentHelper;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(TestMetricsService);
@@ -65,13 +66,8 @@
  public:
   TestMetricsLog(const std::string& client_id,
                  int session_id,
-                 MetricsServiceClient* client,
-                 PrefService* local_state)
-      : MetricsLog(client_id,
-                   session_id,
-                   MetricsLog::ONGOING_LOG,
-                   client,
-                   local_state) {}
+                 MetricsServiceClient* client)
+      : MetricsLog(client_id, session_id, MetricsLog::ONGOING_LOG, client) {}
 
   ~TestMetricsLog() override {}
 
@@ -190,9 +186,10 @@
   // Save an existing system profile to prefs, to correspond to what would be
   // saved from a previous session.
   TestMetricsServiceClient client;
-  TestMetricsLog log("client", 1, &client, GetLocalState());
+  TestMetricsLog log("client", 1, &client);
   DelegatingProvider delegating_provider;
-  log.RecordEnvironment(&delegating_provider, 0, 0);
+  TestMetricsService::RecordCurrentEnvironmentHelper(
+      &log, GetLocalState(), &delegating_provider, 0, 0);
 
   // Record stability build time and version from previous session, so that
   // stability metrics (including exited cleanly flag) won't be cleared.
@@ -261,9 +258,10 @@
   // Save an existing system profile to prefs, to correspond to what would be
   // saved from a previous session.
   TestMetricsServiceClient client;
-  TestMetricsLog log("client", 1, &client, GetLocalState());
+  TestMetricsLog log("client", 1, &client);
   DelegatingProvider delegating_provider;
-  log.RecordEnvironment(&delegating_provider, 0, 0);
+  TestMetricsService::RecordCurrentEnvironmentHelper(
+      &log, GetLocalState(), &delegating_provider, 0, 0);
 
   // Record stability build time and version from previous session, so that
   // stability metrics (including exited cleanly flag) won't be cleared.
diff --git a/components/metrics/metrics_state_manager.cc b/components/metrics/metrics_state_manager.cc
index 45c2c48..2e93a8e 100644
--- a/components/metrics/metrics_state_manager.cc
+++ b/components/metrics/metrics_state_manager.cc
@@ -20,6 +20,7 @@
 #include "components/metrics/enabled_state_provider.h"
 #include "components/metrics/machine_id_provider.h"
 #include "components/metrics/metrics_pref_names.h"
+#include "components/metrics/metrics_provider.h"
 #include "components/metrics/metrics_switches.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
@@ -50,6 +51,22 @@
                               low_entropy_source_value);
 }
 
+class MetricsStateMetricsProvider : public MetricsProvider {
+ public:
+  MetricsStateMetricsProvider(PrefService* local_state)
+      : local_state_(local_state) {}
+
+  // MetricsProvider:
+  void ProvideCurrentSessionData(
+      ChromeUserMetricsExtension* uma_proto) override {
+    if (local_state_->GetBoolean(prefs::kMetricsResetIds))
+      UMA_HISTOGRAM_BOOLEAN("UMA.IsClonedInstall", true);
+  }
+
+ private:
+  PrefService* local_state_;
+};
+
 }  // namespace
 
 // static
@@ -81,6 +98,10 @@
   instance_exists_ = false;
 }
 
+std::unique_ptr<MetricsProvider> MetricsStateManager::GetProvider() {
+  return base::MakeUnique<MetricsStateMetricsProvider>(local_state_);
+}
+
 bool MetricsStateManager::IsMetricsReportingEnabled() {
   return enabled_state_provider_->IsReportingEnabled();
 }
diff --git a/components/metrics/metrics_state_manager.h b/components/metrics/metrics_state_manager.h
index fbb0f595..2eb84369 100644
--- a/components/metrics/metrics_state_manager.h
+++ b/components/metrics/metrics_state_manager.h
@@ -23,6 +23,7 @@
 
 class ClonedInstallDetector;
 class EnabledStateProvider;
+class MetricsProvider;
 
 // Responsible for managing MetricsService state prefs, specifically the UMA
 // client id and low entropy source. Code outside the metrics directory should
@@ -41,6 +42,8 @@
 
   virtual ~MetricsStateManager();
 
+  std::unique_ptr<MetricsProvider> GetProvider();
+
   // Returns true if the user has consented to sending metric reports, and there
   // is no other reason to disable reporting. One such reason is client
   // sampling, and this client isn't in the sample.
diff --git a/content/browser/renderer_host/media/media_stream_dispatcher_host.cc b/content/browser/renderer_host/media/media_stream_dispatcher_host.cc
index 1537b46..2a6b586 100644
--- a/content/browser/renderer_host/media/media_stream_dispatcher_host.cc
+++ b/content/browser/renderer_host/media/media_stream_dispatcher_host.cc
@@ -119,6 +119,27 @@
 MediaStreamDispatcherHost::~MediaStreamDispatcherHost() {
 }
 
+void MediaStreamDispatcherHost::DeviceOpenFailed(int render_frame_id,
+                                                 int page_request_id) {
+  DVLOG(1) << __func__ << " page_request_id=" << page_request_id;
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  auto it = dispatchers_.find(render_frame_id);
+  if (it != dispatchers_.end()) {
+    it->second->OnDeviceOpenFailed(page_request_id);
+    return;
+  }
+
+  // TODO(c.padhi): Avoid this hop between threads if possible, see
+  // https://crbug.com/742682.
+  BrowserThread::PostTaskAndReplyWithResult(
+      BrowserThread::UI, FROM_HERE,
+      base::Bind(&GetMediaStreamDispatcherPtrInfo, render_process_id_,
+                 render_frame_id),
+      base::Bind(&MediaStreamDispatcherHost::OnDeviceOpenFailed,
+                 base::Unretained(this), render_frame_id, page_request_id));
+}
+
 void MediaStreamDispatcherHost::GenerateStream(
     int32_t render_frame_id,
     int32_t page_request_id,
@@ -133,10 +154,12 @@
            << " user_gesture=" << user_gesture;
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
-  // TODO(c.padhi): Report GenerateStream failure to renderer, see
-  // https://crbug.com/742682.
-  if (!MediaStreamManager::IsOriginAllowed(render_process_id_, security_origin))
+  if (!MediaStreamManager::IsOriginAllowed(render_process_id_,
+                                           security_origin)) {
+    StreamGenerationFailed(render_frame_id, page_request_id,
+                           MEDIA_DEVICE_INVALID_SECURITY_ORIGIN_DEPRECATED);
     return;
+  }
 
   media_stream_manager_->GenerateStream(
       this, render_process_id_, render_frame_id, salt_, page_request_id,
@@ -174,10 +197,11 @@
            << " security_origin=" << security_origin;
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
-  // TODO(c.padhi): Report OpenDevice failure to renderer, see
-  // https://crbug.com/742682.
-  if (!MediaStreamManager::IsOriginAllowed(render_process_id_, security_origin))
+  if (!MediaStreamManager::IsOriginAllowed(render_process_id_,
+                                           security_origin)) {
+    DeviceOpenFailed(render_frame_id, page_request_id);
     return;
+  }
 
   media_stream_manager_->OpenDevice(this, render_process_id_, render_frame_id,
                                     salt_, page_request_id, device_id, type,
@@ -223,4 +247,17 @@
   dispatchers_[render_frame_id] = std::move(dispatcher);
 }
 
+void MediaStreamDispatcherHost::OnDeviceOpenFailed(
+    int render_frame_id,
+    int page_request_id,
+    mojom::MediaStreamDispatcherPtrInfo dispatcher_info) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  mojom::MediaStreamDispatcherPtr dispatcher =
+      mojo::MakeProxy(std::move(dispatcher_info));
+  DCHECK(dispatcher.is_bound());
+  dispatcher->OnDeviceOpenFailed(page_request_id);
+  dispatchers_[render_frame_id] = std::move(dispatcher);
+}
+
 }  // namespace content
diff --git a/content/browser/renderer_host/media/media_stream_dispatcher_host.h b/content/browser/renderer_host/media/media_stream_dispatcher_host.h
index 888712b..14c6a2ea 100644
--- a/content/browser/renderer_host/media/media_stream_dispatcher_host.h
+++ b/content/browser/renderer_host/media/media_stream_dispatcher_host.h
@@ -70,6 +70,8 @@
  private:
   friend class MockMediaStreamDispatcherHost;
 
+  void DeviceOpenFailed(int render_frame_id, int page_request_id);
+
   // mojom::MediaStreamDispatcherHost implementation
   void GenerateStream(int32_t render_frame_id,
                       int32_t request_id,
@@ -96,6 +98,9 @@
       int page_request_id,
       MediaStreamRequestResult result,
       mojom::MediaStreamDispatcherPtrInfo dispatcher_info);
+  void OnDeviceOpenFailed(int render_frame_id,
+                          int page_request_id,
+                          mojom::MediaStreamDispatcherPtrInfo dispatcher_info);
 
   std::map<int, mojom::MediaStreamDispatcherPtr> dispatchers_;
 
diff --git a/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc b/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc
index ddde9417..a196b0e 100644
--- a/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc
+++ b/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc
@@ -145,6 +145,8 @@
     OnStreamGenerationFailedInternal(request_id, result);
   }
 
+  void OnDeviceOpenFailed(int32_t request_id) override {}
+
   mojom::MediaStreamDispatcherPtr CreateInterfacePtrAndBind() {
     mojom::MediaStreamDispatcherPtr dispatcher;
     binding_.Bind(mojo::MakeRequest(&dispatcher));
diff --git a/content/common/input/input_event_struct_traits.cc b/content/common/input/input_event_struct_traits.cc
index 1c57527..a02c660 100644
--- a/content/common/input/input_event_struct_traits.cc
+++ b/content/common/input/input_event_struct_traits.cc
@@ -366,175 +366,178 @@
   return event.ReadLatency(&((*out)->latency_info));
 }
 
-// static
-content::mojom::KeyDataPtr
-StructTraits<content::mojom::EventDataView, InputEventUniquePtr>::key_data(
-    const InputEventUniquePtr& event) {
-  if (!event->web_event ||
-      !blink::WebInputEvent::IsKeyboardEventType(event->web_event->GetType()))
-    return nullptr;
-  const blink::WebKeyboardEvent* key_event =
-      static_cast<const blink::WebKeyboardEvent*>(event->web_event.get());
-  return content::mojom::KeyData::New(
-      key_event->dom_key, key_event->dom_code, key_event->windows_key_code,
-      key_event->native_key_code, key_event->is_system_key,
-      key_event->is_browser_shortcut, key_event->text,
-      key_event->unmodified_text);
-}
+void* StructTraits<content::mojom::EventDataView,
+                   InputEventUniquePtr>::SetUpContext(const InputEventUniquePtr&
+                                                          event) {
+  InputEventSerializationContext* context =
+      new InputEventSerializationContext();
 
-// static
-content::mojom::PointerDataPtr
-StructTraits<content::mojom::EventDataView, InputEventUniquePtr>::pointer_data(
-    const InputEventUniquePtr& event) {
   if (!event->web_event)
-    return nullptr;
+    return context;
+
+  if (blink::WebInputEvent::IsKeyboardEventType(event->web_event->GetType())) {
+    const blink::WebKeyboardEvent* key_event =
+        static_cast<const blink::WebKeyboardEvent*>(event->web_event.get());
+    context->key_data = content::mojom::KeyData::New(
+        key_event->dom_key, key_event->dom_code, key_event->windows_key_code,
+        key_event->native_key_code, key_event->is_system_key,
+        key_event->is_browser_shortcut, key_event->text,
+        key_event->unmodified_text);
+    return context;
+  }
+  if (blink::WebInputEvent::IsGestureEventType(event->web_event->GetType())) {
+    const blink::WebGestureEvent* gesture_event =
+        static_cast<const blink::WebGestureEvent*>(event->web_event.get());
+
+    context->gesture_data = content::mojom::GestureData::New();
+    content::mojom::GestureDataPtr& gesture_data = context->gesture_data;
+    gesture_data->screen_position = gesture_event->PositionInScreen();
+    gesture_data->widget_position = gesture_event->PositionInWidget();
+    gesture_data->source_device = gesture_event->source_device;
+    gesture_data->unique_touch_event_id = gesture_event->unique_touch_event_id;
+    gesture_data->resending_plugin_id = gesture_event->resending_plugin_id;
+
+    switch (gesture_event->GetType()) {
+      default:
+        break;
+      case blink::WebInputEvent::Type::kGestureTapDown:
+        gesture_data->contact_size =
+            gfx::Size(gesture_event->data.tap_down.width,
+                      gesture_event->data.tap_down.height);
+        break;
+      case blink::WebInputEvent::Type::kGestureShowPress:
+        gesture_data->contact_size =
+            gfx::Size(gesture_event->data.show_press.width,
+                      gesture_event->data.show_press.height);
+        break;
+      case blink::WebInputEvent::Type::kGestureTap:
+      case blink::WebInputEvent::Type::kGestureTapUnconfirmed:
+      case blink::WebInputEvent::Type::kGestureDoubleTap:
+        gesture_data->contact_size = gfx::Size(gesture_event->data.tap.width,
+                                               gesture_event->data.tap.height);
+        gesture_data->tap_data =
+            content::mojom::TapData::New(gesture_event->data.tap.tap_count);
+        break;
+      case blink::WebInputEvent::Type::kGestureLongPress:
+        gesture_data->contact_size =
+            gfx::Size(gesture_event->data.long_press.width,
+                      gesture_event->data.long_press.height);
+        break;
+
+      case blink::WebInputEvent::Type::kGestureTwoFingerTap:
+        gesture_data->contact_size =
+            gfx::Size(gesture_event->data.two_finger_tap.first_finger_width,
+                      gesture_event->data.two_finger_tap.first_finger_height);
+        break;
+      case blink::WebInputEvent::Type::kGestureScrollBegin:
+        gesture_data->scroll_data = content::mojom::ScrollData::New(
+            gesture_event->data.scroll_begin.delta_x_hint,
+            gesture_event->data.scroll_begin.delta_y_hint,
+            gesture_event->data.scroll_begin.delta_hint_units,
+            gesture_event->data.scroll_begin.target_viewport,
+            gesture_event->data.scroll_begin.inertial_phase,
+            gesture_event->data.scroll_begin.synthetic,
+            gesture_event->data.scroll_begin.pointer_count, nullptr);
+        break;
+      case blink::WebInputEvent::Type::kGestureScrollEnd:
+        gesture_data->scroll_data = content::mojom::ScrollData::New(
+            0, 0, gesture_event->data.scroll_end.delta_units, false,
+            gesture_event->data.scroll_end.inertial_phase,
+            gesture_event->data.scroll_end.synthetic, 0, nullptr);
+        break;
+      case blink::WebInputEvent::Type::kGestureScrollUpdate:
+        gesture_data->scroll_data = content::mojom::ScrollData::New(
+            gesture_event->data.scroll_update.delta_x,
+            gesture_event->data.scroll_update.delta_y,
+            gesture_event->data.scroll_update.delta_units, false,
+            gesture_event->data.scroll_update.inertial_phase, false, 0,
+            content::mojom::ScrollUpdate::New(
+                gesture_event->data.scroll_update.velocity_x,
+                gesture_event->data.scroll_update.velocity_y,
+                gesture_event->data.scroll_update
+                    .previous_update_in_sequence_prevented,
+                gesture_event->data.scroll_update.prevent_propagation));
+        break;
+      case blink::WebInputEvent::Type::kGestureFlingStart:
+        gesture_data->fling_data = content::mojom::FlingData::New(
+            gesture_event->data.fling_start.velocity_x,
+            gesture_event->data.fling_start.velocity_y,
+            gesture_event->data.fling_start.target_viewport, false);
+        break;
+      case blink::WebInputEvent::Type::kGestureFlingCancel:
+        gesture_data->fling_data = content::mojom::FlingData::New(
+            0, 0, gesture_event->data.fling_cancel.target_viewport,
+            gesture_event->data.fling_cancel.prevent_boosting);
+        break;
+      case blink::WebInputEvent::Type::kGesturePinchUpdate:
+        gesture_data->pinch_data = content::mojom::PinchData::New(
+            gesture_event->data.pinch_update.zoom_disabled,
+            gesture_event->data.pinch_update.scale);
+        break;
+    }
+    return context;
+  }
+  if (blink::WebInputEvent::IsTouchEventType(event->web_event->GetType())) {
+    const blink::WebTouchEvent* touch_event =
+        static_cast<const blink::WebTouchEvent*>(event->web_event.get());
+
+    context->touch_data = content::mojom::TouchData::New(
+        touch_event->dispatch_type, touch_event->moved_beyond_slop_region,
+        touch_event->touch_start_or_first_touch_move,
+        touch_event->unique_touch_event_id,
+        std::vector<content::mojom::TouchPointPtr>());
+
+    for (unsigned i = 0; i < touch_event->touches_length; ++i) {
+      content::mojom::PointerDataPtr pointer_data =
+          PointerDataFromPointerProperties(touch_event->touches[i], nullptr);
+      context->touch_data->touches.emplace_back(content::mojom::TouchPoint::New(
+          touch_event->touches[i].state, touch_event->touches[i].radius_x,
+          touch_event->touches[i].radius_y,
+          touch_event->touches[i].rotation_angle, std::move(pointer_data)));
+    }
+
+    return context;
+  }
+
   bool is_wheel_event =
       event->web_event->GetType() == blink::WebInputEvent::Type::kMouseWheel;
-  if (!blink::WebInputEvent::IsMouseEventType(event->web_event->GetType()) &&
-      !is_wheel_event) {
-    return nullptr;
-  }
-  const blink::WebMouseEvent* mouse_event =
-      static_cast<const blink::WebMouseEvent*>(event->web_event.get());
+  if (blink::WebInputEvent::IsMouseEventType(event->web_event->GetType()) ||
+      is_wheel_event) {
+    const blink::WebMouseEvent* mouse_event =
+        static_cast<const blink::WebMouseEvent*>(event->web_event.get());
 
-  content::mojom::WheelDataPtr wheel_data;
-  if (is_wheel_event) {
-    const blink::WebMouseWheelEvent* wheel_event =
-        static_cast<const blink::WebMouseWheelEvent*>(mouse_event);
-    wheel_data = content::mojom::WheelData::New(
-        wheel_event->delta_x, wheel_event->delta_y, wheel_event->wheel_ticks_x,
-        wheel_event->wheel_ticks_y, wheel_event->acceleration_ratio_x,
-        wheel_event->acceleration_ratio_y, wheel_event->resending_plugin_id,
-        wheel_event->phase, wheel_event->momentum_phase,
-        wheel_event->scroll_by_page, wheel_event->has_precise_scrolling_deltas,
-        wheel_event->dispatch_type);
+    content::mojom::WheelDataPtr wheel_data;
+    if (is_wheel_event) {
+      const blink::WebMouseWheelEvent* wheel_event =
+          static_cast<const blink::WebMouseWheelEvent*>(mouse_event);
+      wheel_data = content::mojom::WheelData::New(
+          wheel_event->delta_x, wheel_event->delta_y,
+          wheel_event->wheel_ticks_x, wheel_event->wheel_ticks_y,
+          wheel_event->acceleration_ratio_x, wheel_event->acceleration_ratio_y,
+          wheel_event->resending_plugin_id, wheel_event->phase,
+          wheel_event->momentum_phase, wheel_event->scroll_by_page,
+          wheel_event->has_precise_scrolling_deltas,
+          wheel_event->dispatch_type);
+    }
+
+    context->pointer_data = PointerDataFromPointerProperties(
+        *mouse_event, content::mojom::MouseData::New(mouse_event->click_count,
+                                                     std::move(wheel_data)));
+    return context;
   }
 
-  return PointerDataFromPointerProperties(
-      *mouse_event, content::mojom::MouseData::New(mouse_event->click_count,
-                                                   std::move(wheel_data)));
+  return context;
 }
 
-// static
-content::mojom::GestureDataPtr
-StructTraits<content::mojom::EventDataView, InputEventUniquePtr>::gesture_data(
-    const InputEventUniquePtr& event) {
-  if (!event->web_event ||
-      !blink::WebInputEvent::IsGestureEventType(event->web_event->GetType()))
-    return nullptr;
-  const blink::WebGestureEvent* gesture_event =
-      static_cast<const blink::WebGestureEvent*>(event->web_event.get());
-  auto gesture_data = content::mojom::GestureData::New();
-  gesture_data->screen_position = gesture_event->PositionInScreen();
-  gesture_data->widget_position = gesture_event->PositionInWidget();
-  gesture_data->source_device = gesture_event->source_device;
-  gesture_data->unique_touch_event_id = gesture_event->unique_touch_event_id;
-  gesture_data->resending_plugin_id = gesture_event->resending_plugin_id;
-  switch (gesture_event->GetType()) {
-    default:
-      break;
-    case blink::WebInputEvent::Type::kGestureTapDown:
-      gesture_data->contact_size =
-          gfx::Size(gesture_event->data.tap_down.width,
-                    gesture_event->data.tap_down.height);
-      break;
-    case blink::WebInputEvent::Type::kGestureShowPress:
-      gesture_data->contact_size =
-          gfx::Size(gesture_event->data.show_press.width,
-                    gesture_event->data.show_press.height);
-      break;
-    case blink::WebInputEvent::Type::kGestureTap:
-    case blink::WebInputEvent::Type::kGestureTapUnconfirmed:
-    case blink::WebInputEvent::Type::kGestureDoubleTap:
-      gesture_data->contact_size = gfx::Size(gesture_event->data.tap.width,
-                                             gesture_event->data.tap.height);
-      gesture_data->tap_data =
-          content::mojom::TapData::New(gesture_event->data.tap.tap_count);
-      break;
-    case blink::WebInputEvent::Type::kGestureLongPress:
-      gesture_data->contact_size =
-          gfx::Size(gesture_event->data.long_press.width,
-                    gesture_event->data.long_press.height);
-      break;
-
-    case blink::WebInputEvent::Type::kGestureTwoFingerTap:
-      gesture_data->contact_size =
-          gfx::Size(gesture_event->data.two_finger_tap.first_finger_width,
-                    gesture_event->data.two_finger_tap.first_finger_height);
-      break;
-    case blink::WebInputEvent::Type::kGestureScrollBegin:
-      gesture_data->scroll_data = content::mojom::ScrollData::New(
-          gesture_event->data.scroll_begin.delta_x_hint,
-          gesture_event->data.scroll_begin.delta_y_hint,
-          gesture_event->data.scroll_begin.delta_hint_units,
-          gesture_event->data.scroll_begin.target_viewport,
-          gesture_event->data.scroll_begin.inertial_phase,
-          gesture_event->data.scroll_begin.synthetic,
-          gesture_event->data.scroll_begin.pointer_count, nullptr);
-      break;
-    case blink::WebInputEvent::Type::kGestureScrollEnd:
-      gesture_data->scroll_data = content::mojom::ScrollData::New(
-          0, 0, gesture_event->data.scroll_end.delta_units, false,
-          gesture_event->data.scroll_end.inertial_phase,
-          gesture_event->data.scroll_end.synthetic, 0, nullptr);
-      break;
-    case blink::WebInputEvent::Type::kGestureScrollUpdate:
-      gesture_data->scroll_data = content::mojom::ScrollData::New(
-          gesture_event->data.scroll_update.delta_x,
-          gesture_event->data.scroll_update.delta_y,
-          gesture_event->data.scroll_update.delta_units, false,
-          gesture_event->data.scroll_update.inertial_phase, false, 0,
-          content::mojom::ScrollUpdate::New(
-              gesture_event->data.scroll_update.velocity_x,
-              gesture_event->data.scroll_update.velocity_y,
-              gesture_event->data.scroll_update
-                  .previous_update_in_sequence_prevented,
-              gesture_event->data.scroll_update.prevent_propagation));
-      break;
-    case blink::WebInputEvent::Type::kGestureFlingStart:
-      gesture_data->fling_data = content::mojom::FlingData::New(
-          gesture_event->data.fling_start.velocity_x,
-          gesture_event->data.fling_start.velocity_y,
-          gesture_event->data.fling_start.target_viewport, false);
-      break;
-    case blink::WebInputEvent::Type::kGestureFlingCancel:
-      gesture_data->fling_data = content::mojom::FlingData::New(
-          0, 0, gesture_event->data.fling_cancel.target_viewport,
-          gesture_event->data.fling_cancel.prevent_boosting);
-      break;
-    case blink::WebInputEvent::Type::kGesturePinchUpdate:
-      gesture_data->pinch_data = content::mojom::PinchData::New(
-          gesture_event->data.pinch_update.zoom_disabled,
-          gesture_event->data.pinch_update.scale);
-      break;
-  }
-  return gesture_data;
+void StructTraits<content::mojom::EventDataView, InputEventUniquePtr>::
+    TearDownContext(const InputEventUniquePtr& event, void* context) {
+  delete static_cast<InputEventSerializationContext*>(context);
 }
 
-// static
-content::mojom::TouchDataPtr
-StructTraits<content::mojom::EventDataView, InputEventUniquePtr>::touch_data(
-    const InputEventUniquePtr& event) {
-  if (!event->web_event ||
-      !blink::WebInputEvent::IsTouchEventType(event->web_event->GetType()))
-    return nullptr;
+StructTraits<content::mojom::EventDataView, InputEventUniquePtr>::
+    InputEventSerializationContext::InputEventSerializationContext() {}
 
-  const blink::WebTouchEvent* touch_event =
-      static_cast<const blink::WebTouchEvent*>(event->web_event.get());
-  auto touch_data = content::mojom::TouchData::New(
-      touch_event->dispatch_type, touch_event->moved_beyond_slop_region,
-      touch_event->touch_start_or_first_touch_move,
-      touch_event->unique_touch_event_id,
-      std::vector<content::mojom::TouchPointPtr>());
-  for (unsigned i = 0; i < touch_event->touches_length; ++i) {
-    content::mojom::PointerDataPtr pointer_data =
-        PointerDataFromPointerProperties(touch_event->touches[i], nullptr);
-    touch_data->touches.emplace_back(content::mojom::TouchPoint::New(
-        touch_event->touches[i].state, touch_event->touches[i].radius_x,
-        touch_event->touches[i].radius_y,
-        touch_event->touches[i].rotation_angle, std::move(pointer_data)));
-  }
-  return touch_data;
-}
+StructTraits<content::mojom::EventDataView, InputEventUniquePtr>::
+    InputEventSerializationContext::~InputEventSerializationContext() {}
 
 }  // namespace mojo
diff --git a/content/common/input/input_event_struct_traits.h b/content/common/input/input_event_struct_traits.h
index d63ca68..9237448 100644
--- a/content/common/input/input_event_struct_traits.h
+++ b/content/common/input/input_event_struct_traits.h
@@ -33,15 +33,44 @@
     return event->latency_info;
   }
 
-  static content::mojom::KeyDataPtr key_data(const InputEventUniquePtr& event);
-  static content::mojom::PointerDataPtr pointer_data(
-      const InputEventUniquePtr& event);
-  static content::mojom::GestureDataPtr gesture_data(
-      const InputEventUniquePtr& event);
-  static content::mojom::TouchDataPtr touch_data(
-      const InputEventUniquePtr& event);
+  static const content::mojom::KeyDataPtr& key_data(
+      const InputEventUniquePtr& event,
+      void* context) {
+    return static_cast<InputEventSerializationContext*>(context)->key_data;
+  }
+
+  static const content::mojom::PointerDataPtr& pointer_data(
+      const InputEventUniquePtr& event,
+      void* context) {
+    return static_cast<InputEventSerializationContext*>(context)->pointer_data;
+  }
+
+  static const content::mojom::GestureDataPtr& gesture_data(
+      const InputEventUniquePtr& event,
+      void* context) {
+    return static_cast<InputEventSerializationContext*>(context)->gesture_data;
+  }
+
+  static const content::mojom::TouchDataPtr& touch_data(
+      const InputEventUniquePtr& event,
+      void* context) {
+    return static_cast<InputEventSerializationContext*>(context)->touch_data;
+  }
 
   static bool Read(content::mojom::EventDataView r, InputEventUniquePtr* out);
+  static void* SetUpContext(const InputEventUniquePtr& handle);
+  static void TearDownContext(const InputEventUniquePtr& handle, void* context);
+
+ private:
+  struct InputEventSerializationContext {
+    content::mojom::KeyDataPtr key_data;
+    content::mojom::GestureDataPtr gesture_data;
+    content::mojom::PointerDataPtr pointer_data;
+    content::mojom::TouchDataPtr touch_data;
+
+    InputEventSerializationContext();
+    ~InputEventSerializationContext();
+  };
 };
 
 }  // namespace mojo
diff --git a/content/common/media/media_stream.mojom b/content/common/media/media_stream.mojom
index 9ad45f9..8710c68 100644
--- a/content/common/media/media_stream.mojom
+++ b/content/common/media/media_stream.mojom
@@ -57,6 +57,9 @@
 
   // Informs the renderer that browser has failed to generate a stream.
   OnStreamGenerationFailed(int32 request_id, MediaStreamRequestResult result);
+
+  // Informs the renderer that browser has failed to open a device.
+  OnDeviceOpenFailed(int32 request_id);
 };
 
 interface MediaStreamDispatcherHost {
diff --git a/content/common/media/media_stream_messages.h b/content/common/media/media_stream_messages.h
index d1fdc11..e7f08dbf 100644
--- a/content/common/media/media_stream_messages.h
+++ b/content/common/media/media_stream_messages.h
@@ -63,7 +63,3 @@
                     int /* request id */,
                     std::string /* label */,
                     content::StreamDeviceInfo /* the device */)
-
-// The browser has failed to open a device.
-IPC_MESSAGE_ROUTED1(MediaStreamMsg_DeviceOpenFailed,
-                    int /* request id */)
diff --git a/content/common/service_worker/service_worker_fetch_request_struct_traits.cc b/content/common/service_worker/service_worker_fetch_request_struct_traits.cc
index f5f94399..dec7383 100644
--- a/content/common/service_worker/service_worker_fetch_request_struct_traits.cc
+++ b/content/common/service_worker/service_worker_fetch_request_struct_traits.cc
@@ -10,6 +10,19 @@
 
 namespace mojo {
 
+namespace {
+
+// Struct traits context for the FetchAPIRequest type. Since getters are invoked
+// twice when serializing the type, this reduces the load for heavy members.
+struct ServiceWorkerFetchRequestStructTraitsContext {
+  ServiceWorkerFetchRequestStructTraitsContext() = default;
+  ~ServiceWorkerFetchRequestStructTraitsContext() = default;
+
+  std::map<std::string, std::string> headers;
+};
+
+}  // namespace
+
 using blink::mojom::FetchCredentialsMode;
 using blink::mojom::FetchRedirectMode;
 using blink::mojom::FetchRequestMode;
@@ -391,13 +404,29 @@
   return false;
 }
 
-std::map<std::string, std::string>
+void* StructTraits<blink::mojom::FetchAPIRequestDataView,
+                   content::ServiceWorkerFetchRequest>::
+    SetUpContext(const content::ServiceWorkerFetchRequest& request) {
+  ServiceWorkerFetchRequestStructTraitsContext* context =
+      new ServiceWorkerFetchRequestStructTraitsContext();
+  context->headers.insert(request.headers.begin(), request.headers.end());
+
+  return context;
+}
+
+void StructTraits<blink::mojom::FetchAPIRequestDataView,
+                  content::ServiceWorkerFetchRequest>::
+    TearDownContext(const content::ServiceWorkerFetchRequest& request,
+                    void* context) {
+  delete static_cast<ServiceWorkerFetchRequestStructTraitsContext*>(context);
+}
+
+const std::map<std::string, std::string>&
 StructTraits<blink::mojom::FetchAPIRequestDataView,
              content::ServiceWorkerFetchRequest>::
-    headers(const content::ServiceWorkerFetchRequest& request) {
-  std::map<std::string, std::string> header_map;
-  header_map.insert(request.headers.begin(), request.headers.end());
-  return header_map;
+    headers(const content::ServiceWorkerFetchRequest& request, void* context) {
+  return static_cast<ServiceWorkerFetchRequestStructTraitsContext*>(context)
+      ->headers;
 }
 
 bool StructTraits<blink::mojom::FetchAPIRequestDataView,
diff --git a/content/common/service_worker/service_worker_fetch_request_struct_traits.h b/content/common/service_worker/service_worker_fetch_request_struct_traits.h
index c357154..80912e2 100644
--- a/content/common/service_worker/service_worker_fetch_request_struct_traits.h
+++ b/content/common/service_worker/service_worker_fetch_request_struct_traits.h
@@ -73,6 +73,10 @@
 template <>
 struct StructTraits<blink::mojom::FetchAPIRequestDataView,
                     content::ServiceWorkerFetchRequest> {
+  static void* SetUpContext(const content::ServiceWorkerFetchRequest& request);
+  static void TearDownContext(const content::ServiceWorkerFetchRequest& request,
+                              void* context);
+
   static content::FetchRequestMode mode(
       const content::ServiceWorkerFetchRequest& request) {
     return request.mode;
@@ -102,8 +106,9 @@
     return request.method;
   }
 
-  static std::map<std::string, std::string> headers(
-      const content::ServiceWorkerFetchRequest& request);
+  static const std::map<std::string, std::string>& headers(
+      const content::ServiceWorkerFetchRequest& request,
+      void* context);
 
   static const std::string& blob_uuid(
       const content::ServiceWorkerFetchRequest& request) {
diff --git a/content/renderer/media/media_stream_dispatcher.cc b/content/renderer/media/media_stream_dispatcher.cc
index 00a80d3..d1909bf 100644
--- a/content/renderer/media/media_stream_dispatcher.cc
+++ b/content/renderer/media/media_stream_dispatcher.cc
@@ -210,8 +210,6 @@
                         OnDeviceStopped)
     IPC_MESSAGE_HANDLER(MediaStreamMsg_DeviceOpened,
                         OnDeviceOpened)
-    IPC_MESSAGE_HANDLER(MediaStreamMsg_DeviceOpenFailed,
-                        OnDeviceOpenFailed)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
   return handled;
@@ -309,22 +307,6 @@
   }
 }
 
-void MediaStreamDispatcher::OnDeviceOpenFailed(int request_id) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  for (auto it = requests_.begin(); it != requests_.end(); ++it) {
-    Request& request = *it;
-    if (request.ipc_request != request_id)
-      continue;
-    if (request.handler.get()) {
-      request.handler->OnDeviceOpenFailed(request.request_id);
-      DVLOG(1) << __func__ << " request_id=" << request.request_id;
-    }
-    requests_.erase(it);
-    break;
-  }
-}
-
 void MediaStreamDispatcher::OnStreamGenerationFailed(
     int32_t request_id,
     MediaStreamRequestResult result) {
@@ -343,6 +325,22 @@
   }
 }
 
+void MediaStreamDispatcher::OnDeviceOpenFailed(int32_t request_id) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  for (auto it = requests_.begin(); it != requests_.end(); ++it) {
+    Request& request = *it;
+    if (request.ipc_request != request_id)
+      continue;
+    if (request.handler.get()) {
+      request.handler->OnDeviceOpenFailed(request.request_id);
+      DVLOG(1) << __func__ << " request_id=" << request.request_id;
+    }
+    requests_.erase(it);
+    break;
+  }
+}
+
 void MediaStreamDispatcher::BindMediaStreamDispatcherRequest(
     mojom::MediaStreamDispatcherRequest request) {
   binding_.Bind(std::move(request));
diff --git a/content/renderer/media/media_stream_dispatcher.h b/content/renderer/media/media_stream_dispatcher.h
index dbc6be0..3a195e4da 100644
--- a/content/renderer/media/media_stream_dispatcher.h
+++ b/content/renderer/media/media_stream_dispatcher.h
@@ -129,11 +129,11 @@
       int request_id,
       const std::string& label,
       const StreamDeviceInfo& device_info);
-  void OnDeviceOpenFailed(int request_id);
 
   // mojom::MediaStreamDispatcher implementation.
   void OnStreamGenerationFailed(int32_t request_id,
                                 MediaStreamRequestResult result) override;
+  void OnDeviceOpenFailed(int32_t request_id) override;
 
   void BindMediaStreamDispatcherRequest(
       mojom::MediaStreamDispatcherRequest request);
diff --git a/ios/chrome/app/main_controller.mm b/ios/chrome/app/main_controller.mm
index ead40d6..7f41d98e 100644
--- a/ios/chrome/app/main_controller.mm
+++ b/ios/chrome/app/main_controller.mm
@@ -1424,11 +1424,6 @@
     case IDC_SHOW_MAIL_COMPOSER:
       [self.currentBVC chromeExecuteCommand:sender];
       break;
-    case IDC_VOICE_SEARCH: {
-      StartVoiceSearchCommand* command =
-          [[StartVoiceSearchCommand alloc] initWithOriginView:nil];
-      [self startVoiceSearch:command];
-    } break;
 
     case IDC_CLEAR_BROWSING_DATA_IOS: {
       // Clear both the main browser state and the associated incognito
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm
index 0279a644..8fb3ded 100644
--- a/ios/chrome/browser/ui/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -518,7 +518,7 @@
   // Notifies the toolbar menu of reading list changes.
   ReadingListMenuNotifier* _readingListMenuNotifier;
 
-  // The sender for the last received IDC_VOICE_SEARCH command.
+  // The view used by the voice search presentation animation.
   __weak UIView* _voiceSearchButton;
 
   // Coordinator for displaying alerts.
@@ -4213,13 +4213,6 @@
     case IDC_RATE_THIS_APP:
       [self showRateThisAppDialog];
       break;
-    case IDC_VOICE_SEARCH: {
-      // If the voice search command is coming from a UIView sender, store it
-      // before sending the command up the responder chain.
-      StartVoiceSearchCommand* command = [[StartVoiceSearchCommand alloc]
-          initWithOriginView:base::mac::ObjCCast<UIView>(sender)];
-      [self.dispatcher startVoiceSearch:command];
-    } break;
     default:
       // Unknown commands get sent up the responder chain.
       [super chromeExecuteCommand:sender];
diff --git a/ios/chrome/browser/ui/commands/ios_command_ids.h b/ios/chrome/browser/ui/commands/ios_command_ids.h
index 52690363..3cecd7b 100644
--- a/ios/chrome/browser/ui/commands/ios_command_ids.h
+++ b/ios/chrome/browser/ui/commands/ios_command_ids.h
@@ -20,7 +20,6 @@
 #define IDC_SHOW_BOOKMARK_MANAGER                      40011
 #define IDC_HELP_PAGE_VIA_MENU                         40020
 #define IDC_TOGGLE_TAB_SWITCHER                        40901
-#define IDC_VOICE_SEARCH                               40902
 #define IDC_CLOSE_ALL_TABS                             40904
 #define IDC_SHOW_SIGNIN_IOS                            40905
 #define IDC_FIND_CLOSE                                 40907
diff --git a/ios/chrome/browser/ui/favicon/BUILD.gn b/ios/chrome/browser/ui/favicon/BUILD.gn
index d31f2c23..68fdc0eb 100644
--- a/ios/chrome/browser/ui/favicon/BUILD.gn
+++ b/ios/chrome/browser/ui/favicon/BUILD.gn
@@ -27,7 +27,7 @@
   ]
   deps = [
     "//base",
-    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/util:constraints_ui",
   ]
   configs += [ "//build/config/compiler:enable_arc" ]
 }
diff --git a/ios/chrome/browser/ui/ntp/ntp_tile_saver.mm b/ios/chrome/browser/ui/ntp/ntp_tile_saver.mm
index d780004..9d18aa87 100644
--- a/ios/chrome/browser/ui/ntp/ntp_tile_saver.mm
+++ b/ios/chrome/browser/ui/ntp/ntp_tile_saver.mm
@@ -153,6 +153,9 @@
   NSUserDefaults* sharedDefaults =
       [[NSUserDefaults alloc] initWithSuiteName:app_group::ApplicationGroup()];
   [sharedDefaults setObject:data forKey:app_group::kSuggestedItems];
+
+  // TODO(crbug.com/750673): Update the widget's visibility depending on
+  // availability of sites.
 }
 
 NSDictionary* ReadSavedMostVisited() {
diff --git a/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm b/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm
index 07ce8de..a9f84f9c 100644
--- a/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm
+++ b/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm
@@ -514,10 +514,6 @@
                            action:@selector(toolbarVoiceSearchButtonPressed:)
                  forControlEvents:UIControlEventTouchUpInside];
 
-    // Assign tags before calling -setUpButton, since only buttons with tags
-    // have -chromeExecuteCommand added as a target.
-    [_voiceSearchButton setTag:IDC_VOICE_SEARCH];
-
     [_webToolbar addSubview:_voiceSearchButton];
     [_webToolbar addSubview:_starButton];
     [_webToolbar addSubview:_stopButton];
diff --git a/ios/chrome/content_widget_extension/BUILD.gn b/ios/chrome/content_widget_extension/BUILD.gn
index 99d36b62..ee09443 100644
--- a/ios/chrome/content_widget_extension/BUILD.gn
+++ b/ios/chrome/content_widget_extension/BUILD.gn
@@ -44,11 +44,15 @@
     "content_widget_view.mm",
     "content_widget_view_controller.h",
     "content_widget_view_controller.mm",
+    "most_visited_tile_view.h",
+    "most_visited_tile_view.mm",
   ]
 
   deps = [
     "//base",
+    "//ios/chrome/browser/ui/favicon:favicon_ui",
     "//ios/chrome/browser/ui/ntp:ntp_tile",
+    "//ios/chrome/browser/ui/util:constraints_ui",
     "//ios/chrome/common/app_group",
   ]
 
diff --git a/ios/chrome/content_widget_extension/DEPS b/ios/chrome/content_widget_extension/DEPS
index c3b4e83..1c81fa2d8 100644
--- a/ios/chrome/content_widget_extension/DEPS
+++ b/ios/chrome/content_widget_extension/DEPS
@@ -1,4 +1,6 @@
 include_rules = [
   "-url",
+  "+ios/chrome/browser/ui/util",
+  "+ios/chrome/browser/ui/favicon",
   "+ios/chrome/browser/ui/ntp",
 ]
diff --git a/ios/chrome/content_widget_extension/content_widget_view.h b/ios/chrome/content_widget_extension/content_widget_view.h
index aab8a81..450bdd35 100644
--- a/ios/chrome/content_widget_extension/content_widget_view.h
+++ b/ios/chrome/content_widget_extension/content_widget_view.h
@@ -7,7 +7,30 @@
 
 #import <UIKit/UIKit.h>
 
+// View for the content widget. Shows 1 (compact view) or 2 (full size view)
+// rows of 4 most visited tiles (favicon or fallback + title), if there are
+// enough tiles to show. If there are fewer than 4 tiles, always displays a
+// single row.
 @interface ContentWidgetView : UIView
+
+// The height of the widget in expanded mode.
+@property(nonatomic, readonly) CGFloat widgetExpandedHeight;
+
+// Designated initializer, creates the widget view. |compactHeight| indicates
+// the size to use in compact display. |initiallyCompact| indicates which mode
+// to display on initialization.
+- (instancetype)initWithCompactHeight:(CGFloat)compactHeight
+                     initiallyCompact:(BOOL)compact NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE;
+- (instancetype)initWithCoder:(NSCoder*)aDecoder NS_UNAVAILABLE;
+- (instancetype)init NS_UNAVAILABLE;
+
+// Updates the view to display a compact or expanded view, depending on
+// |compact|. If |compact| is false, the view shows a maximum of 8 tiles. If
+// |compact| is true, the view is set to show a single row of 4 tiles at most
+// within the |compactHeight| passed in the constructor.
+- (void)showMode:(BOOL)compact;
+
 @end
 
 #endif  // IOS_CHROME_CONTENT_WIDGET_EXTENSION_CONTENT_WIDGET_VIEW_H_
diff --git a/ios/chrome/content_widget_extension/content_widget_view.mm b/ios/chrome/content_widget_extension/content_widget_view.mm
index 71a436e..dab4fab6 100644
--- a/ios/chrome/content_widget_extension/content_widget_view.mm
+++ b/ios/chrome/content_widget_extension/content_widget_view.mm
@@ -4,12 +4,159 @@
 
 #import "ios/chrome/content_widget_extension/content_widget_view.h"
 
-#include "base/ios/ios_util.h"
-#include "base/logging.h"
+#import "ios/chrome/browser/ui/favicon/favicon_view.h"
+#import "ios/chrome/browser/ui/util/constraints_ui_util.h"
+#import "ios/chrome/content_widget_extension/most_visited_tile_view.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
 
+namespace {
+// Spacing between tiles.
+const CGFloat kTileSpacing = 16;
+// Height of a tile row.
+const CGFloat kTileHeight = 100;
+// Icons to show per row.
+const int kIconsPerRow = 4;
+}
+
+@interface ContentWidgetView ()
+
+// The first row of sites.
+@property(nonatomic, strong) UIView* firstRow;
+// The second row of sites.
+@property(nonatomic, strong) UIView* secondRow;
+// The height used in the compact display mode.
+@property(nonatomic) CGFloat compactHeight;
+// The first row's height constraint. Set its constant to modify the first row's
+// height.
+@property(nonatomic, strong) NSLayoutConstraint* firstRowHeightConstraint;
+// Whether the second row of sites should be shown. False if there are no sites
+// to show in that row.
+@property(nonatomic, readonly) BOOL shouldShowSecondRow;
+// The number of sites to display.
+@property(nonatomic, assign) int siteCount;
+
+// Sets up the widget UI for an expanded or compact appearance based on
+// |compact|.
+- (void)createUI:(BOOL)compact;
+
+// Creates the view for a row of 4 sites.
+- (UIView*)createRowOfSites;
+
+// Returns the height to use for the first row, depending on the display mode.
+- (CGFloat)firstRowHeight:(BOOL)compact;
+
+// Returns the height to use for the second row (can be 0 if the row should not
+// be shown).
+- (CGFloat)secondRowHeight;
+
+@end
+
 @implementation ContentWidgetView
+
+@synthesize firstRow = _firstRow;
+@synthesize secondRow = _secondRow;
+@synthesize compactHeight = _compactHeight;
+@synthesize firstRowHeightConstraint = _firstRowHeightConstraint;
+@synthesize siteCount = _siteCount;
+
+- (instancetype)initWithCompactHeight:(CGFloat)compactHeight
+                     initiallyCompact:(BOOL)compact {
+  self = [super initWithFrame:CGRectZero];
+  if (self) {
+    _compactHeight = compactHeight;
+    [self createUI:compact];
+  }
+  return self;
+}
+
+#pragma mark - properties
+
+- (CGFloat)widgetExpandedHeight {
+  return [self firstRowHeight:NO] + [self secondRowHeight];
+}
+
+- (BOOL)shouldShowSecondRow {
+  return self.siteCount > kIconsPerRow;
+}
+
+#pragma mark - UI creation
+
+- (void)createUI:(BOOL)compact {
+  _firstRow = [self createRowOfSites];
+  _secondRow = [self createRowOfSites];
+
+  [self addSubview:_firstRow];
+  [self addSubview:_secondRow];
+
+  _firstRowHeightConstraint = [_firstRow.heightAnchor
+      constraintEqualToConstant:[self firstRowHeight:compact]];
+
+  [NSLayoutConstraint activateConstraints:@[
+    [_firstRow.topAnchor constraintEqualToAnchor:self.topAnchor],
+    [_secondRow.topAnchor constraintEqualToAnchor:_firstRow.bottomAnchor],
+    [self.leadingAnchor constraintEqualToAnchor:_firstRow.leadingAnchor],
+    [self.leadingAnchor constraintEqualToAnchor:_secondRow.leadingAnchor],
+    [self.trailingAnchor constraintEqualToAnchor:_firstRow.trailingAnchor],
+    [self.trailingAnchor constraintEqualToAnchor:_secondRow.trailingAnchor],
+    _firstRowHeightConstraint,
+  ]];
+}
+
+- (UIView*)createRowOfSites {
+  NSMutableArray<MostVisitedTileView*>* cells = [[NSMutableArray alloc] init];
+  for (int i = 0; i < kIconsPerRow; i++) {
+    cells[i] = [[MostVisitedTileView alloc] init];
+    cells[i].translatesAutoresizingMaskIntoConstraints = NO;
+  }
+
+  UIStackView* stack = [[UIStackView alloc] initWithArrangedSubviews:cells];
+  stack.translatesAutoresizingMaskIntoConstraints = NO;
+  stack.axis = UILayoutConstraintAxisHorizontal;
+  stack.alignment = UIStackViewAlignmentTop;
+  stack.distribution = UIStackViewDistributionEqualSpacing;
+  stack.layoutMargins = UIEdgeInsetsZero;
+  stack.spacing = kTileSpacing;
+  stack.layoutMarginsRelativeArrangement = YES;
+
+  UIView* container = [[UIView alloc] initWithFrame:CGRectZero];
+  container.translatesAutoresizingMaskIntoConstraints = NO;
+  [container addSubview:stack];
+
+  [NSLayoutConstraint activateConstraints:@[
+    [stack.centerYAnchor constraintEqualToAnchor:container.centerYAnchor],
+    [stack.centerXAnchor constraintEqualToAnchor:container.centerXAnchor],
+    [container.heightAnchor constraintGreaterThanOrEqualToConstant:kTileHeight],
+  ]];
+
+  return container;
+}
+
+- (CGFloat)firstRowHeight:(BOOL)compact {
+  if (compact) {
+    return self.compactHeight;
+  }
+
+  CGFloat firstRowHeight = kTileHeight + 2 * kTileSpacing;
+  CGFloat secondRowHeight = [self secondRowHeight];
+  CGFloat totalHeight = firstRowHeight + secondRowHeight;
+  if (totalHeight >= self.compactHeight) {
+    return firstRowHeight;
+  }
+
+  return self.compactHeight - secondRowHeight;
+}
+
+- (CGFloat)secondRowHeight {
+  return self.shouldShowSecondRow ? kTileHeight + kTileSpacing : 0;
+}
+
+#pragma mark - ContentWidgetView
+
+- (void)showMode:(BOOL)compact {
+  self.firstRowHeightConstraint.constant = [self firstRowHeight:compact];
+}
+
 @end
diff --git a/ios/chrome/content_widget_extension/content_widget_view_controller.mm b/ios/chrome/content_widget_extension/content_widget_view_controller.mm
index 204b3631..f3de0bd 100644
--- a/ios/chrome/content_widget_extension/content_widget_view_controller.mm
+++ b/ios/chrome/content_widget_extension/content_widget_view_controller.mm
@@ -10,6 +10,7 @@
 #include "base/mac/foundation_util.h"
 #include "base/strings/sys_string_conversions.h"
 #import "ios/chrome/browser/ui/ntp/ntp_tile.h"
+#import "ios/chrome/browser/ui/util/constraints_ui_util.h"
 #include "ios/chrome/common/app_group/app_group_constants.h"
 #include "ios/chrome/content_widget_extension/content_widget_view.h"
 
@@ -23,11 +24,13 @@
 // cannot be used. This class makes a very basic use of x-callback-url, so no
 // full implementation is required.
 NSString* const kXCallbackURLHost = @"x-callback-url";
+const CGFloat widgetCompactHeightIOS9 = 110;
 }  // namespace
 
 @interface ContentWidgetViewController ()
+@property(nonatomic, strong) NSDictionary<NSURL*, NTPTile*>* sites;
 @property(nonatomic, weak) ContentWidgetView* widgetView;
-@property(nonatomic, strong) NSArray<NTPTile*>* sites;
+@property(nonatomic, readonly) BOOL isCompact;
 
 // Updates the widget with latest data. Returns whether any visual updates
 // occurred.
@@ -41,16 +44,11 @@
 @synthesize sites = _sites;
 @synthesize widgetView = _widgetView;
 
-- (instancetype)init {
-  self = [super init];
-  if (self) {
-    NSUserDefaults* sharedDefaults = [[NSUserDefaults alloc]
-        initWithSuiteName:app_group::ApplicationGroup()];
-    _sites = [NSKeyedUnarchiver
-        unarchiveObjectWithData:[sharedDefaults
-                                    objectForKey:app_group::kSuggestedItems]];
-  }
-  return self;
+#pragma mark - properties
+
+- (BOOL)isCompact {
+  return [self.extensionContext widgetActiveDisplayMode] ==
+         NCWidgetDisplayModeCompact;
 }
 
 #pragma mark - UIViewController
@@ -58,9 +56,18 @@
 - (void)viewDidLoad {
   [super viewDidLoad];
 
+  CGFloat height =
+      self.extensionContext
+          ? [self.extensionContext
+                widgetMaximumSizeForDisplayMode:NCWidgetDisplayModeCompact]
+                .height
+          : widgetCompactHeightIOS9;
+
   // A local variable is necessary here as the property is declared weak and the
   // object would be deallocated before being retained by the addSubview call.
-  ContentWidgetView* widgetView = [[ContentWidgetView alloc] init];
+  ContentWidgetView* widgetView =
+      [[ContentWidgetView alloc] initWithCompactHeight:height
+                                      initiallyCompact:self.isCompact];
   self.widgetView = widgetView;
   [self.view addSubview:self.widgetView];
 
@@ -70,15 +77,7 @@
   }
 
   self.widgetView.translatesAutoresizingMaskIntoConstraints = NO;
-  [NSLayoutConstraint activateConstraints:@[
-    [self.view.leadingAnchor
-        constraintEqualToAnchor:self.widgetView.leadingAnchor],
-    [self.view.trailingAnchor
-        constraintEqualToAnchor:self.widgetView.trailingAnchor],
-    [self.view.topAnchor constraintEqualToAnchor:self.widgetView.topAnchor],
-    [self.view.bottomAnchor
-        constraintEqualToAnchor:self.widgetView.bottomAnchor]
-  ]];
+  AddSameConstraints(self.widgetView, self.view);
 }
 
 - (void)viewWillAppear:(BOOL)animated {
@@ -92,29 +91,32 @@
                                         : NCUpdateResultNoData);
 }
 
+- (void)viewWillTransitionToSize:(CGSize)size
+       withTransitionCoordinator:
+           (id<UIViewControllerTransitionCoordinator>)coordinator {
+  [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
+
+  [coordinator
+      animateAlongsideTransition:^(
+          id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
+        [self.widgetView showMode:self.isCompact];
+      }
+                      completion:nil];
+}
+
 #pragma mark - NCWidgetProviding
 
 - (void)widgetActiveDisplayModeDidChange:(NCWidgetDisplayMode)activeDisplayMode
                          withMaximumSize:(CGSize)maxSize {
-  BOOL isVariableHeight = (activeDisplayMode == NCWidgetDisplayModeExpanded);
-
-  // If the widget's height is not variable, the preferredContentSize is the
-  // maxSize. Widgets cannot be shrunk, and this ensures the view will lay
-  // itself out according to the actual screen size. (This is only likely to
-  // happen if the accessibility option for larger font is used.) If the widget
-  // is not a fixed size, if the fitting size for the widget's contents is
-  // larger than the maximum size for the current widget display mode, this
-  // maximum size is used for the widget. Otherwise, the preferredContentSize is
-  // set to the fitting size so that the widget gets the correct height.
-  if (isVariableHeight) {
-    CGSize fittingSize = [self.widgetView
-        systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
-    if (fittingSize.height < maxSize.height) {
-      self.preferredContentSize = fittingSize;
-      return;
-    }
+  switch (activeDisplayMode) {
+    case NCWidgetDisplayModeCompact:
+      self.preferredContentSize = maxSize;
+      break;
+    case NCWidgetDisplayModeExpanded:
+      self.preferredContentSize =
+          CGSizeMake(maxSize.width, [self.widgetView widgetExpandedHeight]);
+      break;
   }
-  self.preferredContentSize = maxSize;
 }
 
 // Implementing this method removes the leading edge inset for iOS version < 10.
@@ -131,13 +133,13 @@
 - (BOOL)updateWidget {
   NSUserDefaults* sharedDefaults =
       [[NSUserDefaults alloc] initWithSuiteName:app_group::ApplicationGroup()];
-  NSMutableArray<NTPTile*>* newSites = [NSKeyedUnarchiver
+  NSDictionary<NSURL*, NTPTile*>* newSites = [NSKeyedUnarchiver
       unarchiveObjectWithData:[sharedDefaults
                                   objectForKey:app_group::kSuggestedItems]];
-
   if (newSites == self.sites) {
     return NO;
   }
+  self.sites = newSites;
   return YES;
 }
 
diff --git a/ios/chrome/content_widget_extension/most_visited_tile_view.h b/ios/chrome/content_widget_extension/most_visited_tile_view.h
new file mode 100644
index 0000000..c68eabb
--- /dev/null
+++ b/ios/chrome/content_widget_extension/most_visited_tile_view.h
@@ -0,0 +1,24 @@
+// 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 IOS_CHROME_CONTENT_WIDGET_EXTENSION_MOST_VISITED_TILE_VIEW_H_
+#define IOS_CHROME_CONTENT_WIDGET_EXTENSION_MOST_VISITED_TILE_VIEW_H_
+
+#import <UIKit/UIKit.h>
+
+@class FaviconViewNew;
+
+// View to display a Most Visited tile based on the suggestion.
+// It displays the favicon for this Most Visited suggestion and its title.
+@interface MostVisitedTileView : UIView
+
+// FaviconView displaying the favicon.
+@property(nonatomic, strong, readonly, nonnull) FaviconViewNew* faviconView;
+
+// Title of the Most Visited.
+@property(nonatomic, strong, readonly, nonnull) UILabel* titleLabel;
+
+@end
+
+#endif  // IOS_CHROME_CONTENT_WIDGET_EXTENSION_MOST_VISITED_TILE_VIEW_H_
diff --git a/ios/chrome/content_widget_extension/most_visited_tile_view.mm b/ios/chrome/content_widget_extension/most_visited_tile_view.mm
new file mode 100644
index 0000000..fd4d567
--- /dev/null
+++ b/ios/chrome/content_widget_extension/most_visited_tile_view.mm
@@ -0,0 +1,65 @@
+// 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.
+
+#import "ios/chrome/content_widget_extension/most_visited_tile_view.h"
+
+#import "ios/chrome/browser/ui/favicon/favicon_view.h"
+#import "ios/chrome/browser/ui/util/constraints_ui_util.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+const CGFloat kLabelTextColor = 0.314;
+const NSInteger kLabelNumLines = 2;
+const CGFloat kFaviconSize = 48;
+const CGFloat kSpaceFaviconTitle = 8;
+
+// Width of a tile.
+const CGFloat kTileWidth = 73;
+}
+
+@implementation MostVisitedTileView
+
+@synthesize faviconView = _faviconView;
+@synthesize titleLabel = _titleLabel;
+
+#pragma mark - Public
+
+- (instancetype)initWithFrame:(CGRect)frame {
+  self = [super initWithFrame:frame];
+  if (self) {
+    _titleLabel = [[UILabel alloc] initWithFrame:CGRectZero];
+    _titleLabel.textColor = [UIColor colorWithWhite:kLabelTextColor alpha:1.0];
+    _titleLabel.font =
+        [UIFont preferredFontForTextStyle:UIFontTextStyleFootnote];
+    _titleLabel.textAlignment = NSTextAlignmentCenter;
+    _titleLabel.isAccessibilityElement = NO;
+    _titleLabel.numberOfLines = kLabelNumLines;
+
+    _faviconView = [[FaviconViewNew alloc] init];
+    _faviconView.isAccessibilityElement = NO;
+    _faviconView.font =
+        [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline];
+
+    UIStackView* stack = [[UIStackView alloc]
+        initWithArrangedSubviews:@[ _faviconView, _titleLabel ]];
+    stack.axis = UILayoutConstraintAxisVertical;
+    stack.spacing = kSpaceFaviconTitle;
+    stack.alignment = UIStackViewAlignmentCenter;
+    stack.translatesAutoresizingMaskIntoConstraints = NO;
+    [self addSubview:stack];
+    AddSameConstraints(self, stack);
+
+    [NSLayoutConstraint activateConstraints:@[
+      [stack.widthAnchor constraintEqualToConstant:kTileWidth],
+      [_faviconView.widthAnchor constraintEqualToConstant:kFaviconSize],
+      [_faviconView.heightAnchor constraintEqualToConstant:kFaviconSize],
+    ]];
+  }
+  return self;
+}
+
+@end
diff --git a/ios/chrome/today_extension/today_metrics_logger.h b/ios/chrome/today_extension/today_metrics_logger.h
index 7d93f55e..c4d62fdf 100644
--- a/ios/chrome/today_extension/today_metrics_logger.h
+++ b/ios/chrome/today_extension/today_metrics_logger.h
@@ -15,7 +15,6 @@
 namespace base {
 
 class SequencedWorkerPool;
-class SequencedTaskRunner;
 
 }  // namespace base
 
@@ -26,10 +25,6 @@
 
 }  // namespace
 
-class ValueMapPrefStore;
-class PrefRegistrySimple;
-class PrefService;
-
 // Utility class to create metrics log that can be pushed to Chrome. The
 // extension creates and fills the logs with UserAction. The upload is done by
 // the Chrome application.
@@ -56,10 +51,6 @@
   bool CreateNewLog();
 
   base::MessageLoop message_loop_;
-  scoped_refptr<PrefRegistrySimple> pref_registry_;
-  std::unique_ptr<PrefService> pref_service_;
-  scoped_refptr<ValueMapPrefStore> value_map_prefs_;
-  scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner_;
   std::unique_ptr<TodayMetricsLog> log_;
   scoped_refptr<base::SequencedWorkerPool> thread_pool_;
   std::unique_ptr<TodayMetricsServiceClient> metrics_service_client_;
diff --git a/ios/chrome/today_extension/today_metrics_logger.mm b/ios/chrome/today_extension/today_metrics_logger.mm
index 6d02986c..55b210c 100644
--- a/ios/chrome/today_extension/today_metrics_logger.mm
+++ b/ios/chrome/today_extension/today_metrics_logger.mm
@@ -84,8 +84,7 @@
   TodayMetricsLog(const std::string& client_id,
                   int session_id,
                   LogType log_type,
-                  TodayMetricsServiceClient* client,
-                  PrefService* local_state);
+                  TodayMetricsServiceClient* client);
 
   // Fills |encoded_log| with the serialized protobuf representation of the
   // record. Can be called even on open log.
@@ -158,13 +157,8 @@
 TodayMetricsLog::TodayMetricsLog(const std::string& client_id,
                                  int session_id,
                                  LogType log_type,
-                                 TodayMetricsServiceClient* client,
-                                 PrefService* local_state)
-    : metrics::MetricsLog(client_id,
-                          session_id,
-                          log_type,
-                          client,
-                          local_state) {}
+                                 TodayMetricsServiceClient* client)
+    : metrics::MetricsLog(client_id, session_id, log_type, client) {}
 
 void TodayMetricsLog::GetOpenEncodedLog(std::string* encoded_log) const {
   uma_proto()->SerializeToString(encoded_log);
@@ -239,8 +233,7 @@
       session_id, app_group::APP_GROUP_TODAY_EXTENSION);
   log_.reset(new TodayMetricsLog(base::SysNSStringToUTF8(client_id), session_id,
                                  metrics::MetricsLog::ONGOING_LOG,
-                                 metrics_service_client_.get(),
-                                 pref_service_.get()));
+                                 metrics_service_client_.get()));
 
   metrics::DelegatingProvider delegating_provider;
   log_->RecordEnvironment(&delegating_provider, [install_date longLongValue],
@@ -250,25 +243,12 @@
 }
 
 TodayMetricsLogger::TodayMetricsLogger()
-    : pref_registry_(new PrefRegistrySimple()),
-      thread_pool_(
+    : thread_pool_(
           new base::SequencedWorkerPool(2,
                                         "LoggerPool",
                                         base::TaskPriority::BACKGROUND)),
       metrics_service_client_(new TodayMetricsServiceClient()),
       histogram_snapshot_manager_(this) {
-  metrics::MetricsLog::RegisterPrefs(pref_registry_.get());
-
-  NSString* url = [[NSSearchPathForDirectoriesInDomains(
-      NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0]
-      stringByAppendingPathComponent:@"Application Support/localstate"];
-  base::FilePath path(base::SysNSStringToUTF8(url));
-  sequenced_task_runner_ =
-      JsonPrefStore::GetTaskRunnerForFile(path, thread_pool_.get());
-  PrefServiceFactory factory;
-  factory.set_extension_prefs(value_map_prefs_.get());
-  factory.SetUserPrefsFile(path, sequenced_task_runner_.get());
-  pref_service_ = factory.Create(pref_registry_.get());
   base::StatisticsRecorder::Initialize();
 }
 
diff --git a/media/mojo/interfaces/video_frame_struct_traits.cc b/media/mojo/interfaces/video_frame_struct_traits.cc
index bd73cde..c68fed42 100644
--- a/media/mojo/interfaces/video_frame_struct_traits.cc
+++ b/media/mojo/interfaces/video_frame_struct_traits.cc
@@ -56,10 +56,26 @@
 }  // namespace
 
 // static
-media::mojom::VideoFrameDataPtr StructTraits<media::mojom::VideoFrameDataView,
-                                             scoped_refptr<media::VideoFrame>>::
-    data(const scoped_refptr<media::VideoFrame>& input) {
-  return media::mojom::VideoFrameDataPtr(MakeVideoFrameData(input));
+void* StructTraits<media::mojom::VideoFrameDataView,
+                   scoped_refptr<media::VideoFrame>>::
+    SetUpContext(const scoped_refptr<media::VideoFrame>& input) {
+  return new media::mojom::VideoFrameDataPtr(MakeVideoFrameData(input));
+}
+
+// static
+void StructTraits<media::mojom::VideoFrameDataView,
+                  scoped_refptr<media::VideoFrame>>::
+    TearDownContext(const scoped_refptr<media::VideoFrame>& input,
+                    void* context) {
+  delete static_cast<media::mojom::VideoFrameDataPtr*>(context);
+}
+
+// static
+media::mojom::VideoFrameDataPtr&
+StructTraits<media::mojom::VideoFrameDataView,
+             scoped_refptr<media::VideoFrame>>::
+    data(const scoped_refptr<media::VideoFrame>& input, void* context) {
+  return *static_cast<media::mojom::VideoFrameDataPtr*>(context);
 }
 
 // static
diff --git a/media/mojo/interfaces/video_frame_struct_traits.h b/media/mojo/interfaces/video_frame_struct_traits.h
index 712a3270..3324b09 100644
--- a/media/mojo/interfaces/video_frame_struct_traits.h
+++ b/media/mojo/interfaces/video_frame_struct_traits.h
@@ -19,6 +19,11 @@
 template <>
 struct StructTraits<media::mojom::VideoFrameDataView,
                     scoped_refptr<media::VideoFrame>> {
+  static void* SetUpContext(const scoped_refptr<media::VideoFrame>& input);
+
+  static void TearDownContext(const scoped_refptr<media::VideoFrame>&,
+                              void* context);
+
   static bool IsNull(const scoped_refptr<media::VideoFrame>& input) {
     return !input;
   }
@@ -52,8 +57,9 @@
     return input->timestamp();
   }
 
-  static media::mojom::VideoFrameDataPtr data(
-      const scoped_refptr<media::VideoFrame>& input);
+  static media::mojom::VideoFrameDataPtr& data(
+      const scoped_refptr<media::VideoFrame>& input,
+      void* context);
 
   static bool Read(media::mojom::VideoFrameDataView input,
                    scoped_refptr<media::VideoFrame>* output);
diff --git a/mojo/public/cpp/bindings/tests/struct_with_traits_impl_traits.cc b/mojo/public/cpp/bindings/tests/struct_with_traits_impl_traits.cc
index 2586d8d0..6b770b1 100644
--- a/mojo/public/cpp/bindings/tests/struct_with_traits_impl_traits.cc
+++ b/mojo/public/cpp/bindings/tests/struct_with_traits_impl_traits.cc
@@ -5,11 +5,39 @@
 #include "mojo/public/cpp/bindings/tests/struct_with_traits_impl_traits.h"
 
 namespace mojo {
+namespace {
+
+struct Context {
+  int32_t value;
+};
+
+}  // namespace
+
+// static
+void* StructTraits<test::NestedStructWithTraitsDataView,
+                   test::NestedStructWithTraitsImpl>::
+    SetUpContext(const test::NestedStructWithTraitsImpl& input) {
+  Context* context = new Context;
+  context->value = input.value;
+  return context;
+}
+
+// static
+void StructTraits<test::NestedStructWithTraitsDataView,
+                  test::NestedStructWithTraitsImpl>::
+    TearDownContext(const test::NestedStructWithTraitsImpl& input,
+                    void* context) {
+  Context* context_obj = static_cast<Context*>(context);
+  CHECK_EQ(context_obj->value, input.value);
+  delete context_obj;
+}
 
 // static
 int32_t StructTraits<test::NestedStructWithTraitsDataView,
                      test::NestedStructWithTraitsImpl>::
-    value(const test::NestedStructWithTraitsImpl& input) {
+    value(const test::NestedStructWithTraitsImpl& input, void* context) {
+  Context* context_obj = static_cast<Context*>(context);
+  CHECK_EQ(context_obj->value, input.value);
   return input.value;
 }
 
diff --git a/mojo/public/cpp/bindings/tests/struct_with_traits_impl_traits.h b/mojo/public/cpp/bindings/tests/struct_with_traits_impl_traits.h
index 59a5d1a2..3590bd55 100644
--- a/mojo/public/cpp/bindings/tests/struct_with_traits_impl_traits.h
+++ b/mojo/public/cpp/bindings/tests/struct_with_traits_impl_traits.h
@@ -20,7 +20,12 @@
 template <>
 struct StructTraits<test::NestedStructWithTraitsDataView,
                     test::NestedStructWithTraitsImpl> {
-  static int32_t value(const test::NestedStructWithTraitsImpl& input);
+  static void* SetUpContext(const test::NestedStructWithTraitsImpl& input);
+  static void TearDownContext(const test::NestedStructWithTraitsImpl& input,
+                              void* context);
+
+  static int32_t value(const test::NestedStructWithTraitsImpl& input,
+                       void* context);
 
   static bool Read(test::NestedStructWithTraitsDataView data,
                    test::NestedStructWithTraitsImpl* output);
diff --git a/services/identity/public/cpp/scope_set_struct_traits.h b/services/identity/public/cpp/scope_set_struct_traits.h
index 17882b0..467b9065 100644
--- a/services/identity/public/cpp/scope_set_struct_traits.h
+++ b/services/identity/public/cpp/scope_set_struct_traits.h
@@ -11,11 +11,22 @@
 
 template <>
 struct StructTraits<identity::mojom::ScopeSet::DataView, identity::ScopeSet> {
-  static std::vector<std::string> scopes(const identity::ScopeSet& scope_set) {
-    std::vector<std::string> entries;
+  static void* SetUpContext(const identity::ScopeSet& scope_set) {
+    std::vector<std::string>* scopes = new std::vector<std::string>();
     for (const auto& scope : scope_set)
-      entries.push_back(scope);
-    return entries;
+      scopes->push_back(scope);
+    return scopes;
+  }
+
+  static void TearDownContext(const identity::ScopeSet& scope_set,
+                              void* context) {
+    delete static_cast<std::vector<std::string>*>(context);
+  }
+
+  static const std::vector<std::string>& scopes(
+      const identity::ScopeSet& scope_set,
+      void* context) {
+    return *(static_cast<std::vector<std::string>*>(context));
   }
 
   static bool Read(identity::mojom::ScopeSetDataView data,
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 82c6f2c..8ba7ea4f 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -1332,21 +1332,6 @@
             ]
         }
     ],
-    "MacV2Sandbox": [
-        {
-            "platforms": [
-                "mac"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "MacV2Sandbox"
-                    ]
-                }
-            ]
-        }
-    ],
     "MaxDelayableRequestsNetworkOverride": [
         {
             "platforms": [
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 39704c5..527b1d9 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -2258,10 +2258,6 @@
 crbug.com/490511 external/wpt/html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-remove-from-document-networkState.html [ Timeout ]
 crbug.com/675540 external/wpt/service-workers/service-worker/claim-with-redirect.https.html [ Skip ]
 crbug.com/675540 virtual/off-main-thread-fetch/external/wpt/service-workers/service-worker/claim-with-redirect.https.html [ Skip ]
-crbug.com/658997 external/wpt/service-workers/service-worker/clients-matchall-client-types.https.html [ Skip ]
-crbug.com/658997 virtual/off-main-thread-fetch/external/wpt/service-workers/service-worker/clients-matchall-client-types.https.html [ Skip ]
-crbug.com/658997 virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/clients-matchall-client-types.https.html [ Skip ]
-crbug.com/658997 virtual/mojo-blobs/external/wpt/service-workers/service-worker/clients-matchall-client-types.https.html [ Skip ]
 
 crbug.com/435547 http/tests/cachestorage/serviceworker/ignore-search-with-credentials.html [ Skip ]
 crbug.com/435547 virtual/mojo-loading/http/tests/cachestorage/serviceworker/ignore-search-with-credentials.html [ Skip ]
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/dom/reflection-embedded-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/dom/reflection-embedded-expected.txt
index 9904c6c..37c62f4 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/dom/reflection-embedded-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/dom/reflection-embedded-expected.txt
@@ -1,4 +1,5 @@
 This is a testharness.js-based test.
+Found 6750 tests; 6552 PASS, 198 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS img.title: 32 tests
 PASS img.lang: 32 tests
 PASS img.dir: 62 tests
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/dom/reflection-forms-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/dom/reflection-forms-expected.txt
index c0b8795..a2c68eb 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/dom/reflection-forms-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/dom/reflection-forms-expected.txt
@@ -1,4 +1,5 @@
 This is a testharness.js-based test.
+Found 7074 tests; 6624 PASS, 450 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS form.title: 32 tests
 PASS form.lang: 32 tests
 PASS form.dir: 62 tests
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/dom/reflection-metadata-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/dom/reflection-metadata-expected.txt
index 251e93f..450e325 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/dom/reflection-metadata-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/dom/reflection-metadata-expected.txt
@@ -1,4 +1,5 @@
 This is a testharness.js-based test.
+Found 2458 tests; 2344 PASS, 114 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS head.title: 32 tests
 PASS head.lang: 32 tests
 PASS head.dir: 62 tests
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/dom/reflection-misc-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/dom/reflection-misc-expected.txt
index fb97de4..c2de0c6 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/dom/reflection-misc-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/dom/reflection-misc-expected.txt
@@ -1,4 +1,5 @@
 This is a testharness.js-based test.
+Found 3089 tests; 3075 PASS, 14 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS html.title: 32 tests
 PASS html.lang: 32 tests
 PASS html.dir: 62 tests
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/dom/reflection-obsolete-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/dom/reflection-obsolete-expected.txt
index 0cf53ee..dd0a4a5 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/dom/reflection-obsolete-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/dom/reflection-obsolete-expected.txt
@@ -1,4 +1,5 @@
 This is a testharness.js-based test.
+Found 2809 tests; 2351 PASS, 458 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS applet.title: 32 tests
 PASS applet.lang: 32 tests
 PASS applet.dir: 62 tests
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/dom/reflection-tabular-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/dom/reflection-tabular-expected.txt
index 79d4c86..8b828292 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/dom/reflection-tabular-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/dom/reflection-tabular-expected.txt
@@ -1,4 +1,5 @@
 This is a testharness.js-based test.
+Found 4830 tests; 4820 PASS, 10 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS table.title: 32 tests
 PASS table.lang: 32 tests
 PASS table.dir: 62 tests
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/dom/reflection-text-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/dom/reflection-text-expected.txt
index 8bf6b8b..76ee833 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/dom/reflection-text-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/dom/reflection-text-expected.txt
@@ -1,4 +1,5 @@
 This is a testharness.js-based test.
+Found 7799 tests; 7755 PASS, 44 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS a.title: 32 tests
 PASS a.lang: 32 tests
 PASS a.dir: 62 tests
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/clients-matchall-client-types.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/clients-matchall-client-types.https-expected.txt
new file mode 100644
index 0000000..1f2011a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/clients-matchall-client-types.https-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+FAIL Verify matchAll() with window client type assert_unreached: unexpected rejection: assert_array_equals: property 2, expected "https://web-platform.test:8444/service-workers/service-worker/resources/clients-matchall-client-types-iframe.html" but got "https://web-platform.test:8444/service-workers/service-worker/resources/url-modified-via-pushstate.html" Reached unreachable code
+FAIL Verify matchAll() with {window, sharedworker, worker} client types promise_test: Unhandled rejection with value: object "Error: wait_for_state must be passed a ServiceWorker"
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/resources/testharnessreport.js b/third_party/WebKit/LayoutTests/resources/testharnessreport.js
index 7a31e662..337f40f8 100644
--- a/third_party/WebKit/LayoutTests/resources/testharnessreport.js
+++ b/third_party/WebKit/LayoutTests/resources/testharnessreport.js
@@ -175,6 +175,11 @@
                 harness_status.message +
                 "\n";
         }
+
+        // Iterate through tests array and build string that contains
+        // results for all tests.
+        let testResults = "";
+        let resultCounter = [0, 0, 0, 0];
         // reflection tests contain huge number of tests, and Chromium code
         // review tool has the 1MB diff size limit. We merge PASS lines.
         if (output_document.URL.indexOf("/html/dom/reflection") >= 0) {
@@ -188,40 +193,39 @@
                             if (!tests[j].name.startsWith(prefix) || tests[j].status != 0)
                                 break;
                         }
-                        if ((j - i) > 1) {
-                            resultStr += convertResult(tests[i].status) +
-                                " " + sanitize(prefix) + " " + (j - i) + " tests\n"
+                        const numPasses = j - i;
+                        if (numPasses > 1) {
+                            resultCounter[0] += numPasses;
+                            testResults += convertResult(tests[i].status) +
+                                ` ${sanitize(prefix)} ${numPasses} tests\n`;
                             i = j - 1;
                             continue;
                         }
                     }
                 }
-                resultStr += convertResult(tests[i].status) + " " +
+                resultCounter[tests[i].status]++;
+                testResults += convertResult(tests[i].status) + " " +
                     sanitize(tests[i].name) + " " +
                     sanitize(tests[i].message) + "\n";
             }
         } else {
-            // Iterate through tests array and build string that contains
-            // results for all tests.
-            let testResults = "";
-            let resultCounter = [0, 0, 0, 0];
             for (var i = 0; i < tests.length; ++i) {
                 resultCounter[tests[i].status]++;
                 testResults += convertResult(tests[i].status) + " " +
                     sanitize(tests[i].name) + " " +
                     sanitize(tests[i].message) + "\n";
             }
-            if (output_document.URL.indexOf("http://web-platform.test") >= 0 &&
-                tests.length >= 50 && (resultCounter[1] || resultCounter[2] || resultCounter[3])) {
-                // Output failure metrics if there are many.
-                resultStr += `Found ${tests.length} tests;` +
-                    ` ${resultCounter[0]} PASS,` +
-                    ` ${resultCounter[1]} FAIL,` +
-                    ` ${resultCounter[2]} TIMEOUT,` +
-                    ` ${resultCounter[3]} NOTRUN.\n`;
-            }
-            resultStr += testResults;
         }
+        if (output_document.URL.indexOf("http://web-platform.test") >= 0 &&
+            tests.length >= 50 && (resultCounter[1] || resultCounter[2] || resultCounter[3])) {
+            // Output failure metrics if there are many.
+            resultStr += `Found ${tests.length} tests;` +
+                ` ${resultCounter[0]} PASS,` +
+                ` ${resultCounter[1]} FAIL,` +
+                ` ${resultCounter[2]} TIMEOUT,` +
+                ` ${resultCounter[3]} NOTRUN.\n`;
+        }
+        resultStr += testResults;
 
         resultStr += "Harness: the test ran to completion.\n";
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutTheme.cpp b/third_party/WebKit/Source/core/layout/LayoutTheme.cpp
index 45bf894..3612784 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTheme.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutTheme.cpp
@@ -57,11 +57,18 @@
 #include "public/platform/Platform.h"
 #include "public/platform/WebFallbackThemeEngine.h"
 #include "public/platform/WebRect.h"
+#include "public/web/WebKit.h"
 
 // The methods in this file are shared by all themes on every platform.
 
 namespace blink {
 
+// Wrapper function defined in WebKit.h
+void SetMockThemeEnabledForTest(bool value) {
+  LayoutTestSupport::SetMockThemeEnabledForTest(value);
+  LayoutTheme::GetTheme().DidChangeThemeEngine();
+}
+
 using namespace HTMLNames;
 
 LayoutTheme& LayoutTheme::GetTheme() {
diff --git a/third_party/WebKit/Source/core/page/Page.cpp b/third_party/WebKit/Source/core/page/Page.cpp
index 2d86a7e..cadab3e 100644
--- a/third_party/WebKit/Source/core/page/Page.cpp
+++ b/third_party/WebKit/Source/core/page/Page.cpp
@@ -64,9 +64,17 @@
 #include "platform/plugins/PluginData.h"
 #include "platform/scroll/SmoothScrollSequencer.h"
 #include "public/platform/Platform.h"
+#include "public/web/WebKit.h"
 
 namespace blink {
 
+// Wrapper function defined in WebKit.h
+void ResetPluginCache(bool reload_pages) {
+  DCHECK(!reload_pages);
+  Page::RefreshPlugins();
+  Page::ResetPluginData();
+}
+
 // Set of all live pages; includes internal Page objects that are
 // not observable from scripts.
 static Page::PageSet& AllPages() {
diff --git a/third_party/WebKit/Source/core/workers/WorkerBackingThread.cpp b/third_party/WebKit/Source/core/workers/WorkerBackingThread.cpp
index a632bb7..a070ff8 100644
--- a/third_party/WebKit/Source/core/workers/WorkerBackingThread.cpp
+++ b/third_party/WebKit/Source/core/workers/WorkerBackingThread.cpp
@@ -18,9 +18,20 @@
 #include "platform/wtf/PtrUtil.h"
 #include "public/platform/Platform.h"
 #include "public/platform/WebTraceLocation.h"
+#include "public/web/WebKit.h"
 
 namespace blink {
 
+// Wrapper functions defined in WebKit.h
+void MemoryPressureNotificationToWorkerThreadIsolates(
+    v8::MemoryPressureLevel level) {
+  WorkerBackingThread::MemoryPressureNotificationToWorkerThreadIsolates(level);
+}
+
+void SetRAILModeOnWorkerThreadIsolates(v8::RAILMode rail_mode) {
+  WorkerBackingThread::SetRAILModeOnWorkerThreadIsolates(rail_mode);
+}
+
 static Mutex& IsolatesMutex() {
   DEFINE_THREAD_SAFE_STATIC_LOCAL(Mutex, mutex, ());
   return mutex;
diff --git a/third_party/WebKit/Source/platform/DEPS b/third_party/WebKit/Source/platform/DEPS
index 5f473f6..e935b5e5 100644
--- a/third_party/WebKit/Source/platform/DEPS
+++ b/third_party/WebKit/Source/platform/DEPS
@@ -39,6 +39,8 @@
     "+mozilla",
     "+platform",
     "+public/platform",
+    #TODO(nverne): remove this
+    "+public/web/WebKit.h",
     "+skia/ext",
     "+third_party/ced/src/compact_enc_det/compact_enc_det.h",
     "+third_party/khronos",
diff --git a/third_party/WebKit/Source/platform/LayoutTestSupport.cpp b/third_party/WebKit/Source/platform/LayoutTestSupport.cpp
index 81cc1e4..f41932b1 100644
--- a/third_party/WebKit/Source/platform/LayoutTestSupport.cpp
+++ b/third_party/WebKit/Source/platform/LayoutTestSupport.cpp
@@ -31,9 +31,27 @@
 #include "platform/LayoutTestSupport.h"
 
 #include "platform/wtf/Assertions.h"
+#include "public/web/WebKit.h"
 
 namespace blink {
 
+// Wrapper functions defined in WebKit.h
+void SetLayoutTestMode(bool value) {
+  LayoutTestSupport::SetIsRunningLayoutTest(value);
+}
+
+bool LayoutTestMode() {
+  return LayoutTestSupport::IsRunningLayoutTest();
+}
+
+void SetFontAntialiasingEnabledForTest(bool value) {
+  LayoutTestSupport::SetFontAntialiasingEnabledForTest(value);
+}
+
+bool FontAntialiasingEnabledForTest() {
+  return LayoutTestSupport::IsFontAntialiasingEnabledForTest();
+}
+
 static bool g_is_running_layout_test = false;
 static bool g_is_mock_theme_enabled = false;
 static bool g_is_font_antialiasing_enabled = false;
diff --git a/third_party/WebKit/Source/platform/MemoryCoordinator.cpp b/third_party/WebKit/Source/platform/MemoryCoordinator.cpp
index 4afa2b0f..a005c613f 100644
--- a/third_party/WebKit/Source/platform/MemoryCoordinator.cpp
+++ b/third_party/WebKit/Source/platform/MemoryCoordinator.cpp
@@ -12,6 +12,7 @@
 #include "platform/instrumentation/tracing/TraceEvent.h"
 #include "platform/wtf/allocator/Partitions.h"
 #include "public/platform/WebThread.h"
+#include "public/web/WebKit.h"
 
 #if defined(OS_ANDROID)
 #include "base/android/sys_utils.h"
@@ -19,6 +20,11 @@
 
 namespace blink {
 
+// Wrapper function defined in WebKit.h
+void DecommitFreeableMemory() {
+  WTF::Partitions::DecommitFreeableMemory();
+}
+
 // static
 bool MemoryCoordinator::is_low_end_device_ = false;
 int64_t MemoryCoordinator::physical_memory_mb_ = 0;
diff --git a/third_party/WebKit/Source/platform/bindings/RuntimeCallStats.cpp b/third_party/WebKit/Source/platform/bindings/RuntimeCallStats.cpp
index 8923142..3617883 100644
--- a/third_party/WebKit/Source/platform/bindings/RuntimeCallStats.cpp
+++ b/third_party/WebKit/Source/platform/bindings/RuntimeCallStats.cpp
@@ -8,9 +8,17 @@
 #include <algorithm>
 #include "platform/bindings/V8PerIsolateData.h"
 #include "platform/wtf/text/StringBuilder.h"
+#include "public/web/WebKit.h"
 
 namespace blink {
 
+// Wrapper function defined in WebKit.h
+void LogRuntimeCallStats() {
+  LOG(INFO)
+      << "\n"
+      << RuntimeCallStats::From(MainThreadIsolate())->ToString().Utf8().data();
+}
+
 namespace {
 RuntimeCallStats* g_runtime_call_stats_for_testing = nullptr;
 }
diff --git a/third_party/WebKit/Source/platform/bindings/V8PerIsolateData.cpp b/third_party/WebKit/Source/platform/bindings/V8PerIsolateData.cpp
index 6ba47d5..98d32aa2 100644
--- a/third_party/WebKit/Source/platform/bindings/V8PerIsolateData.cpp
+++ b/third_party/WebKit/Source/platform/bindings/V8PerIsolateData.cpp
@@ -37,10 +37,16 @@
 #include "platform/wtf/LeakAnnotations.h"
 #include "platform/wtf/PtrUtil.h"
 #include "public/platform/Platform.h"
+#include "public/web/WebKit.h"
 #include "v8/include/v8-debug.h"
 
 namespace blink {
 
+// Wrapper function defined in WebKit.h
+v8::Isolate* MainThreadIsolate() {
+  return V8PerIsolateData::MainThreadIsolate();
+}
+
 static V8PerIsolateData* g_main_thread_per_isolate_data = 0;
 
 static void BeforeCallEnteredCallback(v8::Isolate* isolate) {
diff --git a/third_party/WebKit/Source/platform/mojo/FetchAPIRequestStructTraits.cpp b/third_party/WebKit/Source/platform/mojo/FetchAPIRequestStructTraits.cpp
index ccb34a29..aa67d0c 100644
--- a/third_party/WebKit/Source/platform/mojo/FetchAPIRequestStructTraits.cpp
+++ b/third_party/WebKit/Source/platform/mojo/FetchAPIRequestStructTraits.cpp
@@ -14,6 +14,19 @@
 
 namespace mojo {
 
+namespace {
+
+// Struct traits context for the FetchAPIRequest type. Since getters are invoked
+// twice when serializing the type, this reduces the load for heavy members.
+struct FetchAPIRequestStructTraitsContext {
+  FetchAPIRequestStructTraitsContext() = default;
+  ~FetchAPIRequestStructTraitsContext() = default;
+
+  WTF::HashMap<WTF::String, WTF::String> headers;
+};
+
+}  // namespace
+
 using blink::mojom::FetchCredentialsMode;
 using blink::mojom::FetchRedirectMode;
 using blink::mojom::FetchRequestMode;
@@ -367,6 +380,26 @@
 }
 
 // static
+void* StructTraits<blink::mojom::FetchAPIRequestDataView,
+                   blink::WebServiceWorkerRequest>::
+    SetUpContext(const blink::WebServiceWorkerRequest& request) {
+  FetchAPIRequestStructTraitsContext* context =
+      new FetchAPIRequestStructTraitsContext();
+  for (const auto& pair : request.Headers())
+    context->headers.insert(pair.key, pair.value);
+
+  return context;
+}
+
+// static
+void StructTraits<blink::mojom::FetchAPIRequestDataView,
+                  blink::WebServiceWorkerRequest>::
+    TearDownContext(const blink::WebServiceWorkerRequest& request,
+                    void* context) {
+  delete static_cast<FetchAPIRequestStructTraitsContext*>(context);
+}
+
+// static
 blink::KURL StructTraits<blink::mojom::FetchAPIRequestDataView,
                          blink::WebServiceWorkerRequest>::
     url(const blink::WebServiceWorkerRequest& request) {
@@ -381,14 +414,12 @@
 }
 
 // static
-WTF::HashMap<WTF::String, WTF::String>
+const WTF::HashMap<WTF::String, WTF::String>&
 StructTraits<blink::mojom::FetchAPIRequestDataView,
              blink::WebServiceWorkerRequest>::
-    headers(const blink::WebServiceWorkerRequest& request) {
-  WTF::HashMap<WTF::String, WTF::String> header_map;
-  for (const auto& pair : request.Headers())
-    header_map.insert(pair.key, pair.value);
-  return header_map;
+    headers(const blink::WebServiceWorkerRequest& request, void* context) {
+  DCHECK(context);
+  return static_cast<FetchAPIRequestStructTraitsContext*>(context)->headers;
 }
 
 // static
diff --git a/third_party/WebKit/Source/platform/mojo/FetchAPIRequestStructTraits.h b/third_party/WebKit/Source/platform/mojo/FetchAPIRequestStructTraits.h
index e054128..a28b1e5c 100644
--- a/third_party/WebKit/Source/platform/mojo/FetchAPIRequestStructTraits.h
+++ b/third_party/WebKit/Source/platform/mojo/FetchAPIRequestStructTraits.h
@@ -68,6 +68,10 @@
 template <>
 struct StructTraits<blink::mojom::FetchAPIRequestDataView,
                     blink::WebServiceWorkerRequest> {
+  static void* SetUpContext(const blink::WebServiceWorkerRequest&);
+  static void TearDownContext(const blink::WebServiceWorkerRequest&,
+                              void* context);
+
   static blink::WebURLRequest::FetchRequestMode mode(
       const blink::WebServiceWorkerRequest& request) {
     return request.Mode();
@@ -92,8 +96,9 @@
 
   static WTF::String method(const blink::WebServiceWorkerRequest&);
 
-  static WTF::HashMap<WTF::String, WTF::String> headers(
-      const blink::WebServiceWorkerRequest&);
+  static const WTF::HashMap<WTF::String, WTF::String>& headers(
+      const blink::WebServiceWorkerRequest&,
+      void* context);
 
   static WTF::String blob_uuid(const blink::WebServiceWorkerRequest&);
 
diff --git a/third_party/WebKit/Source/web/BUILD.gn b/third_party/WebKit/Source/web/BUILD.gn
index 176c6c9d..1341043d 100644
--- a/third_party/WebKit/Source/web/BUILD.gn
+++ b/third_party/WebKit/Source/web/BUILD.gn
@@ -37,8 +37,6 @@
 
   sources = [
     "AssertMatchingEnums.cpp",
-    "WebExport.h",
-    "WebKit.cpp",
   ]
 
   if (is_mac) {
diff --git a/third_party/WebKit/Source/web/WebExport.h b/third_party/WebKit/Source/web/WebExport.h
deleted file mode 100644
index 57ab557..0000000
--- a/third_party/WebKit/Source/web/WebExport.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef WebExport_h
-#define WebExport_h
-
-#include "platform/wtf/Compiler.h"
-
-namespace blink {
-
-// This macro is intended to export symbols in Source/web/ which are still
-// private to Blink (for instance, because they are used in unit tests).
-
-#if defined(COMPONENT_BUILD)
-#if defined(WIN32)
-#if BLINK_WEB_IMPLEMENTATION
-#define WEB_EXPORT __declspec(dllexport)
-#else
-#define WEB_EXPORT __declspec(dllimport)
-#endif  // BLINK_WEB_IMPLEMENTATION
-#else   // defined(WIN32)
-#define WEB_EXPORT __attribute__((visibility("default")))
-#endif
-#else  // defined(COMPONENT_BUILD)
-#define WEB_EXPORT
-#endif
-
-}  // namespace blink
-
-#endif  // WebExport_h
diff --git a/third_party/WebKit/Source/web/WebKit.cpp b/third_party/WebKit/Source/web/WebKit.cpp
deleted file mode 100644
index 54d56cd0..0000000
--- a/third_party/WebKit/Source/web/WebKit.cpp
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2009 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "public/web/WebKit.h"
-
-#include <memory>
-
-#include "bindings/core/v8/V8BindingForCore.h"
-#include "bindings/core/v8/V8GCController.h"
-#include "core/layout/LayoutTheme.h"
-#include "core/page/Page.h"
-#include "core/workers/WorkerBackingThread.h"
-#include "gin/public/v8_platform.h"
-#include "platform/LayoutTestSupport.h"
-#include "platform/heap/Heap.h"
-#include "platform/wtf/Assertions.h"
-#include "platform/wtf/PtrUtil.h"
-#include "platform/wtf/WTF.h"
-#include "platform/wtf/allocator/Partitions.h"
-#include "platform/wtf/text/AtomicString.h"
-#include "platform/wtf/text/TextEncoding.h"
-
-namespace blink {
-
-v8::Isolate* MainThreadIsolate() {
-  return V8PerIsolateData::MainThreadIsolate();
-}
-
-// TODO(tkent): The following functions to wrap LayoutTestSupport should be
-// moved to public/platform/.
-
-void SetLayoutTestMode(bool value) {
-  LayoutTestSupport::SetIsRunningLayoutTest(value);
-}
-
-bool LayoutTestMode() {
-  return LayoutTestSupport::IsRunningLayoutTest();
-}
-
-void SetMockThemeEnabledForTest(bool value) {
-  LayoutTestSupport::SetMockThemeEnabledForTest(value);
-  LayoutTheme::GetTheme().DidChangeThemeEngine();
-}
-
-void SetFontAntialiasingEnabledForTest(bool value) {
-  LayoutTestSupport::SetFontAntialiasingEnabledForTest(value);
-}
-
-bool FontAntialiasingEnabledForTest() {
-  return LayoutTestSupport::IsFontAntialiasingEnabledForTest();
-}
-
-void ResetPluginCache(bool reload_pages) {
-  DCHECK(!reload_pages);
-  Page::RefreshPlugins();
-  Page::ResetPluginData();
-}
-
-void DecommitFreeableMemory() {
-  WTF::Partitions::DecommitFreeableMemory();
-}
-
-void MemoryPressureNotificationToWorkerThreadIsolates(
-    v8::MemoryPressureLevel level) {
-  WorkerBackingThread::MemoryPressureNotificationToWorkerThreadIsolates(level);
-}
-
-void SetRAILModeOnWorkerThreadIsolates(v8::RAILMode rail_mode) {
-  WorkerBackingThread::SetRAILModeOnWorkerThreadIsolates(rail_mode);
-}
-
-void LogRuntimeCallStats() {
-  LOG(INFO)
-      << "\n"
-      << RuntimeCallStats::From(MainThreadIsolate())->ToString().Utf8().data();
-}
-
-}  // namespace blink
diff --git a/third_party/freetype/README.chromium b/third_party/freetype/README.chromium
index 207879b2..01234c0 100644
--- a/third_party/freetype/README.chromium
+++ b/third_party/freetype/README.chromium
@@ -1,7 +1,7 @@
 Name: FreeType
 URL: http://www.freetype.org/
-Version: VER-2-8-73
-Revision: 38bdf22bfe68432aebdd33c198a0bd11b4ebb96f
+Version: VER-2-8-78
+Revision: 7e50824288fac5a36c2938fdb3e1c949ea53f982
 License: Custom license "inspired by the BSD, Artistic, and IJG (Independent
          JPEG Group) licenses"
 License File: src/docs/FTL.TXT
diff --git a/tools/accessibility/nvda/nvda_chrome_tests.py b/tools/accessibility/nvda/nvda_chrome_tests.py
index 6cbfd1b3..67d2fb6c 100755
--- a/tools/accessibility/nvda/nvda_chrome_tests.py
+++ b/tools/accessibility/nvda/nvda_chrome_tests.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python
-# Copyright 2014 The Chromium Authors. All rights reserved.
+# 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.
 
@@ -52,13 +52,13 @@
 class NvdaChromeTest(unittest.TestCase):
   @classmethod
   def setUpClass(cls):
-    print 'user data: %s' % CHROME_PROFILES_PATH
-    print 'chrome: %s' % CHROME_PATH
-    print 'nvda: %s' % NVDA_PATH
-    print 'nvda_proctest: %s' % NVDA_PROCTEST_PATH
+    print('user data: %s' % CHROME_PROFILES_PATH)
+    print('chrome: %s' % CHROME_PATH)
+    print('nvda: %s' % NVDA_PATH)
+    print('nvda_proctest: %s' % NVDA_PROCTEST_PATH)
 
-    print
-    print 'Clearing user data directory and log file from previous runs'
+    print()
+    print('Clearing user data directory and log file from previous runs')
     if os.access(NVDA_LOGPATH, os.F_OK):
       os.remove(NVDA_LOGPATH)
     if os.access(CHROME_PROFILES_PATH, os.F_OK):
@@ -66,7 +66,7 @@
     os.mkdir(CHROME_PROFILES_PATH, 0777)
 
     def handler(signum, frame):
-      print 'Test interrupted, attempting to kill subprocesses.'
+      print('Test interrupted, attempting to kill subprocesses.')
       self.tearDown()
       sys.exit()
     signal.signal(signal.SIGINT, handler)
@@ -77,16 +77,16 @@
             '--user-data-dir=%s' % user_data_dir,
             '--no-first-run',
             'about:blank']
-    print
-    print ' '.join(args)
+    print()
+    print(' '.join(args))
     self._chrome_proc = subprocess.Popen(args)
     self._chrome_proc.poll()
     if self._chrome_proc.returncode is None:
-      print 'Chrome is running'
+      print('Chrome is running')
     else:
-      print 'Chrome exited with code', self._chrome_proc.returncode
+      print('Chrome exited with code', self._chrome_proc.returncode)
       sys.exit()
-    print 'Chrome pid: %d' % self._chrome_proc.pid
+    print('Chrome pid: %d' % self._chrome_proc.pid)
 
     os.environ['NVDA_SPECIFIC_PROCESS'] = str(self._chrome_proc.pid)
 
@@ -99,11 +99,11 @@
     self._nvda_proc = subprocess.Popen(args)
     self._nvda_proc.poll()
     if self._nvda_proc.returncode is None:
-      print 'NVDA is running'
+      print('NVDA is running')
     else:
-      print 'NVDA exited with code', self._nvda_proc.returncode
+      print('NVDA exited with code', self._nvda_proc.returncode)
       sys.exit()
-    print 'NVDA pid: %d' % self._nvda_proc.pid
+    print('NVDA pid: %d' % self._nvda_proc.pid)
 
     app = pywinauto.application.Application()
     app.connect_(process = self._chrome_proc.pid)
@@ -115,22 +115,22 @@
       self.tearDown()
 
   def tearDown(self):
-    print
-    print 'Shutting down'
+    print()
+    print('Shutting down')
 
     self._chrome_proc.poll()
     if self._chrome_proc.returncode is None:
-      print 'Killing Chrome subprocess'
+      print('Killing Chrome subprocess')
       self._chrome_proc.kill()
     else:
-      print 'Chrome already died.'
+      print('Chrome already died.')
 
     self._nvda_proc.poll()
     if self._nvda_proc.returncode is None:
-      print 'Killing NVDA subprocess'
+      print('Killing NVDA subprocess')
       self._nvda_proc.kill()
     else:
-      print 'NVDA already died.'
+      print('NVDA already died.')
 
   def _GetSpeechFromNvdaLogFile(self):
     """Return everything NVDA would have spoken as a list of strings.
@@ -176,12 +176,12 @@
         break
 
       if time.time() - start_time >= WAIT_FOR_SPEECH_TIMEOUT_SECS:
-        print '** Speech from NVDA so far:'
+        print('** Speech from NVDA so far:')
         for line in lines:
-          print '"%s"' % line
-        print '** Was waiting for:'
+          print('"%s"' % line)
+        print('** Was waiting for:')
         for line in expected:
-          print '"%s"' % line
+          print('"%s"' % line)
         raise Exception('Timed out')
       time.sleep(0.1)
 
diff --git a/tools/perf/fetch_benchmark_deps.py b/tools/perf/fetch_benchmark_deps.py
index 3a21c3d08..80fa071 100755
--- a/tools/perf/fetch_benchmark_deps.py
+++ b/tools/perf/fetch_benchmark_deps.py
@@ -92,9 +92,11 @@
   options = parser.parse_args(args)
 
   if options.benchmark_name:
+    perf_dir = path_util.GetPerfDir()
+    benchmark_dirs=[os.path.join(perf_dir, 'benchmarks'),
+                    os.path.join(perf_dir, 'contrib')]
     config = chromium_config.ChromiumConfig(
-        top_level_dir=path_util.GetPerfDir(),
-        benchmark_dirs=[os.path.join(path_util.GetPerfDir(), 'benchmarks')])
+        top_level_dir=path_util.GetPerfDir(), benchmark_dirs=benchmark_dirs)
     benchmark = benchmark_runner.GetBenchmarkByName(
         options.benchmark_name, config)
     if not benchmark:
diff --git a/ui/gfx/image/mojo/image_skia_struct_traits.cc b/ui/gfx/image/mojo/image_skia_struct_traits.cc
index cb9487f..98ef823 100644
--- a/ui/gfx/image/mojo/image_skia_struct_traits.cc
+++ b/ui/gfx/image/mojo/image_skia_struct_traits.cc
@@ -107,12 +107,32 @@
 }
 
 // static
-std::vector<gfx::ImageSkiaRep>
-StructTraits<gfx::mojom::ImageSkiaDataView, gfx::ImageSkia>::image_reps(
+void* StructTraits<gfx::mojom::ImageSkiaDataView, gfx::ImageSkia>::SetUpContext(
     const gfx::ImageSkia& input) {
   // Trigger the image to load everything.
   input.EnsureRepsForSupportedScales();
-  return input.image_reps();
+
+  // Use a context to return a stable list of ImageSkiaRep objects. That is,
+  // multiple calls of image_reps() should return exactly the same list of
+  // ImageSkiaRep objects. So that ImageSkiaRep with the same backing pixel
+  // buffer is properly serialized and only once.
+  return new std::vector<gfx::ImageSkiaRep>(input.image_reps());
+}
+
+// static
+void StructTraits<gfx::mojom::ImageSkiaDataView,
+                  gfx::ImageSkia>::TearDownContext(const gfx::ImageSkia& input,
+                                                   void* context) {
+  delete static_cast<std::vector<gfx::ImageSkiaRep>*>(context);
+}
+
+// static
+const std::vector<gfx::ImageSkiaRep>&
+StructTraits<gfx::mojom::ImageSkiaDataView, gfx::ImageSkia>::image_reps(
+    const gfx::ImageSkia& input,
+    void* context) {
+  // See the comment in SetUpContext regarding context usage.
+  return *(static_cast<std::vector<gfx::ImageSkiaRep>*>(context));
 }
 
 // static
diff --git a/ui/gfx/image/mojo/image_skia_struct_traits.h b/ui/gfx/image/mojo/image_skia_struct_traits.h
index 0b9cfecf..974ec9c 100644
--- a/ui/gfx/image/mojo/image_skia_struct_traits.h
+++ b/ui/gfx/image/mojo/image_skia_struct_traits.h
@@ -56,7 +56,11 @@
 
 template <>
 struct StructTraits<gfx::mojom::ImageSkiaDataView, gfx::ImageSkia> {
-  static std::vector<gfx::ImageSkiaRep> image_reps(const gfx::ImageSkia& input);
+  static void* SetUpContext(const gfx::ImageSkia& input);
+  static void TearDownContext(const gfx::ImageSkia& input, void* context);
+  static const std::vector<gfx::ImageSkiaRep>& image_reps(
+      const gfx::ImageSkia& input,
+      void* context);
 
   static bool IsNull(const gfx::ImageSkia& input) {
     return input.image_reps().empty();
diff --git a/ui/gfx/mojo/buffer_types_struct_traits.cc b/ui/gfx/mojo/buffer_types_struct_traits.cc
index e9aea16..186e2eb5 100644
--- a/ui/gfx/mojo/buffer_types_struct_traits.cc
+++ b/ui/gfx/mojo/buffer_types_struct_traits.cc
@@ -8,17 +8,30 @@
 
 namespace mojo {
 
-std::vector<mojo::ScopedHandle>
-StructTraits<gfx::mojom::NativePixmapHandleDataView, gfx::NativePixmapHandle>::
-    fds(const gfx::NativePixmapHandle& pixmap_handle) {
-  std::vector<mojo::ScopedHandle> handles;
+void* StructTraits<gfx::mojom::NativePixmapHandleDataView,
+                   gfx::NativePixmapHandle>::
+    SetUpContext(const gfx::NativePixmapHandle& pixmap_handle) {
+  auto* handles = new std::vector<mojo::ScopedHandle>();
 #if defined(OS_LINUX)
   for (const base::FileDescriptor& fd : pixmap_handle.fds)
-    handles.emplace_back(mojo::WrapPlatformFile(fd.fd));
+    handles->emplace_back(mojo::WrapPlatformFile(fd.fd));
 #endif  // defined(OS_LINUX)
   return handles;
 }
 
+void StructTraits<gfx::mojom::NativePixmapHandleDataView,
+                  gfx::NativePixmapHandle>::
+    TearDownContext(const gfx::NativePixmapHandle& handle, void* context) {
+  delete static_cast<std::vector<mojo::ScopedHandle>*>(context);
+}
+
+std::vector<mojo::ScopedHandle>& StructTraits<
+    gfx::mojom::NativePixmapHandleDataView,
+    gfx::NativePixmapHandle>::fds(const gfx::NativePixmapHandle& pixmap_handle,
+                                  void* context) {
+  return *static_cast<std::vector<mojo::ScopedHandle>*>(context);
+}
+
 bool StructTraits<
     gfx::mojom::NativePixmapHandleDataView,
     gfx::NativePixmapHandle>::Read(gfx::mojom::NativePixmapHandleDataView data,
diff --git a/ui/gfx/mojo/buffer_types_struct_traits.h b/ui/gfx/mojo/buffer_types_struct_traits.h
index fadb17a8..0fdf909 100644
--- a/ui/gfx/mojo/buffer_types_struct_traits.h
+++ b/ui/gfx/mojo/buffer_types_struct_traits.h
@@ -239,6 +239,10 @@
 template <>
 struct StructTraits<gfx::mojom::NativePixmapHandleDataView,
                     gfx::NativePixmapHandle> {
+  static void* SetUpContext(const gfx::NativePixmapHandle& handle);
+  static void TearDownContext(const gfx::NativePixmapHandle& handle,
+                              void* context);
+
   static bool IsNull(const gfx::NativePixmapHandle& handle) {
 #if defined(OS_LINUX)
     return false;
@@ -247,8 +251,9 @@
     return true;
 #endif
   }
-  static std::vector<mojo::ScopedHandle> fds(
-      const gfx::NativePixmapHandle& pixmap_handle);
+  static std::vector<mojo::ScopedHandle>& fds(
+      const gfx::NativePixmapHandle& pixmap_handle,
+      void* context);
 
   static const std::vector<gfx::NativePixmapPlane>& planes(
       const gfx::NativePixmapHandle& pixmap_handle) {