diff --git a/DEPS b/DEPS
index 9f33847..fc06943 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': '4a0f180211dbcf5c400f797aafe6cc3ff6fc021f',
+  'skia_revision': '01eb360ce063ee8df4109f22fc779d7eb69583ae',
   # 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': '8ff4cb255b571e8d39ad09deb32e22fbd4a19fe8',
+  'v8_revision': '2c2e365f52d98d12f040c30b0f48654811d2e392',
   # 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.
@@ -52,7 +52,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '0dc97810e5e4ed49d4a6c31d071550e618e9e25e',
+  'angle_revision': 'f0be43fee2a89588a63d4d7beb82ea18db7431e8',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling build tools
   # and whatever else without interference from each other.
@@ -64,7 +64,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '1ef2f828f71e40437d82bb039dcb087c1beb7bd6',
+  'pdfium_revision': 'a173900b19e158130df049dd1c31b7494baefffd',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -92,11 +92,11 @@
   # 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': 'a12a34451a99cbbcad55d466940fd445171927fd',
+  'freetype_revision': '7819aeb622a94be0d89caf8382f290d0266c4aed',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '56836f4aacdc15e1284ef9c09afdbb9f9bd92cda',
+  'catapult_revision': '6d102fd0828209a8f9c0fb39eab1e846f3114e84',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -235,7 +235,7 @@
     Var('chromium_git') + '/native_client/src/third_party/scons-2.0.1.git' + '@' + '1c1550e17fc26355d08627fbdec13d8291227067',
 
   'src/third_party/webrtc':
-    Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + '08fc06e0c0ab20d64b5283a7d6bf698fa72189c5', # commit position 18824
+    Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + '675c61ecddf34a2073b0715adf15205fa3d42856', # commit position 18836
 
   'src/third_party/openmax_dl':
     Var('chromium_git') + '/external/webrtc/deps/third_party/openmax.git' + '@' +  Var('openmax_dl_revision'),
@@ -382,6 +382,10 @@
 
     'src/third_party/google_toolbox_for_mac/src':
       Var('chromium_git') + '/external/github.com/google/google-toolbox-for-mac.git' + '@' + Var('google_toolbox_for_mac_revision'),
+
+    'src/third_party/material_design_icons/src':
+      Var('chromium_git') + '/external/github.com/google/material-design-icons.git' + '@' +
+      'a6145e167b4a3a65640dd6279319cbc77a7e4e96',
   },
   'mac': {
     'src/chrome/installer/mac/third_party/xz/xz':
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 3b003c8..3ab7802 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -2089,6 +2089,7 @@
   results.extend(_CheckPatchFiles(input_api, output_api))
   results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
   results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
+  results.extend(_CheckBuildConfigMacrosWithoutInclude(input_api, output_api))
   results.extend(_CheckForInvalidOSMacros(input_api, output_api))
   results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
   results.extend(_CheckFlakyTestUsage(input_api, output_api))
@@ -2132,6 +2133,51 @@
     return []
 
 
+def _CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
+  macro_re = input_api.re.compile(
+      r'^\s*#(el)?if.*\bdefined\(((OS_|COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
+  include_re = input_api.re.compile(
+      r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
+  extension_re = input_api.re.compile(r'\.[a-z]+$')
+  errors = []
+  for f in input_api.AffectedFiles():
+    if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
+      continue
+    found_line_number = None
+    found_macro = None
+    for line_num, line in f.ChangedContents():
+      match = macro_re.search(line)
+      if match:
+        found_line_number = line_num
+        found_macro = match.group(2)
+        break
+    if not found_line_number:
+      continue
+
+    found_include = False
+    for line in f.NewContents():
+      if include_re.search(line):
+        found_include = True
+        break
+    if found_include:
+      continue
+
+    if not f.LocalPath().endswith('.h'):
+      primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
+      try:
+        content = input_api.ReadFile(primary_header_path, 'r')
+        if include_re.search(content):
+          continue
+      except IOError:
+        pass
+    errors.append('%s:%d %s macro is used without including build/'
+                  'build_config.h.'
+                  % (f.LocalPath(), found_line_number, found_macro))
+  if errors:
+    return [output_api.PresubmitPromptWarning('\n'.join(errors))]
+  return []
+
+
 def _DidYouMeanOSMacro(bad_macro):
   try:
     return {'A': 'OS_ANDROID',
diff --git a/WATCHLISTS b/WATCHLISTS
index ac3b7238..9d7a0012 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -1723,8 +1723,7 @@
     'blink_bindings_serialization': ['jbroman+watch@chromium.org'],
     'blink_bluetooth': ['ortuno+watch@chromium.org',
                         'scheib+watch@chromium.org'],
-    'blink_canvas2d': ['cabanier@adobe.com',
-                       'dongseong.hwang@intel.com',
+    'blink_canvas2d': ['dongseong.hwang@intel.com',
                        'junov@chromium.org'],
     'blink_client_hints': ['yoav@yoav.ws'],
     'blink_clipboard': ['dcheng@chromium.org'],
@@ -1820,7 +1819,6 @@
     'blink_permissions': ['mlamouri+watch-blink@chromium.org'],
     'blink_platform': ['kinuko+watch@chromium.org'],
     'blink_platform_graphics': ['blink-reviews-platform-graphics@chromium.org',
-                                'cabanier@adobe.com',
                                 'dongseong.hwang@intel.com',
                                 'drott+blinkwatch@chromium.org',
                                 'dschulze@chromium.org',
diff --git a/android_webview/browser/aw_pdf_exporter.cc b/android_webview/browser/aw_pdf_exporter.cc
index 6ba16f5..5d422880 100644
--- a/android_webview/browser/aw_pdf_exporter.cc
+++ b/android_webview/browser/aw_pdf_exporter.cc
@@ -68,7 +68,7 @@
       base::Bind(&AwPdfExporter::DidExportPdf, base::Unretained(this)));
 
   if (!print_manager->PrintNow())
-    DidExportPdf(fd, false);
+    DidExportPdf(fd, 0);
 }
 
 namespace {
@@ -113,12 +113,12 @@
   settings.set_should_print_backgrounds(true);
 }
 
-void AwPdfExporter::DidExportPdf(int fd, bool success) {
+void AwPdfExporter::DidExportPdf(int fd, int page_count) {
   JNIEnv* env = base::android::AttachCurrentThread();
   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
   if (obj.is_null())
     return;
-  Java_AwPdfExporter_didExportPdf(env, obj, success);
+  Java_AwPdfExporter_didExportPdf(env, obj, page_count);
 }
 
 bool RegisterAwPdfExporter(JNIEnv* env) {
diff --git a/android_webview/browser/aw_pdf_exporter.h b/android_webview/browser/aw_pdf_exporter.h
index 8ca42899..21e012f 100644
--- a/android_webview/browser/aw_pdf_exporter.h
+++ b/android_webview/browser/aw_pdf_exporter.h
@@ -42,7 +42,7 @@
                        const base::android::JavaRef<jobject>& obj,
                        const printing::PageRanges& page_ranges,
                        printing::PrintSettings& settings);
-  void DidExportPdf(int fd, bool success);
+  void DidExportPdf(int fd, int page_count);
 
   JavaObjectWeakGlobalRef java_ref_;
   content::WebContents* web_contents_;
diff --git a/android_webview/browser/aw_printing_message_filter.cc b/android_webview/browser/aw_printing_message_filter.cc
index 6dac67f..91fe96c 100644
--- a/android_webview/browser/aw_printing_message_filter.cc
+++ b/android_webview/browser/aw_printing_message_filter.cc
@@ -73,14 +73,15 @@
   temp_file_fd->auto_close = false;
 }
 
-void AwPrintingMessageFilter::OnTempFileForPrintingWritten(
-    int render_frame_id,
-    int sequence_number) {
+void AwPrintingMessageFilter::OnTempFileForPrintingWritten(int render_frame_id,
+                                                           int sequence_number,
+                                                           int page_count) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK_GT(page_count, 0);
   AwPrintManager* print_manager =
       GetPrintManager(render_process_id_, render_frame_id);
   if (print_manager)
-    print_manager->PdfWritingDone(true);
+    print_manager->PdfWritingDone(page_count);
 }
 
 }  // namespace android_webview
diff --git a/android_webview/browser/aw_printing_message_filter.h b/android_webview/browser/aw_printing_message_filter.h
index a94e0c4..338b985 100644
--- a/android_webview/browser/aw_printing_message_filter.h
+++ b/android_webview/browser/aw_printing_message_filter.h
@@ -33,7 +33,9 @@
   void OnAllocateTempFileForPrinting(int render_frame_id,
                                      base::FileDescriptor* temp_file_fd,
                                      int* sequence_number);
-  void OnTempFileForPrintingWritten(int render_frame_id, int sequence_number);
+  void OnTempFileForPrintingWritten(int render_frame_id,
+                                    int sequence_number,
+                                    int page_count);
 
   const int render_process_id_;
 
diff --git a/android_webview/browser/browser_view_renderer.cc b/android_webview/browser/browser_view_renderer.cc
index c4191417..039b59b 100644
--- a/android_webview/browser/browser_view_renderer.cc
+++ b/android_webview/browser/browser_view_renderer.cc
@@ -315,14 +315,14 @@
   if (!child_frame.get() || !child_frame->frame.get())
     return;
 
-  cc::ReturnedResourceArray resources;
-  cc::TransferableResource::ReturnResources(child_frame->frame->resource_list,
-                                            &resources);
+  std::vector<cc::ReturnedResource> resources =
+      cc::TransferableResource::ReturnResources(
+          child_frame->frame->resource_list);
   content::SynchronousCompositor* compositor =
       FindCompositor(child_frame->compositor_id);
   if (compositor && !resources.empty())
     compositor->ReturnResources(child_frame->layer_tree_frame_sink_id,
-                                resources);
+                                std::move(resources));
 }
 
 void BrowserViewRenderer::ReturnResourceFromParent(
@@ -332,7 +332,7 @@
   for (auto& pair : returned_resource_map) {
     CompositorID compositor_id = pair.first;
     content::SynchronousCompositor* compositor = FindCompositor(compositor_id);
-    cc::ReturnedResourceArray resources;
+    std::vector<cc::ReturnedResource> resources;
     resources.swap(pair.second.resources);
 
     if (compositor && !resources.empty()) {
diff --git a/android_webview/browser/compositor_frame_consumer.h b/android_webview/browser/compositor_frame_consumer.h
index d1cb24b3..0c0820b36 100644
--- a/android_webview/browser/compositor_frame_consumer.h
+++ b/android_webview/browser/compositor_frame_consumer.h
@@ -26,7 +26,7 @@
     ~ReturnedResources();
 
     uint32_t layer_tree_frame_sink_id;
-    cc::ReturnedResourceArray resources;
+    std::vector<cc::ReturnedResource> resources;
   };
   using ReturnedResourcesMap =
       std::map<CompositorID, ReturnedResources, CompositorIDComparator>;
diff --git a/android_webview/browser/hardware_renderer.cc b/android_webview/browser/hardware_renderer.cc
index f88749b..4515045f4 100644
--- a/android_webview/browser/hardware_renderer.cc
+++ b/android_webview/browser/hardware_renderer.cc
@@ -176,7 +176,7 @@
 }
 
 void HardwareRenderer::DidReceiveCompositorFrameAck(
-    const cc::ReturnedResourceArray& resources) {
+    const std::vector<cc::ReturnedResource>& resources) {
   ReturnResourcesToCompositor(resources, compositor_id_,
                               last_submitted_layer_tree_frame_sink_id_);
 }
@@ -186,7 +186,7 @@
 }
 
 void HardwareRenderer::ReclaimResources(
-    const cc::ReturnedResourceArray& resources) {
+    const std::vector<cc::ReturnedResource>& resources) {
   ReturnResourcesToCompositor(resources, compositor_id_,
                               last_submitted_layer_tree_frame_sink_id_);
 }
@@ -237,9 +237,9 @@
   if (!child_frame || !child_frame->frame)
     return;
 
-  cc::ReturnedResourceArray resources_to_return;
-  cc::TransferableResource::ReturnResources(child_frame->frame->resource_list,
-                                            &resources_to_return);
+  std::vector<cc::ReturnedResource> resources_to_return =
+      cc::TransferableResource::ReturnResources(
+          child_frame->frame->resource_list);
 
   // The child frame's compositor id is not necessarily same as
   // compositor_id_.
@@ -248,7 +248,7 @@
 }
 
 void HardwareRenderer::ReturnResourcesToCompositor(
-    const cc::ReturnedResourceArray& resources,
+    const std::vector<cc::ReturnedResource>& resources,
     const CompositorID& compositor_id,
     uint32_t layer_tree_frame_sink_id) {
   if (layer_tree_frame_sink_id != last_committed_layer_tree_frame_sink_id_)
diff --git a/android_webview/browser/hardware_renderer.h b/android_webview/browser/hardware_renderer.h
index a6836bf..64056d89 100644
--- a/android_webview/browser/hardware_renderer.h
+++ b/android_webview/browser/hardware_renderer.h
@@ -51,16 +51,18 @@
  private:
   // cc::CompositorFrameSinkSupportClient implementation.
   void DidReceiveCompositorFrameAck(
-      const cc::ReturnedResourceArray& resources) override;
+      const std::vector<cc::ReturnedResource>& resources) override;
   void OnBeginFrame(const cc::BeginFrameArgs& args) override;
-  void ReclaimResources(const cc::ReturnedResourceArray& resources) override;
+  void ReclaimResources(
+      const std::vector<cc::ReturnedResource>& resources) override;
   void WillDrawSurface(const cc::LocalSurfaceId& local_surface_id,
                        const gfx::Rect& damage_rect) override;
 
   void ReturnChildFrame(std::unique_ptr<ChildFrame> child_frame);
-  void ReturnResourcesToCompositor(const cc::ReturnedResourceArray& resources,
-                                   const CompositorID& compositor_id,
-                                   uint32_t layer_tree_frame_sink_id);
+  void ReturnResourcesToCompositor(
+      const std::vector<cc::ReturnedResource>& resources,
+      const CompositorID& compositor_id,
+      uint32_t layer_tree_frame_sink_id);
 
   void AllocateSurface();
   void DestroySurface();
diff --git a/android_webview/browser/render_thread_manager.cc b/android_webview/browser/render_thread_manager.cc
index 8faa8eb..10dae381 100644
--- a/android_webview/browser/render_thread_manager.cc
+++ b/android_webview/browser/render_thread_manager.cc
@@ -265,7 +265,7 @@
 RenderThreadManager::ReturnedResources::~ReturnedResources() {}
 
 void RenderThreadManager::InsertReturnedResourcesOnRT(
-    const cc::ReturnedResourceArray& resources,
+    const std::vector<cc::ReturnedResource>& resources,
     const CompositorID& compositor_id,
     uint32_t layer_tree_frame_sink_id) {
   base::AutoLock lock(lock_);
diff --git a/android_webview/browser/render_thread_manager.h b/android_webview/browser/render_thread_manager.h
index fe335d36..fea3032 100644
--- a/android_webview/browser/render_thread_manager.h
+++ b/android_webview/browser/render_thread_manager.h
@@ -64,9 +64,10 @@
   void DrawGL(AwDrawGLInfo* draw_info);
   void PostExternalDrawConstraintsToChildCompositorOnRT(
       const ParentCompositorDrawConstraints& parent_draw_constraints);
-  void InsertReturnedResourcesOnRT(const cc::ReturnedResourceArray& resources,
-                                   const CompositorID& compositor_id,
-                                   uint32_t layer_tree_frame_sink_id);
+  void InsertReturnedResourcesOnRT(
+      const std::vector<cc::ReturnedResource>& resources,
+      const CompositorID& compositor_id,
+      uint32_t layer_tree_frame_sink_id);
 
  private:
   friend class internal::RequestInvokeGLTracker;
diff --git a/android_webview/browser/surfaces_instance.cc b/android_webview/browser/surfaces_instance.cc
index 7520a12..8855884 100644
--- a/android_webview/browser/surfaces_instance.cc
+++ b/android_webview/browser/surfaces_instance.cc
@@ -199,7 +199,7 @@
 }
 
 void SurfacesInstance::DidReceiveCompositorFrameAck(
-    const cc::ReturnedResourceArray& resources) {
+    const std::vector<cc::ReturnedResource>& resources) {
   ReclaimResources(resources);
 }
 
@@ -210,7 +210,7 @@
     const gfx::Rect& damage_rect) {}
 
 void SurfacesInstance::ReclaimResources(
-    const cc::ReturnedResourceArray& resources) {
+    const std::vector<cc::ReturnedResource>& resources) {
   // Root surface should have no resources to return.
   CHECK(resources.empty());
 }
diff --git a/android_webview/browser/surfaces_instance.h b/android_webview/browser/surfaces_instance.h
index f84ae05..1a261e3 100644
--- a/android_webview/browser/surfaces_instance.h
+++ b/android_webview/browser/surfaces_instance.h
@@ -66,11 +66,12 @@
 
   // cc::CompositorFrameSinkSupportClient implementation.
   void DidReceiveCompositorFrameAck(
-      const cc::ReturnedResourceArray& resources) override;
+      const std::vector<cc::ReturnedResource>& resources) override;
   void OnBeginFrame(const cc::BeginFrameArgs& args) override;
   void WillDrawSurface(const cc::LocalSurfaceId& local_surface_id,
                        const gfx::Rect& damage_rect) override;
-  void ReclaimResources(const cc::ReturnedResourceArray& resources) override;
+  void ReclaimResources(
+      const std::vector<cc::ReturnedResource>& resources) override;
 
   void SetSolidColorRootFrame();
 
diff --git a/android_webview/common/crash_reporter/crash_keys.cc b/android_webview/common/crash_reporter/crash_keys.cc
index cd4b083..1099d10 100644
--- a/android_webview/common/crash_reporter/crash_keys.cc
+++ b/android_webview/common/crash_reporter/crash_keys.cc
@@ -53,6 +53,7 @@
       {gpu::crash_keys::kGPUVertexShaderVersion, kSmallSize},
       {gpu::crash_keys::kGPUVendor, kSmallSize},
       {gpu::crash_keys::kGPURenderer, kSmallSize},
+      {gpu::crash_keys::kGPUGLContextIsVirtual, kSmallSize},
 
       // content/:
       {"bad_message_reason", kSmallSize},
diff --git a/android_webview/java/src/org/chromium/android_webview/AwPdfExporter.java b/android_webview/java/src/org/chromium/android_webview/AwPdfExporter.java
index 53aa447..b02945c 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwPdfExporter.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwPdfExporter.java
@@ -10,7 +10,6 @@
 import android.print.PrintAttributes;
 import android.util.Log;
 import android.view.ViewGroup;
-import android.webkit.ValueCallback;
 
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
@@ -27,7 +26,7 @@
     private long mNativeAwPdfExporter;
     // TODO(sgurun) result callback should return an int/object indicating errors.
     // potential errors: invalid print parameters, already pending, IO error
-    private ValueCallback<Boolean> mResultCallback;
+    private AwPdfExporterCallback mResultCallback;
     private PrintAttributes mAttributes;
     private ParcelFileDescriptor mFd;
     // Maintain a reference to the top level object (i.e. WebView) since in a common
@@ -38,6 +37,18 @@
     // be reflected there.
     private ViewGroup mContainerView;
 
+    /**
+     * AwPdfExporter callback used to call onWrite* callbacks in Android framework.
+     */
+    public interface AwPdfExporterCallback {
+        /**
+         * Called by the native side when PDF generation is done.
+         * @param pageCount How many pages native side wrote to PDF file descriptor. Non-positive
+         *                  value indicates native side writing failed.
+         */
+        public void pdfWritingDone(int pageCount);
+    }
+
     AwPdfExporter(ViewGroup containerView) {
         setContainerView(containerView);
     }
@@ -47,7 +58,7 @@
     }
 
     public void exportToPdf(final ParcelFileDescriptor fd, PrintAttributes attributes, int[] pages,
-            ValueCallback<Boolean> resultCallback, CancellationSignal cancellationSignal) {
+            AwPdfExporterCallback resultCallback, CancellationSignal cancellationSignal) {
         if (fd == null) {
             throw new IllegalArgumentException("fd cannot be null");
         }
@@ -67,7 +78,7 @@
             throw new IllegalArgumentException("attributes must specify margins");
         }
         if (mNativeAwPdfExporter == 0) {
-            resultCallback.onReceiveValue(false);
+            resultCallback.pdfWritingDone(0);
             return;
         }
         mResultCallback = resultCallback;
@@ -83,7 +94,7 @@
         // via Webview.Destroy) before it has a chance to complete the pdf exporting.
         if (nativePdfExporter == 0 && mResultCallback != null) {
             try {
-                mResultCallback.onReceiveValue(false);
+                mResultCallback.pdfWritingDone(0);
                 mResultCallback = null;
             } catch (IllegalStateException ex) {
                 // Swallow the illegal state exception here. It is possible that app
@@ -105,8 +116,8 @@
     }
 
     @CalledByNative
-    private void didExportPdf(boolean success) {
-        mResultCallback.onReceiveValue(success);
+    private void didExportPdf(int pageCount) {
+        mResultCallback.pdfWritingDone(pageCount);
         mResultCallback = null;
         mAttributes = null;
         // The caller should close the file.
diff --git a/android_webview/java/src/org/chromium/android_webview/AwPrintDocumentAdapter.java b/android_webview/java/src/org/chromium/android_webview/AwPrintDocumentAdapter.java
index 51501bb7..954b111 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwPrintDocumentAdapter.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwPrintDocumentAdapter.java
@@ -12,7 +12,6 @@
 import android.print.PrintAttributes;
 import android.print.PrintDocumentAdapter;
 import android.print.PrintDocumentInfo;
-import android.webkit.ValueCallback;
 
 import java.util.ArrayList;
 
@@ -73,12 +72,12 @@
             return;
         }
 
-        mPdfExporter.exportToPdf(
-                destination, mAttributes, normalizeRanges(pages), new ValueCallback<Boolean>() {
+        mPdfExporter.exportToPdf(destination, mAttributes,
+                normalizeRanges(pages), new AwPdfExporter.AwPdfExporterCallback() {
                     @Override
-                    public void onReceiveValue(Boolean value) {
-                        if (value) {
-                            callback.onWriteFinished(pages);
+                    public void pdfWritingDone(int pageCount) {
+                        if (pageCount > 0) {
+                            callback.onWriteFinished(validatePageRanges(pages, pageCount));
                         } else {
                             // TODO(sgurun) provide a localized error message
                             callback.onWriteFailed(null);
@@ -87,7 +86,14 @@
                 }, cancellationSignal);
     }
 
-    private int[] normalizeRanges(final PageRange[] ranges) {
+    private static PageRange[] validatePageRanges(PageRange[] pages, int pageCount) {
+        if (pages.length == 1 && PageRange.ALL_PAGES.equals(pages[0])) {
+            return new PageRange[] {new PageRange(0, pageCount - 1)};
+        }
+        return pages;
+    }
+
+    private static int[] normalizeRanges(final PageRange[] ranges) {
         if (ranges.length == 1 && PageRange.ALL_PAGES.equals(ranges[0])) {
             return new int[0];
         }
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/SafeBrowsingTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/SafeBrowsingTest.java
index d5e4685..0031980f 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/SafeBrowsingTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/SafeBrowsingTest.java
@@ -280,6 +280,34 @@
         });
     }
 
+    private void loadPathAndWaitForInterstitial(final String path) throws Exception {
+        int interstitialCount =
+                mWebContentsObserver.getAttachedInterstitialPageHelper().getCallCount();
+        final String responseUrl = mTestServer.getURL(path);
+        loadUrlAsync(mAwContents, responseUrl);
+        mWebContentsObserver.getAttachedInterstitialPageHelper().waitForCallback(interstitialCount);
+    }
+
+    private void assertTargetPageHasLoaded(int pageColor) throws Exception {
+        waitForVisualStateCallback(mAwContents);
+        assertEquals("Target page should be visible", pageColor,
+                GraphicsTestUtils.getPixelColorAtCenterOfView(mAwContents, mContainerView));
+    }
+
+    private void assertGreenPageNotShowing() throws Exception {
+        assertTrue("Original page should not be showing",
+                GREEN_PAGE_BACKGROUND_COLOR
+                        != GraphicsTestUtils.getPixelColorAtCenterOfView(
+                                   mAwContents, mContainerView));
+    }
+
+    private void assertTargetPageNotShowing(int pageColor) throws Exception {
+        assertTrue("Target page should not be showing",
+                pageColor
+                        != GraphicsTestUtils.getPixelColorAtCenterOfView(
+                                   mAwContents, mContainerView));
+    }
+
     @SmallTest
     @Feature({"AndroidWebView"})
     @CommandLineFlags.Add(AwSwitches.WEBVIEW_ENABLE_SAFEBROWSING_SUPPORT)
@@ -287,9 +315,7 @@
         loadGreenPage();
         final String responseUrl = mTestServer.getURL(SAFE_HTML_PATH);
         loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), responseUrl);
-        waitForVisualStateCallback(mAwContents);
-        assertEquals("Target page should be visible", SAFE_PAGE_BACKGROUND_COLOR,
-                GraphicsTestUtils.getPixelColorAtCenterOfView(mAwContents, mContainerView));
+        assertTargetPageHasLoaded(SAFE_PAGE_BACKGROUND_COLOR);
     }
 
     @SmallTest
@@ -301,9 +327,7 @@
         loadGreenPage();
         final String responseUrl = mTestServer.getURL(UNWANTED_SOFTWARE_HTML_PATH);
         loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), responseUrl);
-        waitForVisualStateCallback(mAwContents);
-        assertEquals("Target page should be visible", UNWANTED_SOFTWARE_PAGE_BACKGROUND_COLOR,
-                GraphicsTestUtils.getPixelColorAtCenterOfView(mAwContents, mContainerView));
+        assertTargetPageHasLoaded(UNWANTED_SOFTWARE_PAGE_BACKGROUND_COLOR);
     }
 
     @SmallTest
@@ -311,18 +335,9 @@
     @CommandLineFlags.Add(AwSwitches.WEBVIEW_ENABLE_SAFEBROWSING_SUPPORT)
     public void testSafeBrowsingBlocksPhishingPages() throws Throwable {
         loadGreenPage();
-        int count = mWebContentsObserver.getAttachedInterstitialPageHelper().getCallCount();
-        final String responseUrl = mTestServer.getURL(PHISHING_HTML_PATH);
-        loadUrlAsync(mAwContents, responseUrl);
-        mWebContentsObserver.getAttachedInterstitialPageHelper().waitForCallback(count);
-        assertTrue("Original page should not be showing",
-                GREEN_PAGE_BACKGROUND_COLOR
-                        != GraphicsTestUtils.getPixelColorAtCenterOfView(
-                                   mAwContents, mContainerView));
-        assertTrue("Target page should not be visible",
-                PHISHING_PAGE_BACKGROUND_COLOR
-                        != GraphicsTestUtils.getPixelColorAtCenterOfView(
-                                   mAwContents, mContainerView));
+        loadPathAndWaitForInterstitial(PHISHING_HTML_PATH);
+        assertGreenPageNotShowing();
+        assertTargetPageNotShowing(PHISHING_PAGE_BACKGROUND_COLOR);
         // Assume that we are rendering the interstitial, since we see neither the previous page nor
         // the target page
     }
@@ -332,18 +347,9 @@
     @CommandLineFlags.Add(AwSwitches.WEBVIEW_ENABLE_SAFEBROWSING_SUPPORT)
     public void testSafeBrowsingShowsInterstitialForMainFrame() throws Throwable {
         loadGreenPage();
-        int count = mWebContentsObserver.getAttachedInterstitialPageHelper().getCallCount();
-        final String responseUrl = mTestServer.getURL(MALWARE_HTML_PATH);
-        loadUrlAsync(mAwContents, responseUrl);
-        mWebContentsObserver.getAttachedInterstitialPageHelper().waitForCallback(count);
-        assertTrue("Original page should not be showing",
-                GREEN_PAGE_BACKGROUND_COLOR
-                        != GraphicsTestUtils.getPixelColorAtCenterOfView(
-                                   mAwContents, mContainerView));
-        assertTrue("Target page should not be visible",
-                MALWARE_PAGE_BACKGROUND_COLOR
-                        != GraphicsTestUtils.getPixelColorAtCenterOfView(
-                                   mAwContents, mContainerView));
+        loadPathAndWaitForInterstitial(MALWARE_HTML_PATH);
+        assertGreenPageNotShowing();
+        assertTargetPageNotShowing(MALWARE_PAGE_BACKGROUND_COLOR);
         // Assume that we are rendering the interstitial, since we see neither the previous page nor
         // the target page
     }
@@ -353,18 +359,9 @@
     @CommandLineFlags.Add(AwSwitches.WEBVIEW_ENABLE_SAFEBROWSING_SUPPORT)
     public void testSafeBrowsingShowsInterstitialForSubresource() throws Throwable {
         loadGreenPage();
-        int count = mWebContentsObserver.getAttachedInterstitialPageHelper().getCallCount();
-        final String responseUrl = mTestServer.getURL(IFRAME_HTML_PATH);
-        loadUrlAsync(mAwContents, responseUrl);
-        mWebContentsObserver.getAttachedInterstitialPageHelper().waitForCallback(count);
-        assertTrue("Original page should not be showing",
-                GREEN_PAGE_BACKGROUND_COLOR
-                        != GraphicsTestUtils.getPixelColorAtCenterOfView(
-                                   mAwContents, mContainerView));
-        assertTrue("Target page should not be visible",
-                IFRAME_EMBEDDER_BACKGROUND_COLOR
-                        != GraphicsTestUtils.getPixelColorAtCenterOfView(
-                                   mAwContents, mContainerView));
+        loadPathAndWaitForInterstitial(IFRAME_HTML_PATH);
+        assertGreenPageNotShowing();
+        assertTargetPageNotShowing(IFRAME_EMBEDDER_BACKGROUND_COLOR);
         // Assume that we are rendering the interstitial, since we see neither the previous page nor
         // the target page
     }
@@ -373,52 +370,36 @@
     @Feature({"AndroidWebView"})
     @CommandLineFlags.Add(AwSwitches.WEBVIEW_ENABLE_SAFEBROWSING_SUPPORT)
     public void testSafeBrowsingProceedThroughInterstitialForMainFrame() throws Throwable {
-        int interstitialCount =
-                mWebContentsObserver.getAttachedInterstitialPageHelper().getCallCount();
-        int pageFinishedCount =
-                mContentsClient.getOnPageFinishedHelper().getCallCount();
-        final String responseUrl = mTestServer.getURL(MALWARE_HTML_PATH);
-        loadUrlAsync(mAwContents, responseUrl);
-        mWebContentsObserver.getAttachedInterstitialPageHelper().waitForCallback(interstitialCount);
+        int pageFinishedCount = mContentsClient.getOnPageFinishedHelper().getCallCount();
+        loadPathAndWaitForInterstitial(MALWARE_HTML_PATH);
         proceedThroughInterstitial();
         mContentsClient.getOnPageFinishedHelper().waitForCallback(pageFinishedCount);
-        waitForVisualStateCallback(mAwContents);
-        assertEquals("Target page should be visible", MALWARE_PAGE_BACKGROUND_COLOR,
-                GraphicsTestUtils.getPixelColorAtCenterOfView(mAwContents, mContainerView));
+        assertTargetPageHasLoaded(MALWARE_PAGE_BACKGROUND_COLOR);
     }
 
     @SmallTest
     @Feature({"AndroidWebView"})
     @CommandLineFlags.Add(AwSwitches.WEBVIEW_ENABLE_SAFEBROWSING_SUPPORT)
     public void testSafeBrowsingCanProceedThroughInterstitialForSubresource() throws Throwable {
-        int interstitialCount =
-                mWebContentsObserver.getAttachedInterstitialPageHelper().getCallCount();
         int pageFinishedCount = mContentsClient.getOnPageFinishedHelper().getCallCount();
-        final String responseUrl = mTestServer.getURL(IFRAME_HTML_PATH);
-        loadUrlAsync(mAwContents, responseUrl);
-        mWebContentsObserver.getAttachedInterstitialPageHelper().waitForCallback(interstitialCount);
+        loadPathAndWaitForInterstitial(IFRAME_HTML_PATH);
         proceedThroughInterstitial();
         mContentsClient.getOnPageFinishedHelper().waitForCallback(pageFinishedCount);
-        waitForVisualStateCallback(mAwContents);
-        assertEquals("Target page should be visible", IFRAME_EMBEDDER_BACKGROUND_COLOR,
-                GraphicsTestUtils.getPixelColorAtCenterOfView(mAwContents, mContainerView));
+        assertTargetPageHasLoaded(IFRAME_EMBEDDER_BACKGROUND_COLOR);
     }
 
     @SmallTest
     @Feature({"AndroidWebView"})
     @CommandLineFlags.Add(AwSwitches.WEBVIEW_ENABLE_SAFEBROWSING_SUPPORT)
     public void testSafeBrowsingDontProceedCausesNetworkErrorForMainFrame() throws Throwable {
-        int interstitialCount =
-                mWebContentsObserver.getAttachedInterstitialPageHelper().getCallCount();
-        final String responseUrl = mTestServer.getURL(MALWARE_HTML_PATH);
-        loadUrlAsync(mAwContents, responseUrl);
-        mWebContentsObserver.getAttachedInterstitialPageHelper().waitForCallback(interstitialCount);
+        loadPathAndWaitForInterstitial(MALWARE_HTML_PATH);
         OnReceivedError2Helper errorHelper = mContentsClient.getOnReceivedError2Helper();
         int errorCount = errorHelper.getCallCount();
         dontProceedThroughInterstitial();
         errorHelper.waitForCallback(errorCount);
         assertEquals(
                 ErrorCodeConversionHelper.ERROR_UNSAFE_RESOURCE, errorHelper.getError().errorCode);
+        final String responseUrl = mTestServer.getURL(MALWARE_HTML_PATH);
         assertEquals("Network error is for the malicious page", responseUrl,
                 errorHelper.getRequest().url);
     }
@@ -427,11 +408,7 @@
     @Feature({"AndroidWebView"})
     @CommandLineFlags.Add(AwSwitches.WEBVIEW_ENABLE_SAFEBROWSING_SUPPORT)
     public void testSafeBrowsingDontProceedCausesNetworkErrorForSubresource() throws Throwable {
-        int interstitialCount =
-                mWebContentsObserver.getAttachedInterstitialPageHelper().getCallCount();
-        final String responseUrl = mTestServer.getURL(IFRAME_HTML_PATH);
-        loadUrlAsync(mAwContents, responseUrl);
-        mWebContentsObserver.getAttachedInterstitialPageHelper().waitForCallback(interstitialCount);
+        loadPathAndWaitForInterstitial(IFRAME_HTML_PATH);
         OnReceivedError2Helper errorHelper = mContentsClient.getOnReceivedError2Helper();
         int errorCount = errorHelper.getCallCount();
         dontProceedThroughInterstitial();
@@ -449,11 +426,7 @@
     public void testSafeBrowsingDontProceedNavigatesBackForMainFrame() throws Throwable {
         loadGreenPage();
         final String originalTitle = getTitleOnUiThread(mAwContents);
-        int interstitialCount =
-                mWebContentsObserver.getAttachedInterstitialPageHelper().getCallCount();
-        final String responseUrl = mTestServer.getURL(MALWARE_HTML_PATH);
-        loadUrlAsync(mAwContents, responseUrl);
-        mWebContentsObserver.getAttachedInterstitialPageHelper().waitForCallback(interstitialCount);
+        loadPathAndWaitForInterstitial(MALWARE_HTML_PATH);
         waitForInterstitialToChangeTitle();
         dontProceedThroughInterstitial();
 
@@ -474,9 +447,7 @@
 
         final String responseUrl = mTestServer.getURL(MALWARE_HTML_PATH);
         loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), responseUrl);
-        waitForVisualStateCallback(mAwContents);
-        assertEquals("Target page should be visible", MALWARE_PAGE_BACKGROUND_COLOR,
-                GraphicsTestUtils.getPixelColorAtCenterOfView(mAwContents, mContainerView));
+        assertTargetPageHasLoaded(MALWARE_PAGE_BACKGROUND_COLOR);
     }
 
     @SmallTest
@@ -484,24 +455,14 @@
     public void testSafeBrowsingCanBeEnabledPerWebview() throws Throwable {
         final String responseUrl = mTestServer.getURL(MALWARE_HTML_PATH);
         loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), responseUrl);
-        waitForVisualStateCallback(mAwContents);
-        assertEquals("Target page should be visible", MALWARE_PAGE_BACKGROUND_COLOR,
-                GraphicsTestUtils.getPixelColorAtCenterOfView(mAwContents, mContainerView));
+        assertTargetPageHasLoaded(MALWARE_PAGE_BACKGROUND_COLOR);
 
         getAwSettingsOnUiThread(mAwContents).setSafeBrowsingEnabled(true);
 
         loadGreenPage();
-        int count = mWebContentsObserver.getAttachedInterstitialPageHelper().getCallCount();
-        loadUrlAsync(mAwContents, responseUrl);
-        mWebContentsObserver.getAttachedInterstitialPageHelper().waitForCallback(count);
-        assertTrue("Original page should not be showing",
-                GREEN_PAGE_BACKGROUND_COLOR
-                        != GraphicsTestUtils.getPixelColorAtCenterOfView(
-                                   mAwContents, mContainerView));
-        assertTrue("Target page should not be visible",
-                MALWARE_PAGE_BACKGROUND_COLOR
-                        != GraphicsTestUtils.getPixelColorAtCenterOfView(
-                                   mAwContents, mContainerView));
+        loadPathAndWaitForInterstitial(MALWARE_HTML_PATH);
+        assertGreenPageNotShowing();
+        assertTargetPageNotShowing(MALWARE_PAGE_BACKGROUND_COLOR);
     }
 
     @SmallTest
@@ -527,18 +488,9 @@
     public void testSafeBrowsingShowsQuietInterstitialForOddSizedViews() throws Throwable {
         mAwContents.setCanShowBigInterstitial(false);
         loadGreenPage();
-        int count = mWebContentsObserver.getAttachedInterstitialPageHelper().getCallCount();
-        final String responseUrl = mTestServer.getURL(MALWARE_HTML_PATH);
-        loadUrlAsync(mAwContents, responseUrl);
-        mWebContentsObserver.getAttachedInterstitialPageHelper().waitForCallback(count);
-        assertTrue("Original page should not be showing",
-                GREEN_PAGE_BACKGROUND_COLOR
-                        != GraphicsTestUtils.getPixelColorAtCenterOfView(
-                                   mAwContents, mContainerView));
-        assertTrue("Target page should not be visible",
-                MALWARE_PAGE_BACKGROUND_COLOR
-                        != GraphicsTestUtils.getPixelColorAtCenterOfView(
-                                   mAwContents, mContainerView));
+        loadPathAndWaitForInterstitial(MALWARE_HTML_PATH);
+        assertGreenPageNotShowing();
+        assertTargetPageNotShowing(MALWARE_PAGE_BACKGROUND_COLOR);
     }
 
     @SmallTest
@@ -547,18 +499,9 @@
     public void testSafeBrowsingCanShowQuietPhishingInterstitial() throws Throwable {
         mAwContents.setCanShowBigInterstitial(false);
         loadGreenPage();
-        int count = mWebContentsObserver.getAttachedInterstitialPageHelper().getCallCount();
-        final String responseUrl = mTestServer.getURL(PHISHING_HTML_PATH);
-        loadUrlAsync(mAwContents, responseUrl);
-        mWebContentsObserver.getAttachedInterstitialPageHelper().waitForCallback(count);
-        assertTrue("Original page should not be showing",
-                GREEN_PAGE_BACKGROUND_COLOR
-                        != GraphicsTestUtils.getPixelColorAtCenterOfView(
-                                   mAwContents, mContainerView));
-        assertTrue("Target page should not be visible",
-                PHISHING_PAGE_BACKGROUND_COLOR
-                        != GraphicsTestUtils.getPixelColorAtCenterOfView(
-                                   mAwContents, mContainerView));
+        loadPathAndWaitForInterstitial(PHISHING_HTML_PATH);
+        assertGreenPageNotShowing();
+        assertTargetPageNotShowing(PHISHING_PAGE_BACKGROUND_COLOR);
     }
 
     @SmallTest
@@ -566,16 +509,10 @@
     @CommandLineFlags.Add(AwSwitches.WEBVIEW_ENABLE_SAFEBROWSING_SUPPORT)
     public void testSafeBrowsingProceedQuietInterstitial() throws Throwable {
         mAwContents.setCanShowBigInterstitial(false);
-        int interstitialCount =
-                mWebContentsObserver.getAttachedInterstitialPageHelper().getCallCount();
         int pageFinishedCount = mContentsClient.getOnPageFinishedHelper().getCallCount();
-        final String responseUrl = mTestServer.getURL(PHISHING_HTML_PATH);
-        loadUrlAsync(mAwContents, responseUrl);
-        mWebContentsObserver.getAttachedInterstitialPageHelper().waitForCallback(interstitialCount);
+        loadPathAndWaitForInterstitial(PHISHING_HTML_PATH);
         proceedThroughInterstitial();
         mContentsClient.getOnPageFinishedHelper().waitForCallback(pageFinishedCount);
-        waitForVisualStateCallback(mAwContents);
-        assertEquals("Target page should be visible", PHISHING_PAGE_BACKGROUND_COLOR,
-                GraphicsTestUtils.getPixelColorAtCenterOfView(mAwContents, mContainerView));
+        assertTargetPageHasLoaded(PHISHING_PAGE_BACKGROUND_COLOR);
     }
 }
diff --git a/ash/laser/laser_pointer_view.cc b/ash/laser/laser_pointer_view.cc
index 23e9ae87..82ed189 100644
--- a/ash/laser/laser_pointer_view.cc
+++ b/ash/laser/laser_pointer_view.cc
@@ -201,7 +201,8 @@
 
   // Overridden from cc::LayerTreeFrameSinkClient:
   void SetBeginFrameSource(cc::BeginFrameSource* source) override {}
-  void ReclaimResources(const cc::ReturnedResourceArray& resources) override {
+  void ReclaimResources(
+      const std::vector<cc::ReturnedResource>& resources) override {
     if (view_)
       view_->ReclaimResources(resources);
   }
@@ -421,7 +422,7 @@
 }
 
 void LaserPointerView::ReclaimResources(
-    const cc::ReturnedResourceArray& resources) {
+    const std::vector<cc::ReturnedResource>& resources) {
   DCHECK_EQ(resources.size(), 1u);
 
   auto it = resources_.find(resources.front().id);
diff --git a/ash/laser/laser_pointer_view.h b/ash/laser/laser_pointer_view.h
index fd8df67..d59889c7 100644
--- a/ash/laser/laser_pointer_view.h
+++ b/ash/laser/laser_pointer_view.h
@@ -19,6 +19,10 @@
 class Window;
 }
 
+namespace cc {
+struct ReturnedResource;
+}
+
 namespace gfx {
 class GpuMemoryBuffer;
 class PointF;
@@ -51,7 +55,7 @@
   void DidReceiveCompositorFrameAck();
 
   // Call this to return resources so they can be reused or freed.
-  void ReclaimResources(const cc::ReturnedResourceArray& resources);
+  void ReclaimResources(const std::vector<cc::ReturnedResource>& resources);
 
  private:
   friend class LaserPointerControllerTestApi;
diff --git a/ash/login/ui/lock_debug_view.cc b/ash/login/ui/lock_debug_view.cc
index 29c1dbc..9be97e2 100644
--- a/ash/login/ui/lock_debug_view.cc
+++ b/ash/login/ui/lock_debug_view.cc
@@ -7,6 +7,7 @@
 #include <algorithm>
 
 #include "ash/login/ui/lock_contents_view.h"
+#include "ash/login/ui/lock_screen.h"
 #include "ash/login/ui/login_data_dispatcher.h"
 #include "base/strings/utf_string_conversions.h"
 #include "ui/views/controls/button/md_text_button.h"
@@ -149,6 +150,9 @@
   debug_->SetLayoutManager(new views::BoxLayout(views::BoxLayout::kHorizontal));
   AddChildView(debug_);
 
+  toggle_blur_ = views::MdTextButton::Create(this, base::ASCIIToUTF16("Blur"));
+  debug_->AddChildView(WrapViewForPreferredSize(toggle_blur_));
+
   add_user_ = views::MdTextButton::Create(this, base::ASCIIToUTF16("Add"));
   debug_->AddChildView(WrapViewForPreferredSize(add_user_));
 
@@ -174,6 +178,12 @@
 
 void LockDebugView::ButtonPressed(views::Button* sender,
                                   const ui::Event& event) {
+  // Enable or disable wallpaper blur.
+  if (sender == toggle_blur_) {
+    LockScreen::Get()->ToggleBlur();
+    return;
+  }
+
   // Add or remove a user.
   if (sender == add_user_ || sender == remove_user_) {
     if (sender == add_user_)
@@ -185,6 +195,7 @@
     debug_data_dispatcher_->SetUserCount(num_users_);
     RebuildDebugUserColumn();
     Layout();
+    return;
   }
 
   // Enable or disable PIN.
diff --git a/ash/login/ui/lock_debug_view.h b/ash/login/ui/lock_debug_view.h
index 08f6f7b..ce34cda6 100644
--- a/ash/login/ui/lock_debug_view.h
+++ b/ash/login/ui/lock_debug_view.h
@@ -38,6 +38,7 @@
   LockContentsView* lock_;
 
   views::View* debug_;
+  views::View* toggle_blur_;
   views::View* add_user_;
   views::View* remove_user_;
 
diff --git a/ash/login/ui/lock_screen.cc b/ash/login/ui/lock_screen.cc
index f66b0e3f..f6a5dd2 100644
--- a/ash/login/ui/lock_screen.cc
+++ b/ash/login/ui/lock_screen.cc
@@ -61,14 +61,13 @@
   }
   data_dispatcher->NotifyUsers(users);
 
-  auto* window = instance_->window_ = new LockWindow();
+  auto* window = instance_->window_ = new LockWindow(Shell::GetAshConfig());
   window->SetBounds(display::Screen::GetScreen()->GetPrimaryDisplay().bounds());
   window->SetContentsView(contents);
   window->set_data_dispatcher(std::move(data_dispatcher));
   window->Show();
 
-  // TODO(jdufault): Use correct blur amount.
-  window->GetLayer()->SetBackgroundBlur(20);
+  instance_->ToggleBlur();
 }
 
 void LockScreen::Destroy() {
@@ -78,6 +77,15 @@
   instance_ = nullptr;
 }
 
+void LockScreen::ToggleBlur() {
+  if (instance_->window_->GetLayer()->background_blur() == 0) {
+    // TODO(jdufault): Use correct blur amount.
+    instance_->window_->GetLayer()->SetBackgroundBlur(20);
+  } else {
+    instance_->window_->GetLayer()->SetBackgroundBlur(0);
+  }
+}
+
 void LockScreen::SetPinEnabledForUser(const AccountId& account_id,
                                       bool is_enabled) {
   window_->data_dispatcher()->SetPinEnabledForUser(account_id, is_enabled);
diff --git a/ash/login/ui/lock_screen.h b/ash/login/ui/lock_screen.h
index 13a0b255..43b5b71 100644
--- a/ash/login/ui/lock_screen.h
+++ b/ash/login/ui/lock_screen.h
@@ -27,6 +27,9 @@
   // Destroys an existing lock screen instance.
   void Destroy();
 
+  // Enables/disables background blur.
+  void ToggleBlur();
+
   // Enable or disable PIN for the given user.
   void SetPinEnabledForUser(const AccountId& account_id, bool is_enabled);
 
diff --git a/ash/login/ui/lock_window.cc b/ash/login/ui/lock_window.cc
index f0fbbfd..1c0b17cbf 100644
--- a/ash/login/ui/lock_window.cc
+++ b/ash/login/ui/lock_window.cc
@@ -14,7 +14,7 @@
 
 namespace ash {
 
-LockWindow::LockWindow() {
+LockWindow::LockWindow(Config config) {
   ui::GestureRecognizer::Get()->CancelActiveTouchesExcept(nullptr);
 
   views::Widget::InitParams params(
@@ -23,7 +23,8 @@
   params.show_state = ui::SHOW_STATE_FULLSCREEN;
   params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
   const int kLockContainer = ash::kShellWindowId_LockScreenContainer;
-  if (Shell::GetAshConfig() == Config::MASH) {
+
+  if (config == Config::MASH) {
     params.mus_properties[ui::mojom::WindowManager::kContainerId_InitProperty] =
         mojo::ConvertTo<std::vector<uint8_t>>(kLockContainer);
   } else {
diff --git a/ash/login/ui/lock_window.h b/ash/login/ui/lock_window.h
index 7852c36..236be24 100644
--- a/ash/login/ui/lock_window.h
+++ b/ash/login/ui/lock_window.h
@@ -18,11 +18,13 @@
 
 namespace ash {
 
+enum class Config;
+
 // Shows the widget for the lock screen.
 class ASH_EXPORT LockWindow : public views::Widget,
                               public views::WidgetDelegate {
  public:
-  LockWindow();
+  explicit LockWindow(ash::Config config);
   ~LockWindow() override;
 
   LoginDataDispatcher* data_dispatcher() const {
diff --git a/ash/login/ui/login_auth_user_view.cc b/ash/login/ui/login_auth_user_view.cc
index b9fa5bae..9300411 100644
--- a/ash/login/ui/login_auth_user_view.cc
+++ b/ash/login/ui/login_auth_user_view.cc
@@ -11,6 +11,7 @@
 #include "ash/login/ui/login_pin_view.h"
 #include "ash/login/ui/login_user_view.h"
 #include "ash/shell.h"
+#include "base/strings/utf_string_conversions.h"
 #include "components/user_manager/user.h"
 #include "ui/views/layout/box_layout.h"
 #include "ui/views/view.h"
@@ -120,7 +121,7 @@
 void LoginAuthUserView::OnAuthSubmit(bool is_pin,
                                      const base::string16& password) {
   Shell::Get()->lock_screen_controller()->AuthenticateUser(
-      current_user_, std::string(), is_pin,
+      current_user_, UTF16ToUTF8(password), is_pin,
       base::BindOnce([](OnAuthCallback on_auth,
                         bool auth_success) { on_auth.Run(auth_success); },
                      on_auth_));
diff --git a/ash/mus/bridge/shell_port_mash.cc b/ash/mus/bridge/shell_port_mash.cc
index 58fa0608..9e93232 100644
--- a/ash/mus/bridge/shell_port_mash.cc
+++ b/ash/mus/bridge/shell_port_mash.cc
@@ -131,27 +131,47 @@
 }
 
 void ShellPortMash::LockCursor() {
-  window_manager_->window_manager_client()->LockCursor();
+  // When we are running in mus, we need to keep track of state not just in the
+  // window server, but also locally in ash because ash treats the cursor
+  // manager as the canonical state for now. NativeCursorManagerAsh will keep
+  // this state, while also forwarding it to the window manager for us.
+  if (GetAshConfig() == Config::MUS)
+    Shell::Get()->cursor_manager()->LockCursor();
+  else
+    window_manager_->window_manager_client()->LockCursor();
 }
 
 void ShellPortMash::UnlockCursor() {
-  window_manager_->window_manager_client()->UnlockCursor();
+  if (GetAshConfig() == Config::MUS)
+    Shell::Get()->cursor_manager()->UnlockCursor();
+  else
+    window_manager_->window_manager_client()->UnlockCursor();
 }
 
 void ShellPortMash::ShowCursor() {
-  window_manager_->window_manager_client()->SetCursorVisible(true);
+  if (GetAshConfig() == Config::MUS)
+    Shell::Get()->cursor_manager()->ShowCursor();
+  else
+    window_manager_->window_manager_client()->SetCursorVisible(true);
 }
 
 void ShellPortMash::HideCursor() {
-  window_manager_->window_manager_client()->SetCursorVisible(false);
+  if (GetAshConfig() == Config::MUS)
+    Shell::Get()->cursor_manager()->HideCursor();
+  else
+    window_manager_->window_manager_client()->SetCursorVisible(false);
 }
 
 void ShellPortMash::SetCursorSize(ui::CursorSize cursor_size) {
-  window_manager_->window_manager_client()->SetCursorSize(cursor_size);
+  if (GetAshConfig() == Config::MUS)
+    Shell::Get()->cursor_manager()->SetCursorSize(cursor_size);
+  else
+    window_manager_->window_manager_client()->SetCursorSize(cursor_size);
 }
 
 void ShellPortMash::SetGlobalOverrideCursor(
     base::Optional<ui::CursorData> cursor) {
+  DCHECK(mash_state_);
   window_manager_->window_manager_client()->SetGlobalOverrideCursor(
       std::move(cursor));
 }
diff --git a/ash/public/interfaces/session_controller.mojom b/ash/public/interfaces/session_controller.mojom
index 7b8273dd..fe8ba501 100644
--- a/ash/public/interfaces/session_controller.mojom
+++ b/ash/public/interfaces/session_controller.mojom
@@ -123,6 +123,11 @@
   // active user session.
   SetUserSessionOrder(array<uint32> user_session_ids);
 
+  // Prepares ash for lock screen. Currently this ensures the current active
+  // window could not be used to mimic the lock screen. Lock screen is created
+  // after this call returns.
+  PrepareForLock() => ();
+
   // Runs the pre-lock animation to start locking ash. When the call returns,
   // |locked| == true means that the ash post-lock animation is finished and ash
   // is fully locked. Otherwise |locked| is false, which means something is
diff --git a/ash/session/session_controller.cc b/ash/session/session_controller.cc
index 6ebfff7..c5c06417 100644
--- a/ash/session/session_controller.cc
+++ b/ash/session/session_controller.cc
@@ -12,6 +12,9 @@
 #include "ash/shell.h"
 #include "ash/system/power/power_event_observer.h"
 #include "ash/wm/lock_state_controller.h"
+#include "ash/wm/window_state.h"
+#include "ash/wm/window_util.h"
+#include "ash/wm/wm_event.h"
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/command_line.h"
@@ -248,6 +251,21 @@
   }
 }
 
+void SessionController::PrepareForLock(PrepareForLockCallback callback) {
+  // If the active window is fullscreen, exit fullscreen to avoid the web page
+  // or app mimicking the lock screen. Do not exit fullscreen if the shelf is
+  // visible while in fullscreen because the shelf makes it harder for a web
+  // page or app to mimick the lock screen.
+  wm::WindowState* active_window_state = wm::GetActiveWindowState();
+  if (active_window_state && active_window_state->IsFullscreen() &&
+      active_window_state->hide_shelf_when_fullscreen()) {
+    const wm::WMEvent event(wm::WM_EVENT_TOGGLE_FULLSCREEN);
+    active_window_state->OnWMEvent(&event);
+  }
+
+  std::move(callback).Run();
+}
+
 void SessionController::StartLock(StartLockCallback callback) {
   DCHECK(start_lock_callback_.is_null());
   start_lock_callback_ = std::move(callback);
diff --git a/ash/session/session_controller.h b/ash/session/session_controller.h
index 22952b7..d5358db 100644
--- a/ash/session/session_controller.h
+++ b/ash/session/session_controller.h
@@ -124,6 +124,7 @@
   void UpdateUserSession(mojom::UserSessionPtr user_session) override;
   void SetUserSessionOrder(
       const std::vector<uint32_t>& user_session_order) override;
+  void PrepareForLock(PrepareForLockCallback callback) override;
   void StartLock(StartLockCallback callback) override;
   void NotifyChromeLockAnimationsComplete() override;
   void RunUnlockAnimation(RunUnlockAnimationCallback callback) override;
diff --git a/ash/system/network/network_list.cc b/ash/system/network/network_list.cc
index 1d75f99..9ed47151 100644
--- a/ash/system/network/network_list.cc
+++ b/ash/system/network/network_list.cc
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "ash/metrics/user_metrics_recorder.h"
+#include "ash/public/cpp/config.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
@@ -437,13 +438,15 @@
   const bool using_vpn =
       !!NetworkHandler::Get()->network_state_handler()->ConnectedNetworkByType(
           NetworkTypePattern::VPN());
-  // TODO(jamescook): Eliminate the null check by creating UIProxyConfigService
-  // under mash. This will require the mojo pref service to work with prefs in
-  // Local State. http://crbug.com/718072
-  const bool using_proxy = NetworkHandler::Get()->ui_proxy_config_service() &&
-                           NetworkHandler::Get()
-                               ->ui_proxy_config_service()
-                               ->HasDefaultNetworkProxyConfigured();
+  bool using_proxy = false;
+  // TODO(jamescook): Create UIProxyConfigService under mash. This will require
+  // the mojo pref service to work with prefs in Local State.
+  // http://crbug.com/718072
+  if (Shell::GetAshConfig() != Config::MASH) {
+    using_proxy = NetworkHandler::Get()
+                      ->ui_proxy_config_service()
+                      ->HasDefaultNetworkProxyConfigured();
+  }
   if (using_vpn || using_proxy) {
     if (!connection_warning_)
       connection_warning_ = CreateConnectionWarning();
diff --git a/ash/system/network/tray_network_unittest.cc b/ash/system/network/tray_network_unittest.cc
index 32f23bd..ac421aad 100644
--- a/ash/system/network/tray_network_unittest.cc
+++ b/ash/system/network/tray_network_unittest.cc
@@ -5,6 +5,8 @@
 #include "ash/system/network/tray_network.h"
 
 #include "ash/login_status.h"
+#include "ash/public/cpp/config.h"
+#include "ash/shell.h"
 #include "ash/system/network/network_list.h"
 #include "ash/system/tray/system_tray.h"
 #include "ash/system/tray/system_tray_test_api.h"
@@ -31,15 +33,21 @@
     // Initializing NetworkHandler before ash is more like production.
     chromeos::NetworkHandler::Initialize();
     test::AshTestBase::SetUp();
-    chromeos::NetworkHandler::Get()->InitializePrefServices(&profile_prefs_,
-                                                            &local_state_);
+    // Mash doesn't do this yet, so don't do it in tests either.
+    // http://crbug.com/718072
+    if (Shell::GetAshConfig() != Config::MASH) {
+      chromeos::NetworkHandler::Get()->InitializePrefServices(&profile_prefs_,
+                                                              &local_state_);
+    }
     // Networking stubs may have asynchronous initialization.
     RunAllPendingInMessageLoop();
   }
 
   void TearDown() override {
     // This roughly matches production shutdown order.
-    chromeos::NetworkHandler::Get()->ShutdownPrefServices();
+    if (Shell::GetAshConfig() != Config::MASH) {
+      chromeos::NetworkHandler::Get()->ShutdownPrefServices();
+    }
     test::AshTestBase::TearDown();
     chromeos::NetworkHandler::Shutdown();
     chromeos::DBusThreadManager::Shutdown();
diff --git a/ash/wm/native_cursor_manager_ash_mus.cc b/ash/wm/native_cursor_manager_ash_mus.cc
index b8ea0ea..c36b5314 100644
--- a/ash/wm/native_cursor_manager_ash_mus.cc
+++ b/ash/wm/native_cursor_manager_ash_mus.cc
@@ -7,8 +7,8 @@
 #include "ash/display/cursor_window_controller.h"
 #include "ash/display/window_tree_host_manager.h"
 #include "ash/shell.h"
-#include "ash/shell_port.h"
 #include "ui/aura/env.h"
+#include "ui/aura/mus/window_manager_delegate.h"
 #include "ui/aura/mus/window_port_mus.h"
 #include "ui/aura/window_event_dispatcher.h"
 #include "ui/aura/window_tree_host.h"
@@ -42,7 +42,7 @@
   // As the window manager, tell mus to use |mojo_cursor| everywhere. We do
   // this instead of trying to set per-window because otherwise we run into the
   // event targeting issue.
-  ShellPort::Get()->SetGlobalOverrideCursor(mojo_cursor);
+  Shell::window_manager_client()->SetGlobalOverrideCursor(mojo_cursor);
 
   // Make sure the local state is set properly, so that local queries show that
   // we set the cursor.
@@ -57,10 +57,7 @@
 
 void NotifyCursorVisibilityChange(bool visible) {
   // Communicate the cursor visibility state to the mus server.
-  if (visible)
-    ShellPort::Get()->ShowCursor();
-  else
-    ShellPort::Get()->HideCursor();
+  Shell::window_manager_client()->SetCursorVisible(visible);
 
   // Communicate the cursor visibility change to our local root window objects.
   aura::Window::Windows root_windows = Shell::Get()->GetAllRootWindows();
@@ -184,7 +181,7 @@
     ::wm::NativeCursorManagerDelegate* delegate) {
   delegate->CommitCursorSize(cursor_size);
 
-  ShellPort::Get()->SetCursorSize(cursor_size);
+  Shell::window_manager_client()->SetCursorSize(cursor_size);
 
   Shell::Get()
       ->window_tree_host_manager()
diff --git a/base/android/build_info.cc b/base/android/build_info.cc
index 2b527ca4..7dd4291 100644
--- a/base/android/build_info.cc
+++ b/base/android/build_info.cc
@@ -67,7 +67,9 @@
       package_version_name_(StrDupParam(params, 10)),
       android_build_fp_(StrDupParam(params, 11)),
       gms_version_code_(StrDupParam(params, 12)),
-      extracted_file_suffix_(params[13]),
+      installer_package_name_(StrDupParam(params, 13)),
+      abi_name_(StrDupParam(params, 14)),
+      extracted_file_suffix_(params[15]),
       java_exception_info_(NULL) {}
 
 // static
diff --git a/base/android/build_info.h b/base/android/build_info.h
index acb6bfa..163f70e 100644
--- a/base/android/build_info.h
+++ b/base/android/build_info.h
@@ -101,6 +101,10 @@
     return build_type_;
   }
 
+  const char* installer_package_name() const { return installer_package_name_; }
+
+  const char* abi_name() const { return abi_name_; }
+
   std::string extracted_file_suffix() const { return extracted_file_suffix_; }
 
   int sdk_int() const {
@@ -137,6 +141,8 @@
   const char* const package_version_name_;
   const char* const android_build_fp_;
   const char* const gms_version_code_;
+  const char* const installer_package_name_;
+  const char* const abi_name_;
   // Not needed by breakpad.
   const std::string extracted_file_suffix_;
   // This is set via set_java_exception_info, not at constructor time.
diff --git a/base/android/java/src/org/chromium/base/BuildInfo.java b/base/android/java/src/org/chromium/base/BuildInfo.java
index 4f1355f..9617afb 100644
--- a/base/android/java/src/org/chromium/base/BuildInfo.java
+++ b/base/android/java/src/org/chromium/base/BuildInfo.java
@@ -9,6 +9,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.os.Build;
+import android.text.TextUtils;
 
 import org.chromium.base.annotations.CalledByNative;
 
@@ -25,6 +26,7 @@
      */
     private BuildInfo() {}
 
+    @SuppressWarnings("deprecation")
     @CalledByNative
     private static String[] getAll() {
         try {
@@ -37,6 +39,18 @@
             CharSequence label = pm.getApplicationLabel(pi.applicationInfo);
             String packageLabel = label == null ? "" : label.toString();
 
+            String installerPackageName = pm.getInstallerPackageName(packageName);
+            if (installerPackageName == null) {
+                installerPackageName = "";
+            }
+
+            String abiString = null;
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+                abiString = TextUtils.join(", ", Build.SUPPORTED_ABIS);
+            } else {
+                abiString = "ABI1: " + Build.CPU_ABI + ", ABI2: " + Build.CPU_ABI2;
+            }
+
             // Use lastUpdateTime when developing locally, since versionCode does not normally
             // change in this case.
             long version = pi.versionCode > 10 ? pi.versionCode : pi.lastUpdateTime;
@@ -47,7 +61,7 @@
                     Build.BRAND, Build.DEVICE, Build.ID, Build.MANUFACTURER, Build.MODEL,
                     String.valueOf(Build.VERSION.SDK_INT), Build.TYPE, packageLabel, packageName,
                     versionCode, versionName, getAndroidBuildFingerprint(), getGMSVersionCode(pm),
-                    extractedFileSuffix,
+                    installerPackageName, abiString, extractedFileSuffix,
             };
         } catch (NameNotFoundException e) {
             throw new RuntimeException(e);
@@ -81,7 +95,7 @@
 
     /** Returns a string that is different each time the apk changes. */
     public static String getExtractedFileSuffix() {
-        return getAll()[13];
+        return getAll()[15];
     }
 
     public static String getPackageLabel() {
diff --git a/base/android/java/src/org/chromium/base/metrics/RecordHistogram.java b/base/android/java/src/org/chromium/base/metrics/RecordHistogram.java
index eaf57b7..b3667c55 100644
--- a/base/android/java/src/org/chromium/base/metrics/RecordHistogram.java
+++ b/base/android/java/src/org/chromium/base/metrics/RecordHistogram.java
@@ -270,6 +270,15 @@
     }
 
     /**
+     * Returns the number of samples recorded for the given histogram.
+     * @param name name of the histogram to look up.
+     */
+    @VisibleForTesting
+    public static int getHistogramTotalCountForTesting(String name) {
+        return nativeGetHistogramTotalCountForTesting(name);
+    }
+
+    /**
      * Initializes the metrics system.
      */
     public static void initialize() {
@@ -290,5 +299,6 @@
     private static native long nativeRecordSparseHistogram(String name, long key, int sample);
 
     private static native int nativeGetHistogramValueCountForTesting(String name, int sample);
+    private static native int nativeGetHistogramTotalCountForTesting(String name);
     private static native void nativeInitialize();
 }
diff --git a/base/android/record_histogram.cc b/base/android/record_histogram.cc
index 1a207a18..0561986 100644
--- a/base/android/record_histogram.cc
+++ b/base/android/record_histogram.cc
@@ -315,6 +315,20 @@
   return samples->GetCount(static_cast<int>(sample));
 }
 
+jint GetHistogramTotalCountForTesting(
+    JNIEnv* env,
+    const JavaParamRef<jclass>& clazz,
+    const JavaParamRef<jstring>& histogram_name) {
+  HistogramBase* histogram = StatisticsRecorder::FindHistogram(
+      android::ConvertJavaStringToUTF8(env, histogram_name));
+  if (histogram == nullptr) {
+    // No samples have been recorded for this histogram.
+    return 0;
+  }
+
+  return histogram->SnapshotSamples()->TotalCount();
+}
+
 bool RegisterRecordHistogram(JNIEnv* env) {
   return RegisterNativesImpl(env);
 }
diff --git a/base/memory/shared_memory_helper.cc b/base/memory/shared_memory_helper.cc
index e80083c..68f0c06b 100644
--- a/base/memory/shared_memory_helper.cc
+++ b/base/memory/shared_memory_helper.cc
@@ -4,6 +4,13 @@
 
 #include "base/memory/shared_memory_helper.h"
 
+#if defined(OS_CHROMEOS)
+#include <sys/resource.h>
+#include <sys/time.h>
+
+#include "base/debug/alias.h"
+#endif  // defined(OS_CHROMEOS)
+
 #include "base/threading/thread_restrictions.h"
 
 namespace base {
@@ -90,6 +97,56 @@
   *mapped_file = HANDLE_EINTR(dup(fileno(fp.get())));
   if (*mapped_file == -1) {
     NOTREACHED() << "Call to dup failed, errno=" << errno;
+
+#if defined(OS_CHROMEOS)
+    if (errno == EMFILE) {
+      // We're out of file descriptors and are probably about to crash somewhere
+      // else in Chrome anyway. Let's collect what FD information we can and
+      // crash.
+      // Added for debugging crbug.com/733718
+      int original_fd_limit = 16384;
+      struct rlimit rlim;
+      if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) {
+        original_fd_limit = rlim.rlim_cur;
+        if (rlim.rlim_max > rlim.rlim_cur) {
+          // Increase fd limit so breakpad has a chance to write a minidump.
+          rlim.rlim_cur = rlim.rlim_max;
+          if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) {
+            PLOG(ERROR) << "setrlimit() failed";
+          }
+        }
+      } else {
+        PLOG(ERROR) << "getrlimit() failed";
+      }
+
+      const char kFileDataMarker[] = "FDATA";
+      char buf[PATH_MAX];
+      char fd_path[PATH_MAX];
+      char crash_buffer[32 * 1024] = {0};
+      char* crash_ptr = crash_buffer;
+      base::debug::Alias(crash_buffer);
+
+      // Put a marker at the start of our data so we can confirm where it
+      // begins.
+      crash_ptr = strncpy(crash_ptr, kFileDataMarker, strlen(kFileDataMarker));
+      for (int i = original_fd_limit; i >= 0; --i) {
+        memset(buf, 0, arraysize(buf));
+        memset(fd_path, 0, arraysize(fd_path));
+        snprintf(fd_path, arraysize(fd_path) - 1, "/proc/self/fd/%d", i);
+        ssize_t count = readlink(fd_path, buf, arraysize(buf) - 1);
+        if (count < 0) {
+          PLOG(ERROR) << "readlink failed for: " << fd_path;
+          continue;
+        }
+
+        if (crash_ptr + count + 1 < crash_buffer + arraysize(crash_buffer)) {
+          crash_ptr = strncpy(crash_ptr, buf, count + 1);
+        }
+        LOG(ERROR) << i << ": " << buf;
+      }
+      LOG(FATAL) << "Logged for file descriptor exhaustion, crashing now";
+    }
+#endif  // defined(OS_CHROMEOS)
   }
   *readonly_mapped_file = readonly_fd.release();
 
diff --git a/base/memory/weak_ptr.cc b/base/memory/weak_ptr.cc
index b6e997b..8879651 100644
--- a/base/memory/weak_ptr.cc
+++ b/base/memory/weak_ptr.cc
@@ -68,14 +68,12 @@
   }
 }
 
-WeakPtrBase::WeakPtrBase() {
-}
+WeakPtrBase::WeakPtrBase() : ptr_(0) {}
 
-WeakPtrBase::~WeakPtrBase() {
-}
+WeakPtrBase::~WeakPtrBase() {}
 
-WeakPtrBase::WeakPtrBase(const WeakReference& ref) : ref_(ref) {
-}
+WeakPtrBase::WeakPtrBase(const WeakReference& ref, uintptr_t ptr)
+    : ref_(ref), ptr_(ptr) {}
 
 WeakPtrFactoryBase::WeakPtrFactoryBase(uintptr_t ptr) : ptr_(ptr) {}
 
diff --git a/base/memory/weak_ptr.h b/base/memory/weak_ptr.h
index d7d590b..5c9ed54 100644
--- a/base/memory/weak_ptr.h
+++ b/base/memory/weak_ptr.h
@@ -155,9 +155,13 @@
   WeakPtrBase& operator=(WeakPtrBase&& other) = default;
 
  protected:
-  explicit WeakPtrBase(const WeakReference& ref);
+  WeakPtrBase(const WeakReference& ref, uintptr_t ptr);
 
   WeakReference ref_;
+
+  // This pointer is only valid when ref_.is_valid() is true.  Otherwise, its
+  // value is undefined (as opposed to nullptr).
+  uintptr_t ptr_;
 };
 
 // This class provides a common implementation of common functions that would
@@ -185,7 +189,8 @@
   static WeakPtr<Derived> AsWeakPtrImpl(
       Derived* t, const SupportsWeakPtr<Base>&) {
     WeakPtr<Base> ptr = t->Base::AsWeakPtr();
-    return WeakPtr<Derived>(ptr.ref_, static_cast<Derived*>(ptr.ptr_));
+    return WeakPtr<Derived>(
+        ptr.ref_, static_cast<Derived*>(reinterpret_cast<Base*>(ptr.ptr_)));
   }
 };
 
@@ -209,20 +214,30 @@
 template <typename T>
 class WeakPtr : public internal::WeakPtrBase {
  public:
-  WeakPtr() : ptr_(nullptr) {}
+  WeakPtr() {}
 
-  WeakPtr(std::nullptr_t) : ptr_(nullptr) {}
+  WeakPtr(std::nullptr_t) {}
 
   // Allow conversion from U to T provided U "is a" T. Note that this
   // is separate from the (implicit) copy and move constructors.
   template <typename U>
-  WeakPtr(const WeakPtr<U>& other) : WeakPtrBase(other), ptr_(other.ptr_) {
+  WeakPtr(const WeakPtr<U>& other) : WeakPtrBase(other) {
+    // Need to cast from U* to T* to do pointer adjustment in case of multiple
+    // inheritance. This also enforces the "U is a T" rule.
+    T* t = reinterpret_cast<U*>(other.ptr_);
+    ptr_ = reinterpret_cast<uintptr_t>(t);
   }
   template <typename U>
-  WeakPtr(WeakPtr<U>&& other)
-      : WeakPtrBase(std::move(other)), ptr_(other.ptr_) {}
+  WeakPtr(WeakPtr<U>&& other) : WeakPtrBase(std::move(other)) {
+    // Need to cast from U* to T* to do pointer adjustment in case of multiple
+    // inheritance. This also enforces the "U is a T" rule.
+    T* t = reinterpret_cast<U*>(other.ptr_);
+    ptr_ = reinterpret_cast<uintptr_t>(t);
+  }
 
-  T* get() const { return ref_.is_valid() ? ptr_ : nullptr; }
+  T* get() const {
+    return ref_.is_valid() ? reinterpret_cast<T*>(ptr_) : nullptr;
+  }
 
   T& operator*() const {
     DCHECK(get() != nullptr);
@@ -235,7 +250,7 @@
 
   void reset() {
     ref_ = internal::WeakReference();
-    ptr_ = nullptr;
+    ptr_ = 0;
   }
 
   // Allow conditionals to test validity, e.g. if (weak_ptr) {...};
@@ -248,13 +263,7 @@
   friend class WeakPtrFactory<T>;
 
   WeakPtr(const internal::WeakReference& ref, T* ptr)
-      : WeakPtrBase(ref),
-        ptr_(ptr) {
-  }
-
-  // This pointer is only valid when ref_.is_valid() is true.  Otherwise, its
-  // value is undefined (as opposed to nullptr).
-  T* ptr_;
+      : WeakPtrBase(ref, reinterpret_cast<uintptr_t>(ptr)) {}
 };
 
 // Allow callers to compare WeakPtrs against nullptr to test validity.
diff --git a/base/memory/weak_ptr_unittest.nc b/base/memory/weak_ptr_unittest.nc
index 9b1226b7..8efb59e7 100644
--- a/base/memory/weak_ptr_unittest.nc
+++ b/base/memory/weak_ptr_unittest.nc
@@ -17,7 +17,7 @@
 struct Unrelated {};
 struct DerivedUnrelated : Unrelated {};
 
-#if defined(NCTEST_AUTO_DOWNCAST)  // [r"fatal error: cannot initialize a member subobject of type 'base::DerivedProducer \*' with an lvalue of type 'base::Producer \*const'"]
+#if defined(NCTEST_AUTO_DOWNCAST)  // [r"cannot initialize a variable of type 'base::DerivedProducer \*' with an rvalue of type 'base::Producer \*'"]
 
 void WontCompile() {
   Producer f;
@@ -25,7 +25,7 @@
   WeakPtr<DerivedProducer> derived_ptr = ptr;
 }
 
-#elif defined(NCTEST_STATIC_DOWNCAST)  // [r"fatal error: cannot initialize a member subobject of type 'base::DerivedProducer \*' with an lvalue of type 'base::Producer \*const'"]
+#elif defined(NCTEST_STATIC_DOWNCAST)  // [r"cannot initialize a variable of type 'base::DerivedProducer \*' with an rvalue of type 'base::Producer \*'"]
 
 void WontCompile() {
   Producer f;
@@ -59,7 +59,7 @@
       SupportsWeakPtr<Producer>::StaticAsWeakPtr<DerivedProducer>(&f);
 }
 
-#elif defined(NCTEST_UNSAFE_HELPER_DOWNCAST)  // [r"fatal error: cannot initialize a member subobject of type 'base::DerivedProducer \*' with an lvalue of type 'base::Producer \*'"]
+#elif defined(NCTEST_UNSAFE_HELPER_DOWNCAST)  // [r"cannot initialize a variable of type 'base::DerivedProducer \*' with an rvalue of type 'base::Producer \*'"]
 
 void WontCompile() {
   Producer f;
@@ -73,14 +73,14 @@
   WeakPtr<DerivedProducer> ptr = AsWeakPtr<DerivedProducer>(&f);
 }
 
-#elif defined(NCTEST_UNSAFE_WRONG_INSANTIATED_HELPER_DOWNCAST)  // [r"fatal error: cannot initialize a member subobject of type 'base::DerivedProducer \*' with an lvalue of type 'base::Producer \*'"]
+#elif defined(NCTEST_UNSAFE_WRONG_INSANTIATED_HELPER_DOWNCAST)  // [r"cannot initialize a variable of type 'base::DerivedProducer \*' with an rvalue of type 'base::Producer \*'"]
 
 void WontCompile() {
-  Producer f; 
+  Producer f;
   WeakPtr<DerivedProducer> ptr = AsWeakPtr<Producer>(&f);
 }
 
-#elif defined(NCTEST_UNSAFE_HELPER_CAST)  // [r"fatal error: cannot initialize a member subobject of type 'base::OtherDerivedProducer \*' with an lvalue of type 'base::DerivedProducer \*'"]
+#elif defined(NCTEST_UNSAFE_HELPER_CAST)  // [r"cannot initialize a variable of type 'base::OtherDerivedProducer \*' with an rvalue of type 'base::DerivedProducer \*'"]
 
 void WontCompile() {
   DerivedProducer f;
@@ -94,14 +94,14 @@
   WeakPtr<OtherDerivedProducer> ptr = AsWeakPtr<OtherDerivedProducer>(&f);
 }
 
-#elif defined(NCTEST_UNSAFE_WRONG_INSTANTIATED_HELPER_SIDECAST)  // [r"fatal error: cannot initialize a member subobject of type 'base::OtherDerivedProducer \*' with an lvalue of type 'base::DerivedProducer \*'"]
+#elif defined(NCTEST_UNSAFE_WRONG_INSTANTIATED_HELPER_SIDECAST)  // [r"cannot initialize a variable of type 'base::OtherDerivedProducer \*' with an rvalue of type 'base::DerivedProducer \*'"]
 
 void WontCompile() {
   DerivedProducer f;
   WeakPtr<OtherDerivedProducer> ptr = AsWeakPtr<DerivedProducer>(&f);
 }
 
-#elif defined(NCTEST_UNRELATED_HELPER)  // [r"fatal error: cannot initialize a member subobject of type 'base::Unrelated \*' with an lvalue of type 'base::DerivedProducer \*'"]
+#elif defined(NCTEST_UNRELATED_HELPER)  // [r"cannot initialize a variable of type 'base::Unrelated \*' with an rvalue of type 'base::DerivedProducer \*'"]
 
 void WontCompile() {
   DerivedProducer f;
diff --git a/base/message_loop/message_pump_fuchsia.cc b/base/message_loop/message_pump_fuchsia.cc
index a4d4770..7d8b547b 100644
--- a/base/message_loop/message_pump_fuchsia.cc
+++ b/base/message_loop/message_pump_fuchsia.cc
@@ -26,9 +26,9 @@
 }
 
 bool MessagePumpFuchsia::FileDescriptorWatcher::StopWatchingFileDescriptor() {
-  uint64_t controller_as_key =
+  uint64_t this_as_key =
       static_cast<uint64_t>(reinterpret_cast<uintptr_t>(this));
-  return mx_port_cancel(port_, handle_, controller_as_key) == MX_OK;
+  return mx_port_cancel(port_, handle_, this_as_key) == MX_OK;
 }
 
 MessagePumpFuchsia::MessagePumpFuchsia() : keep_running_(true) {
@@ -50,7 +50,9 @@
   DCHECK_GE(fd, 0);
   DCHECK(controller);
   DCHECK(delegate);
-  DCHECK(!persistent);  // TODO(fuchsia): Not yet implemented.
+  controller->watcher_ = delegate;
+  controller->port_ = port_;
+
   DCHECK(mode == WATCH_READ || mode == WATCH_WRITE || mode == WATCH_READ_WRITE);
 
   uint32_t events;
@@ -69,25 +71,28 @@
       return false;
   }
 
+  controller->desired_events_ = events;
+
   controller->io_ = __mxio_fd_to_io(fd);
   if (!controller->io_)
     return false;
 
-  controller->watcher_ = delegate;
   controller->fd_ = fd;
-  controller->desired_events_ = events;
+  controller->persistent_ = persistent;
 
-  uint32_t signals;
-  __mxio_wait_begin(controller->io_, events, &controller->handle_, &signals);
-  if (controller->handle_ == MX_HANDLE_INVALID)
+  return controller->WaitBegin();
+}
+
+bool MessagePumpFuchsia::FileDescriptorWatcher::WaitBegin() {
+  uint32_t signals = 0u;
+  __mxio_wait_begin(io_, desired_events_, &handle_, &signals);
+  if (handle_ == MX_HANDLE_INVALID)
     return false;
-  controller->port_ = port_;
 
-  uint64_t controller_as_key =
-      static_cast<uint64_t>(reinterpret_cast<uintptr_t>(controller));
-  mx_status_t status =
-      mx_object_wait_async(controller->handle_, port_, controller_as_key,
-                           signals, MX_WAIT_ASYNC_ONCE);
+  uint64_t this_as_key =
+      static_cast<uint64_t>(reinterpret_cast<uintptr_t>(this));
+  mx_status_t status = mx_object_wait_async(handle_, port_, this_as_key,
+                                            signals, MX_WAIT_ASYNC_ONCE);
   if (status != MX_OK) {
     DLOG(ERROR) << "mx_object_wait_async failed: " << status;
     return false;
@@ -95,6 +100,18 @@
   return true;
 }
 
+uint32_t MessagePumpFuchsia::FileDescriptorWatcher::WaitEnd(uint32_t observed) {
+  uint32_t events;
+  __mxio_wait_end(io_, observed, &events);
+  // |observed| can include other spurious things, in particular, that the fd
+  // is writable, when we only asked to know when it was readable. In that
+  // case, we don't want to call both the CanWrite and CanRead callback,
+  // when the caller asked for only, for example, readable callbacks. So,
+  // mask with the events that we actually wanted to know about.
+  events &= desired_events_;
+  return events;
+}
+
 void MessagePumpFuchsia::Run(Delegate* delegate) {
   DCHECK(keep_running_);
 
@@ -137,25 +154,18 @@
 
       DCHECK(packet.signal.trigger & packet.signal.observed);
 
-      uint32_t events;
-      __mxio_wait_end(controller->io_, packet.signal.observed, &events);
-      // .observed can include other spurious things, in particular, that the fd
-      // is writable, when we only asked to know when it was readable. In that
-      // case, we don't want to call both the CanWrite and CanRead callback,
-      // when the caller asked for only, for example, readable callbacks. So,
-      // mask with the events that we actually wanted to know about.
-      events &= controller->desired_events_;
+      uint32_t events = controller->WaitEnd(packet.signal.observed);
 
+      // Multiple callbacks may be called, must check controller destruction
+      // after the first callback is run, which is done by letting the
+      // destructor set a bool here (which is located on the stack). If it's set
+      // during the first callback, then the controller was destroyed during the
+      // first callback so we do not call the second one, as the controller
+      // pointer is now invalid.
+      bool controller_was_destroyed = false;
+      controller->was_destroyed_ = &controller_was_destroyed;
       if ((events & (MXIO_EVT_READABLE | MXIO_EVT_WRITABLE)) ==
           (MXIO_EVT_READABLE | MXIO_EVT_WRITABLE)) {
-        // Both callbacks to be called, must check controller destruction after
-        // the first callback is run, which is done by letting the destructor
-        // set a bool here (which is located on the stack). If it's set during
-        // the first callback, then the controller was destroyed during the
-        // first callback so we do not call the second one, as the controller
-        // pointer is now invalid.
-        bool controller_was_destroyed = false;
-        controller->was_destroyed_ = &controller_was_destroyed;
         controller->watcher_->OnFileCanWriteWithoutBlocking(controller->fd_);
         if (!controller_was_destroyed)
           controller->watcher_->OnFileCanReadWithoutBlocking(controller->fd_);
@@ -166,6 +176,9 @@
       } else if (events & MXIO_EVT_READABLE) {
         controller->watcher_->OnFileCanReadWithoutBlocking(controller->fd_);
       }
+      if (!controller_was_destroyed && controller->persistent_) {
+        controller->WaitBegin();
+      }
     } else {
       // Wakeup caused by ScheduleWork().
       DCHECK(packet.type == MX_PKT_TYPE_USER);
diff --git a/base/message_loop/message_pump_fuchsia.h b/base/message_loop/message_pump_fuchsia.h
index b175025..3ca0785 100644
--- a/base/message_loop/message_pump_fuchsia.h
+++ b/base/message_loop/message_pump_fuchsia.h
@@ -44,6 +44,13 @@
     }
 
    private:
+    // Start watching the FD.
+    bool WaitBegin();
+
+    // Stop watching the FD. Returns the set of events the watcher is interested
+    // in based on the observed bits from the underlying packet.
+    uint32_t WaitEnd(uint32_t observed);
+
     friend class MessagePumpFuchsia;
 
     const tracked_objects::Location created_from_location_;
@@ -62,6 +69,10 @@
     // to true in ~FileDescriptorWatcher() to handle this case.
     bool* was_destroyed_ = nullptr;
 
+    // A watch may be marked as persistent, which means it remains active even
+    // after triggering.
+    bool persistent_ = false;
+
     DISALLOW_COPY_AND_ASSIGN(FileDescriptorWatcher);
   };
 
diff --git a/base/process/launch_win.cc b/base/process/launch_win.cc
index f55c9684..f7ce62b 100644
--- a/base/process/launch_win.cc
+++ b/base/process/launch_win.cc
@@ -253,7 +253,7 @@
   if (options.empty_desktop_name)
     startup_info->lpDesktop = const_cast<wchar_t*>(L"");
   startup_info->dwFlags = STARTF_USESHOWWINDOW;
-  startup_info->wShowWindow = options.start_hidden ? SW_HIDE : SW_SHOW;
+  startup_info->wShowWindow = options.start_hidden ? SW_HIDE : SW_SHOWNORMAL;
 
   if (options.stdin_handle || options.stdout_handle || options.stderr_handle) {
     DCHECK(inherit_handles);
@@ -350,7 +350,7 @@
   shex_info.lpFile = file.c_str();
   shex_info.lpParameters = arguments.c_str();
   shex_info.lpDirectory = nullptr;
-  shex_info.nShow = options.start_hidden ? SW_HIDE : SW_SHOW;
+  shex_info.nShow = options.start_hidden ? SW_HIDE : SW_SHOWNORMAL;
   shex_info.hInstApp = nullptr;
 
   if (!ShellExecuteEx(&shex_info)) {
diff --git a/build/android/pylib/local/device/local_device_gtest_run.py b/build/android/pylib/local/device/local_device_gtest_run.py
index e4c6aef..f78f2ff 100644
--- a/build/android/pylib/local/device/local_device_gtest_run.py
+++ b/build/android/pylib/local/device/local_device_gtest_run.py
@@ -9,6 +9,7 @@
 import posixpath
 import time
 
+from devil.android import crash_handler
 from devil.android import device_errors
 from devil.android import device_temp_file
 from devil.android import ports
@@ -360,8 +361,10 @@
     @local_device_environment.handle_shard_failures_with(
         on_failure=self._env.BlacklistDevice)
     def list_tests(dev):
-      raw_test_list = self._delegate.Run(
-          None, dev, flags='--gtest_list_tests', timeout=30)
+      raw_test_list = crash_handler.RetryOnSystemCrash(
+          lambda d: self._delegate.Run(
+              None, d, flags='--gtest_list_tests', timeout=30),
+          device=dev)
       tests = gtest_test_instance.ParseGTestListTests(raw_test_list)
       if not tests:
         logging.info('No tests found. Output:')
diff --git a/build/android/pylib/local/device/local_device_test_run.py b/build/android/pylib/local/device/local_device_test_run.py
index 14c4366..71a234a 100644
--- a/build/android/pylib/local/device/local_device_test_run.py
+++ b/build/android/pylib/local/device/local_device_test_run.py
@@ -10,6 +10,7 @@
 import thread
 import threading
 
+from devil.android import crash_handler
 from devil.utils import signal_handler
 from pylib import valgrind_tools
 from pylib.base import base_test_result
@@ -86,7 +87,9 @@
         result = None
         rerun = None
         try:
-          result, rerun = self._RunTest(dev, test)
+          result, rerun = crash_handler.RetryOnSystemCrash(
+              lambda d, t=test: self._RunTest(d, t),
+              device=dev)
           if isinstance(result, base_test_result.BaseTestResult):
             results.AddResult(result)
           elif isinstance(result, list):
@@ -215,6 +218,7 @@
 
   def _GetTests(self):
     raise NotImplementedError
+
   def _RunTest(self, device, test):
     raise NotImplementedError
 
diff --git a/build/android/test_runner.pydeps b/build/android/test_runner.pydeps
index 63326874..bdf0596 100644
--- a/build/android/test_runner.pydeps
+++ b/build/android/test_runner.pydeps
@@ -31,6 +31,7 @@
 ../../third_party/catapult/devil/devil/android/constants/__init__.py
 ../../third_party/catapult/devil/devil/android/constants/chrome.py
 ../../third_party/catapult/devil/devil/android/constants/file_system.py
+../../third_party/catapult/devil/devil/android/crash_handler.py
 ../../third_party/catapult/devil/devil/android/decorators.py
 ../../third_party/catapult/devil/devil/android/device_blacklist.py
 ../../third_party/catapult/devil/devil/android/device_errors.py
diff --git a/build/config/c++/c++.gni b/build/config/c++/c++.gni
index e83c50e..5a62670a 100644
--- a/build/config/c++/c++.gni
+++ b/build/config/c++/c++.gni
@@ -12,8 +12,12 @@
   # Use libc++ (buildtools/third_party/libc++ and
   # buildtools/third_party/libc++abi) instead of stdlibc++ as standard
   # library.
+  # TODO(thomasanderson): Clean up this complex condition.  The
+  # is_tsan, is_msan, and (use_libfuzzer && !is_mac), clauses can be
+  # removed since they are only used on non-CrOs Linux.  is_ubsan can
+  # probably also be removed for the same reason.
   use_custom_libcxx =
-      (is_asan && is_linux && !is_chromeos &&
-       (!is_chromecast || is_cast_desktop_build)) || is_tsan || is_msan ||
-      is_ubsan || is_ubsan_security || (use_libfuzzer && !is_mac) || use_afl
+      (is_linux && !is_chromeos && (!is_chromecast || is_cast_desktop_build)) ||
+      is_tsan || is_msan || is_ubsan || is_ubsan_security ||
+      (use_libfuzzer && !is_mac) || use_afl
 }
diff --git a/build/config/features.gni b/build/config/features.gni
index d143dac..5323602d 100644
--- a/build/config/features.gni
+++ b/build/config/features.gni
@@ -24,7 +24,7 @@
   # Enables Native Client support.
   # Temporarily disable nacl on arm64 linux to get rid of compilation errors.
   # TODO(mcgrathr): When mipsel-nacl-clang is available, drop the exclusion.
-  enable_nacl = !is_ios && !is_android && !is_chromecast &&
+  enable_nacl = !is_ios && !is_android && !is_fuchsia && !is_chromecast &&
                 current_cpu != "mipsel" && !(is_linux && target_cpu == "arm64")
 
   # Non-SFI is not yet supported on mipsel
diff --git a/build/config/ios/rules.gni b/build/config/ios/rules.gni
index fc6c681..3d3f0cfd 100644
--- a/build/config/ios/rules.gni
+++ b/build/config/ios/rules.gni
@@ -323,7 +323,6 @@
     }
     extra_substitutions += [
       "IOS_BUNDLE_ID_PREFIX=$ios_app_bundle_id_prefix",
-      "IOS_DEPLOYMENT_TARGET=$ios_deployment_target",
       "IOS_PLATFORM_BUILD=$ios_platform_build",
       "IOS_PLATFORM_NAME=$ios_sdk_name",
       "IOS_PLATFORM_VERSION=$ios_sdk_version",
diff --git a/build/config/mac/base_rules.gni b/build/config/mac/base_rules.gni
index 341c750..941b5df 100644
--- a/build/config/mac/base_rules.gni
+++ b/build/config/mac/base_rules.gni
@@ -196,6 +196,11 @@
       "XCODE_BUILD=$xcode_build",
       "XCODE_VERSION=$xcode_version",
     ]
+    if (is_mac) {
+      substitutions += [ "MACOSX_DEPLOYMENT_TARGET=$mac_deployment_target" ]
+    } else if (is_ios) {
+      substitutions += [ "IOS_DEPLOYMENT_TARGET=$ios_deployment_target" ]
+    }
     if (defined(invoker.extra_substitutions)) {
       substitutions += invoker.extra_substitutions
     }
diff --git a/build/config/mac/mac_sdk.gni b/build/config/mac/mac_sdk.gni
index 2b2501c..3a651e6 100644
--- a/build/config/mac/mac_sdk.gni
+++ b/build/config/mac/mac_sdk.gni
@@ -14,8 +14,9 @@
   # Minimum supported version of the Mac SDK.
   mac_sdk_min = mac_sdk_min_build_override
 
-  # Minimum supported version of OSX.
-  mac_deployment_target = "10.9"
+  # Minimum supported version of macOS. Must be of the form x.x.x for
+  # Info.plist files.
+  mac_deployment_target = "10.9.0"
 
   # Path to a specific version of the Mac SDK, not including a slash at the end.
   # If empty, the path to the lowest version greater than or equal to
diff --git a/build/get_landmines.py b/build/get_landmines.py
index 481240f..4819700 100755
--- a/build/get_landmines.py
+++ b/build/get_landmines.py
@@ -28,6 +28,16 @@
   # need to be cleaned up. If you're writing a new CL that causes build
   # dependency problems, fix the dependency problems instead of adding a
   # landmine.
+  #
+  # Before adding or changing a landmine consider the consequences of doing so.
+  # Doing so will wipe out every output directory on every Chrome developer's
+  # machine. This can be particularly problematic on Windows where the directory
+  # deletion may well fail (locked files, command prompt in the directory,
+  # etc.), and generated .sln and .vcxproj files will be deleted.
+  #
+  # This output directory deletion will be repeated when going back and forth
+  # across the change that added the landmine, adding to the cost. There are
+  # usually less troublesome alternatives.
 
   if distributor() == 'goma' and platform() == 'win32':
     print 'Need to clobber winja goma due to backend cwd cache fix.'
diff --git a/build/install-build-deps.sh b/build/install-build-deps.sh
index fcb62a05..0a1e3f3 100755
--- a/build/install-build-deps.sh
+++ b/build/install-build-deps.sh
@@ -112,7 +112,7 @@
 
 distro_codename=$(lsb_release --codename --short)
 distro_id=$(lsb_release --id --short)
-supported_codenames="(trusty|xenial|yakkety)"
+supported_codenames="(trusty|xenial|yakkety|zesty)"
 supported_ids="(Debian)"
 if [ 0 -eq "${do_unsupported-0}" ] && [ 0 -eq "${do_quick_check-0}" ] ; then
   if [[ ! $distro_codename =~ $supported_codenames &&
@@ -121,6 +121,7 @@
       "\tUbuntu 14.04 (trusty)\n" \
       "\tUbuntu 16.04 (xenial)\n" \
       "\tUbuntu 16.10 (yakkety)\n" \
+      "\tUbuntu 17.04 (zesty)\n" \
       "\tDebian 8 (jessie) or later" >&2
     exit 1
   fi
@@ -359,7 +360,7 @@
     arm_list+=" g++-4.8-multilib-arm-linux-gnueabihf
                 gcc-4.8-multilib-arm-linux-gnueabihf"
     ;;
-  xenial|yakkety)
+  xenial|yakkety|zesty)
     arm_list+=" g++-5-multilib-arm-linux-gnueabihf
                 gcc-5-multilib-arm-linux-gnueabihf
                 gcc-arm-linux-gnueabihf"
diff --git a/build/vs_toolchain.py b/build/vs_toolchain.py
index 2f1ef173..e131a0d 100755
--- a/build/vs_toolchain.py
+++ b/build/vs_toolchain.py
@@ -311,7 +311,7 @@
 
 
 def _CopyDebugger(target_dir, target_cpu):
-  """Copy dbghelp.dll into the requested directory as needed.
+  """Copy dbghelp.dll and dbgcore.dll into the requested directory as needed.
 
   target_cpu is one of 'x86' or 'x64'.
 
@@ -319,19 +319,23 @@
   from the SDK directory avoids using the system copy of dbghelp.dll which then
   ensures compatibility with recent debug information formats, such as VS
   2017 /debug:fastlink PDBs.
+
+  dbgcore.dll is needed when using some functions from dbghelp.dll (like
+  MinidumpWriteDump).
   """
   win_sdk_dir = SetEnvironmentAndGetSDKDir()
   if not win_sdk_dir:
     return
 
-  debug_file = 'dbghelp.dll'
-  full_path = os.path.join(win_sdk_dir, 'Debuggers', target_cpu, debug_file)
-  if not os.path.exists(full_path):
-    raise Exception('dbghelp.dll not found in "%s"\r\nYou must install the '
-                    '"Debugging Tools for Windows" feature from the Windows '
-                    '10 SDK.' % full_path)
-  target_path = os.path.join(target_dir, debug_file)
-  _CopyRuntimeImpl(target_path, full_path)
+  debug_files = ['dbghelp.dll', 'dbgcore.dll']
+  for debug_file in debug_files:
+    full_path = os.path.join(win_sdk_dir, 'Debuggers', target_cpu, debug_file)
+    if not os.path.exists(full_path):
+      raise Exception('%s not found in "%s"\r\nYou must install the '
+                      '"Debugging Tools for Windows" feature from the Windows '
+                      '10 SDK.' % (debug_file, full_path))
+    target_path = os.path.join(target_dir, debug_file)
+    _CopyRuntimeImpl(target_path, full_path)
 
 
 def _GetDesiredVsToolchainHashes():
diff --git a/cc/ipc/cc_serialization_perftest.cc b/cc/ipc/cc_serialization_perftest.cc
index 51e27869..6d731c0 100644
--- a/cc/ipc/cc_serialization_perftest.cc
+++ b/cc/ipc/cc_serialization_perftest.cc
@@ -230,7 +230,7 @@
   static void RunComplexCompositorFrameTest(const std::string& test_name) {
     CompositorFrame frame;
 
-    TransferableResourceArray& resource_list = frame.resource_list;
+    std::vector<TransferableResource>& resource_list = frame.resource_list;
     for (uint32_t i = 0; i < 80; ++i) {
       TransferableResource arbitrary_resource;
       resource_list.push_back(arbitrary_resource);
diff --git a/cc/ipc/compositor_frame_sink.mojom b/cc/ipc/compositor_frame_sink.mojom
index 94fd8d1..41cc741 100644
--- a/cc/ipc/compositor_frame_sink.mojom
+++ b/cc/ipc/compositor_frame_sink.mojom
@@ -48,13 +48,13 @@
   // TODO(fsamuel): This method ought not be necessary with unified BeginFrame.
   // However, there's a fair amount of cleanup and refactoring necessary to get
   // rid of it.
-  DidReceiveCompositorFrameAck(ReturnedResourceArray resources);
+  DidReceiveCompositorFrameAck(array<ReturnedResource> resources);
 
   // Notification for the client to generate a CompositorFrame.
   OnBeginFrame(BeginFrameArgs args);
 
   // Returns resources sent to SubmitCompositorFrame to be reused or freed.
-  ReclaimResources(ReturnedResourceArray resources);
+  ReclaimResources(array<ReturnedResource> resources);
 };
 
 // CompositorFrameSinkPrivate connects the host process to viz and allows the
diff --git a/cc/ipc/compositor_frame_struct_traits.h b/cc/ipc/compositor_frame_struct_traits.h
index 63c191bd..fbb356e7 100644
--- a/cc/ipc/compositor_frame_struct_traits.h
+++ b/cc/ipc/compositor_frame_struct_traits.h
@@ -17,7 +17,7 @@
     return input.metadata;
   }
 
-  static const cc::TransferableResourceArray& resources(
+  static const std::vector<cc::TransferableResource>& resources(
       const cc::CompositorFrame& input) {
     return input.resource_list;
   }
diff --git a/cc/ipc/returned_resource.mojom b/cc/ipc/returned_resource.mojom
index 16e673e0..396d2e6f 100644
--- a/cc/ipc/returned_resource.mojom
+++ b/cc/ipc/returned_resource.mojom
@@ -13,7 +13,3 @@
   int32 count;
   bool lost;
 };
-
-struct ReturnedResourceArray {
-  array<ReturnedResource> returned_resources;
-};
diff --git a/cc/ipc/returned_resource_struct_traits.h b/cc/ipc/returned_resource_struct_traits.h
index e7a1f1ef..2ca18f4 100644
--- a/cc/ipc/returned_resource_struct_traits.h
+++ b/cc/ipc/returned_resource_struct_traits.h
@@ -40,20 +40,6 @@
   }
 };
 
-template <>
-struct StructTraits<cc::mojom::ReturnedResourceArrayDataView,
-                    cc::ReturnedResourceArray> {
-  static const cc::ReturnedResourceArray& returned_resources(
-      const cc::ReturnedResourceArray& resource_array) {
-    return resource_array;
-  }
-
-  static bool Read(cc::mojom::ReturnedResourceArrayDataView data,
-                   cc::ReturnedResourceArray* out) {
-    return data.ReadReturnedResources(out);
-  }
-};
-
 }  // namespace mojo
 
 #endif  // CC_IPC_RETURNED_RESOURCE_STRUCT_TRAITS_H_
diff --git a/cc/layers/texture_layer_unittest.cc b/cc/layers/texture_layer_unittest.cc
index 7e224a8..73e48a4 100644
--- a/cc/layers/texture_layer_unittest.cc
+++ b/cc/layers/texture_layer_unittest.cc
@@ -1066,7 +1066,7 @@
   // Transfer some resources to the parent.
   ResourceProvider::ResourceIdArray resource_ids_to_transfer;
   resource_ids_to_transfer.push_back(id);
-  TransferableResourceArray list;
+  std::vector<TransferableResource> list;
   provider->PrepareSendToParent(resource_ids_to_transfer, &list);
   EXPECT_TRUE(provider->InUseByConsumer(id));
   EXPECT_CALL(test_data_.mock_callback_, ReleaseImpl(_, _, _, _)).Times(0);
@@ -1074,8 +1074,8 @@
   Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
   EXPECT_CALL(test_data_.mock_callback_,
               ReleaseImpl(test_data_.mailbox_name1_, _, false, _)).Times(1);
-  ReturnedResourceArray returned;
-  TransferableResource::ReturnResources(list, &returned);
+  std::vector<ReturnedResource> returned =
+      TransferableResource::ReturnResources(list);
   provider->ReceiveReturnsFromParent(returned);
 }
 
diff --git a/cc/output/compositor_frame.h b/cc/output/compositor_frame.h
index 1ee3fb7..362a597 100644
--- a/cc/output/compositor_frame.h
+++ b/cc/output/compositor_frame.h
@@ -31,7 +31,7 @@
   CompositorFrame& operator=(CompositorFrame&& other);
 
   CompositorFrameMetadata metadata;
-  TransferableResourceArray resource_list;
+  std::vector<TransferableResource> resource_list;
   // This list is in the order that each RenderPass will be drawn. The last one
   // is the "root" RenderPass that all others are directly or indirectly drawn
   // into.
diff --git a/cc/output/layer_tree_frame_sink_client.h b/cc/output/layer_tree_frame_sink_client.h
index 9cf8728..1015f5b 100644
--- a/cc/output/layer_tree_frame_sink_client.h
+++ b/cc/output/layer_tree_frame_sink_client.h
@@ -31,7 +31,8 @@
   virtual void SetBeginFrameSource(BeginFrameSource* source) = 0;
 
   // Returns resources sent to SubmitCompositorFrame to be reused or freed.
-  virtual void ReclaimResources(const ReturnedResourceArray& resources) = 0;
+  virtual void ReclaimResources(
+      const std::vector<ReturnedResource>& resources) = 0;
 
   // If set, |callback| will be called subsequent to each new tree activation,
   // regardless of the compositor visibility or damage. |callback| must remain
diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc
index bf8046f..ad18719 100644
--- a/cc/resources/resource_provider.cc
+++ b/cc/resources/resource_provider.cc
@@ -1476,8 +1476,9 @@
   return it->second.child_to_parent_map;
 }
 
-void ResourceProvider::PrepareSendToParent(const ResourceIdArray& resource_ids,
-                                           TransferableResourceArray* list) {
+void ResourceProvider::PrepareSendToParent(
+    const ResourceIdArray& resource_ids,
+    std::vector<TransferableResource>* list) {
   DCHECK(thread_checker_.CalledOnValidThread());
   GLES2Interface* gl = ContextGL();
 
@@ -1566,12 +1567,12 @@
 
 void ResourceProvider::ReceiveFromChild(
     int child,
-    const TransferableResourceArray& resources) {
+    const std::vector<TransferableResource>& resources) {
   DCHECK(thread_checker_.CalledOnValidThread());
   GLES2Interface* gl = ContextGL();
   Child& child_info = children_.find(child)->second;
   DCHECK(!child_info.marked_for_deletion);
-  for (TransferableResourceArray::const_iterator it = resources.begin();
+  for (std::vector<TransferableResource>::const_iterator it = resources.begin();
        it != resources.end(); ++it) {
     ResourceIdMap::iterator resource_in_map_it =
         child_info.child_to_parent_map.find(it->id);
@@ -1585,7 +1586,7 @@
     if ((!it->is_software && !gl) ||
         (it->is_software && !shared_bitmap_manager_)) {
       TRACE_EVENT0("cc", "ResourceProvider::ReceiveFromChild dropping invalid");
-      ReturnedResourceArray to_return;
+      std::vector<ReturnedResource> to_return;
       to_return.push_back(it->ToReturnedResource());
       child_info.return_callback.Run(to_return,
                                      blocking_main_thread_task_runner_);
@@ -1649,7 +1650,7 @@
 }
 
 void ResourceProvider::ReceiveReturnsFromParent(
-    const ReturnedResourceArray& resources) {
+    const std::vector<ReturnedResource>& resources) {
   DCHECK(thread_checker_.CalledOnValidThread());
   GLES2Interface* gl = ContextGL();
 
@@ -1822,7 +1823,7 @@
   if (unused.empty() && !child_info->marked_for_deletion)
     return;
 
-  ReturnedResourceArray to_return;
+  std::vector<ReturnedResource> to_return;
   to_return.reserve(unused.size());
   std::vector<ReturnedResource*> need_synchronization_resources;
   std::vector<GLbyte*> unverified_sync_tokens;
diff --git a/cc/resources/resource_provider.h b/cc/resources/resource_provider.h
index 238cc13..af2f322 100644
--- a/cc/resources/resource_provider.h
+++ b/cc/resources/resource_provider.h
@@ -192,8 +192,9 @@
   // mailboxes and serializing meta-data into TransferableResources.
   // Resources are not removed from the ResourceProvider, but are marked as
   // "in use".
-  void PrepareSendToParent(const ResourceIdArray& resource_ids,
-                           TransferableResourceArray* transferable_resources);
+  void PrepareSendToParent(
+      const ResourceIdArray& resource_ids,
+      std::vector<TransferableResource>* transferable_resources);
 
   // Receives resources from a child, moving them from mailboxes. Resource IDs
   // passed are in the child namespace, and will be translated to the parent
@@ -205,7 +206,8 @@
   // NOTE: if the sync_token is set on any TransferableResource, this will
   // wait on it.
   void ReceiveFromChild(
-      int child, const TransferableResourceArray& transferable_resources);
+      int child,
+      const std::vector<TransferableResource>& transferable_resources);
 
   // Once a set of resources have been received, they may or may not be used.
   // This declares what set of resources are currently in use from the child,
@@ -218,7 +220,7 @@
   // NOTE: if the sync_token is set on any TransferableResource, this will
   // wait on it.
   void ReceiveReturnsFromParent(
-      const ReturnedResourceArray& transferable_resources);
+      const std::vector<ReturnedResource>& transferable_resources);
 
 #if defined(OS_ANDROID)
   // Send an overlay promotion hint to all resources that requested it via
diff --git a/cc/resources/resource_provider_unittest.cc b/cc/resources/resource_provider_unittest.cc
index 16d050c07..29468de9 100644
--- a/cc/resources/resource_provider_unittest.cc
+++ b/cc/resources/resource_provider_unittest.cc
@@ -476,13 +476,14 @@
 
   ResourceProviderTest() : ResourceProviderTest(true) {}
 
-  static void CollectResources(ReturnedResourceArray* array,
-                               const ReturnedResourceArray& returned,
+  static void CollectResources(std::vector<ReturnedResource>* array,
+                               const std::vector<ReturnedResource>& returned,
                                BlockingTaskRunner* main_thread_task_runner) {
     array->insert(array->end(), returned.begin(), returned.end());
   }
 
-  static ReturnCallback GetReturnCallback(ReturnedResourceArray* array) {
+  static ReturnCallback GetReturnCallback(
+      std::vector<ReturnedResource>* array) {
     return base::Bind(&ResourceProviderTest::CollectResources, array);
   }
 
@@ -663,7 +664,7 @@
       id4_mailbox,
       SingleReleaseCallbackImpl::Create(base::Bind(&EmptyReleaseCallback)));
 
-  ReturnedResourceArray returned_to_child;
+  std::vector<ReturnedResource> returned_to_child;
   int child_id =
       resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
 
@@ -678,7 +679,7 @@
     child_resource_provider_->GenerateSyncTokenForResources(
         resource_ids_to_transfer);
 
-    TransferableResourceArray list;
+    std::vector<TransferableResource> list;
     child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
                                                   &list);
     ASSERT_EQ(4u, list.size());
@@ -770,7 +771,7 @@
     resource_ids_to_transfer.push_back(id1);
     resource_ids_to_transfer.push_back(id2);
     resource_ids_to_transfer.push_back(id3);
-    TransferableResourceArray list;
+    std::vector<TransferableResource> list;
     child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
                                                   &list);
     EXPECT_EQ(3u, list.size());
@@ -783,8 +784,8 @@
               list[1].mailbox_holder.texture_target);
     EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D),
               list[2].mailbox_holder.texture_target);
-    ReturnedResourceArray returned;
-    TransferableResource::ReturnResources(list, &returned);
+    std::vector<ReturnedResource> returned =
+        TransferableResource::ReturnResources(list);
     child_resource_provider_->ReceiveReturnsFromParent(returned);
     // ids were exported twice, we returned them only once, they should still
     // be in-use.
@@ -842,7 +843,7 @@
     resource_ids_to_transfer.push_back(id2);
     resource_ids_to_transfer.push_back(id3);
     resource_ids_to_transfer.push_back(id4);
-    TransferableResourceArray list;
+    std::vector<TransferableResource> list;
     child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
                                                   &list);
     ASSERT_EQ(4u, list.size());
@@ -927,7 +928,7 @@
       id2_mailbox,
       SingleReleaseCallbackImpl::Create(base::Bind(&EmptyReleaseCallback)));
 
-  ReturnedResourceArray returned_to_child;
+  std::vector<ReturnedResource> returned_to_child;
   int child_id =
       resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
 
@@ -940,7 +941,7 @@
     child_resource_provider_->GenerateSyncTokenForResources(
         resource_ids_to_transfer);
 
-    TransferableResourceArray list;
+    std::vector<TransferableResource> list;
     child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
                                                   &list);
     ASSERT_EQ(2u, list.size());
@@ -1037,7 +1038,7 @@
                      GL_TEXTURE_EXTERNAL_OES),
       SingleReleaseCallbackImpl::Create(base::Bind(&EmptyReleaseCallback)));
 
-  ReturnedResourceArray returned_to_child;
+  std::vector<ReturnedResource> returned_to_child;
   int child_id =
       resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
   resource_provider_->SetChildNeedsSyncTokens(child_id, false);
@@ -1047,7 +1048,7 @@
     resource_ids_to_transfer.push_back(id1);
     resource_ids_to_transfer.push_back(id2);
     resource_ids_to_transfer.push_back(id3);
-    TransferableResourceArray list;
+    std::vector<TransferableResource> list;
     child_resource_provider_->GenerateSyncTokenForResources(
         resource_ids_to_transfer);
     child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
@@ -1113,7 +1114,7 @@
   ResourceFormat format = RGBA_8888;
 
   uint8_t data1[4] = {1, 2, 3, 4};
-  ReturnedResourceArray returned_to_child;
+  std::vector<ReturnedResource> returned_to_child;
   int child_id =
       resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
 
@@ -1131,7 +1132,7 @@
   child_resource_provider_->GenerateSyncTokenForResources(
       resource_ids_to_transfer);
 
-  TransferableResourceArray list;
+  std::vector<TransferableResource> list;
   child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
                                                 &list);
   ASSERT_EQ(2u, list.size());
@@ -1179,7 +1180,7 @@
   uint8_t data1[4] = {1, 2, 3, 4};
   child_resource_provider_->CopyToResource(id1, data1, size);
 
-  ReturnedResourceArray returned_to_child;
+  std::vector<ReturnedResource> returned_to_child;
   int child_id =
       resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
   {
@@ -1190,7 +1191,7 @@
     child_resource_provider_->GenerateSyncTokenForResources(
         resource_ids_to_transfer);
 
-    TransferableResourceArray list;
+    std::vector<TransferableResource> list;
     child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
                                                   &list);
     ASSERT_EQ(1u, list.size());
@@ -1249,7 +1250,7 @@
   uint8_t data1[4] = {1, 2, 3, 4};
   child_resource_provider_->CopyToResource(id1, data1, size);
   child_resource_provider_->EnableReadLockFencesForTesting(id1);
-  ReturnedResourceArray returned_to_child;
+  std::vector<ReturnedResource> returned_to_child;
   int child_id =
       resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
 
@@ -1260,7 +1261,7 @@
   child_resource_provider_->GenerateSyncTokenForResources(
       resource_ids_to_transfer);
 
-  TransferableResourceArray list;
+  std::vector<TransferableResource> list;
   child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
                                                 &list);
   ASSERT_EQ(1u, list.size());
@@ -1310,7 +1311,7 @@
       gfx::ColorSpace());
   child_resource_provider_->CopyToResource(id2, data, size);
 
-  ReturnedResourceArray returned_to_child;
+  std::vector<ReturnedResource> returned_to_child;
   int child_id =
       resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
 
@@ -1322,7 +1323,7 @@
   child_resource_provider_->GenerateSyncTokenForResources(
       resource_ids_to_transfer);
 
-  TransferableResourceArray list;
+  std::vector<TransferableResource> list;
   child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
                                                 &list);
   ASSERT_EQ(2u, list.size());
@@ -1378,7 +1379,7 @@
       gfx::ColorSpace());
   child_resource_provider_->CopyToResource(id2, data, size);
 
-  ReturnedResourceArray returned_to_child;
+  std::vector<ReturnedResource> returned_to_child;
   int child_id =
       resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
 
@@ -1390,7 +1391,7 @@
   child_resource_provider_->GenerateSyncTokenForResources(
       resource_ids_to_transfer);
 
-  TransferableResourceArray list;
+  std::vector<TransferableResource> list;
   child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
                                                 &list);
   ASSERT_EQ(2u, list.size());
@@ -1450,7 +1451,7 @@
       SingleReleaseCallbackImpl::Create(base::Bind(
           &SharedBitmapReleaseCallback, base::Passed(&shared_bitmap))));
 
-  ReturnedResourceArray returned_to_child;
+  std::vector<ReturnedResource> returned_to_child;
   int child_id =
       resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
   {
@@ -1463,7 +1464,7 @@
     child_resource_provider_->GenerateSyncTokenForResources(
         resource_ids_to_transfer);
 
-    TransferableResourceArray list;
+    std::vector<TransferableResource> list;
     child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
                                                   &list);
     ASSERT_EQ(3u, list.size());
@@ -1514,14 +1515,14 @@
     child_resource_provider_->GenerateSyncTokenForResources(
         resource_ids_to_transfer);
 
-    TransferableResourceArray list;
+    std::vector<TransferableResource> list;
     child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
                                                   &list);
     EXPECT_EQ(2u, list.size());
     EXPECT_EQ(id1, list[0].id);
     EXPECT_EQ(id2, list[1].id);
-    ReturnedResourceArray returned;
-    TransferableResource::ReturnResources(list, &returned);
+    std::vector<ReturnedResource> returned =
+        TransferableResource::ReturnResources(list);
     child_resource_provider_->ReceiveReturnsFromParent(returned);
     // ids were exported twice, we returned them only once, they should still
     // be in-use.
@@ -1584,7 +1585,7 @@
     child_resource_provider_->GenerateSyncTokenForResources(
         resource_ids_to_transfer);
 
-    TransferableResourceArray list;
+    std::vector<TransferableResource> list;
     child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
                                                   &list);
     ASSERT_EQ(3u, list.size());
@@ -1654,14 +1655,14 @@
   child_resource_provider->CopyToResource(id1, data1, size);
   child_resource_provider->GenerateSyncTokenForResource(id1);
 
-  ReturnedResourceArray returned_to_child;
+  std::vector<ReturnedResource> returned_to_child;
   int child_id =
       resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
   {
     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
     resource_ids_to_transfer.push_back(id1);
 
-    TransferableResourceArray list;
+    std::vector<TransferableResource> list;
     child_resource_provider->PrepareSendToParent(resource_ids_to_transfer,
                                                  &list);
     ASSERT_EQ(1u, list.size());
@@ -1702,7 +1703,7 @@
   uint8_t data1[4] = { 1, 2, 3, 4 };
   child_resource_provider_->CopyToResource(id1, data1, size);
 
-  ReturnedResourceArray returned_to_child;
+  std::vector<ReturnedResource> returned_to_child;
   int child_id =
       resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
   {
@@ -1712,7 +1713,7 @@
     child_resource_provider_->GenerateSyncTokenForResources(
         resource_ids_to_transfer);
 
-    TransferableResourceArray list;
+    std::vector<TransferableResource> list;
     child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
                                                   &list);
     ASSERT_EQ(1u, list.size());
@@ -1760,7 +1761,7 @@
   uint8_t data2[4] = {5, 5, 5, 5};
   child_resource_provider_->CopyToResource(id2, data2, size);
 
-  ReturnedResourceArray returned_to_child;
+  std::vector<ReturnedResource> returned_to_child;
   int child_id =
       resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
   {
@@ -1772,7 +1773,7 @@
     child_resource_provider_->GenerateSyncTokenForResources(
         resource_ids_to_transfer);
 
-    TransferableResourceArray list;
+    std::vector<TransferableResource> list;
     child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
                                                   &list);
     ASSERT_EQ(2u, list.size());
@@ -1809,7 +1810,7 @@
     child_resource_provider_->GenerateSyncTokenForResources(
         resource_ids_to_transfer);
 
-    TransferableResourceArray list;
+    std::vector<TransferableResource> list;
     resource_provider_->PrepareSendToParent(resource_ids_to_transfer, &list);
 
     ASSERT_EQ(2u, list.size());
@@ -1833,8 +1834,8 @@
     EXPECT_EQ(2u, list.size());
     EXPECT_EQ(mapped_id1, list[0].id);
     EXPECT_EQ(mapped_id2, list[1].id);
-    ReturnedResourceArray returned;
-    TransferableResource::ReturnResources(list, &returned);
+    std::vector<ReturnedResource> returned =
+        TransferableResource::ReturnResources(list);
     resource_provider_->ReceiveReturnsFromParent(returned);
 
     EXPECT_EQ(0u, resource_provider_->num_resources());
@@ -1866,7 +1867,7 @@
   uint8_t data2[4] = {5, 5, 5, 5};
   child_resource_provider_->CopyToResource(id2, data2, size);
 
-  ReturnedResourceArray returned_to_child;
+  std::vector<ReturnedResource> returned_to_child;
   int child_id =
       resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
   {
@@ -1878,7 +1879,7 @@
     child_resource_provider_->GenerateSyncTokenForResources(
         resource_ids_to_transfer);
 
-    TransferableResourceArray list;
+    std::vector<TransferableResource> list;
     child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
                                                   &list);
     ASSERT_EQ(2u, list.size());
@@ -1915,7 +1916,7 @@
     child_resource_provider_->GenerateSyncTokenForResources(
         resource_ids_to_transfer);
 
-    TransferableResourceArray list;
+    std::vector<TransferableResource> list;
     resource_provider_->PrepareSendToParent(resource_ids_to_transfer, &list);
 
     ASSERT_EQ(2u, list.size());
@@ -1945,11 +1946,11 @@
     EXPECT_EQ(2u, list.size());
     EXPECT_EQ(mapped_id1, list[0].id);
     EXPECT_EQ(mapped_id2, list[1].id);
-    TransferableResourceArray return_list;
+    std::vector<TransferableResource> return_list;
     return_list.push_back(list[1]);
     list.pop_back();
-    ReturnedResourceArray returned;
-    TransferableResource::ReturnResources(return_list, &returned);
+    std::vector<ReturnedResource> returned =
+        TransferableResource::ReturnResources(return_list);
     resource_provider_->ReceiveReturnsFromParent(returned);
 
     EXPECT_EQ(1u, resource_provider_->num_resources());
@@ -1983,7 +1984,7 @@
   uint8_t data[4] = { 1, 2, 3, 4 };
   child_resource_provider_->CopyToResource(id, data, size);
 
-  ReturnedResourceArray returned_to_child;
+  std::vector<ReturnedResource> returned_to_child;
   int child_id =
       resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
   {
@@ -1994,7 +1995,7 @@
     child_resource_provider_->GenerateSyncTokenForResources(
         resource_ids_to_transfer);
 
-    TransferableResourceArray list;
+    std::vector<TransferableResource> list;
     child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
                                                   &list);
     ASSERT_EQ(1u, list.size());
@@ -2039,7 +2040,7 @@
   uint8_t data[4] = {1, 2, 3, 4};
   child_resource_provider_->CopyToResource(id, data, size);
 
-  ReturnedResourceArray returned_to_child;
+  std::vector<ReturnedResource> returned_to_child;
   int child_id =
       resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
   const ResourceProvider::ResourceIdMap& map =
@@ -2052,7 +2053,7 @@
     child_resource_provider_->GenerateSyncTokenForResources(
         resource_ids_to_transfer);
 
-    TransferableResourceArray list;
+    std::vector<TransferableResource> list;
     child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
                                                   &list);
     EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id));
@@ -2062,7 +2063,7 @@
     resource_provider_->DeclareUsedResourcesFromChild(child_id,
                                                       resource_ids_to_receive);
   }
-  TransferableResourceArray sent_to_top_level;
+  std::vector<TransferableResource> sent_to_top_level;
   {
     // Parent transfers to top-level.
     ASSERT_TRUE(map.find(id) != map.end());
@@ -2085,7 +2086,7 @@
     // Send the resource to the parent again.
     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
     resource_ids_to_transfer.push_back(id);
-    TransferableResourceArray list;
+    std::vector<TransferableResource> list;
     child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
                                                   &list);
     EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id));
@@ -2097,8 +2098,8 @@
   }
   {
     // Receive returns back from top-level.
-    ReturnedResourceArray returned;
-    TransferableResource::ReturnResources(sent_to_top_level, &returned);
+    std::vector<ReturnedResource> returned =
+        TransferableResource::ReturnResources(sent_to_top_level);
     resource_provider_->ReceiveReturnsFromParent(returned);
     // Resource is still not yet returned to the child, since it's declared used
     // in the parent.
@@ -2120,8 +2121,8 @@
   }
   {
     // Receive returns back from top-level.
-    ReturnedResourceArray returned;
-    TransferableResource::ReturnResources(sent_to_top_level, &returned);
+    std::vector<ReturnedResource> returned =
+        TransferableResource::ReturnResources(sent_to_top_level);
     resource_provider_->ReceiveReturnsFromParent(returned);
     // Resource is still not yet returned to the child, since it's still
     // declared used in the parent.
@@ -2225,14 +2226,14 @@
     SetResourceFilter(child_resource_provider.get(), id, child_filter);
     Mock::VerifyAndClearExpectations(child_context);
 
-    ReturnedResourceArray returned_to_child;
+    std::vector<ReturnedResource> returned_to_child;
     int child_id = parent_resource_provider->CreateChild(
         GetReturnCallback(&returned_to_child));
     {
       // Transfer some resource to the parent.
       ResourceProvider::ResourceIdArray resource_ids_to_transfer;
       resource_ids_to_transfer.push_back(id);
-      TransferableResourceArray list;
+      std::vector<TransferableResource> list;
 
       EXPECT_CALL(*child_context,
                   produceTextureDirectCHROMIUM(_, GL_TEXTURE_2D, _));
@@ -2357,7 +2358,7 @@
     // Transfer the resource, expect the sync points to be consistent.
     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
     resource_ids_to_transfer.push_back(resource);
-    TransferableResourceArray list;
+    std::vector<TransferableResource> list;
     resource_provider_->PrepareSendToParent(resource_ids_to_transfer, &list);
     ASSERT_EQ(1u, list.size());
     EXPECT_LE(sync_token.release_count(),
@@ -2385,8 +2386,8 @@
 
     // Receive the resource, then delete it, expect the sync points to be
     // consistent.
-    ReturnedResourceArray returned;
-    TransferableResource::ReturnResources(list, &returned);
+    std::vector<ReturnedResource> returned =
+        TransferableResource::ReturnResources(list);
     resource_provider_->ReceiveReturnsFromParent(returned);
     EXPECT_EQ(1u, context()->NumTextures());
     EXPECT_FALSE(release_sync_token.HasData());
@@ -2412,7 +2413,7 @@
     // Transfer the resource, expect the sync points to be consistent.
     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
     resource_ids_to_transfer.push_back(resource);
-    TransferableResourceArray list;
+    std::vector<TransferableResource> list;
     resource_provider_->PrepareSendToParent(resource_ids_to_transfer, &list);
     ASSERT_EQ(1u, list.size());
     EXPECT_LE(sync_token.release_count(),
@@ -2445,8 +2446,8 @@
 
     // Then receive the resource which should release the mailbox, expect the
     // sync points to be consistent.
-    ReturnedResourceArray returned;
-    TransferableResource::ReturnResources(list, &returned);
+    std::vector<ReturnedResource> returned =
+        TransferableResource::ReturnResources(list);
     resource_provider_->ReceiveReturnsFromParent(returned);
     EXPECT_LE(list[0].mailbox_holder.sync_token.release_count(),
               release_sync_token.release_count());
@@ -2471,14 +2472,14 @@
   bool should_lose_resource =
       GetParam() == ResourceProvider::RESOURCE_TYPE_GL_TEXTURE;
 
-  ReturnedResourceArray returned_to_child;
+  std::vector<ReturnedResource> returned_to_child;
   int child_id =
       resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
   {
     // Transfer the resource to the parent.
     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
     resource_ids_to_transfer.push_back(resource);
-    TransferableResourceArray list;
+    std::vector<TransferableResource> list;
     child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
                                                   &list);
     EXPECT_EQ(1u, list.size());
@@ -2524,14 +2525,14 @@
       gfx::ColorSpace());
   child_resource_provider_->AllocateForTesting(resource);
 
-  ReturnedResourceArray returned_to_child;
+  std::vector<ReturnedResource> returned_to_child;
   int child_id =
       resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
   {
     // Transfer the resource to the parent.
     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
     resource_ids_to_transfer.push_back(resource);
-    TransferableResourceArray list;
+    std::vector<TransferableResource> list;
     child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
                                                   &list);
     EXPECT_EQ(1u, list.size());
@@ -2552,14 +2553,14 @@
     // Transfer to a grandparent.
     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
     resource_ids_to_transfer.push_back(parent_resource);
-    TransferableResourceArray list;
+    std::vector<TransferableResource> list;
     resource_provider_->PrepareSendToParent(resource_ids_to_transfer, &list);
 
     // Receive back a lost resource from the grandparent.
     EXPECT_EQ(1u, list.size());
     EXPECT_EQ(parent_resource, list[0].id);
-    ReturnedResourceArray returned;
-    TransferableResource::ReturnResources(list, &returned);
+    std::vector<ReturnedResource> returned =
+        TransferableResource::ReturnResources(list);
     EXPECT_EQ(1u, returned.size());
     EXPECT_EQ(parent_resource, returned[0].id);
     returned[0].lost = true;
@@ -2602,14 +2603,14 @@
   ResourceId resource = CreateChildMailbox(&release_sync_token, &lost_resource,
                                            &release_called, &sync_token);
 
-  ReturnedResourceArray returned_to_child;
+  std::vector<ReturnedResource> returned_to_child;
   int child_id =
       resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
   {
     // Transfer the resource to the parent.
     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
     resource_ids_to_transfer.push_back(resource);
-    TransferableResourceArray list;
+    std::vector<TransferableResource> list;
     child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
                                                   &list);
     EXPECT_EQ(1u, list.size());
@@ -2655,14 +2656,14 @@
   ResourceId resource = CreateChildMailbox(&release_sync_token, &lost_resource,
                                            &release_called, &sync_token);
 
-  ReturnedResourceArray returned_to_child;
+  std::vector<ReturnedResource> returned_to_child;
   int child_id =
       resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
   {
     // Transfer the resource to the parent.
     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
     resource_ids_to_transfer.push_back(resource);
-    TransferableResourceArray list;
+    std::vector<TransferableResource> list;
     child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
                                                   &list);
     EXPECT_EQ(1u, list.size());
@@ -2683,14 +2684,14 @@
     // Transfer to a grandparent.
     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
     resource_ids_to_transfer.push_back(parent_resource);
-    TransferableResourceArray list;
+    std::vector<TransferableResource> list;
     resource_provider_->PrepareSendToParent(resource_ids_to_transfer, &list);
 
     // Receive back a lost resource from the grandparent.
     EXPECT_EQ(1u, list.size());
     EXPECT_EQ(parent_resource, list[0].id);
-    ReturnedResourceArray returned;
-    TransferableResource::ReturnResources(list, &returned);
+    std::vector<ReturnedResource> returned =
+        TransferableResource::ReturnResources(list);
     EXPECT_EQ(1u, returned.size());
     EXPECT_EQ(parent_resource, returned[0].id);
     returned[0].lost = true;
@@ -2748,7 +2749,7 @@
   // Transfer the resource, so we can't release it properly on shutdown.
   ResourceProvider::ResourceIdArray resource_ids_to_transfer;
   resource_ids_to_transfer.push_back(resource);
-  TransferableResourceArray list;
+  std::vector<TransferableResource> list;
   child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
                                                 &list);
 
@@ -3419,7 +3420,7 @@
   Mock::VerifyAndClearExpectations(context);
 
   ResourceProvider::ResourceIdArray resource_ids_to_transfer{id};
-  TransferableResourceArray list;
+  std::vector<TransferableResource> list;
   resource_provider->PrepareSendToParent(resource_ids_to_transfer, &list);
   ASSERT_EQ(1u, list.size());
   EXPECT_FALSE(list[0].mailbox_holder.sync_token.HasData());
diff --git a/cc/resources/return_callback.h b/cc/resources/return_callback.h
index abf5aec..f14a5ce 100644
--- a/cc/resources/return_callback.h
+++ b/cc/resources/return_callback.h
@@ -11,7 +11,7 @@
 namespace cc {
 class BlockingTaskRunner;
 
-typedef base::Callback<void(const ReturnedResourceArray&,
+typedef base::Callback<void(const std::vector<ReturnedResource>&,
                             BlockingTaskRunner* main_thread_task_runner)>
     ReturnCallback;
 
diff --git a/cc/resources/returned_resource.h b/cc/resources/returned_resource.h
index d919df9..9ba79994 100644
--- a/cc/resources/returned_resource.h
+++ b/cc/resources/returned_resource.h
@@ -50,8 +50,6 @@
   bool lost;
 };
 
-typedef std::vector<ReturnedResource> ReturnedResourceArray;
-
 }  // namespace cc
 
 #endif  // CC_RESOURCES_RETURNED_RESOURCE_H_
diff --git a/cc/resources/transferable_resource.cc b/cc/resources/transferable_resource.cc
index 65ac1f6..bfe5652b 100644
--- a/cc/resources/transferable_resource.cc
+++ b/cc/resources/transferable_resource.cc
@@ -36,12 +36,13 @@
 }
 
 // static
-void TransferableResource::ReturnResources(
-    const TransferableResourceArray& input,
-    ReturnedResourceArray* output) {
-  for (TransferableResourceArray::const_iterator it = input.begin();
-       it != input.end(); ++it)
-    output->push_back(it->ToReturnedResource());
+std::vector<ReturnedResource> TransferableResource::ReturnResources(
+    const std::vector<TransferableResource>& input) {
+  std::vector<ReturnedResource> out;
+  out.reserve(input.size());
+  for (const auto& r : input)
+    out.push_back(r.ToReturnedResource());
+  return out;
 }
 
 }  // namespace cc
diff --git a/cc/resources/transferable_resource.h b/cc/resources/transferable_resource.h
index baa4048..9be21514 100644
--- a/cc/resources/transferable_resource.h
+++ b/cc/resources/transferable_resource.h
@@ -18,11 +18,7 @@
 #include "ui/gfx/geometry/size.h"
 
 namespace cc {
-
 struct ReturnedResource;
-typedef std::vector<ReturnedResource> ReturnedResourceArray;
-struct TransferableResource;
-typedef std::vector<TransferableResource> TransferableResourceArray;
 
 struct CC_EXPORT TransferableResource {
   TransferableResource();
@@ -30,8 +26,8 @@
   ~TransferableResource();
 
   ReturnedResource ToReturnedResource() const;
-  static void ReturnResources(const TransferableResourceArray& input,
-                              ReturnedResourceArray* output);
+  static std::vector<ReturnedResource> ReturnResources(
+      const std::vector<TransferableResource>& input);
 
   ResourceId id;
   // Refer to ResourceProvider::Resource for the meaning of the following data.
diff --git a/cc/scheduler/begin_frame_source.cc b/cc/scheduler/begin_frame_source.cc
index c5ec595..4b7fe01 100644
--- a/cc/scheduler/begin_frame_source.cc
+++ b/cc/scheduler/begin_frame_source.cc
@@ -283,10 +283,19 @@
     client_->OnNeedsBeginFrames(true);
 
   // Send a MISSED begin frame if necessary.
-  BeginFrameArgs missed_args = GetMissedBeginFrameArgs(obs);
-  if (missed_args.IsValid()) {
-    DCHECK_EQ(BeginFrameArgs::MISSED, missed_args.type);
-    obs->OnBeginFrame(missed_args);
+  if (last_begin_frame_args_.IsValid()) {
+    const BeginFrameArgs& last_args = obs->LastUsedBeginFrameArgs();
+    if (!last_args.IsValid() ||
+        (last_begin_frame_args_.frame_time > last_args.frame_time)) {
+      DCHECK(
+          (last_begin_frame_args_.source_id != last_args.source_id) ||
+          (last_begin_frame_args_.sequence_number > last_args.sequence_number))
+          << "current " << last_begin_frame_args_.AsValue()->ToString()
+          << ", last " << last_args.AsValue()->ToString();
+      BeginFrameArgs missed_args = last_begin_frame_args_;
+      missed_args.type = BeginFrameArgs::MISSED;
+      obs->OnBeginFrame(missed_args);
+    }
   }
 }
 
@@ -295,8 +304,10 @@
   DCHECK(observers_.find(obs) != observers_.end());
 
   observers_.erase(obs);
-  if (observers_.empty())
+  if (observers_.empty()) {
+    last_begin_frame_args_ = BeginFrameArgs();
     client_->OnNeedsBeginFrames(false);
+  }
 }
 
 bool ExternalBeginFrameSource::IsThrottled() const {
@@ -330,24 +341,4 @@
   }
 }
 
-BeginFrameArgs ExternalBeginFrameSource::GetMissedBeginFrameArgs(
-    BeginFrameObserver* obs) {
-  if (!last_begin_frame_args_.IsValid())
-    return BeginFrameArgs();
-
-  const BeginFrameArgs& last_args = obs->LastUsedBeginFrameArgs();
-  if (last_args.IsValid() &&
-      last_begin_frame_args_.frame_time <= last_args.frame_time) {
-    return BeginFrameArgs();
-  }
-
-  DCHECK((last_begin_frame_args_.source_id != last_args.source_id) ||
-         (last_begin_frame_args_.sequence_number > last_args.sequence_number))
-      << "current " << last_begin_frame_args_.AsValue()->ToString() << ", last "
-      << last_args.AsValue()->ToString();
-  BeginFrameArgs missed_args = last_begin_frame_args_;
-  missed_args.type = BeginFrameArgs::MISSED;
-  return missed_args;
-}
-
 }  // namespace cc
diff --git a/cc/scheduler/begin_frame_source.h b/cc/scheduler/begin_frame_source.h
index ea7276a2..e21878dd 100644
--- a/cc/scheduler/begin_frame_source.h
+++ b/cc/scheduler/begin_frame_source.h
@@ -257,10 +257,6 @@
   void OnBeginFrame(const BeginFrameArgs& args);
 
  protected:
-  // Called on AddObserver and gets missed BeginFrameArgs for the given
-  // observer.
-  virtual BeginFrameArgs GetMissedBeginFrameArgs(BeginFrameObserver* obs);
-
   BeginFrameArgs last_begin_frame_args_;
   std::unordered_set<BeginFrameObserver*> observers_;
   ExternalBeginFrameSourceClient* client_;
diff --git a/cc/scheduler/begin_frame_source_unittest.cc b/cc/scheduler/begin_frame_source_unittest.cc
index bff0d46..a4cf4b5 100644
--- a/cc/scheduler/begin_frame_source_unittest.cc
+++ b/cc/scheduler/begin_frame_source_unittest.cc
@@ -15,7 +15,6 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 using testing::NiceMock;
-using testing::_;
 
 namespace cc {
 namespace {
@@ -574,29 +573,5 @@
   source2.OnBeginFrame(args);
 }
 
-// https://crbug.com/730218: Avoid DCHECK crash in
-// ExternalBeginFrameSource::GetMissedBeginFrameArgs.
-TEST_F(ExternalBeginFrameSourceTest, GetMissedBeginFrameArgs) {
-  BeginFrameArgs args = CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0,
-                                                       2, 10000, 10100, 100);
-  source_->OnBeginFrame(args);
-
-  EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
-  EXPECT_BEGIN_FRAME_USED_MISSED(*obs_, 0, 2, 10000, 10100, 100);
-  source_->AddObserver(obs_.get());
-  source_->RemoveObserver(obs_.get());
-
-  // Out of order frame_time. This might not be valid but still shouldn't
-  // cause a DCHECK in ExternalBeginFrameSource code.
-  args = CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 2, 9999, 10100,
-                                        101);
-  source_->OnBeginFrame(args);
-
-  EXPECT_CALL((*client_), OnNeedsBeginFrames(true)).Times(1);
-  EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
-  EXPECT_CALL(*obs_, OnBeginFrame(_)).Times(0);
-  source_->AddObserver(obs_.get());
-}
-
 }  // namespace
 }  // namespace cc
diff --git a/cc/surfaces/compositor_frame_sink_support.cc b/cc/surfaces/compositor_frame_sink_support.cc
index 962c023..ce83947 100644
--- a/cc/surfaces/compositor_frame_sink_support.cc
+++ b/cc/surfaces/compositor_frame_sink_support.cc
@@ -54,7 +54,7 @@
 }
 
 void CompositorFrameSinkSupport::ReturnResources(
-    const ReturnedResourceArray& resources) {
+    const std::vector<ReturnedResource>& resources) {
   if (resources.empty())
     return;
   if (!ack_pending_count_ && client_) {
@@ -146,8 +146,8 @@
       TRACE_EVENT_INSTANT0("cc", "Invalid SurfaceInfo",
                            TRACE_EVENT_SCOPE_THREAD);
       EvictCurrentSurface();
-      ReturnedResourceArray resources;
-      TransferableResource::ReturnResources(frame.resource_list, &resources);
+      std::vector<ReturnedResource> resources =
+          TransferableResource::ReturnResources(frame.resource_list);
       ReturnResources(resources);
       DidReceiveCompositorFrameAck();
       return true;
@@ -253,17 +253,17 @@
 }
 
 void CompositorFrameSinkSupport::ReceiveFromChild(
-    const TransferableResourceArray& resources) {
+    const std::vector<TransferableResource>& resources) {
   surface_resource_holder_.ReceiveFromChild(resources);
 }
 
 void CompositorFrameSinkSupport::RefResources(
-    const TransferableResourceArray& resources) {
+    const std::vector<TransferableResource>& resources) {
   surface_resource_holder_.RefResources(resources);
 }
 
 void CompositorFrameSinkSupport::UnrefResources(
-    const ReturnedResourceArray& resources) {
+    const std::vector<ReturnedResource>& resources) {
   surface_resource_holder_.UnrefResources(resources);
 }
 
diff --git a/cc/surfaces/compositor_frame_sink_support.h b/cc/surfaces/compositor_frame_sink_support.h
index 808cb29..6b84d16 100644
--- a/cc/surfaces/compositor_frame_sink_support.h
+++ b/cc/surfaces/compositor_frame_sink_support.h
@@ -47,7 +47,7 @@
   bool needs_sync_points() { return needs_sync_points_; }
 
   // SurfaceResourceHolderClient implementation.
-  void ReturnResources(const ReturnedResourceArray& resources) override;
+  void ReturnResources(const std::vector<ReturnedResource>& resources) override;
 
   // FrameSinkManagerClient implementation.
   void SetBeginFrameSource(BeginFrameSource* begin_frame_source) override;
@@ -61,9 +61,9 @@
   void ClaimTemporaryReference(const SurfaceId& surface_id);
 
   // TODO(staraz): Move the following 3 methods to private.
-  void ReceiveFromChild(const TransferableResourceArray& resources);
-  void RefResources(const TransferableResourceArray& resources);
-  void UnrefResources(const ReturnedResourceArray& resources);
+  void ReceiveFromChild(const std::vector<TransferableResource>& resources);
+  void RefResources(const std::vector<TransferableResource>& resources);
+  void UnrefResources(const std::vector<ReturnedResource>& resources);
 
   void OnSurfaceActivated(Surface* surface);
 
@@ -119,7 +119,7 @@
   // Counts the number of CompositorFrames that have been submitted and have not
   // yet received an ACK.
   int ack_pending_count_ = 0;
-  ReturnedResourceArray surface_returned_resources_;
+  std::vector<ReturnedResource> surface_returned_resources_;
 
   // The begin frame source being observered. Null if none.
   BeginFrameSource* begin_frame_source_ = nullptr;
diff --git a/cc/surfaces/compositor_frame_sink_support_client.h b/cc/surfaces/compositor_frame_sink_support_client.h
index 4fd3786..242d46e9 100644
--- a/cc/surfaces/compositor_frame_sink_support_client.h
+++ b/cc/surfaces/compositor_frame_sink_support_client.h
@@ -27,13 +27,14 @@
   // However, there's a fair amount of cleanup and refactoring necessary to get
   // rid of it.
   virtual void DidReceiveCompositorFrameAck(
-      const ReturnedResourceArray& resources) = 0;
+      const std::vector<ReturnedResource>& resources) = 0;
 
   // Notification for the client to generate a CompositorFrame.
   virtual void OnBeginFrame(const BeginFrameArgs& args) = 0;
 
   // Returns resources sent to SubmitCompositorFrame to be reused or freed.
-  virtual void ReclaimResources(const ReturnedResourceArray& resources) = 0;
+  virtual void ReclaimResources(
+      const std::vector<ReturnedResource>& resources) = 0;
 
   // Called when surface is being scheduled for a draw.
   virtual void WillDrawSurface(const LocalSurfaceId& local_surface_id,
diff --git a/cc/surfaces/compositor_frame_sink_support_unittest.cc b/cc/surfaces/compositor_frame_sink_support_unittest.cc
index 913247f..7bdf969 100644
--- a/cc/surfaces/compositor_frame_sink_support_unittest.cc
+++ b/cc/surfaces/compositor_frame_sink_support_unittest.cc
@@ -62,13 +62,14 @@
   ~FakeCompositorFrameSinkSupportClient() override = default;
 
   void DidReceiveCompositorFrameAck(
-      const ReturnedResourceArray& resources) override {
+      const std::vector<ReturnedResource>& resources) override {
     InsertResources(resources);
   }
 
   void OnBeginFrame(const BeginFrameArgs& args) override {}
 
-  void ReclaimResources(const ReturnedResourceArray& resources) override {
+  void ReclaimResources(
+      const std::vector<ReturnedResource>& resources) override {
     InsertResources(resources);
   }
 
@@ -76,17 +77,17 @@
                        const gfx::Rect& damage_rect) override {}
 
   void clear_returned_resources() { returned_resources_.clear(); }
-  const ReturnedResourceArray& returned_resources() {
+  const std::vector<ReturnedResource>& returned_resources() {
     return returned_resources_;
   }
 
  private:
-  void InsertResources(const ReturnedResourceArray& resources) {
+  void InsertResources(const std::vector<ReturnedResource>& resources) {
     returned_resources_.insert(returned_resources_.end(), resources.begin(),
                                resources.end());
   }
 
-  ReturnedResourceArray returned_resources_;
+  std::vector<ReturnedResource> returned_resources_;
 
   DISALLOW_COPY_AND_ASSIGN(FakeCompositorFrameSinkSupportClient);
 };
@@ -131,7 +132,7 @@
   void UnrefResources(ResourceId* ids_to_unref,
                       int* counts_to_unref,
                       size_t num_ids_to_unref) {
-    ReturnedResourceArray unref_array;
+    std::vector<ReturnedResource> unref_array;
     for (size_t i = 0; i < num_ids_to_unref; ++i) {
       ReturnedResource resource;
       resource.sync_token = consumer_sync_token_;
@@ -146,7 +147,7 @@
                                            int* expected_returned_counts,
                                            size_t expected_resources,
                                            gpu::SyncToken expected_sync_token) {
-    const ReturnedResourceArray& actual_resources =
+    const std::vector<ReturnedResource>& actual_resources =
         fake_support_client_.returned_resources();
     ASSERT_EQ(expected_resources, actual_resources.size());
     for (size_t i = 0; i < expected_resources; ++i) {
@@ -290,7 +291,7 @@
   // Now it should be returned.
   // We don't care how many entries are in the returned array for 7, so long as
   // the total returned count matches the submitted count.
-  const ReturnedResourceArray& returned =
+  const std::vector<ReturnedResource>& returned =
       fake_support_client_.returned_resources();
   size_t return_count = 0;
   for (size_t i = 0; i < returned.size(); ++i) {
@@ -519,7 +520,8 @@
             local_surface_id);
   local_surface_id_ = LocalSurfaceId();
 
-  ReturnedResourceArray returned_resources = {resource.ToReturnedResource()};
+  std::vector<ReturnedResource> returned_resources = {
+      resource.ToReturnedResource()};
   EXPECT_TRUE(manager_.GetSurfaceForId(id));
   EXPECT_CALL(mock_client, DidReceiveCompositorFrameAck(returned_resources))
       .Times(1);
@@ -552,7 +554,8 @@
   surface->AddDestructionDependency(
       SurfaceSequence(kYetAnotherArbitraryFrameSinkId, 4));
 
-  ReturnedResourceArray returned_resource = {resource.ToReturnedResource()};
+  std::vector<ReturnedResource> returned_resource = {
+      resource.ToReturnedResource()};
 
   EXPECT_TRUE(manager_.GetSurfaceForId(surface_id));
   EXPECT_CALL(mock_client, DidReceiveCompositorFrameAck(returned_resource))
@@ -589,7 +592,7 @@
   surface->AddDestructionDependency(
       SurfaceSequence(kYetAnotherArbitraryFrameSinkId, 4));
 
-  ReturnedResourceArray returned_resources;
+  std::vector<ReturnedResource> returned_resources;
   EXPECT_TRUE(manager_.GetSurfaceForId(surface_id));
   support->EvictCurrentSurface();
   EXPECT_TRUE(manager_.GetSurfaceForId(surface_id));
diff --git a/cc/surfaces/direct_layer_tree_frame_sink.cc b/cc/surfaces/direct_layer_tree_frame_sink.cc
index 2bae572..8a3bee4 100644
--- a/cc/surfaces/direct_layer_tree_frame_sink.cc
+++ b/cc/surfaces/direct_layer_tree_frame_sink.cc
@@ -135,7 +135,7 @@
 }
 
 void DirectLayerTreeFrameSink::DidReceiveCompositorFrameAck(
-    const ReturnedResourceArray& resources) {
+    const std::vector<ReturnedResource>& resources) {
   client_->ReclaimResources(resources);
   client_->DidReceiveCompositorFrameAck();
 }
@@ -145,7 +145,7 @@
 }
 
 void DirectLayerTreeFrameSink::ReclaimResources(
-    const ReturnedResourceArray& resources) {
+    const std::vector<ReturnedResource>& resources) {
   client_->ReclaimResources(resources);
 }
 
diff --git a/cc/surfaces/direct_layer_tree_frame_sink.h b/cc/surfaces/direct_layer_tree_frame_sink.h
index f1c9c4b..303357e 100644
--- a/cc/surfaces/direct_layer_tree_frame_sink.h
+++ b/cc/surfaces/direct_layer_tree_frame_sink.h
@@ -63,9 +63,10 @@
  private:
   // CompositorFrameSinkSupportClient implementation:
   void DidReceiveCompositorFrameAck(
-      const ReturnedResourceArray& resources) override;
+      const std::vector<ReturnedResource>& resources) override;
   void OnBeginFrame(const BeginFrameArgs& args) override;
-  void ReclaimResources(const ReturnedResourceArray& resources) override;
+  void ReclaimResources(
+      const std::vector<ReturnedResource>& resources) override;
   void WillDrawSurface(const LocalSurfaceId& local_surface_id,
                        const gfx::Rect& damage_rect) override;
 
diff --git a/cc/surfaces/surface.cc b/cc/surfaces/surface.cc
index 19c54082..8703b8a1 100644
--- a/cc/surfaces/surface.cc
+++ b/cc/surfaces/surface.cc
@@ -67,8 +67,8 @@
   }
 
   if (closed_) {
-    ReturnedResourceArray resources;
-    TransferableResource::ReturnResources(frame.resource_list, &resources);
+    std::vector<ReturnedResource> resources =
+        TransferableResource::ReturnResources(frame.resource_list);
     compositor_frame_sink_support_->ReturnResources(resources);
     callback.Run();
     return true;
@@ -333,9 +333,8 @@
   if (!frame_data || !compositor_frame_sink_support_)
     return;
 
-  ReturnedResourceArray resources;
-  TransferableResource::ReturnResources(frame_data->frame.resource_list,
-                                        &resources);
+  std::vector<ReturnedResource> resources =
+      TransferableResource::ReturnResources(frame_data->frame.resource_list);
   // No point in returning same sync token to sender.
   for (auto& resource : resources)
     resource.sync_token.Clear();
diff --git a/cc/surfaces/surface_aggregator.cc b/cc/surfaces/surface_aggregator.cc
index 0127799..841286c 100644
--- a/cc/surfaces/surface_aggregator.cc
+++ b/cc/surfaces/surface_aggregator.cc
@@ -124,7 +124,7 @@
 
 static void UnrefHelper(
     base::WeakPtr<CompositorFrameSinkSupport> compositor_frame_sink_support,
-    const ReturnedResourceArray& resources,
+    const std::vector<ReturnedResource>& resources,
     BlockingTaskRunner* main_thread_task_runner) {
   if (compositor_frame_sink_support)
     compositor_frame_sink_support->UnrefResources(resources);
diff --git a/cc/surfaces/surface_resource_holder.cc b/cc/surfaces/surface_resource_holder.cc
index 8d46b25..bbcd0cf 100644
--- a/cc/surfaces/surface_resource_holder.cc
+++ b/cc/surfaces/surface_resource_holder.cc
@@ -21,7 +21,7 @@
 }
 
 void SurfaceResourceHolder::ReceiveFromChild(
-    const TransferableResourceArray& resources) {
+    const std::vector<TransferableResource>& resources) {
   for (const auto& resource : resources) {
     ResourceRefs& ref = resource_id_info_map_[resource.id];
     ref.refs_holding_resource_alive++;
@@ -30,10 +30,9 @@
 }
 
 void SurfaceResourceHolder::RefResources(
-    const TransferableResourceArray& resources) {
-  for (TransferableResourceArray::const_iterator it = resources.begin();
-       it != resources.end();
-       ++it) {
+    const std::vector<TransferableResource>& resources) {
+  for (std::vector<TransferableResource>::const_iterator it = resources.begin();
+       it != resources.end(); ++it) {
     ResourceIdInfoMap::iterator count_it = resource_id_info_map_.find(it->id);
     DCHECK(count_it != resource_id_info_map_.end());
     count_it->second.refs_holding_resource_alive++;
@@ -41,12 +40,11 @@
 }
 
 void SurfaceResourceHolder::UnrefResources(
-    const ReturnedResourceArray& resources) {
-  ReturnedResourceArray resources_available_to_return;
+    const std::vector<ReturnedResource>& resources) {
+  std::vector<ReturnedResource> resources_available_to_return;
 
-  for (ReturnedResourceArray::const_iterator it = resources.begin();
-       it != resources.end();
-       ++it) {
+  for (std::vector<ReturnedResource>::const_iterator it = resources.begin();
+       it != resources.end(); ++it) {
     unsigned id = it->id;
     ResourceIdInfoMap::iterator count_it = resource_id_info_map_.find(id);
     if (count_it == resource_id_info_map_.end())
diff --git a/cc/surfaces/surface_resource_holder.h b/cc/surfaces/surface_resource_holder.h
index e40f4945..c96d4e5 100644
--- a/cc/surfaces/surface_resource_holder.h
+++ b/cc/surfaces/surface_resource_holder.h
@@ -26,9 +26,9 @@
   ~SurfaceResourceHolder();
 
   void Reset();
-  void ReceiveFromChild(const TransferableResourceArray& resources);
-  void RefResources(const TransferableResourceArray& resources);
-  void UnrefResources(const ReturnedResourceArray& resources);
+  void ReceiveFromChild(const std::vector<TransferableResource>& resources);
+  void RefResources(const std::vector<TransferableResource>& resources);
+  void UnrefResources(const std::vector<ReturnedResource>& resources);
 
  private:
   SurfaceResourceHolderClient* client_;
diff --git a/cc/surfaces/surface_resource_holder_client.h b/cc/surfaces/surface_resource_holder_client.h
index 2a9c78d..3cb1518 100644
--- a/cc/surfaces/surface_resource_holder_client.h
+++ b/cc/surfaces/surface_resource_holder_client.h
@@ -15,7 +15,8 @@
 
   // ReturnResources gets called when the display compositor is done using the
   // resources so that the client can use them.
-  virtual void ReturnResources(const ReturnedResourceArray& resources) = 0;
+  virtual void ReturnResources(
+      const std::vector<ReturnedResource>& resources) = 0;
 };
 
 }  // namespace cc
diff --git a/cc/surfaces/surface_synchronization_unittest.cc b/cc/surfaces/surface_synchronization_unittest.cc
index 6fc69e6e..1f6a1922 100644
--- a/cc/surfaces/surface_synchronization_unittest.cc
+++ b/cc/surfaces/surface_synchronization_unittest.cc
@@ -234,7 +234,7 @@
   parent_support().SubmitCompositorFrame(
       parent_id.local_surface_id(),
       MakeCompositorFrame({child_id1, child_id2}, empty_surface_ids(),
-                          TransferableResourceArray()));
+                          std::vector<TransferableResource>()));
 
   // parent_support is blocked on |child_id1| and |child_id2|.
   EXPECT_TRUE(HasDeadline());
@@ -274,7 +274,7 @@
   parent_support().SubmitCompositorFrame(
       parent_id.local_surface_id(),
       MakeCompositorFrame({child_id1}, empty_surface_ids(),
-                          TransferableResourceArray()));
+                          std::vector<TransferableResource>()));
 
   // parent_support is blocked on |child_id1|.
   EXPECT_TRUE(HasDeadline());
@@ -288,7 +288,7 @@
   child_support1().SubmitCompositorFrame(
       child_id1.local_surface_id(),
       MakeCompositorFrame({child_id2}, empty_surface_ids(),
-                          TransferableResourceArray()));
+                          std::vector<TransferableResource>()));
 
   // child_support1 should now be blocked on |child_id2|.
   EXPECT_TRUE(HasDeadline());
@@ -309,7 +309,7 @@
   child_support2().SubmitCompositorFrame(
       child_id2.local_surface_id(),
       MakeCompositorFrame(empty_surface_ids(), empty_surface_ids(),
-                          TransferableResourceArray()));
+                          std::vector<TransferableResource>()));
 
   EXPECT_FALSE(HasDeadline());
 
@@ -339,7 +339,7 @@
   parent_support().SubmitCompositorFrame(
       parent_id.local_surface_id(),
       MakeCompositorFrame({child_id2}, empty_surface_ids(),
-                          TransferableResourceArray()));
+                          std::vector<TransferableResource>()));
 
   // parent_support is blocked on |child_id2|.
   EXPECT_TRUE(HasDeadline());
@@ -352,7 +352,7 @@
   child_support1().SubmitCompositorFrame(
       child_id1.local_surface_id(),
       MakeCompositorFrame({child_id2}, empty_surface_ids(),
-                          TransferableResourceArray()));
+                          std::vector<TransferableResource>()));
 
   EXPECT_TRUE(HasDeadline());
   EXPECT_FALSE(child_surface1()->HasActiveFrame());
@@ -392,7 +392,7 @@
   parent_support().SubmitCompositorFrame(
       parent_id.local_surface_id(),
       MakeCompositorFrame({child_id1}, empty_surface_ids(),
-                          TransferableResourceArray()));
+                          std::vector<TransferableResource>()));
 
   // parent_support is blocked on |child_id1|.
   EXPECT_TRUE(HasDeadline());
@@ -404,7 +404,7 @@
   child_support1().SubmitCompositorFrame(
       child_id1.local_surface_id(),
       MakeCompositorFrame({child_id2}, empty_surface_ids(),
-                          TransferableResourceArray()));
+                          std::vector<TransferableResource>()));
 
   // child_support1 should now be blocked on |child_id2|.
   EXPECT_TRUE(HasDeadline());
@@ -465,7 +465,7 @@
     support(i).SubmitCompositorFrame(
         local_surface_id,
         MakeCompositorFrame({arbitrary_id}, empty_surface_ids(),
-                            TransferableResourceArray()));
+                            std::vector<TransferableResource>()));
     // The deadline has been set.
     EXPECT_TRUE(HasDeadline());
 
@@ -498,7 +498,7 @@
   parent_support().SubmitCompositorFrame(
       parent_id.local_surface_id(),
       MakeCompositorFrame({arbitrary_id}, empty_surface_ids(),
-                          TransferableResourceArray()));
+                          std::vector<TransferableResource>()));
 
   // Verify that the CompositorFrame is blocked on |arbitrary_id|.
   EXPECT_FALSE(parent_surface()->HasActiveFrame());
@@ -548,7 +548,7 @@
   parent_support().SubmitCompositorFrame(
       parent_id.local_surface_id(),
       MakeCompositorFrame({child_id2}, {child_id1},
-                          TransferableResourceArray()));
+                          std::vector<TransferableResource>()));
   EXPECT_FALSE(parent_surface()->HasActiveFrame());
   EXPECT_TRUE(parent_surface()->HasPendingFrame());
   EXPECT_THAT(parent_surface()->blocking_surfaces(),
@@ -597,7 +597,7 @@
   resource.format = ALPHA_8;
   resource.filter = 1234;
   resource.size = gfx::Size(1234, 5678);
-  TransferableResourceArray resource_list = {resource};
+  std::vector<TransferableResource> resource_list = {resource};
   parent_support().SubmitCompositorFrame(
       parent_id.local_surface_id(),
       MakeCompositorFrame({child_id}, empty_surface_ids(), resource_list));
@@ -611,7 +611,7 @@
   child_support1().SubmitCompositorFrame(
       child_id.local_surface_id(),
       MakeCompositorFrame(empty_surface_ids(), empty_surface_ids(),
-                          TransferableResourceArray()));
+                          std::vector<TransferableResource>()));
 
   // Verify that the child CompositorFrame activates immediately.
   EXPECT_TRUE(child_surface1()->HasActiveFrame());
@@ -623,7 +623,8 @@
   EXPECT_FALSE(parent_surface()->HasPendingFrame());
   EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty());
 
-  ReturnedResourceArray returned_resources = {resource.ToReturnedResource()};
+  std::vector<ReturnedResource> returned_resources = {
+      resource.ToReturnedResource()};
   EXPECT_CALL(support_client_,
               DidReceiveCompositorFrameAck(returned_resources));
 
@@ -633,7 +634,7 @@
   parent_support().SubmitCompositorFrame(
       parent_id.local_surface_id(),
       MakeCompositorFrame({empty_surface_ids()}, {empty_surface_ids()},
-                          TransferableResourceArray()));
+                          std::vector<TransferableResource>()));
   EXPECT_TRUE(parent_surface()->HasActiveFrame());
   EXPECT_FALSE(parent_surface()->HasPendingFrame());
   EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty());
@@ -651,7 +652,7 @@
   parent_support().SubmitCompositorFrame(
       parent_id1.local_surface_id(),
       MakeCompositorFrame({child_id1}, empty_surface_ids(),
-                          TransferableResourceArray()));
+                          std::vector<TransferableResource>()));
 
   // Verify that the CompositorFrame is blocked on |child_id1|.
   EXPECT_FALSE(parent_surface()->HasActiveFrame());
@@ -663,7 +664,7 @@
   child_support1().SubmitCompositorFrame(
       child_id1.local_surface_id(),
       MakeCompositorFrame({child_id2}, empty_surface_ids(),
-                          TransferableResourceArray()));
+                          std::vector<TransferableResource>()));
 
   // Verify that the CompositorFrame is blocked on |child_id2|.
   EXPECT_FALSE(child_surface1()->HasActiveFrame());
@@ -698,7 +699,7 @@
   parent_support().SubmitCompositorFrame(
       parent_id.local_surface_id(),
       MakeCompositorFrame({child_id1}, empty_surface_ids(),
-                          TransferableResourceArray()));
+                          std::vector<TransferableResource>()));
 
   // Verify that the CompositorFrame is blocked on |child_id|.
   EXPECT_FALSE(parent_surface()->HasActiveFrame());
@@ -731,7 +732,7 @@
   parent_support().SubmitCompositorFrame(
       parent_id.local_surface_id(),
       MakeCompositorFrame(empty_surface_ids(), {child_id1},
-                          TransferableResourceArray()));
+                          std::vector<TransferableResource>()));
 
   // Verify that the parent Surface has activated.
   EXPECT_TRUE(parent_surface()->HasActiveFrame());
@@ -749,7 +750,7 @@
   parent_support().SubmitCompositorFrame(
       parent_id.local_surface_id(),
       MakeCompositorFrame({child_id2}, empty_surface_ids(),
-                          TransferableResourceArray()));
+                          std::vector<TransferableResource>()));
   testing::Mock::VerifyAndClearExpectations(&support_client_);
 
   // The parent surface should now have both a pending and activate
@@ -875,8 +876,8 @@
   ui::LatencyInfo info2;
   info2.AddLatencyNumber(latency_type2, latency_id2, latency_sequence_number2);
 
-  CompositorFrame frame2 = MakeCompositorFrame({child_id}, empty_surface_ids(),
-                                               TransferableResourceArray());
+  CompositorFrame frame2 = MakeCompositorFrame(
+      {child_id}, empty_surface_ids(), std::vector<TransferableResource>());
   frame2.metadata.latency_info.push_back(info2);
 
   parent_support().SubmitCompositorFrame(parent_id1.local_surface_id(),
@@ -959,8 +960,8 @@
   ui::LatencyInfo info2;
   info2.AddLatencyNumber(latency_type2, latency_id2, latency_sequence_number2);
 
-  CompositorFrame frame2 = MakeCompositorFrame({child_id}, empty_surface_ids(),
-                                               TransferableResourceArray());
+  CompositorFrame frame2 = MakeCompositorFrame(
+      {child_id}, empty_surface_ids(), std::vector<TransferableResource>());
   frame2.metadata.latency_info.push_back(info2);
 
   parent_support().SubmitCompositorFrame(parent_id2.local_surface_id(),
@@ -1011,8 +1012,8 @@
       parent_id.local_surface_id(),
       MakeCompositorFrame(empty_surface_ids(), empty_surface_ids(),
                           {resource}));
-  ReturnedResourceArray returned_resources;
-  TransferableResource::ReturnResources({resource}, &returned_resources);
+  std::vector<ReturnedResource> returned_resources =
+      TransferableResource::ReturnResources({resource});
   EXPECT_CALL(support_client_, ReclaimResources(_)).Times(0);
   EXPECT_CALL(support_client_,
               DidReceiveCompositorFrameAck(Eq(returned_resources)));
@@ -1038,7 +1039,8 @@
   // Add a reference from the parent to the child.
   parent_support().SubmitCompositorFrame(
       parent_id.local_surface_id(),
-      MakeCompositorFrame({child_id}, {child_id}, TransferableResourceArray()));
+      MakeCompositorFrame({child_id}, {child_id},
+                          std::vector<TransferableResource>()));
 
   // Attempt to destroy the child surface. The surface must still exist since
   // the parent needs it but it will be marked as destroyed.
@@ -1073,7 +1075,8 @@
   // Add a reference from parent.
   parent_support().SubmitCompositorFrame(
       parent_id.local_surface_id(),
-      MakeCompositorFrame({child_id}, {child_id}, TransferableResourceArray()));
+      MakeCompositorFrame({child_id}, {child_id},
+                          std::vector<TransferableResource>()));
 
   // Remove the reference from parant. This allows us to destroy the surface.
   parent_support().SubmitCompositorFrame(parent_id.local_surface_id(),
@@ -1106,11 +1109,11 @@
   parent_support().SubmitCompositorFrame(
       parent_id1.local_surface_id(),
       MakeCompositorFrame({child_id}, empty_surface_ids(),
-                          TransferableResourceArray()));
+                          std::vector<TransferableResource>()));
   display_support().SubmitCompositorFrame(
       display_id.local_surface_id(),
       MakeCompositorFrame({parent_id1}, empty_surface_ids(),
-                          TransferableResourceArray()));
+                          std::vector<TransferableResource>()));
 
   EXPECT_TRUE(HasDeadline());
 
@@ -1133,11 +1136,11 @@
   parent_support().SubmitCompositorFrame(
       parent_id2.local_surface_id(),
       MakeCompositorFrame({child_id}, empty_surface_ids(),
-                          TransferableResourceArray()));
+                          std::vector<TransferableResource>()));
   display_support().SubmitCompositorFrame(
       display_id.local_surface_id(),
       MakeCompositorFrame({parent_id2}, empty_surface_ids(),
-                          TransferableResourceArray()));
+                          std::vector<TransferableResource>()));
 
   // The display surface now has two CompositorFrames. One that is pending,
   // indirectly blocked on child_id and one that is active, also indirectly
@@ -1169,12 +1172,12 @@
   parent_support().SubmitCompositorFrame(
       parent_id1.local_surface_id(),
       MakeCompositorFrame({child_id}, empty_surface_ids(),
-                          TransferableResourceArray()));
+                          std::vector<TransferableResource>()));
 
   display_support().SubmitCompositorFrame(
       display_id.local_surface_id(),
       MakeCompositorFrame({parent_id1}, {parent_id1},
-                          TransferableResourceArray()));
+                          std::vector<TransferableResource>()));
 
   EXPECT_TRUE(HasDeadline());
   EXPECT_TRUE(display_surface()->HasPendingFrame());
@@ -1199,13 +1202,13 @@
   display_support().SubmitCompositorFrame(
       display_id.local_surface_id(),
       MakeCompositorFrame({parent_id2}, empty_surface_ids(),
-                          TransferableResourceArray()));
+                          std::vector<TransferableResource>()));
 
   // Now |parent_id1| is only kept alive by the active |display_id| frame.
   parent_support().SubmitCompositorFrame(
       parent_id2.local_surface_id(),
       MakeCompositorFrame({child_id}, empty_surface_ids(),
-                          TransferableResourceArray()));
+                          std::vector<TransferableResource>()));
 
   // SurfaceDependencyTracker should now be tracking |display_id|, |parent_id1|
   // and |parent_id2|. By activating the pending |display_id| frame by deadline,
@@ -1235,7 +1238,7 @@
   display_support().SubmitCompositorFrame(
       display_id.local_surface_id(),
       MakeCompositorFrame({parent_id1}, {parent_id2},
-                          TransferableResourceArray()));
+                          std::vector<TransferableResource>()));
 
   EXPECT_TRUE(display_surface()->HasPendingFrame());
   EXPECT_FALSE(display_surface()->HasActiveFrame());
@@ -1270,7 +1273,7 @@
   display_support().SubmitCompositorFrame(
       display_id.local_surface_id(),
       MakeCompositorFrame({parent_id1}, empty_surface_ids(),
-                          TransferableResourceArray()));
+                          std::vector<TransferableResource>()));
 
   EXPECT_TRUE(display_surface()->HasPendingFrame());
   EXPECT_FALSE(display_surface()->HasActiveFrame());
@@ -1294,7 +1297,7 @@
   parent_support().SubmitCompositorFrame(
       parent_id1.local_surface_id(),
       MakeCompositorFrame({child_id1}, empty_surface_ids(),
-                          TransferableResourceArray()));
+                          std::vector<TransferableResource>()));
   EXPECT_FALSE(HasDeadline());
   EXPECT_FALSE(parent_surface()->HasPendingFrame());
   EXPECT_TRUE(parent_surface()->HasActiveFrame());
@@ -1319,11 +1322,11 @@
   resource.format = ALPHA_8;
   resource.filter = 1234;
   resource.size = gfx::Size(1234, 5678);
-  ReturnedResourceArray returned_resources;
-  TransferableResource::ReturnResources({resource}, &returned_resources);
+  std::vector<ReturnedResource> returned_resources =
+      TransferableResource::ReturnResources({resource});
 
-  EXPECT_CALL(support_client_,
-              DidReceiveCompositorFrameAck(Eq(ReturnedResourceArray())));
+  EXPECT_CALL(support_client_, DidReceiveCompositorFrameAck(
+                                   Eq(std::vector<ReturnedResource>())));
   child_support1().SubmitCompositorFrame(
       child_id1.local_surface_id(),
       MakeCompositorFrame(empty_surface_ids(), empty_surface_ids(),
@@ -1336,7 +1339,7 @@
   parent_support().SubmitCompositorFrame(
       parent_id1.local_surface_id(),
       MakeCompositorFrame({child_id2}, {child_id1},
-                          TransferableResourceArray()));
+                          std::vector<TransferableResource>()));
   EXPECT_TRUE(HasDeadline());
   EXPECT_TRUE(parent_surface()->HasPendingFrame());
   EXPECT_FALSE(parent_surface()->HasActiveFrame());
@@ -1348,8 +1351,8 @@
   resource2.format = ALPHA_8;
   resource2.filter = 1357;
   resource2.size = gfx::Size(8765, 4321);
-  ReturnedResourceArray returned_resources2;
-  TransferableResource::ReturnResources({resource2}, &returned_resources2);
+  std::vector<ReturnedResource> returned_resources2 =
+      TransferableResource::ReturnResources({resource2});
   EXPECT_CALL(support_client_,
               DidReceiveCompositorFrameAck(Eq(returned_resources2)));
   child_support1().SubmitCompositorFrame(
diff --git a/cc/test/compositor_frame_helpers.cc b/cc/test/compositor_frame_helpers.cc
index 73451ab..7db4647 100644
--- a/cc/test/compositor_frame_helpers.cc
+++ b/cc/test/compositor_frame_helpers.cc
@@ -30,7 +30,7 @@
 CompositorFrame MakeCompositorFrame(
     std::vector<SurfaceId> activation_dependencies,
     std::vector<SurfaceId> referenced_surfaces,
-    TransferableResourceArray resource_list) {
+    std::vector<TransferableResource> resource_list) {
   CompositorFrame compositor_frame = test::MakeCompositorFrame();
   compositor_frame.metadata.begin_frame_ack = BeginFrameAck(0, 1, 1, true);
   compositor_frame.metadata.activation_dependencies =
diff --git a/cc/test/compositor_frame_helpers.h b/cc/test/compositor_frame_helpers.h
index 32356e6..9894910b 100644
--- a/cc/test/compositor_frame_helpers.h
+++ b/cc/test/compositor_frame_helpers.h
@@ -26,7 +26,7 @@
 CompositorFrame MakeCompositorFrame(
     std::vector<SurfaceId> activation_dependencies,
     std::vector<SurfaceId> referenced_surfaces,
-    TransferableResourceArray resource_list);
+    std::vector<TransferableResource> resource_list);
 
 }  // namespace test
 }  // namespace cc
diff --git a/cc/test/fake_compositor_frame_sink_support_client.cc b/cc/test/fake_compositor_frame_sink_support_client.cc
index ab502e8..ff3568d 100644
--- a/cc/test/fake_compositor_frame_sink_support_client.cc
+++ b/cc/test/fake_compositor_frame_sink_support_client.cc
@@ -14,7 +14,7 @@
     default;
 
 void FakeCompositorFrameSinkSupportClient::DidReceiveCompositorFrameAck(
-    const ReturnedResourceArray& resources) {
+    const std::vector<ReturnedResource>& resources) {
   returned_resources_ = resources;
 }
 
@@ -22,7 +22,7 @@
     const BeginFrameArgs& args) {}
 
 void FakeCompositorFrameSinkSupportClient::ReclaimResources(
-    const ReturnedResourceArray& resources) {
+    const std::vector<ReturnedResource>& resources) {
   returned_resources_ = resources;
 }
 
diff --git a/cc/test/fake_compositor_frame_sink_support_client.h b/cc/test/fake_compositor_frame_sink_support_client.h
index 444315f..31d9804 100644
--- a/cc/test/fake_compositor_frame_sink_support_client.h
+++ b/cc/test/fake_compositor_frame_sink_support_client.h
@@ -19,9 +19,10 @@
 
   // CompositorFrameSinkSupportClient implementation.
   void DidReceiveCompositorFrameAck(
-      const ReturnedResourceArray& resources) override;
+      const std::vector<ReturnedResource>& resources) override;
   void OnBeginFrame(const BeginFrameArgs& args) override;
-  void ReclaimResources(const ReturnedResourceArray& resources) override;
+  void ReclaimResources(
+      const std::vector<ReturnedResource>& resources) override;
   void WillDrawSurface(const LocalSurfaceId& local_surface_id,
                        const gfx::Rect& damage_rect) override;
 
@@ -29,14 +30,14 @@
   const LocalSurfaceId& last_local_surface_id() const {
     return last_local_surface_id_;
   }
-  const ReturnedResourceArray& returned_resources() const {
+  const std::vector<ReturnedResource>& returned_resources() const {
     return returned_resources_;
   }
 
  private:
   gfx::Rect last_damage_rect_;
   LocalSurfaceId last_local_surface_id_;
-  ReturnedResourceArray returned_resources_;
+  std::vector<ReturnedResource> returned_resources_;
 
   DISALLOW_COPY_AND_ASSIGN(FakeCompositorFrameSinkSupportClient);
 };
diff --git a/cc/test/fake_layer_tree_frame_sink.cc b/cc/test/fake_layer_tree_frame_sink.cc
index 88b3793..0eeca9b5 100644
--- a/cc/test/fake_layer_tree_frame_sink.cc
+++ b/cc/test/fake_layer_tree_frame_sink.cc
@@ -73,7 +73,7 @@
 void FakeLayerTreeFrameSink::ReturnResourcesHeldByParent() {
   if (last_sent_frame_) {
     // Return the last frame's resources immediately.
-    ReturnedResourceArray resources;
+    std::vector<ReturnedResource> resources;
     for (const auto& resource : resources_held_by_parent_)
       resources.push_back(resource.ToReturnedResource());
     resources_held_by_parent_.clear();
diff --git a/cc/test/fake_layer_tree_frame_sink.h b/cc/test/fake_layer_tree_frame_sink.h
index d6d63c4..4efc404 100644
--- a/cc/test/fake_layer_tree_frame_sink.h
+++ b/cc/test/fake_layer_tree_frame_sink.h
@@ -71,7 +71,7 @@
 
   LayerTreeFrameSinkClient* client() { return client_; }
 
-  const TransferableResourceArray& resources_held_by_parent() {
+  const std::vector<TransferableResource>& resources_held_by_parent() {
     return resources_held_by_parent_;
   }
 
@@ -89,7 +89,7 @@
 
   std::unique_ptr<CompositorFrame> last_sent_frame_;
   size_t num_sent_frames_ = 0;
-  TransferableResourceArray resources_held_by_parent_;
+  std::vector<TransferableResource> resources_held_by_parent_;
   gfx::Rect last_swap_rect_;
 
  private:
diff --git a/cc/test/fake_layer_tree_frame_sink_client.h b/cc/test/fake_layer_tree_frame_sink_client.h
index fff25f14..b43d95b 100644
--- a/cc/test/fake_layer_tree_frame_sink_client.h
+++ b/cc/test/fake_layer_tree_frame_sink_client.h
@@ -17,7 +17,8 @@
 
   void SetBeginFrameSource(BeginFrameSource* source) override;
   void DidReceiveCompositorFrameAck() override;
-  void ReclaimResources(const ReturnedResourceArray& resources) override {}
+  void ReclaimResources(
+      const std::vector<ReturnedResource>& resources) override {}
   void DidLoseLayerTreeFrameSink() override;
   void SetExternalTilePriorityConstraints(
       const gfx::Rect& viewport_rect_for_tile_priority,
diff --git a/cc/test/fake_surface_resource_holder_client.cc b/cc/test/fake_surface_resource_holder_client.cc
index a5cd8f1..43c3ae0 100644
--- a/cc/test/fake_surface_resource_holder_client.cc
+++ b/cc/test/fake_surface_resource_holder_client.cc
@@ -11,7 +11,7 @@
 FakeSurfaceResourceHolderClient::~FakeSurfaceResourceHolderClient() = default;
 
 void FakeSurfaceResourceHolderClient::ReturnResources(
-    const ReturnedResourceArray& resources) {
+    const std::vector<ReturnedResource>& resources) {
   returned_resources_.insert(returned_resources_.end(), resources.begin(),
                              resources.end());
 }
diff --git a/cc/test/fake_surface_resource_holder_client.h b/cc/test/fake_surface_resource_holder_client.h
index aa0e6906..c79ce6a 100644
--- a/cc/test/fake_surface_resource_holder_client.h
+++ b/cc/test/fake_surface_resource_holder_client.h
@@ -15,15 +15,15 @@
   ~FakeSurfaceResourceHolderClient() override;
 
   // SurfaceResourceHolderClient implementation.
-  void ReturnResources(const ReturnedResourceArray& resources) override;
+  void ReturnResources(const std::vector<ReturnedResource>& resources) override;
 
   void clear_returned_resources() { returned_resources_.clear(); }
-  const ReturnedResourceArray& returned_resources() {
+  const std::vector<ReturnedResource>& returned_resources() {
     return returned_resources_;
   }
 
  private:
-  ReturnedResourceArray returned_resources_;
+  std::vector<ReturnedResource> returned_resources_;
 };
 
 }  // namespace cc
diff --git a/cc/test/mock_compositor_frame_sink_support_client.h b/cc/test/mock_compositor_frame_sink_support_client.h
index 792bb9d..6230223 100644
--- a/cc/test/mock_compositor_frame_sink_support_client.h
+++ b/cc/test/mock_compositor_frame_sink_support_client.h
@@ -19,9 +19,9 @@
 
   // CompositorFrameSinkSupportClient implementation.
   MOCK_METHOD1(DidReceiveCompositorFrameAck,
-               void(const ReturnedResourceArray&));
+               void(const std::vector<ReturnedResource>&));
   MOCK_METHOD1(OnBeginFrame, void(const BeginFrameArgs&));
-  MOCK_METHOD1(ReclaimResources, void(const ReturnedResourceArray&));
+  MOCK_METHOD1(ReclaimResources, void(const std::vector<ReturnedResource>&));
   MOCK_METHOD2(WillDrawSurface, void(const LocalSurfaceId&, const gfx::Rect&));
 };
 
diff --git a/cc/test/test_layer_tree_frame_sink.cc b/cc/test/test_layer_tree_frame_sink.cc
index 36b7e98b..0ef669a1 100644
--- a/cc/test/test_layer_tree_frame_sink.cc
+++ b/cc/test/test_layer_tree_frame_sink.cc
@@ -175,7 +175,7 @@
 }
 
 void TestLayerTreeFrameSink::DidReceiveCompositorFrameAck(
-    const ReturnedResourceArray& resources) {
+    const std::vector<ReturnedResource>& resources) {
   ReclaimResources(resources);
   // In synchronous mode, we manually send acks and this method should not be
   // used.
@@ -189,7 +189,7 @@
 }
 
 void TestLayerTreeFrameSink::ReclaimResources(
-    const ReturnedResourceArray& resources) {
+    const std::vector<ReturnedResource>& resources) {
   client_->ReclaimResources(resources);
 }
 
diff --git a/cc/test/test_layer_tree_frame_sink.h b/cc/test/test_layer_tree_frame_sink.h
index 569c039..ed72e96 100644
--- a/cc/test/test_layer_tree_frame_sink.h
+++ b/cc/test/test_layer_tree_frame_sink.h
@@ -84,9 +84,10 @@
 
   // CompositorFrameSinkSupportClient implementation.
   void DidReceiveCompositorFrameAck(
-      const ReturnedResourceArray& resources) override;
+      const std::vector<ReturnedResource>& resources) override;
   void OnBeginFrame(const BeginFrameArgs& args) override;
-  void ReclaimResources(const ReturnedResourceArray& resources) override;
+  void ReclaimResources(
+      const std::vector<ReturnedResource>& resources) override;
   void WillDrawSurface(const LocalSurfaceId& local_surface_id,
                        const gfx::Rect& damage_rect) override;
 
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 5f62cb6..5018686 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -1530,7 +1530,7 @@
 }
 
 void LayerTreeHostImpl::ReclaimResources(
-    const ReturnedResourceArray& resources) {
+    const std::vector<ReturnedResource>& resources) {
   // TODO(piman): We may need to do some validation on this ack before
   // processing it.
   if (!resource_provider_)
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index 8fba6e2..8728ac57 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -373,7 +373,8 @@
       const gfx::Transform& transform) override;
   void DidLoseLayerTreeFrameSink() override;
   void DidReceiveCompositorFrameAck() override;
-  void ReclaimResources(const ReturnedResourceArray& resources) override;
+  void ReclaimResources(
+      const std::vector<ReturnedResource>& resources) override;
   void SetMemoryPolicy(const ManagedMemoryPolicy& policy) override;
   void SetTreeActivationCallback(const base::Closure& callback) override;
   void OnDraw(const gfx::Transform& transform,
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 50d4aee..afb6683 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -8448,7 +8448,7 @@
     host_impl_->DrawLayers(&frame);
     host_impl_->DidDrawAllLayers(frame);
   }
-  host_impl_->ReclaimResources(ReturnedResourceArray());
+  host_impl_->ReclaimResources(std::vector<ReturnedResource>());
   host_impl_->DidReceiveCompositorFrameAck();
   EXPECT_EQ(acks_received_, 1);
 }
diff --git a/cc/trees/property_tree.cc b/cc/trees/property_tree.cc
index b4a4222..6f2fcdd 100644
--- a/cc/trees/property_tree.cc
+++ b/cc/trees/property_tree.cc
@@ -1248,6 +1248,9 @@
     scale_factor = transform_tree.page_scale_factor();
 
   gfx::SizeF scaled_scroll_bounds = gfx::ScaleSize(scroll_bounds, scale_factor);
+  scaled_scroll_bounds.SetSize(std::floor(scaled_scroll_bounds.width()),
+                               std::floor(scaled_scroll_bounds.height()));
+
   gfx::Size clip_layer_bounds = scroll_clip_layer_bounds(scroll_node->id);
 
   gfx::ScrollOffset max_offset(
diff --git a/chrome/VERSION b/chrome/VERSION
index 1701a9d..60373ca 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=61
 MINOR=0
-BUILD=3145
+BUILD=3146
 PATCH=0
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index 63010bdf..d5bd176 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -41,6 +41,7 @@
 import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
 import org.chromium.base.MemoryPressureListener;
+import org.chromium.base.ThreadUtils;
 import org.chromium.base.TraceEvent;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.base.library_loader.LibraryLoader;
@@ -67,6 +68,8 @@
 import org.chromium.chrome.browser.document.DocumentUtils;
 import org.chromium.chrome.browser.download.DownloadUtils;
 import org.chromium.chrome.browser.feature_engagement_tracker.FeatureEngagementTrackerFactory;
+import org.chromium.chrome.browser.feature_engagement_tracker.ScreenshotMonitor;
+import org.chromium.chrome.browser.feature_engagement_tracker.ScreenshotMonitorDelegate;
 import org.chromium.chrome.browser.firstrun.FirstRunActivity;
 import org.chromium.chrome.browser.firstrun.FirstRunFlowSequencer;
 import org.chromium.chrome.browser.firstrun.FirstRunSignInProcessor;
@@ -84,7 +87,6 @@
 import org.chromium.chrome.browser.multiwindow.MultiInstanceChromeTabbedActivity;
 import org.chromium.chrome.browser.multiwindow.MultiWindowUtils;
 import org.chromium.chrome.browser.net.spdyproxy.DataReductionProxySettings;
-import org.chromium.chrome.browser.ntp.ChromeHomeNewTabPage;
 import org.chromium.chrome.browser.ntp.NativePageAssassin;
 import org.chromium.chrome.browser.ntp.NewTabPage;
 import org.chromium.chrome.browser.ntp.NewTabPageUma;
@@ -122,6 +124,7 @@
 import org.chromium.chrome.browser.widget.emptybackground.EmptyBackgroundViewWrapper;
 import org.chromium.chrome.browser.widget.findinpage.FindToolbarManager;
 import org.chromium.chrome.browser.widget.textbubble.ViewAnchoredTextBubble;
+import org.chromium.components.feature_engagement_tracker.EventConstants;
 import org.chromium.components.feature_engagement_tracker.FeatureConstants;
 import org.chromium.components.feature_engagement_tracker.FeatureEngagementTracker;
 import org.chromium.content.browser.ContentVideoView;
@@ -147,8 +150,8 @@
  * This is the main activity for ChromeMobile when not running in document mode.  All the tabs
  * are accessible via a chrome specific tab switching UI.
  */
-public class ChromeTabbedActivity extends ChromeActivity implements OverviewModeObserver {
-
+public class ChromeTabbedActivity
+        extends ChromeActivity implements OverviewModeObserver, ScreenshotMonitorDelegate {
     private static final int FIRST_RUN_EXPERIENCE_RESULT = 101;
 
     @Retention(RetentionPolicy.SOURCE)
@@ -230,6 +233,8 @@
     private TabModelSelectorTabObserver mTabModelSelectorTabObserver;
     private TabModelSelectorTabModelObserver mTabModelObserver;
 
+    private ScreenshotMonitor mScreenshotMonitor;
+
     private boolean mUIInitialized;
 
     private boolean mIsOnFirstRun;
@@ -585,6 +590,18 @@
         } else {
             SuggestionsEventReporterBridge.onColdStart();
         }
+
+        maybeStartMonitoringForScreenshots();
+    }
+
+    private void maybeStartMonitoringForScreenshots() {
+        // Part of the (more runtime-related) check to determine whether to trigger help UI is
+        // left until onScreenshotTaken() since it is less expensive to keep monitoring on and
+        // check when the help UI is accessed than it is to start/stop monitoring per tab change
+        // (e.g. tab switch or in overview mode).
+        if (DeviceFormFactor.isTablet()) return;
+
+        mScreenshotMonitor.startMonitoring();
     }
 
     @Override
@@ -595,6 +612,8 @@
         mLocaleManager.setSnackbarManager(null);
         mLocaleManager.stopObservingPhoneChanges();
 
+        mScreenshotMonitor.stopMonitoring();
+
         super.onPauseWithNative();
     }
 
@@ -773,26 +792,26 @@
                 mLayoutManager.hideOverview(false);
             }
 
-            FeatureEngagementTracker tracker =
+            final FeatureEngagementTracker tracker =
                     FeatureEngagementTrackerFactory.getFeatureEngagementTrackerForProfile(
                             Profile.getLastUsedProfile());
             tracker.addOnInitializedCallback(new Callback<Boolean>() {
                 @Override
                 public void onResult(Boolean result) {
-                    showFeatureEngagementTextBubbleForDownloadHome();
+                    showFeatureEngagementTextBubbleForDownloadHome(tracker);
                 }
             });
 
+            mScreenshotMonitor = ScreenshotMonitor.create(ChromeTabbedActivity.this);
+
             mUIInitialized = true;
         } finally {
             TraceEvent.end("ChromeTabbedActivity.initializeUI");
         }
     }
 
-    private void showFeatureEngagementTextBubbleForDownloadHome() {
-        final FeatureEngagementTracker tracker =
-                FeatureEngagementTrackerFactory.getFeatureEngagementTrackerForProfile(
-                        Profile.getLastUsedProfile());
+    private void showFeatureEngagementTextBubbleForDownloadHome(
+            final FeatureEngagementTracker tracker) {
         if (!tracker.shouldTriggerHelpUI(FeatureConstants.DOWNLOAD_HOME_FEATURE)) return;
 
         ViewAnchoredTextBubble textBubble = new ViewAnchoredTextBubble(this,
@@ -1713,12 +1732,11 @@
         if (!mUIInitialized) return false;
         final Tab currentTab = getActivityTab();
 
-        // Close the bottom sheet before trying to navigate back. If the tab is on the NTP, fall
-        // through to decide if the browser should be sent into the background.
+        // Close the bottom sheet before trying to navigate back.
         if (getBottomSheet() != null
-                && getBottomSheet().getSheetState() != BottomSheet.SHEET_STATE_PEEK
-                && (currentTab == null
-                           || !(currentTab.getNativePage() instanceof ChromeHomeNewTabPage))) {
+                && getBottomSheet().getSheetState() != BottomSheet.SHEET_STATE_PEEK) {
+            getBottomSheet().getBottomSheetMetrics().setSheetCloseReason(
+                    BottomSheetMetrics.CLOSED_BY_BACK_PRESS);
             getBottomSheet().setSheetState(BottomSheet.SHEET_STATE_PEEK, true);
             return true;
         }
@@ -2203,4 +2221,45 @@
     public boolean supportsFullscreenActivity() {
         return !VrShellDelegate.isInVr();
     }
-}
+
+    @Override
+    public void onScreenshotTaken() {
+        // Second part of the check to determine whether to trigger help UI
+        if (isInOverviewMode() || !DownloadUtils.isAllowedToDownloadPage(getActivityTab())) return;
+
+        FeatureEngagementTracker tracker =
+                FeatureEngagementTrackerFactory.getFeatureEngagementTrackerForProfile(
+                        Profile.getLastUsedProfile());
+        tracker.notifyEvent(EventConstants.SCREENSHOT_TAKEN_CHROME_IN_FOREGROUND);
+        maybeShowFeatureEngagementTextBubbleForDownloadPage(tracker);
+    }
+
+    private void maybeShowFeatureEngagementTextBubbleForDownloadPage(
+            final FeatureEngagementTracker tracker) {
+        if (!tracker.shouldTriggerHelpUI(FeatureConstants.DOWNLOAD_PAGE_SCREENSHOT_FEATURE)) return;
+
+        ViewAnchoredTextBubble textBubble =
+                new ViewAnchoredTextBubble(this, getToolbarManager().getMenuButton(),
+                        R.string.iph_download_page_for_offline_usage_text,
+                        R.string.iph_download_page_for_offline_usage_accessibility_text);
+        textBubble.setDismissOnTouchInteraction(true);
+        textBubble.addOnDismissListener(new OnDismissListener() {
+            @Override
+            public void onDismiss() {
+                ThreadUtils.postOnUiThread(new Runnable() {
+                    @Override
+                    public void run() {
+                        tracker.dismissed(FeatureConstants.DOWNLOAD_PAGE_SCREENSHOT_FEATURE);
+                        getAppMenuHandler().setMenuHighlight(null);
+                    }
+                });
+            }
+        });
+        getAppMenuHandler().setMenuHighlight(R.id.offline_page_id);
+        int yInsetPx =
+                getResources().getDimensionPixelOffset(R.dimen.text_bubble_menu_anchor_y_inset);
+        textBubble.setInsetPx(0, FeatureUtilities.isChromeHomeEnabled() ? yInsetPx : 0, 0,
+                FeatureUtilities.isChromeHomeEnabled() ? 0 : yInsetPx);
+        textBubble.show();
+    }
+}
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ServiceTabLauncher.java b/chrome/android/java/src/org/chromium/chrome/browser/ServiceTabLauncher.java
index 1c18a1e93..efb09f15 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ServiceTabLauncher.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ServiceTabLauncher.java
@@ -105,7 +105,7 @@
         // - The WebappDataStorage hasn't been opened recently enough.
         // OR
         // - The WebappDataStorage corresponds to a WebAPK (and WebAPKs are disabled).
-        if (storage == null || !storage.wasLaunchedRecently()
+        if (storage == null || !storage.wasUsedRecently()
                 || storage.getWebApkPackageName() != null) {
             LoadUrlParams loadUrlParams = new LoadUrlParams(url, PageTransition.LINK);
             loadUrlParams.setPostData(postData);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchContext.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchContext.java
index e8b55e0..eac80488 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchContext.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchContext.java
@@ -8,6 +8,7 @@
 import android.os.Build;
 import android.text.TextUtils;
 
+import org.chromium.base.VisibleForTesting;
 import org.chromium.base.annotations.CalledByNative;
 
 import javax.annotation.Nullable;
@@ -38,6 +39,9 @@
     private int mSelectionStartOffset = INVALID_OFFSET;
     private int mSelectionEndOffset = INVALID_OFFSET;
 
+    // The home country, or an empty string if not set.
+    private String mHomeCountry = "";
+
     // The offset of an initial Tap gesture within the text content.
     private int mTapOffset = INVALID_OFFSET;
 
@@ -47,12 +51,22 @@
     // The original encoding of the base page.
     private String mEncoding;
 
-    // The tapped word, as analyzed internally before selection takes place, or {@code null} if no
-    // analysis has been done yet.
-    private String mTappedWord;
+    // The word that was tapped, as analyzed internally before selection takes place,
+    // or {@code null} if no analysis has been done yet.
+    private String mWordTapped;
 
-    // The offset of the tap within the tapped word or {@code INVALID_OFFSET} if not yet analyzed.
-    private int mTappedWordOffset = INVALID_OFFSET;
+    // The offset of the tapped word within the surrounding text or {@code INVALID_OFFSET} if not
+    // yet analyzed.
+    private int mWordTappedStartOffset = INVALID_OFFSET;
+
+    // The offset of the tap within the tapped word, or {@code INVALID_OFFSET} if not yet analyzed.
+    private int mTapWithinWordOffset = INVALID_OFFSET;
+
+    // The words before and after the tapped word, and their offsets.
+    private String mWordPreviousToTap;
+    private int mWordPreviousToTapOffset = INVALID_OFFSET;
+    private String mWordFollowingTap;
+    private int mWordFollowingTapOffset = INVALID_OFFSET;
 
     /**
      * Constructs a context that tracks the selection and some amount of page content.
@@ -71,6 +85,7 @@
      */
     void setResolveProperties(String homeCountry, boolean maySendBasePageUrl) {
         mHasSetResolveProperties = true;
+        mHomeCountry = homeCountry;
         nativeSetResolveProperties(getNativePointer(), homeCountry, maySendBasePageUrl);
     }
 
@@ -139,6 +154,13 @@
     }
 
     /**
+     * @return The home country, or an empty string if none set.
+     */
+    String getHomeCountry() {
+        return mHomeCountry;
+    }
+
+    /**
      * @return The initial word selected by a Tap.
      */
     String getInitialSelectedWord() {
@@ -203,7 +225,8 @@
     /**
      * @return Whether this context has valid Surrounding text and initial Tap offset.
      */
-    private boolean hasValidTappedText() {
+    @VisibleForTesting
+    boolean hasValidTappedText() {
         return !TextUtils.isEmpty(mSurroundingText) && mTapOffset >= 0
                 && mTapOffset <= mSurroundingText.length();
     }
@@ -211,10 +234,10 @@
     /**
      * @return Whether this context has a valid selection.
      */
-    private boolean hasValidSelection() {
-        if (!hasValidTappedText()) return false;
-
-        return mSelectionStartOffset != INVALID_OFFSET && mSelectionEndOffset != INVALID_OFFSET
+    @VisibleForTesting
+    boolean hasValidSelection() {
+        return !TextUtils.isEmpty(mSurroundingText) && mSelectionStartOffset != INVALID_OFFSET
+                && mSelectionEndOffset != INVALID_OFFSET
                 && mSelectionStartOffset < mSelectionEndOffset
                 && mSelectionEndOffset < mSurroundingText.length();
     }
@@ -222,30 +245,70 @@
     /**
      * @return Whether a Tap gesture has occurred and been analyzed.
      */
-    private boolean hasAnalyzedTap() {
+    @VisibleForTesting
+    boolean hasAnalyzedTap() {
         return mTapOffset >= 0;
     }
 
     /**
-     * @return The tapped word, or {@code null} if the tapped word cannot be identified by the
-     *         current limited parsing capability.
-     * @see #analyzeTap
+     * @return The word tapped, or {@code null} if the word that was tapped cannot be identified by
+     *         the current limited parsing capability.
+     * @see #analyzeTap(int)
      */
-    String getTappedWord() {
-        return mTappedWord;
+    String getWordTapped() {
+        return mWordTapped;
     }
 
     /**
-     * @return The offset of the tap within the tapped word, or {@code -1} if the tapped word cannot
-     *         be identified by the current parsing capability.
-     * @see #analyzeTap
+     * @return The offset of the start of the tapped word, or {@code INVALID_OFFSET} if the tapped
+     *         word cannot be identified by the current parsing capability.
+     * @see #analyzeTap(int)
      */
-    int getTappedWordOffset() {
-        return mTappedWordOffset;
+    int getWordTappedOffset() {
+        return mWordTappedStartOffset;
     }
 
     /**
-     * Finds the tapped word by expanding from the initial Tap offset looking for word-breaks.
+     * @return The offset of the tap within the tapped word, or {@code INVALID_OFFSET} if the tapped
+     *         word cannot be identified by the current parsing capability.
+     * @see #analyzeTap(int)
+     */
+    int getTapOffsetWithinTappedWord() {
+        return mTapWithinWordOffset;
+    }
+
+    /**
+     * @return The word previous to the word that was tapped, or {@code null} if not available.
+     */
+    String getWordPreviousToTap() {
+        return mWordPreviousToTap;
+    }
+
+    /**
+     * @return The offset of the first character of the word previous to the word that was tapped,
+     *         or {@code INVALID_OFFSET} if not available.
+     */
+    int getWordPreviousToTapOffset() {
+        return mWordPreviousToTapOffset;
+    }
+
+    /**
+     * @return The word following the word that was tapped, or {@code null} if not available.
+     */
+    String getWordFollowingTap() {
+        return mWordFollowingTap;
+    }
+
+    /**
+     * @return The offset of the first character of the word following the word that was tapped,
+     *         or {@code INVALID_OFFSET} if not available.
+     */
+    int getWordFollowingTapOffset() {
+        return mWordFollowingTapOffset;
+    }
+
+    /**
+     * Finds the words around the initial Tap offset by expanding and looking for word-breaks.
      * This mimics the Blink word-segmentation invoked by SelectWordAroundCaret and similar
      * selection logic, but is only appropriate for limited use.  Does not work on ideographic
      * languages and possibly many other cases.  Should only be used only for ML signal evaluation.
@@ -253,39 +316,76 @@
      */
     private void analyzeTap(int tapOffset) {
         mTapOffset = tapOffset;
-        mTappedWord = null;
-        mTappedWordOffset = INVALID_OFFSET;
+        mWordTapped = null;
+        mTapWithinWordOffset = INVALID_OFFSET;
 
         assert hasValidTappedText();
 
-        int wordStartOffset = findWordStartOffset(mSurroundingText, mTapOffset);
-        int wordEndOffset = findWordEndOffset(mSurroundingText, mTapOffset);
+        int wordStartOffset = findWordStartOffset(mTapOffset);
+        int wordEndOffset = findWordEndOffset(mTapOffset);
         if (wordStartOffset == INVALID_OFFSET || wordEndOffset == INVALID_OFFSET) return;
 
-        mTappedWord = mSurroundingText.substring(wordStartOffset, wordEndOffset);
-        mTappedWordOffset = mTapOffset - wordStartOffset;
+        mWordTappedStartOffset = wordStartOffset;
+        mWordTapped = mSurroundingText.substring(wordStartOffset, wordEndOffset);
+        mTapWithinWordOffset = mTapOffset - wordStartOffset;
+
+        findPreviousWord();
+        findFollowingWord();
     }
 
     /**
-     * Finds the offset of the start of the word that includes the given initial offset.
-     * The character at the initial offset is not examined, but the one before it is, and scanning
-     * continues on to earlier characters until a non-word character is found.  The offset just
-     * before the non-word character is returned.  If the initial offset is a space immediately
-     * following a word then the start offset of that word is returned.
-     * @param text The text to scan.
-     * @param initial The initial offset to scan before.
-     * @return The start of the word that contains the given initial offset, within {@code text}.
+     * Finds the word previous to the word tapped.
      */
-    private int findWordStartOffset(String text, int initial) {
+    void findPreviousWord() {
+        // Scan past word-break characters preceding the tapped word.
+        int previousWordEndOffset = mWordTappedStartOffset;
+        while (previousWordEndOffset >= 1 && isWordBreakAtIndex(previousWordEndOffset - 1)) {
+            --previousWordEndOffset;
+        }
+        if (previousWordEndOffset == 0) return;
+
+        mWordPreviousToTapOffset = findWordStartOffset(previousWordEndOffset);
+        if (mWordPreviousToTapOffset == INVALID_OFFSET) return;
+
+        mWordPreviousToTap =
+                mSurroundingText.substring(mWordPreviousToTapOffset, previousWordEndOffset);
+    }
+
+    /**
+     * Finds the word following the word tapped.
+     */
+    void findFollowingWord() {
+        int tappedWordOffset = getWordTappedOffset();
+        int followingWordStartOffset = tappedWordOffset + mWordTapped.length() + 1;
+        while (followingWordStartOffset < mSurroundingText.length()
+                && isWordBreakAtIndex(followingWordStartOffset)) {
+            ++followingWordStartOffset;
+        }
+        if (followingWordStartOffset == mSurroundingText.length()) return;
+
+        int wordFollowingTapEndOffset = findWordEndOffset(followingWordStartOffset);
+        if (wordFollowingTapEndOffset == INVALID_OFFSET) return;
+
+        mWordFollowingTapOffset = followingWordStartOffset;
+        mWordFollowingTap =
+                mSurroundingText.substring(mWordFollowingTapOffset, wordFollowingTapEndOffset);
+    }
+
+    /**
+     * @return The start of the word that contains the given initial offset, within the surrounding
+     *         text, or {@code INVALID_OFFSET} if not found.
+     */
+    private int findWordStartOffset(int initial) {
         // Scan before, aborting if we hit any ideographic letter.
         for (int offset = initial - 1; offset >= 0; offset--) {
-            if (isUnreliableWordBreakAtIndex(text, offset)) return INVALID_OFFSET;
+            if (isCharFromAlphabetWithUnreliableWordBreakAtIndex(offset)) return INVALID_OFFSET;
 
-            if (isWordBreakAtIndex(text, offset)) {
+            if (isWordBreakAtIndex(offset)) {
                 // The start of the word is after this word break.
                 return offset + 1;
             }
         }
+
         return INVALID_OFFSET;
     }
 
@@ -295,16 +395,16 @@
      * so a 3 character word "who" has start index 0 and end index 3.
      * The character at the initial offset is examined and each one after that too until a non-word
      * character is encountered, and that offset will be returned.
-     * @param text The text to scan.
      * @param initial The initial offset to scan from.
-     * @return The end of the word that contains the given initial offset, within {@code text}.
+     * @return The end of the word that contains the given initial offset, within the surrounding
+     *         text.
      */
-    private int findWordEndOffset(String text, int initial) {
+    private int findWordEndOffset(int initial) {
         // Scan after, aborting if we hit any CJKN letter.
-        for (int offset = initial; offset < text.length(); offset++) {
-            if (isUnreliableWordBreakAtIndex(text, offset)) return INVALID_OFFSET;
+        for (int offset = initial; offset < mSurroundingText.length(); offset++) {
+            if (isCharFromAlphabetWithUnreliableWordBreakAtIndex(offset)) return INVALID_OFFSET;
 
-            if (isWordBreakAtIndex(text, offset)) {
+            if (isWordBreakAtIndex(offset)) {
                 // The end of the word is the offset of this word break.
                 return offset;
             }
@@ -318,7 +418,7 @@
      *         platforms where we can't know for sure.
      */
     @SuppressLint("NewApi")
-    private boolean isUnreliableWordBreakAtIndex(String text, int index) {
+    boolean isCharFromAlphabetWithUnreliableWordBreakAtIndex(String text, int index) {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
             return Character.isIdeographic(text.charAt(index));
         } else {
@@ -327,11 +427,20 @@
     }
 
     /**
+     * @return Whether the character at the given index in the surrounding text might be in an
+     *         alphabet that has unreliable word breaks, such as CKJV languages.  Returns
+     *         {@code true} on older platforms where we can't know for sure.
+     */
+    private boolean isCharFromAlphabetWithUnreliableWordBreakAtIndex(int index) {
+        return isCharFromAlphabetWithUnreliableWordBreakAtIndex(mSurroundingText, index);
+    }
+
+    /**
      * @return Whether the character at the given index is a word-break.
      */
-    private boolean isWordBreakAtIndex(String text, int index) {
-        return !Character.isLetterOrDigit(text.charAt(index))
-                && text.codePointAt(index) != SOFT_HYPHEN_CHAR;
+    private boolean isWordBreakAtIndex(int index) {
+        return !Character.isLetterOrDigit(mSurroundingText.charAt(index))
+                && mSurroundingText.charAt(index) != SOFT_HYPHEN_CHAR;
     }
 
     // ============================================================================================
@@ -347,10 +456,14 @@
     // ============================================================================================
     // Native methods.
     // ============================================================================================
-    private native long nativeInit();
-    private native void nativeDestroy(long nativeContextualSearchContext);
-    private native void nativeSetResolveProperties(
+    @VisibleForTesting
+    protected native long nativeInit();
+    @VisibleForTesting
+    protected native void nativeDestroy(long nativeContextualSearchContext);
+    @VisibleForTesting
+    protected native void nativeSetResolveProperties(
             long nativeContextualSearchContext, String homeCountry, boolean maySendBasePageUrl);
-    private native void nativeAdjustSelection(
+    @VisibleForTesting
+    protected native void nativeAdjustSelection(
             long nativeContextualSearchContext, int startAdjust, int endAdjust);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchEntityHeuristic.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchEntityHeuristic.java
new file mode 100644
index 0000000..6134f90
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchEntityHeuristic.java
@@ -0,0 +1,221 @@
+// 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.
+
+package org.chromium.chrome.browser.contextualsearch;
+
+import android.text.TextUtils;
+
+import org.chromium.base.VisibleForTesting;
+
+import java.util.Locale;
+
+/**
+ * Implements a simple first-cut heuristic for whether a Tap is on an entity or not.
+ * This is intended to be a proof-of-concept that entities are worth tapping upon.
+ * This implementation only recognizes one simple pattern that we recognize as a proper noun: two
+ * camel-case words that are not at the beginning of a sentence, in a page that we think is English.
+ * <p>
+ * This is not a robust implementation -- it's only really suitable as a strong-positive signal
+ * that can sometimes be extracted from the page content.  Future implementations could use CLD or
+ * some translate infrastructure to determine if the page is really in a language that uses
+ * camel-case for proper nouns (e.g. exclude German because it capitalizes all nouns).  Leveraging
+ * an on-device entity recognizer is another natural extension to this idea.
+ * <p>
+ * The current algorithm is designed to have relatively high precision at the expense of very low
+ * recall (lots of false-negatives, but patterns that are "recognized" should usually be entities).
+ * <p>
+ * We implement suppression, but only really apply that for testing and interactive demo purposes.
+ */
+class ContextualSearchEntityHeuristic extends ContextualSearchHeuristic {
+    private static final int INVALID_OFFSET = ContextualSearchContext.INVALID_OFFSET;
+
+    private final boolean mIsSuppressionEnabled;
+    private final boolean mIsConditionSatisfied;
+    private final boolean mIsProbablyEnglishProperNoun;
+
+    /**
+     * Constructs a heuristic to determine if the current Tap looks like it was on a name or not.
+     * @param contextualSearchContext The current {@link ContextualSearchContext} so we can figure
+     *        out the words around what has been tapped.
+     */
+    ContextualSearchEntityHeuristic(ContextualSearchContext contextualSearchContext) {
+        this(contextualSearchContext, ContextualSearchFieldTrial.isNotAnEntitySuppressionEnabled());
+    }
+
+    /**
+     * Constructs an instance for testing.
+     */
+    static ContextualSearchEntityHeuristic testInstance(
+            ContextualSearchContext contextualSearchContext, boolean isEnabled) {
+        return new ContextualSearchEntityHeuristic(contextualSearchContext, isEnabled);
+    }
+
+    /**
+     * Constructs an instance of a {@link ContextualSearchHeuristic} that provides a signal for a
+     * tap that is probably on a proper noun in an English page.
+     * @param contextualSearchContext The current {@link ContextualSearchContext} so we can figure
+     *                                out the words around what has been tapped.
+     * @param isEnabled Whether or not to enable suppression.
+     */
+    private ContextualSearchEntityHeuristic(
+            ContextualSearchContext contextualSearchContext, boolean isEnabled) {
+        mIsSuppressionEnabled = isEnabled;
+        boolean isProbablyEnglishPage = isProbablyEnglishUserOrPage(contextualSearchContext);
+        mIsProbablyEnglishProperNoun = isProbablyEnglishPage
+                && isTapOnTwoCamelCaseWordsMidSentence(contextualSearchContext);
+        mIsConditionSatisfied = !mIsProbablyEnglishProperNoun;
+    }
+
+    @Override
+    protected boolean isConditionSatisfiedAndEnabled() {
+        return mIsSuppressionEnabled && mIsConditionSatisfied;
+    }
+
+    @Override
+    protected void logResultsSeen(boolean wasSearchContentViewSeen, boolean wasActivatedByTap) {
+        if (wasActivatedByTap) {
+            ContextualSearchUma.logTapOnEntitySeen(
+                    wasSearchContentViewSeen, !mIsConditionSatisfied);
+        }
+    }
+
+    @VisibleForTesting
+    protected boolean isProbablyEnglishProperNoun() {
+        return mIsProbablyEnglishProperNoun;
+    }
+
+    /**
+     * @return Whether the tap is on a proper noun.
+     */
+    private boolean isTapOnTwoCamelCaseWordsMidSentence(
+            ContextualSearchContext contextualSearchContext) {
+        // Check common cases that we can quickly reject.
+        String tappedWord = contextualSearchContext.getWordTapped();
+        if (TextUtils.isEmpty(tappedWord)
+                || hasCharWithUnreliableWordBreak(contextualSearchContext, tappedWord)
+                || !isCapitalizedCamelCase(tappedWord)) {
+            return false;
+        }
+
+        // Check if the tapped word is the first word of a two-word entity.
+        if (isTwoWordCamelCaseSpaceSeparatedEntity(contextualSearchContext, tappedWord,
+                    contextualSearchContext.getWordTappedOffset(),
+                    contextualSearchContext.getWordFollowingTap(),
+                    contextualSearchContext.getWordFollowingTapOffset())) {
+            return true;
+        }
+
+        // Otherwise the tapped word needs to be the second word of a two-word entity.
+        return isTwoWordCamelCaseSpaceSeparatedEntity(contextualSearchContext,
+                    contextualSearchContext.getWordPreviousToTap(),
+                    contextualSearchContext.getWordPreviousToTapOffset(), tappedWord,
+                    contextualSearchContext.getWordTappedOffset());
+    }
+
+    /**
+     * Considers whether the given words at the given offsets are probably a two-word entity based
+     * on our simple rules for English: both camel-case and separated by just a single space and
+     * not following whitespace that precedes a character that commonly ends a sentence.
+     * @param contextualSearchContext The {@link ContextualSearchContext} that the words came from.
+     * @param firstWord The first word of a possible entity.
+     * @param firstWordOffset The offset of the first word.
+     * @param secondWord The second word of a possible entity.
+     * @param secondWordOffset The offset of the second word.
+     * @return Whether the words are probably an entity.
+     */
+    private boolean isTwoWordCamelCaseSpaceSeparatedEntity(
+            ContextualSearchContext contextualSearchContext, String firstWord, int firstWordOffset,
+            String secondWord, int secondWordOffset) {
+        if (!isCapitalizedCamelCase(firstWord) || !isCapitalizedCamelCase(secondWord)) return false;
+
+        if (!isWhitespaceThatDoesntEndASentence(contextualSearchContext, firstWordOffset - 1)) {
+            return false;
+        }
+
+        // Check that there's just one separator character.
+        if (firstWordOffset + firstWord.length() + 1 != secondWordOffset) return false;
+
+        // Check that it's a space.
+        return isWhitespaceAtOffset(contextualSearchContext, secondWordOffset - 1);
+    }
+
+    /**
+     * Scans previous characters starting from the given offset in the given context.
+     * @return Whether there is whitespace that doesn't end a sentence at the given offset.
+     */
+    private boolean isWhitespaceThatDoesntEndASentence(
+            ContextualSearchContext contextualSearchContext, int offset) {
+        int whitespaceScanOffset = offset;
+        while (whitespaceScanOffset > 0
+                && isWhitespaceAtOffset(contextualSearchContext, whitespaceScanOffset)) {
+            --whitespaceScanOffset;
+        }
+        return whitespaceScanOffset > 0
+                && !isEndOfSentenceChar(contextualSearchContext.getSurroundingText().charAt(
+                           whitespaceScanOffset));
+    }
+
+    /**
+     * @return Whether the given character is often used to end a sentence (with high precision, low
+     *         recall).
+     */
+    private boolean isEndOfSentenceChar(char c) {
+        return c == '.' || c == '?' || c == '!' || c == ':';
+    }
+
+    /**
+     * @return {@code true} if the word starts with an upper-case letter and has at least one letter
+     *         that is not considered upper-case.
+     */
+    private boolean isCapitalizedCamelCase(String word) {
+        if (TextUtils.isEmpty(word) || word.length() <= 1) return false;
+
+        Character firstChar = word.charAt(0);
+        return Character.isUpperCase(firstChar)
+                && !word.toUpperCase(Locale.getDefault()).equals(word);
+    }
+
+    /**
+     * @return Whether the surrounding text has a whitespace character at the given offset.
+     */
+    private boolean isWhitespaceAtOffset(
+            ContextualSearchContext contextualSearchContext, int offset) {
+        if (offset == INVALID_OFFSET) return false;
+
+        Character charAtOffset = contextualSearchContext.getSurroundingText().charAt(offset);
+        return Character.isWhitespace(charAtOffset);
+    }
+
+    /**
+     * @return Whether the given word in the given context has any characters in a alphabet that
+     *         has unreliable word-breaks.
+     */
+    private boolean hasCharWithUnreliableWordBreak(
+            ContextualSearchContext contextualSearchContext, String word) {
+        for (int index = 0; index < word.length(); index++) {
+            if (contextualSearchContext.isCharFromAlphabetWithUnreliableWordBreakAtIndex(
+                        word, index)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Makes an educated guess that the page is probably in English based on the factors that
+     * tend to exclude non-English users.
+     * This implementation may return lots of false-negatives, but should be pretty reliable on
+     * positive results.
+     * @param contextualSearchContext The ContextualSearchContext.
+     * @return Whether we think the page is English based on information we have about the user's
+     *         language preferences.
+     */
+    private boolean isProbablyEnglishUserOrPage(ContextualSearchContext contextualSearchContext) {
+        if (!Locale.ENGLISH.getLanguage().equals(Locale.getDefault().getLanguage())) return false;
+
+        return Locale.getDefault().getCountry().equalsIgnoreCase(
+                contextualSearchContext.getHomeCountry());
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java
index 92c2176f..c68b61e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java
@@ -52,6 +52,8 @@
     private static final String SHORT_WORD_SUPPRESSION_ENABLED = "enable_short_word_suppression";
     private static final String NOT_LONG_WORD_SUPPRESSION_ENABLED =
             "enable_not_long_word_suppression";
+    @VisibleForTesting
+    static final String NOT_AN_ENTITY_SUPPRESSION_ENABLED = "enable_not_an_entity_suppression";
 
     private static final String MINIMUM_SELECTION_LENGTH = "minimum_selection_length";
 
@@ -86,6 +88,7 @@
     private static Boolean sIsWordEdgeSuppressionEnabled;
     private static Boolean sIsShortWordSuppressionEnabled;
     private static Boolean sIsNotLongWordSuppressionEnabled;
+    private static Boolean sIsNotAnEntitySuppressionEnabled;
     private static Integer sMinimumSelectionLength;
     private static Boolean sIsOnlineDetectionDisabled;
     private static Boolean sIsAmpAsSeparateTabDisabled;
@@ -286,6 +289,16 @@
     }
 
     /**
+     * @return Whether triggering is suppressed for a tap that's not on an entity.
+     */
+    static boolean isNotAnEntitySuppressionEnabled() {
+        if (sIsNotAnEntitySuppressionEnabled == null) {
+            sIsNotAnEntitySuppressionEnabled = getBooleanParam(NOT_AN_ENTITY_SUPPRESSION_ENABLED);
+        }
+        return sIsNotAnEntitySuppressionEnabled.booleanValue();
+    }
+
+    /**
      * @return The minimum valid selection length.
      */
     static int getMinimumSelectionLength() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchInternalStateController.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchInternalStateController.java
index c913693..f864760 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchInternalStateController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchInternalStateController.java
@@ -72,6 +72,11 @@
         /** This starts a sequence of states needed to get to the SHOWING_TAP_SEARCH resting state.
          */
         TAP_RECOGNIZED,
+        /** Waits to see if the Tap was on a previous tap-selection, which will show the selection
+         * manipulation pins and be subsumed by a LONG_PRESS_RECOGNIZED.  If that doesn't happen
+         * within the waiting period we'll advance.
+         */
+        WAITING_FOR_POSSIBLE_TAP_ON_TAP_SELECTION,
         /** Gathers text surrounding the selection. */
         GATHERING_SURROUNDINGS,
         /** Decides if the gesture should trigger the UX or be suppressed. */
@@ -233,6 +238,9 @@
                 break;
             case TAP_RECOGNIZED:
                 break;
+            case WAITING_FOR_POSSIBLE_TAP_ON_TAP_SELECTION:
+                mStateHandler.waitForPossibleTapOnTapSelection();
+                break;
             case GATHERING_SURROUNDINGS:
                 mStateHandler.gatherSurroundingText();
                 break;
@@ -293,13 +301,15 @@
                 reset(StateChangeReason.BASE_PAGE_TAP);
                 break;
             case TAP_RECOGNIZED:
-                if (mPreviousState == InternalState.SHOWING_TAP_SEARCH) {
-                    // This is a second-tap on a Tap-selection.
-                    // We'll soon recognize a Long-press and show the edit pins, so nothing needed.
+                if (mPreviousState != null && mPreviousState != InternalState.IDLE) {
+                    transitionTo(InternalState.WAITING_FOR_POSSIBLE_TAP_ON_TAP_SELECTION);
                 } else {
                     transitionTo(InternalState.GATHERING_SURROUNDINGS);
                 }
                 break;
+            case WAITING_FOR_POSSIBLE_TAP_ON_TAP_SELECTION:
+                transitionTo(InternalState.GATHERING_SURROUNDINGS);
+                break;
             case GATHERING_SURROUNDINGS:
                 // We gather surroundings for both Tap and Long-press in order to notify icing.
                 if (mPreviousState == InternalState.LONG_PRESS_RECOGNIZED) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchInternalStateHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchInternalStateHandler.java
index 8151381..9e1f23b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchInternalStateHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchInternalStateHandler.java
@@ -13,51 +13,60 @@
 public interface ContextualSearchInternalStateHandler {
     /**
      * Hides the Contextual Search user interface.
-     * {@See ContextualSearchInternalStateController#InternalState#IDLE}.
+     * @see ContextualSearchInternalStateController.InternalState#IDLE
      */
     void hideContextualSearchUi(StateChangeReason reason);
 
     /**
      * Shows the Contextual Search user interface for a Tap.
-     * {@See ContextualSearchInternalStateController#InternalState#SHOW_FULL_TAP_UI}.
+     * @see ContextualSearchInternalStateController.InternalState#SHOW_FULL_TAP_UI
      */
     void showContextualSearchTapUi();
 
     /**
      * Shows the Contextual Search user interface for a Long-press.
-     * {@See ContextualSearchInternalStateController#InternalState#SHOWING_LONGPRESS_SEARCH}.
+     * @see ContextualSearchInternalStateController.InternalState#SHOWING_LONGPRESS_SEARCH
      */
     void showContextualSearchLongpressUi();
 
     /**
      * Gathers text surrounding the current selection, which may have been created by either a Tap
      * or a Long-press gesture.
-     * {@See ContextualSearchInternalStateController#InternalState#GATHERING_SURROUNDINGS}.
+     * @see ContextualSearchInternalStateController.InternalState#GATHERING_SURROUNDINGS
      */
     void gatherSurroundingText();
 
     /**
      * Starts the process of deciding if we'll suppress the current gesture or not.
-     * {@See ContextualSearchInternalStateController#InternalState#DECIDING_SUPPRESSION}.
+     * @see ContextualSearchInternalStateController.InternalState#DECIDING_SUPPRESSION
      */
     void decideSuppression();
 
     /**
      * Starts the process of selecting a word around the current caret.
-     * {@See ContextualSearchInternalStateController#InternalState#START_SHOWING_TAP_UI}.
+     * @see ContextualSearchInternalStateController.InternalState#START_SHOWING_TAP_UI
      */
     void startShowingTapUi();
 
     /**
-     * Waits to see if a Tap gesture will be made when a previous Tap was recognized.
-     * {@See
-     * ContextualSearchInternalStateController#InternalState#WAITING_FOR_POSSIBLE_TAP_NEAR_PREVIOUS}
+     * Waits to see if a Tap gesture will be made when the selection has been cleared, which allows
+     * a Tap near a previous Tap to be handled without a hide/show of the UI.
+     * @see
+     * ContextualSearchInternalStateController.InternalState#WAITING_FOR_POSSIBLE_TAP_NEAR_PREVIOUS
      */
     void waitForPossibleTapNearPrevious();
 
     /**
+     * Waits to see if a Tap gesture will be made on a previous Tap-selection when a Tap was
+     * recognized.
+     * @see ContextualSearchInternalStateController.InternalState#
+     * WAITING_FOR_POSSIBLE_TAP_ON_TAP_SELECTION
+     */
+    void waitForPossibleTapOnTapSelection();
+
+    /**
      * Starts a Resolve request to our server for the best Search Term.
-     * {@See ContextualSearchInternalStateController#InternalState#RESOLVING}.
+     * @see ContextualSearchInternalStateController.InternalState#RESOLVING
      */
     void resolveSearchTerm();
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
index 53e907b3..bddb157a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
@@ -94,6 +94,10 @@
     // timer).
     private static final int TAP_NEAR_PREVIOUS_DETECTION_DELAY_MS = 100;
 
+    // How long to wait for a Tap to be converted to a Long-press gesture when the user taps on
+    // an existing tap-selection.
+    private static final int TAP_ON_TAP_SELECTION_DELAY_MS = 100;
+
     private static final int NANOSECONDS_IN_A_MILLISECOND = 1000000;
 
     private final ObserverList<ContextualSearchObserver> mObservers =
@@ -778,7 +782,6 @@
 
         // Notify the UI of the caption.
         mSearchPanel.setCaption(caption);
-        System.out.println("ctxs checking mQuickAnswersHeuristic " + mQuickAnswersHeuristic);
         if (mQuickAnswersHeuristic != null) {
             mQuickAnswersHeuristic.setConditionSatisfied(true);
             mQuickAnswersHeuristic.setDoesAnswer(doesAnswer);
@@ -1519,6 +1522,26 @@
                 }, TAP_NEAR_PREVIOUS_DETECTION_DELAY_MS);
             }
 
+            /**
+             * Waits for possible Tap gesture that's on a previously established tap-selection.
+             * If the current Tap was on the previous tap-selection then this selection will become
+             * a Long-press selection and we'll recognize that gesture and start processing it.
+             * If that doesn't happen within our time window (which is the common case) then we'll
+             * advance to the next state in normal Tap processing.
+             */
+            @Override
+            public void waitForPossibleTapOnTapSelection() {
+                mInternalStateController.notifyStartingWorkOn(
+                        InternalState.WAITING_FOR_POSSIBLE_TAP_ON_TAP_SELECTION);
+                new Handler().postDelayed(new Runnable() {
+                    @Override
+                    public void run() {
+                        mInternalStateController.notifyFinishedWorkOn(
+                                InternalState.WAITING_FOR_POSSIBLE_TAP_ON_TAP_SELECTION);
+                    }
+                }, TAP_ON_TAP_SELECTION_DELAY_MS);
+            }
+
             /** Starts a Resolve request to our server for the best Search Term. */
             @Override
             public void resolveSearchTerm() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUma.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUma.java
index 589c9767..a49e129 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUma.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUma.java
@@ -844,6 +844,21 @@
     }
 
     /**
+     * Log whether results were seen due to a Tap on what we've recognized as a probable entity.
+     * @param wasSearchContentViewSeen If the panel was opened.
+     * @param isWordAnEntity Whether this tap was on a word that's an entity.
+     */
+    public static void logTapOnEntitySeen(
+            boolean wasSearchContentViewSeen, boolean isWordAnEntity) {
+        if (isWordAnEntity) {
+            // We just record CTR of probable entity words.
+            RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchEntitySeen",
+                    wasSearchContentViewSeen ? RESULTS_SEEN : RESULTS_NOT_SEEN,
+                    RESULTS_SEEN_BOUNDARY);
+        }
+    }
+
+    /**
      * Logs whether results were seen and whether any tap suppression heuristics were satisfied.
      * @param wasSearchContentViewSeen If the panel was opened.
      * @param wasAnySuppressionHeuristicSatisfied Whether any of the implemented suppression
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/TapSuppressionHeuristics.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/TapSuppressionHeuristics.java
index c12da127..ab9358fc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/TapSuppressionHeuristics.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/TapSuppressionHeuristics.java
@@ -25,11 +25,11 @@
         mCtrSuppression = new CtrSuppression();
         mHeuristics.add(mCtrSuppression);
         mHeuristics.add(new RecentScrollTapSuppression(selectionController));
-        TapFarFromPreviousSuppression farFromPreviousHeuristic =
-                new TapFarFromPreviousSuppression(selectionController, previousTapState, x, y);
-        mHeuristics.add(farFromPreviousHeuristic);
+        mHeuristics.add(
+                new TapFarFromPreviousSuppression(selectionController, previousTapState, x, y));
         mHeuristics.add(new TapWordLengthSuppression(contextualSearchContext));
         mHeuristics.add(new TapWordEdgeSuppression(contextualSearchContext));
+        mHeuristics.add(new ContextualSearchEntityHeuristic(contextualSearchContext));
         mHeuristics.add(new NearTopTapSuppression(selectionController, y));
         mHeuristics.add(new BarOverlapTapSuppression(selectionController, y));
         // General Tap Suppression and Tap Twice.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/TapWordEdgeSuppression.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/TapWordEdgeSuppression.java
index 0e25b12e..9193134 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/TapWordEdgeSuppression.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/TapWordEdgeSuppression.java
@@ -60,15 +60,15 @@
      */
     private boolean isTapNearWordEdge(ContextualSearchContext contextualSearchContext) {
         // If setup failed, don't suppress.
-        String tappedWord = contextualSearchContext.getTappedWord();
-        int tapOffset = contextualSearchContext.getTappedWordOffset();
-        if (TextUtils.isEmpty(tappedWord) || tapOffset == INVALID_OFFSET) return false;
+        String wordTapped = contextualSearchContext.getWordTapped();
+        int tapOffset = contextualSearchContext.getTapOffsetWithinTappedWord();
+        if (TextUtils.isEmpty(wordTapped) || tapOffset == INVALID_OFFSET) return false;
 
         // If the word is long enough, suppress if the tap was near one end or the other.
-        boolean isInStartEdge = (double) tapOffset / tappedWord.length() < MIN_WORD_START_RATIO;
-        boolean isInEndEdge = (double) (tappedWord.length() - tapOffset) / tappedWord.length()
+        boolean isInStartEdge = (double) tapOffset / wordTapped.length() < MIN_WORD_START_RATIO;
+        boolean isInEndEdge = (double) (wordTapped.length() - tapOffset) / wordTapped.length()
                 < MIN_WORD_END_RATIO;
-        if (tappedWord.length() >= MIN_WORD_LENGTH && (isInStartEdge || isInEndEdge)) return true;
+        if (wordTapped.length() >= MIN_WORD_LENGTH && (isInStartEdge || isInEndEdge)) return true;
 
         return false;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/TapWordLengthSuppression.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/TapWordLengthSuppression.java
index 11a039d..c1d661e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/TapWordLengthSuppression.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/TapWordLengthSuppression.java
@@ -69,7 +69,7 @@
     private boolean isTapOnWordLongerThan(
             int maxWordLength, ContextualSearchContext contextualSearchContext) {
         // If setup failed, don't suppress.
-        String tappedWord = contextualSearchContext.getTappedWord();
-        return !TextUtils.isEmpty(tappedWord) && tappedWord.length() > maxWordLength;
+        String wordTapped = contextualSearchContext.getWordTapped();
+        return !TextUtils.isEmpty(wordTapped) && wordTapped.length() > maxWordLength;
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/feature_engagement_tracker/ScreenshotMonitor.java b/chrome/android/java/src/org/chromium/chrome/browser/feature_engagement_tracker/ScreenshotMonitor.java
new file mode 100644
index 0000000..3525656
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/feature_engagement_tracker/ScreenshotMonitor.java
@@ -0,0 +1,114 @@
+// 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.
+
+package org.chromium.chrome.browser.feature_engagement_tracker;
+
+import android.os.Environment;
+import android.os.FileObserver;
+import android.os.StrictMode;
+
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.VisibleForTesting;
+
+import java.io.File;
+
+/**
+ * This class detects screenshots by monitoring the screenshots directory on the sdcard and notifies
+ * the ScreenshotMonitorDelegate. The caller should use
+ * @{link ScreenshotMonitor#create(ScreenshotMonitorDelegate)} to create an instance.
+ */
+public class ScreenshotMonitor {
+    private final ScreenshotMonitorDelegate mDelegate;
+
+    @VisibleForTesting
+    final ScreenshotMonitorFileObserver mFileObserver;
+    /**
+     * This tracks whether monitoring is on (i.e. started but not stopped). It must only be accessed
+     * on the UI thread.
+     */
+    private boolean mIsMonitoring;
+
+    /**
+     * This class requires the caller (ScreenshotMonitor) to call
+     * @{link ScreenshotMonitorFileObserver#setScreenshotMonitor(ScreenshotMonitor)} after
+     * instantiation of the class.
+     */
+    @VisibleForTesting
+    static class ScreenshotMonitorFileObserver extends FileObserver {
+        // TODO(angelashao): Generate screenshot directory path based on device (crbug/734220).
+        @VisibleForTesting
+        static String getDirPath() {
+            String path;
+            StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+            try {
+                path = Environment.getExternalStorageDirectory().getPath();
+            } finally {
+                StrictMode.setThreadPolicy(oldPolicy);
+            }
+            return path + File.separator + Environment.DIRECTORY_PICTURES + File.separator
+                    + "Screenshots";
+        }
+
+        // This can only be accessed on the UI thread.
+        private ScreenshotMonitor mScreenshotMonitor;
+
+        public ScreenshotMonitorFileObserver() {
+            super(getDirPath(), FileObserver.CREATE);
+        }
+
+        public void setScreenshotMonitor(ScreenshotMonitor monitor) {
+            ThreadUtils.assertOnUiThread();
+            mScreenshotMonitor = monitor;
+        }
+
+        @Override
+        public void onEvent(final int event, final String path) {
+            ThreadUtils.postOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    if (mScreenshotMonitor == null) return;
+                    mScreenshotMonitor.onEventOnUiThread(event, path);
+                }
+            });
+        }
+    }
+
+    @VisibleForTesting
+    ScreenshotMonitor(
+            ScreenshotMonitorDelegate delegate, ScreenshotMonitorFileObserver fileObserver) {
+        mDelegate = delegate;
+        mFileObserver = fileObserver;
+        mFileObserver.setScreenshotMonitor(this);
+    }
+
+    public static ScreenshotMonitor create(ScreenshotMonitorDelegate delegate) {
+        return new ScreenshotMonitor(delegate, new ScreenshotMonitorFileObserver());
+    }
+
+    /**
+     * Start monitoring the screenshot directory.
+     */
+    public void startMonitoring() {
+        ThreadUtils.assertOnUiThread();
+        mFileObserver.startWatching();
+        mIsMonitoring = true;
+    }
+
+    /**
+     * Stop monitoring the screenshot directory.
+     */
+    public void stopMonitoring() {
+        ThreadUtils.assertOnUiThread();
+        mFileObserver.stopWatching();
+        mIsMonitoring = false;
+    }
+
+    private void onEventOnUiThread(final int event, final String path) {
+        if (!mIsMonitoring) return;
+        if (path == null) return;
+        assert event == FileObserver.CREATE;
+
+        mDelegate.onScreenshotTaken();
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/feature_engagement_tracker/ScreenshotMonitorDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/feature_engagement_tracker/ScreenshotMonitorDelegate.java
new file mode 100644
index 0000000..c8432c0
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/feature_engagement_tracker/ScreenshotMonitorDelegate.java
@@ -0,0 +1,10 @@
+// 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.
+
+package org.chromium.chrome.browser.feature_engagement_tracker;
+
+/**
+ * This class serves as a callback from ScreenshotMonitor.
+ */
+public interface ScreenshotMonitorDelegate { void onScreenshotTaken(); }
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateCompactInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateCompactInfoBar.java
index 1dc3f01..3588891 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateCompactInfoBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateCompactInfoBar.java
@@ -103,6 +103,8 @@
     private TranslateMenuHelper mLanguageMenuHelper;
     private TintedImageButton mMenuButton;
 
+    private TranslateSnackbarController mSnackbarController;
+
     private boolean mMenuExpanded;
     private boolean mIsFirstLayout = true;
     private boolean mUserInteracted;
@@ -117,11 +119,13 @@
 
         @Override
         public void onDismissNoAction(Object actionData) {
+            mSnackbarController = null;
             handleTranslateOptionPostSnackbar(mActionId);
         }
 
         @Override
         public void onAction(Object actionData) {
+            mSnackbarController = null;
             switch (mActionId) {
                 case ACTION_OVERFLOW_ALWAYS_TRANSLATE:
                     recordInfobarAction(INFOBAR_SNACKBAR_CANCEL_ALWAYS);
@@ -433,8 +437,9 @@
     @Override
     protected void onStartedHiding() {
         dismissMenus();
-        if (getSnackbarManager() != null) getSnackbarManager().dismissAllSnackbars();
-        super.onStartedHiding();
+        if (getSnackbarManager() != null && mSnackbarController != null) {
+            getSnackbarManager().dismissSnackbars(mSnackbarController);
+        }
     }
 
     /**
@@ -479,9 +484,9 @@
                 assert false : "Unsupported Menu Item Id, to show snackbar.";
         }
 
+        mSnackbarController = new TranslateSnackbarController(actionId);
         getSnackbarManager().showSnackbar(
-                Snackbar.make(title, new TranslateSnackbarController(actionId),
-                                Snackbar.TYPE_NOTIFICATION, umaType)
+                Snackbar.make(title, mSnackbarController, Snackbar.TYPE_NOTIFICATION, umaType)
                         .setSingleLine(false)
                         .setAction(
                                 getContext().getString(R.string.translate_snackbar_cancel), null));
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/metrics/WebApkUma.java b/chrome/android/java/src/org/chromium/chrome/browser/metrics/WebApkUma.java
index 75850a2..4a3a0423 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/metrics/WebApkUma.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/metrics/WebApkUma.java
@@ -132,4 +132,13 @@
                 : "WebApk.ShellApkVersion.UnboundApk";
         RecordHistogram.recordSparseSlowlyHistogram(name, shellApkVersion);
     }
+
+    /**
+     * Recorded when a WebAPK is launched from the homescreen. Records the time elapsed since the
+     * previous WebAPK launch. Not recorded the first time that a WebAPK is launched.
+     */
+    public static void recordLaunchInterval(long intervalMs) {
+        RecordHistogram.recordCustomTimesHistogram("WebApk.LaunchInterval", intervalMs,
+                TimeUnit.HOURS.toMillis(1), TimeUnit.DAYS.toMillis(30), TimeUnit.MILLISECONDS, 50);
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/ChromeHomeIncognitoNewTabPage.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/ChromeHomeIncognitoNewTabPage.java
deleted file mode 100644
index 55f379e..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/ChromeHomeIncognitoNewTabPage.java
+++ /dev/null
@@ -1,64 +0,0 @@
-// 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.
-
-package org.chromium.chrome.browser.ntp;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.support.annotation.Nullable;
-import android.view.LayoutInflater;
-import android.view.View;
-
-import org.chromium.base.ApiCompatibilityUtils;
-import org.chromium.chrome.R;
-import org.chromium.chrome.browser.compositor.layouts.LayoutManagerChrome;
-import org.chromium.chrome.browser.tab.Tab;
-import org.chromium.chrome.browser.tabmodel.TabModelSelector;
-
-/**
- * The incognito new tab page to display when Chrome Home is enabled.
- */
-public class ChromeHomeIncognitoNewTabPage extends ChromeHomeNewTabPageBase {
-    private final View mView;
-    private final int mBackgroundColor;
-    private final int mThemeColor;
-
-    /**
-     * Constructs a ChromeHomeIncognitoNewTabPage.
-     * @param context The context used to inflate the view.
-     * @param tab The {@link Tab} that is showing this new tab page.
-     * @param tabModelSelector The {@link TabModelSelector} used to open tabs.
-     * @param layoutManager The {@link LayoutManagerChrome} used to observe overview mode changes.
-     *                      This may be null if the NTP is created on startup due to
-     *                      PartnerBrowserCustomizations.
-     */
-    public ChromeHomeIncognitoNewTabPage(final Context context, final Tab tab,
-            final TabModelSelector tabModelSelector,
-            @Nullable final LayoutManagerChrome layoutManager) {
-        super(context, tab, tabModelSelector, layoutManager);
-
-        mView = LayoutInflater.from(context).inflate(
-                R.layout.chrome_home_incognito_new_tab_page, null);
-        initializeCloseButton(mView.findViewById(R.id.close_button));
-
-        Resources res = context.getResources();
-        mBackgroundColor = ApiCompatibilityUtils.getColor(res, R.color.ntp_bg_incognito);
-        mThemeColor = ApiCompatibilityUtils.getColor(res, R.color.incognito_primary_color);
-    }
-
-    @Override
-    public View getView() {
-        return mView;
-    }
-
-    @Override
-    public int getBackgroundColor() {
-        return mBackgroundColor;
-    }
-
-    @Override
-    public int getThemeColor() {
-        return mThemeColor;
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/ChromeHomeNewTabPage.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/ChromeHomeNewTabPage.java
deleted file mode 100644
index d31f9617..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/ChromeHomeNewTabPage.java
+++ /dev/null
@@ -1,120 +0,0 @@
-// 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.
-
-package org.chromium.chrome.browser.ntp;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.support.annotation.Nullable;
-import android.view.LayoutInflater;
-import android.view.View;
-
-import org.chromium.base.ApiCompatibilityUtils;
-import org.chromium.chrome.R;
-import org.chromium.chrome.browser.compositor.layouts.LayoutManagerChrome;
-import org.chromium.chrome.browser.ntp.LogoBridge.Logo;
-import org.chromium.chrome.browser.ntp.LogoBridge.LogoObserver;
-import org.chromium.chrome.browser.search_engines.TemplateUrlService;
-import org.chromium.chrome.browser.search_engines.TemplateUrlService.TemplateUrlServiceObserver;
-import org.chromium.chrome.browser.tab.Tab;
-import org.chromium.chrome.browser.tabmodel.TabModelSelector;
-
-/**
- * The new tab page to display when Chrome Home is enabled.
- */
-public class ChromeHomeNewTabPage
-        extends ChromeHomeNewTabPageBase implements TemplateUrlServiceObserver {
-    private final LogoDelegateImpl mLogoDelegate;
-
-    private final View mView;
-    private final LogoView mLogoView;
-
-    private final int mBackgroundColor;
-    private final int mThemeColor;
-
-    /**
-     * Constructs a ChromeHomeNewTabPage.
-     * @param context The context used to inflate the view.
-     * @param tab The {@link Tab} that is showing this new tab page.
-     * @param tabModelSelector The {@link TabModelSelector} used to open tabs.
-     * @param layoutManager The {@link LayoutManagerChrome} used to observe overview mode changes.
-     *                      This may be null if the NTP is created on startup due to
-     *                      PartnerBrowserCustomizations.
-     */
-    public ChromeHomeNewTabPage(final Context context, final Tab tab,
-            final TabModelSelector tabModelSelector,
-            @Nullable final LayoutManagerChrome layoutManager) {
-        super(context, tab, tabModelSelector, layoutManager);
-
-        mView = LayoutInflater.from(context).inflate(R.layout.chrome_home_new_tab_page, null);
-        mLogoView = (LogoView) mView.findViewById(R.id.search_provider_logo);
-        initializeCloseButton(mView.findViewById(R.id.close_button));
-
-        Resources res = context.getResources();
-        mBackgroundColor = ApiCompatibilityUtils.getColor(res, R.color.ntp_bg);
-        mThemeColor = ApiCompatibilityUtils.getColor(res, R.color.default_primary_color);
-
-        mLogoDelegate = initializeLogoView();
-
-    }
-
-    @Override
-    public View getView() {
-        return mView;
-    }
-
-    @Override
-    public int getBackgroundColor() {
-        return mBackgroundColor;
-    }
-
-    @Override
-    public int getThemeColor() {
-        return mThemeColor;
-    }
-
-    @Override
-    public boolean needsToolbarShadow() {
-        return false;
-    }
-
-    @Override
-    public void updateForUrl(String url) {}
-
-    @Override
-    public void destroy() {
-        super.destroy();
-        mLogoDelegate.destroy();
-    }
-
-    private void updateSearchProviderLogoVisibility() {
-        boolean hasLogo = TemplateUrlService.getInstance().doesDefaultSearchEngineHaveLogo();
-        mLogoView.setVisibility(hasLogo ? View.VISIBLE : View.GONE);
-    }
-
-    private LogoDelegateImpl initializeLogoView() {
-        TemplateUrlService.getInstance().addObserver(this);
-
-        final LogoDelegateImpl logoDelegate = new LogoDelegateImpl(mTab, mLogoView);
-        logoDelegate.getSearchProviderLogo(new LogoObserver() {
-            @Override
-            public void onLogoAvailable(Logo logo, boolean fromCache) {
-                if (logo == null && fromCache) return;
-                mLogoView.setDelegate(logoDelegate);
-                mLogoView.updateLogo(logo);
-                // TODO(twellington): The new logo may be taller than the default logo. Adjust
-                //                    the view positioning.
-            }
-        });
-        updateSearchProviderLogoVisibility();
-        return logoDelegate;
-    }
-
-    // TemplateUrlServiceObserver overrides.
-
-    @Override
-    public void onTemplateURLServiceChanged() {
-        updateSearchProviderLogoVisibility();
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/ChromeHomeNewTabPageBase.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/ChromeHomeNewTabPageBase.java
deleted file mode 100644
index be47bd46..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/ChromeHomeNewTabPageBase.java
+++ /dev/null
@@ -1,211 +0,0 @@
-// 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.
-
-package org.chromium.chrome.browser.ntp;
-
-import android.content.Context;
-import android.support.annotation.CallSuper;
-import android.support.annotation.Nullable;
-import android.text.TextUtils;
-import android.view.View;
-import android.view.View.OnClickListener;
-
-import org.chromium.base.VisibleForTesting;
-import org.chromium.chrome.R;
-import org.chromium.chrome.browser.ChromeTabbedActivity;
-import org.chromium.chrome.browser.NativePage;
-import org.chromium.chrome.browser.UrlConstants;
-import org.chromium.chrome.browser.compositor.layouts.EmptyOverviewModeObserver;
-import org.chromium.chrome.browser.compositor.layouts.LayoutManagerChrome;
-import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior.OverviewModeObserver;
-import org.chromium.chrome.browser.tab.EmptyTabObserver;
-import org.chromium.chrome.browser.tab.Tab;
-import org.chromium.chrome.browser.tab.TabObserver;
-import org.chromium.chrome.browser.tabmodel.TabModelSelector;
-import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet;
-import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetMetrics;
-import org.chromium.content_public.browser.LoadUrlParams;
-
-/**
- * The base class for the new tab pages displayed in Chrome Home.
- */
-public abstract class ChromeHomeNewTabPageBase implements NativePage {
-    final Tab mTab;
-    final TabObserver mTabObserver;
-    final TabModelSelector mTabModelSelector;
-    final OverviewModeObserver mOverviewModeObserver;
-    @Nullable
-    final LayoutManagerChrome mLayoutManager;
-    BottomSheet mBottomSheet;
-    final String mTitle;
-
-    private boolean mShowOverviewOnClose;
-    private View mCloseButton;
-
-    /**
-     * Constructs a ChromeHomeNewTabPageBase.
-     * @param context The context used to inflate the view.
-     * @param tab The {@link Tab} that is showing this new tab page.
-     * @param tabModelSelector The {@link TabModelSelector} used to open tabs.
-     * @param layoutManager The {@link LayoutManagerChrome} used to observe overview mode changes.
-     *                      This may be null if the NTP is created on startup due to
-     *                      PartnerBrowserCustomizations.
-     */
-    public ChromeHomeNewTabPageBase(final Context context, final Tab tab,
-            final TabModelSelector tabModelSelector,
-            @Nullable final LayoutManagerChrome layoutManager) {
-        mTab = tab;
-        mTabModelSelector = tabModelSelector;
-        mLayoutManager = layoutManager;
-        mBottomSheet = mTab.getActivity().getBottomSheet();
-        mTitle = context.getResources().getString(R.string.button_new_tab);
-
-        // A new tab may be created on startup due to PartnerBrowserCustomizations before the
-        // LayoutManagerChrome has been created (see ChromeTabbedActivity#initializeState()).
-        if (mLayoutManager != null) {
-            mShowOverviewOnClose = mLayoutManager.overviewVisible();
-
-            // TODO(twellington): Long term we will not allow NTPs to remain open after the user
-            // navigates away from them. Remove this observer after that happens.
-            mOverviewModeObserver = new EmptyOverviewModeObserver() {
-                @Override
-                public void onOverviewModeFinishedHiding() {
-                    mShowOverviewOnClose = mTabModelSelector.getCurrentTab() == mTab;
-                }
-            };
-            mLayoutManager.addOverviewModeObserver(mOverviewModeObserver);
-        } else {
-            mOverviewModeObserver = null;
-        }
-
-        mTabObserver = new EmptyTabObserver() {
-            @Override
-            public void onShown(Tab tab) {
-                onNewTabPageShown();
-            }
-
-            @Override
-            public void onHidden(Tab tab) {
-                if (mTab.getActivity().getFadingBackgroundView() != null) {
-                    mTab.getActivity().getFadingBackgroundView().setEnabled(true);
-                }
-                if (!mTab.isClosing()) mShowOverviewOnClose = false;
-            }
-
-            @Override
-            public void onLoadUrl(Tab tab, LoadUrlParams params, int loadType) {
-                // If the NTP is loading, the sheet state will be set to SHEET_STATE_HALF.
-                if (TextUtils.equals(tab.getUrl(), getUrl())) return;
-
-                mBottomSheet = mTab.getActivity().getBottomSheet();
-                if (mBottomSheet != null) {
-                    mBottomSheet.getBottomSheetMetrics().setSheetCloseReason(
-                            BottomSheetMetrics.CLOSED_BY_NAVIGATION);
-                    mBottomSheet.setSheetState(BottomSheet.SHEET_STATE_PEEK, true);
-                }
-            }
-        };
-        mTab.addObserver(mTabObserver);
-
-        // If the tab is already showing TabObserver#onShown() won't be called, so we need to call
-        // #onNewTabPageShown() directly.
-        boolean tabAlreadyShowing = mTabModelSelector.getCurrentTab() == mTab;
-        if (tabAlreadyShowing) onNewTabPageShown();
-
-        if (mBottomSheet != null) {
-            mBottomSheet.setSheetState(BottomSheet.SHEET_STATE_HALF, true);
-            mBottomSheet.getBottomSheetMetrics().recordSheetOpenReason(
-                    BottomSheetMetrics.OPENED_BY_NEW_TAB_CREATION);
-        }
-
-        // TODO(twellington): disallow moving the NTP to the other window in Android N+
-        //                    multi-window mode.
-    }
-
-    @Override
-    public String getTitle() {
-        return mTitle;
-    }
-
-    @Override
-    public String getUrl() {
-        return UrlConstants.NTP_URL;
-    }
-
-    @Override
-    public String getHost() {
-        return UrlConstants.NTP_HOST;
-    }
-
-    @Override
-    public boolean needsToolbarShadow() {
-        return false;
-    }
-
-    @Override
-    public void updateForUrl(String url) {}
-
-    @Override
-    @CallSuper
-    public void destroy() {
-        // The next tab will be selected before this one is destroyed. If the currently selected
-        // tab is a Chrome Home new tab page, the FadingBackgroundView should not be enabled.
-        if (mTab.getActivity().getFadingBackgroundView() != null) {
-            mTab.getActivity().getFadingBackgroundView().setEnabled(
-                    !isTabChromeHomeNewTabPage(mTabModelSelector.getCurrentTab()));
-        }
-
-        if (mLayoutManager != null) {
-            mLayoutManager.removeOverviewModeObserver(mOverviewModeObserver);
-        }
-        mTab.removeObserver(mTabObserver);
-    }
-
-    private void onNewTabPageShown() {
-        if (mTab.getActivity().getFadingBackgroundView() != null) {
-            mTab.getActivity().getFadingBackgroundView().setEnabled(false);
-        }
-    }
-
-    private boolean isTabChromeHomeNewTabPage(Tab tab) {
-        return tab != null && tab.getUrl().equals(getUrl());
-    }
-
-    void initializeCloseButton(View closeButton) {
-        mCloseButton = closeButton;
-        mCloseButton.setOnClickListener(new OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                mBottomSheet = mTab.getActivity().getBottomSheet();
-                if (mBottomSheet != null) {
-                    mBottomSheet.getBottomSheetMetrics().setSheetCloseReason(
-                            BottomSheetMetrics.CLOSED_BY_NTP_CLOSE_BUTTON);
-                    mBottomSheet.setSheetState(BottomSheet.SHEET_STATE_PEEK, true);
-                }
-
-                if (mShowOverviewOnClose && getLayoutManager() != null) {
-                    getLayoutManager().showOverview(false);
-                }
-
-                // Close the tab after showing the overview mode so the bottom sheet doesn't open
-                // if another NTP is selected when this one is closed.
-                // TODO(twellington): remove this comment after only one NTP may be open at a time.
-                mTabModelSelector.closeTab(mTab);
-            }
-        });
-    }
-
-    private LayoutManagerChrome getLayoutManager() {
-        if (mLayoutManager != null) return mLayoutManager;
-
-        return ((ChromeTabbedActivity) mTab.getActivity()).getLayoutManager();
-    }
-
-    // Methods for testing.
-
-    @VisibleForTesting
-    public View getCloseButtonForTests() {
-        return mCloseButton;
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NativePageFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NativePageFactory.java
index c423cab..ac108f9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NativePageFactory.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NativePageFactory.java
@@ -10,7 +10,6 @@
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.ChromeFeatureList;
-import org.chromium.chrome.browser.ChromeTabbedActivity;
 import org.chromium.chrome.browser.NativePage;
 import org.chromium.chrome.browser.NativePageHost;
 import org.chromium.chrome.browser.TabLoadStatus;
@@ -22,7 +21,8 @@
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
-import org.chromium.chrome.browser.util.FeatureUtilities;
+import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet;
+import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetMetrics;
 import org.chromium.content_public.browser.LoadUrlParams;
 
 /**
@@ -35,14 +35,13 @@
     static class NativePageBuilder {
         protected NativePage buildNewTabPage(ChromeActivity activity, Tab tab,
                 TabModelSelector tabModelSelector) {
-            if (FeatureUtilities.isChromeHomeEnabled()) {
-                if (tab.isIncognito()) {
-                    return new ChromeHomeIncognitoNewTabPage(activity, tab, tabModelSelector,
-                            ((ChromeTabbedActivity) activity).getLayoutManager());
-                } else {
-                    return new ChromeHomeNewTabPage(activity, tab, tabModelSelector,
-                            ((ChromeTabbedActivity) activity).getLayoutManager());
-                }
+            if (activity.getBottomSheet() != null) {
+                BottomSheet sheet = activity.getBottomSheet();
+                sheet.getBottomSheetMetrics().recordNativeNewTabPageShown();
+                sheet.getBottomSheetMetrics().recordSheetOpenReason(
+                        BottomSheetMetrics.OPENED_BY_NEW_TAB_CREATION);
+                sheet.setSheetState(BottomSheet.SHEET_STATE_FULL, true);
+                return null;
             } else if (tab.isIncognito()) {
                 return new IncognitoNewTabPage(activity);
             } else {
@@ -164,7 +163,7 @@
                 assert false;
                 return null;
         }
-        page.updateForUrl(url);
+        if (page != null) page.updateForUrl(url);
         return page;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java
index 9e859e6..0eab84b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java
@@ -22,6 +22,7 @@
 import org.chromium.chrome.browser.suggestions.SuggestionsUiDelegate;
 import org.chromium.chrome.browser.suggestions.TileGrid;
 import org.chromium.chrome.browser.suggestions.TileGroup;
+import org.chromium.chrome.browser.util.FeatureUtilities;
 import org.chromium.chrome.browser.widget.displaystyle.UiConfig;
 
 import java.util.List;
@@ -182,7 +183,7 @@
 
     /** Resets suggestions, pulling the current state as known by the backend. */
     public void refreshSuggestions() {
-        if (ChromeFeatureList.isEnabled(ChromeFeatureList.CHROME_HOME)) {
+        if (FeatureUtilities.isChromeHomeEnabled()) {
             mSections.synchroniseWithSource();
         } else {
             mSections.refreshSuggestions();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SectionList.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SectionList.java
index 773e7a67..ccd6938 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SectionList.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SectionList.java
@@ -6,7 +6,6 @@
 
 import org.chromium.base.Log;
 import org.chromium.base.VisibleForTesting;
-import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.ntp.snippets.CategoryInt;
 import org.chromium.chrome.browser.ntp.snippets.CategoryStatus;
 import org.chromium.chrome.browser.ntp.snippets.KnownCategories;
@@ -17,6 +16,7 @@
 import org.chromium.chrome.browser.suggestions.DestructionObserver;
 import org.chromium.chrome.browser.suggestions.SuggestionsRanker;
 import org.chromium.chrome.browser.suggestions.SuggestionsUiDelegate;
+import org.chromium.chrome.browser.util.FeatureUtilities;
 
 import java.util.Arrays;
 import java.util.HashSet;
@@ -189,7 +189,7 @@
 
     @Override
     public boolean isResetAllowed() {
-        if (!ChromeFeatureList.isEnabled(ChromeFeatureList.CHROME_HOME)) return false;
+        if (!FeatureUtilities.isChromeHomeEnabled()) return false;
 
         // TODO(dgn): Also check if the bottom sheet is closed and how long since it has been closed
         // or opened, so that we don't refresh content while the user still cares about it.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditText.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditText.java
index ce6e3eea5..1edaf88d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditText.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditText.java
@@ -33,9 +33,9 @@
 
     private final AccessibilityManager mAccessibilityManager;
 
-    // This contains most of the logic. Lazily initialized in ensureModel() because View constructor
-    // may call its methods, so always call ensureModel() before accessing it.
     private AutocompleteEditTextModelBase mModel;
+    private boolean mIgnoreTextChangesForAutocomplete = true;
+    private boolean mLastEditWasPaste;
 
     /**
      * Whether default TextView scrolling should be disabled because autocomplete has been added.
@@ -52,9 +52,18 @@
     }
 
     private void ensureModel() {
-        // Lazy initialization here to ensure that model methods get called even in View's
-        // constructor.
-        if (mModel == null) mModel = new AutocompleteEditTextModel(this);
+        if (mModel == null) {
+            mModel = new AutocompleteEditTextModel(this);
+            // Feed initial values.
+            mModel.setIgnoreTextChangeFromAutocomplete(true);
+            mModel.onFocusChanged(hasFocus());
+            mModel.onSetText(getText());
+            mModel.onTextChanged(getText(), 0, 0, getText().length());
+            mModel.onSelectionChanged(getSelectionStart(), getSelectionEnd());
+            if (mLastEditWasPaste) mModel.onPaste();
+            mModel.setIgnoreTextChangeFromAutocomplete(false);
+            mModel.setIgnoreTextChangeFromAutocomplete(mIgnoreTextChangesForAutocomplete);
+        }
     }
 
     /**
@@ -64,28 +73,28 @@
      *                           triggered.
      */
     public void setIgnoreTextChangesForAutocomplete(boolean ignoreAutocomplete) {
-        ensureModel();
-        mModel.setIgnoreTextChangeFromAutocomplete(ignoreAutocomplete);
+        mIgnoreTextChangesForAutocomplete = ignoreAutocomplete;
+        if (mModel != null) mModel.setIgnoreTextChangeFromAutocomplete(ignoreAutocomplete);
     }
 
     /**
      * @return The user text without the autocomplete text.
      */
     public String getTextWithoutAutocomplete() {
-        ensureModel();
+        if (mModel == null) return "";
         return mModel.getTextWithoutAutocomplete();
     }
 
     /** @return Text that includes autocomplete. */
     public String getTextWithAutocomplete() {
-        ensureModel();
+        if (mModel == null) return "";
         return mModel.getTextWithAutocomplete();
     }
 
     /** @return Whether any autocomplete information is specified on the current text. */
     @VisibleForTesting
     public boolean hasAutocomplete() {
-        ensureModel();
+        if (mModel == null) return false;
         return mModel.hasAutocomplete();
     }
 
@@ -96,21 +105,19 @@
      * @return Whether we want to be showing inline autocomplete results.
      */
     public boolean shouldAutocomplete() {
-        ensureModel();
+        if (mModel == null) return false;
         return mModel.shouldAutocomplete();
     }
 
     @Override
     protected void onSelectionChanged(int selStart, int selEnd) {
-        ensureModel();
-        mModel.onSelectionChanged(selStart, selEnd);
+        if (mModel != null) mModel.onSelectionChanged(selStart, selEnd);
         super.onSelectionChanged(selStart, selEnd);
     }
 
     @Override
     protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
-        ensureModel();
-        mModel.onFocusChanged(focused);
+        if (mModel != null) mModel.onFocusChanged(focused);
         super.onFocusChanged(focused, direction, previouslyFocusedRect);
     }
 
@@ -136,8 +143,8 @@
 
     /** Call this when text is pasted. */
     public void onPaste() {
-        ensureModel();
-        mModel.onPaste();
+        mLastEditWasPaste = true;
+        if (mModel != null) mModel.onPaste();
     }
 
     /**
@@ -149,8 +156,7 @@
     public void setAutocompleteText(CharSequence userText, CharSequence inlineAutocompleteText) {
         boolean emptyAutocomplete = TextUtils.isEmpty(inlineAutocompleteText);
         if (!emptyAutocomplete) mDisableTextScrollingFromAutocomplete = true;
-        ensureModel();
-        mModel.setAutocompleteText(userText, inlineAutocompleteText);
+        if (mModel != null) mModel.setAutocompleteText(userText, inlineAutocompleteText);
     }
 
     /**
@@ -158,15 +164,15 @@
      * currently displayed.
      */
     public int getAutocompleteLength() {
-        ensureModel();
+        if (mModel == null) return 0;
         return mModel.getAutocompleteText().length();
     }
 
     @Override
     protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
         super.onTextChanged(text, start, lengthBefore, lengthAfter);
-        ensureModel();
-        mModel.onTextChanged(text, start, lengthBefore, lengthAfter);
+        mLastEditWasPaste = false;
+        if (mModel != null) mModel.onTextChanged(text, start, lengthBefore, lengthAfter);
     }
 
     @Override
@@ -187,14 +193,12 @@
                 StrictMode.setThreadPolicy(oldPolicy);
             }
         }
-        ensureModel();
-        mModel.onSetText(text);
+        if (mModel != null) mModel.onSetText(text);
     }
 
     @Override
     public void sendAccessibilityEventUnchecked(AccessibilityEvent event) {
-        ensureModel();
-        if (mModel.shouldIgnoreTextChangeFromAutocomplete()) {
+        if (mIgnoreTextChangesForAutocomplete) {
             if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED
                     || event.getEventType() == AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED) {
                 if (DEBUG) Log.i(TAG, "Ignoring accessibility event from autocomplete.");
@@ -218,7 +222,7 @@
 
     @VisibleForTesting
     public InputConnection getInputConnection() {
-        ensureModel();
+        if (mModel == null) return null;
         return mModel.getInputConnection();
     }
 
@@ -234,6 +238,11 @@
 
     @VisibleForTesting
     public InputConnection createInputConnection(InputConnection target) {
+        // Initially, target is null until View gets the focus.
+        if (target == null && mModel == null) {
+            if (DEBUG) Log.i(TAG, "createInputConnection - ignoring null target.");
+            return null;
+        }
         ensureModel();
         InputConnection retVal = mModel.onCreateInputConnection(target);
         if (mIgnoreImeForTest) return null;
@@ -249,9 +258,8 @@
     /**
      * @return Whether the current UrlBar input has been pasted from the clipboard.
      */
-    public boolean isPastedText() {
-        ensureModel();
-        return mModel.isPastedText();
+    public boolean wasLastEditPaste() {
+        return mLastEditWasPaste;
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditTextModel.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditTextModel.java
index 23b5fb8c..2c669ac 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditTextModel.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditTextModel.java
@@ -35,9 +35,10 @@
     private boolean mIgnoreTextChangeFromAutocomplete = true;
 
     private boolean mLastEditWasDelete;
-    private boolean mIsPastedText;
+    private boolean mLastEditWasPaste;
 
     public AutocompleteEditTextModel(AutocompleteEditTextModel.Delegate delegate) {
+        if (DEBUG) Log.i(TAG, "constructor");
         mDelegate = delegate;
         mAutocompleteSpan = new AutocompleteSpan();
     }
@@ -92,7 +93,7 @@
     public boolean shouldAutocomplete() {
         if (mLastEditWasDelete) return false;
         Editable text = mDelegate.getText();
-        return isCursorAtEndOfTypedText() && !isPastedText() && mBatchEditNestCount == 0
+        return isCursorAtEndOfTypedText() && !mLastEditWasPaste && mBatchEditNestCount == 0
                 && BaseInputConnection.getComposingSpanEnd(text)
                 == BaseInputConnection.getComposingSpanStart(text);
     }
@@ -251,7 +252,7 @@
         } else {
             mTextDeletedInBatchMode = textDeleted;
         }
-        mIsPastedText = false;
+        mLastEditWasPaste = false;
     }
 
     @Override
@@ -432,19 +433,9 @@
     }
 
     @Override
-    public boolean shouldIgnoreTextChangeFromAutocomplete() {
-        return mIgnoreTextChangeFromAutocomplete;
-    }
-
-    @Override
     public void onPaste() {
         if (DEBUG) Log.i(TAG, "onPaste");
-        mIsPastedText = true;
-    }
-
-    @Override
-    public boolean isPastedText() {
-        return mIsPastedText;
+        mLastEditWasPaste = true;
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditTextModelBase.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditTextModelBase.java
index 674300d5..3e2ed62 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditTextModelBase.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditTextModelBase.java
@@ -92,11 +92,6 @@
     void onPaste();
 
     /**
-     * @return Whether or not the user just pasted text.
-     */
-    boolean isPastedText();
-
-    /**
      * @return The whole text including both user text and autocomplete text.
      */
     String getTextWithAutocomplete();
@@ -118,9 +113,6 @@
      */
     void setIgnoreTextChangeFromAutocomplete(boolean ignore);
 
-    /** @return Whether we should ignore text change from autocomplete. */
-    boolean shouldIgnoreTextChangeFromAutocomplete();
-
     /**
      * Autocompletes the text and selects the text that was not entered by the user. Using append()
      * instead of setText() to preserve the soft-keyboard layout.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
index 20f0722..b1becb8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
@@ -412,8 +412,9 @@
             // omnibox results. There is one special case where the suggestion text was pasted,
             // where we want the transition type to be LINK.
             int transition = suggestionMatch.getType() == OmniboxSuggestionType.URL_WHAT_YOU_TYPED
-                    && mUrlBar.isPastedText() ? PageTransition.LINK
-                            : suggestionMatch.getTransition();
+                            && mUrlBar.wasLastEditPaste()
+                    ? PageTransition.LINK
+                    : suggestionMatch.getTransition();
 
             loadUrlFromOmniboxMatch(suggestionMatchUrl, transition, suggestionMatchPosition,
                     suggestionMatch.getType());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/MostVisitedSitesBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/MostVisitedSitesBridge.java
index ad5ff12..0d0fe2c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/MostVisitedSitesBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/MostVisitedSitesBridge.java
@@ -6,10 +6,10 @@
 
 import org.chromium.base.ContextUtils;
 import org.chromium.base.annotations.JNIAdditionalImport;
-import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.ntp.NewTabPage;
 import org.chromium.chrome.browser.partnercustomizations.HomepageManager;
 import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.util.FeatureUtilities;
 
 /**
  * Methods to bridge into native history to provide most recent urls, titles and thumbnails.
@@ -28,7 +28,7 @@
         mNativeMostVisitedSitesBridge = nativeInit(profile);
         // The first tile replaces the home page button (only) in Chrome Home. To support that,
         // provide information about the home page.
-        if (ChromeFeatureList.isEnabled(ChromeFeatureList.CHROME_HOME)) {
+        if (FeatureUtilities.isChromeHomeEnabled()) {
             nativeSetHomePageClient(mNativeMostVisitedSitesBridge, new HomePageClient() {
                 @Override
                 public boolean isHomePageEnabled() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabCreatorManager.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabCreatorManager.java
index 6257c64..cd0a7f2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabCreatorManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabCreatorManager.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser.tabmodel;
 
+import android.support.annotation.Nullable;
+
 import org.chromium.base.TraceEvent;
 import org.chromium.chrome.browser.TabState;
 import org.chromium.chrome.browser.UrlConstants;
@@ -33,8 +35,9 @@
          * @param loadUrlParams parameters of the url load.
          * @param type Information about how the tab was launched.
          * @param parent the parent tab, if present.
-         * @return The new tab.
+         * @return The new tab or null if no tab was created.
          */
+        @Nullable
         public abstract Tab createNewTab(
                 LoadUrlParams loadUrlParams, TabModel.TabLaunchType type, Tab parent);
 
@@ -54,8 +57,9 @@
          * @param url the URL to open.
          * @param type the type of action that triggered that launch. Determines how the tab is
          *             opened (for example, in the foreground or background).
-         * @return the created tab.
+         * @return The new tab or null if no tab was created.
          */
+        @Nullable
         public abstract Tab launchUrl(String url, TabModel.TabLaunchType type);
 
         /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java
index fbd11b8..6847e8f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java
@@ -604,6 +604,9 @@
             Log.w(TAG, "Failed to restore TabState; creating Tab with last known URL.");
             Tab fallbackTab = mTabCreatorManager.getTabCreator(isIncognito).createNewTab(
                     new LoadUrlParams(tabToRestore.url), TabModel.TabLaunchType.FROM_RESTORE, null);
+
+            if (fallbackTab == null) return;
+
             tabId = fallbackTab.getId();
             model.moveTab(tabId, restoredIndex);
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivity.java
index 51158cc..a7fc0d0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivity.java
@@ -272,6 +272,14 @@
         maybeShowDisclosure(storage);
     }
 
+    @Override
+    protected void onUpdatedLastUsedTime(
+            WebappDataStorage storage, boolean previouslyLaunched, long previousUsageTimestamp) {
+        if (previouslyLaunched) {
+            WebApkUma.recordLaunchInterval(storage.getLastUsedTime() - previousUsageTimestamp);
+        }
+    }
+
     /**
      * If we're showing a WebApk that's not with an expected package, it must be an
      * "Unbound WebApk" (crbug.com/714735) so show a notification that it's running in Chrome.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java
index aacdbf8a..5e7d270 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java
@@ -366,10 +366,23 @@
         // app is not directly launched from the home screen, as this interferes
         // with the heuristic.
         if (mWebappInfo.isLaunchedFromHomescreen()) {
+            boolean previouslyLaunched = storage.hasBeenLaunched();
+            long previousUsageTimestamp = storage.getLastUsedTime();
+            storage.setHasBeenLaunched();
             storage.updateLastUsedTime();
+            onUpdatedLastUsedTime(storage, previouslyLaunched, previousUsageTimestamp);
         }
     }
 
+    /**
+     * Called after updating the last used time in {@link WebappDataStorage}.
+     * @param previouslyLaunched Whether the webapp has been previously launched from the home
+     *     screen.
+     * @param previousUsageTimestamp The previous time that the webapp was used.
+     */
+    protected void onUpdatedLastUsedTime(
+            WebappDataStorage storage, boolean previouslyLaunched, long previousUsageTimestamp) {}
+
     private void updateUrlBar() {
         Tab tab = getActivityTab();
         if (tab == null || mUrlBar == null) return;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDataStorage.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDataStorage.java
index 9c85fda..650fcb7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDataStorage.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDataStorage.java
@@ -33,6 +33,7 @@
     static final String SHARED_PREFS_FILE_PREFIX = "webapp_";
     static final String KEY_SPLASH_ICON = "splash_icon";
     static final String KEY_LAST_USED = "last_used";
+    static final String KEY_HAS_BEEN_LAUNCHED = "has_been_launched";
     static final String KEY_URL = "url";
     static final String KEY_SCOPE = "scope";
     static final String KEY_ICON = "icon";
@@ -291,10 +292,12 @@
     }
 
     /**
-     * Returns true if this web app has been launched from home screen recently (within
-     * WEBAPP_LAST_OPEN_MAX_TIME milliseconds).
+     * Returns true if this web app recently (within WEBAPP_LAST_OPEN_MAX_TIME milliseconds) was
+     * either:
+     * - registered with WebappRegistry
+     * - launched from the homescreen
      */
-    public boolean wasLaunchedRecently() {
+    public boolean wasUsedRecently() {
         // WebappRegistry.register sets the last used time, so that counts as a 'launch'.
         return (sClock.currentTimeMillis() - getLastUsedTime() < WEBAPP_LAST_OPEN_MAX_TIME);
     }
@@ -315,6 +318,7 @@
         SharedPreferences.Editor editor = mPreferences.edit();
 
         editor.remove(KEY_LAST_USED);
+        editor.remove(KEY_HAS_BEEN_LAUNCHED);
         editor.remove(KEY_URL);
         editor.remove(KEY_SCOPE);
         editor.remove(KEY_LAST_CHECK_WEB_MANIFEST_UPDATE_TIME);
@@ -374,6 +378,16 @@
         mPreferences.edit().putLong(KEY_LAST_USED, sClock.currentTimeMillis()).apply();
     }
 
+    /** Returns true if the web app has been launched at least once from the home screen. */
+    boolean hasBeenLaunched() {
+        return mPreferences.getBoolean(KEY_HAS_BEEN_LAUNCHED, false);
+    }
+
+    /** Sets whether the web app was launched at least once from the home screen. */
+    void setHasBeenLaunched() {
+        mPreferences.edit().putBoolean(KEY_HAS_BEEN_LAUNCHED, true).apply();
+    }
+
     /**
      * Returns the package name if the data is for a WebAPK, null otherwise.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappRegistry.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappRegistry.java
index f55a895..36777a62 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappRegistry.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappRegistry.java
@@ -35,7 +35,7 @@
  * after it is created.
  *
  * This class is not a comprehensive list of installed web apps because it is impossible to know
- * when the user removes a web app from the home screen. The WebappDataStorage.wasLaunchedRecently()
+ * when the user removes a web app from the home screen. The WebappDataStorage.wasUsedRecently()
  * heuristic attempts to compensate for this.
  */
 public class WebappRegistry {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
index 570a7ae..1805022 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
@@ -42,6 +42,7 @@
 import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager;
 import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager.FullscreenListener;
 import org.chromium.chrome.browser.ntp.NativePageFactory;
+import org.chromium.chrome.browser.ntp.NewTabPage;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
@@ -55,6 +56,7 @@
 import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetContentController.ContentType;
 import org.chromium.chrome.browser.widget.textbubble.ViewAnchoredTextBubble;
 import org.chromium.content.browser.BrowserStartupController;
+import org.chromium.content.browser.ContentViewCore;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.ui.UiUtils;
 
@@ -752,6 +754,11 @@
 
     @Override
     public int loadUrl(LoadUrlParams params, boolean incognito) {
+        if (NewTabPage.isNTPUrl(params.getUrl())) {
+            displayNewTabUi(incognito);
+            return TabLoadStatus.PAGE_LOAD_FAILED;
+        }
+
         boolean isShowingNtp = isShowingNewTab();
         for (BottomSheetObserver o : mObservers) o.onLoadUrl(params.getUrl());
 
@@ -953,6 +960,7 @@
         if (mIsSheetOpen) return;
 
         mIsSheetOpen = true;
+        dismissSelectedText();
         for (BottomSheetObserver o : mObservers) o.onSheetOpened();
         announceForAccessibility(getResources().getString(R.string.bottom_sheet_opened));
         mActivity.addViewObscuringAllTabs(this);
@@ -1098,6 +1106,18 @@
     }
 
     /**
+     * Deselects any text in the active tab's web contents and dismisses the text controls.
+     */
+    private void dismissSelectedText() {
+        Tab activeTab = getActiveTab();
+        if (activeTab == null) return;
+
+        ContentViewCore contentViewCore = activeTab.getContentViewCore();
+        if (contentViewCore == null) return;
+        contentViewCore.clearSelection();
+    }
+
+    /**
      * This is the same as {@link #setSheetOffsetFromBottom(float)} but exclusively for testing.
      * @param offset The offset to set the sheet to.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetMetrics.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetMetrics.java
index 05e8a147b..9fb1154 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetMetrics.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetMetrics.java
@@ -33,12 +33,12 @@
     private static final int OPENED_BY_BOUNDARY = 4;
 
     /** The different ways that the bottom sheet can be closed. */
-    @IntDef({CLOSED_BY_NONE, CLOSED_BY_SWIPE, CLOSED_BY_NTP_CLOSE_BUTTON, CLOSED_BY_TAP_SCRIM,
+    @IntDef({CLOSED_BY_NONE, CLOSED_BY_SWIPE, CLOSED_BY_BACK_PRESS, CLOSED_BY_TAP_SCRIM,
             CLOSED_BY_NAVIGATION})
     public @interface SheetCloseReason {}
     private static final int CLOSED_BY_NONE = -1;
     public static final int CLOSED_BY_SWIPE = 0;
-    public static final int CLOSED_BY_NTP_CLOSE_BUTTON = 1;
+    public static final int CLOSED_BY_BACK_PRESS = 1;
     public static final int CLOSED_BY_TAP_SCRIM = 2;
     public static final int CLOSED_BY_NAVIGATION = 3;
 
@@ -176,8 +176,8 @@
             case CLOSED_BY_SWIPE:
                 RecordUserAction.record("Android.ChromeHome.ClosedBySwipe");
                 break;
-            case CLOSED_BY_NTP_CLOSE_BUTTON:
-                RecordUserAction.record("Android.ChromeHome.ClosedByNTPCloseButton");
+            case CLOSED_BY_BACK_PRESS:
+                RecordUserAction.record("Android.ChromeHome.ClosedByBackPress");
                 break;
             case CLOSED_BY_TAP_SCRIM:
                 RecordUserAction.record("Android.ChromeHome.ClosedByTapScrim");
@@ -192,4 +192,12 @@
                 assert false;
         }
     }
+
+    /**
+     * Records that a user navigation instructed the NativePageFactory to create a native page for
+     * the NTP. This may occur if the user has NTP URLs in a tab's navigation history.
+     */
+    public void recordNativeNewTabPageShown() {
+        RecordUserAction.record("Android.ChromeHome.NativeNTPShown");
+    }
 }
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 3b1bc49..48e8f351 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -235,6 +235,7 @@
   "java/src/org/chromium/chrome/browser/contextmenu/ShareContextMenuItem.java",
   "java/src/org/chromium/chrome/browser/contextualsearch/BarOverlapTapSuppression.java",
   "java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchContext.java",
+  "java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchEntityHeuristic.java",
   "java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java",
   "java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchHeuristic.java",
   "java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchHeuristics.java",
@@ -375,6 +376,8 @@
   "java/src/org/chromium/chrome/browser/favicon/FaviconHelper.java",
   "java/src/org/chromium/chrome/browser/favicon/LargeIconBridge.java",
   "java/src/org/chromium/chrome/browser/feature_engagement_tracker/FeatureEngagementTrackerFactory.java",
+  "java/src/org/chromium/chrome/browser/feature_engagement_tracker/ScreenshotMonitor.java",
+  "java/src/org/chromium/chrome/browser/feature_engagement_tracker/ScreenshotMonitorDelegate.java",
   "java/src/org/chromium/chrome/browser/feedback/ConnectivityChecker.java",
   "java/src/org/chromium/chrome/browser/feedback/ConnectivityTask.java",
   "java/src/org/chromium/chrome/browser/feedback/EmptyFeedbackReporter.java",
@@ -606,9 +609,6 @@
   "java/src/org/chromium/chrome/browser/notifications/channels/ChannelsInitializer.java",
   "java/src/org/chromium/chrome/browser/notifications/channels/ChannelsUpdater.java",
   "java/src/org/chromium/chrome/browser/notifications/channels/SiteChannelsManager.java",
-  "java/src/org/chromium/chrome/browser/ntp/ChromeHomeIncognitoNewTabPage.java",
-  "java/src/org/chromium/chrome/browser/ntp/ChromeHomeNewTabPage.java",
-  "java/src/org/chromium/chrome/browser/ntp/ChromeHomeNewTabPageBase.java",
   "java/src/org/chromium/chrome/browser/ntp/ContentSuggestionsNotificationHelper.java",
   "java/src/org/chromium/chrome/browser/ntp/ContextMenuManager.java",
   "java/src/org/chromium/chrome/browser/ntp/FakeRecentlyClosedTabManager.java",
@@ -1424,6 +1424,7 @@
   "javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java",
   "javatests/src/org/chromium/chrome/browser/externalnav/IntentWithGesturesHandlerTest.java",
   "javatests/src/org/chromium/chrome/browser/externalnav/UrlOverridingTest.java",
+  "javatests/src/org/chromium/chrome/browser/feature_engagement_tracker/ScreenshotMonitorTest.java",
   "javatests/src/org/chromium/chrome/browser/feedback/ConnectivityCheckerTest.java",
   "javatests/src/org/chromium/chrome/browser/feedback/ConnectivityCheckerTestRule.java",
   "javatests/src/org/chromium/chrome/browser/feedback/ConnectivityTaskTest.java",
@@ -1718,6 +1719,9 @@
   "junit/src/org/chromium/chrome/browser/browseractions/BrowserActionActivityTest.java",
   "junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java",
   "junit/src/org/chromium/chrome/browser/compositor/CompositorSurfaceManagerTest.java",
+  "junit/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchContextForTest.java",
+  "junit/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchContextTest.java",
+  "junit/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchEntityHeuristicTest.java",
   "junit/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchInternalStateTest.java",
   "junit/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionControllerTest.java",
   "junit/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulatorTest.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/feature_engagement_tracker/ScreenshotMonitorTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/feature_engagement_tracker/ScreenshotMonitorTest.java
new file mode 100644
index 0000000..68e8556
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/feature_engagement_tracker/ScreenshotMonitorTest.java
@@ -0,0 +1,348 @@
+// 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.
+
+package org.chromium.chrome.browser.feature_engagement_tracker;
+
+import android.os.FileObserver;
+import android.support.test.filters.SmallTest;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.Log;
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.test.util.Feature;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+
+import java.io.File;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+/**
+ * Tests ScreenshotMonitor.
+ */
+@RunWith(ChromeJUnit4ClassRunner.class)
+public class ScreenshotMonitorTest {
+    private static final String FILENAME = "image.jpeg";
+    private static final String TAG = "ScreenshotTest";
+
+    private ScreenshotMonitor mTestScreenshotMonitor;
+    private TestScreenshotMonitorDelegate mTestScreenshotMonitorDelegate;
+    private TestScreenshotMonitorFileObserver mTestFileObserver;
+
+    /**
+     * This class acts as the inner FileObserver used by TestScreenshotMonitor to test that
+     * ScreenshotMonitor calls the FileObserver.
+     */
+    static class TestScreenshotMonitorFileObserver
+            extends ScreenshotMonitor.ScreenshotMonitorFileObserver {
+        // The number of times concurrent watching occurs. It corresponds to the number of times
+        // startWatching() and stopWatching() are called. It is modified on the UI thread and
+        // accessed on the test thread.
+        public final AtomicInteger watchingCount = new AtomicInteger();
+
+        // Note: FileObserver's startWatching will have no effect if monitoring started already.
+        @Override
+        public void startWatching() {
+            watchingCount.getAndIncrement();
+        }
+
+        // Note: FileObserver's stopWatching will have no effect if monitoring stopped already.
+        @Override
+        public void stopWatching() {
+            watchingCount.getAndDecrement();
+        }
+    }
+
+    static class TestScreenshotMonitorDelegate implements ScreenshotMonitorDelegate {
+        // This is modified on the UI thread and accessed on the test thread.
+        public final AtomicInteger screenshotShowUiCount = new AtomicInteger();
+
+        public void onScreenshotTaken() {
+            Assert.assertTrue(ThreadUtils.runningOnUiThread());
+            screenshotShowUiCount.getAndIncrement();
+        }
+    }
+
+    static String getTestFilePath() {
+        return ScreenshotMonitor.ScreenshotMonitorFileObserver.getDirPath() + File.separator
+                + FILENAME;
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        mTestScreenshotMonitorDelegate = new TestScreenshotMonitorDelegate();
+
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                mTestScreenshotMonitor = new ScreenshotMonitor(
+                        mTestScreenshotMonitorDelegate, new TestScreenshotMonitorFileObserver());
+            }
+        });
+        Assert.assertTrue(
+                mTestScreenshotMonitor.mFileObserver instanceof TestScreenshotMonitorFileObserver);
+        mTestFileObserver =
+                (TestScreenshotMonitorFileObserver) mTestScreenshotMonitor.mFileObserver;
+    }
+
+    /**
+     * Verify that if monitoring starts, the delegate should be called. Also verify that the
+     * inner TestFileObserver monitors as expected.
+     */
+    @Test
+    @SmallTest
+    @Feature({"FeatureEngagementTracker", "Screenshot"})
+    public void testStartMonitoringShouldTriggerDelegate() throws Throwable {
+        Assert.assertEquals(0, mTestFileObserver.watchingCount.get());
+
+        startMonitoringOnUiThreadBlocking();
+        Assert.assertEquals(1, mTestFileObserver.watchingCount.get());
+        Assert.assertEquals(0, mTestScreenshotMonitorDelegate.screenshotShowUiCount.get());
+
+        mTestScreenshotMonitor.mFileObserver.onEvent(FileObserver.CREATE, getTestFilePath());
+        assertScreenshotShowUiCountOnUiThreadBlocking(1);
+
+        stopMonitoringOnUiThreadBlocking();
+        Assert.assertEquals(0, mTestFileObserver.watchingCount.get());
+    }
+
+    /**
+     * Verify that if monitoring starts multiple times, the delegate should still be called.
+     */
+    @Test
+    @SmallTest
+    @Feature({"FeatureEngagementTracker", "Screenshot"})
+    public void testMultipleStartMonitoringShouldTriggerDelegate() throws Throwable {
+        Assert.assertEquals(0, mTestFileObserver.watchingCount.get());
+
+        startMonitoringOnUiThreadBlocking();
+        startMonitoringOnUiThreadBlocking();
+        Assert.assertEquals(2, mTestFileObserver.watchingCount.get());
+
+        mTestScreenshotMonitor.mFileObserver.onEvent(FileObserver.CREATE, getTestFilePath());
+        assertScreenshotShowUiCountOnUiThreadBlocking(1);
+    }
+
+    /**
+     * Verify that if monitoring stops multiple times, the delegate should not be called.
+     */
+    @Test
+    @SmallTest
+    @Feature({"FeatureEngagementTracker", "Screenshot"})
+    public void testMultipleStopMonitoringShouldNotTriggerDelegate() throws Throwable {
+        Assert.assertEquals(0, mTestFileObserver.watchingCount.get());
+
+        stopMonitoringOnUiThreadBlocking();
+        stopMonitoringOnUiThreadBlocking();
+        Assert.assertEquals(-2, mTestFileObserver.watchingCount.get());
+
+        mTestScreenshotMonitor.mFileObserver.onEvent(FileObserver.CREATE, getTestFilePath());
+        assertScreenshotShowUiCountOnUiThreadBlocking(0);
+    }
+
+    /**
+     * Verify that even if startMonitoring is called multiple times before stopMonitoring, the
+     * delegate should not be called.
+     */
+    @Test
+    @SmallTest
+    @Feature({"FeatureEngagementTracker", "Screenshot"})
+    public void testMultipleStartMonitoringThenStopShouldNotTriggerDelegate() throws Throwable {
+        Assert.assertEquals(0, mTestFileObserver.watchingCount.get());
+        Assert.assertEquals(0, mTestScreenshotMonitorDelegate.screenshotShowUiCount.get());
+
+        multipleStartMonitoringBeforeStopMonitoringOnUiThreadBlocking(2);
+        Assert.assertEquals(1, mTestFileObserver.watchingCount.get());
+
+        mTestScreenshotMonitor.mFileObserver.onEvent(FileObserver.CREATE, getTestFilePath());
+        assertScreenshotShowUiCountOnUiThreadBlocking(0);
+    }
+
+    /**
+     * Verify that if stopMonitoring is called multiple times before startMonitoring, the delegate
+     * should still be called.
+     */
+    @Test
+    @SmallTest
+    @Feature({"FeatureEngagementTracker", "Screenshot"})
+    public void testMultipleStopMonitoringThenStartShouldTriggerDelegate() throws Throwable {
+        Assert.assertEquals(0, mTestFileObserver.watchingCount.get());
+
+        multipleStopMonitoringBeforeStartMonitoringOnUiThreadBlocking(2);
+        Assert.assertEquals(-1, mTestFileObserver.watchingCount.get());
+        Assert.assertEquals(0, mTestScreenshotMonitorDelegate.screenshotShowUiCount.get());
+
+        mTestScreenshotMonitor.mFileObserver.onEvent(FileObserver.CREATE, getTestFilePath());
+        assertScreenshotShowUiCountOnUiThreadBlocking(1);
+    }
+
+    /**
+     * Verify that the delegate is called after a restart.
+     */
+    @Test
+    @SmallTest
+    @Feature({"FeatureEngagementTracker", "Screenshot"})
+    public void testRestartShouldTriggerDelegate() throws Throwable {
+        Assert.assertEquals(0, mTestFileObserver.watchingCount.get());
+
+        startMonitoringOnUiThreadBlocking();
+        Assert.assertEquals(1, mTestFileObserver.watchingCount.get());
+        Assert.assertEquals(0, mTestScreenshotMonitorDelegate.screenshotShowUiCount.get());
+
+        mTestScreenshotMonitor.mFileObserver.onEvent(FileObserver.CREATE, getTestFilePath());
+        assertScreenshotShowUiCountOnUiThreadBlocking(1);
+
+        stopMonitoringOnUiThreadBlocking();
+        Assert.assertEquals(0, mTestFileObserver.watchingCount.get());
+
+        // Restart and call onEvent a second time
+        startMonitoringOnUiThreadBlocking();
+        Assert.assertEquals(1, mTestFileObserver.watchingCount.get());
+        Assert.assertEquals(1, mTestScreenshotMonitorDelegate.screenshotShowUiCount.get());
+
+        mTestScreenshotMonitor.mFileObserver.onEvent(FileObserver.CREATE, getTestFilePath());
+        assertScreenshotShowUiCountOnUiThreadBlocking(2);
+    }
+
+    /**
+     * Verify that if monitoring stops, the delegate should not be called.
+     */
+    @Test
+    @SmallTest
+    @Feature({"FeatureEngagementTracker", "Screenshot"})
+    public void testStopMonitoringShouldNotTriggerDelegate() throws Throwable {
+        Assert.assertEquals(0, mTestFileObserver.watchingCount.get());
+
+        startMonitoringOnUiThreadBlocking();
+        Assert.assertEquals(1, mTestFileObserver.watchingCount.get());
+        Assert.assertEquals(0, mTestScreenshotMonitorDelegate.screenshotShowUiCount.get());
+
+        stopMonitoringOnUiThreadBlocking();
+        Assert.assertEquals(0, mTestFileObserver.watchingCount.get());
+
+        mTestScreenshotMonitor.mFileObserver.onEvent(FileObserver.CREATE, getTestFilePath());
+        assertScreenshotShowUiCountOnUiThreadBlocking(0);
+    }
+
+    /**
+     * Verify that if monitoring is never started, the delegate should not be called.
+     */
+    @Test
+    @SmallTest
+    @Feature({"FeatureEngagementTracker", "Screenshot"})
+    public void testNoMonitoringShouldNotTriggerDelegate() throws Throwable {
+        Assert.assertEquals(0, mTestFileObserver.watchingCount.get());
+        Assert.assertEquals(0, mTestScreenshotMonitorDelegate.screenshotShowUiCount.get());
+
+        mTestScreenshotMonitor.mFileObserver.onEvent(FileObserver.CREATE, getTestFilePath());
+        assertScreenshotShowUiCountOnUiThreadBlocking(0);
+
+        Assert.assertEquals(0, mTestFileObserver.watchingCount.get());
+    }
+
+    // This ensures that the UI thread finishes executing startMonitoring.
+    private void startMonitoringOnUiThreadBlocking() {
+        final Semaphore semaphore = new Semaphore(0);
+
+        ThreadUtils.postOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mTestScreenshotMonitor.startMonitoring();
+                semaphore.release();
+            }
+        });
+        try {
+            Assert.assertTrue(semaphore.tryAcquire(10, TimeUnit.SECONDS));
+        } catch (InterruptedException e) {
+            Log.e(TAG, "Cannot acquire semaphore");
+        }
+    }
+
+    // This ensures that the UI thread finishes executing stopMonitoring.
+    private void stopMonitoringOnUiThreadBlocking() {
+        final Semaphore semaphore = new Semaphore(0);
+
+        ThreadUtils.postOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mTestScreenshotMonitor.stopMonitoring();
+                semaphore.release();
+            }
+        });
+        try {
+            Assert.assertTrue(semaphore.tryAcquire(10, TimeUnit.SECONDS));
+        } catch (InterruptedException e) {
+            Log.e(TAG, "Cannot acquire semaphore");
+        }
+    }
+
+    // This ensures that the UI thread finishes executing startCallCount calls to startMonitoring
+    // before calling stopMonitoring.
+    private void multipleStartMonitoringBeforeStopMonitoringOnUiThreadBlocking(
+            final int startCallCount) {
+        final Semaphore semaphore = new Semaphore(0);
+
+        ThreadUtils.postOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                for (int i = 0; i < startCallCount; i++) {
+                    mTestScreenshotMonitor.startMonitoring();
+                }
+                mTestScreenshotMonitor.stopMonitoring();
+                semaphore.release();
+            }
+        });
+        try {
+            Assert.assertTrue(semaphore.tryAcquire(10, TimeUnit.SECONDS));
+        } catch (InterruptedException e) {
+            Log.e(TAG, "Cannot acquire semaphore");
+        }
+    }
+
+    // This ensures that the UI thread finishes executing stopCallCount calls to stopMonitoring
+    // before calling startMonitoring.
+    private void multipleStopMonitoringBeforeStartMonitoringOnUiThreadBlocking(
+            final int stopCallCount) {
+        final Semaphore semaphore = new Semaphore(0);
+
+        ThreadUtils.postOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                for (int i = 0; i < stopCallCount; i++) {
+                    mTestScreenshotMonitor.stopMonitoring();
+                }
+                mTestScreenshotMonitor.startMonitoring();
+                semaphore.release();
+            }
+        });
+        try {
+            Assert.assertTrue(semaphore.tryAcquire(10, TimeUnit.SECONDS));
+        } catch (InterruptedException e) {
+            Log.e(TAG, "Cannot acquire semaphore");
+        }
+    }
+
+    // This ensures that after UI thread finishes all tasks, screenshotShowUiCount equals
+    // expectedCount.
+    private void assertScreenshotShowUiCountOnUiThreadBlocking(int expectedCount) {
+        final Semaphore semaphore = new Semaphore(0);
+
+        ThreadUtils.postOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                semaphore.release();
+            }
+        });
+        try {
+            Assert.assertTrue(semaphore.tryAcquire(10, TimeUnit.SECONDS));
+        } catch (InterruptedException e) {
+            Log.e(TAG, "Cannot acquire semaphore");
+        }
+        Assert.assertEquals(
+                expectedCount, mTestScreenshotMonitorDelegate.screenshotShowUiCount.get());
+    }
+}
\ No newline at end of file
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxTest.java
index 9b6f9af..38105ad 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxTest.java
@@ -87,6 +87,13 @@
         });
     }
 
+    private static final OnSuggestionsReceivedListener sEmptySuggestionListener =
+            new OnSuggestionsReceivedListener() {
+                @Override
+                public void onSuggestionsReceived(
+                        List<OmniboxSuggestion> suggestions, String inlineAutocompleteText) {}
+            };
+
     /**
      * Sanity check of Omnibox.  The problem in http://b/5021723 would
      * cause this to fail (hang or crash).
@@ -168,8 +175,8 @@
             }
         });
 
-        final TestAutocompleteController controller = new TestAutocompleteController(
-                locationBar, null, null);
+        final TestAutocompleteController controller = new TestAutocompleteController(locationBar,
+                sEmptySuggestionListener, new HashMap<String, List<SuggestionsResult>>());
 
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
@@ -208,17 +215,8 @@
         final ImageButton deleteButton =
                 (ImageButton) mActivityTestRule.getActivity().findViewById(R.id.delete_button);
 
-        final OnSuggestionsReceivedListener emptySuggestionListener =
-                new OnSuggestionsReceivedListener() {
-                    @Override
-                    public void onSuggestionsReceived(
-                            List<OmniboxSuggestion> suggestions, String inlineAutocompleteText) {
-                    }
-                };
-
-        final TestAutocompleteController controller = new TestAutocompleteController(
-                locationBar, emptySuggestionListener,
-                new HashMap<String, List<SuggestionsResult>>());
+        final TestAutocompleteController controller = new TestAutocompleteController(locationBar,
+                sEmptySuggestionListener, new HashMap<String, List<SuggestionsResult>>());
 
         OmniboxTestUtils.toggleUrlBarFocus(urlBar, true);
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
@@ -260,17 +258,8 @@
                 (LocationBarLayout) mActivityTestRule.getActivity().findViewById(R.id.location_bar);
         final UrlBar urlBar = (UrlBar) mActivityTestRule.getActivity().findViewById(R.id.url_bar);
 
-        final OnSuggestionsReceivedListener emptySuggestionListener =
-                new OnSuggestionsReceivedListener() {
-                    @Override
-                    public void onSuggestionsReceived(List<OmniboxSuggestion> suggestions,
-                            String inlineAutocompleteText) {
-                    }
-                };
-
-        final TestAutocompleteController controller = new TestAutocompleteController(
-                locationBar, emptySuggestionListener,
-                new HashMap<String, List<SuggestionsResult>>());
+        final TestAutocompleteController controller = new TestAutocompleteController(locationBar,
+                sEmptySuggestionListener, new HashMap<String, List<SuggestionsResult>>());
 
         OmniboxTestUtils.toggleUrlBarFocus(urlBar, true);
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrTabTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrTabTest.java
index 1c5bce9..29c0e760 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrTabTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrTabTest.java
@@ -14,6 +14,7 @@
 import org.junit.runner.RunWith;
 
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.FlakyTest;
 import org.chromium.base.test.util.MinAndroidSdkLevel;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.test.ChromeActivityTestRule;
@@ -35,6 +36,7 @@
      */
     @Test
     @MediumTest
+    @FlakyTest(message = "crbug.com/738148")
     public void testPoseDataUnfocusedTab() throws InterruptedException {
         mVrTestRule.loadUrlAndAwaitInitialization(
                 VrTestRule.getHtmlTestFile("test_pose_data_unfocused_tab"), PAGE_LOAD_TIMEOUT_S);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkIntegrationTest.java
index 9468ac5..99595a3 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkIntegrationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkIntegrationTest.java
@@ -9,21 +9,25 @@
 import android.support.test.filters.LargeTest;
 
 import org.junit.After;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.ScalableTimeout;
 import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.ChromeSwitches;
+import org.chromium.chrome.browser.DeferredStartupHandler;
 import org.chromium.chrome.browser.ShortcutHelper;
 import org.chromium.chrome.browser.customtabs.CustomTabActivity;
 import org.chromium.chrome.test.ChromeActivityTestRule;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.util.ChromeTabUtils;
+import org.chromium.content.browser.test.NativeLibraryTestRule;
 import org.chromium.content.browser.test.util.Criteria;
 import org.chromium.content.browser.test.util.CriteriaHelper;
 import org.chromium.net.test.EmbeddedTestServer;
@@ -39,6 +43,9 @@
             new ChromeActivityTestRule<>(WebApkActivity.class);
 
     @Rule
+    public final NativeLibraryTestRule mNativeLibraryTestRule = new NativeLibraryTestRule();
+
+    @Rule
     public final TopActivityListener activityListener = new TopActivityListener();
 
     private static final long STARTUP_TIMEOUT = ScalableTimeout.scaleTimeout(10000);
@@ -80,6 +87,14 @@
         });
     }
 
+    /** Register WebAPK with WebappDataStorage */
+    private WebappDataStorage registerWithStorage(final String webappId) throws Exception {
+        TestFetchStorageCallback callback = new TestFetchStorageCallback();
+        WebappRegistry.getInstance().register(webappId, callback);
+        callback.waitForCallback(0);
+        return WebappRegistry.getInstance().getWebappDataStorage(webappId);
+    }
+
     @Before
     public void setUp() throws Exception {
         mTestServer = EmbeddedTestServer.createAndStartServer(
@@ -119,4 +134,58 @@
             }
         });
     }
+
+    /**
+     * Test that on first launch:
+     * - the "WebApk.LaunchInterval" histogram is not recorded (because there is no prevous launch
+     *   to compute the interval from).
+     * - the "last used" time is updated (to compute future "launch intervals").
+     */
+    @Test
+    @LargeTest
+    @Feature({"WebApk"})
+    public void testLaunchIntervalHistogramNotRecordedOnFirstLaunch() throws Exception {
+        final String histogramName = "WebApk.LaunchInterval";
+        final String packageName = "org.chromium.webapk.test";
+        startWebApkActivity(packageName, mTestServer.getURL("/chrome/test/data/android/test.html"));
+
+        CriteriaHelper.pollUiThread(new Criteria("Deferred startup never completed") {
+            @Override
+            public boolean isSatisfied() {
+                return DeferredStartupHandler.getInstance().isDeferredStartupCompleteForApp();
+            }
+        });
+        Assert.assertEquals(0, RecordHistogram.getHistogramTotalCountForTesting(histogramName));
+        WebappDataStorage storage = WebappRegistry.getInstance().getWebappDataStorage(
+                WebApkConstants.WEBAPK_ID_PREFIX + packageName);
+        Assert.assertNotEquals(WebappDataStorage.TIMESTAMP_INVALID, storage.getLastUsedTime());
+    }
+
+    /** Test that the "WebApk.LaunchInterval" histogram is recorded on susbequent launches. */
+    @Test
+    @LargeTest
+    @Feature({"WebApk"})
+    public void testLaunchIntervalHistogramRecordedOnSecondLaunch() throws Exception {
+        mNativeLibraryTestRule.loadNativeLibraryNoBrowserProcess();
+
+        final String histogramName = "WebApk.LaunchInterval";
+        final String packageName = "org.chromium.webapk.test";
+
+        WebappDataStorage storage =
+                registerWithStorage(WebApkConstants.WEBAPK_ID_PREFIX + packageName);
+        storage.setHasBeenLaunched();
+        storage.updateLastUsedTime();
+        Assert.assertEquals(0, RecordHistogram.getHistogramTotalCountForTesting(histogramName));
+
+        startWebApkActivity(packageName, mTestServer.getURL("/chrome/test/data/android/test.html"));
+
+        CriteriaHelper.pollUiThread(new Criteria("Deferred startup never completed") {
+            @Override
+            public boolean isSatisfied() {
+                return DeferredStartupHandler.getInstance().isDeferredStartupCompleteForApp();
+            }
+        });
+
+        Assert.assertEquals(1, RecordHistogram.getHistogramTotalCountForTesting(histogramName));
+    }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappModeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappModeTest.java
index 5845ad5..fd3b21ad 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappModeTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappModeTest.java
@@ -24,11 +24,13 @@
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.RetryOnFailure;
+import org.chromium.base.test.util.ScalableTimeout;
 import org.chromium.base.test.util.UrlUtils;
 import org.chromium.blink_public.platform.WebDisplayMode;
 import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
+import org.chromium.chrome.browser.DeferredStartupHandler;
 import org.chromium.chrome.browser.ShortcutHelper;
 import org.chromium.chrome.browser.ShortcutSource;
 import org.chromium.chrome.browser.tab.Tab;
@@ -267,6 +269,28 @@
         });
     }
 
+    /** Test that on first launch {@link WebappDataStorage#hasBeenLaunched()} is set. */
+    @Test
+    @MediumTest
+    @Feature({"Webapps"})
+    public void testSetsHasBeenLaunchedOnFirstLaunch() throws Exception {
+        WebappDataStorage storage = WebappRegistry.getInstance().getWebappDataStorage(WEBAPP_1_ID);
+        Assert.assertFalse(storage.hasBeenLaunched());
+
+        startWebappActivity(WEBAPP_1_ID, WEBAPP_1_URL, WEBAPP_1_TITLE, WEBAPP_ICON);
+
+        // Use a longer timeout because the DeferredStartupHandler is called after the page has
+        // finished loading.
+        CriteriaHelper.pollUiThread(new Criteria("Deferred startup never completed") {
+            @Override
+            public boolean isSatisfied() {
+                return DeferredStartupHandler.getInstance().isDeferredStartupCompleteForApp();
+            }
+        }, ScalableTimeout.scaleTimeout(5000), CriteriaHelper.DEFAULT_POLLING_INTERVAL);
+
+        Assert.assertTrue(storage.hasBeenLaunched());
+    }
+
     /**
      * Starts a WebappActivity for the given data and waits for it to be initialized.  We can't use
      * ActivityUtils.waitForActivity() because of the way WebappActivity is instanced on pre-L
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetNewTabControllerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetNewTabControllerTest.java
index c43be51..80ae4b39 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetNewTabControllerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetNewTabControllerTest.java
@@ -26,9 +26,7 @@
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
 import org.chromium.chrome.browser.LauncherShortcutActivity;
-import org.chromium.chrome.browser.UrlConstants;
 import org.chromium.chrome.browser.compositor.layouts.LayoutManagerChrome;
-import org.chromium.chrome.browser.ntp.ChromeHomeNewTabPageBase;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tabmodel.EmptyTabModelObserver;
 import org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver;
@@ -45,8 +43,7 @@
 import java.util.concurrent.TimeoutException;
 
 /**
- * Tests for the NTP UI displayed when Chrome Home is enabled. TODO(twellington): Remove remaining
- * tests for ChromeHomeNewTabPage after it's completely removed.
+ * Tests for the NTP UI displayed when Chrome Home is enabled.
  */
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({BottomSheetTestRule.ENABLE_CHROME_HOME,
@@ -519,72 +516,6 @@
         assertFalse("Normal model should be selected.", mTabModelSelector.isIncognitoSelected());
     }
 
-    @Test
-    @SmallTest
-    public void testCloseNTP()
-            throws IllegalArgumentException, InterruptedException, TimeoutException {
-        // Create a new tab.
-        createNewBlankTab(false);
-        loadChromeHomeNewTab();
-
-        // Close the new tab.
-        closeNewTab();
-        assertEquals(1, mTabModelSelector.getTotalTabCount());
-    }
-
-    @Test
-    @SmallTest
-    public void testCloseNTP_Incognito()
-            throws IllegalArgumentException, InterruptedException, TimeoutException {
-        // Create new incognito NTP.
-        createNewBlankTab(true);
-        loadChromeHomeNewTab();
-
-        // Close the new tab.
-        closeNewTab();
-        assertEquals(1, mTabModelSelector.getTotalTabCount());
-    }
-
-    private void loadChromeHomeNewTab() throws InterruptedException {
-        final Tab tab = mActivity.getActivityTab();
-        ChromeTabUtils.loadUrlOnUiThread(tab, UrlConstants.NTP_URL);
-        ChromeTabUtils.waitForTabPageLoaded(tab, UrlConstants.NTP_URL);
-        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
-    }
-
-    private void createNewBlankTab(final boolean incognito) {
-        MenuUtils.invokeCustomMenuActionSync(InstrumentationRegistry.getInstrumentation(),
-                mActivity, incognito ? R.id.new_incognito_tab_menu_id : R.id.new_tab_menu_id);
-
-        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
-            @Override
-            public void run() {
-                mBottomSheet.loadUrl(new LoadUrlParams("about:blank"), incognito);
-                mActivity.getLayoutManager().getActiveLayout().finishAnimationsForTests();
-            }
-        });
-    }
-
-    private void closeNewTab() throws InterruptedException, TimeoutException {
-        Tab tab = mActivity.getActivityTab();
-        TestTabModelObserver observer =
-                tab.isIncognito() ? mIncognitoTabModelObserver : mNormalTabModelObserver;
-        int currentCallCount = observer.mDidCloseTabCallbackHelper.getCallCount();
-        final ChromeHomeNewTabPageBase newTabPage = (ChromeHomeNewTabPageBase) tab.getNativePage();
-
-        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
-            @Override
-            public void run() {
-                newTabPage.getCloseButtonForTests().callOnClick();
-                mActivity.getLayoutManager().getActiveLayout().finishAnimationsForTests();
-            }
-        });
-
-        observer.mDidCloseTabCallbackHelper.waitForCallback(currentCallCount, 1);
-
-        validateState(false, BottomSheet.SHEET_STATE_PEEK);
-    }
-
     private void validateState(boolean chromeHomeTabPageSelected, int expectedEndState) {
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchContextForTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchContextForTest.java
new file mode 100644
index 0000000..91b0662
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchContextForTest.java
@@ -0,0 +1,46 @@
+// 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.
+
+package org.chromium.chrome.browser.contextualsearch;
+
+/**
+ * Provides a {@link ContextualSearchContext} suitable for injection into a class for testing.  This
+ * has native calls stubbed out and is set up to provide some simple test feedback.
+ */
+public class ContextualSearchContextForTest extends ContextualSearchContext {
+    private boolean mDidSelectionChange;
+
+    /**
+     * @return Whether {@link #onSelectionChanged} was called.
+     */
+    boolean getDidSelectionChange() {
+        return mDidSelectionChange;
+    }
+
+    @Override
+    void onSelectionChanged() {
+        mDidSelectionChange = true;
+    }
+
+    @Override
+    protected long nativeInit() {
+        return -1;
+    }
+
+    @Override
+    protected void nativeDestroy(long nativeContextualSearchContext) {}
+
+    @Override
+    protected void nativeSetResolveProperties(
+            long nativeContextualSearchContext, String homeCountry, boolean maySendBasePageUrl) {}
+
+    @Override
+    protected void nativeAdjustSelection(
+            long nativeContextualSearchContext, int startAdjust, int endAdjust) {}
+
+    @Override
+    protected boolean isCharFromAlphabetWithUnreliableWordBreakAtIndex(String text, int index) {
+        return false;
+    }
+}
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchContextTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchContextTest.java
new file mode 100644
index 0000000..a1ebea5
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchContextTest.java
@@ -0,0 +1,201 @@
+// 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.
+
+package org.chromium.chrome.browser.contextualsearch;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.BlockJUnit4ClassRunner;
+
+import org.chromium.base.test.util.Feature;
+
+/**
+ * Tests parts of the ContextualSearchContext class.
+ */
+@RunWith(BlockJUnit4ClassRunner.class)
+public class ContextualSearchContextTest {
+    private static final int INVALID = ContextualSearchContext.INVALID_OFFSET;
+    private static final String UTF_8 = "UTF-8";
+    private static final String SAMPLE_TEXT =
+            "Now Barack Obama is not the best example.  And Clinton is ambiguous.";
+    private static final String HOME_COUNTRY = "unused";
+
+    private ContextualSearchContextForTest mContext;
+
+    @Before
+    public void setup() {
+        mContext = new ContextualSearchContextForTest();
+    }
+
+    private void setupLongpressOfBarack() {
+        int barackStartOffset = "Now ".length();
+        int barackEndOffset = "Now Barack".length() - barackStartOffset;
+        mContext.setSurroundingText(UTF_8, SAMPLE_TEXT, barackStartOffset, barackEndOffset);
+    }
+
+    private void setupTapInBarack() {
+        int barackBeforeROffset = "Now Ba".length();
+        mContext.setSurroundingText(UTF_8, SAMPLE_TEXT, barackBeforeROffset, barackBeforeROffset);
+    }
+
+    private void simulateSelectWordAroundCaret(int startAdjust, int endAdjust) {
+        mContext.onSelectionAdjusted(startAdjust, endAdjust);
+    }
+
+    private void simulateResolve(int startAdjust, int endAdjust) {
+        mContext.onSelectionAdjusted(startAdjust, endAdjust);
+    }
+
+    private void setupResolvingTapInBarak() {
+        setupTapInBarack();
+        mContext.setResolveProperties(HOME_COUNTRY, true);
+    }
+
+    private void setupResolvingTapInObama() {
+        int obamaBeforeMOffset = "Now Barack Oba".length();
+        mContext.setSurroundingText(UTF_8, SAMPLE_TEXT, obamaBeforeMOffset, obamaBeforeMOffset);
+        mContext.setResolveProperties(HOME_COUNTRY, true);
+    }
+
+    @Test
+    @Feature({"ContextualSearch", "Context"})
+    public void testEmptyContext() {
+        assertFalse(mContext.hasAnalyzedTap());
+        assertFalse(mContext.hasValidTappedText());
+        assertFalse(mContext.hasValidSelection());
+        assertFalse(mContext.canResolve());
+        assertNull(mContext.getWordTapped());
+        assertNull(mContext.getWordPreviousToTap());
+        assertNull(mContext.getWordFollowingTap());
+        assertEquals(INVALID, mContext.getWordTappedOffset());
+        assertEquals(INVALID, mContext.getTapOffsetWithinTappedWord());
+        assertEquals(INVALID, mContext.getWordFollowingTapOffset());
+        assertNull(mContext.getSurroundingText());
+        assertEquals(INVALID, mContext.getSelectionStartOffset());
+        assertEquals(INVALID, mContext.getSelectionEndOffset());
+        assertNull(mContext.getEncoding());
+        assertNull(mContext.getInitialSelectedWord());
+        assertEquals("", mContext.getTextContentFollowingSelection());
+    }
+
+    @Test
+    @Feature({"ContextualSearch", "Context"})
+    public void testLongpressContext() {
+        setupLongpressOfBarack();
+        assertFalse(mContext.canResolve());
+        assertFalse(mContext.hasAnalyzedTap());
+        assertFalse(mContext.hasValidTappedText());
+        assertTrue(mContext.hasValidSelection());
+        assertNotNull(mContext.getSurroundingText());
+        assertTrue(mContext.getSelectionStartOffset() >= 0);
+        assertTrue(mContext.getSelectionEndOffset() >= 0);
+        assertNotNull(mContext.getEncoding());
+        assertTrue(mContext.getDidSelectionChange());
+    }
+
+    @Test
+    @Feature({"ContextualSearch", "Context"})
+    public void testTapContext() {
+        setupTapInBarack();
+        assertFalse(mContext.canResolve());
+        assertTrue(mContext.hasAnalyzedTap());
+        assertTrue(mContext.hasValidTappedText());
+        assertFalse(mContext.hasValidSelection());
+        assertNotNull(mContext.getSurroundingText());
+        assertTrue(mContext.getSelectionStartOffset() >= 0);
+        assertTrue(mContext.getSelectionEndOffset() >= 0);
+        assertNotNull(mContext.getEncoding());
+        assertNull(mContext.getInitialSelectedWord());
+        assertFalse(mContext.getDidSelectionChange());
+
+        simulateSelectWordAroundCaret(-"Ba".length(), "rack".length());
+        assertEquals("Barack", mContext.getInitialSelectedWord());
+        assertEquals("Barack".length(),
+                mContext.getSelectionEndOffset() - mContext.getSelectionStartOffset());
+        assertTrue(mContext.getDidSelectionChange());
+        assertTrue(mContext.hasValidSelection());
+    }
+
+    @Test
+    @Feature({"ContextualSearch", "Context"})
+    public void testResolvingTapContext() {
+        setupResolvingTapInBarak();
+        assertFalse(mContext.canResolve());
+
+        simulateSelectWordAroundCaret(-"Ba".length(), "rack".length());
+        assertTrue(mContext.canResolve());
+
+        simulateResolve(0, " Obama".length());
+        assertEquals("Barack", mContext.getInitialSelectedWord());
+        assertEquals("Barack Obama".length(),
+                mContext.getSelectionEndOffset() - mContext.getSelectionStartOffset());
+    }
+
+    @Test
+    @Feature({"ContextualSearch", "Context"})
+    public void testAnalysisOfWord() {
+        setupResolvingTapInBarak();
+        assertEquals("Barack", mContext.getWordTapped());
+        assertEquals("Ba".length(), mContext.getTapOffsetWithinTappedWord());
+        assertEquals("Now ".length(), mContext.getWordTappedOffset());
+    }
+
+    @Test
+    @Feature({"ContextualSearch", "Context"})
+    public void testAnalysisOfWordsPreviousAndFollowing() {
+        setupResolvingTapInObama();
+        assertEquals("Barack", mContext.getWordPreviousToTap());
+        assertEquals("is", mContext.getWordFollowingTap());
+        assertEquals("Now ".length(), mContext.getWordPreviousToTapOffset());
+        assertEquals("Now Barack Obama ".length(), mContext.getWordFollowingTapOffset());
+    }
+
+    @Test
+    @Feature({"ContextualSearch", "Context"})
+    public void testAnalysisAtStartOfText() {
+        int startOffset = 0;
+        mContext.setSurroundingText(UTF_8, SAMPLE_TEXT, startOffset, startOffset);
+        assertNull(mContext.getWordPreviousToTap());
+        // We can't recognize the first word because we need a space before it to do so.
+        assertNull(mContext.getWordTapped());
+        assertNull(mContext.getWordFollowingTap());
+    }
+
+    @Test
+    @Feature({"ContextualSearch", "Context"})
+    public void testAnalysisAtSecondWordOfText() {
+        int secondWordOffset = "Now ".length();
+        mContext.setSurroundingText(UTF_8, SAMPLE_TEXT, secondWordOffset, secondWordOffset);
+        assertNull(mContext.getWordPreviousToTap());
+        assertEquals("Barack", mContext.getWordTapped());
+        assertEquals("Obama", mContext.getWordFollowingTap());
+    }
+
+    @Test
+    @Feature({"ContextualSearch", "Context"})
+    public void testAnalysisAtEndOfText() {
+        int endOffset = SAMPLE_TEXT.length();
+        mContext.setSurroundingText(UTF_8, SAMPLE_TEXT, endOffset, endOffset);
+        assertNull(mContext.getWordPreviousToTap());
+        assertNull(mContext.getWordTapped());
+        assertNull(mContext.getWordFollowingTap());
+    }
+
+    @Test
+    @Feature({"ContextualSearch", "Context"})
+    public void testAnalysisAtWordBeforeEndOfText() {
+        int wordBeforeEndOffset = SAMPLE_TEXT.length() - "s ambiguous.".length();
+        mContext.setSurroundingText(UTF_8, SAMPLE_TEXT, wordBeforeEndOffset, wordBeforeEndOffset);
+        assertEquals("Clinton", mContext.getWordPreviousToTap());
+        assertEquals("is", mContext.getWordTapped());
+        assertEquals("ambiguous", mContext.getWordFollowingTap());
+    }
+}
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchEntityHeuristicTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchEntityHeuristicTest.java
new file mode 100644
index 0000000..a011fee7
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchEntityHeuristicTest.java
@@ -0,0 +1,93 @@
+// 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.
+
+package org.chromium.chrome.browser.contextualsearch;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.BlockJUnit4ClassRunner;
+
+import org.chromium.base.test.util.Feature;
+
+import java.util.Locale;
+
+/**
+ * Tests parts of the {@link ContextualSearchEntityHeuristic} class.
+ */
+@RunWith(BlockJUnit4ClassRunner.class)
+public class ContextualSearchEntityHeuristicTest {
+    private static final String SAMPLE_TEXT =
+            "Now Barack Obama, Michelle are not the best examples.  And Clinton is ambiguous.";
+    private static final String UTF_8 = "UTF-8";
+
+    private ContextualSearchContext mContext;
+    private ContextualSearchEntityHeuristic mEntityHeuristic;
+
+    @Before
+    public void setup() {
+        mContext = new ContextualSearchContextForTest();
+    }
+
+    private void setupInstanceToTest(Locale locale, int tapOffset) {
+        mContext.setSurroundingText(UTF_8, SAMPLE_TEXT, tapOffset, tapOffset);
+        mContext.setResolveProperties(locale.getCountry().toString(), true);
+        mEntityHeuristic = ContextualSearchEntityHeuristic.testInstance(mContext, true);
+    }
+
+    private void setupTapInObama(Locale locale) {
+        setupInstanceToTest(locale, "Now Barack Oba".length());
+    }
+
+    private void setupTapInEnglishStartOfBuffer() {
+        setupInstanceToTest(Locale.US, 0);
+    }
+
+    private void setupTapInEnglishClinton() {
+        setupInstanceToTest(Locale.US,
+                "Now Barack Obama, Michelle are not the best examples.  And Clin".length());
+    }
+
+    private void setupTapInWordAfterComma() {
+        setupInstanceToTest(Locale.US, "Now Barack Obama, Mich".length());
+    }
+
+    @Test
+    @Feature({"ContextualSearch", "TapProperNounSuppression"})
+    public void testTapInProperNounRecognized() {
+        setupTapInObama(Locale.US);
+        assertTrue(mEntityHeuristic.isProbablyEnglishProperNoun());
+    }
+
+    @Test
+    @Feature({"ContextualSearch", "TapProperNounSuppression"})
+    public void testTapInProperNounNotEnglishNotRecognized() {
+        setupTapInObama(Locale.GERMANY);
+        assertFalse(mEntityHeuristic.isProbablyEnglishProperNoun());
+    }
+
+    @Test
+    @Feature({"ContextualSearch", "TapProperNounSuppression"})
+    public void testTapInProperNounAfterPeriodNotRecognized() {
+        setupTapInEnglishClinton();
+        assertFalse(mEntityHeuristic.isProbablyEnglishProperNoun());
+    }
+
+    @Test
+    @Feature({"ContextualSearch", "TapProperNounSuppression"})
+    public void testTapInStartOfTextBufferNotRecognized() {
+        setupTapInEnglishStartOfBuffer();
+        assertFalse(mEntityHeuristic.isProbablyEnglishProperNoun());
+    }
+
+    @Test
+    @Feature({"ContextualSearch", "TapProperNounSuppression"})
+    public void testTapInSingleWordAfterCommaNotRecognized() {
+        setupTapInWordAfterComma();
+        assertFalse(mEntityHeuristic.isProbablyEnglishProperNoun());
+    }
+}
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchInternalStateTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchInternalStateTest.java
index 32054ee3..e91ab55 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchInternalStateTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchInternalStateTest.java
@@ -74,6 +74,11 @@
             stubForWorkOnState(InternalState.WAITING_FOR_POSSIBLE_TAP_NEAR_PREVIOUS);
         }
 
+        @Override
+        public void waitForPossibleTapOnTapSelection() {
+            stubForWorkOnState(InternalState.WAITING_FOR_POSSIBLE_TAP_ON_TAP_SELECTION);
+        }
+
         boolean didResolve() {
             return mDidResolve;
         }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/AutocompleteEditTextTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/AutocompleteEditTextTest.java
index a1ebffd4..109ae734 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/AutocompleteEditTextTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/AutocompleteEditTextTest.java
@@ -81,13 +81,14 @@
         MockitoAnnotations.initMocks(this);
         mContext = RuntimeEnvironment.application;
         mEmbedder = spy(new AutocompleteEmbedder());
-        mAutocomplete = spy(new TestAutocompleteEditText(mEmbedder, mContext, null));
+        mAutocomplete = new TestAutocompleteEditText(mEmbedder, mContext, null);
         assertNotNull(mAutocomplete);
         // Note: this cannot catch the first {@link
         // AutocompleteEditText#onAutocompleteTextStateChanged(boolean)}, which is caused
         // by View constructor's call to setText().
         mInOrder = inOrder(mEmbedder);
-        mAutocomplete.onCreateInputConnection(new EditorInfo());
+        assertTrue(mAutocomplete.requestFocus());
+        assertNotNull(mAutocomplete.onCreateInputConnection(new EditorInfo()));
         mInputConnection = mAutocomplete.getInputConnection();
         assertNotNull(mInputConnection);
         mInOrder.verifyNoMoreInteractions();
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebappDataStorageTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebappDataStorageTest.java
index 89b2c24..bfdcde5 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebappDataStorageTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebappDataStorageTest.java
@@ -187,11 +187,11 @@
 
         // Opening a data storage doesn't count as a launch.
         WebappDataStorage storage = WebappDataStorage.open("test");
-        assertTrue(!storage.wasLaunchedRecently());
+        assertTrue(!storage.wasUsedRecently());
 
         // When the last used time is updated, then it is a launch.
         storage.updateLastUsedTime();
-        assertTrue(storage.wasLaunchedRecently());
+        assertTrue(storage.wasUsedRecently());
 
         long lastUsedTime = mSharedPreferences.getLong(
                 WebappDataStorage.KEY_LAST_USED, WebappDataStorage.TIMESTAMP_INVALID);
@@ -202,29 +202,29 @@
         mSharedPreferences.edit()
                 .putLong(WebappDataStorage.KEY_LAST_USED, lastUsedTime - TimeUnit.DAYS.toMillis(1L))
                 .apply();
-        assertTrue(storage.wasLaunchedRecently());
+        assertTrue(storage.wasUsedRecently());
 
         // Move the last used time three days in the past.
         mSharedPreferences.edit()
                 .putLong(WebappDataStorage.KEY_LAST_USED, lastUsedTime - TimeUnit.DAYS.toMillis(3L))
                 .apply();
-        assertTrue(storage.wasLaunchedRecently());
+        assertTrue(storage.wasUsedRecently());
 
         // Move the last used time one week in the past.
         mSharedPreferences.edit()
                 .putLong(WebappDataStorage.KEY_LAST_USED, lastUsedTime - TimeUnit.DAYS.toMillis(7L))
                 .apply();
-        assertTrue(storage.wasLaunchedRecently());
+        assertTrue(storage.wasUsedRecently());
 
         // Move the last used time just under ten days in the past.
         mSharedPreferences.edit().putLong(WebappDataStorage.KEY_LAST_USED,
                 lastUsedTime - TimeUnit.DAYS.toMillis(10L) + 1).apply();
-        assertTrue(storage.wasLaunchedRecently());
+        assertTrue(storage.wasUsedRecently());
 
         // Move the last used time to exactly ten days in the past.
         mSharedPreferences.edit().putLong(WebappDataStorage.KEY_LAST_USED,
                 lastUsedTime - TimeUnit.DAYS.toMillis(10L)).apply();
-        assertTrue(!storage.wasLaunchedRecently());
+        assertTrue(!storage.wasUsedRecently());
     }
 
     @Test
diff --git a/chrome/android/webapk/shell_apk/shell_apk_version.gni b/chrome/android/webapk/shell_apk/shell_apk_version.gni
index 63a64b9..23adf54 100644
--- a/chrome/android/webapk/shell_apk/shell_apk_version.gni
+++ b/chrome/android/webapk/shell_apk/shell_apk_version.gni
@@ -6,7 +6,7 @@
 # (including AndroidManifest.xml) is updated. This version should be incremented
 # prior to uploading a new ShellAPK to the WebAPK Minting Server.
 # Does not affect Chrome.apk
-template_shell_apk_version = 10
+template_shell_apk_version = 11
 
 # The ShellAPK version expected by Chrome. Chrome will try to update the WebAPK
 # if the WebAPK's ShellAPK version is less than |expected_shell_apk_version|.
diff --git a/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/ChooseHostBrowserDialog.java b/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/ChooseHostBrowserDialog.java
index 6802038..dace205 100644
--- a/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/ChooseHostBrowserDialog.java
+++ b/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/ChooseHostBrowserDialog.java
@@ -81,10 +81,10 @@
      * @param context The current Context.
      * @param listener The listener for the dialog.
      * @param infos The list of ResolvedInfos of the browsers that are shown on the dialog.
-     * @param url URL of the WebAPK for which the dialog is shown.
+     * @param appName The name of the WebAPK for which the dialog is shown.
      */
-    public static void show(
-            Context context, final DialogListener listener, List<ResolveInfo> infos, String url) {
+    public static void show(Context context, final DialogListener listener, List<ResolveInfo> infos,
+            String appName) {
         final List<BrowserItem> browserItems =
                 getBrowserInfosForHostBrowserSelection(context.getPackageManager(), infos);
 
@@ -94,13 +94,13 @@
         View view = LayoutInflater.from(context).inflate(R.layout.choose_host_browser_dialog, null);
         TextView desc = (TextView) view.findViewById(R.id.desc);
         ListView browserList = (ListView) view.findViewById(R.id.browser_list);
-        desc.setText(context.getString(R.string.choose_host_browser, url));
-        browserList.setAdapter(new BrowserArrayAdapter(context, browserItems, url));
+        desc.setText(R.string.choose_host_browser);
+        browserList.setAdapter(new BrowserArrayAdapter(context, browserItems));
 
         // The context theme wrapper is needed for pre-L.
         AlertDialog.Builder builder = new AlertDialog.Builder(
                 new ContextThemeWrapper(context, android.R.style.Theme_DeviceDefault_Light_Dialog));
-        builder.setTitle(context.getString(R.string.choose_host_browser_dialog_title, url))
+        builder.setTitle(context.getString(R.string.choose_host_browser_dialog_title, appName))
                 .setView(view)
                 .setNegativeButton(R.string.choose_host_browser_dialog_quit,
                         new DialogInterface.OnClickListener() {
@@ -156,13 +156,11 @@
     private static class BrowserArrayAdapter extends ArrayAdapter<BrowserItem> {
         private List<BrowserItem> mBrowsers;
         private Context mContext;
-        private String mUrl;
 
-        public BrowserArrayAdapter(Context context, List<BrowserItem> browsers, String url) {
+        public BrowserArrayAdapter(Context context, List<BrowserItem> browsers) {
             super(context, R.layout.host_browser_list_item, browsers);
             mContext = context;
             mBrowsers = browsers;
-            mUrl = url;
         }
 
         @Override
@@ -182,7 +180,7 @@
                 name.setTextColor(Color.BLACK);
             } else {
                 name.setText(mContext.getString(R.string.host_browser_item_not_supporting_webapks,
-                        item.getApplicationName(), mUrl));
+                        item.getApplicationName()));
                 name.setSingleLine(false);
                 name.setTextColor(Color.LTGRAY);
             }
diff --git a/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/InstallHostBrowserDialog.java b/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/InstallHostBrowserDialog.java
index 2dcf615..ddf8d39 100644
--- a/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/InstallHostBrowserDialog.java
+++ b/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/InstallHostBrowserDialog.java
@@ -29,12 +29,12 @@
      * Shows the dialog to install a host browser.
      * @param context The current context.
      * @param listener The listener for the dialog.
-     * @param url URL of the WebAPK for which the dialog is shown.
+     * @param appName The name of the WebAPK for which the dialog is shown.
      * @param hostBrowserPackageName The package name of the host browser.
      * @param hostBrowserApplicationName The application name of the host browser.
      * @param hostBrowserIconId The resource id of the icon of the host browser.
      */
-    public static void show(Context context, final DialogListener listener, String url,
+    public static void show(Context context, final DialogListener listener, String appName,
             final String hostBrowserPackageName, String hostBrowserApplicationName,
             int hostBrowserIconId) {
         View view = LayoutInflater.from(context).inflate(R.layout.host_browser_list_item, null);
@@ -48,7 +48,7 @@
         // The context theme wrapper is needed for pre-L.
         AlertDialog.Builder builder = new AlertDialog.Builder(
                 new ContextThemeWrapper(context, android.R.style.Theme_DeviceDefault_Light_Dialog));
-        builder.setTitle(context.getString(R.string.install_host_browser_dialog_title, url))
+        builder.setTitle(context.getString(R.string.install_host_browser_dialog_title, appName))
                 .setView(view)
                 .setNegativeButton(R.string.choose_host_browser_dialog_quit,
                         new DialogInterface.OnClickListener() {
diff --git a/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/MainActivity.java b/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/MainActivity.java
index d33e4d30..70e1b180 100644
--- a/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/MainActivity.java
+++ b/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/MainActivity.java
@@ -20,8 +20,6 @@
 import org.chromium.webapk.lib.common.WebApkMetaDataKeys;
 
 import java.io.File;
-import java.net.MalformedURLException;
-import java.net.URL;
 import java.util.List;
 
 /**
@@ -111,20 +109,11 @@
             return;
         }
 
-        String hostUrl = "";
-        try {
-            hostUrl = new URL(mStartUrl).getHost();
-        } catch (MalformedURLException e) {
-            Log.e(TAG, "Invalid URL of the WebApk.");
-            finish();
-            return;
-        }
-
         List<ResolveInfo> infos = WebApkUtils.getInstalledBrowserResolveInfos(getPackageManager());
         if (hasBrowserSupportingWebApks(infos)) {
-            showChooseHostBrowserDialog(infos, hostUrl);
+            showChooseHostBrowserDialog(infos);
         } else {
-            showInstallHostBrowserDialog(hostUrl, metadata);
+            showInstallHostBrowserDialog(metadata);
         }
     }
 
@@ -227,7 +216,7 @@
     }
 
     /** Shows a dialog to choose the host browser. */
-    private void showChooseHostBrowserDialog(List<ResolveInfo> infos, String hostUrl) {
+    private void showChooseHostBrowserDialog(List<ResolveInfo> infos) {
         ChooseHostBrowserDialog.DialogListener listener =
                 new ChooseHostBrowserDialog.DialogListener() {
                     @Override
@@ -242,11 +231,11 @@
                         finish();
                     }
                 };
-        ChooseHostBrowserDialog.show(this, listener, infos, hostUrl);
+        ChooseHostBrowserDialog.show(this, listener, infos, getString(R.string.name));
     }
 
     /** Shows a dialog to install the host browser. */
-    private void showInstallHostBrowserDialog(String hostUrl, Bundle metadata) {
+    private void showInstallHostBrowserDialog(Bundle metadata) {
         String lastResortHostBrowserPackageName =
                 metadata.getString(WebApkMetaDataKeys.RUNTIME_HOST);
         String lastResortHostBrowserApplicationName =
@@ -273,7 +262,8 @@
                     }
                 };
 
-        InstallHostBrowserDialog.show(this, listener, hostUrl, lastResortHostBrowserPackageName,
-                lastResortHostBrowserApplicationName, R.drawable.last_resort_runtime_host_logo);
+        InstallHostBrowserDialog.show(this, listener, getString(R.string.name),
+                lastResortHostBrowserPackageName, lastResortHostBrowserApplicationName,
+                R.drawable.last_resort_runtime_host_logo);
     }
 }
diff --git a/chrome/android/webapk/strings/android_webapk_strings.grd b/chrome/android/webapk/strings/android_webapk_strings.grd
index 3192084..94c2192 100644
--- a/chrome/android/webapk/strings/android_webapk_strings.grd
+++ b/chrome/android/webapk/strings/android_webapk_strings.grd
@@ -95,19 +95,19 @@
     <messages fallback_to_english="true">
       <!-- Select host browser dialog -->
       <message name="IDS_CHOOSE_HOST_BROWSER_DIALOG_TITLE" desc="Title for the host browser picker dialog, which is used to ask users to pick a browser to launch the installed WebAPK.">
-        <ph name="WEBAPK_SITE">%1$s<ex>Housing.com</ex></ph> needs a web browser to run
+        <ph name="APP_NAME">%1$s<ex>Progressive Web Apps</ex></ph> requires a web browser
       </message>
       <message name="IDS_CHOOSE_HOST_BROWSER" desc="Content for the host browser picker dialog, which is used to ask users to pick a browser to launch the installed WebAPK.">
-        Please select the browser you'd like to use to run <ph name="WEBAPK_SITE">%1$s<ex>Housing.com</ex></ph>
+        Choose a browser that supports this app:
       </message>
       <message name="IDS_CHOOSE_HOST_BROWSER_DIALOG_QUIT" desc="Text for the cancel button on the dialog. ">
-        QUIT
+        CLOSE
       </message>
       <message name="IDS_HOST_BROWSER_ITEM_NOT_SUPPORTING_WEBAPKS" desc="Text for the host browser item that doesn't support WebAPKs on the choose host browser dialog. ">
-        <ph name="BROWSER_NAME">%1$s<ex>Chrome</ex></ph>\nUnsupported by <ph name="WEBAPK_SITE">%2$s<ex>Housing.com</ex></ph>
+        <ph name="BROWSER_NAME">%1$s<ex>Chrome</ex></ph>\nUnsupported
       </message>
       <message name="IDS_INSTALL_HOST_BROWSER_DIALOG_TITLE" desc="Title for the dialog to install the host browser to launch the WebAPK.">
-        <ph name="WEBAPK_SITE">%1$s<ex>Housing.com</ex></ph> needs the following app to run
+        <ph name="APP_NAME">%1$s<ex>Progressive Web Apps</ex></ph> requires the following app:
       </message>
       <message name="IDS_INSTALL_HOST_BROWSER_DIALOG_INSTALL_BUTTON" desc="Text for the install button on the dialog. ">
         INSTALL
diff --git a/chrome/app/app-Info.plist b/chrome/app/app-Info.plist
index f7dd4ec..e6e073f 100644
--- a/chrome/app/app-Info.plist
+++ b/chrome/app/app-Info.plist
@@ -319,7 +319,7 @@
 	<key>LSHasLocalizedDisplayName</key>
 	<string>1</string>
 	<key>LSMinimumSystemVersion</key>
-	<string>10.9.0</string>
+	<string>${MACOSX_DEPLOYMENT_TARGET}</string>
 	<key>NSPrincipalClass</key>
 	<string>BrowserCrApplication</string>
 	<key>NSSupportsAutomaticGraphicsSwitching</key>
diff --git a/chrome/app/chrome_crash_reporter_client_win.cc b/chrome/app/chrome_crash_reporter_client_win.cc
index 9083c2b..90c74c4 100644
--- a/chrome/app/chrome_crash_reporter_client_win.cc
+++ b/chrome/app/chrome_crash_reporter_client_win.cc
@@ -111,6 +111,7 @@
       {gpu::crash_keys::kGPUDriverVersion, kSmallSize},
       {gpu::crash_keys::kGPUPixelShaderVersion, kSmallSize},
       {gpu::crash_keys::kGPUVertexShaderVersion, kSmallSize},
+      {gpu::crash_keys::kGPUGLContextIsVirtual, kSmallSize},
 
       // browser/:
       {kThirdPartyModulesLoaded, kSmallSize},
diff --git a/chrome/app/chrome_main.cc b/chrome/app/chrome_main.cc
index 24ba3f6..52b2f96 100644
--- a/chrome/app/chrome_main.cc
+++ b/chrome/app/chrome_main.cc
@@ -9,6 +9,7 @@
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "chrome/app/chrome_main_delegate.h"
+#include "chrome/browser/profiling_host/profiling_process_host.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/features.h"
 #include "content/public/app/content_main.h"
@@ -108,12 +109,19 @@
 #endif  // defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN)
 
 #if BUILDFLAG(ENABLE_OOP_HEAP_PROFILING)
-#if !defined(OS_WIN) || defined(CHROME_MULTIPLE_DLL_BROWSER)
+#if !defined(OS_WIN) || defined(COMPONENT_BUILD) || \
+    defined(CHROME_MULTIPLE_DLL_BROWSER)
   // The profiling server is only compiled into the browser process. On Windows,
-  // it should be called only for CHROME_MULTIPLE_DLL_BROWSER.
+  // non-component builds, browser code is only used for
+  // CHROME_MULTIPLE_DLL_BROWSER.
   if (command_line->HasSwitch(switches::kMemlog))
-    return profiling::ProfilingMain(*command_line);
+    profiling::ProfilingProcessHost::EnsureStarted();
 #endif
+  // The profiling process. This is a child process type implemented at the
+  // Chrome layer rather than the content layer (like the other child procs.).
+  if (command_line->GetSwitchValueASCII(switches::kProcessType) ==
+      switches::kProfiling)
+    return profiling::ProfilingMain(*command_line);
   profiling::InitMemlogSenderIfNecessary(*command_line);
 #endif  // ENABLE_OOP_HEAP_PROFILING
 
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index afb8f991..82a8b4eb 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -11185,7 +11185,7 @@
           Search or type URL
         </message>
         <message name="IDS_SEARCH_BOX_HINT_FULLSCREEN" desc="Hint text for the search box in fullscreen app list window.">
-          Search your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph>, apps, web...
+          Search your device, apps, web...
         </message>
         <message name="IDS_SEARCH_BOX_HOTWORD_HINT" desc="Hint text for the search box in app list window when the hotword is enabled.">
           Search, or say "Ok Google"
@@ -12370,6 +12370,13 @@
         Press App button to exit
       </message>
     </if>
+
+    <!-- Experimental Fullscreen Exit Control strings -->
+    <if expr="toolkit_views">
+      <message name="IDS_FULLSCREEN_EXIT_CONTROL_EXIT_FULLSCREEN" desc="Text displayed in a button that exits fullscreen mode.">
+        Exit Fullscreen
+      </message>
+    </if>
   </messages>
  </release>
 </grit>
diff --git a/chrome/app/helper-Info.plist b/chrome/app/helper-Info.plist
index 5fca138..e2d8ebd 100644
--- a/chrome/app/helper-Info.plist
+++ b/chrome/app/helper-Info.plist
@@ -21,7 +21,7 @@
 	<key>LSFileQuarantineEnabled</key>
 	<true/>
 	<key>LSMinimumSystemVersion</key>
-	<string>10.9.0</string>
+	<string>${MACOSX_DEPLOYMENT_TARGET}</string>
 	<key>LSUIElement</key>
 	<string>1</string>
 	<key>NSSupportsAutomaticGraphicsSwitching</key>
diff --git a/chrome/app_shim/app_mode-Info.plist b/chrome/app_shim/app_mode-Info.plist
index 6250b0c..9442527 100644
--- a/chrome/app_shim/app_mode-Info.plist
+++ b/chrome/app_shim/app_mode-Info.plist
@@ -27,7 +27,7 @@
        <key>CrBundleIdentifier</key>
        <string>@APP_MODE_BROWSER_BUNDLE_ID@</string>
        <key>LSMinimumSystemVersion</key>
-       <string>10.9.0</string>
+       <string>${MACOSX_DEPLOYMENT_TARGET}</string>
        <key>NSAppleScriptEnabled</key>
        <true/>
 </dict>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 4616e29..c183606 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1465,6 +1465,7 @@
     "//chrome/browser/media/router",
     "//chrome/browser/metrics/variations:chrome_ui_string_overrider_factory",
     "//chrome/browser/net:probe_message_proto",
+    "//chrome/browser/profiling_host",
     "//chrome/browser/safe_browsing",
     "//chrome/browser/ssl:proto",
     "//chrome/browser/ui",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 7bc31c6..805f114 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -3107,6 +3107,14 @@
      FEATURE_VALUE_TYPE(features::kBrowserTouchBar)},
 #endif  // defined(OS_MACOSX)
 
+#if defined(TOOLKIT_VIEWS)
+    {"enable-experimental-fullscreen-exit-ui",
+     flag_descriptions::kExperimentalFullscreenExitUIName,
+     flag_descriptions::kExperimentalFullscreenExitUIDescription,
+     kOsWin | kOsLinux | kOsCrOS,
+     SINGLE_VALUE_TYPE(switches::kEnableExperimentalFullscreenExitUI)},
+#endif  // defined(TOOLKIT_VIEWS)
+
     // NOTE: Adding new command-line switches requires adding corresponding
     // entries to enum "LoginCustomFlags" in histograms/enums.xml. See note in
     // enums.xml and don't forget to run AboutFlagsHistogramTest unit test.
diff --git a/chrome/browser/android/compositor/tab_content_manager.h b/chrome/browser/android/compositor/tab_content_manager.h
index 331330b..e5e7763f 100644
--- a/chrome/browser/android/compositor/tab_content_manager.h
+++ b/chrome/browser/android/compositor/tab_content_manager.h
@@ -7,11 +7,11 @@
 
 #include <jni.h>
 
-#include <unordered_map>
+#include <map>
 
 #include "base/android/jni_android.h"
 #include "base/android/jni_weak_ref.h"
-#include "base/containers/hash_tables.h"
+#include "base/containers/flat_map.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "cc/layers/ui_resource_layer.h"
@@ -105,10 +105,12 @@
 
  private:
   class TabReadbackRequest;
-  using LayerMap = base::hash_map<int, scoped_refptr<cc::Layer>>;
-  using ThumbnailLayerMap = base::hash_map<int, scoped_refptr<ThumbnailLayer>>;
+  // TODO(bug 714384) check sizes and consider using base::flat_map if these
+  // layer maps are small.
+  using LayerMap = std::map<int, scoped_refptr<cc::Layer>>;
+  using ThumbnailLayerMap = std::map<int, scoped_refptr<ThumbnailLayer>>;
   using TabReadbackRequestMap =
-      std::unordered_map<int, std::unique_ptr<TabReadbackRequest>>;
+      base::flat_map<int, std::unique_ptr<TabReadbackRequest>>;
 
   void PutThumbnailIntoCache(int tab_id,
                              float thumbnail_scale,
diff --git a/chrome/browser/android/data_usage/data_use_tab_model.h b/chrome/browser/android/data_usage/data_use_tab_model.h
index cf15558..2e5877b 100644
--- a/chrome/browser/android/data_usage/data_use_tab_model.h
+++ b/chrome/browser/android/data_usage/data_use_tab_model.h
@@ -7,13 +7,13 @@
 
 #include <stddef.h>
 
+#include <map>
 #include <memory>
 #include <string>
 #include <vector>
 
 #include "base/callback.h"
 #include "base/callback_forward.h"
-#include "base/containers/hash_tables.h"
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
@@ -239,7 +239,7 @@
   FRIEND_TEST_ALL_PREFIXES(ExternalDataUseObserverTest,
                            MatchingRuleFetchOnControlAppInstall);
 
-  typedef base::hash_map<SessionID::id_type, TabDataUseEntry> TabEntryMap;
+  using TabEntryMap = std::map<SessionID::id_type, TabDataUseEntry>;
 
   // Gets the current label of a tab, and the new label if a navigation event
   // occurs in the tab. |tab_id| is the source tab of the generated event,
diff --git a/chrome/browser/android/data_usage/data_use_ui_tab_model.h b/chrome/browser/android/data_usage/data_use_ui_tab_model.h
index fe33bd4..c57a2d3 100644
--- a/chrome/browser/android/data_usage/data_use_ui_tab_model.h
+++ b/chrome/browser/android/data_usage/data_use_ui_tab_model.h
@@ -5,10 +5,10 @@
 #ifndef CHROME_BROWSER_ANDROID_DATA_USAGE_DATA_USE_UI_TAB_MODEL_H_
 #define CHROME_BROWSER_ANDROID_DATA_USAGE_DATA_USE_UI_TAB_MODEL_H_
 
+#include <map>
 #include <memory>
 #include <string>
 
-#include "base/containers/hash_tables.h"
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
@@ -136,7 +136,7 @@
     const std::string package;
   };
 
-  typedef base::hash_map<SessionID::id_type, DataUseTrackingEvent> TabEvents;
+  typedef std::map<SessionID::id_type, DataUseTrackingEvent> TabEvents;
 
   // DataUseTabModel::TabDataUseObserver implementation:
   void NotifyTrackingStarting(SessionID::id_type tab_id) override;
diff --git a/chrome/browser/android/data_usage/external_data_use_reporter.h b/chrome/browser/android/data_usage/external_data_use_reporter.h
index 22e1207..c0592776 100644
--- a/chrome/browser/android/data_usage/external_data_use_reporter.h
+++ b/chrome/browser/android/data_usage/external_data_use_reporter.h
@@ -10,10 +10,10 @@
 
 #include <memory>
 #include <string>
+#include <unordered_map>
 #include <vector>
 
 #include "base/callback.h"
-#include "base/containers/hash_tables.h"
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/threading/thread_checker.h"
@@ -171,8 +171,9 @@
     size_t operator()(const DataUseReportKey& k) const;
   };
 
-  typedef base::hash_map<DataUseReportKey, DataUseReport, DataUseReportKeyHash>
-      DataUseReports;
+  typedef std::
+      unordered_map<DataUseReportKey, DataUseReport, DataUseReportKeyHash>
+          DataUseReports;
 
   // Maximum size of the data use report buffer. Once this limit is reached, new
   // reports will be ignored.
diff --git a/chrome/browser/android/history_report/data_provider.cc b/chrome/browser/android/history_report/data_provider.cc
index 7fa938b..ce89fe2 100644
--- a/chrome/browser/android/history_report/data_provider.cc
+++ b/chrome/browser/android/history_report/data_provider.cc
@@ -6,8 +6,9 @@
 
 #include <stddef.h>
 
+#include <map>
+
 #include "base/bind.h"
-#include "base/containers/hash_tables.h"
 #include "base/logging.h"
 #include "base/synchronization/waitable_event.h"
 #include "chrome/browser/android/history_report/delta_file_commons.h"
@@ -27,7 +28,7 @@
 namespace {
 static bool g_is_debug = false;
 
-typedef base::hash_map<std::string, BookmarkModel::URLAndTitle*> BookmarkMap;
+using BookmarkMap = std::map<std::string, BookmarkModel::URLAndTitle*>;
 
 struct Context {
   history::HistoryService* history_service;
diff --git a/chrome/browser/android/thumbnail/thumbnail_cache.h b/chrome/browser/android/thumbnail/thumbnail_cache.h
index cd0378f..4422743 100644
--- a/chrome/browser/android/thumbnail/thumbnail_cache.h
+++ b/chrome/browser/android/thumbnail/thumbnail_cache.h
@@ -8,11 +8,11 @@
 #include <stddef.h>
 
 #include <list>
+#include <map>
 #include <set>
 #include <string>
 
 #include "base/bind.h"
-#include "base/containers/hash_tables.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/memory/memory_pressure_listener.h"
@@ -90,8 +90,8 @@
     GURL url_;
   };
 
-  typedef ScopedPtrExpiringCache<TabId, Thumbnail> ExpiringThumbnailCache;
-  typedef base::hash_map<TabId, ThumbnailMetaData> ThumbnailMetaDataMap;
+  using ExpiringThumbnailCache = ScopedPtrExpiringCache<TabId, Thumbnail>;
+  using ThumbnailMetaDataMap = std::map<TabId, ThumbnailMetaData>;
 
   void RemoveFromDisk(TabId tab_id);
   static void RemoveFromDiskTask(TabId tab_id);
diff --git a/chrome/browser/android/vr_shell/BUILD.gn b/chrome/browser/android/vr_shell/BUILD.gn
index b9716ae..dc2cb26 100644
--- a/chrome/browser/android/vr_shell/BUILD.gn
+++ b/chrome/browser/android/vr_shell/BUILD.gn
@@ -56,6 +56,10 @@
     "textures/ui_texture.h",
     "textures/url_bar_texture.cc",
     "textures/url_bar_texture.h",
+    "toolbar_helper.cc",
+    "toolbar_helper.h",
+    "toolbar_state.cc",
+    "toolbar_state.h",
     "ui_browser_interface.h",
     "ui_elements/button.cc",
     "ui_elements/button.h",
@@ -70,10 +74,14 @@
     "ui_elements/screen_dimmer.cc",
     "ui_elements/screen_dimmer.h",
     "ui_elements/simple_textured_element.h",
+    "ui_elements/splash_screen_icon.cc",
+    "ui_elements/splash_screen_icon.h",
     "ui_elements/system_indicator.cc",
     "ui_elements/system_indicator.h",
     "ui_elements/textured_element.cc",
     "ui_elements/textured_element.h",
+    "ui_elements/transience_manager.cc",
+    "ui_elements/transience_manager.h",
     "ui_elements/transient_url_bar.cc",
     "ui_elements/transient_url_bar.h",
     "ui_elements/ui_element.cc",
@@ -95,7 +103,7 @@
     "//chrome/app:generated_resources",
     "//components/security_state/core",
     "//components/strings",
-    "//components/toolbar:vector_icons",
+    "//components/toolbar",
     "//components/url_formatter",
     "//components/vector_icons",
     "//skia",
@@ -203,6 +211,7 @@
     "textures/close_button_texture_unittest.cc",
     "textures/url_bar_texture_unittest.cc",
     "ui_elements/exit_prompt_unittest.cc",
+    "ui_elements/transience_manager_unittest.cc",
     "ui_elements/ui_element_unittest.cc",
     "ui_scene_manager_unittest.cc",
     "ui_scene_unittest.cc",
@@ -213,6 +222,7 @@
     "//base/test:test_support",
     "//components:components_tests_pak",
     "//components/security_state/core",
+    "//components/toolbar:vector_icons",
     "//skia",
     "//testing/gmock",
     "//testing/gtest",
diff --git a/chrome/browser/android/vr_shell/textures/url_bar_texture.cc b/chrome/browser/android/vr_shell/textures/url_bar_texture.cc
index 1e1a85c4..e4e8111 100644
--- a/chrome/browser/android/vr_shell/textures/url_bar_texture.cc
+++ b/chrome/browser/android/vr_shell/textures/url_bar_texture.cc
@@ -8,10 +8,7 @@
 #include "cc/paint/skia_paint_canvas.h"
 #include "chrome/browser/android/vr_shell/color_scheme.h"
 #include "chrome/browser/android/vr_shell/textures/render_text_wrapper.h"
-#include "components/strings/grit/components_strings.h"
-#include "components/toolbar/vector_icons.h"
 #include "components/url_formatter/url_formatter.h"
-#include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/font.h"
 #include "ui/gfx/font_list.h"
@@ -19,7 +16,6 @@
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/gfx/render_text.h"
-#include "ui/gfx/vector_icon_types.h"
 #include "ui/vector_icons/vector_icons.h"
 
 namespace vr_shell {
@@ -33,35 +29,13 @@
 static constexpr float kBackIconHeight = 0.0375;
 static constexpr float kBackIconOffset = 0.005;
 static constexpr float kFieldSpacing = 0.014;
-static constexpr float kSecurityIconHeight = 0.03;
+static constexpr float kSecurityIconSize = 0.03;
 static constexpr float kUrlRightMargin = 0.02;
 static constexpr float kSeparatorWidth = 0.002;
 static constexpr float kChipTextLineMargin = kHeight * 0.3;
 
 using security_state::SecurityLevel;
 
-// See ToolbarModelImpl::GetVectorIcon().
-const struct gfx::VectorIcon& GetSecurityIcon(SecurityLevel level) {
-  switch (level) {
-    case security_state::NONE:
-    case security_state::HTTP_SHOW_WARNING:
-      return toolbar::kHttpIcon;
-    case security_state::EV_SECURE:
-    case security_state::SECURE:
-      return toolbar::kHttpsValidIcon;
-    case security_state::SECURITY_WARNING:
-      // Surface Dubious as Neutral.
-      return toolbar::kHttpIcon;
-    case security_state::SECURE_WITH_POLICY_INSTALLED_CERT:  // ChromeOS only.
-      return ui::kBusinessIcon;
-    case security_state::DANGEROUS:
-      return toolbar::kHttpsInvalidIcon;
-    default:
-      NOTREACHED();
-      return toolbar::kHttpsInvalidIcon;
-  }
-}
-
 // See LocationBarView::GetSecureTextColor().
 SkColor GetSchemeColor(SecurityLevel level, const ColorScheme& color_scheme) {
   switch (level) {
@@ -83,21 +57,6 @@
   }
 }
 
-// See ToolbarModelImpl::GetSecureVerboseText().
-int GetSecurityTextId(SecurityLevel level, bool malware) {
-  switch (level) {
-    case security_state::HTTP_SHOW_WARNING:
-      return IDS_NOT_SECURE_VERBOSE_STATE;
-    case security_state::SECURE:
-      return IDS_SECURE_VERBOSE_STATE;
-    case security_state::DANGEROUS:
-      return (malware ? IDS_DANGEROUS_VERBOSE_STATE
-                      : IDS_NOT_SECURE_VERBOSE_STATE);
-    default:
-      return 0;
-  }
-}
-
 void setEmphasis(vr_shell::RenderTextWrapper* render_text,
                  bool emphasis,
                  const gfx::Range& range,
@@ -120,17 +79,17 @@
 UrlBarTexture::UrlBarTexture(
     bool web_vr,
     const base::Callback<void(UiUnsupportedMode)>& failure_callback)
-    : security_level_(SecurityLevel::DANGEROUS),
-      has_back_button_(!web_vr),
+    : has_back_button_(!web_vr),
       has_security_chip_(false),
       failure_callback_(failure_callback) {}
 
 UrlBarTexture::~UrlBarTexture() = default;
 
-void UrlBarTexture::SetURL(const GURL& gurl) {
-  if (gurl_ != gurl)
-    set_dirty();
-  gurl_ = gurl;
+void UrlBarTexture::SetToolbarState(const ToolbarState& state) {
+  if (state_ == state)
+    return;
+  state_ = state;
+  set_dirty();
 }
 
 void UrlBarTexture::SetHistoryButtonsEnabled(bool can_go_back) {
@@ -139,13 +98,6 @@
   can_go_back_ = can_go_back;
 }
 
-void UrlBarTexture::SetSecurityInfo(SecurityLevel level, bool malware) {
-  if (security_level_ != level || malware_ != malware)
-    set_dirty();
-  security_level_ = level;
-  malware_ = malware;
-}
-
 float UrlBarTexture::ToPixels(float meters) const {
   return meters * size_.width() / kWidth;
 }
@@ -266,36 +218,35 @@
   }
 
   // Site security state icon.
-  if (!gurl_.is_empty()) {
-    left_edge += kFieldSpacing;
-
-    gfx::RectF icon_region(left_edge, kHeight / 2 - kSecurityIconHeight / 2,
-                           kSecurityIconHeight, kSecurityIconHeight);
+  left_edge += kFieldSpacing;
+  if (state_.security_level != security_state::NONE &&
+      state_.vector_icon != nullptr) {
+    gfx::RectF icon_region(left_edge, kHeight / 2 - kSecurityIconSize / 2,
+                           kSecurityIconSize, kSecurityIconSize);
     canvas->save();
     canvas->translate(icon_region.x(), icon_region.y());
-    const gfx::VectorIcon& icon = GetSecurityIcon(security_level_);
-    float icon_scale = kSecurityIconHeight / GetDefaultSizeOfVectorIcon(icon);
+    const gfx::VectorIcon& icon = *state_.vector_icon;
+    float icon_scale = kSecurityIconSize / GetDefaultSizeOfVectorIcon(icon);
     canvas->scale(icon_scale, icon_scale);
     PaintVectorIcon(&gfx_canvas, icon,
-                    GetSchemeColor(security_level_, color_scheme()));
+                    GetSchemeColor(state_.security_level, color_scheme()));
     canvas->restore();
 
     security_hit_region_ = icon_region;
-    left_edge += kSecurityIconHeight + kFieldSpacing;
+    left_edge += kSecurityIconSize + kFieldSpacing;
   }
 
   canvas->restore();
 
   // Draw security chip text (eg. "Not secure") next to the security icon.
-  int chip_string_id = GetSecurityTextId(security_level_, malware_);
-  if (has_security_chip_ && !gurl_.is_empty() && chip_string_id != 0) {
+  if (has_security_chip_ && state_.should_display_url) {
     float chip_max_width = kWidth - left_edge - kUrlRightMargin;
     gfx::Rect text_bounds(ToPixels(left_edge), 0, ToPixels(chip_max_width),
                           ToPixels(kHeight));
 
     int pixel_font_height = texture_size.height() * kFontHeight / kHeight;
-    SkColor chip_color = GetSchemeColor(security_level_, color_scheme());
-    auto chip_text = l10n_util::GetStringUTF16(chip_string_id);
+    SkColor chip_color = GetSchemeColor(state_.security_level, color_scheme());
+    const base::string16& chip_text = state_.secure_verbose_text;
     DCHECK(!chip_text.empty());
 
     gfx::FontList font_list;
@@ -330,16 +281,16 @@
     left_edge += kFieldSpacing + kSeparatorWidth;
   }
 
-  if (!gurl_.is_empty()) {
-    if (last_drawn_gurl_ != gurl_ ||
-        last_drawn_security_level_ != security_level_) {
+  if (state_.should_display_url) {
+    if (!url_render_text_ || last_drawn_gurl_ != state_.gurl ||
+        last_drawn_security_level_ != state_.security_level) {
       float url_x = left_edge;
       float url_width = kWidth - url_x - kUrlRightMargin;
       gfx::Rect text_bounds(ToPixels(url_x), 0, ToPixels(url_width),
                             ToPixels(kHeight));
       RenderUrl(texture_size, text_bounds);
-      last_drawn_gurl_ = gurl_;
-      last_drawn_security_level_ = security_level_;
+      last_drawn_gurl_ = state_.gurl;
+      last_drawn_security_level_ = state_.security_level;
     }
     url_render_text_->Draw(&gfx_canvas);
   }
@@ -349,7 +300,7 @@
                               const gfx::Rect& bounds) {
   url::Parsed parsed;
   const base::string16 text = url_formatter::FormatUrl(
-      gurl_, url_formatter::kFormatUrlOmitAll, net::UnescapeRule::NORMAL,
+      state_.gurl, url_formatter::kFormatUrlOmitAll, net::UnescapeRule::NORMAL,
       &parsed, nullptr, nullptr);
 
   int pixel_font_height = texture_size.height() * kFontHeight / kHeight;
@@ -384,7 +335,7 @@
   }
 
   vr_shell::RenderTextWrapper vr_render_text(render_text.get());
-  ApplyUrlStyling(text, parsed, security_level_, &vr_render_text,
+  ApplyUrlStyling(text, parsed, state_.security_level, &vr_render_text,
                   color_scheme());
 
   url_render_text_ = std::move(render_text);
diff --git a/chrome/browser/android/vr_shell/textures/url_bar_texture.h b/chrome/browser/android/vr_shell/textures/url_bar_texture.h
index 11e18d0..bc24715 100644
--- a/chrome/browser/android/vr_shell/textures/url_bar_texture.h
+++ b/chrome/browser/android/vr_shell/textures/url_bar_texture.h
@@ -12,6 +12,8 @@
 #include "base/macros.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/android/vr_shell/textures/ui_texture.h"
+#include "chrome/browser/android/vr_shell/toolbar_state.h"
+#include "chrome/browser/android/vr_shell/ui_interface.h"
 #include "chrome/browser/android/vr_shell/ui_unsupported_mode.h"
 #include "components/security_state/core/security_state.h"
 #include "ui/gfx/geometry/rect_f.h"
@@ -41,9 +43,8 @@
   gfx::Size GetPreferredTextureSize(int width) const override;
   gfx::SizeF GetDrawnSize() const override;
 
-  void SetURL(const GURL& gurl);
+  void SetToolbarState(const ToolbarState& state);
   void SetHistoryButtonsEnabled(bool can_go_back);
-  void SetSecurityInfo(security_state::SecurityLevel level, bool malware);
 
   bool HitsBackButton(const gfx::PointF& position) const;
   bool HitsUrlBar(const gfx::PointF& position) const;
@@ -76,10 +77,7 @@
   bool back_pressed_ = false;
   bool can_go_back_ = false;
 
-  GURL gurl_;
-  security_state::SecurityLevel security_level_ =
-      security_state::SecurityLevel::NONE;
-  bool malware_ = false;
+  ToolbarState state_;
 
   GURL last_drawn_gurl_;
   bool has_back_button_ = true;
diff --git a/chrome/browser/android/vr_shell/textures/url_bar_texture_unittest.cc b/chrome/browser/android/vr_shell/textures/url_bar_texture_unittest.cc
index 01709d4511..452a5920 100644
--- a/chrome/browser/android/vr_shell/textures/url_bar_texture_unittest.cc
+++ b/chrome/browser/android/vr_shell/textures/url_bar_texture_unittest.cc
@@ -9,7 +9,9 @@
 #include "base/memory/ptr_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/android/vr_shell/textures/render_text_wrapper.h"
+#include "chrome/browser/android/vr_shell/toolbar_state.h"
 #include "components/security_state/core/security_state.h"
+#include "components/toolbar/vector_icons.h"
 #include "components/url_formatter/url_formatter.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -44,7 +46,11 @@
 
   void DrawURL(const GURL& gurl) {
     unsupported_mode_ = UiUnsupportedMode::kCount;
-    SetURL(gurl);
+    ToolbarState state(gurl, SecurityLevel::HTTP_SHOW_WARNING,
+                       &toolbar::kHttpsInvalidIcon,
+                       base::UTF8ToUTF16("Not secure"), true);
+    ASSERT_TRUE(state.should_display_url);
+    SetToolbarState(state);
     sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul(
         texture_size_.width(), texture_size_.height());
     DrawAndLayout(surface->getCanvas(), texture_size_);
@@ -280,4 +286,10 @@
   EXPECT_EQ(UiUnsupportedMode::kCount, texture.unsupported_mode());
 }
 
+TEST(UrlBarTexture, EmptyURL) {
+  TestUrlBarTexture texture;
+  texture.DrawURL(GURL());
+  EXPECT_EQ(UiUnsupportedMode::kCount, texture.unsupported_mode());
+}
+
 }  // namespace vr_shell
diff --git a/chrome/browser/android/vr_shell/toolbar_helper.cc b/chrome/browser/android/vr_shell/toolbar_helper.cc
new file mode 100644
index 0000000..3e1bbd7
--- /dev/null
+++ b/chrome/browser/android/vr_shell/toolbar_helper.cc
@@ -0,0 +1,41 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/android/vr_shell/toolbar_helper.h"
+
+#include "base/memory/ptr_util.h"
+#include "components/toolbar/toolbar_model_impl.h"
+
+class ToolbarModelDelegate;
+
+namespace vr_shell {
+
+namespace {
+
+// This number is arbitrary. For VR, use a number smaller than desktop's 32K, as
+// the URL indicator does not show long URLs.
+constexpr int kMaxURLDisplayChars = 1024;
+
+}  // namespace
+
+ToolbarHelper::ToolbarHelper(UiInterface* ui, ToolbarModelDelegate* delegate)
+    : ui_(ui),
+      toolbar_model_(
+          base::MakeUnique<ToolbarModelImpl>(delegate, kMaxURLDisplayChars)) {}
+
+ToolbarHelper::~ToolbarHelper() {}
+
+void ToolbarHelper::Update() {
+  ToolbarState state(
+      toolbar_model_->GetURL(), toolbar_model_->GetSecurityLevel(true),
+      &toolbar_model_->GetVectorIcon(), toolbar_model_->GetSecureVerboseText(),
+      toolbar_model_->ShouldDisplayURL());
+
+  if (current_state_ == state)
+    return;
+  current_state_ = state;
+  ui_->SetToolbarState(state);
+}
+
+}  // namespace vr_shell
diff --git a/chrome/browser/android/vr_shell/toolbar_helper.h b/chrome/browser/android/vr_shell/toolbar_helper.h
new file mode 100644
index 0000000..c87491d8
--- /dev/null
+++ b/chrome/browser/android/vr_shell/toolbar_helper.h
@@ -0,0 +1,36 @@
+// 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 CHROME_BROWSER_ANDROID_VR_SHELL_TOOLBAR_HELPER_H_
+#define CHROME_BROWSER_ANDROID_VR_SHELL_TOOLBAR_HELPER_H_
+
+#include "chrome/browser/android/vr_shell/toolbar_state.h"
+#include "chrome/browser/android/vr_shell/ui_interface.h"
+
+class ToolbarModel;
+class ToolbarModelDelegate;
+
+namespace vr_shell {
+
+class UiInterface;
+
+// This class houses an instance of ToolbarModel, and queries it when requested,
+// passing a snapshot of the toolbar state to the UI when necessary.
+class ToolbarHelper {
+ public:
+  ToolbarHelper(UiInterface* ui, ToolbarModelDelegate* delegate);
+  virtual ~ToolbarHelper();
+
+  // Poll ToolbarModel and post an update to the UI if state has changed.
+  void Update();
+
+ private:
+  UiInterface* ui_;
+  std::unique_ptr<ToolbarModel> toolbar_model_;
+  ToolbarState current_state_;
+};
+
+}  // namespace vr_shell
+
+#endif  // CHROME_BROWSER_ANDROID_VR_SHELL_TOOLBAR_HELPER_H_
diff --git a/chrome/browser/android/vr_shell/toolbar_state.cc b/chrome/browser/android/vr_shell/toolbar_state.cc
new file mode 100644
index 0000000..d752f7f2
--- /dev/null
+++ b/chrome/browser/android/vr_shell/toolbar_state.cc
@@ -0,0 +1,37 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/android/vr_shell/toolbar_state.h"
+
+namespace vr_shell {
+
+ToolbarState::ToolbarState()
+    : gurl(GURL()),
+      security_level(security_state::SecurityLevel::NONE),
+      vector_icon(nullptr),
+      should_display_url(true) {}
+
+ToolbarState::ToolbarState(const GURL& url,
+                           security_state::SecurityLevel level,
+                           const gfx::VectorIcon* icon,
+                           base::string16 verbose_text,
+                           bool display_url)
+    : gurl(url),
+      security_level(level),
+      vector_icon(icon),
+      secure_verbose_text(verbose_text),
+      should_display_url(display_url) {}
+
+bool ToolbarState::operator==(const ToolbarState& other) const {
+  return (gurl == other.gurl && security_level == other.security_level &&
+          vector_icon == other.vector_icon &&
+          should_display_url == other.should_display_url &&
+          secure_verbose_text == other.secure_verbose_text);
+}
+
+bool ToolbarState::operator!=(const ToolbarState& other) const {
+  return !(*this == other);
+}
+
+}  // namespace vr_shell
diff --git a/chrome/browser/android/vr_shell/toolbar_state.h b/chrome/browser/android/vr_shell/toolbar_state.h
new file mode 100644
index 0000000..a39de5f6
--- /dev/null
+++ b/chrome/browser/android/vr_shell/toolbar_state.h
@@ -0,0 +1,39 @@
+// 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 CHROME_BROWSER_ANDROID_VR_SHELL_TOOLBAR_STATE_H_
+#define CHROME_BROWSER_ANDROID_VR_SHELL_TOOLBAR_STATE_H_
+
+#include "components/security_state/core/security_state.h"
+#include "url/gurl.h"
+
+namespace gfx {
+struct VectorIcon;
+}
+
+namespace vr_shell {
+
+// Passes information obtained from ToolbarModel to the VR UI framework.
+struct ToolbarState {
+ public:
+  ToolbarState();
+  ToolbarState(const GURL& url,
+               security_state::SecurityLevel level,
+               const gfx::VectorIcon* icon,
+               base::string16 verbose_text,
+               bool display_url);
+
+  bool operator==(const ToolbarState& other) const;
+  bool operator!=(const ToolbarState& other) const;
+
+  GURL gurl;
+  security_state::SecurityLevel security_level;
+  const gfx::VectorIcon* vector_icon;
+  base::string16 secure_verbose_text;
+  bool should_display_url;
+};
+
+}  // namespace vr_shell
+
+#endif  // CHROME_BROWSER_ANDROID_VR_SHELL_TOOLBAR_STATE_H_
diff --git a/chrome/browser/android/vr_shell/ui_elements/exclusive_screen_toast.cc b/chrome/browser/android/vr_shell/ui_elements/exclusive_screen_toast.cc
index e43d3e6..1cffe56 100644
--- a/chrome/browser/android/vr_shell/ui_elements/exclusive_screen_toast.cc
+++ b/chrome/browser/android/vr_shell/ui_elements/exclusive_screen_toast.cc
@@ -9,8 +9,9 @@
 
 namespace vr_shell {
 
-ExclusiveScreenToast::ExclusiveScreenToast(int preferred_width)
-    : SimpleTexturedElement(preferred_width) {}
+ExclusiveScreenToast::ExclusiveScreenToast(int preferred_width,
+                                           const base::TimeDelta& timeout)
+    : TransientSimpleTexturedElement(preferred_width, timeout) {}
 
 ExclusiveScreenToast::~ExclusiveScreenToast() = default;
 
diff --git a/chrome/browser/android/vr_shell/ui_elements/exclusive_screen_toast.h b/chrome/browser/android/vr_shell/ui_elements/exclusive_screen_toast.h
index 9bb7f88..4c2d5f3 100644
--- a/chrome/browser/android/vr_shell/ui_elements/exclusive_screen_toast.h
+++ b/chrome/browser/android/vr_shell/ui_elements/exclusive_screen_toast.h
@@ -12,9 +12,9 @@
 namespace vr_shell {
 
 class ExclusiveScreenToast
-    : public SimpleTexturedElement<ExclusiveScreenToastTexture> {
+    : public TransientSimpleTexturedElement<ExclusiveScreenToastTexture> {
  public:
-  explicit ExclusiveScreenToast(int preferred_width);
+  ExclusiveScreenToast(int preferred_width, const base::TimeDelta& timeout);
   ~ExclusiveScreenToast() override;
 
  private:
diff --git a/chrome/browser/android/vr_shell/ui_elements/simple_textured_element.h b/chrome/browser/android/vr_shell/ui_elements/simple_textured_element.h
index 2b42a2e..c4467c9 100644
--- a/chrome/browser/android/vr_shell/ui_elements/simple_textured_element.h
+++ b/chrome/browser/android/vr_shell/ui_elements/simple_textured_element.h
@@ -13,9 +13,9 @@
 #include "chrome/browser/android/vr_shell/textures/exit_warning_texture.h"
 #include "chrome/browser/android/vr_shell/textures/insecure_content_permanent_texture.h"
 #include "chrome/browser/android/vr_shell/textures/insecure_content_transient_texture.h"
-#include "chrome/browser/android/vr_shell/textures/splash_screen_icon_texture.h"
 #include "chrome/browser/android/vr_shell/textures/ui_texture.h"
 #include "chrome/browser/android/vr_shell/ui_elements/textured_element.h"
+#include "chrome/browser/android/vr_shell/ui_elements/transience_manager.h"
 
 namespace vr_shell {
 
@@ -39,12 +39,30 @@
   DISALLOW_COPY_AND_ASSIGN(SimpleTexturedElement);
 };
 
+template <class T>
+class TransientSimpleTexturedElement : public SimpleTexturedElement<T> {
+ public:
+  TransientSimpleTexturedElement(int maximum_width,
+                                 const base::TimeDelta& timeout)
+      : SimpleTexturedElement<T>(maximum_width), transience_(this, timeout) {}
+
+  ~TransientSimpleTexturedElement() override {}
+
+  void SetEnabled(bool enabled) override { transience_.SetEnabled(enabled); }
+
+  TransienceManager* transience() { return &transience_; }
+
+ private:
+  TransienceManager transience_;
+
+  DISALLOW_COPY_AND_ASSIGN(TransientSimpleTexturedElement);
+};
+
 typedef SimpleTexturedElement<ExitWarningTexture> ExitWarning;
 typedef SimpleTexturedElement<InsecureContentPermanentTexture>
     PermanentSecurityWarning;
-typedef SimpleTexturedElement<InsecureContentTransientTexture>
+typedef TransientSimpleTexturedElement<InsecureContentTransientTexture>
     TransientSecurityWarning;
-typedef SimpleTexturedElement<SplashScreenIconTexture> SplashScreenIcon;
 
 }  // namespace vr_shell
 
diff --git a/chrome/browser/android/vr_shell/ui_elements/splash_screen_icon.cc b/chrome/browser/android/vr_shell/ui_elements/splash_screen_icon.cc
new file mode 100644
index 0000000..dc67480
--- /dev/null
+++ b/chrome/browser/android/vr_shell/ui_elements/splash_screen_icon.cc
@@ -0,0 +1,27 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/android/vr_shell/ui_elements/splash_screen_icon.h"
+
+#include "base/memory/ptr_util.h"
+#include "chrome/browser/android/vr_shell/textures/splash_screen_icon_texture.h"
+
+namespace vr_shell {
+
+SplashScreenIcon::SplashScreenIcon(int preferred_width)
+    : TexturedElement(preferred_width),
+      texture_(base::MakeUnique<SplashScreenIconTexture>()) {}
+
+SplashScreenIcon::~SplashScreenIcon() = default;
+
+void SplashScreenIcon::SetSplashScreenIconBitmap(const SkBitmap& bitmap) {
+  texture_->SetSplashScreenIconBitmap(bitmap);
+  UpdateTexture();
+}
+
+UiTexture* SplashScreenIcon::GetTexture() const {
+  return texture_.get();
+}
+
+}  // namespace vr_shell
diff --git a/chrome/browser/android/vr_shell/ui_elements/splash_screen_icon.h b/chrome/browser/android/vr_shell/ui_elements/splash_screen_icon.h
new file mode 100644
index 0000000..feaf6be
--- /dev/null
+++ b/chrome/browser/android/vr_shell/ui_elements/splash_screen_icon.h
@@ -0,0 +1,36 @@
+// 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 CHROME_BROWSER_ANDROID_VR_SHELL_UI_ELEMENTS_SPLASH_SCREEN_ICON_H_
+#define CHROME_BROWSER_ANDROID_VR_SHELL_UI_ELEMENTS_SPLASH_SCREEN_ICON_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "chrome/browser/android/vr_shell/ui_elements/textured_element.h"
+
+class SkBitmap;
+
+namespace vr_shell {
+
+class SplashScreenIconTexture;
+
+class SplashScreenIcon : public TexturedElement {
+ public:
+  explicit SplashScreenIcon(int preferred_width);
+  ~SplashScreenIcon() override;
+
+  void SetSplashScreenIconBitmap(const SkBitmap& bitmap);
+
+ private:
+  UiTexture* GetTexture() const override;
+
+  std::unique_ptr<SplashScreenIconTexture> texture_;
+
+  DISALLOW_COPY_AND_ASSIGN(SplashScreenIcon);
+};
+
+}  // namespace vr_shell
+
+#endif  // CHROME_BROWSER_ANDROID_VR_SHELL_UI_ELEMENTS_SPLASH_SCREEN_ICON_H_
diff --git a/chrome/browser/android/vr_shell/ui_elements/transience_manager.cc b/chrome/browser/android/vr_shell/ui_elements/transience_manager.cc
new file mode 100644
index 0000000..94ce01e
--- /dev/null
+++ b/chrome/browser/android/vr_shell/ui_elements/transience_manager.cc
@@ -0,0 +1,52 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/android/vr_shell/ui_elements/transience_manager.h"
+
+namespace vr_shell {
+
+TransienceManager::TransienceManager(UiElement* element,
+                                     const base::TimeDelta& timeout)
+    : element_(element), timeout_(timeout) {
+  element_->set_visible(false);
+}
+
+void TransienceManager::SetEnabled(bool enabled) {
+  if (enabled_ == enabled)
+    return;
+  enabled_ = enabled;
+  if (enabled) {
+    element_->set_visible(true);
+    StartTimer();
+  } else {
+    element_->set_visible(false);
+    visibility_timer_.Stop();
+  }
+}
+
+void TransienceManager::KickVisibilityIfEnabled() {
+  if (enabled_) {
+    element_->set_visible(true);
+    StartTimer();
+  }
+}
+
+void TransienceManager::EndVisibilityIfEnabled() {
+  if (enabled_) {
+    element_->set_visible(false);
+    visibility_timer_.Stop();
+  }
+}
+
+void TransienceManager::StartTimer() {
+  visibility_timer_.Start(
+      FROM_HERE, timeout_,
+      base::Bind(&TransienceManager::OnTimeout, base::Unretained(this)));
+}
+
+void TransienceManager::OnTimeout() {
+  element_->set_visible(false);
+}
+
+}  // namespace vr_shell
diff --git a/chrome/browser/android/vr_shell/ui_elements/transience_manager.h b/chrome/browser/android/vr_shell/ui_elements/transience_manager.h
new file mode 100644
index 0000000..b248f479
--- /dev/null
+++ b/chrome/browser/android/vr_shell/ui_elements/transience_manager.h
@@ -0,0 +1,37 @@
+// 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 CHROME_BROWSER_ANDROID_VR_SHELL_UI_ELEMENTS_TRANSIENCE_MANAGER_H_
+#define CHROME_BROWSER_ANDROID_VR_SHELL_UI_ELEMENTS_TRANSIENCE_MANAGER_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "base/timer/timer.h"
+#include "chrome/browser/android/vr_shell/ui_elements/ui_element.h"
+
+namespace vr_shell {
+
+class TransienceManager {
+ public:
+  TransienceManager(UiElement* element, const base::TimeDelta& timeout);
+  virtual ~TransienceManager() = default;
+
+  void SetEnabled(bool enabled);
+  void KickVisibilityIfEnabled();
+  void EndVisibilityIfEnabled();
+
+ private:
+  void StartTimer();
+  void OnTimeout();
+
+  UiElement* element_;
+  base::TimeDelta timeout_;
+  bool enabled_ = false;
+  base::OneShotTimer visibility_timer_;
+};
+
+}  // namespace vr_shell
+
+#endif  // CHROME_BROWSER_ANDROID_VR_SHELL_UI_ELEMENTS_TRANSIENCE_MANAGER_H_
diff --git a/chrome/browser/android/vr_shell/ui_elements/transience_manager_unittest.cc b/chrome/browser/android/vr_shell/ui_elements/transience_manager_unittest.cc
new file mode 100644
index 0000000..6fc1e72
--- /dev/null
+++ b/chrome/browser/android/vr_shell/ui_elements/transience_manager_unittest.cc
@@ -0,0 +1,59 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/android/vr_shell/ui_elements/transience_manager.h"
+
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/message_loop/message_loop.h"
+#include "base/test/scoped_mock_time_message_loop_task_runner.h"
+#include "chrome/browser/android/vr_shell/ui_elements/ui_element.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace vr_shell {
+
+TEST(TransienceManager, Visibility) {
+  base::MessageLoop message_loop_;
+  base::ScopedMockTimeMessageLoopTaskRunner task_runner_;
+
+  UiElement element;
+
+  TransienceManager transience(&element, base::TimeDelta::FromSeconds(10));
+  EXPECT_EQ(element.visible(), false);
+
+  transience.KickVisibilityIfEnabled();
+  EXPECT_EQ(element.visible(), false);
+
+  // Enable and disable, making sure the element appears and disappears.
+  transience.SetEnabled(true);
+  EXPECT_EQ(element.visible(), true);
+  transience.SetEnabled(false);
+  EXPECT_EQ(element.visible(), false);
+
+  // Enable, and ensure that the element transiently disappears.
+  transience.SetEnabled(true);
+  EXPECT_EQ(element.visible(), true);
+  task_runner_->FastForwardUntilNoTasksRemain();
+  EXPECT_EQ(element.visible(), false);
+
+  // Kick visibility, and ensure that the element transiently disappears.
+  transience.KickVisibilityIfEnabled();
+  EXPECT_EQ(element.visible(), true);
+  task_runner_->FastForwardUntilNoTasksRemain();
+  EXPECT_EQ(element.visible(), false);
+
+  // Kick visibility, and ensure that ending visibility hides the element.
+  transience.KickVisibilityIfEnabled();
+  EXPECT_EQ(element.visible(), true);
+  transience.EndVisibilityIfEnabled();
+  EXPECT_EQ(element.visible(), false);
+
+  // Kick visibility, and ensure that disabling hides the element.
+  transience.KickVisibilityIfEnabled();
+  EXPECT_EQ(element.visible(), true);
+  transience.SetEnabled(false);
+  EXPECT_EQ(element.visible(), false);
+}
+
+}  // namespace vr_shell
diff --git a/chrome/browser/android/vr_shell/ui_elements/transient_url_bar.cc b/chrome/browser/android/vr_shell/ui_elements/transient_url_bar.cc
index 6c960ca6..ad4c4e5 100644
--- a/chrome/browser/android/vr_shell/ui_elements/transient_url_bar.cc
+++ b/chrome/browser/android/vr_shell/ui_elements/transient_url_bar.cc
@@ -11,9 +11,11 @@
 
 TransientUrlBar::TransientUrlBar(
     int preferred_width,
+    const base::TimeDelta& timeout,
     const base::Callback<void(UiUnsupportedMode)>& failure_callback)
     : TexturedElement(preferred_width),
-      texture_(base::MakeUnique<UrlBarTexture>(true, failure_callback)) {}
+      texture_(base::MakeUnique<UrlBarTexture>(true, failure_callback)),
+      transience_(this, timeout) {}
 
 TransientUrlBar::~TransientUrlBar() = default;
 
@@ -21,15 +23,12 @@
   return texture_.get();
 }
 
-void TransientUrlBar::SetURL(const GURL& gurl) {
-  texture_->SetURL(gurl);
-  UpdateTexture();
+void TransientUrlBar::SetEnabled(bool enabled) {
+  transience_.SetEnabled(enabled);
 }
 
-void TransientUrlBar::SetSecurityInfo(security_state::SecurityLevel level,
-                                      bool malware) {
-  texture_->SetSecurityInfo(level, malware);
-  UpdateTexture();
+void TransientUrlBar::SetToolbarState(const ToolbarState& state) {
+  texture_->SetToolbarState(state);
 }
 
 }  // namespace vr_shell
diff --git a/chrome/browser/android/vr_shell/ui_elements/transient_url_bar.h b/chrome/browser/android/vr_shell/ui_elements/transient_url_bar.h
index 9978cea..b28d1662 100644
--- a/chrome/browser/android/vr_shell/ui_elements/transient_url_bar.h
+++ b/chrome/browser/android/vr_shell/ui_elements/transient_url_bar.h
@@ -11,6 +11,7 @@
 #include "base/macros.h"
 #include "base/time/time.h"
 #include "chrome/browser/android/vr_shell/ui_elements/textured_element.h"
+#include "chrome/browser/android/vr_shell/ui_elements/transience_manager.h"
 #include "chrome/browser/android/vr_shell/ui_unsupported_mode.h"
 #include "components/security_state/core/security_state.h"
 #include "url/gurl.h"
@@ -18,6 +19,7 @@
 namespace vr_shell {
 
 class UrlBarTexture;
+struct ToolbarState;
 
 // The non-interactive URL bar that shows for some time when WebVR content is
 // autopresented.
@@ -25,16 +27,19 @@
  public:
   TransientUrlBar(
       int preferred_width,
+      const base::TimeDelta& timeout,
       const base::Callback<void(UiUnsupportedMode)>& failure_callback);
   ~TransientUrlBar() override;
 
-  void SetURL(const GURL& gurl);
-  void SetSecurityInfo(security_state::SecurityLevel level, bool malware);
+  void SetEnabled(bool enabled) override;
+
+  void SetToolbarState(const ToolbarState& state);
 
  private:
   UiTexture* GetTexture() const override;
 
   std::unique_ptr<UrlBarTexture> texture_;
+  TransienceManager transience_;
 
   DISALLOW_COPY_AND_ASSIGN(TransientUrlBar);
 };
diff --git a/chrome/browser/android/vr_shell/ui_elements/url_bar.cc b/chrome/browser/android/vr_shell/ui_elements/url_bar.cc
index 3ad755b..40dede3 100644
--- a/chrome/browser/android/vr_shell/ui_elements/url_bar.cc
+++ b/chrome/browser/android/vr_shell/ui_elements/url_bar.cc
@@ -88,8 +88,8 @@
   set_visible(enabled);
 }
 
-void UrlBar::SetURL(const GURL& gurl) {
-  texture_->SetURL(gurl);
+void UrlBar::SetToolbarState(const ToolbarState& state) {
+  texture_->SetToolbarState(state);
 }
 
 void UrlBar::SetHistoryButtonsEnabled(bool can_go_back) {
@@ -97,11 +97,6 @@
   texture_->SetHistoryButtonsEnabled(can_go_back_);
 }
 
-void UrlBar::SetSecurityInfo(security_state::SecurityLevel level,
-                             bool malware) {
-  texture_->SetSecurityInfo(level, malware);
-}
-
 void UrlBar::OnStateUpdated(const gfx::PointF& position) {
   const bool hovered = texture_->HitsBackButton(position);
   const bool pressed = hovered ? down_ : false;
diff --git a/chrome/browser/android/vr_shell/ui_elements/url_bar.h b/chrome/browser/android/vr_shell/ui_elements/url_bar.h
index 730c2b1..f5e116d 100644
--- a/chrome/browser/android/vr_shell/ui_elements/url_bar.h
+++ b/chrome/browser/android/vr_shell/ui_elements/url_bar.h
@@ -18,6 +18,7 @@
 namespace vr_shell {
 
 class UrlBarTexture;
+struct ToolbarState;
 
 class UrlBar : public TexturedElement {
  public:
@@ -38,8 +39,7 @@
   void SetEnabled(bool enabled) override;
 
   void SetHistoryButtonsEnabled(bool can_go_back);
-  void SetURL(const GURL& gurl);
-  void SetSecurityInfo(security_state::SecurityLevel level, bool malware);
+  void SetToolbarState(const ToolbarState& state);
 
  private:
   void UpdateTexture() override;
diff --git a/chrome/browser/android/vr_shell/ui_interface.h b/chrome/browser/android/vr_shell/ui_interface.h
index f46ccce..29c3bf3 100644
--- a/chrome/browser/android/vr_shell/ui_interface.h
+++ b/chrome/browser/android/vr_shell/ui_interface.h
@@ -7,11 +7,12 @@
 
 #include "components/security_state/core/security_state.h"
 
-class GURL;
 class SkBitmap;
 
 namespace vr_shell {
 
+struct ToolbarState;
+
 // This class manages the communication of browser state from VR shell to the
 // HTML UI. State information is asynchronous and unidirectional.
 class UiInterface {
@@ -27,10 +28,8 @@
   virtual ~UiInterface() {}
 
   virtual void SetWebVrMode(bool enabled, bool show_toast) = 0;
-  virtual void SetURL(const GURL& url) = 0;
   virtual void SetFullscreen(bool enabled) = 0;
-  virtual void SetSecurityInfo(security_state::SecurityLevel level,
-                               bool fails_malware_check) = 0;
+  virtual void SetToolbarState(const ToolbarState& state) = 0;
   virtual void SetIncognito(bool enabled) = 0;
   virtual void SetWebVrSecureOrigin(bool secure) = 0;
   virtual void SetLoading(bool loading) = 0;
diff --git a/chrome/browser/android/vr_shell/ui_scene_manager.cc b/chrome/browser/android/vr_shell/ui_scene_manager.cc
index 3dd3b77..dca383c 100644
--- a/chrome/browser/android/vr_shell/ui_scene_manager.cc
+++ b/chrome/browser/android/vr_shell/ui_scene_manager.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/android/vr_shell/ui_elements/exit_prompt_backplane.h"
 #include "chrome/browser/android/vr_shell/ui_elements/loading_indicator.h"
 #include "chrome/browser/android/vr_shell/ui_elements/screen_dimmer.h"
+#include "chrome/browser/android/vr_shell/ui_elements/splash_screen_icon.h"
 #include "chrome/browser/android/vr_shell/ui_elements/system_indicator.h"
 #include "chrome/browser/android/vr_shell/ui_elements/transient_url_bar.h"
 #include "chrome/browser/android/vr_shell/ui_elements/ui_element.h"
@@ -138,6 +139,7 @@
       scene_(scene),
       in_cct_(in_cct),
       web_vr_mode_(in_web_vr),
+      web_vr_autopresentation_(web_vr_autopresentation_expected),
       web_vr_autopresentation_expected_(web_vr_autopresentation_expected),
       weak_ptr_factory_(this) {
   CreateSplashScreen();
@@ -153,7 +155,6 @@
   CreateToasts();
 
   ConfigureScene();
-  ConfigureSecurityWarnings();
 }
 
 UiSceneManager::~UiSceneManager() {}
@@ -193,7 +194,10 @@
   permanent_security_warning_ = element.get();
   scene_->AddUiElement(std::move(element));
 
-  element = base::MakeUnique<TransientSecurityWarning>(1024);
+  auto transient_warning = base::MakeUnique<TransientSecurityWarning>(
+      1024, base::TimeDelta::FromSeconds(kWarningTimeoutSeconds));
+  transient_security_warning_ = transient_warning.get();
+  element = std::move(transient_warning);
   element->set_debug_id(kWebVrTransientHttpSecurityWarning);
   element->set_id(AllocateId());
   element->set_fill(vr_shell::Fill::NONE);
@@ -203,7 +207,6 @@
   element->set_visible(false);
   element->set_hit_testable(false);
   element->set_lock_to_fov(true);
-  transient_security_warning_ = element.get();
   scene_->AddUiElement(std::move(element));
 
   element = base::MakeUnique<ExitWarning>(1024);
@@ -369,7 +372,7 @@
 
 void UiSceneManager::CreateTransientUrlBar() {
   auto url_bar = base::MakeUnique<TransientUrlBar>(
-      512,
+      512, base::TimeDelta::FromSeconds(kTransientUrlBarTimeoutSeconds),
       base::Bind(&UiSceneManager::OnUnsupportedMode, base::Unretained(this)));
   url_bar->set_debug_id(kTransientUrlBar);
   url_bar->set_id(AllocateId());
@@ -433,8 +436,8 @@
 }
 
 void UiSceneManager::CreateToasts() {
-  std::unique_ptr<UiElement> element =
-      base::MakeUnique<ExclusiveScreenToast>(512);
+  auto element = base::MakeUnique<ExclusiveScreenToast>(
+      512, base::TimeDelta::FromSeconds(kToastTimeoutSeconds));
   element->set_debug_id(kExclusiveScreenToast);
   element->set_id(AllocateId());
   element->set_fill(vr_shell::Fill::NONE);
@@ -453,22 +456,28 @@
   if (web_vr_mode_ == web_vr && web_vr_show_toast_ == show_toast) {
     return;
   }
+
   web_vr_mode_ = web_vr;
-  ConfigureTransientUrlBar();
-  scene_->set_showing_splash_screen(false);
   web_vr_autopresentation_expected_ = false;
   web_vr_show_toast_ = show_toast;
-  toast_state_ = SET_FOR_WEB_VR;
+  if (!web_vr_mode_)
+    web_vr_autopresentation_ = false;
+  scene_->set_showing_splash_screen(false);
   ConfigureScene();
-  ConfigureSecurityWarnings();
-  ConfigureExclusiveScreenToast();
+
+  // Because we may be transitioning from and to fullscreen, where the toast is
+  // also shown, explicitly kick or end visibility here.
+  if (web_vr) {
+    exclusive_screen_toast_->transience()->KickVisibilityIfEnabled();
+  } else {
+    exclusive_screen_toast_->transience()->EndVisibilityIfEnabled();
+  }
 }
 
 void UiSceneManager::ConfigureScene() {
   // Splash screen.
   scene_->set_showing_splash_screen(web_vr_autopresentation_expected_);
-  splash_screen_icon_->SetEnabled(!web_vr_mode_ &&
-                                  web_vr_autopresentation_expected_);
+  splash_screen_icon_->SetEnabled(web_vr_autopresentation_expected_);
 
   // Exit warning.
   exit_warning_->SetEnabled(scene_->is_exiting());
@@ -531,12 +540,11 @@
                                 -kBackgroundDistanceMultiplier);
   UpdateBackgroundColor();
 
-  // Configure other subsystems here as well. Ultimately, it would be nice if we
-  // could configure all elements through ConfigureScene(), as the exact
-  // conditions that control each element are getting complicated. More systems
-  // should move in here, such that a single method call can update the entire
-  // scene. The drawback is slightly more overhead for individual scene
-  // reconfigurations.
+  transient_url_bar_->SetEnabled(web_vr_autopresentation_ &&
+                                 !scene_->showing_splash_screen());
+
+  ConfigureExclusiveScreenToast();
+  ConfigureSecurityWarnings();
   ConfigureIndicators();
 }
 
@@ -551,7 +559,7 @@
 }
 
 void UiSceneManager::SetSplashScreenIcon(const SkBitmap& bitmap) {
-  splash_screen_icon_->GetDerivedTexture()->SetSplashScreenIconBitmap(bitmap);
+  splash_screen_icon_->SetSplashScreenIconBitmap(bitmap);
   ConfigureScene();
 }
 
@@ -581,6 +589,8 @@
 }
 
 void UiSceneManager::SetWebVrSecureOrigin(bool secure) {
+  if (secure_origin_ == secure)
+    return;
   secure_origin_ = secure;
   ConfigureSecurityWarnings();
 }
@@ -611,22 +621,13 @@
   if (fullscreen_ == fullscreen)
     return;
   fullscreen_ = fullscreen;
-  toast_state_ = SET_FOR_FULLSCREEN;
   ConfigureScene();
-  ConfigureExclusiveScreenToast();
 }
 
 void UiSceneManager::ConfigureSecurityWarnings() {
   bool enabled = web_vr_mode_ && !secure_origin_;
-  permanent_security_warning_->set_visible(enabled);
-  transient_security_warning_->set_visible(enabled);
-  if (enabled) {
-    security_warning_timer_.Start(
-        FROM_HERE, base::TimeDelta::FromSeconds(kWarningTimeoutSeconds), this,
-        &UiSceneManager::OnSecurityWarningTimer);
-  } else {
-    security_warning_timer_.Stop();
-  }
+  permanent_security_warning_->SetEnabled(enabled);
+  transient_security_warning_->SetEnabled(enabled);
 }
 
 void UiSceneManager::ConfigureIndicators() {
@@ -663,17 +664,9 @@
 }
 
 void UiSceneManager::ConfigureExclusiveScreenToast() {
-  bool toast_visible = false;
-  switch (toast_state_) {
-    case SET_FOR_WEB_VR:
-      toast_visible = web_vr_show_toast_;
-      break;
-    case SET_FOR_FULLSCREEN:
-      toast_visible = fullscreen_;
-      break;
-    case UNCHANGED:
-      return;
-  }
+  exclusive_screen_toast_->SetEnabled((fullscreen_ && !web_vr_mode_) ||
+                                      (web_vr_mode_ && web_vr_show_toast_));
+
   if (fullscreen_ && !web_vr_mode_) {
     // Do not set size again. The size might have been changed by the backing
     // texture size in UpdateElementSize.
@@ -697,39 +690,6 @@
         gfx::Quaternion(gfx::Vector3dF(1, 0, 0), kWebVrAngleRadians));
     exclusive_screen_toast_->set_lock_to_fov(true);
   }
-  exclusive_screen_toast_->set_visible(toast_visible);
-  if (toast_visible) {
-    exclusive_screen_toast_timer_.Start(
-        FROM_HERE, base::TimeDelta::FromSeconds(kToastTimeoutSeconds), this,
-        &UiSceneManager::OnExclusiveScreenToastTimer);
-  } else {
-    exclusive_screen_toast_timer_.Stop();
-  }
-  toast_state_ = UNCHANGED;
-}
-
-void UiSceneManager::OnSecurityWarningTimer() {
-  transient_security_warning_->set_visible(false);
-}
-
-void UiSceneManager::ConfigureTransientUrlBar() {
-  bool enabled = web_vr_mode_ && web_vr_autopresentation_expected_;
-  transient_url_bar_->set_visible(enabled);
-  if (enabled) {
-    transient_url_bar_timer_.Start(
-        FROM_HERE, base::TimeDelta::FromSeconds(kTransientUrlBarTimeoutSeconds),
-        this, &UiSceneManager::OnTransientUrlBarTimer);
-  } else {
-    transient_url_bar_timer_.Stop();
-  }
-}
-
-void UiSceneManager::OnTransientUrlBarTimer() {
-  transient_url_bar_->set_visible(false);
-}
-
-void UiSceneManager::OnExclusiveScreenToastTimer() {
-  exclusive_screen_toast_->set_visible(false);
 }
 
 void UiSceneManager::OnBackButtonClicked() {
@@ -770,15 +730,9 @@
   OnUnsupportedMode(UiUnsupportedMode::kUnhandledPageInfo);
 }
 
-void UiSceneManager::SetURL(const GURL& gurl) {
-  url_bar_->SetURL(gurl);
-  transient_url_bar_->SetURL(gurl);
-}
-
-void UiSceneManager::SetSecurityInfo(security_state::SecurityLevel level,
-                                     bool malware) {
-  url_bar_->SetSecurityInfo(level, malware);
-  transient_url_bar_->SetSecurityInfo(level, malware);
+void UiSceneManager::SetToolbarState(const ToolbarState& state) {
+  url_bar_->SetToolbarState(state);
+  transient_url_bar_->SetToolbarState(state);
 }
 
 void UiSceneManager::SetLoading(bool loading) {
diff --git a/chrome/browser/android/vr_shell/ui_scene_manager.h b/chrome/browser/android/vr_shell/ui_scene_manager.h
index 5581043..81e5615 100644
--- a/chrome/browser/android/vr_shell/ui_scene_manager.h
+++ b/chrome/browser/android/vr_shell/ui_scene_manager.h
@@ -8,7 +8,6 @@
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
-#include "base/timer/timer.h"
 #include "base/values.h"
 #include "chrome/browser/android/vr_shell/color_scheme.h"
 #include "chrome/browser/android/vr_shell/ui_elements/simple_textured_element.h"
@@ -18,7 +17,9 @@
 
 namespace vr_shell {
 
+class ExclusiveScreenToast;
 class LoadingIndicator;
+class SplashScreenIcon;
 class TransientUrlBar;
 class UiBrowserInterface;
 class UiElement;
@@ -38,10 +39,9 @@
 
   void SetFullscreen(bool fullscreen);
   void SetIncognito(bool incognito);
-  void SetURL(const GURL& gurl);
+  void SetToolbarState(const ToolbarState& state);
   void SetWebVrSecureOrigin(bool secure);
   void SetWebVrMode(bool web_vr, bool show_toast);
-  void SetSecurityInfo(security_state::SecurityLevel level, bool malware);
   void SetLoading(bool loading);
   void SetLoadProgress(float progress);
   void SetIsExiting();
@@ -63,11 +63,6 @@
   void OnExitPromptPrimaryButtonClickedForTesting();
 
  private:
-  enum ToastState {
-    UNCHANGED = 0,
-    SET_FOR_WEB_VR,
-    SET_FOR_FULLSCREEN,
-  };
   void CreateScreenDimmer();
   void CreateSecurityWarnings();
   void CreateSystemIndicators();
@@ -82,14 +77,10 @@
 
   void ConfigureScene();
   void ConfigureSecurityWarnings();
-  void ConfigureTransientUrlBar();
-  void ConfigureIndicators();
   void ConfigureExclusiveScreenToast();
+  void ConfigureIndicators();
   void UpdateBackgroundColor();
   void CloseExitPrompt();
-  void OnSecurityWarningTimer();
-  void OnTransientUrlBarTimer();
-  void OnExclusiveScreenToastTimer();
   void OnBackButtonClicked();
   void OnSecurityIconClicked();
   void OnExitPromptPrimaryButtonClicked();
@@ -106,8 +97,8 @@
 
   // UI element pointers (not owned by the scene manager).
   UiElement* permanent_security_warning_ = nullptr;
-  UiElement* transient_security_warning_ = nullptr;
-  UiElement* exclusive_screen_toast_ = nullptr;
+  TransientSecurityWarning* transient_security_warning_ = nullptr;
+  ExclusiveScreenToast* exclusive_screen_toast_ = nullptr;
   UiElement* exit_prompt_ = nullptr;
   UiElement* exit_prompt_backplane_ = nullptr;
   UiElement* exit_warning_ = nullptr;
@@ -131,6 +122,7 @@
   bool in_cct_;
   bool web_vr_mode_;
   bool web_vr_show_toast_ = false;
+  bool web_vr_autopresentation_ = false;
   bool web_vr_autopresentation_expected_ = false;
   bool secure_origin_ = false;
   bool fullscreen_ = false;
@@ -140,7 +132,6 @@
   bool screen_capturing_ = false;
   bool location_access_ = false;
   bool bluetooth_connected_ = false;
-  ToastState toast_state_ = UNCHANGED;
 
   int next_available_id_ = 1;
 
@@ -148,10 +139,6 @@
   std::vector<UiElement*> background_elements_;
   std::vector<UiElement*> control_elements_;
 
-  base::OneShotTimer security_warning_timer_;
-  base::OneShotTimer transient_url_bar_timer_;
-  base::OneShotTimer exclusive_screen_toast_timer_;
-
   base::WeakPtrFactory<UiSceneManager> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(UiSceneManager);
diff --git a/chrome/browser/android/vr_shell/ui_scene_manager_unittest.cc b/chrome/browser/android/vr_shell/ui_scene_manager_unittest.cc
index c8a4081..197bfea 100644
--- a/chrome/browser/android/vr_shell/ui_scene_manager_unittest.cc
+++ b/chrome/browser/android/vr_shell/ui_scene_manager_unittest.cc
@@ -163,7 +163,7 @@
   EXPECT_FALSE(IsVisible(kWebVrTransientHttpSecurityWarning));
 }
 
-TEST_F(UiSceneManagerTest, ToastVisibility) {
+TEST_F(UiSceneManagerTest, ToastStateTransitions) {
   // Tests toast not showing when directly entering VR though WebVR
   // presentation.
   MakeManager(kNotInCct, kInWebVr);
@@ -188,7 +188,27 @@
   EXPECT_FALSE(IsVisible(kExclusiveScreenToast));
 
   manager_->SetWebVrMode(false, true);
+  EXPECT_FALSE(IsVisible(kExclusiveScreenToast));
+}
+
+TEST_F(UiSceneManagerTest, ToastTransience) {
+  base::ScopedMockTimeMessageLoopTaskRunner task_runner_;
+
+  MakeManager(kNotInCct, kNotInWebVr);
+  EXPECT_FALSE(IsVisible(kExclusiveScreenToast));
+
+  manager_->SetFullscreen(true);
   EXPECT_TRUE(IsVisible(kExclusiveScreenToast));
+  task_runner_->FastForwardUntilNoTasksRemain();
+  EXPECT_FALSE(IsVisible(kExclusiveScreenToast));
+
+  manager_->SetWebVrMode(true, true);
+  EXPECT_TRUE(IsVisible(kExclusiveScreenToast));
+  task_runner_->FastForwardUntilNoTasksRemain();
+  EXPECT_FALSE(IsVisible(kExclusiveScreenToast));
+
+  manager_->SetWebVrMode(false, false);
+  EXPECT_FALSE(IsVisible(kExclusiveScreenToast));
 }
 
 TEST_F(UiSceneManagerTest, CloseButtonVisibleInCctFullscreen) {
@@ -277,8 +297,9 @@
 }
 
 TEST_F(UiSceneManagerTest, WebVrAutopresented) {
-  MakeAutoPresentedManager();
+  base::ScopedMockTimeMessageLoopTaskRunner task_runner_;
 
+  MakeAutoPresentedManager();
   manager_->SetWebVrSecureOrigin(true);
 
   // Initially, we should only show the splash screen.
@@ -287,9 +308,12 @@
 
   // Enter WebVR with autopresentation.
   manager_->SetWebVrMode(true, false);
-
   VerifyElementsVisible("Autopresented",
                         std::set<UiElementDebugId>{kTransientUrlBar});
+
+  // Make sure the transient URL bar times out.
+  task_runner_->FastForwardUntilNoTasksRemain();
+  EXPECT_FALSE(IsVisible(kTransientUrlBar));
 }
 
 TEST_F(UiSceneManagerTest, UiUpdatesForFullscreenChanges) {
diff --git a/chrome/browser/android/vr_shell/vr_gl_thread.cc b/chrome/browser/android/vr_shell/vr_gl_thread.cc
index 2762eca..a703d1b3 100644
--- a/chrome/browser/android/vr_shell/vr_gl_thread.cc
+++ b/chrome/browser/android/vr_shell/vr_gl_thread.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "chrome/browser/android/vr_shell/toolbar_state.h"
 #include "chrome/browser/android/vr_shell/ui_interface.h"
 #include "chrome/browser/android/vr_shell/ui_scene.h"
 #include "chrome/browser/android/vr_shell/ui_scene_manager.h"
@@ -179,18 +180,11 @@
                                                 weak_scene_manager_, loading));
 }
 
-void VrGLThread::SetSecurityInfo(security_state::SecurityLevel level,
-                                 bool malware) {
+void VrGLThread::SetToolbarState(const ToolbarState& state) {
   WaitUntilThreadStarted();
-  task_runner()->PostTask(FROM_HERE,
-                          base::Bind(&UiSceneManager::SetSecurityInfo,
-                                     weak_scene_manager_, level, malware));
-}
-
-void VrGLThread::SetURL(const GURL& gurl) {
-  WaitUntilThreadStarted();
-  task_runner()->PostTask(FROM_HERE, base::Bind(&UiSceneManager::SetURL,
-                                                weak_scene_manager_, gurl));
+  task_runner()->PostTask(
+      FROM_HERE,
+      base::Bind(&UiSceneManager::SetToolbarState, weak_scene_manager_, state));
 }
 
 void VrGLThread::SetWebVrMode(bool enabled, bool show_toast) {
diff --git a/chrome/browser/android/vr_shell/vr_gl_thread.h b/chrome/browser/android/vr_shell/vr_gl_thread.h
index 538d89c..5bbcde9 100644
--- a/chrome/browser/android/vr_shell/vr_gl_thread.h
+++ b/chrome/browser/android/vr_shell/vr_gl_thread.h
@@ -16,8 +16,6 @@
 #include "chrome/browser/android/vr_shell/ui_interface.h"
 #include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr_types.h"
 
-class GURL;
-
 namespace vr_shell {
 
 class UiScene;
@@ -75,9 +73,7 @@
   void SetHistoryButtonsEnabled(bool can_go_back, bool can_go_forward) override;
   void SetLoadProgress(float progress) override;
   void SetLoading(bool loading) override;
-  void SetSecurityInfo(security_state::SecurityLevel level,
-                       bool malware) override;
-  void SetURL(const GURL& gurl) override;
+  void SetToolbarState(const ToolbarState& state) override;
   void SetWebVrMode(bool enabled, bool show_toast) override;
   void SetWebVrSecureOrigin(bool secure) override;
   void SetVideoCapturingIndicator(bool enabled) override;
diff --git a/chrome/browser/android/vr_shell/vr_shell.cc b/chrome/browser/android/vr_shell/vr_shell.cc
index 07e04bf..b659625 100644
--- a/chrome/browser/android/vr_shell/vr_shell.cc
+++ b/chrome/browser/android/vr_shell/vr_shell.cc
@@ -21,6 +21,7 @@
 #include "base/values.h"
 #include "chrome/browser/android/tab_android.h"
 #include "chrome/browser/android/vr_shell/android_ui_gesture_target.h"
+#include "chrome/browser/android/vr_shell/toolbar_helper.h"
 #include "chrome/browser/android/vr_shell/ui_interface.h"
 #include "chrome/browser/android/vr_shell/ui_scene_manager.h"
 #include "chrome/browser/android/vr_shell/vr_compositor.h"
@@ -117,6 +118,7 @@
       for_web_vr, web_vr_autopresentation_expected, in_cct,
       reprojected_rendering_, HasDaydreamSupport(env));
   ui_ = gl_thread_.get();
+  toolbar_ = base::MakeUnique<ToolbarHelper>(ui_, this);
 
   base::Thread::Options options(base::MessageLoop::TYPE_DEFAULT, 0);
   options.priority = base::ThreadPriority::DISPLAY;
@@ -163,8 +165,8 @@
     return;
   }
   input_manager_ = base::MakeUnique<VrInputManager>(web_contents_);
-  vr_web_contents_observer_ =
-      base::MakeUnique<VrWebContentsObserver>(web_contents_, ui_, this);
+  vr_web_contents_observer_ = base::MakeUnique<VrWebContentsObserver>(
+      web_contents_, this, ui_, toolbar_.get());
   // TODO(billorr): Make VrMetricsHelper tab-aware and able to track multiple
   // tabs. crbug.com/684661
   metrics_helper_ = base::MakeUnique<VrMetricsHelper>(web_contents_);
@@ -173,14 +175,13 @@
 }
 
 void VrShell::SetUiState() {
+  toolbar_->Update();
+
   if (!web_contents_) {
-    // TODO(mthiesse): Properly handle native page URLs.
-    ui_->SetURL(GURL());
     ui_->SetLoading(false);
     ui_->SetFullscreen(false);
     ui_->SetIncognito(false);
   } else {
-    ui_->SetURL(web_contents_->GetVisibleURL());
     ui_->SetLoading(web_contents_->IsLoading());
     ui_->SetFullscreen(web_contents_->IsFullscreen());
     ui_->SetIncognito(web_contents_->GetBrowserContext()->IsOffTheRecord());
@@ -714,6 +715,10 @@
   return Java_VrShellImpl_hasDaydreamSupport(env, j_vr_shell_.obj());
 }
 
+content::WebContents* VrShell::GetActiveWebContents() const {
+  return web_contents_;
+}
+
 // ----------------------------------------------------------------------------
 // Native JNI methods
 // ----------------------------------------------------------------------------
diff --git a/chrome/browser/android/vr_shell/vr_shell.h b/chrome/browser/android/vr_shell/vr_shell.h
index 2d2a627f..df45efc 100644
--- a/chrome/browser/android/vr_shell/vr_shell.h
+++ b/chrome/browser/android/vr_shell/vr_shell.h
@@ -17,6 +17,7 @@
 #include "chrome/browser/android/vr_shell/ui_interface.h"
 #include "chrome/browser/android/vr_shell/ui_unsupported_mode.h"
 #include "chrome/browser/android/vr_shell/vr_controller_model.h"
+#include "chrome/browser/ui/toolbar/chrome_toolbar_model_delegate.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "device/vr/android/gvr/cardboard_gamepad_data_provider.h"
 #include "device/vr/android/gvr/gvr_delegate.h"
@@ -39,6 +40,7 @@
 namespace vr_shell {
 
 class AndroidUiGestureTarget;
+class ToolbarHelper;
 class UiInterface;
 class VrCompositor;
 class VrGLThread;
@@ -62,7 +64,8 @@
 // must only be used on the UI thread.
 class VrShell : public device::GvrDelegate,
                 device::GvrGamepadDataProvider,
-                device::CardboardGamepadDataProvider {
+                device::CardboardGamepadDataProvider,
+                public ChromeToolbarModelDelegate {
  public:
   VrShell(JNIEnv* env,
           jobject obj,
@@ -175,6 +178,9 @@
   void RegisterCardboardGamepadDataFetcher(
       device::CardboardGamepadDataFetcher*) override;
 
+  // ChromeToolbarModelDelegate implementation.
+  content::WebContents* GetActiveWebContents() const override;
+
  private:
   ~VrShell() override;
   void WaitForGlThread();
@@ -221,9 +227,11 @@
   scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
   std::unique_ptr<VrGLThread> gl_thread_;
   bool thread_started_ = false;
-  UiInterface* ui_;
   bool reprojected_rendering_;
 
+  UiInterface* ui_;
+  std::unique_ptr<ToolbarHelper> toolbar_;
+
   jobject content_surface_ = nullptr;
   bool taken_surface_ = false;
   base::CancelableClosure poll_capturing_media_task_;
diff --git a/chrome/browser/android/vr_shell/vr_web_contents_observer.cc b/chrome/browser/android/vr_shell/vr_web_contents_observer.cc
index 0a60565..aec6c6f 100644
--- a/chrome/browser/android/vr_shell/vr_web_contents_observer.cc
+++ b/chrome/browser/android/vr_shell/vr_web_contents_observer.cc
@@ -4,11 +4,9 @@
 
 #include "chrome/browser/android/vr_shell/vr_web_contents_observer.h"
 
+#include "chrome/browser/android/vr_shell/toolbar_helper.h"
 #include "chrome/browser/android/vr_shell/ui_interface.h"
 #include "chrome/browser/android/vr_shell/vr_shell.h"
-#include "chrome/browser/ssl/security_state_tab_helper.h"
-#include "components/security_state/core/security_state.h"
-#include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_view.h"
@@ -16,13 +14,14 @@
 namespace vr_shell {
 
 VrWebContentsObserver::VrWebContentsObserver(content::WebContents* web_contents,
+                                             VrShell* vr_shell,
                                              UiInterface* ui_interface,
-                                             VrShell* vr_shell)
+                                             ToolbarHelper* toolbar)
     : WebContentsObserver(web_contents),
+      vr_shell_(vr_shell),
       ui_interface_(ui_interface),
-      vr_shell_(vr_shell) {
-  ui_interface_->SetURL(web_contents->GetVisibleURL());
-  DidChangeVisibleSecurityState();
+      toolbar_(toolbar) {
+  toolbar_->Update();
 }
 
 VrWebContentsObserver::~VrWebContentsObserver() {}
@@ -41,33 +40,21 @@
 
 void VrWebContentsObserver::DidStartNavigation(
     content::NavigationHandle* navigation_handle) {
-  if (navigation_handle->IsInMainFrame()) {
-    ui_interface_->SetURL(navigation_handle->GetURL());
-  }
+  toolbar_->Update();
 }
 
 void VrWebContentsObserver::DidRedirectNavigation(
     content::NavigationHandle* navigation_handle) {
-  if (navigation_handle->IsInMainFrame()) {
-    ui_interface_->SetURL(navigation_handle->GetURL());
-  }
+  toolbar_->Update();
 }
 
 void VrWebContentsObserver::DidFinishNavigation(
     content::NavigationHandle* navigation_handle) {
-  if (navigation_handle->IsInMainFrame()) {
-    ui_interface_->SetURL(navigation_handle->GetURL());
-  }
+  toolbar_->Update();
 }
 
 void VrWebContentsObserver::DidChangeVisibleSecurityState() {
-  const auto* helper = SecurityStateTabHelper::FromWebContents(web_contents());
-  DCHECK(helper);
-  security_state::SecurityInfo security_info;
-  helper->GetSecurityInfo(&security_info);
-  bool malware = (security_info.malicious_content_status !=
-                  security_state::MALICIOUS_CONTENT_STATUS_NONE);
-  ui_interface_->SetSecurityInfo(security_info.security_level, malware);
+  toolbar_->Update();
 }
 
 void VrWebContentsObserver::DidToggleFullscreenModeForTab(
diff --git a/chrome/browser/android/vr_shell/vr_web_contents_observer.h b/chrome/browser/android/vr_shell/vr_web_contents_observer.h
index 12b4bd6b..ac10b059 100644
--- a/chrome/browser/android/vr_shell/vr_web_contents_observer.h
+++ b/chrome/browser/android/vr_shell/vr_web_contents_observer.h
@@ -16,13 +16,15 @@
 
 class UiInterface;
 class VrShell;
+class ToolbarHelper;
 
 class CONTENT_EXPORT VrWebContentsObserver
     : public content::WebContentsObserver {
  public:
   VrWebContentsObserver(content::WebContents* web_contents,
+                        VrShell* vr_shell,
                         UiInterface* ui_interface,
-                        VrShell* vr_shell);
+                        ToolbarHelper* toolbar);
   ~VrWebContentsObserver() override;
 
   void SetUiInterface(UiInterface* ui_interface);
@@ -47,9 +49,10 @@
   void RenderViewHostChanged(content::RenderViewHost* old_host,
                              content::RenderViewHost* new_host) override;
 
-  // This class does not own the UI interface.
-  UiInterface* ui_interface_;
+  // This class does not own these pointers.
   VrShell* vr_shell_;
+  UiInterface* ui_interface_;
+  ToolbarHelper* toolbar_;
 
   DISALLOW_COPY_AND_ASSIGN(VrWebContentsObserver);
 };
diff --git a/chrome/browser/android/webapk/webapk_update_data_fetcher.cc b/chrome/browser/android/webapk/webapk_update_data_fetcher.cc
index 1846a4a..6849a69 100644
--- a/chrome/browser/android/webapk/webapk_update_data_fetcher.cc
+++ b/chrome/browser/android/webapk/webapk_update_data_fetcher.cc
@@ -121,7 +121,6 @@
   params.check_installable = true;
   params.fetch_valid_primary_icon = true;
   params.fetch_valid_badge_icon = true;
-  InstallableManager::CreateForWebContents(web_contents());
   InstallableManager* installable_manager =
       InstallableManager::FromWebContents(web_contents());
   installable_manager->GetData(
diff --git a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc
index 4e31565..2729854 100644
--- a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc
+++ b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc
@@ -32,9 +32,6 @@
 
 namespace {
 
-// The default number of milliseconds to wait for the data download to complete.
-const int kDataTimeoutInMilliseconds = 4000;
-
 // Looks up the original, online URL of the site requested.  The URL from the
 // WebContents may be a distilled article which is not appropriate for a home
 // screen shortcut.
@@ -43,7 +40,7 @@
   return dom_distiller::url_utils::GetOriginalUrlFromDistillerUrl(actual_url);
 }
 
-InstallableParams ParamsToPerformInstallableCheck(
+InstallableParams ParamsToPerformManifestAndIconFetch(
     int ideal_icon_size_in_px,
     int minimum_icon_size_in_px,
     int badge_size_in_px,
@@ -51,16 +48,22 @@
   InstallableParams params;
   params.ideal_primary_icon_size_in_px = ideal_icon_size_in_px;
   params.minimum_primary_icon_size_in_px = minimum_icon_size_in_px;
-  params.check_installable = check_webapk_compatibility;
   params.fetch_valid_primary_icon = true;
   if (check_webapk_compatibility) {
+    params.fetch_valid_badge_icon = true;
     params.ideal_badge_icon_size_in_px = badge_size_in_px;
     params.minimum_badge_icon_size_in_px = badge_size_in_px;
-    params.fetch_valid_badge_icon = true;
   }
   return params;
 }
 
+InstallableParams ParamsToPerformInstallableCheck(
+    bool check_webapk_compatibility) {
+  InstallableParams params;
+  params.check_installable = check_webapk_compatibility;
+  return params;
+}
+
 }  // namespace
 
 AddToHomescreenDataFetcher::AddToHomescreenDataFetcher(
@@ -70,9 +73,11 @@
     int ideal_splash_image_size_in_px,
     int minimum_splash_image_size_in_px,
     int badge_size_in_px,
+    int data_timeout_ms,
     bool check_webapk_compatibility,
     Observer* observer)
     : content::WebContentsObserver(web_contents),
+      installable_manager_(InstallableManager::FromWebContents(web_contents)),
       weak_observer_(observer),
       shortcut_info_(GetShortcutUrl(web_contents->GetBrowserContext(),
                                     web_contents->GetLastCommittedURL())),
@@ -81,10 +86,10 @@
       ideal_splash_image_size_in_px_(ideal_splash_image_size_in_px),
       minimum_splash_image_size_in_px_(minimum_splash_image_size_in_px),
       badge_size_in_px_(badge_size_in_px),
+      data_timeout_ms_(data_timeout_ms),
       check_webapk_compatibility_(check_webapk_compatibility),
       is_waiting_for_web_application_info_(true),
-      is_installable_check_complete_(false),
-      is_icon_saved_(false) {
+      is_installable_check_complete_(false) {
   DCHECK(minimum_icon_size_in_px <= ideal_icon_size_in_px);
   DCHECK(minimum_splash_image_size_in_px <= ideal_splash_image_size_in_px);
 
@@ -135,24 +140,17 @@
       break;
   }
 
-  InstallableManager::CreateForWebContents(web_contents());
-  InstallableManager* manager =
-      InstallableManager::FromWebContents(web_contents());
-  DCHECK(manager);
-
   // Kick off a timeout for downloading data. If we haven't finished within the
   // timeout, fall back to using a dynamically-generated launcher icon.
   data_timeout_timer_.Start(
-      FROM_HERE, base::TimeDelta::FromMilliseconds(kDataTimeoutInMilliseconds),
+      FROM_HERE, base::TimeDelta::FromMilliseconds(data_timeout_ms_),
       base::Bind(&AddToHomescreenDataFetcher::OnDataTimedout, this));
 
-  manager->GetData(
-      ParamsToPerformInstallableCheck(ideal_icon_size_in_px_,
-                                      minimum_icon_size_in_px_,
-                                      badge_size_in_px_,
-                                      check_webapk_compatibility_),
-      base::Bind(&AddToHomescreenDataFetcher::OnDidPerformInstallableCheck,
-                 this));
+  installable_manager_->GetData(
+      ParamsToPerformManifestAndIconFetch(
+          ideal_icon_size_in_px_, minimum_icon_size_in_px_, badge_size_in_px_,
+          check_webapk_compatibility_),
+      base::Bind(&AddToHomescreenDataFetcher::OnDidGetManifestAndIcons, this));
 }
 
 AddToHomescreenDataFetcher::~AddToHomescreenDataFetcher() {
@@ -187,48 +185,34 @@
     weak_observer_->OnUserTitleAvailable(shortcut_info_.user_title);
   }
 
-  badge_icon_.reset();
-  CreateLauncherIcon(SkBitmap());
+  CreateLauncherIcon(raw_primary_icon_);
 }
 
-void AddToHomescreenDataFetcher::OnDidPerformInstallableCheck(
+void AddToHomescreenDataFetcher::OnDidGetManifestAndIcons(
     const InstallableData& data) {
-  data_timeout_timer_.Stop();
-  badge_icon_.reset();
-
   if (!web_contents() || !weak_observer_ || is_installable_check_complete_)
     return;
 
-  is_installable_check_complete_ = true;
-
-  bool webapk_compatible = false;
-  if (check_webapk_compatibility_) {
-    webapk_compatible = (data.error_code == NO_ERROR_DETECTED &&
-                         AreWebManifestUrlsWebApkCompatible(data.manifest));
-    weak_observer_->OnDidDetermineWebApkCompatibility(webapk_compatible);
-
-    if (webapk_compatible) {
-      // WebAPKs are wholly defined by the Web Manifest. Ignore the <meta> tag
-      // data received in OnDidGetWebApplicationInfo().
-      shortcut_info_ = ShortcutInfo(GURL());
-    }
-  }
-
   if (!data.manifest.IsEmpty()) {
     base::RecordAction(base::UserMetricsAction("webapps.AddShortcut.Manifest"));
     shortcut_info_.UpdateFromManifest(data.manifest);
     shortcut_info_.manifest_url = data.manifest_url;
-
-    if (webapk_compatible) {
-      shortcut_info_.UpdateSource(ShortcutInfo::SOURCE_ADD_TO_HOMESCREEN_PWA);
-
-      if (data.badge_icon && !data.badge_icon->drawsNothing()) {
-        shortcut_info_.best_badge_icon_url = data.badge_icon_url;
-        badge_icon_ = *data.badge_icon;
-      }
-    }
   }
 
+  // Do this after updating from the manifest for the case where a site has
+  // a manifest with name and standalone specified, but no icons.
+  if (data.manifest.IsEmpty() || !data.primary_icon) {
+    if (check_webapk_compatibility_)
+      weak_observer_->OnDidDetermineWebApkCompatibility(false);
+    weak_observer_->OnUserTitleAvailable(shortcut_info_.user_title);
+    data_timeout_timer_.Stop();
+    FetchFavicon();
+    return;
+  }
+
+  raw_primary_icon_ = *data.primary_icon;
+  shortcut_info_.best_primary_icon_url = data.primary_icon_url;
+
   // Save the splash screen URL for the later download.
   shortcut_info_.splash_image_url =
       content::ManifestIconSelector::FindBestMatchingIcon(
@@ -238,20 +222,41 @@
   shortcut_info_.ideal_splash_image_size_in_px = ideal_splash_image_size_in_px_;
   shortcut_info_.minimum_splash_image_size_in_px =
       minimum_splash_image_size_in_px_;
-
-  weak_observer_->OnUserTitleAvailable(shortcut_info_.user_title);
-
-  if (data.primary_icon) {
-    shortcut_info_.best_primary_icon_url = data.primary_icon_url;
-
-    if (webapk_compatible)
-      NotifyObserver(*data.primary_icon);
-    else
-      CreateLauncherIcon(*(data.primary_icon));
-    return;
+  if (data.badge_icon) {
+    shortcut_info_.best_badge_icon_url = data.badge_icon_url;
+    badge_icon_ = *data.badge_icon;
   }
 
-  FetchFavicon();
+  installable_manager_->GetData(
+      ParamsToPerformInstallableCheck(check_webapk_compatibility_),
+      base::Bind(&AddToHomescreenDataFetcher::OnDidPerformInstallableCheck,
+                 this));
+}
+
+void AddToHomescreenDataFetcher::OnDidPerformInstallableCheck(
+    const InstallableData& data) {
+  data_timeout_timer_.Stop();
+
+  if (!web_contents() || !weak_observer_ || is_installable_check_complete_)
+    return;
+
+  is_installable_check_complete_ = true;
+
+  bool webapk_compatible = false;
+  if (check_webapk_compatibility_) {
+    webapk_compatible =
+        (data.error_code == NO_ERROR_DETECTED && data.is_installable &&
+         AreWebManifestUrlsWebApkCompatible(data.manifest));
+    weak_observer_->OnDidDetermineWebApkCompatibility(webapk_compatible);
+  }
+
+  weak_observer_->OnUserTitleAvailable(shortcut_info_.user_title);
+  if (webapk_compatible) {
+    shortcut_info_.UpdateSource(ShortcutInfo::SOURCE_ADD_TO_HOMESCREEN_PWA);
+    NotifyObserver(raw_primary_icon_);
+  } else {
+    CreateLauncherIcon(raw_primary_icon_);
+  }
 }
 
 void AddToHomescreenDataFetcher::FetchFavicon() {
@@ -283,7 +288,7 @@
     const favicon_base::FaviconRawBitmapResult& bitmap_result) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
-  if (!web_contents() || !weak_observer_ || is_icon_saved_)
+  if (!web_contents() || !weak_observer_)
     return;
 
   // The user is waiting for the icon to be processed before they can proceed
@@ -304,17 +309,17 @@
     const favicon_base::FaviconRawBitmapResult& bitmap_result) {
   base::ThreadRestrictions::AssertIOAllowed();
 
-  SkBitmap raw_icon;
   if (bitmap_result.is_valid()) {
     gfx::PNGCodec::Decode(bitmap_result.bitmap_data->front(),
-                          bitmap_result.bitmap_data->size(), &raw_icon);
+                          bitmap_result.bitmap_data->size(),
+                          &raw_primary_icon_);
   }
 
   shortcut_info_.best_primary_icon_url = bitmap_result.icon_url;
-  return CreateLauncherIconInBackground(raw_icon);
+  return CreateLauncherIconInBackground(raw_primary_icon_);
 }
 
-void AddToHomescreenDataFetcher::CreateLauncherIcon(const SkBitmap& raw_icon) {
+void AddToHomescreenDataFetcher::CreateLauncherIcon(const SkBitmap& icon) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   // The user is waiting for the icon to be processed before they can proceed
@@ -326,20 +331,20 @@
        base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
       base::BindOnce(
           &AddToHomescreenDataFetcher::CreateLauncherIconInBackground,
-          base::Unretained(this), raw_icon),
+          base::Unretained(this), icon),
       base::BindOnce(&AddToHomescreenDataFetcher::NotifyObserver,
                      base::RetainedRef(this)));
 }
 
 SkBitmap AddToHomescreenDataFetcher::CreateLauncherIconInBackground(
-    const SkBitmap& raw_icon) {
+    const SkBitmap& icon) {
   base::ThreadRestrictions::AssertIOAllowed();
 
   SkBitmap primary_icon;
   bool is_generated = false;
   if (weak_observer_) {
     primary_icon = weak_observer_->FinalizeLauncherIconInBackground(
-        raw_icon, shortcut_info_.url, &is_generated);
+        icon, shortcut_info_.url, &is_generated);
   }
 
   if (is_generated)
@@ -350,10 +355,9 @@
 
 void AddToHomescreenDataFetcher::NotifyObserver(const SkBitmap& primary_icon) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  if (!web_contents() || !weak_observer_ || is_icon_saved_)
+  if (!web_contents() || !weak_observer_)
     return;
 
-  is_icon_saved_ = true;
   primary_icon_ = primary_icon;
   weak_observer_->OnDataAvailable(shortcut_info_, primary_icon_, badge_icon_);
 }
diff --git a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.h b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.h
index 77679690..6212b1692 100644
--- a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.h
+++ b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.h
@@ -19,6 +19,7 @@
 }
 
 class GURL;
+class InstallableManager;
 struct InstallableData;
 struct WebApplicationInfo;
 
@@ -27,19 +28,19 @@
 //
 // Because of the various asynchronous calls made by this class, it is
 // refcounted to prevent the class from being prematurely deleted.  If the
-// pointer to the ShortcutHelper becomes invalid, the pipeline should kill
-// itself.
+// |weak_observer_| pointer becomes invalid, the pipeline should kill itself.
 class AddToHomescreenDataFetcher
     : public base::RefCounted<AddToHomescreenDataFetcher>,
       public content::WebContentsObserver {
  public:
   class Observer {
    public:
-    // Callded when the installable check is compelte.
+    // Called when the installable check is complete.
     virtual void OnDidDetermineWebApkCompatibility(
         bool is_webapk_compatible) = 0;
 
-    // Called when the title of the page is available.
+    // Called when the title of the page is available. Will be called after
+    // OnDidDetermineWebApkCompatibility.
     virtual void OnUserTitleAvailable(const base::string16& title) = 0;
 
     // Converts the icon into one that can be used on the Android Home screen.
@@ -67,6 +68,7 @@
                              int ideal_splash_image_size_in_px,
                              int minimum_splash_image_size_in_px,
                              int badge_size_in_px,
+                             int data_timeout_ms,
                              bool check_webapk_compatible,
                              Observer* observer);
 
@@ -92,6 +94,9 @@
   void OnDataTimedout();
 
   // Called when InstallableManager finishes looking for a manifest and icon.
+  void OnDidGetManifestAndIcons(const InstallableData& data);
+
+  // Called when InstallableManager finishes checking for installability.
   void OnDidPerformInstallableCheck(const InstallableData& data);
 
   // Grabs the favicon for the current URL.
@@ -105,16 +110,18 @@
   SkBitmap CreateLauncherIconFromFaviconInBackground(
       const favicon_base::FaviconRawBitmapResult& bitmap_result);
 
-  // Creates the launcher icon from the given |raw_icon|.
-  void CreateLauncherIcon(const SkBitmap& raw_icon);
-  SkBitmap CreateLauncherIconInBackground(const SkBitmap& raw_icon);
+  // Creates the primary launcher icon from the given |icon|.
+  void CreateLauncherIcon(const SkBitmap& icon);
+  SkBitmap CreateLauncherIconInBackground(const SkBitmap& icon);
 
   // Notifies the observer that the shortcut data is all available.
   void NotifyObserver(const SkBitmap& icon);
 
+  InstallableManager* installable_manager_;
   Observer* weak_observer_;
 
   // The icons must only be set on the UI thread for thread safety.
+  SkBitmap raw_primary_icon_;
   SkBitmap badge_icon_;
   SkBitmap primary_icon_;
   ShortcutInfo shortcut_info_;
@@ -127,12 +134,12 @@
   const int ideal_splash_image_size_in_px_;
   const int minimum_splash_image_size_in_px_;
   const int badge_size_in_px_;
+  const int data_timeout_ms_;
 
   // Indicates whether to check WebAPK compatibility.
   bool check_webapk_compatibility_;
   bool is_waiting_for_web_application_info_;
   bool is_installable_check_complete_;
-  bool is_icon_saved_;
 
   DISALLOW_COPY_AND_ASSIGN(AddToHomescreenDataFetcher);
 };
diff --git a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher_unittest.cc b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher_unittest.cc
index 8725d7f..ebe6b85 100644
--- a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher_unittest.cc
+++ b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher_unittest.cc
@@ -17,6 +17,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
+#include "chrome/browser/installable/installable_manager.h"
 #include "chrome/common/web_application_info.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_profile.h"
@@ -33,11 +34,9 @@
 #include "ui/gfx/image/image_unittest_util.h"
 #include "url/gurl.h"
 
-// TODO(zpeng): Effectively test scenarios where both timeout callback and
-// success callback are invoked. See crbug.com/697228.
-
 namespace {
 
+const char* kWebApplicationInfoTitle = "Meta Title";
 const char* kDefaultManifestUrl = "https://www.example.com/manifest.json";
 const char* kDefaultManifestName = "Default Name";
 const char* kDefaultManifestShortName = "Default Short Name";
@@ -49,20 +48,16 @@
 class MockWebContents : public content::TestWebContents {
  public:
   explicit MockWebContents(content::BrowserContext* browser_context)
-      : content::TestWebContents(browser_context) {}
+      : content::TestWebContents(browser_context),
+        should_image_time_out_(false),
+        should_manifest_time_out_(false) {}
 
-  ~MockWebContents() override {
-  }
+  ~MockWebContents() override {}
 
-  // Sets the manifest to be returned by GetManifest().
-  // |fetch_delay_ms| is the time in milliseconds that the simulated fetch of
-  // the web manifest should take.
   void SetManifest(const GURL& manifest_url,
-                   const content::Manifest& manifest,
-                   int fetch_delay_ms) {
+                   const content::Manifest& manifest) {
     manifest_url_ = manifest_url;
     manifest_ = manifest;
-    manifest_fetch_delay_ms_ = fetch_delay_ms;
   }
 
   int DownloadImage(const GURL& url,
@@ -70,28 +65,40 @@
                     uint32_t max_bitmap_size,
                     bool bypass_cache,
                     const ImageDownloadCallback& callback) override {
+    if (should_image_time_out_)
+      return 0;
+
     const int kIconSizePx = 144;
     SkBitmap icon = gfx::test::CreateBitmap(kIconSizePx, kIconSizePx);
     std::vector<SkBitmap> icons(1u, icon);
     std::vector<gfx::Size> pixel_sizes(1u, gfx::Size(kIconSizePx, kIconSizePx));
-    content::BrowserThread::PostTask(
-        content::BrowserThread::UI,
-        FROM_HERE,
-        base::Bind(callback, 0, net::HTTP_OK, url, icons, pixel_sizes));
+    content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::UI)
+        ->PostTask(FROM_HERE, base::Bind(callback, 0, net::HTTP_OK, url, icons,
+                                         pixel_sizes));
     return 0;
   }
 
   void GetManifest(const GetManifestCallback& callback) override {
-    content::BrowserThread::PostDelayedTask(
-        content::BrowserThread::UI, FROM_HERE,
-        base::Bind(callback, manifest_url_, manifest_),
-        base::TimeDelta::FromMilliseconds(manifest_fetch_delay_ms_));
+    if (should_manifest_time_out_)
+      return;
+
+    content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::UI)
+        ->PostTask(FROM_HERE, base::Bind(callback, manifest_url_, manifest_));
+  }
+
+  void SetShouldImageTimeOut(bool should_time_out) {
+    should_image_time_out_ = should_time_out;
+  }
+
+  void SetShouldManifestTimeOut(bool should_time_out) {
+    should_manifest_time_out_ = should_time_out;
   }
 
  private:
   GURL manifest_url_;
   content::Manifest manifest_;
-  int manifest_fetch_delay_ms_;
+  bool should_image_time_out_;
+  bool should_manifest_time_out_;
 
   DISALLOW_COPY_AND_ASSIGN(MockWebContents);
 };
@@ -118,12 +125,15 @@
   }
 
   void OnDidDetermineWebApkCompatibility(bool is_webapk_compatible) override {
+    EXPECT_FALSE(title_available_);
     determined_webapk_compatibility_ = true;
     is_webapk_compatible_ = is_webapk_compatible;
   }
 
   void OnUserTitleAvailable(const base::string16& title) override {
+    EXPECT_FALSE(data_available_);
     title_available_ = true;
+    title_ = title;
   }
 
   SkBitmap FinalizeLauncherIconInBackground(const SkBitmap& icon,
@@ -136,11 +146,13 @@
   void OnDataAvailable(const ShortcutInfo& info,
                        const SkBitmap& primary_icon,
                        const SkBitmap& badge_icon) override {
+    EXPECT_TRUE(title_available_);
     data_available_ = true;
     if (!quit_closure_.is_null())
       quit_closure_.Run();
   }
 
+  base::string16 title() const { return title_; }
   bool is_webapk_compatible() const { return is_webapk_compatible_; }
   bool determined_webapk_compatibility() const {
     return determined_webapk_compatibility_;
@@ -148,6 +160,7 @@
   bool title_available() const { return title_available_; }
 
  private:
+  base::string16 title_;
   bool is_webapk_compatible_;
   bool determined_webapk_compatibility_;
   bool title_available_;
@@ -162,6 +175,10 @@
   return base::NullableString16(base::UTF8ToUTF16(value), false);
 }
 
+content::Manifest BuildEmptyManifest() {
+  return content::Manifest();
+}
+
 // Builds WebAPK compatible content::Manifest.
 content::Manifest BuildDefaultManifest() {
   content::Manifest manifest;
@@ -169,6 +186,14 @@
   manifest.short_name = NullableStringFromUTF8(kDefaultManifestShortName);
   manifest.start_url = GURL(kDefaultStartUrl);
   manifest.display = kDefaultManifestDisplayMode;
+
+  content::Manifest::Icon primary_icon;
+  primary_icon.type = base::ASCIIToUTF16("image/png");
+  primary_icon.sizes.push_back(gfx::Size(144, 144));
+  primary_icon.purpose.push_back(content::Manifest::Icon::IconPurpose::ANY);
+  primary_icon.src = GURL("https://www.google.com/image.png");
+  manifest.icons.push_back(primary_icon);
+
   return manifest;
 }
 
@@ -196,7 +221,9 @@
     MockWebContents* mock_web_contents = new MockWebContents(browser_context());
     mock_web_contents->Init(content::WebContents::CreateParams(
         browser_context(), std::move(site_instance)));
+    InstallableManager::CreateForWebContents(mock_web_contents);
     SetContents(mock_web_contents);
+    NavigateAndCommit(GURL(kDefaultStartUrl));
   }
 
   void TearDown() override {
@@ -207,17 +234,28 @@
   scoped_refptr<AddToHomescreenDataFetcher> BuildFetcher(
       bool check_webapk_compatible,
       AddToHomescreenDataFetcher::Observer* observer) {
-    return new AddToHomescreenDataFetcher(web_contents(), 1, 1, 1, 1, 1,
+    return new AddToHomescreenDataFetcher(web_contents(), 1, 1, 1, 1, 1, 500,
                                           check_webapk_compatible, observer);
   }
 
   // Set the manifest to be returned as a result of WebContents::GetManifest().
   void SetManifest(const GURL& manifest_url,
-                   const content::Manifest& manifest,
-                   int fetch_delay_ms) {
+                   const content::Manifest& manifest) {
     MockWebContents* mock_web_contents =
         static_cast<MockWebContents*>(web_contents());
-    mock_web_contents->SetManifest(manifest_url, manifest, fetch_delay_ms);
+    mock_web_contents->SetManifest(manifest_url, manifest);
+  }
+
+  void SetShouldImageTimeOut(bool should_time_out) {
+    MockWebContents* mock_web_contents =
+        static_cast<MockWebContents*>(web_contents());
+    mock_web_contents->SetShouldImageTimeOut(should_time_out);
+  }
+
+  void SetShouldManifestTimeOut(bool should_time_out) {
+    MockWebContents* mock_web_contents =
+        static_cast<MockWebContents*>(web_contents());
+    mock_web_contents->SetShouldManifestTimeOut(should_time_out);
   }
 
   // Registers service worker at |url|. Blocks till the service worker is
@@ -248,25 +286,6 @@
   DISALLOW_COPY_AND_ASSIGN(AddToHomescreenDataFetcherTest);
 };
 
-// Checks that AddToHomescreenDataFetcher::Observer::OnUserTitleAvailable() is
-// called when the web manifest fetch times out. The add-to-homescreen dialog
-// makes the dialog's text field editable once OnUserTitleAvailable() is called.
-TEST_F(AddToHomescreenDataFetcherTest,
-    DISABLED_ManifestFetchTimesOutNoServiceWorker) {
-  SetManifest(GURL(kDefaultManifestUrl), BuildDefaultManifest(), 10000);
-
-  ObserverWaiter waiter;
-  scoped_refptr<AddToHomescreenDataFetcher> fetcher(
-      BuildFetcher(false, &waiter));
-  fetcher->OnDidGetWebApplicationInfo(WebApplicationInfo());
-  waiter.WaitForDataAvailable();
-
-  EXPECT_FALSE(waiter.determined_webapk_compatibility());
-  EXPECT_TRUE(waiter.title_available());
-
-  fetcher->set_weak_observer(nullptr);
-}
-
 // Class for tests which should be run with AddToHomescreenDataFetcher built
 // with both true and false values of |check_webapk_compatible|.
 class AddToHomescreenDataFetcherTestCommon
@@ -290,25 +309,49 @@
   DISALLOW_COPY_AND_ASSIGN(AddToHomescreenDataFetcherTestCommon);
 };
 
-// Test that when the manifest provides Manifest::short_name but not
-// Manifest::name that Manifest::short_name is used as the name instead of
-// WebApplicationInfo::title.
-TEST_P(AddToHomescreenDataFetcherTestCommon,
-       ManifestShortNameClobbersWebApplicationName) {
+// Checks that AddToHomescreenDataFetcher::Observer::OnUserTitleAvailable() is
+// called when the web manifest returned is empty. The add-to-homescreen dialog
+// makes the dialog's text field editable once OnUserTitleAvailable() is called.
+TEST_P(AddToHomescreenDataFetcherTestCommon, EmptyManifest) {
   WebApplicationInfo web_application_info;
-  web_application_info.title = base::UTF8ToUTF16("Meta Title");
+  web_application_info.title = base::UTF8ToUTF16(kWebApplicationInfoTitle);
 
-  content::Manifest manifest(BuildDefaultManifest());
-  manifest.name = base::NullableString16();
-
-  RegisterServiceWorker(GURL(kDefaultStartUrl));
-  SetManifest(GURL(kDefaultManifestUrl), manifest, 0);
+  SetManifest(GURL(kDefaultManifestUrl), BuildEmptyManifest());
 
   ObserverWaiter waiter;
   scoped_refptr<AddToHomescreenDataFetcher> fetcher(BuildFetcher(&waiter));
   fetcher->OnDidGetWebApplicationInfo(web_application_info);
   waiter.WaitForDataAvailable();
 
+  EXPECT_EQ(check_webapk_compatibility(),
+            waiter.determined_webapk_compatibility());
+  EXPECT_FALSE(waiter.is_webapk_compatible());
+  EXPECT_TRUE(waiter.title_available());
+  EXPECT_TRUE(base::EqualsASCII(waiter.title(), kWebApplicationInfoTitle));
+
+  fetcher->set_weak_observer(nullptr);
+}
+
+// Test that when the manifest provides Manifest::short_name but not
+// Manifest::name that Manifest::short_name is used as the name instead of
+// WebApplicationInfo::title.
+TEST_P(AddToHomescreenDataFetcherTestCommon,
+       ManifestShortNameClobbersWebApplicationName) {
+  WebApplicationInfo web_application_info;
+  web_application_info.title = base::UTF8ToUTF16(kWebApplicationInfoTitle);
+
+  content::Manifest manifest(BuildDefaultManifest());
+  manifest.name = base::NullableString16();
+
+  RegisterServiceWorker(GURL(kDefaultStartUrl));
+  SetManifest(GURL(kDefaultManifestUrl), manifest);
+
+  ObserverWaiter waiter;
+  scoped_refptr<AddToHomescreenDataFetcher> fetcher(BuildFetcher(&waiter));
+  fetcher->OnDidGetWebApplicationInfo(web_application_info);
+  waiter.WaitForDataAvailable();
+
+  EXPECT_TRUE(base::EqualsASCII(waiter.title(), kDefaultManifestShortName));
   EXPECT_TRUE(base::EqualsASCII(fetcher->shortcut_info().name,
                                 kDefaultManifestShortName));
 
@@ -320,50 +363,107 @@
 // - The page is not WebAPK compatible.
 // - WebApplicationInfo::title is used as the "name".
 TEST_P(AddToHomescreenDataFetcherTestCommon, ManifestNoNameNoShortName) {
-    const char* kWebApplicationInfoTitle = "Meta Title";
-    WebApplicationInfo web_application_info;
-    web_application_info.title = base::UTF8ToUTF16(kWebApplicationInfoTitle);
+  WebApplicationInfo web_application_info;
+  web_application_info.title = base::UTF8ToUTF16(kWebApplicationInfoTitle);
 
-    content::Manifest manifest(BuildDefaultManifest());
-    manifest.name = base::NullableString16();
-    manifest.short_name = base::NullableString16();
+  content::Manifest manifest(BuildDefaultManifest());
+  manifest.name = base::NullableString16();
+  manifest.short_name = base::NullableString16();
 
-    RegisterServiceWorker(GURL(kDefaultStartUrl));
-    SetManifest(GURL(kDefaultManifestUrl), manifest, 0);
+  RegisterServiceWorker(GURL(kDefaultStartUrl));
+  SetManifest(GURL(kDefaultManifestUrl), manifest);
 
-    ObserverWaiter waiter;
-    scoped_refptr<AddToHomescreenDataFetcher> fetcher(BuildFetcher(&waiter));
-    fetcher->OnDidGetWebApplicationInfo(web_application_info);
-    waiter.WaitForDataAvailable();
+  ObserverWaiter waiter;
+  scoped_refptr<AddToHomescreenDataFetcher> fetcher(BuildFetcher(&waiter));
+  fetcher->OnDidGetWebApplicationInfo(web_application_info);
+  waiter.WaitForDataAvailable();
 
-    EXPECT_FALSE(waiter.is_webapk_compatible());
-    EXPECT_TRUE(base::EqualsASCII(fetcher->shortcut_info().name,
-                                  kWebApplicationInfoTitle));
+  EXPECT_EQ(check_webapk_compatibility(),
+            waiter.determined_webapk_compatibility());
+  EXPECT_FALSE(waiter.is_webapk_compatible());
+  EXPECT_TRUE(base::EqualsASCII(waiter.title(), kWebApplicationInfoTitle));
+  EXPECT_TRUE(base::EqualsASCII(fetcher->shortcut_info().name,
+                                kWebApplicationInfoTitle));
 
-    fetcher->set_weak_observer(nullptr);
+  fetcher->set_weak_observer(nullptr);
 }
 
 // Checks that the AddToHomescreenDataFetcher::Observer callbacks are called
-// when a service worker is registered and the manifest fetch times out.
-TEST_P(AddToHomescreenDataFetcherTestCommon, DISABLED_ManifestFetchTimesOut) {
-    RegisterServiceWorker(GURL(kDefaultStartUrl));
-    SetManifest(GURL(kDefaultManifestUrl), BuildDefaultManifest(), 10000);
+// when the manifest fetch times out.
+TEST_P(AddToHomescreenDataFetcherTestCommon, ManifestFetchTimesOut) {
+  WebApplicationInfo web_application_info;
+  web_application_info.title = base::UTF8ToUTF16(kWebApplicationInfoTitle);
 
-    ObserverWaiter waiter;
-    scoped_refptr<AddToHomescreenDataFetcher> fetcher(BuildFetcher(&waiter));
-    fetcher->OnDidGetWebApplicationInfo(WebApplicationInfo());
-    waiter.WaitForDataAvailable();
+  RegisterServiceWorker(GURL(kDefaultStartUrl));
+  SetManifest(GURL(kDefaultManifestUrl), BuildDefaultManifest());
+  SetShouldManifestTimeOut(true);
+  SetShouldImageTimeOut(false);
 
-    if (check_webapk_compatibility()) {
-      EXPECT_TRUE(waiter.determined_webapk_compatibility());
-      EXPECT_FALSE(waiter.is_webapk_compatible());
-    } else {
-      EXPECT_FALSE(waiter.determined_webapk_compatibility());
-    }
-    // This callback enables the text field in the add-to-homescreen dialog.
-    EXPECT_TRUE(waiter.title_available());
+  ObserverWaiter waiter;
+  scoped_refptr<AddToHomescreenDataFetcher> fetcher(BuildFetcher(&waiter));
+  fetcher->OnDidGetWebApplicationInfo(web_application_info);
+  waiter.WaitForDataAvailable();
 
-    fetcher->set_weak_observer(nullptr);
+  EXPECT_EQ(check_webapk_compatibility(),
+            waiter.determined_webapk_compatibility());
+  EXPECT_FALSE(waiter.is_webapk_compatible());
+  EXPECT_TRUE(base::EqualsASCII(waiter.title(), kWebApplicationInfoTitle));
+  EXPECT_TRUE(waiter.title_available());
+
+  fetcher->set_weak_observer(nullptr);
+}
+
+// Checks that the AddToHomescreenDataFetcher::Observer callbacks are called
+// when the image fetch times out.
+TEST_P(AddToHomescreenDataFetcherTestCommon, ImageFetchTimesOut) {
+  WebApplicationInfo web_application_info;
+  web_application_info.title = base::UTF8ToUTF16(kWebApplicationInfoTitle);
+
+  RegisterServiceWorker(GURL(kDefaultStartUrl));
+  SetManifest(GURL(kDefaultManifestUrl), BuildDefaultManifest());
+  SetShouldManifestTimeOut(false);
+  SetShouldImageTimeOut(true);
+
+  ObserverWaiter waiter;
+  scoped_refptr<AddToHomescreenDataFetcher> fetcher(BuildFetcher(&waiter));
+  fetcher->OnDidGetWebApplicationInfo(web_application_info);
+  waiter.WaitForDataAvailable();
+
+  EXPECT_EQ(check_webapk_compatibility(),
+            waiter.determined_webapk_compatibility());
+  EXPECT_FALSE(waiter.is_webapk_compatible());
+  EXPECT_TRUE(waiter.title_available());
+  EXPECT_TRUE(base::EqualsASCII(waiter.title(), kWebApplicationInfoTitle));
+
+  fetcher->set_weak_observer(nullptr);
+}
+
+// Checks that the AddToHomescreenDataFetcher::Observer callbacks are called
+// when the service worker check times out.
+TEST_P(AddToHomescreenDataFetcherTestCommon, ServiceWorkerCheckTimesOut) {
+  WebApplicationInfo web_application_info;
+  web_application_info.title = base::UTF8ToUTF16(kWebApplicationInfoTitle);
+
+  // Not registering a service worker means we'll wait and time out for the
+  // worker.
+  SetManifest(GURL(kDefaultManifestUrl), BuildDefaultManifest());
+  SetShouldManifestTimeOut(false);
+  SetShouldImageTimeOut(false);
+
+  ObserverWaiter waiter;
+  scoped_refptr<AddToHomescreenDataFetcher> fetcher(BuildFetcher(&waiter));
+  fetcher->OnDidGetWebApplicationInfo(web_application_info);
+  waiter.WaitForDataAvailable();
+
+  EXPECT_EQ(check_webapk_compatibility(),
+            waiter.determined_webapk_compatibility());
+  EXPECT_FALSE(waiter.is_webapk_compatible());
+  EXPECT_TRUE(waiter.title_available());
+  EXPECT_TRUE(base::EqualsASCII(waiter.title(), kDefaultManifestShortName));
+  EXPECT_TRUE(base::EqualsASCII(fetcher->shortcut_info().user_title,
+                                kDefaultManifestShortName));
+
+  fetcher->set_weak_observer(nullptr);
 }
 
 INSTANTIATE_TEST_CASE_P(CheckWebApkCompatibility,
diff --git a/chrome/browser/android/webapps/add_to_homescreen_manager.cc b/chrome/browser/android/webapps/add_to_homescreen_manager.cc
index bba4d5d..17be747 100644
--- a/chrome/browser/android/webapps/add_to_homescreen_manager.cc
+++ b/chrome/browser/android/webapps/add_to_homescreen_manager.cc
@@ -31,6 +31,14 @@
 using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 
+namespace {
+
+// The length of time to allow the add to homescreen data fetcher to run before
+// timing out and generating an icon.
+const int kDataTimeoutInMilliseconds = 4000;
+
+}  // namespace
+
 jlong InitializeAndStart(JNIEnv* env,
                          const JavaParamRef<jobject>& obj,
                          const JavaParamRef<jobject>& java_web_contents) {
@@ -94,7 +102,7 @@
       ShortcutHelper::GetMinimumHomescreenIconSizeInPx(),
       ShortcutHelper::GetIdealSplashImageSizeInPx(),
       ShortcutHelper::GetMinimumSplashImageSizeInPx(),
-      ShortcutHelper::GetIdealBadgeIconSizeInPx(),
+      ShortcutHelper::GetIdealBadgeIconSizeInPx(), kDataTimeoutInMilliseconds,
       check_webapk_compatible, this);
 }
 
diff --git a/chrome/browser/banners/app_banner_manager.cc b/chrome/browser/banners/app_banner_manager.cc
index 3af8374e..ee166f2 100644
--- a/chrome/browser/banners/app_banner_manager.cc
+++ b/chrome/browser/banners/app_banner_manager.cc
@@ -140,7 +140,7 @@
       SiteEngagementObserver(SiteEngagementService::Get(
           Profile::FromBrowserContext(web_contents->GetBrowserContext()))),
       state_(State::INACTIVE),
-      manager_(nullptr),
+      manager_(InstallableManager::FromWebContents(web_contents)),
       event_request_id_(-1),
       binding_(this),
       has_sufficient_engagement_(false),
@@ -149,9 +149,6 @@
       triggered_by_devtools_(false),
       need_to_log_status_(false),
       weak_factory_(this) {
-  // Ensure the InstallableManager exists since we have a hard dependency on it.
-  InstallableManager::CreateForWebContents(web_contents);
-  manager_ = InstallableManager::FromWebContents(web_contents);
   DCHECK(manager_);
 
   AppBannerSettingsHelper::UpdateFromFieldTrial();
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index 100d4117..54f9e542 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -273,6 +273,8 @@
             <include name="IDR_MD_BOOKMARKS_COMMAND_MANAGER_JS" file="resources\md_bookmarks\command_manager.js" type="BINDATA" />
             <include name="IDR_MD_BOOKMARKS_CONSTANTS_HTML" file="resources\md_bookmarks\constants.html" type="BINDATA" />
             <include name="IDR_MD_BOOKMARKS_CONSTANTS_JS" file="resources\md_bookmarks\constants.js" type="BINDATA" />
+            <include name="IDR_MD_BOOKMARKS_DIALOG_FOCUS_MANAGER_HTML" file="resources\md_bookmarks\dialog_focus_manager.html" type="BINDATA" />
+            <include name="IDR_MD_BOOKMARKS_DIALOG_FOCUS_MANAGER_JS" file="resources\md_bookmarks\dialog_focus_manager.js" type="BINDATA" />
             <include name="IDR_MD_BOOKMARKS_DND_MANAGER_HTML" file="resources\md_bookmarks\dnd_manager.html" type="BINDATA" />
             <include name="IDR_MD_BOOKMARKS_DND_MANAGER_JS" file="resources\md_bookmarks\dnd_manager.js" type="BINDATA" />
             <include name="IDR_MD_BOOKMARKS_EDIT_DIALOG_HTML" file="resources\md_bookmarks\edit_dialog.html" type="BINDATA" />
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index 1d0f415..294ab87 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -1166,6 +1166,17 @@
                              base::Time::Now().ToInternalValue());
     }
 
+#if defined(OS_MACOSX) || defined(OS_LINUX)
+    // Create directory for user-level Native Messaging manifest files. This
+    // makes it less likely that the directory will be created by third-party
+    // software with incorrect owner or permission. See crbug.com/725513 .
+    base::FilePath user_native_messaging_dir;
+    CHECK(PathService::Get(chrome::DIR_USER_NATIVE_MESSAGING,
+                           &user_native_messaging_dir));
+    if (!base::PathExists(user_native_messaging_dir))
+      base::CreateDirectory(user_native_messaging_dir);
+#endif  // defined(OS_MACOSX) || defined(OS_LINUX)
+
     if (!master_prefs_->suppress_default_browser_prompt_for_version.empty()) {
       local_state_->SetString(
           prefs::kBrowserSuppressDefaultBrowserPrompt,
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 98cac7f..6461d768 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -69,6 +69,7 @@
 #include "chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_io_data.h"
+#include "chrome/browser/profiling_host/profiling_process_host.h"
 #include "chrome/browser/renderer_host/chrome_navigation_ui_data.h"
 #include "chrome/browser/renderer_host/chrome_render_message_filter.h"
 #include "chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h"
@@ -1640,6 +1641,9 @@
   };
   command_line->CopySwitchesFrom(browser_command_line, kCommonSwitchNames,
                                  arraysize(kCommonSwitchNames));
+#if BUILDFLAG(ENABLE_OOP_HEAP_PROFILING)
+  profiling::ProfilingProcessHost::AddSwitchesToChildCmdLine(command_line);
+#endif
 
   static const char* const kDinosaurEasterEggSwitches[] = {
       error_page::switches::kDisableDinosaurEasterEgg,
diff --git a/chrome/browser/chromeos/arc/arc_session_manager.cc b/chrome/browser/chromeos/arc/arc_session_manager.cc
index a5e991a..e1ca910d 100644
--- a/chrome/browser/chromeos/arc/arc_session_manager.cc
+++ b/chrome/browser/chromeos/arc/arc_session_manager.cc
@@ -33,6 +33,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_launcher.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
+#include "chrome/browser/ui/app_list/arc/arc_pai_starter.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/common/pref_names.h"
@@ -604,6 +605,11 @@
     return;
   }
 
+  if (!pai_starter_ && !profile_->GetPrefs()->GetBoolean(prefs::kArcSignedIn) &&
+      IsPlayStoreAvailable()) {
+    pai_starter_ = base::MakeUnique<ArcPaiStarter>(profile_);
+  }
+
   if (start_arc_directly) {
     StartArc();
     // Check Android management in parallel.
diff --git a/chrome/browser/chromeos/arc/arc_session_manager.h b/chrome/browser/chromeos/arc/arc_session_manager.h
index dae79de..4a25ddc 100644
--- a/chrome/browser/chromeos/arc/arc_session_manager.h
+++ b/chrome/browser/chromeos/arc/arc_session_manager.h
@@ -29,6 +29,7 @@
 
 class ArcAndroidManagementChecker;
 class ArcAuthContext;
+class ArcPaiStarter;
 class ArcTermsOfServiceNegotiator;
 enum class ProvisioningResult : int;
 
@@ -226,6 +227,10 @@
   // Returns true if ARC requested to start.
   bool enable_requested() const { return enable_requested_; }
 
+  // Returns PAI starter that is used to start Play Auto Install flow. It is
+  // available only on initial start.
+  ArcPaiStarter* pai_starter() { return pai_starter_.get(); }
+
   // Injectors for testing.
   void SetArcSessionRunnerForTesting(
       std::unique_ptr<ArcSessionRunner> arc_session_runner);
@@ -342,6 +347,7 @@
   std::unique_ptr<ArcAndroidManagementChecker> android_management_checker_;
 
   std::unique_ptr<ScopedOptInFlowTracker> scoped_opt_in_tracker_;
+  std::unique_ptr<ArcPaiStarter> pai_starter_;
 
   // The time when the sign in process started.
   base::Time sign_in_start_time_;
diff --git a/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_arc_home_service.cc b/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_arc_home_service.cc
index 0ab5ad1..9bf01d2 100644
--- a/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_arc_home_service.cc
+++ b/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_arc_home_service.cc
@@ -12,8 +12,10 @@
 #include "base/logging.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/chromeos/arc/arc_session_manager.h"
 #include "chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.h"
 #include "chrome/browser/chromeos/first_run/first_run.h"
+#include "chrome/browser/ui/app_list/arc/arc_pai_starter.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_list.h"
@@ -136,6 +138,10 @@
 
 void ArcVoiceInteractionArcHomeService::OnVoiceInteractionOobeSetupComplete() {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  arc::ArcPaiStarter* pai_starter =
+      arc::ArcSessionManager::Get()->pai_starter();
+  if (pai_starter)
+    pai_starter->ReleaseLock();
   chromeos::first_run::MaybeLaunchDialogImmediately();
 }
 
diff --git a/chrome/browser/chromeos/extensions/quick_unlock_private/quick_unlock_private_api.cc b/chrome/browser/chromeos/extensions/quick_unlock_private/quick_unlock_private_api.cc
index 3161294..8dbc51a 100644
--- a/chrome/browser/chromeos/extensions/quick_unlock_private/quick_unlock_private_api.cc
+++ b/chrome/browser/chromeos/extensions/quick_unlock_private/quick_unlock_private_api.cc
@@ -8,6 +8,9 @@
 #include "base/stl_util.h"
 #include "chrome/browser/chromeos/login/quick_unlock/quick_unlock_factory.h"
 #include "chrome/browser/chromeos/login/quick_unlock/quick_unlock_storage.h"
+#include "chrome/browser/chromeos/login/supervised/supervised_user_authentication.h"
+#include "chrome/browser/chromeos/login/users/chrome_user_manager.h"
+#include "chrome/browser/chromeos/login/users/supervised_user_manager.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/login/auth/extended_authenticator.h"
@@ -327,11 +330,20 @@
     }
   }
 
-  user_manager::User* user = chromeos::ProfileHelper::Get()->GetUserByProfile(
-      chrome_details_.GetProfile());
+  const user_manager::User* const user =
+      chromeos::ProfileHelper::Get()->GetUserByProfile(
+          chrome_details_.GetProfile());
   chromeos::UserContext user_context(user->GetAccountId());
   user_context.SetKey(chromeos::Key(params_->account_password));
 
+  // Alter |user_context| if the user is supervised.
+  if (user->GetType() == user_manager::USER_TYPE_SUPERVISED) {
+    user_context = chromeos::ChromeUserManager::Get()
+                       ->GetSupervisedUserManager()
+                       ->GetAuthentication()
+                       ->TransformKey(user_context);
+  }
+
   // Lazily allocate the authenticator. We do this here, instead of in the ctor,
   // so that tests can install a fake.
   if (authenticator_allocator_.is_null())
diff --git a/chrome/browser/chromeos/login/lock/screen_locker.cc b/chrome/browser/chromeos/login/lock/screen_locker.cc
index fd78daa..71490d3e 100644
--- a/chrome/browser/chromeos/login/lock/screen_locker.cc
+++ b/chrome/browser/chromeos/login/lock/screen_locker.cc
@@ -10,10 +10,6 @@
 #include "ash/login/ui/lock_screen.h"
 #include "ash/public/interfaces/constants.mojom.h"
 #include "ash/public/interfaces/session_controller.mojom.h"
-#include "ash/shell.h"
-#include "ash/wm/window_state.h"
-#include "ash/wm/window_util.h"
-#include "ash/wm/wm_event.h"
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/lazy_instance.h"
@@ -519,26 +515,13 @@
     return;
   }
 
-  // Manipulating active window state directly does not work in mash so skip it
-  // for mash. http://crbug.com/714677 tracks work to add the support for mash.
-  if (!ash_util::IsRunningInMash()) {
-    // If the active window is fullscreen, exit fullscreen to avoid the web page
-    // or app mimicking the lock screen. Do not exit fullscreen if the shelf is
-    // visible while in fullscreen because the shelf makes it harder for a web
-    // page or app to mimick the lock screen.
-    ash::wm::WindowState* active_window_state = ash::wm::GetActiveWindowState();
-    if (active_window_state && active_window_state->IsFullscreen() &&
-        active_window_state->hide_shelf_when_fullscreen()) {
-      const ash::wm::WMEvent event(ash::wm::WM_EVENT_TOGGLE_FULLSCREEN);
-      active_window_state->OnWMEvent(&event);
-    }
-  }
-
   if (!screen_locker_) {
-    ScreenLocker* locker =
-        new ScreenLocker(user_manager::UserManager::Get()->GetUnlockUsers());
-    VLOG(1) << "Created ScreenLocker " << locker;
-    locker->Init();
+    SessionControllerClient::Get()->PrepareForLock(base::Bind([]() {
+      ScreenLocker* locker =
+          new ScreenLocker(user_manager::UserManager::Get()->GetUnlockUsers());
+      VLOG(1) << "Created ScreenLocker " << locker;
+      locker->Init();
+    }));
   } else {
     VLOG(1) << "ScreenLocker " << screen_locker_ << " already exists; "
             << " calling session manager's HandleLockScreenShown D-Bus method";
diff --git a/chrome/browser/chromeos/login/lock/webui_screen_locker.cc b/chrome/browser/chromeos/login/lock/webui_screen_locker.cc
index aa4fd53..6e109bc 100644
--- a/chrome/browser/chromeos/login/lock/webui_screen_locker.cc
+++ b/chrome/browser/chromeos/login/lock/webui_screen_locker.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/browser_shutdown.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/accessibility/accessibility_util.h"
+#include "chrome/browser/chromeos/ash_config.h"
 #include "chrome/browser/chromeos/login/helper.h"
 #include "chrome/browser/chromeos/login/lock/screen_locker.h"
 #include "chrome/browser/chromeos/login/quick_unlock/quick_unlock_factory.h"
@@ -151,7 +152,7 @@
   gfx::Rect bounds = display::Screen::GetScreen()->GetPrimaryDisplay().bounds();
 
   lock_time_ = base::TimeTicks::Now();
-  lock_window_ = new ash::LockWindow();
+  lock_window_ = new ash::LockWindow(chromeos::GetAshConfig());
   lock_window_->AddObserver(this);
 
   Init();
diff --git a/chrome/browser/chromeos/login/screens/voice_interaction_value_prop_screen.cc b/chrome/browser/chromeos/login/screens/voice_interaction_value_prop_screen.cc
index c9a7fc3..c011d25 100644
--- a/chrome/browser/chromeos/login/screens/voice_interaction_value_prop_screen.cc
+++ b/chrome/browser/chromeos/login/screens/voice_interaction_value_prop_screen.cc
@@ -4,10 +4,12 @@
 
 #include "chrome/browser/chromeos/login/screens/voice_interaction_value_prop_screen.h"
 
+#include "chrome/browser/chromeos/arc/arc_session_manager.h"
 #include "chrome/browser/chromeos/login/screens/base_screen_delegate.h"
 #include "chrome/browser/chromeos/login/screens/voice_interaction_value_prop_screen_view.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/ui/app_list/arc/arc_pai_starter.h"
 #include "chrome/common/pref_names.h"
 #include "components/prefs/pref_service.h"
 
@@ -40,6 +42,13 @@
     return;
 
   view_->Show();
+
+  arc::ArcPaiStarter* pai_starter =
+      arc::ArcSessionManager::Get()->pai_starter();
+  if (pai_starter)
+    pai_starter->AcquireLock();
+  else
+    DLOG(ERROR) << "There is no PAI starter.";
 }
 
 void VoiceInteractionValuePropScreen::Hide() {
@@ -64,10 +73,16 @@
 }
 
 void VoiceInteractionValuePropScreen::OnNoThanksPressed() {
+  arc::ArcPaiStarter* pai_starter =
+      arc::ArcSessionManager::Get()->pai_starter();
+  if (pai_starter)
+    pai_starter->ReleaseLock();
   Finish(ScreenExitCode::VOICE_INTERACTION_VALUE_PROP_SKIPPED);
 }
 
 void VoiceInteractionValuePropScreen::OnContinuePressed() {
+  // Note! Release lock for PAI will be called at
+  // ArcVoiceInteractionArcHomeService::OnVoiceInteractionOobeSetupComplete.
   ProfileManager::GetActiveUserProfile()->GetPrefs()->SetBoolean(
       prefs::kArcVoiceInteractionValuePropAccepted, true);
   Finish(ScreenExitCode::VOICE_INTERACTION_VALUE_PROP_ACCEPTED);
diff --git a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.h b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.h
index 4ef6942a..a3f4eba8 100644
--- a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.h
+++ b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.h
@@ -10,7 +10,6 @@
 #include <string>
 #include <vector>
 
-#include "base/containers/hash_tables.h"
 #include "base/macros.h"
 #include "base/memory/linked_ptr.h"
 #include "base/memory/weak_ptr.h"
@@ -178,8 +177,7 @@
   friend class WallpaperManager;
   friend class WallpaperManagerTest;
 
-  using UserImageManagerMap =
-      base::hash_map<AccountId, linked_ptr<UserImageManager> >;
+  using UserImageManagerMap = std::map<AccountId, linked_ptr<UserImageManager>>;
 
   ChromeUserManagerImpl();
 
diff --git a/chrome/browser/chromeos/login/wizard_controller.h b/chrome/browser/chromeos/login/wizard_controller.h
index 20d66f63..f2618ad 100644
--- a/chrome/browser/chromeos/login/wizard_controller.h
+++ b/chrome/browser/chromeos/login/wizard_controller.h
@@ -10,7 +10,6 @@
 #include <string>
 
 #include "base/compiler_specific.h"
-#include "base/containers/hash_tables.h"
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/memory/linked_ptr.h"
@@ -431,7 +430,7 @@
   std::unique_ptr<pairing_chromeos::HostPairingController> remora_controller_;
 
   // Maps screen names to last time of their shows.
-  base::hash_map<std::string, base::Time> screen_show_times_;
+  std::map<std::string, base::Time> screen_show_times_;
 
   // Tests check result of timezone resolve.
   bool timezone_resolved_ = false;
diff --git a/chrome/browser/chromeos/net/network_portal_detector_impl.h b/chrome/browser/chromeos/net/network_portal_detector_impl.h
index c28afefd..84aa5f24 100644
--- a/chrome/browser/chromeos/net/network_portal_detector_impl.h
+++ b/chrome/browser/chromeos/net/network_portal_detector_impl.h
@@ -5,12 +5,12 @@
 #ifndef CHROME_BROWSER_CHROMEOS_NET_NETWORK_PORTAL_DETECTOR_IMPL_H_
 #define CHROME_BROWSER_CHROMEOS_NET_NETWORK_PORTAL_DETECTOR_IMPL_H_
 
+#include <map>
 #include <memory>
 #include <string>
 
 #include "base/cancelable_callback.h"
 #include "base/compiler_specific.h"
-#include "base/containers/hash_tables.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
@@ -75,7 +75,7 @@
   friend class NetworkPortalDetectorImplTest;
   friend class NetworkPortalDetectorImplBrowserTest;
 
-  using CaptivePortalStateMap = base::hash_map<std::string, CaptivePortalState>;
+  using CaptivePortalStateMap = std::map<std::string, CaptivePortalState>;
 
   enum State {
     // No portal check is running.
diff --git a/chrome/browser/chromeos/net/network_portal_detector_test_impl.h b/chrome/browser/chromeos/net/network_portal_detector_test_impl.h
index 91fef887..8701d5d4 100644
--- a/chrome/browser/chromeos/net/network_portal_detector_test_impl.h
+++ b/chrome/browser/chromeos/net/network_portal_detector_test_impl.h
@@ -5,11 +5,11 @@
 #ifndef CHROME_BROWSER_CHROMEOS_NET_NETWORK_PORTAL_DETECTOR_TEST_IMPL_H_
 #define CHROME_BROWSER_CHROMEOS_NET_NETWORK_PORTAL_DETECTOR_TEST_IMPL_H_
 
+#include <map>
 #include <memory>
 #include <string>
 
 #include "base/compiler_specific.h"
-#include "base/containers/hash_tables.h"
 #include "base/macros.h"
 #include "base/observer_list.h"
 #include "chromeos/network/portal_detector/network_portal_detector.h"
@@ -44,8 +44,8 @@
   }
 
  private:
-  typedef std::string NetworkId;
-  typedef base::hash_map<NetworkId, CaptivePortalState> CaptivePortalStateMap;
+  using NetworkId = std::string;
+  using CaptivePortalStateMap = std::map<NetworkId, CaptivePortalState>;
 
   base::ObserverList<Observer> observers_;
   std::unique_ptr<NetworkState> default_network_;
diff --git a/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.cc b/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.cc
index f974f24..20cc798 100644
--- a/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.cc
+++ b/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.cc
@@ -349,6 +349,15 @@
 }
 
 void UserCloudPolicyManagerChromeOS::FetchPolicyOAuthToken() {
+  // By-pass token fetching for test.
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          chromeos::switches::kDisableGaiaServices)) {
+    OnOAuth2PolicyTokenFetched(
+        "fake_policy_token",
+        GoogleServiceAuthError(GoogleServiceAuthError::NONE));
+    return;
+  }
+
   const std::string& refresh_token = chromeos::UserSessionManager::GetInstance()
                                          ->user_context()
                                          .GetRefreshToken();
diff --git a/chrome/browser/chromeos/printing/cups_print_job_manager_impl.cc b/chrome/browser/chromeos/printing/cups_print_job_manager_impl.cc
index d03c07c..78375691 100644
--- a/chrome/browser/chromeos/printing/cups_print_job_manager_impl.cc
+++ b/chrome/browser/chromeos/printing/cups_print_job_manager_impl.cc
@@ -14,10 +14,12 @@
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/sequenced_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/threading/sequenced_task_runner_handle.h"
-#include "base/threading/sequenced_worker_pool.h"
+#include "base/task_runner_util.h"
+#include "base/task_scheduler/post_task.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/printing/cups_print_job.h"
 #include "chrome/browser/chromeos/printing/printers_manager.h"
@@ -102,13 +104,6 @@
   return State::STATE_NONE;
 }
 
-chromeos::QueryResult QueryCups(::printing::CupsConnection* connection,
-                                const std::vector<std::string>& printer_ids) {
-  chromeos::QueryResult result;
-  result.success = connection->GetJobs(printer_ids, &result.queues);
-  return result;
-}
-
 // Returns true if |printer_status|.reasons contains |reason|.
 bool ContainsReason(const printing::PrinterStatus printer_status,
                     PrinterReason::Reason reason) {
@@ -172,6 +167,43 @@
   return pages_updated;
 }
 
+// Updates the state of a print job based on |printer_status| and |job|.
+// Returns true if observers need to be notified of an update.
+bool UpdatePrintJob(const ::printing::PrinterStatus& printer_status,
+                    const ::printing::CupsJob& job,
+                    chromeos::CupsPrintJob* print_job) {
+  DCHECK_EQ(job.id, print_job->job_id());
+
+  State old_state = print_job->state();
+
+  bool pages_updated = false;
+  switch (job.state) {
+    case ::printing::CupsJob::PROCESSING:
+      if (ContainsReason(printer_status, PrinterReason::CONNECTING_TO_DEVICE)) {
+        if (EnforceTimeout(job, print_job)) {
+          LOG(WARNING) << "Connecting to printer timed out";
+          print_job->set_expired(true);
+        }
+      } else {
+        pages_updated = UpdateCurrentPage(job, print_job);
+      }
+      break;
+    case ::printing::CupsJob::COMPLETED:
+      DCHECK_GE(job.current_pages, print_job->total_page_number());
+      print_job->set_state(State::STATE_DOCUMENT_DONE);
+      break;
+    case ::printing::CupsJob::ABORTED:
+    case ::printing::CupsJob::CANCELED:
+      print_job->set_error_code(ErrorCodeFromReasons(printer_status));
+    // fall through
+    default:
+      print_job->set_state(ConvertState(job.state));
+      break;
+  }
+
+  return print_job->state() != old_state || pages_updated;
+}
+
 }  // namespace
 
 namespace chromeos {
@@ -182,9 +214,47 @@
 
 QueryResult::~QueryResult() = default;
 
+CupsWrapper::CupsWrapper()
+    : cups_connection_(GURL(), HTTP_ENCRYPT_NEVER, false) {
+  DETACH_FROM_SEQUENCE(sequence_checker_);
+}
+
+CupsWrapper::~CupsWrapper() = default;
+
+void CupsWrapper::QueryCups(const std::vector<std::string>& printer_ids,
+                            QueryResult* result) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  result->success = cups_connection_.GetJobs(printer_ids, &result->queues);
+}
+
+void CupsWrapper::CancelJobImpl(const std::string& printer_id,
+                                const int job_id) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  std::unique_ptr<::printing::CupsPrinter> printer =
+      cups_connection_.GetPrinter(printer_id);
+  if (!printer) {
+    LOG(WARNING) << "Printer not found: " << printer_id;
+    return;
+  }
+
+  if (!printer->CancelJob(job_id)) {
+    // This is not expected to fail but log it if it does.
+    LOG(WARNING) << "Cancelling job failed.  Job may be stuck in queue.";
+  }
+}
+
 CupsPrintJobManagerImpl::CupsPrintJobManagerImpl(Profile* profile)
     : CupsPrintJobManager(profile),
-      cups_connection_(GURL(), HTTP_ENCRYPT_NEVER, false),
+      query_runner_(base::CreateSequencedTaskRunnerWithTraits(
+          base::TaskTraits(base::TaskPriority::BACKGROUND,
+                           base::MayBlock(),
+                           base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN))),
+      cups_wrapper_(new CupsWrapper(),
+                    base::OnTaskRunnerDeleter(query_runner_)),
       weak_ptr_factory_(this) {
   registrar_.Add(this, chrome::NOTIFICATION_PRINT_JOB_EVENT,
                  content::NotificationService::AllSources());
@@ -203,12 +273,10 @@
   // Stop montioring jobs after we cancel them.  The user no longer cares.
   jobs_.erase(job->GetUniqueId());
 
-  // Be sure to copy out all relevant fields.  |job| may be destroyed after we
-  // exit this scope.
-  content::BrowserThread::GetBlockingPool()->PostTask(
+  query_runner_->PostTask(
       FROM_HERE,
-      base::Bind(&CupsPrintJobManagerImpl::CancelJobImpl,
-                 weak_ptr_factory_.GetWeakPtr(), printer_id, job_id));
+      base::Bind(&CupsWrapper::CancelJobImpl,
+                 base::Unretained(cups_wrapper_.get()), printer_id, job_id));
 }
 
 bool CupsPrintJobManagerImpl::SuspendPrintJob(CupsPrintJob* job) {
@@ -244,6 +312,8 @@
                                              const std::string& title,
                                              int job_id,
                                              int total_page_number) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
   auto printer =
       PrintersManagerFactory::GetForBrowserContext(profile_)->GetPrinter(
           printer_name);
@@ -281,18 +351,22 @@
 }
 
 void CupsPrintJobManagerImpl::ScheduleQuery(const base::TimeDelta& delay) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
   if (!in_query_) {
     in_query_ = true;
 
-    base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
-        FROM_HERE,
-        base::Bind(&CupsPrintJobManagerImpl::PostQuery,
-                   weak_ptr_factory_.GetWeakPtr()),
-        delay);
+    content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::UI)
+        ->PostDelayedTask(FROM_HERE,
+                          base::Bind(&CupsPrintJobManagerImpl::PostQuery,
+                                     weak_ptr_factory_.GetWeakPtr()),
+                          delay);
   }
 }
 
 void CupsPrintJobManagerImpl::PostQuery() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
   // The set of active printers is expected to be small.
   std::set<std::string> printer_ids;
   for (const auto& entry : jobs_) {
@@ -300,60 +374,31 @@
   }
   std::vector<std::string> ids{printer_ids.begin(), printer_ids.end()};
 
-  content::BrowserThread::PostTaskAndReplyWithResult(
-      content::BrowserThread::FILE_USER_BLOCKING, FROM_HERE,
-      base::Bind(&QueryCups, &cups_connection_, ids),
+  auto result = base::MakeUnique<QueryResult>();
+  QueryResult* result_ptr = result.get();
+  // Runs a query on query_runner_ which will rejoin this sequnece on
+  // completion.
+  query_runner_->PostTaskAndReply(
+      FROM_HERE,
+      base::Bind(&CupsWrapper::QueryCups, base::Unretained(cups_wrapper_.get()),
+                 ids, result_ptr),
       base::Bind(&CupsPrintJobManagerImpl::UpdateJobs,
-                 weak_ptr_factory_.GetWeakPtr()));
-}
-
-bool CupsPrintJobManagerImpl::UpdatePrintJob(
-    const ::printing::PrinterStatus& printer_status,
-    const ::printing::CupsJob& job,
-    CupsPrintJob* print_job) {
-  DCHECK_EQ(job.id, print_job->job_id());
-
-  State old_state = print_job->state();
-
-  bool pages_updated = false;
-  switch (job.state) {
-    case ::printing::CupsJob::PROCESSING:
-      if (ContainsReason(printer_status, PrinterReason::CONNECTING_TO_DEVICE)) {
-        if (EnforceTimeout(job, print_job)) {
-          LOG(WARNING) << "Connecting to printer timed out";
-          print_job->set_expired(true);
-        }
-      } else {
-        pages_updated = UpdateCurrentPage(job, print_job);
-      }
-      break;
-    case ::printing::CupsJob::COMPLETED:
-      DCHECK_GE(job.current_pages, print_job->total_page_number());
-      print_job->set_state(State::STATE_DOCUMENT_DONE);
-      break;
-    case ::printing::CupsJob::ABORTED:
-    case ::printing::CupsJob::CANCELED:
-      print_job->set_error_code(ErrorCodeFromReasons(printer_status));
-    // fall through
-    default:
-      print_job->set_state(ConvertState(job.state));
-      break;
-  }
-
-  return print_job->state() != old_state || pages_updated;
+                 weak_ptr_factory_.GetWeakPtr(), base::Passed(&result)));
 }
 
 // Use job information to update local job states.  Previously completed jobs
-// could be in |jobs| but those are ignored as we will not emit updates for them
-// after they are completed.
-void CupsPrintJobManagerImpl::UpdateJobs(const QueryResult& result) {
-  const std::vector<::printing::QueueStatus>& queues = result.queues;
+// could be in |jobs| but those are ignored as we will not emit updates for
+// them after they are completed.
+void CupsPrintJobManagerImpl::UpdateJobs(std::unique_ptr<QueryResult> result) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  const std::vector<::printing::QueueStatus>& queues = result->queues;
 
   // Query has completed.  Allow more queries.
   in_query_ = false;
 
   // If the query failed, either retry or purge.
-  if (!result.success) {
+  if (!result->success) {
     retry_count_++;
     LOG(WARNING) << "Failed to query CUPS for queue status.  Schedule retry ("
                  << retry_count_ << ")";
@@ -407,14 +452,16 @@
     // During normal operations, we poll at the default rate.
     ScheduleQuery();
   } else if (!jobs_.empty()) {
-    // We're tracking jobs that we didn't receive an update for.  Something bad
-    // has happened.
+    // We're tracking jobs that we didn't receive an update for.  Something
+    // bad has happened.
     LOG(ERROR) << "Lost track of (" << jobs_.size() << ") jobs";
     PurgeJobs();
   }
 }
 
 void CupsPrintJobManagerImpl::PurgeJobs() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
   for (const auto& entry : jobs_) {
     // Declare all lost jobs errors.
     RecordJobResult(LOST);
@@ -426,22 +473,9 @@
   jobs_.clear();
 }
 
-void CupsPrintJobManagerImpl::CancelJobImpl(const std::string& printer_id,
-                                            const int job_id) {
-  std::unique_ptr<::printing::CupsPrinter> printer =
-      cups_connection_.GetPrinter(printer_id);
-  if (!printer) {
-    LOG(WARNING) << "Printer not found: " << printer_id;
-    return;
-  }
-
-  if (!printer->CancelJob(job_id)) {
-    // This is not expected to fail but log it if it does.
-    LOG(WARNING) << "Cancelling job failed.  Job may be stuck in queue.";
-  }
-}
-
 void CupsPrintJobManagerImpl::NotifyJobStateUpdate(CupsPrintJob* job) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
   switch (job->state()) {
     case State::STATE_NONE:
       // State does not require notification.
diff --git a/chrome/browser/chromeos/printing/cups_print_job_manager_impl.h b/chrome/browser/chromeos/printing/cups_print_job_manager_impl.h
index cdf72369..804ddb1 100644
--- a/chrome/browser/chromeos/printing/cups_print_job_manager_impl.h
+++ b/chrome/browser/chromeos/printing/cups_print_job_manager_impl.h
@@ -8,10 +8,12 @@
 #include <map>
 #include <memory>
 #include <string>
-#include <unordered_map>
 #include <vector>
 
+#include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
+#include "base/sequence_checker.h"
+#include "base/sequenced_task_runner.h"
 #include "chrome/browser/chromeos/printing/cups_print_job.h"
 #include "chrome/browser/chromeos/printing/cups_print_job_manager.h"
 #include "chrome/browser/chromeos/printing/printers_manager.h"
@@ -32,6 +34,28 @@
   std::vector<::printing::QueueStatus> queues;
 };
 
+// A wrapper around the CUPS connection to ensure that it's always accessed on
+// the same sequence.
+class CupsWrapper {
+ public:
+  CupsWrapper();
+  ~CupsWrapper();
+
+  // Query CUPS for the current jobs for the given |printer_ids|.  Writes result
+  // to |result|.
+  void QueryCups(const std::vector<std::string>& printer_ids,
+                 QueryResult* result);
+
+  // Cancel the print job on the blocking thread.
+  void CancelJobImpl(const std::string& printer_id, const int job_id);
+
+ private:
+  ::printing::CupsConnection cups_connection_;
+  SEQUENCE_CHECKER(sequence_checker_);
+
+  DISALLOW_COPY_AND_ASSIGN(CupsWrapper);
+};
+
 class CupsPrintJobManagerImpl : public CupsPrintJobManager,
                                 public content::NotificationObserver {
  public:
@@ -65,21 +89,12 @@
   // to UpdateJobs.
   void PostQuery();
 
-  // Updates the state of a print job based on |printer_status| and |job|.
-  // Returns true if observers need to be notified of an update.
-  bool UpdatePrintJob(const ::printing::PrinterStatus& printer_status,
-                      const ::printing::CupsJob& job,
-                      CupsPrintJob* print_job);
-
   // Process jobs from CUPS and perform notifications.
-  void UpdateJobs(const QueryResult& results);
+  void UpdateJobs(std::unique_ptr<QueryResult> results);
 
   // Mark remaining jobs as errors and remove active jobs.
   void PurgeJobs();
 
-  // Cancel the print job on the blocking thread.
-  void CancelJobImpl(const std::string& printer_id, const int job_id);
-
   // Notify observers that a state update has occured for |job|.
   void NotifyJobStateUpdate(CupsPrintJob* job);
 
@@ -92,8 +107,10 @@
   // Records the number of consecutive times the GetJobs query has failed.
   int retry_count_ = 0;
 
-  ::printing::CupsConnection cups_connection_;
   content::NotificationRegistrar registrar_;
+  // Task runner for queries to CUPS.
+  scoped_refptr<base::SequencedTaskRunner> query_runner_;
+  std::unique_ptr<CupsWrapper, base::OnTaskRunnerDeleter> cups_wrapper_;
   base::WeakPtrFactory<CupsPrintJobManagerImpl> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(CupsPrintJobManagerImpl);
diff --git a/chrome/browser/chromeos/settings/cros_settings.h b/chrome/browser/chromeos/settings/cros_settings.h
index 77d5c1d..519a804 100644
--- a/chrome/browser/chromeos/settings/cros_settings.h
+++ b/chrome/browser/chromeos/settings/cros_settings.h
@@ -5,13 +5,13 @@
 #ifndef CHROME_BROWSER_CHROMEOS_SETTINGS_CROS_SETTINGS_H_
 #define CHROME_BROWSER_CHROMEOS_SETTINGS_CROS_SETTINGS_H_
 
+#include <map>
 #include <memory>
 #include <string>
 #include <vector>
 
 #include "base/callback_forward.h"
 #include "base/callback_list.h"
-#include "base/containers/hash_tables.h"
 #include "base/macros.h"
 #include "base/sequence_checker.h"
 #include "chromeos/settings/cros_settings_names.h"
@@ -131,7 +131,7 @@
 
   // A map from settings names to a list of observers. Observers get fired in
   // the order they are added.
-  base::hash_map<std::string, std::unique_ptr<base::CallbackList<void(void)>>>
+  std::map<std::string, std::unique_ptr<base::CallbackList<void(void)>>>
       settings_observers_;
 
   SEQUENCE_CHECKER(sequence_checker_);
diff --git a/chrome/browser/command_updater.h b/chrome/browser/command_updater.h
index 31a4e913..035d250 100644
--- a/chrome/browser/command_updater.h
+++ b/chrome/browser/command_updater.h
@@ -6,8 +6,8 @@
 #define CHROME_BROWSER_COMMAND_UPDATER_H_
 
 #include <memory>
+#include <unordered_map>
 
-#include "base/containers/hash_tables.h"
 #include "base/macros.h"
 #include "ui/base/window_open_disposition.h"
 
@@ -77,7 +77,7 @@
   CommandUpdaterDelegate* delegate_;
 
   // This is a map of command IDs to states and observer lists
-  base::hash_map<int, std::unique_ptr<Command>> commands_;
+  std::unordered_map<int, std::unique_ptr<Command>> commands_;
 
   DISALLOW_COPY_AND_ASSIGN(CommandUpdater);
 };
diff --git a/chrome/browser/data_use_measurement/chrome_data_use_ascriber.cc b/chrome/browser/data_use_measurement/chrome_data_use_ascriber.cc
index 11e58907..08c6d098 100644
--- a/chrome/browser/data_use_measurement/chrome_data_use_ascriber.cc
+++ b/chrome/browser/data_use_measurement/chrome_data_use_ascriber.cc
@@ -379,9 +379,11 @@
   NotifyPageLoadCommit(old_frame_entry);
 
   if (is_same_page_navigation) {
-    for (auto& request : entry->pending_url_requests()) {
-      AscribeRecorderWithRequest(request.first, old_frame_entry);
-      old_frame_entry->MovePendingURLRequest(&(*entry), request.first);
+    std::vector<net::URLRequest*> pending_url_requests;
+    entry->GetPendingURLRequests(&pending_url_requests);
+    for (net::URLRequest* request : pending_url_requests) {
+      AscribeRecorderWithRequest(request, old_frame_entry);
+      entry->MovePendingURLRequestTo(&(*old_frame_entry), request);
     }
     data_use_recorders_.erase(entry);
   } else {
diff --git a/chrome/browser/data_use_measurement/chrome_data_use_ascriber.h b/chrome/browser/data_use_measurement/chrome_data_use_ascriber.h
index 9e2c30bf..9dc1530 100644
--- a/chrome/browser/data_use_measurement/chrome_data_use_ascriber.h
+++ b/chrome/browser/data_use_measurement/chrome_data_use_ascriber.h
@@ -6,13 +6,12 @@
 #define CHROME_BROWSER_DATA_USE_MEASUREMENT_CHROME_DATA_USE_ASCRIBER_H_
 
 #include <list>
+#include <map>
 #include <memory>
 #include <string>
 #include <tuple>
-#include <unordered_map>
 #include <utility>
 
-#include "base/containers/hash_tables.h"
 #include "base/hash.h"
 #include "base/macros.h"
 #include "base/supports_user_data.h"
@@ -119,13 +118,6 @@
   typedef std::list<ChromeDataUseRecorder> DataUseRecorderList;
   typedef DataUseRecorderList::iterator DataUseRecorderEntry;
 
-  struct GlobalRequestIDHash {
-   public:
-    std::size_t operator()(const content::GlobalRequestID& x) const {
-      return base::HashInts(x.child_id, x.request_id);
-    }
-  };
-
   class DataUseRecorderEntryAsUserData : public base::SupportsUserData::Data {
    public:
     explicit DataUseRecorderEntryAsUserData(DataUseRecorderEntry entry);
@@ -192,20 +184,17 @@
   // Map from RenderFrameHost to the MainRenderFrameEntry which contains all
   // details of the main frame. New entry is added on main render frame creation
   // and removed on its deletion.
-  base::hash_map<RenderFrameHostID, MainRenderFrameEntry>
+  std::map<RenderFrameHostID, MainRenderFrameEntry>
       main_render_frame_entry_map_;
 
   // Maps subframe IDs to the mainframe ID, so the mainframe lifetime can have
   // ownership over the lifetime of entries in |data_use_recorders_|. Mainframes
   // are mapped to themselves.
-  base::hash_map<RenderFrameHostID, RenderFrameHostID>
-      subframe_to_mainframe_map_;
+  std::map<RenderFrameHostID, RenderFrameHostID> subframe_to_mainframe_map_;
 
   // Map from pending navigations to the DataUseRecorderEntry in
   // |data_use_recorders_| that the navigation ascribes data use to.
-  std::unordered_map<content::GlobalRequestID,
-                     DataUseRecorderEntry,
-                     GlobalRequestIDHash>
+  std::map<content::GlobalRequestID, DataUseRecorderEntry>
       pending_navigation_data_use_map_;
 
   DISALLOW_COPY_AND_ASSIGN(ChromeDataUseAscriber);
diff --git a/chrome/browser/devtools/device/cast_device_provider.cc b/chrome/browser/devtools/device/cast_device_provider.cc
index 8ee6714..53d8e6d0 100644
--- a/chrome/browser/devtools/device/cast_device_provider.cc
+++ b/chrome/browser/devtools/device/cast_device_provider.cc
@@ -7,6 +7,7 @@
 #include <map>
 #include <set>
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "base/single_thread_task_runner.h"
@@ -104,7 +105,7 @@
     device_lister_.reset(new ServiceDiscoveryDeviceLister(
         this, service_discovery_client_.get(), kCastServiceType));
     device_lister_->Start();
-    device_lister_->DiscoverNewDevices(true);
+    device_lister_->DiscoverNewDevices();
   }
 
   // ServiceDiscoveryDeviceLister::Delegate implementation:
diff --git a/chrome/browser/download/chrome_download_manager_delegate.h b/chrome/browser/download/chrome_download_manager_delegate.h
index 2eaf5f4..b19c7fa 100644
--- a/chrome/browser/download/chrome_download_manager_delegate.h
+++ b/chrome/browser/download/chrome_download_manager_delegate.h
@@ -12,7 +12,7 @@
 #include <vector>
 
 #include "base/compiler_specific.h"
-#include "base/containers/hash_tables.h"
+#include "base/containers/flat_map.h"
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
@@ -181,8 +181,9 @@
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
   // Maps from pending extension installations to DownloadItem IDs.
-  typedef base::hash_map<extensions::CrxInstaller*,
-      content::DownloadOpenDelayedCallback> CrxInstallerMap;
+  typedef base::flat_map<extensions::CrxInstaller*,
+                         content::DownloadOpenDelayedCallback>
+      CrxInstallerMap;
   CrxInstallerMap crx_installers_;
 #endif
 
diff --git a/chrome/browser/engagement/important_sites_util.cc b/chrome/browser/engagement/important_sites_util.cc
index d79b9f7..a9133c9 100644
--- a/chrome/browser/engagement/important_sites_util.cc
+++ b/chrome/browser/engagement/important_sites_util.cc
@@ -137,7 +137,7 @@
     const GURL& origin,
     std::set<GURL>* visited_origins,
     ImportantReason reason,
-    base::hash_map<std::string, ImportantDomainInfo>* output) {
+    std::map<std::string, ImportantDomainInfo>* output) {
   if (!origin.is_valid() || !visited_origins->insert(origin).second)
     return;
   std::string registerable_domain =
@@ -227,7 +227,7 @@
     Profile* profile,
     blink::mojom::EngagementLevel minimum_engagement,
     std::map<GURL, double>* engagement_map,
-    base::hash_map<std::string, ImportantDomainInfo>* output) {
+    std::map<std::string, ImportantDomainInfo>* output) {
   SiteEngagementService* service = SiteEngagementService::Get(profile);
   *engagement_map = service->GetScoreMap();
   // We can have multiple origins for a single domain, so we record the one
@@ -254,7 +254,7 @@
     Profile* profile,
     ContentSettingsType content_type,
     ImportantReason reason,
-    base::hash_map<std::string, ImportantDomainInfo>* output) {
+    std::map<std::string, ImportantDomainInfo>* output) {
   // Grab our content settings list.
   ContentSettingsForOneType content_settings_list;
   HostContentSettingsMapFactory::GetForProfile(profile)->GetSettingsForOneType(
@@ -274,7 +274,7 @@
 void PopulateInfoMapWithBookmarks(
     Profile* profile,
     const std::map<GURL, double>& engagement_map,
-    base::hash_map<std::string, ImportantDomainInfo>* output) {
+    std::map<std::string, ImportantDomainInfo>* output) {
   SiteEngagementService* service = SiteEngagementService::Get(profile);
   BookmarkModel* model =
       BookmarkModelFactory::GetForBrowserContextIfExists(profile);
@@ -321,7 +321,7 @@
 
 void PopulateInfoMapWithHomeScreen(
     Profile* profile,
-    base::hash_map<std::string, ImportantDomainInfo>* output) {
+    std::map<std::string, ImportantDomainInfo>* output) {
   ContentSettingsForOneType content_settings_list;
   HostContentSettingsMapFactory::GetForProfile(profile)->GetSettingsForOneType(
       CONTENT_SETTINGS_TYPE_APP_BANNER, content_settings::ResourceIdentifier(),
@@ -370,7 +370,7 @@
 std::vector<ImportantDomainInfo>
 ImportantSitesUtil::GetImportantRegisterableDomains(Profile* profile,
                                                     size_t max_results) {
-  base::hash_map<std::string, ImportantDomainInfo> important_info;
+  std::map<std::string, ImportantDomainInfo> important_info;
   std::map<GURL, double> engagement_map;
 
   PopulateInfoMapWithSiteEngagement(
diff --git a/chrome/browser/extensions/api/downloads/downloads_api.cc b/chrome/browser/extensions/api/downloads/downloads_api.cc
index 085fd949..7098da67 100644
--- a/chrome/browser/extensions/api/downloads/downloads_api.cc
+++ b/chrome/browser/extensions/api/downloads/downloads_api.cc
@@ -14,6 +14,7 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/callback.h"
+#include "base/containers/flat_map.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/json/json_writer.h"
@@ -362,49 +363,69 @@
   }
 }
 
-typedef base::hash_map<std::string, DownloadQuery::FilterType> FilterTypeMap;
-
-void InitFilterTypeMap(FilterTypeMap* filter_types_ptr) {
-  FilterTypeMap& filter_types = *filter_types_ptr;
-  filter_types[kBytesReceivedKey] = DownloadQuery::FILTER_BYTES_RECEIVED;
-  filter_types[kExistsKey] = DownloadQuery::FILTER_EXISTS;
-  filter_types[kFilenameKey] = DownloadQuery::FILTER_FILENAME;
-  filter_types[kFilenameRegexKey] = DownloadQuery::FILTER_FILENAME_REGEX;
-  filter_types[kMimeKey] = DownloadQuery::FILTER_MIME;
-  filter_types[kPausedKey] = DownloadQuery::FILTER_PAUSED;
-  filter_types[kQueryKey] = DownloadQuery::FILTER_QUERY;
-  filter_types[kEndedAfterKey] = DownloadQuery::FILTER_ENDED_AFTER;
-  filter_types[kEndedBeforeKey] = DownloadQuery::FILTER_ENDED_BEFORE;
-  filter_types[kEndTimeKey] = DownloadQuery::FILTER_END_TIME;
-  filter_types[kStartedAfterKey] = DownloadQuery::FILTER_STARTED_AFTER;
-  filter_types[kStartedBeforeKey] = DownloadQuery::FILTER_STARTED_BEFORE;
-  filter_types[kStartTimeKey] = DownloadQuery::FILTER_START_TIME;
-  filter_types[kTotalBytesKey] = DownloadQuery::FILTER_TOTAL_BYTES;
-  filter_types[kTotalBytesGreaterKey] =
-    DownloadQuery::FILTER_TOTAL_BYTES_GREATER;
-  filter_types[kTotalBytesLessKey] = DownloadQuery::FILTER_TOTAL_BYTES_LESS;
-  filter_types[kUrlKey] = DownloadQuery::FILTER_ORIGINAL_URL;
-  filter_types[kUrlRegexKey] = DownloadQuery::FILTER_ORIGINAL_URL_REGEX;
-  filter_types[kFinalUrlKey] = DownloadQuery::FILTER_URL;
-  filter_types[kFinalUrlRegexKey] = DownloadQuery::FILTER_URL_REGEX;
+using FilterTypeMap = base::flat_map<std::string, DownloadQuery::FilterType>;
+void AppendFilter(const char* name,
+                  DownloadQuery::FilterType type,
+                  std::vector<FilterTypeMap::value_type>* v) {
+  v->emplace_back(name, type);
 }
 
-typedef base::hash_map<std::string, DownloadQuery::SortType> SortTypeMap;
+void InitFilterTypeMap(FilterTypeMap* filter_types_ptr) {
+  // Initialize the map in one shot by storing to a vector and assigning.
+  std::vector<FilterTypeMap::value_type> v;
+
+  AppendFilter(kBytesReceivedKey, DownloadQuery::FILTER_BYTES_RECEIVED, &v);
+
+  AppendFilter(kBytesReceivedKey, DownloadQuery::FILTER_BYTES_RECEIVED, &v);
+  AppendFilter(kExistsKey, DownloadQuery::FILTER_EXISTS, &v);
+  AppendFilter(kFilenameKey, DownloadQuery::FILTER_FILENAME, &v);
+  AppendFilter(kFilenameRegexKey, DownloadQuery::FILTER_FILENAME_REGEX, &v);
+  AppendFilter(kMimeKey, DownloadQuery::FILTER_MIME, &v);
+  AppendFilter(kPausedKey, DownloadQuery::FILTER_PAUSED, &v);
+  AppendFilter(kQueryKey, DownloadQuery::FILTER_QUERY, &v);
+  AppendFilter(kEndedAfterKey, DownloadQuery::FILTER_ENDED_AFTER, &v);
+  AppendFilter(kEndedBeforeKey, DownloadQuery::FILTER_ENDED_BEFORE, &v);
+  AppendFilter(kEndTimeKey, DownloadQuery::FILTER_END_TIME, &v);
+  AppendFilter(kStartedAfterKey, DownloadQuery::FILTER_STARTED_AFTER, &v);
+  AppendFilter(kStartedBeforeKey, DownloadQuery::FILTER_STARTED_BEFORE, &v);
+  AppendFilter(kStartTimeKey, DownloadQuery::FILTER_START_TIME, &v);
+  AppendFilter(kTotalBytesKey, DownloadQuery::FILTER_TOTAL_BYTES, &v);
+  AppendFilter(kTotalBytesGreaterKey, DownloadQuery::FILTER_TOTAL_BYTES_GREATER,
+               &v);
+  AppendFilter(kTotalBytesLessKey, DownloadQuery::FILTER_TOTAL_BYTES_LESS, &v);
+  AppendFilter(kUrlKey, DownloadQuery::FILTER_ORIGINAL_URL, &v);
+  AppendFilter(kUrlRegexKey, DownloadQuery::FILTER_ORIGINAL_URL_REGEX, &v);
+  AppendFilter(kFinalUrlKey, DownloadQuery::FILTER_URL, &v);
+  AppendFilter(kFinalUrlRegexKey, DownloadQuery::FILTER_URL_REGEX, &v);
+
+  *filter_types_ptr = FilterTypeMap(std::move(v), base::KEEP_FIRST_OF_DUPES);
+}
+
+using SortTypeMap = base::flat_map<std::string, DownloadQuery::SortType>;
+void AppendFilter(const char* name,
+                  DownloadQuery::SortType type,
+                  std::vector<SortTypeMap::value_type>* v) {
+  v->emplace_back(name, type);
+}
 
 void InitSortTypeMap(SortTypeMap* sorter_types_ptr) {
-  SortTypeMap& sorter_types = *sorter_types_ptr;
-  sorter_types[kBytesReceivedKey] = DownloadQuery::SORT_BYTES_RECEIVED;
-  sorter_types[kDangerKey] = DownloadQuery::SORT_DANGER;
-  sorter_types[kEndTimeKey] = DownloadQuery::SORT_END_TIME;
-  sorter_types[kExistsKey] = DownloadQuery::SORT_EXISTS;
-  sorter_types[kFilenameKey] = DownloadQuery::SORT_FILENAME;
-  sorter_types[kMimeKey] = DownloadQuery::SORT_MIME;
-  sorter_types[kPausedKey] = DownloadQuery::SORT_PAUSED;
-  sorter_types[kStartTimeKey] = DownloadQuery::SORT_START_TIME;
-  sorter_types[kStateKey] = DownloadQuery::SORT_STATE;
-  sorter_types[kTotalBytesKey] = DownloadQuery::SORT_TOTAL_BYTES;
-  sorter_types[kUrlKey] = DownloadQuery::SORT_ORIGINAL_URL;
-  sorter_types[kFinalUrlKey] = DownloadQuery::SORT_URL;
+  // Initialize the map in one shot by storing to a vector and assigning.
+  std::vector<SortTypeMap::value_type> v;
+
+  AppendFilter(kBytesReceivedKey, DownloadQuery::SORT_BYTES_RECEIVED, &v);
+  AppendFilter(kDangerKey, DownloadQuery::SORT_DANGER, &v);
+  AppendFilter(kEndTimeKey, DownloadQuery::SORT_END_TIME, &v);
+  AppendFilter(kExistsKey, DownloadQuery::SORT_EXISTS, &v);
+  AppendFilter(kFilenameKey, DownloadQuery::SORT_FILENAME, &v);
+  AppendFilter(kMimeKey, DownloadQuery::SORT_MIME, &v);
+  AppendFilter(kPausedKey, DownloadQuery::SORT_PAUSED, &v);
+  AppendFilter(kStartTimeKey, DownloadQuery::SORT_START_TIME, &v);
+  AppendFilter(kStateKey, DownloadQuery::SORT_STATE, &v);
+  AppendFilter(kTotalBytesKey, DownloadQuery::SORT_TOTAL_BYTES, &v);
+  AppendFilter(kUrlKey, DownloadQuery::SORT_ORIGINAL_URL, &v);
+  AppendFilter(kFinalUrlKey, DownloadQuery::SORT_URL, &v);
+
+  *sorter_types_ptr = SortTypeMap(std::move(v), base::KEEP_FIRST_OF_DUPES);
 }
 
 bool IsNotTemporaryDownloadFilter(const DownloadItem& download_item) {
diff --git a/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc b/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc
index 0a4e9ba..00258b0 100644
--- a/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc
+++ b/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc
@@ -1258,9 +1258,9 @@
             items[1]->GetTargetFilePath().value());
   // The order of results when orderBy is empty is unspecified. When there are
   // no sorters, DownloadQuery does not call sort(), so the order of the results
-  // depends on the order of the items in base::hash_map<uint32_t,...>
-  // DownloadManagerImpl::downloads_, which is unspecified and differs between
-  // libc++ and libstdc++. http://crbug.com/365334
+  // depends on the order of the items in DownloadManagerImpl::downloads_,
+  // which is unspecified and differs between libc++ and libstdc++.
+  // http://crbug.com/365334
 }
 
 // Test the |danger| option for search().
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index 763dbbbc..f19ebad 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -364,11 +364,15 @@
   // Set up the ExtensionUpdater.
   if (autoupdate_enabled) {
     int update_frequency = extensions::kDefaultUpdateFrequencySeconds;
-    if (command_line->HasSwitch(switches::kExtensionsUpdateFrequency)) {
+    bool is_extensions_update_frequency_switch_used =
+        command_line->HasSwitch(switches::kExtensionsUpdateFrequency);
+    if (is_extensions_update_frequency_switch_used) {
       base::StringToInt(command_line->GetSwitchValueASCII(
           switches::kExtensionsUpdateFrequency),
           &update_frequency);
     }
+    UMA_HISTOGRAM_BOOLEAN("Extensions.UpdateFrequencyCommandLineFlagIsUsed",
+                          is_extensions_update_frequency_switch_used);
     updater_.reset(new extensions::ExtensionUpdater(
         this,
         extension_prefs,
diff --git a/chrome/browser/feedback/system_logs/system_logs_fetcher.cc b/chrome/browser/feedback/system_logs/system_logs_fetcher.cc
index 97dc689..fe9e2ba 100644
--- a/chrome/browser/feedback/system_logs/system_logs_fetcher.cc
+++ b/chrome/browser/feedback/system_logs/system_logs_fetcher.cc
@@ -15,6 +15,29 @@
 
 namespace system_logs {
 
+namespace {
+
+// List of keys in the SystemLogsResponse map whose corresponding values will
+// not be anonymized.
+constexpr const char* const kWhitelistedKeysOfUUIDs[] = {
+    "CHROMEOS_BOARD_APPID",
+    "CHROMEOS_CANARY_APPID",
+    "CHROMEOS_RELEASE_APPID",
+    "CLIENT_ID",
+};
+
+// Returns true if the given |key| is anonymizer-whitelisted and whose
+// corresponding value should not be anonymized.
+bool IsKeyWhitelisted(const std::string& key) {
+  for (auto* const whitelisted_key : kWhitelistedKeysOfUUIDs) {
+    if (key == whitelisted_key)
+      return true;
+  }
+  return false;
+}
+
+}  // namespace
+
 SystemLogsSource::SystemLogsSource(const std::string& source_name)
     : source_name_(source_name) {}
 
@@ -56,8 +79,10 @@
   VLOG(1) << "Received SystemLogSource: " << source_name;
 
   if (anonymizer_) {
-    for (auto& element : *response)
-      element.second = anonymizer_->Anonymize(element.second);
+    for (auto& element : *response) {
+      if (!IsKeyWhitelisted(element.first))
+        element.second = anonymizer_->Anonymize(element.second);
+    }
   }
   AddResponse(source_name, response);
 }
diff --git a/chrome/browser/feedback/system_logs/system_logs_fetcher.h b/chrome/browser/feedback/system_logs/system_logs_fetcher.h
index 8fe6af7..427b3fc 100644
--- a/chrome/browser/feedback/system_logs/system_logs_fetcher.h
+++ b/chrome/browser/feedback/system_logs/system_logs_fetcher.h
@@ -80,9 +80,6 @@
   // AddResponse().
   void OnFetched(const std::string& source_name, SystemLogsResponse* response);
 
-  // Anonymizes the response data.
-  void Scrub(SystemLogsResponse* response);
-
   // Merges the |response| it receives into response_. When all the data sources
   // have responded, it deletes their objects and returns the response to the
   // callback_. After this it deletes this instance of the object.
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 27a9633..a73d18e 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -394,6 +394,13 @@
     "Enables running extensions on chrome:// URLs, where extensions "
     "explicitly request this permission.";
 
+const char kExperimentalFullscreenExitUIName[] =
+    "Experimental fullscreen exit UI";
+
+const char kExperimentalFullscreenExitUIDescription[] =
+    "Displays experimental UI to allow mouse and touch input methods to exit "
+    "fullscreen mode.";
+
 const char kFastUnloadName[] = "Fast tab/window close";
 
 const char kFastUnloadDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 41a03a2..e7b08eca 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -343,6 +343,9 @@
 extern const char kEffectiveConnectionType3GDescription[];
 extern const char kEffectiveConnectionType4GDescription[];
 
+extern const char kExperimentalFullscreenExitUIName[];
+extern const char kExperimentalFullscreenExitUIDescription[];
+
 extern const char kFillOnAccountSelectName[];
 extern const char kFillOnAccountSelectDescription[];
 
diff --git a/chrome/browser/font_family_cache.cc b/chrome/browser/font_family_cache.cc
index bf23590..94611c66 100644
--- a/chrome/browser/font_family_cache.cc
+++ b/chrome/browser/font_family_cache.cc
@@ -91,17 +91,15 @@
 void FontFamilyCache::OnPrefsChanged(const std::string& pref_name) {
   const size_t delimiter_length = 1;
   const char delimiter = '.';
-  for (FontFamilyMap::iterator it = font_family_map_.begin();
-       it != font_family_map_.end();
-       ++it) {
-    const char* map_name = it->first;
+  for (auto& it : font_family_map_) {
+    const char* map_name = it.first;
     size_t map_name_length = strlen(map_name);
 
     // If the map name doesn't match, move on.
     if (pref_name.compare(0, map_name_length, map_name) != 0)
       continue;
 
-    ScriptFontMap& map = it->second;
+    ScriptFontMap& map = it.second;
     for (ScriptFontMap::iterator it2 = map.begin(); it2 != map.end(); ++it2) {
       const char* script = it2->first;
       size_t script_length = strlen(script);
diff --git a/chrome/browser/font_family_cache.h b/chrome/browser/font_family_cache.h
index 743448d..2961f37 100644
--- a/chrome/browser/font_family_cache.h
+++ b/chrome/browser/font_family_cache.h
@@ -5,7 +5,8 @@
 #ifndef CHROME_BROWSER_FONT_FAMILY_CACHE_H_
 #define CHROME_BROWSER_FONT_FAMILY_CACHE_H_
 
-#include "base/containers/hash_tables.h"
+#include <unordered_map>
+
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/strings/string16.h"
@@ -23,7 +24,7 @@
 // Caches font family preferences associated with a PrefService. This class
 // relies on the assumption that each concatenation of map_name + '.' + script
 // is a unique string. It also relies on the assumption that the (const char*)
-// keys used in both inner and outer hash_maps are compile time constants.
+// keys used in both inner and outer maps are compile time constants.
 class FontFamilyCache : public base::SupportsUserData::Data,
                         public content::NotificationObserver {
  public:
@@ -49,11 +50,11 @@
 
   // Map from script to font.
   // Key comparison uses pointer equality.
-  typedef base::hash_map<const char*, base::string16> ScriptFontMap;
+  using ScriptFontMap = std::unordered_map<const char*, base::string16>;
 
   // Map from font family to ScriptFontMap.
   // Key comparison uses pointer equality.
-  typedef base::hash_map<const char*, ScriptFontMap> FontFamilyMap;
+  using FontFamilyMap = std::unordered_map<const char*, ScriptFontMap>;
 
   // Checks the cache for the font. If not present, fetches the font and stores
   // the result in the cache.
@@ -63,7 +64,7 @@
   // of std::string.
   // |script| and |map_name| must be compile time constants. Two behaviors rely
   // on this: key comparison uses pointer equality, and keys must outlive the
-  // hash_maps.
+  // maps.
   base::string16 FetchAndCacheFont(const char* script, const char* map_name);
 
   // Called when font family preferences changed.
diff --git a/chrome/browser/geolocation/geolocation_permission_context_android.cc b/chrome/browser/geolocation/geolocation_permission_context_android.cc
index e722927..085f54401 100644
--- a/chrome/browser/geolocation/geolocation_permission_context_android.cc
+++ b/chrome/browser/geolocation/geolocation_permission_context_android.cc
@@ -149,10 +149,9 @@
     const BrowserPermissionCallback& callback) {
   if (!IsLocationAccessPossible(web_contents, requesting_frame_origin,
                                 user_gesture)) {
-    PermissionDecided(id, requesting_frame_origin,
-                      web_contents->GetLastCommittedURL().GetOrigin(),
-                      user_gesture, callback, false /* persist */,
-                      CONTENT_SETTING_BLOCK);
+    NotifyPermissionSet(id, requesting_frame_origin,
+                        web_contents->GetLastCommittedURL().GetOrigin(),
+                        callback, false /* persist */, CONTENT_SETTING_BLOCK);
     return;
   }
 
diff --git a/chrome/browser/geolocation/geolocation_permission_context_unittest.cc b/chrome/browser/geolocation/geolocation_permission_context_unittest.cc
index 331aa7ee..4d594ad 100644
--- a/chrome/browser/geolocation/geolocation_permission_context_unittest.cc
+++ b/chrome/browser/geolocation/geolocation_permission_context_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <stddef.h>
 
+#include <map>
 #include <set>
 #include <string>
 #include <utility>
@@ -13,7 +14,6 @@
 
 #include "base/bind.h"
 #include "base/command_line.h"
-#include "base/containers/hash_tables.h"
 #include "base/gtest_prod_util.h"
 #include "base/id_map.h"
 #include "base/memory/ptr_util.h"
@@ -210,7 +210,7 @@
 
   // A map between renderer child id and a pair represending the bridge id and
   // whether the requested permission was allowed.
-  base::hash_map<int, std::pair<int, bool> > responses_;
+  std::map<int, std::pair<int, bool>> responses_;
 
   // For testing the PermissionRequestManager on Android
   base::test::ScopedFeatureList scoped_feature_list_;
@@ -557,20 +557,26 @@
   GURL requesting_frame("https://www.example.com/geolocation");
   NavigateAndCommit(requesting_frame);
   RequestManagerDocumentLoadCompleted();
+  base::HistogramTester histograms;
   MockLocationSettings::SetLocationStatus(true /* android */,
                                           true /* system */);
   EXPECT_FALSE(HasActivePrompt());
   RequestGeolocationPermission(
       web_contents(), RequestID(0), requesting_frame, true);
   EXPECT_TRUE(HasActivePrompt());
+  histograms.ExpectTotalCount("Permissions.Action.Geolocation", 0);
 
   Reload();
+  histograms.ExpectUniqueSample("Permissions.Action.Geolocation",
+                                static_cast<int>(PermissionAction::IGNORED), 1);
   MockLocationSettings::SetLocationStatus(false /* android */,
                                           true /* system */);
   MockLocationSettings::SetCanPromptForAndroidPermission(false);
   EXPECT_FALSE(HasActivePrompt());
   RequestGeolocationPermission(
       web_contents(), RequestID(0), requesting_frame, true);
+  histograms.ExpectUniqueSample("Permissions.Action.Geolocation",
+                                static_cast<int>(PermissionAction::IGNORED), 1);
   EXPECT_FALSE(HasActivePrompt());
 }
 
diff --git a/chrome/browser/local_discovery/service_discovery_client.h b/chrome/browser/local_discovery/service_discovery_client.h
index 63d3be2a..70627f3e 100644
--- a/chrome/browser/local_discovery/service_discovery_client.h
+++ b/chrome/browser/local_discovery/service_discovery_client.h
@@ -63,7 +63,7 @@
   virtual void Start() = 0;
 
   // Probe for services of this type.
-  virtual void DiscoverNewServices(bool force_update) = 0;
+  virtual void DiscoverNewServices() = 0;
 
   virtual void SetActivelyRefreshServices(bool actively_refresh_services) = 0;
 
diff --git a/chrome/browser/local_discovery/service_discovery_client_impl.cc b/chrome/browser/local_discovery/service_discovery_client_impl.cc
index 9b07f255..b6ae3a16 100644
--- a/chrome/browser/local_discovery/service_discovery_client_impl.cc
+++ b/chrome/browser/local_discovery/service_discovery_client_impl.cc
@@ -78,11 +78,9 @@
 ServiceWatcherImpl::~ServiceWatcherImpl() {
 }
 
-void ServiceWatcherImpl::DiscoverNewServices(bool force_update) {
+void ServiceWatcherImpl::DiscoverNewServices() {
   DCHECK(started_);
-  if (force_update)
-    services_.clear();
-  SendQuery(kInitialRequeryTimeSeconds, force_update);
+  SendQuery(kInitialRequeryTimeSeconds);
 }
 
 void ServiceWatcherImpl::SetActivelyRefreshServices(
@@ -96,14 +94,12 @@
 
 void ServiceWatcherImpl::ReadCachedServices() {
   DCHECK(started_);
-  CreateTransaction(false /*network*/, true /*cache*/, false /*force refresh*/,
-                    &transaction_cache_);
+  CreateTransaction(false /*network*/, true /*cache*/, &transaction_cache_);
 }
 
 bool ServiceWatcherImpl::CreateTransaction(
     bool network,
     bool cache,
-    bool force_refresh,
     std::unique_ptr<net::MDnsTransaction>* transaction) {
   int transaction_flags = 0;
   if (network)
@@ -112,7 +108,6 @@
   if (cache)
     transaction_flags |= net::MDnsTransaction::QUERY_CACHE;
 
-  // TODO(noamsml): Add flag for force_refresh when supported.
   if (transaction_flags) {
     *transaction = mdns_client_->CreateTransaction(
         net::dns_protocol::kTypePTR, service_type_, transaction_flags,
@@ -318,16 +313,13 @@
     base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE,
         base::BindOnce(&ServiceWatcherImpl::SendQuery, AsWeakPtr(),
-                       timeout_seconds * 2 /*next_timeout_seconds*/,
-                       false /*force_update*/),
+                       timeout_seconds * 2 /*next_timeout_seconds*/),
         base::TimeDelta::FromSeconds(timeout_seconds));
   }
 }
 
-void ServiceWatcherImpl::SendQuery(int next_timeout_seconds,
-                                   bool force_update) {
-  CreateTransaction(true /*network*/, false /*cache*/, force_update,
-                    &transaction_network_);
+void ServiceWatcherImpl::SendQuery(int next_timeout_seconds) {
+  CreateTransaction(true /*network*/, false /*cache*/, &transaction_network_);
   ScheduleQuery(next_timeout_seconds);
 }
 
diff --git a/chrome/browser/local_discovery/service_discovery_client_impl.h b/chrome/browser/local_discovery/service_discovery_client_impl.h
index ff860ba..cb1d8dd3 100644
--- a/chrome/browser/local_discovery/service_discovery_client_impl.h
+++ b/chrome/browser/local_discovery/service_discovery_client_impl.h
@@ -61,7 +61,7 @@
   // ServiceWatcher implementation:
   void Start() override;
 
-  void DiscoverNewServices(bool force_update) override;
+  void DiscoverNewServices() override;
 
   void SetActivelyRefreshServices(bool actively_refresh_services) override;
 
@@ -130,7 +130,6 @@
   void AddSRV(const std::string& service);
   bool CreateTransaction(bool active,
                          bool alert_existing_services,
-                         bool force_refresh,
                          std::unique_ptr<net::MDnsTransaction>* transaction);
 
   void DeferUpdate(ServiceWatcher::UpdateType update_type,
@@ -140,7 +139,7 @@
 
   void ScheduleQuery(int timeout_seconds);
 
-  void SendQuery(int next_timeout_seconds, bool force_update);
+  void SendQuery(int next_timeout_seconds);
 
   const std::string service_type_;
   ServiceListenersMap services_;
diff --git a/chrome/browser/local_discovery/service_discovery_client_mac.h b/chrome/browser/local_discovery/service_discovery_client_mac.h
index 9817495..4305765d 100644
--- a/chrome/browser/local_discovery/service_discovery_client_mac.h
+++ b/chrome/browser/local_discovery/service_discovery_client_mac.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_LOCAL_DISCOVERY_SERVICE_DISCOVERY_CLIENT_MAC_H_
 
 #import <Foundation/Foundation.h>
+#include <memory>
 #include <string>
 
 #include "base/mac/scoped_nsobject.h"
@@ -107,7 +108,7 @@
   ~ServiceWatcherImplMac() override;
 
   void Start() override;
-  void DiscoverNewServices(bool force_update) override;
+  void DiscoverNewServices() override;
   void SetActivelyRefreshServices(bool actively_refresh_services) override;
   std::string GetServiceType() const override;
 
diff --git a/chrome/browser/local_discovery/service_discovery_client_mac.mm b/chrome/browser/local_discovery/service_discovery_client_mac.mm
index f5cbf5ad..38f709e 100644
--- a/chrome/browser/local_discovery/service_discovery_client_mac.mm
+++ b/chrome/browser/local_discovery/service_discovery_client_mac.mm
@@ -271,7 +271,7 @@
   started_ = true;
 }
 
-void ServiceWatcherImplMac::DiscoverNewServices(bool force_update) {
+void ServiceWatcherImplMac::DiscoverNewServices() {
   DCHECK(started_);
   VLOG(1) << "ServiceWatcherImplMac::DiscoverNewServices";
   container_->DiscoverNewServices();
diff --git a/chrome/browser/local_discovery/service_discovery_client_mdns.cc b/chrome/browser/local_discovery/service_discovery_client_mdns.cc
index 0c1e2ca..56f1313 100644
--- a/chrome/browser/local_discovery/service_discovery_client_mdns.cc
+++ b/chrome/browser/local_discovery/service_discovery_client_mdns.cc
@@ -9,11 +9,12 @@
 #include <utility>
 #include <vector>
 
+#include "base/bind.h"
 #include "base/location.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
-#include "base/single_thread_task_runner.h"
+#include "base/task_scheduler/post_task.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/local_discovery/service_discovery_client_impl.h"
 #include "content/public/browser/browser_thread.h"
@@ -210,11 +211,10 @@
     }
   }
 
-  void DiscoverNewServices(bool force_update) override {
+  void DiscoverNewServices() override {
     if (implementation()) {
       PostToMdnsThread(base::Bind(&ServiceWatcher::DiscoverNewServices,
-                                  base::Unretained(implementation()),
-                                  force_update));
+                                  base::Unretained(implementation())));
     }
   }
 
@@ -407,12 +407,11 @@
   DestroyMdns();
   mdns_ = net::MDnsClient::CreateDefault();
   client_ = base::MakeUnique<ServiceDiscoveryClientImpl>(mdns_.get());
-  BrowserThread::PostTaskAndReplyWithResult(
-      BrowserThread::FILE,
-      FROM_HERE,
-      base::Bind(&net::GetMDnsInterfacesToBind),
-      base::Bind(&ServiceDiscoveryClientMdns::OnInterfaceListReady,
-                 weak_ptr_factory_.GetWeakPtr()));
+  base::PostTaskWithTraitsAndReplyWithResult(
+      FROM_HERE, {base::TaskPriority::BACKGROUND, base::MayBlock()},
+      base::BindOnce(&net::GetMDnsInterfacesToBind),
+      base::BindOnce(&ServiceDiscoveryClientMdns::OnInterfaceListReady,
+                     weak_ptr_factory_.GetWeakPtr()));
 }
 
 void ServiceDiscoveryClientMdns::OnInterfaceListReady(
diff --git a/chrome/browser/local_discovery/service_discovery_client_unittest.cc b/chrome/browser/local_discovery/service_discovery_client_unittest.cc
index c252f465..63daa59 100644
--- a/chrome/browser/local_discovery/service_discovery_client_unittest.cc
+++ b/chrome/browser/local_discovery/service_discovery_client_unittest.cc
@@ -266,7 +266,7 @@
 
   EXPECT_CALL(socket_factory_, OnSendTo(_)).Times(2);
 
-  watcher->DiscoverNewServices(false);
+  watcher->DiscoverNewServices();
 
   EXPECT_CALL(socket_factory_, OnSendTo(_)).Times(2);
 
@@ -275,7 +275,6 @@
 
 TEST_F(ServiceDiscoveryTest, ReadCachedServices) {
   socket_factory_.SimulateReceive(kSamplePacketPTR, sizeof(kSamplePacketPTR));
-
   StrictMock<MockServiceWatcherClient> delegate;
 
   std::unique_ptr<ServiceWatcher> watcher(
diff --git a/chrome/browser/local_discovery/service_discovery_device_lister.cc b/chrome/browser/local_discovery/service_discovery_device_lister.cc
index d500ef8..99f56f3 100644
--- a/chrome/browser/local_discovery/service_discovery_device_lister.cc
+++ b/chrome/browser/local_discovery/service_discovery_device_lister.cc
@@ -40,9 +40,9 @@
   CreateServiceWatcher();
 }
 
-void ServiceDiscoveryDeviceLister::DiscoverNewDevices(bool force_update) {
+void ServiceDiscoveryDeviceLister::DiscoverNewDevices() {
   VLOG(1) << "DiscoverNewDevices: service_type: " << service_type_;
-  service_watcher_->DiscoverNewServices(force_update);
+  service_watcher_->DiscoverNewServices();
 }
 
 void ServiceDiscoveryDeviceLister::OnServiceUpdated(
diff --git a/chrome/browser/local_discovery/service_discovery_device_lister.h b/chrome/browser/local_discovery/service_discovery_device_lister.h
index 6836129..affe3ebc 100644
--- a/chrome/browser/local_discovery/service_discovery_device_lister.h
+++ b/chrome/browser/local_discovery/service_discovery_device_lister.h
@@ -33,7 +33,7 @@
   virtual ~ServiceDiscoveryDeviceLister();
 
   void Start();
-  void DiscoverNewDevices(bool force_update);
+  void DiscoverNewDevices();
 
   const std::string& service_type() const { return service_type_; }
 
diff --git a/chrome/browser/local_discovery/service_discovery_shared_client.cc b/chrome/browser/local_discovery/service_discovery_shared_client.cc
index cdc48d9..6179a7c 100644
--- a/chrome/browser/local_discovery/service_discovery_shared_client.cc
+++ b/chrome/browser/local_discovery/service_discovery_shared_client.cc
@@ -10,9 +10,11 @@
 #include "net/net_features.h"
 
 #if defined(OS_WIN)
+#include "base/bind.h"
 #include "base/files/file_path.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/path_service.h"
+#include "base/task_scheduler/post_task.h"
 #include "base/timer/elapsed_timer.h"
 #include "chrome/installer/util/browser_distribution.h"
 #include "chrome/installer/util/firewall_manager_win.h"
@@ -78,8 +80,9 @@
   static bool is_firewall_state_reported = false;
   if (!is_firewall_state_reported) {
     is_firewall_state_reported = true;
-    BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
-                            base::Bind(&ReportFirewallStats));
+    auto task_runner = base::CreateCOMSTATaskRunnerWithTraits(
+        {base::TaskPriority::BACKGROUND, base::MayBlock()});
+    task_runner->PostTask(FROM_HERE, base::BindOnce(&ReportFirewallStats));
   }
 #endif  // defined(OS_WIN)
 
diff --git a/chrome/browser/media/router/discovery/dial/dial_registry.h b/chrome/browser/media/router/discovery/dial/dial_registry.h
index f981fbb..1091e18 100644
--- a/chrome/browser/media/router/discovery/dial/dial_registry.h
+++ b/chrome/browser/media/router/discovery/dial/dial_registry.h
@@ -12,7 +12,6 @@
 #include <string>
 #include <vector>
 
-#include "base/containers/hash_tables.h"
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/memory/singleton.h"
@@ -100,8 +99,7 @@
   std::unique_ptr<DialService> dial_;
 
  private:
-  using DeviceByIdMap =
-      base::hash_map<std::string, std::unique_ptr<DialDeviceData>>;
+  using DeviceByIdMap = std::map<std::string, std::unique_ptr<DialDeviceData>>;
   using DeviceByLabelMap = std::map<std::string, DialDeviceData*>;
 
   friend class MockDialRegistry;
diff --git a/chrome/browser/media/router/discovery/mdns/dns_sd_device_lister.cc b/chrome/browser/media/router/discovery/mdns/dns_sd_device_lister.cc
index cd0e4fda..00b3883 100644
--- a/chrome/browser/media/router/discovery/mdns/dns_sd_device_lister.cc
+++ b/chrome/browser/media/router/discovery/mdns/dns_sd_device_lister.cc
@@ -35,14 +35,14 @@
 
 DnsSdDeviceLister::~DnsSdDeviceLister() {}
 
-void DnsSdDeviceLister::Discover(bool force_update) {
+void DnsSdDeviceLister::Discover() {
   if (!started_) {
     device_lister_.Start();
     started_ = true;
     VLOG(1) << "Started device lister for service type "
             << device_lister_.service_type();
   }
-  device_lister_.DiscoverNewDevices(force_update);
+  device_lister_.DiscoverNewDevices();
   VLOG(1) << "Discovery new devices for service type "
           << device_lister_.service_type();
 }
@@ -70,7 +70,7 @@
   VLOG(1) << "OnDeviceCacheFlushed: "
           << "service_type: " << device_lister_.service_type();
   delegate_->ServicesFlushed(device_lister_.service_type());
-  device_lister_.DiscoverNewDevices(false);
+  device_lister_.DiscoverNewDevices();
 }
 
 }  // namespace media_router
diff --git a/chrome/browser/media/router/discovery/mdns/dns_sd_device_lister.h b/chrome/browser/media/router/discovery/mdns/dns_sd_device_lister.h
index 4e70789..6215463 100644
--- a/chrome/browser/media/router/discovery/mdns/dns_sd_device_lister.h
+++ b/chrome/browser/media/router/discovery/mdns/dns_sd_device_lister.h
@@ -28,7 +28,7 @@
       const std::string& service_type);
   virtual ~DnsSdDeviceLister();
 
-  virtual void Discover(bool force_update);
+  virtual void Discover();
 
  protected:
   void OnDeviceChanged(
diff --git a/chrome/browser/media/router/discovery/mdns/dns_sd_registry.cc b/chrome/browser/media/router/discovery/mdns/dns_sd_registry.cc
index 300daac3..5cce6f5 100644
--- a/chrome/browser/media/router/discovery/mdns/dns_sd_registry.cc
+++ b/chrome/browser/media/router/discovery/mdns/dns_sd_registry.cc
@@ -87,11 +87,11 @@
 }
 
 void DnsSdRegistry::ServiceTypeData::ForceDiscovery() {
-  lister_->Discover(false);
+  lister_->Discover();
 }
 
 bool DnsSdRegistry::ServiceTypeData::ClearServices() {
-  lister_->Discover(false);
+  lister_->Discover();
 
   if (service_list_.empty())
     return false;
@@ -170,7 +170,7 @@
   std::unique_ptr<DnsSdDeviceLister> dns_sd_device_lister(
       CreateDnsSdDeviceLister(this, service_type,
                               service_discovery_client_.get()));
-  dns_sd_device_lister->Discover(false);
+  dns_sd_device_lister->Discover();
   service_data_map_[service_type] =
       base::MakeUnique<ServiceTypeData>(std::move(dns_sd_device_lister));
   DispatchApiEvent(service_type);
diff --git a/chrome/browser/media/router/discovery/mdns/dns_sd_registry_unittest.cc b/chrome/browser/media/router/discovery/mdns/dns_sd_registry_unittest.cc
index 38b87b3..c988f51e 100644
--- a/chrome/browser/media/router/discovery/mdns/dns_sd_registry_unittest.cc
+++ b/chrome/browser/media/router/discovery/mdns/dns_sd_registry_unittest.cc
@@ -15,7 +15,7 @@
   MockDnsSdDeviceLister() : DnsSdDeviceLister(NULL, NULL, "") {}
   ~MockDnsSdDeviceLister() override {}
 
-  MOCK_METHOD1(Discover, void(bool force_update));
+  MOCK_METHOD0(Discover, void());
 };
 
 class TestDnsSdRegistry : public DnsSdRegistry {
@@ -116,8 +116,8 @@
   EXPECT_EQ(1, registry_->GetServiceListenerCount(service_type1));
   EXPECT_EQ(1, registry_->GetServiceListenerCount(service_type2));
 
-  EXPECT_CALL(*registry_->GetLister(service_type1), Discover(false));
-  EXPECT_CALL(*registry_->GetLister(service_type2), Discover(false));
+  EXPECT_CALL(*registry_->GetLister(service_type1), Discover());
+  EXPECT_CALL(*registry_->GetLister(service_type2), Discover());
   registry_->ForceDiscovery();
 }
 
diff --git a/chrome/browser/media_galleries/fileapi/media_path_filter.h b/chrome/browser/media_galleries/fileapi/media_path_filter.h
index 6e9fe5b3..ce87605 100644
--- a/chrome/browser/media_galleries/fileapi/media_path_filter.h
+++ b/chrome/browser/media_galleries/fileapi/media_path_filter.h
@@ -7,10 +7,10 @@
 
 #include <stddef.h>
 
+#include <map>
 #include <string>
 #include <vector>
 
-#include "base/containers/hash_tables.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/sequence_checker.h"
@@ -45,7 +45,7 @@
 
   // Key: .extension
   // Value: MediaGalleryFileType, but stored as an int to allow "|="
-  typedef base::hash_map<base::FilePath::StringType, int> MediaFileExtensionMap;
+  using MediaFileExtensionMap = std::map<base::FilePath::StringType, int>;
 
   void EnsureInitialized();
 
diff --git a/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.h b/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.h
index 37e41665..e169b3b 100644
--- a/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.h
+++ b/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.h
@@ -12,7 +12,6 @@
 #include <memory>
 #include <vector>
 
-#include "base/containers/hash_tables.h"
 #include "base/files/file.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
@@ -156,8 +155,7 @@
   std::unique_ptr<DeviceListener> camera_interface_;
 
   // Stores a map from filename to file metadata received from the camera.
-  base::hash_map<base::FilePath::StringType,
-                 base::File::Info> file_info_;
+  std::map<base::FilePath::StringType, base::File::Info> file_info_;
 
   // List of filenames received from the camera.
   std::vector<base::FilePath> file_paths_;
diff --git a/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.mm b/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.mm
index ce31c826..5b7a959 100644
--- a/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.mm
+++ b/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.mm
@@ -297,9 +297,7 @@
     base::File::Info* file_info,
     base::File::Error* error) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  base::hash_map<base::FilePath::StringType,
-                 base::File::Info>::const_iterator i =
-      file_info_.find(file_path.value());
+  auto i = file_info_.find(file_path.value());
   if (i == file_info_.end()) {
     *error = base::File::FILE_ERROR_NOT_FOUND;
     return;
diff --git a/chrome/browser/metrics/ukm_browsertest.cc b/chrome/browser/metrics/ukm_browsertest.cc
index c11834d..50f2c08 100644
--- a/chrome/browser/metrics/ukm_browsertest.cc
+++ b/chrome/browser/metrics/ukm_browsertest.cc
@@ -62,7 +62,7 @@
 };
 
 // Make sure that UKM is disabled while an incognito window is open.
-IN_PROC_BROWSER_TEST_F(UkmBrowserTest, IncognitoCheck) {
+IN_PROC_BROWSER_TEST_F(UkmBrowserTest, DISABLED_IncognitoCheck) {
   // Enable metrics recording and update MetricsServicesManager.
   bool metrics_enabled = true;
   ChromeMetricsServiceAccessor::SetMetricsAndCrashReportingForTesting(
diff --git a/chrome/browser/net/predictor_browsertest.cc b/chrome/browser/net/predictor_browsertest.cc
index 362e0fa..fe2a9ba 100644
--- a/chrome/browser/net/predictor_browsertest.cc
+++ b/chrome/browser/net/predictor_browsertest.cc
@@ -6,6 +6,7 @@
 #include <stdint.h>
 
 #include <algorithm>
+#include <map>
 #include <memory>
 #include <set>
 
@@ -255,7 +256,7 @@
   // This lock protects all the members below, which each are used on both the
   // IO and UI thread. Members declared after the lock are protected by it.
   mutable base::Lock lock_;
-  typedef base::hash_map<uint16_t, SocketStatus> SocketContainer;
+  typedef std::map<uint16_t, SocketStatus> SocketContainer;
   SocketContainer sockets_;
 
   // If |num_accepted_connections_needed_| is non zero, then the object is
diff --git a/chrome/browser/notifications/notification_interactive_uitest.cc b/chrome/browser/notifications/notification_interactive_uitest.cc
index ee42f66..fc3890dd 100644
--- a/chrome/browser/notifications/notification_interactive_uitest.cc
+++ b/chrome/browser/notifications/notification_interactive_uitest.cc
@@ -236,7 +236,8 @@
 }
 
 IN_PROC_BROWSER_TEST_F(NotificationsTest, TestPermissionAPI) {
-  EnablePermissionsEmbargo();
+  base::test::ScopedFeatureList scoped_feature_list;
+  EnablePermissionsEmbargo(&scoped_feature_list);
   ASSERT_TRUE(embedded_test_server()->Start());
 
   // Test that Notification.permission returns the right thing.
@@ -575,7 +576,8 @@
 }
 
 IN_PROC_BROWSER_TEST_F(NotificationsTest, TestShouldDisplayNormal) {
-  EnableFullscreenNotifications();
+  base::test::ScopedFeatureList scoped_feature_list;
+  EnableFullscreenNotifications(&scoped_feature_list);
   ASSERT_TRUE(embedded_test_server()->Start());
 
   // Creates a simple notification.
@@ -599,7 +601,8 @@
 #if defined(OS_MACOSX)
   ui::test::ScopedFakeNSWindowFullscreen fake_fullscreen;
 #endif
-  EnableFullscreenNotifications();
+  base::test::ScopedFeatureList scoped_feature_list;
+  EnableFullscreenNotifications(&scoped_feature_list);
   ASSERT_TRUE(embedded_test_server()->Start());
 
   // Creates a simple notification.
@@ -636,7 +639,8 @@
 #if defined(OS_MACOSX)
   ui::test::ScopedFakeNSWindowFullscreen fake_fullscreen;
 #endif
-  DisableFullscreenNotifications();
+  base::test::ScopedFeatureList scoped_feature_list;
+  DisableFullscreenNotifications(&scoped_feature_list);
   ASSERT_TRUE(embedded_test_server()->Start());
 
   // Creates a simple notification.
@@ -674,7 +678,8 @@
 // window when another is visible.
 #if !defined(OS_MACOSX)
 IN_PROC_BROWSER_TEST_F(NotificationsTest, TestShouldDisplayMultiFullscreen) {
-  EnableFullscreenNotifications();
+  base::test::ScopedFeatureList scoped_feature_list;
+  EnableFullscreenNotifications(&scoped_feature_list);
   ASSERT_TRUE(embedded_test_server()->Start());
   AllowAllOrigins();
 
@@ -725,7 +730,8 @@
 #if defined(OS_MACOSX)
   ui::test::ScopedFakeNSWindowFullscreen fake_fullscreen;
 #endif
-  EnableFullscreenNotifications();
+  base::test::ScopedFeatureList scoped_feature_list;
+  EnableFullscreenNotifications(&scoped_feature_list);
   ASSERT_TRUE(embedded_test_server()->Start());
 
   // Creates a simple notification.
diff --git a/chrome/browser/notifications/notification_interactive_uitest_support.cc b/chrome/browser/notifications/notification_interactive_uitest_support.cc
index dec1019..4d8e157 100644
--- a/chrome/browser/notifications/notification_interactive_uitest_support.cc
+++ b/chrome/browser/notifications/notification_interactive_uitest_support.cc
@@ -123,8 +123,7 @@
 // Temporary change while the whole support class is changed to deal
 // with native notifications. crbug.com/714679
 #if BUILDFLAG(ENABLE_NATIVE_NOTIFICATIONS)
-  command_line->AppendSwitchASCII(switches::kDisableFeatures,
-                                  features::kNativeNotifications.name);
+  feature_list_.InitAndDisableFeature(features::kNativeNotifications);
 #endif  // BUILDFLAG(ENABLE_NATIVE_NOTIFICATIONS)
 }
 
@@ -301,34 +300,45 @@
   return browser->tab_strip_model()->GetActiveWebContents();
 }
 
-void NotificationsTest::EnablePermissionsEmbargo() {
-  feature_list_.InitWithFeatures({features::kBlockPromptsIfDismissedOften,
-                                  features::kBlockPromptsIfIgnoredOften},
-                                 {});
+void NotificationsTest::EnablePermissionsEmbargo(
+    base::test::ScopedFeatureList* scoped_feature_list) {
+#if BUILDFLAG(ENABLE_NATIVE_NOTIFICATIONS)
+  scoped_feature_list->InitWithFeatures(
+      {features::kBlockPromptsIfDismissedOften,
+       features::kBlockPromptsIfIgnoredOften},
+      {features::kNativeNotifications});
+#else
+  scoped_feature_list->InitWithFeatures(
+      {features::kBlockPromptsIfDismissedOften,
+       features::kBlockPromptsIfIgnoredOften},
+      {});
+#endif  //  BUILDFLAG(ENABLE_NATIVE_NOTIFICATIONS)
 }
 
-void NotificationsTest::EnableFullscreenNotifications() {
+void NotificationsTest::EnableFullscreenNotifications(
+    base::test::ScopedFeatureList* scoped_feature_list) {
 #if BUILDFLAG(ENABLE_NATIVE_NOTIFICATIONS)
-  feature_list_.InitWithFeatures(
+  scoped_feature_list->InitWithFeatures(
       {features::kPreferHtmlOverPlugins,
        features::kAllowFullscreenWebNotificationsFeature},
       {features::kNativeNotifications});
 #else
-  feature_list_.InitWithFeatures(
+  scoped_feature_list->InitWithFeatures(
       {features::kPreferHtmlOverPlugins,
        features::kAllowFullscreenWebNotificationsFeature},
       {});
 #endif  //  BUILDFLAG(ENABLE_NATIVE_NOTIFICATIONS)
 }
 
-void NotificationsTest::DisableFullscreenNotifications() {
+void NotificationsTest::DisableFullscreenNotifications(
+    base::test::ScopedFeatureList* scoped_feature_list) {
 #if BUILDFLAG(ENABLE_NATIVE_NOTIFICATIONS)
-  feature_list_.InitWithFeatures(
+  scoped_feature_list->InitWithFeatures(
       {features::kPreferHtmlOverPlugins},
       {features::kAllowFullscreenWebNotificationsFeature,
        features::kNativeNotifications});
 #else
-  feature_list_.InitWithFeatures(
+  scoped_feature_list->InitWithFeatures(
       {features::kPreferHtmlOverPlugins},
       {features::kAllowFullscreenWebNotificationsFeature});
 #endif  // BUILDFLAG(ENABLE_NATIVE_NOTIFICATIONS)
diff --git a/chrome/browser/notifications/notification_interactive_uitest_support.h b/chrome/browser/notifications/notification_interactive_uitest_support.h
index 1aa23c00..b169bde 100644
--- a/chrome/browser/notifications/notification_interactive_uitest_support.h
+++ b/chrome/browser/notifications/notification_interactive_uitest_support.h
@@ -70,9 +70,12 @@
   content::WebContents* GetActiveWebContents(Browser* browser);
 
  protected:
-  void EnablePermissionsEmbargo();
-  void EnableFullscreenNotifications();
-  void DisableFullscreenNotifications();
+  void EnablePermissionsEmbargo(
+      base::test::ScopedFeatureList* scoped_feature_list);
+  void EnableFullscreenNotifications(
+      base::test::ScopedFeatureList* scoped_feature_list);
+  void DisableFullscreenNotifications(
+      base::test::ScopedFeatureList* scoped_feature_list);
 
  private:
   std::string RequestAndRespondToPermission(
diff --git a/chrome/browser/offline_pages/prefetch/offline_metrics_collector_impl.cc b/chrome/browser/offline_pages/prefetch/offline_metrics_collector_impl.cc
index b1e59748d..5ff927ed 100644
--- a/chrome/browser/offline_pages/prefetch/offline_metrics_collector_impl.cc
+++ b/chrome/browser/offline_pages/prefetch/offline_metrics_collector_impl.cc
@@ -4,14 +4,169 @@
 
 #include "chrome/browser/offline_pages/prefetch/offline_metrics_collector_impl.h"
 
+#include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
+#include "chrome/common/pref_names.h"
+
 namespace offline_pages {
 
-// TODO(dimich): Implement this.
-OfflineMetricsCollectorImpl::OfflineMetricsCollectorImpl() {}
+// static
+void OfflineMetricsCollectorImpl::RegisterPrefs(PrefRegistrySimple* registry) {
+  registry->RegisterBooleanPref(prefs::kOfflineUsageStartObserved, false);
+  registry->RegisterBooleanPref(prefs::kOfflineUsageOnlineObserved, false);
+  registry->RegisterBooleanPref(prefs::kOfflineUsageOfflineObserved, false);
+  registry->RegisterInt64Pref(prefs::kOfflineUsageTrackingDay, 0L);
+  registry->RegisterIntegerPref(prefs::kOfflineUsageUnusedCount, 0);
+  registry->RegisterIntegerPref(prefs::kOfflineUsageStartedCount, 0);
+  registry->RegisterIntegerPref(prefs::kOfflineUsageOfflineCount, 0);
+  registry->RegisterIntegerPref(prefs::kOfflineUsageOnlineCount, 0);
+  registry->RegisterIntegerPref(prefs::kOfflineUsageMixedCount, 0);
+}
+
+OfflineMetricsCollectorImpl::OfflineMetricsCollectorImpl(PrefService* prefs)
+    : prefs_(prefs) {}
+
 OfflineMetricsCollectorImpl::~OfflineMetricsCollectorImpl() {}
-void OfflineMetricsCollectorImpl::OnAppStartupOrResume() {}
-void OfflineMetricsCollectorImpl::OnSuccessfulNavigationOnline() {}
-void OfflineMetricsCollectorImpl::OnSuccessfulNavigationOffline() {}
-void OfflineMetricsCollectorImpl::ReportAccumulatedStats() {}
+
+void OfflineMetricsCollectorImpl::OnAppStartupOrResume() {
+  SetTrackingFlag(&chrome_start_observed_);
+}
+
+void OfflineMetricsCollectorImpl::OnSuccessfulNavigationOffline() {
+  SetTrackingFlag(&offline_navigation_observed_);
+}
+
+void OfflineMetricsCollectorImpl::OnSuccessfulNavigationOnline() {
+  SetTrackingFlag(&online_navigation_observed_);
+}
+
+void OfflineMetricsCollectorImpl::ReportAccumulatedStats() {
+  int total_day_count = unused_days_count_ + started_days_count_ +
+                        offline_days_count_ + online_days_count_ +
+                        mixed_days_count_;
+  // No accumulated daily usage, nothing to report.
+  if (total_day_count == 0)
+    return;
+
+  for (int i = 0; i < unused_days_count_; ++i)
+    ReportUsageForOneDayToUma(DailyUsageType::UNUSED);
+  for (int i = 0; i < started_days_count_; ++i)
+    ReportUsageForOneDayToUma(DailyUsageType::STARTED);
+  for (int i = 0; i < offline_days_count_; ++i)
+    ReportUsageForOneDayToUma(DailyUsageType::OFFLINE);
+  for (int i = 0; i < online_days_count_; ++i)
+    ReportUsageForOneDayToUma(DailyUsageType::ONLINE);
+  for (int i = 0; i < mixed_days_count_; ++i)
+    ReportUsageForOneDayToUma(DailyUsageType::MIXED);
+
+  unused_days_count_ = started_days_count_ = offline_days_count_ =
+      online_days_count_ = mixed_days_count_ = 0;
+  SaveToPrefs();
+}
+
+void OfflineMetricsCollectorImpl::EnsureLoaded() {
+  if (!tracking_day_midnight_.is_null())
+    return;
+
+  DCHECK(prefs_);
+  chrome_start_observed_ =
+      prefs_->GetBoolean(prefs::kOfflineUsageStartObserved);
+  offline_navigation_observed_ =
+      prefs_->GetBoolean(prefs::kOfflineUsageOfflineObserved);
+  online_navigation_observed_ =
+      prefs_->GetBoolean(prefs::kOfflineUsageOnlineObserved);
+  int64_t time_value = prefs_->GetInt64(prefs::kOfflineUsageTrackingDay);
+  // For the very first run, initialize to current time.
+  tracking_day_midnight_ = time_value == 0L
+                               ? Now().LocalMidnight()
+                               : base::Time::FromInternalValue(time_value);
+  unused_days_count_ = prefs_->GetInteger(prefs::kOfflineUsageUnusedCount);
+  started_days_count_ = prefs_->GetInteger(prefs::kOfflineUsageStartedCount);
+  offline_days_count_ = prefs_->GetInteger(prefs::kOfflineUsageOfflineCount);
+  online_days_count_ = prefs_->GetInteger(prefs::kOfflineUsageOnlineCount);
+  mixed_days_count_ = prefs_->GetInteger(prefs::kOfflineUsageMixedCount);
+}
+
+void OfflineMetricsCollectorImpl::SaveToPrefs() {
+  prefs_->SetBoolean(prefs::kOfflineUsageStartObserved, chrome_start_observed_);
+  prefs_->SetBoolean(prefs::kOfflineUsageOfflineObserved,
+                     offline_navigation_observed_);
+  prefs_->SetBoolean(prefs::kOfflineUsageOnlineObserved,
+                     online_navigation_observed_);
+  prefs_->SetInt64(prefs::kOfflineUsageTrackingDay,
+                   tracking_day_midnight_.ToInternalValue());
+  prefs_->SetInteger(prefs::kOfflineUsageUnusedCount, unused_days_count_);
+  prefs_->SetInteger(prefs::kOfflineUsageStartedCount, started_days_count_);
+  prefs_->SetInteger(prefs::kOfflineUsageOfflineCount, offline_days_count_);
+  prefs_->SetInteger(prefs::kOfflineUsageOnlineCount, online_days_count_);
+  prefs_->SetInteger(prefs::kOfflineUsageMixedCount, mixed_days_count_);
+  prefs_->CommitPendingWrite();
+}
+
+void OfflineMetricsCollectorImpl::SetTrackingFlag(bool* flag) {
+  EnsureLoaded();
+
+  bool changed = UpdatePastDaysIfNeeded() || !(*flag);
+  *flag = true;
+
+  if (changed)
+    SaveToPrefs();
+}
+
+bool OfflineMetricsCollectorImpl::UpdatePastDaysIfNeeded() {
+  base::Time current_midnight = Now().LocalMidnight();
+  // It is still the same day, or a day from the future (rarely may happen when
+  // clock is reset), skip updating past days counters.
+  if (tracking_day_midnight_ >= current_midnight)
+    return false;
+
+  // Increment the counter that corresponds to tracked usage.
+  if (online_navigation_observed_ && offline_navigation_observed_)
+    mixed_days_count_++;
+  else if (online_navigation_observed_)
+    online_days_count_++;
+  else if (offline_navigation_observed_)
+    offline_days_count_++;
+  else if (chrome_start_observed_)
+    started_days_count_++;
+  else
+    unused_days_count_++;
+
+  // The days between the day when tracking was done and the current one are
+  // 'unused'.
+  // Calculation of the 'days in between' is as following:
+  // 1. If current_midnight == tracking_day_midnight_, we returned earlier.
+  // 2. If current_midnight is for the next day, days_in_between is 0,
+  //    tracking is reset to start for the current day.
+  // 3. If current_midnight is > 48hrs later, the days_in_between are added,
+  //    tracking is reset to start for the current day.
+  int days_in_between =
+      (current_midnight - tracking_day_midnight_).InDays() - 1;
+  DCHECK(days_in_between >= 0);
+  unused_days_count_ += days_in_between;
+
+  // Reset tracking
+  chrome_start_observed_ = offline_navigation_observed_ =
+      online_navigation_observed_ = false;
+  tracking_day_midnight_ = current_midnight;
+
+  return true;
+}
+
+void OfflineMetricsCollectorImpl::ReportUsageForOneDayToUma(
+    DailyUsageType usage_type) {
+  UMA_HISTOGRAM_ENUMERATION("OfflinePages.OfflineUsage", usage_type,
+                            DailyUsageType::MAX_USAGE);
+}
+
+base::Time OfflineMetricsCollectorImpl::Now() const {
+  if (testing_clock_)
+    return testing_clock_->Now();
+  return base::Time::Now();
+}
+
+void OfflineMetricsCollectorImpl::SetClockForTesting(base::Clock* clock) {
+  testing_clock_ = clock;
+}
 
 }  // namespace offline_pages
diff --git a/chrome/browser/offline_pages/prefetch/offline_metrics_collector_impl.h b/chrome/browser/offline_pages/prefetch/offline_metrics_collector_impl.h
index 496aee7..2fb6c1d 100644
--- a/chrome/browser/offline_pages/prefetch/offline_metrics_collector_impl.h
+++ b/chrome/browser/offline_pages/prefetch/offline_metrics_collector_impl.h
@@ -8,13 +8,60 @@
 #include <memory>
 
 #include "base/macros.h"
+#include "base/time/clock.h"
 #include "components/offline_pages/core/prefetch/offline_metrics_collector.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
 
 namespace offline_pages {
 
+// Tracks the types of usage (started/offline/online etc.) of Chrome observed
+// throughout a day. The objective of this tracking is to count and report:
+// - Days on which the browser was not started.
+// - Days on which the browser was started but no navigations happened.
+// - Days on which the browser observed only successful online navigations.
+// - Days on which the browser observed only successful offline navigations.
+// - Days on which the browser observed both successful online and offline
+//   navigations.
+//
+// For each 'type' of the day there is a separate counter which accumulates the
+// number of those days over time and the counters are reported via UMA when
+// network connectivity is likely given.
+//
+// When Chrome is being used (navigating to URLs etc), one of the
+// OfflineMetricsCollector interface methods is called (normally from a tab
+// helper or some other observer of relevant activity) and the 'current' usage
+// is updated.
+//
+// When transition from one day to another is detected (by
+// comparing the midnight timestamp of when tracking was initialized and current
+// time when usage sample arrives), the counters that correspond to the
+// end-of-day state are updated. If more then one day passes between samples,
+// that means Chrome was not used in the days in between and they have to be
+// counted as 'Chrome was not used' days.
+//
+// To persist tracking data and counters across Chrome restarts, they are backed
+// up in Prefs.
 class OfflineMetricsCollectorImpl : public OfflineMetricsCollector {
  public:
-  OfflineMetricsCollectorImpl();
+  static void RegisterPrefs(PrefRegistrySimple* registry);
+
+  // The kind of Chrome usage during a day.
+  // This class is used in UMA reporting. Keep it in sync with
+  // OfflinePagesOfflineUsage enum in histograms. Public for testing.
+  enum class DailyUsageType {
+    UNUSED = 0,   // Chrome was not used the whole day.
+    STARTED = 1,  // Started, but no successful navigations happened during the
+                  // day (Error pages, Dine etc)
+    OFFLINE = 2,  // Successfully navigated to at least one offline page, no
+                  // online navigations(however device may be connected).
+    ONLINE = 3,   // Only online navigations happened during the day.
+    MIXED = 4,    // Both offline and online navigations happened during the
+                  // day.
+    MAX_USAGE = 5,
+  };
+
+  explicit OfflineMetricsCollectorImpl(PrefService* prefs);
   ~OfflineMetricsCollectorImpl() override;
 
   // OfflineMetricsCollector implementation.
@@ -23,7 +70,56 @@
   void OnSuccessfulNavigationOffline() override;
   void ReportAccumulatedStats() override;
 
+  void SetClockForTesting(base::Clock* clock);
+
  private:
+  void EnsureLoaded();
+  void SaveToPrefs();
+
+  // Sets the specified flag to 'true', saves new tracking state to Prefs if
+  // the there was a change.
+  void SetTrackingFlag(bool* flag);
+
+  // Moves tracking_day_midnight_ to the midnight that starts the current day if
+  // necessary and updates the usage counters accordingly. Returns 'true' if the
+  // past days counters changed and need to be updated on disk.
+  bool UpdatePastDaysIfNeeded();
+
+  // Reports to UMA 1 day of specified usage.
+  void ReportUsageForOneDayToUma(DailyUsageType usage_type);
+
+  // Used to retrieve current time, overrideable in tests.
+  base::Time Now() const;
+
+  // Tracking flags. They reflect the current usage of Chrome through the day,
+  // starting from 'false' at start of the day and then eventually set to 'true'
+  // when corresponding usage is observed.
+  bool chrome_start_observed_ = false;
+  bool offline_navigation_observed_ = false;
+  bool online_navigation_observed_ = false;
+
+  // The midnight that starts the day for which current tracking is happening.
+  // It is used to determine if the time of the observable usage is still during
+  // the same local day (between two consecutive midnights).
+  // If a usage is observed outside of that range, the accumulated counters
+  // should be incremented and tracking state initialized for the current day.
+  base::Time tracking_day_midnight_;
+
+  // Accumulated usage counters. There is a counter for each DailyUsageType
+  // enum value. Count the number of days with specific Chrome usage.
+  int unused_days_count_ = 0;
+  int started_days_count_ = 0;
+  int offline_days_count_ = 0;
+  int online_days_count_ = 0;
+  int mixed_days_count_ = 0;
+
+  // Has the same lifetime as profile, so should outlive this subcomponent
+  // of profile's PrefetchService.
+  PrefService* prefs_ = nullptr;
+
+  // Used in tests, managed by the test, outlives this object.
+  base::Clock* testing_clock_ = nullptr;
+
   DISALLOW_COPY_AND_ASSIGN(OfflineMetricsCollectorImpl);
 };
 
diff --git a/chrome/browser/offline_pages/prefetch/offline_metrics_collector_impl_unittest.cc b/chrome/browser/offline_pages/prefetch/offline_metrics_collector_impl_unittest.cc
new file mode 100644
index 0000000..610c848
--- /dev/null
+++ b/chrome/browser/offline_pages/prefetch/offline_metrics_collector_impl_unittest.cc
@@ -0,0 +1,233 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/offline_pages/prefetch/offline_metrics_collector_impl.h"
+
+#include <memory>
+#include <string>
+
+#include "base/test/histogram_tester.h"
+#include "base/test/simple_test_clock.h"
+#include "chrome/common/pref_names.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/testing_pref_service.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace offline_pages {
+using UsageType = OfflineMetricsCollectorImpl::DailyUsageType;
+
+class OfflineMetricsCollectorTest : public testing::Test {
+ public:
+  OfflineMetricsCollectorTest() {}
+  ~OfflineMetricsCollectorTest() override {}
+
+  // testing::Test:
+  void SetUp() override {
+    test_clock().SetNow(base::Time::Now().LocalMidnight());
+    OfflineMetricsCollectorImpl::RegisterPrefs(pref_service_.registry());
+    Reload();
+  }
+
+  // This creates new collector whcih will read the initial values from Prefs.
+  void Reload() {
+    collector_ =
+        base::MakeUnique<OfflineMetricsCollectorImpl>(&prefs());
+    collector_->SetClockForTesting(&test_clock());
+  }
+
+  base::SimpleTestClock& test_clock() { return test_clock_; }
+  PrefService& prefs() { return pref_service_; }
+  OfflineMetricsCollector* collector() const { return collector_.get(); }
+  const base::HistogramTester& histograms() const { return histogram_tester_; }
+
+  base::Time GetTimestampFromPrefs() {
+    return base::Time::FromInternalValue(
+        prefs().GetInt64(prefs::kOfflineUsageTrackingDay));
+  }
+
+ protected:
+  base::SimpleTestClock test_clock_;
+  TestingPrefServiceSimple pref_service_;
+  std::unique_ptr<OfflineMetricsCollectorImpl> collector_;
+  base::HistogramTester histogram_tester_;
+
+  DISALLOW_COPY_AND_ASSIGN(OfflineMetricsCollectorTest);
+};
+
+TEST_F(OfflineMetricsCollectorTest, CheckCleanInit) {
+  EXPECT_EQ(0L, prefs().GetInt64(prefs::kOfflineUsageTrackingDay));
+  EXPECT_EQ(false, prefs().GetBoolean(prefs::kOfflineUsageStartObserved));
+  EXPECT_EQ(false, prefs().GetBoolean(prefs::kOfflineUsageOfflineObserved));
+  EXPECT_EQ(false, prefs().GetBoolean(prefs::kOfflineUsageOnlineObserved));
+  EXPECT_EQ(0, prefs().GetInteger(prefs::kOfflineUsageUnusedCount));
+  EXPECT_EQ(0, prefs().GetInteger(prefs::kOfflineUsageStartedCount));
+  EXPECT_EQ(0, prefs().GetInteger(prefs::kOfflineUsageOfflineCount));
+  EXPECT_EQ(0, prefs().GetInteger(prefs::kOfflineUsageOnlineCount));
+  EXPECT_EQ(0, prefs().GetInteger(prefs::kOfflineUsageMixedCount));
+}
+
+TEST_F(OfflineMetricsCollectorTest, FirstStart) {
+  EXPECT_EQ(false, prefs().GetBoolean(prefs::kOfflineUsageStartObserved));
+  EXPECT_EQ(false, prefs().GetBoolean(prefs::kOfflineUsageOfflineObserved));
+  EXPECT_EQ(false, prefs().GetBoolean(prefs::kOfflineUsageOnlineObserved));
+  base::Time start = test_clock().Now();
+
+  collector()->OnAppStartupOrResume();
+
+  EXPECT_EQ(true, prefs().GetBoolean(prefs::kOfflineUsageStartObserved));
+  EXPECT_EQ(false, prefs().GetBoolean(prefs::kOfflineUsageOfflineObserved));
+  EXPECT_EQ(false, prefs().GetBoolean(prefs::kOfflineUsageOnlineObserved));
+  // Timestamp shouldn't change.
+  EXPECT_EQ(GetTimestampFromPrefs(), start);
+  // Accumulated counters shouldn't change.
+  EXPECT_EQ(0, prefs().GetInteger(prefs::kOfflineUsageUnusedCount));
+  EXPECT_EQ(0, prefs().GetInteger(prefs::kOfflineUsageStartedCount));
+  EXPECT_EQ(0, prefs().GetInteger(prefs::kOfflineUsageOfflineCount));
+  EXPECT_EQ(0, prefs().GetInteger(prefs::kOfflineUsageOnlineCount));
+  EXPECT_EQ(0, prefs().GetInteger(prefs::kOfflineUsageMixedCount));
+}
+
+TEST_F(OfflineMetricsCollectorTest, SetTrackingFlags) {
+  collector()->OnAppStartupOrResume();
+  EXPECT_EQ(true, prefs().GetBoolean(prefs::kOfflineUsageStartObserved));
+  EXPECT_EQ(false, prefs().GetBoolean(prefs::kOfflineUsageOfflineObserved));
+  EXPECT_EQ(false, prefs().GetBoolean(prefs::kOfflineUsageOnlineObserved));
+  collector()->OnSuccessfulNavigationOffline();
+  EXPECT_EQ(true, prefs().GetBoolean(prefs::kOfflineUsageStartObserved));
+  EXPECT_EQ(true, prefs().GetBoolean(prefs::kOfflineUsageOfflineObserved));
+  EXPECT_EQ(false, prefs().GetBoolean(prefs::kOfflineUsageOnlineObserved));
+  collector()->OnSuccessfulNavigationOnline();
+  EXPECT_EQ(true, prefs().GetBoolean(prefs::kOfflineUsageStartObserved));
+  EXPECT_EQ(true, prefs().GetBoolean(prefs::kOfflineUsageOfflineObserved));
+  EXPECT_EQ(true, prefs().GetBoolean(prefs::kOfflineUsageOnlineObserved));
+}
+
+TEST_F(OfflineMetricsCollectorTest, TrueIsFinalState) {
+  collector()->OnAppStartupOrResume();
+  collector()->OnSuccessfulNavigationOnline();
+  collector()->OnSuccessfulNavigationOffline();
+  EXPECT_EQ(true, prefs().GetBoolean(prefs::kOfflineUsageStartObserved));
+  EXPECT_EQ(true, prefs().GetBoolean(prefs::kOfflineUsageOfflineObserved));
+  EXPECT_EQ(true, prefs().GetBoolean(prefs::kOfflineUsageOnlineObserved));
+  collector()->OnSuccessfulNavigationOffline();
+  collector()->OnSuccessfulNavigationOnline();
+  collector()->OnAppStartupOrResume();
+  // once 'true', tracking flags do not change.
+  EXPECT_EQ(true, prefs().GetBoolean(prefs::kOfflineUsageStartObserved));
+  EXPECT_EQ(true, prefs().GetBoolean(prefs::kOfflineUsageOfflineObserved));
+  EXPECT_EQ(true, prefs().GetBoolean(prefs::kOfflineUsageOnlineObserved));
+}
+
+// Restore from Prefs keeps accumulated state, counters and timestamp.
+TEST_F(OfflineMetricsCollectorTest, RestoreFromPrefs) {
+  base::Time start = test_clock().Now();
+  collector()->OnSuccessfulNavigationOnline();
+  EXPECT_EQ(false, prefs().GetBoolean(prefs::kOfflineUsageStartObserved));
+  EXPECT_EQ(false, prefs().GetBoolean(prefs::kOfflineUsageOfflineObserved));
+  EXPECT_EQ(true, prefs().GetBoolean(prefs::kOfflineUsageOnlineObserved));
+  EXPECT_EQ(GetTimestampFromPrefs(), start);
+
+  prefs().SetInteger(prefs::kOfflineUsageUnusedCount, 1);
+  prefs().SetInteger(prefs::kOfflineUsageStartedCount, 2);
+  prefs().SetInteger(prefs::kOfflineUsageOfflineCount, 3);
+  prefs().SetInteger(prefs::kOfflineUsageOnlineCount, 4);
+  prefs().SetInteger(prefs::kOfflineUsageMixedCount, 5);
+
+  Reload();
+  collector()->OnSuccessfulNavigationOffline();
+  EXPECT_EQ(false, prefs().GetBoolean(prefs::kOfflineUsageStartObserved));
+  EXPECT_EQ(true, prefs().GetBoolean(prefs::kOfflineUsageOfflineObserved));
+  EXPECT_EQ(true, prefs().GetBoolean(prefs::kOfflineUsageOnlineObserved));
+  EXPECT_EQ(GetTimestampFromPrefs(), start);
+
+  collector()->ReportAccumulatedStats();
+  histograms().ExpectBucketCount("OfflinePages.OfflineUsage",
+                                 0 /* UsageType::UNUSED */, 1);
+  histograms().ExpectBucketCount("OfflinePages.OfflineUsage",
+                                 1 /* UsageType::STARTED */, 2);
+  histograms().ExpectBucketCount("OfflinePages.OfflineUsage",
+                                 2 /* UsageType::OFFLINE */, 3);
+  histograms().ExpectBucketCount("OfflinePages.OfflineUsage",
+                                 3 /* UsageType::ONLINE */, 4);
+  histograms().ExpectBucketCount("OfflinePages.OfflineUsage",
+                                 4 /* UsageType::MIXED */, 5);
+
+  // After reporting, counters should be reset.
+  EXPECT_EQ(0, prefs().GetInteger(prefs::kOfflineUsageUnusedCount));
+  EXPECT_EQ(0, prefs().GetInteger(prefs::kOfflineUsageStartedCount));
+  EXPECT_EQ(0, prefs().GetInteger(prefs::kOfflineUsageOfflineCount));
+  EXPECT_EQ(0, prefs().GetInteger(prefs::kOfflineUsageOnlineCount));
+  EXPECT_EQ(0, prefs().GetInteger(prefs::kOfflineUsageMixedCount));
+}
+
+TEST_F(OfflineMetricsCollectorTest, ChangesWithinDay) {
+  base::Time start = test_clock().Now();
+  collector()->OnAppStartupOrResume();
+  collector()->OnSuccessfulNavigationOnline();
+  EXPECT_EQ(true, prefs().GetBoolean(prefs::kOfflineUsageStartObserved));
+  EXPECT_EQ(false, prefs().GetBoolean(prefs::kOfflineUsageOfflineObserved));
+  EXPECT_EQ(true, prefs().GetBoolean(prefs::kOfflineUsageOnlineObserved));
+
+  // Move time ahead but still same day.
+  base::Time later1Hour = start + base::TimeDelta::FromHours(1);
+  test_clock().SetNow(later1Hour);
+  collector()->OnSuccessfulNavigationOffline();
+  // Timestamp shouldn't change.
+  EXPECT_EQ(GetTimestampFromPrefs(), start);
+
+  // Counters should not be affected.
+  EXPECT_EQ(0, prefs().GetInteger(prefs::kOfflineUsageUnusedCount));
+  EXPECT_EQ(0, prefs().GetInteger(prefs::kOfflineUsageStartedCount));
+  EXPECT_EQ(0, prefs().GetInteger(prefs::kOfflineUsageOfflineCount));
+  EXPECT_EQ(0, prefs().GetInteger(prefs::kOfflineUsageOnlineCount));
+  EXPECT_EQ(0, prefs().GetInteger(prefs::kOfflineUsageMixedCount));
+}
+
+TEST_F(OfflineMetricsCollectorTest, MultipleDays) {
+  base::Time start = test_clock().Now();
+  collector()->OnAppStartupOrResume();
+
+  base::Time nextDay = start + base::TimeDelta::FromHours(25);
+  test_clock().SetNow(nextDay);
+
+  collector()->OnAppStartupOrResume();
+  // 1 day 'started' counter, another is being tracked as current day...
+  EXPECT_EQ(1, prefs().GetInteger(prefs::kOfflineUsageStartedCount));
+
+  EXPECT_EQ(true, prefs().GetBoolean(prefs::kOfflineUsageStartObserved));
+  EXPECT_EQ(false, prefs().GetBoolean(prefs::kOfflineUsageOfflineObserved));
+  EXPECT_EQ(false, prefs().GetBoolean(prefs::kOfflineUsageOnlineObserved));
+
+  base::Time skip4Days = nextDay + base::TimeDelta::FromHours(24 * 4);
+  test_clock().SetNow(skip4Days);
+  collector()->OnSuccessfulNavigationOnline();
+  // 2 days started, 3 days skipped ('unused').
+  EXPECT_EQ(2, prefs().GetInteger(prefs::kOfflineUsageStartedCount));
+  EXPECT_EQ(3, prefs().GetInteger(prefs::kOfflineUsageUnusedCount));
+
+  // No online days in the past..
+  EXPECT_EQ(0, prefs().GetInteger(prefs::kOfflineUsageOnlineCount));
+  // .. but current day is 'online' type.
+  EXPECT_EQ(true, prefs().GetBoolean(prefs::kOfflineUsageOnlineObserved));
+
+  // Other counters not affected.
+  EXPECT_EQ(0, prefs().GetInteger(prefs::kOfflineUsageOfflineCount));
+  EXPECT_EQ(0, prefs().GetInteger(prefs::kOfflineUsageMixedCount));
+
+  // Force collector to report stats and observe them reported correctly.
+  collector()->ReportAccumulatedStats();
+  histograms().ExpectBucketCount("OfflinePages.OfflineUsage",
+                                 0 /* UsageType::UNUSED */, 3);
+  histograms().ExpectBucketCount("OfflinePages.OfflineUsage",
+                                 1 /* UsageType::STARTED */, 2);
+  histograms().ExpectBucketCount("OfflinePages.OfflineUsage",
+                                 2 /* UsageType::OFFLINE */, 0);
+  histograms().ExpectBucketCount("OfflinePages.OfflineUsage",
+                                 3 /* UsageType::ONLINE */, 0);
+  histograms().ExpectBucketCount("OfflinePages.OfflineUsage",
+                                 4 /* UsageType::MIXED */, 0);
+}
+
+}  // namespace offline_pages
diff --git a/chrome/browser/offline_pages/prefetch/prefetch_service_factory.cc b/chrome/browser/offline_pages/prefetch/prefetch_service_factory.cc
index 12dbcc3..e16338cb 100644
--- a/chrome/browser/offline_pages/prefetch/prefetch_service_factory.cc
+++ b/chrome/browser/offline_pages/prefetch/prefetch_service_factory.cc
@@ -48,6 +48,7 @@
 KeyedService* PrefetchServiceFactory::BuildServiceInstanceFor(
     content::BrowserContext* context) const {
   Profile* profile = Profile::FromBrowserContext(context);
+  DCHECK(profile);
   auto prefetch_dispatcher = base::MakeUnique<PrefetchDispatcherImpl>();
   auto prefetch_gcm_app_handler = base::MakeUnique<PrefetchGCMAppHandler>(
       base::MakeUnique<PrefetchInstanceIDProxy>(kPrefetchingOfflinePagesAppId,
@@ -56,7 +57,7 @@
       base::MakeUnique<PrefetchNetworkRequestFactoryImpl>(
           profile->GetRequestContext(), chrome::GetChannel(), GetUserAgent());
   auto offline_metrics_collector =
-      base::MakeUnique<OfflineMetricsCollectorImpl>();
+      base::MakeUnique<OfflineMetricsCollectorImpl>(profile->GetPrefs());
   auto suggested_articles_observer =
       base::MakeUnique<SuggestedArticlesObserver>();
 
diff --git a/chrome/browser/pdf/pdf_extension_test.cc b/chrome/browser/pdf/pdf_extension_test.cc
index 28410322..2a3cda54b 100644
--- a/chrome/browser/pdf/pdf_extension_test.cc
+++ b/chrome/browser/pdf/pdf_extension_test.cc
@@ -4,6 +4,7 @@
 
 #include <stddef.h>
 
+#include <map>
 #include <vector>
 
 #include "base/base_paths.h"
@@ -607,7 +608,7 @@
   // Create a string representation of the tree starting with the embedded
   // object.
   std::string ax_tree_dump;
-  base::hash_map<int32_t, int> id_to_indentation;
+  std::map<int32_t, int> id_to_indentation;
   bool found_embedded_object = false;
   for (auto& node : ax_tree.nodes) {
     if (node.role == ui::AX_ROLE_EMBEDDED_OBJECT)
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index c0e7274d..4659a1f 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -146,6 +146,7 @@
 
 #if BUILDFLAG(ENABLE_OFFLINE_PAGES)
 #include "chrome/browser/android/offline_pages/prefetch/prefetch_background_task.h"
+#include "chrome/browser/offline_pages/prefetch/offline_metrics_collector_impl.h"
 #endif
 
 #if BUILDFLAG(ENABLE_PLUGINS)
@@ -646,6 +647,7 @@
   registry->RegisterDictionaryPref(kDistroDict);
 
 #if BUILDFLAG(ENABLE_OFFLINE_PAGES)
+  offline_pages::OfflineMetricsCollectorImpl::RegisterPrefs(registry);
   offline_pages::RegisterPrefetchBackgroundTaskPrefs(registry);
 #endif
 }
diff --git a/chrome/browser/printing/cloud_print/privet_device_lister.h b/chrome/browser/printing/cloud_print/privet_device_lister.h
index 0acee4c7..44aba04 100644
--- a/chrome/browser/printing/cloud_print/privet_device_lister.h
+++ b/chrome/browser/printing/cloud_print/privet_device_lister.h
@@ -28,7 +28,7 @@
   // Start the PrivetServiceLister.
   virtual void Start() = 0;
 
-  virtual void DiscoverNewDevices(bool force_update) = 0;
+  virtual void DiscoverNewDevices() = 0;
 };
 
 }  // namespace cloud_print
diff --git a/chrome/browser/printing/cloud_print/privet_device_lister_impl.cc b/chrome/browser/printing/cloud_print/privet_device_lister_impl.cc
index eb8e46b..46c8ebf 100644
--- a/chrome/browser/printing/cloud_print/privet_device_lister_impl.cc
+++ b/chrome/browser/printing/cloud_print/privet_device_lister_impl.cc
@@ -24,8 +24,8 @@
   device_lister_.Start();
 }
 
-void PrivetDeviceListerImpl::DiscoverNewDevices(bool force_update) {
-  device_lister_.DiscoverNewDevices(force_update);
+void PrivetDeviceListerImpl::DiscoverNewDevices() {
+  device_lister_.DiscoverNewDevices();
 }
 
 void PrivetDeviceListerImpl::OnDeviceChanged(
diff --git a/chrome/browser/printing/cloud_print/privet_device_lister_impl.h b/chrome/browser/printing/cloud_print/privet_device_lister_impl.h
index 1f5c5a7c..5eeff67fe 100644
--- a/chrome/browser/printing/cloud_print/privet_device_lister_impl.h
+++ b/chrome/browser/printing/cloud_print/privet_device_lister_impl.h
@@ -27,7 +27,7 @@
 
   // PrivetDeviceLister:
   void Start() override;
-  void DiscoverNewDevices(bool force_update) override;
+  void DiscoverNewDevices() override;
 
  protected:
   // ServiceDiscoveryDeviceLister:
diff --git a/chrome/browser/printing/cloud_print/privet_device_lister_unittest.cc b/chrome/browser/printing/cloud_print/privet_device_lister_unittest.cc
index 19e2e2d..4bb7bf4 100644
--- a/chrome/browser/printing/cloud_print/privet_device_lister_unittest.cc
+++ b/chrome/browser/printing/cloud_print/privet_device_lister_unittest.cc
@@ -50,7 +50,7 @@
     mock_delegate_->ServiceWatcherStarted(service_type_, this);
   }
 
-  MOCK_METHOD1(DiscoverNewServices, void(bool force_update));
+  MOCK_METHOD0(DiscoverNewServices, void());
 
   MOCK_METHOD1(SetActivelyRefreshServices, void(
       bool actively_refresh_services));
@@ -296,8 +296,8 @@
   privet_lister.Start();
   testing::Mock::VerifyAndClear(&mock_delegate_);
 
-  EXPECT_CALL(*service_watcher, DiscoverNewServices(false));
-  privet_lister.DiscoverNewDevices(false);
+  EXPECT_CALL(*service_watcher, DiscoverNewServices());
+  privet_lister.DiscoverNewDevices();
 }
 
 
diff --git a/chrome/browser/printing/cloud_print/privet_local_printer_lister.cc b/chrome/browser/printing/cloud_print/privet_local_printer_lister.cc
index 1b507e8..3b62e9d 100644
--- a/chrome/browser/printing/cloud_print/privet_local_printer_lister.cc
+++ b/chrome/browser/printing/cloud_print/privet_local_printer_lister.cc
@@ -43,7 +43,7 @@
 
 void PrivetLocalPrinterLister::Start() {
   privet_lister_->Start();
-  privet_lister_->DiscoverNewDevices(false);
+  privet_lister_->DiscoverNewDevices();
 }
 
 void PrivetLocalPrinterLister::Stop() {
diff --git a/chrome/browser/printing/cloud_print/privet_notifications.cc b/chrome/browser/printing/cloud_print/privet_notifications.cc
index 060461e..4b21d9e 100644
--- a/chrome/browser/printing/cloud_print/privet_notifications.cc
+++ b/chrome/browser/printing/cloud_print/privet_notifications.cc
@@ -339,7 +339,7 @@
   device_lister_.reset(
       new PrivetDeviceListerImpl(service_discovery_client_.get(), this));
   device_lister_->Start();
-  device_lister_->DiscoverNewDevices(false);
+  device_lister_->DiscoverNewDevices();
 
   std::unique_ptr<PrivetHTTPAsynchronousFactory> http_factory(
       PrivetHTTPAsynchronousFactory::CreateInstance(
diff --git a/chrome/browser/printing/printing_message_filter.cc b/chrome/browser/printing/printing_message_filter.cc
index 0bb82c0f..8c9c449 100644
--- a/chrome/browser/printing/printing_message_filter.cc
+++ b/chrome/browser/printing/printing_message_filter.cc
@@ -160,12 +160,14 @@
 }
 
 void PrintingMessageFilter::OnTempFileForPrintingWritten(int render_frame_id,
-                                                         int sequence_number) {
+                                                         int sequence_number,
+                                                         int page_count) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK_GT(page_count, 0);
   PrintViewManagerBasic* print_view_manager =
       GetPrintManager(render_process_id_, render_frame_id);
   if (print_view_manager)
-    print_view_manager->PdfWritingDone(true);
+    print_view_manager->PdfWritingDone(page_count);
 }
 #endif  // defined(OS_ANDROID)
 
diff --git a/chrome/browser/printing/printing_message_filter.h b/chrome/browser/printing/printing_message_filter.h
index 3931928e..3402f25 100644
--- a/chrome/browser/printing/printing_message_filter.h
+++ b/chrome/browser/printing/printing_message_filter.h
@@ -60,7 +60,9 @@
   void OnAllocateTempFileForPrinting(int render_frame_id,
                                      base::FileDescriptor* temp_file_fd,
                                      int* sequence_number);
-  void OnTempFileForPrintingWritten(int render_frame_id, int sequence_number);
+  void OnTempFileForPrintingWritten(int render_frame_id,
+                                    int sequence_number,
+                                    int page_count);
 
   // Updates the file descriptor for the PrintViewManagerBasic of a given
   // |render_frame_id|.
diff --git a/chrome/browser/profiling_host/BUILD.gn b/chrome/browser/profiling_host/BUILD.gn
new file mode 100644
index 0000000..8d5fa33b
--- /dev/null
+++ b/chrome/browser/profiling_host/BUILD.gn
@@ -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.
+
+import("//chrome/common/features.gni")
+
+if (enable_oop_heap_profiling) {
+  static_library("profiling_host") {
+    sources = [
+      "profiling_process_host.cc",
+      "profiling_process_host.h",
+    ]
+
+    deps = [
+      "//base",
+      "//chrome/common",
+      "//content/public/common",
+    ]
+  }
+} else {
+  # Dummy group so this target can be unconditionally depended on.
+  group("profiling_host") {
+  }
+}
diff --git a/chrome/browser/profiling_host/README.md b/chrome/browser/profiling_host/README.md
new file mode 100644
index 0000000..d0f54fc
--- /dev/null
+++ b/chrome/browser/profiling_host/README.md
@@ -0,0 +1,6 @@
+# chrome/browser/profiling_host
+
+Contains the host code for managing communication with the profiling process.
+The profiling process maintains out-of-process storage for memory logging.
+
+The code for the profiling process is in `chrome/profiling`
diff --git a/chrome/browser/profiling_host/profiling_process_host.cc b/chrome/browser/profiling_host/profiling_process_host.cc
new file mode 100644
index 0000000..fd64531
--- /dev/null
+++ b/chrome/browser/profiling_host/profiling_process_host.cc
@@ -0,0 +1,92 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/profiling_host/profiling_process_host.h"
+
+#include "base/command_line.h"
+#include "base/path_service.h"
+#include "base/process/launch.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/profiling/memlog_sender.h"
+#include "content/public/common/content_switches.h"
+
+namespace profiling {
+
+namespace {
+
+ProfilingProcessHost* pph_singleton = nullptr;
+
+base::CommandLine MakeProfilingCommandLine(const std::string& pipe_id) {
+  // Program name.
+  base::FilePath child_path;
+#if defined(OS_LINUX)
+  // Use /proc/self/exe rather than our known binary path so updates
+  // can't swap out the binary from underneath us.
+  // When running under Valgrind, forking /proc/self/exe ends up forking the
+  // Valgrind executable, which then crashes. However, it's almost safe to
+  // assume that the updates won't happen while testing with Valgrind tools.
+  if (!RunningOnValgrind())
+    child_path = base::FilePath(base::kProcSelfExe);
+#endif
+  if (child_path.empty())
+    base::PathService::Get(base::FILE_EXE, &child_path);
+  base::CommandLine result(child_path);
+
+  result.AppendSwitchASCII(switches::kProcessType, switches::kProfiling);
+  result.AppendSwitchASCII(switches::kMemlogPipe, pipe_id);
+
+#if defined(OS_WIN)
+  // Windows needs prefetch arguments.
+  result.AppendArg(switches::kPrefetchArgumentOther);
+#endif
+
+  return result;
+}
+
+}  // namespace
+
+ProfilingProcessHost::ProfilingProcessHost() {
+  pph_singleton = this;
+}
+
+ProfilingProcessHost::~ProfilingProcessHost() {
+  pph_singleton = nullptr;
+}
+
+// static
+ProfilingProcessHost* ProfilingProcessHost::EnsureStarted() {
+  static ProfilingProcessHost host;
+  if (!host.process_.IsValid())
+    host.Launch();
+  return &host;
+}
+
+// static
+ProfilingProcessHost* ProfilingProcessHost::Get() {
+  return pph_singleton;
+}
+
+// static
+void ProfilingProcessHost::AddSwitchesToChildCmdLine(
+    base::CommandLine* child_cmd_line) {
+  ProfilingProcessHost* pph = ProfilingProcessHost::Get();
+  if (!pph)
+    return;
+  child_cmd_line->AppendSwitchASCII(switches::kMemlogPipe, pph->pipe_id_);
+}
+
+void ProfilingProcessHost::Launch() {
+  base::Process process = base::Process::Current();
+  pipe_id_ = base::IntToString(static_cast<int>(process.Pid()));
+
+  base::CommandLine profiling_cmd = MakeProfilingCommandLine(pipe_id_);
+
+  base::LaunchOptions options;
+  process_ = base::LaunchProcess(profiling_cmd, options);
+  StartMemlogSender(pipe_id_);
+}
+
+}  // namespace profiling
diff --git a/chrome/browser/profiling_host/profiling_process_host.h b/chrome/browser/profiling_host/profiling_process_host.h
new file mode 100644
index 0000000..9023dfe
--- /dev/null
+++ b/chrome/browser/profiling_host/profiling_process_host.h
@@ -0,0 +1,60 @@
+// 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 CHROME_BROWSER_PROFILING_HOST_PROFILING_PROCESS_HOST_H_
+#define CHROME_BROWSER_PROFILING_HOST_PROFILING_PROCESS_HOST_H_
+
+#include "base/macros.h"
+#include "base/process/process.h"
+
+namespace base {
+class CommandLine;
+}
+
+namespace profiling {
+
+// Represents the browser side of the profiling process (//chrome/profiling).
+//
+// The profiling process is a singleton. The profiling process infrastructure
+// is implemented in the Chrome layer so doesn't depend on the content
+// infrastructure for managing child processes.
+//
+// Not thread safe. Should be used on the browser UI thread only.
+//
+// The profing process host can be started normally while Chrome is running,
+// but can also start in a partial mode where the memory logging connections
+// are active but the Mojo control channel has not yet been connected. This is
+// to support starting the profiling process very early in the startup
+// process (to get most memory events) before other infrastructure like the
+// I/O thread has been started.
+class ProfilingProcessHost {
+ public:
+  // Launches the profiling process if necessary and returns a pointer to it.
+  static ProfilingProcessHost* EnsureStarted();
+
+  // Returns a pointer to the current global profiling process host or, if
+  // no profiling process is launched, nullptr.
+  static ProfilingProcessHost* Get();
+
+  // Appends necessary switches to a command line for a child process so it can
+  // be profiled. These switches will cause the child process to start in the
+  // same mode (either profiling or not) as the browser process.
+  static void AddSwitchesToChildCmdLine(base::CommandLine* child_cmd_line);
+
+ private:
+  ProfilingProcessHost();
+  ~ProfilingProcessHost();
+
+  void Launch();
+
+  // Use process_.IsValid() to determine if the child process has been launched.
+  base::Process process_;
+  std::string pipe_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(ProfilingProcessHost);
+};
+
+}  // namespace profiling
+
+#endif  // CHROME_BROWSER_PROFILING_HOST_PROFILING_PROCESS_HOST_H_
diff --git a/chrome/browser/renderer_host/site_per_process_text_input_browsertest.cc b/chrome/browser/renderer_host/site_per_process_text_input_browsertest.cc
index a06446b..0d3bbb0 100644
--- a/chrome/browser/renderer_host/site_per_process_text_input_browsertest.cc
+++ b/chrome/browser/renderer_host/site_per_process_text_input_browsertest.cc
@@ -5,6 +5,7 @@
 #include <vector>
 
 #include "base/command_line.h"
+#include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/chrome_content_browser_client.h"
 #include "chrome/browser/ui/browser.h"
@@ -15,6 +16,7 @@
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_client.h"
@@ -1250,8 +1252,13 @@
 // class provides that for testing.
 class TestBrowserClient : public ChromeContentBrowserClient {
  public:
-  TestBrowserClient() {}
-  ~TestBrowserClient() override {}
+  TestBrowserClient() {
+    old_client_ = content::SetBrowserClientForTesting(this);
+  }
+
+  ~TestBrowserClient() override {
+    content::SetBrowserClientForTesting(old_client_);
+  }
 
   // ContentBrowserClient overrides.
   void RenderProcessWillLaunch(
@@ -1275,6 +1282,7 @@
   }
 
  private:
+  content::ContentBrowserClient* old_client_ = nullptr;
   std::vector<scoped_refptr<content::TestTextInputClientMessageFilter>>
       filters_;
 
@@ -1294,8 +1302,6 @@
   // been initialized with the original ContentBrowserClient and the new
   // TestBrowserClient, respectively.
   TestBrowserClient browser_client;
-  content::ContentBrowserClient* old_browser_client =
-      content::SetBrowserClientForTesting(&browser_client);
 
   content::WebContents* new_contents =
       content::WebContents::Create(content::WebContents::CreateParams(
@@ -1368,9 +1374,144 @@
   // Closing this WebContents while we still hold on to our TestBrowserClient.
   EXPECT_TRUE(browser()->tab_strip_model()->CloseWebContentsAt(
       1, TabStripModel::CLOSE_USER_GESTURE));
+}
 
-  // For the cleanup of the original WebContents in tab index 0.
-  content::SetBrowserClientForTesting(old_browser_client);
+// This test verifies that when a word lookup result comes from the renderer
+// after the target RenderWidgetHost has been deleted, the browser will not
+// crash. This test covers the case where the target RenderWidgetHost is that of
+// an OOPIF.
+IN_PROC_BROWSER_TEST_F(
+    SitePerProcessTextInputManagerTest,
+    DoNotCrashBrowserInWordLookUpForDestroyedWidget_ChildFrame) {
+  TestBrowserClient browser_client;
+
+  content::WebContents* new_contents =
+      content::WebContents::Create(content::WebContents::CreateParams(
+          active_contents()->GetBrowserContext(), nullptr));
+  browser()->tab_strip_model()->InsertWebContentsAt(1, new_contents,
+                                                    TabStripModel::ADD_ACTIVE);
+  EXPECT_EQ(active_contents(), new_contents);
+
+  // Simple page with 1 cross origin (out-of-process) <iframe>.
+  CreateIframePage("a(b)");
+
+  content::RenderFrameHost* child_frame = GetFrame(IndexVector{0});
+  // Now add an <input> field and select its text.
+  AddInputFieldToFrame(child_frame, "text", "four", true);
+  EXPECT_TRUE(ExecuteScript(child_frame,
+                            "window.focus();"
+                            "document.querySelector('input').focus();"
+                            "document.querySelector('input').select();"));
+
+  content::RenderWidgetHostView* child_view = child_frame->GetView();
+  scoped_refptr<content::TestTextInputClientMessageFilter>
+      child_message_filter =
+          browser_client.GetTextInputClientMessageFilterForProcess(
+              child_view->GetRenderWidgetHost()->GetProcess());
+  DCHECK(child_message_filter);
+
+  // We need to wait for test scenario to complete before leaving this block.
+  base::RunLoop test_complete_waiter;
+
+  // Destroy the RenderWidgetHost from the browser side right after the
+  // dictionary IPC is received. The destruction is post tasked to UI thread.
+  int32_t child_process_id =
+      child_view->GetRenderWidgetHost()->GetProcess()->GetID();
+  int32_t child_frame_routing_id = child_frame->GetRoutingID();
+  child_message_filter->SetStringForRangeCallback(base::Bind(
+      [](int32_t process_id, int32_t routing_id,
+         const base::Closure& callback_on_io) {
+        // This runs before TextInputClientMac gets to handle the IPC. Then,
+        // by the time TextInputClientMac calls back into UI to show the
+        // dictionary, the target RWH is already destroyed which will be a
+        // close enough repro for the crash in https://crbug.com/737032.
+        ASSERT_TRUE(content::DestroyRenderWidgetHost(process_id, routing_id));
+
+        // Quit the run loop on IO to make sure the message handler of
+        // TextInputClientMac has successfully run on UI thread.
+        content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE,
+                                         callback_on_io);
+      },
+      child_process_id, child_frame_routing_id,
+      test_complete_waiter.QuitClosure()));
+
+  content::RenderWidgetHostView* page_rwhv =
+      content::WebContents::FromRenderFrameHost(child_frame)
+          ->GetRenderWidgetHostView();
+
+  // The dictionary request to be made will be routed to the focused frame.
+  ASSERT_EQ(child_frame, new_contents->GetFocusedFrame());
+
+  // Request for the dictionary lookup and intercept the word on its way back.
+  // The request is always on the tab's view which is a RenderWidgetHostViewMac.
+  content::AskForLookUpDictionaryForRange(page_rwhv, gfx::Range(0, 4));
+
+  test_complete_waiter.Run();
+}
+
+// This test verifies that when a word lookup result comes from the renderer
+// after the target RenderWidgetHost has been deleted, the browser will not
+// crash. This test covers the case where the target RenderWidgetHost is that of
+// the main frame (no OOPIFs on page).
+IN_PROC_BROWSER_TEST_F(
+    SitePerProcessTextInputManagerTest,
+    DoNotCrashBrowserInWordLookUpForDestroyedWidget_MainFrame) {
+  TestBrowserClient browser_client;
+
+  content::WebContents* new_contents =
+      content::WebContents::Create(content::WebContents::CreateParams(
+          active_contents()->GetBrowserContext(), nullptr));
+  browser()->tab_strip_model()->InsertWebContentsAt(1, new_contents,
+                                                    TabStripModel::ADD_ACTIVE);
+  EXPECT_EQ(active_contents(), new_contents);
+
+  // Simple page with no <iframe>s.
+  CreateIframePage("a()");
+
+  content::RenderFrameHost* main_frame = GetFrame(IndexVector{});
+  // Now add an <input> field and select its text.
+  AddInputFieldToFrame(main_frame, "text", "four", true);
+  EXPECT_TRUE(ExecuteScript(main_frame,
+                            "document.querySelector('input').focus();"
+                            "document.querySelector('input').select();"));
+
+  content::RenderWidgetHostView* page_rwhv = main_frame->GetView();
+  scoped_refptr<content::TestTextInputClientMessageFilter> message_filter =
+      browser_client.GetTextInputClientMessageFilterForProcess(
+          page_rwhv->GetRenderWidgetHost()->GetProcess());
+  DCHECK(message_filter);
+
+  // We need to wait for test scenario to complete before leaving this block.
+  base::RunLoop test_complete_waiter;
+
+  // Destroy the RenderWidgetHost from the browser side right after the
+  // dictionary IPC is received. The destruction is post tasked to UI thread.
+  int32_t main_frame_process_id =
+      page_rwhv->GetRenderWidgetHost()->GetProcess()->GetID();
+  int32_t main_frame_routing_id = main_frame->GetRoutingID();
+  message_filter->SetStringForRangeCallback(base::Bind(
+      [](int32_t process_id, int32_t routing_id,
+         const base::Closure& callback_on_io) {
+        // This runs before TextInputClientMac gets to handle the IPC. Then,
+        // by the time TextInputClientMac calls back into UI to show the
+        // dictionary, the target RWH is already destroyed which will be a
+        // close enough repro for the crash in https://crbug.com/737032.
+        ASSERT_TRUE(content::DestroyRenderWidgetHost(process_id, routing_id));
+
+        // Quit the run loop on IO to make sure the message handler of
+        // TextInputClientMac has successfully run on UI thread.
+        content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE,
+                                         callback_on_io);
+      },
+      main_frame_process_id, main_frame_routing_id,
+      test_complete_waiter.QuitClosure()));
+
+  // Request for the dictionary lookup and intercept the word on its way back.
+  // The request is always on the tab's view which is a RenderWidgetHostViewMac.
+  content::AskForLookUpDictionaryForRange(page_rwhv, gfx::Range(0, 4));
+
+  test_complete_waiter.Run();
 }
 #endif  //  defined(MAC_OSX)
+
 #endif  // !defined(OS_ANDROID)
diff --git a/chrome/browser/resource_coordinator/tab_manager.cc b/chrome/browser/resource_coordinator/tab_manager.cc
index 122f6bd7..cd87260 100644
--- a/chrome/browser/resource_coordinator/tab_manager.cc
+++ b/chrome/browser/resource_coordinator/tab_manager.cc
@@ -8,13 +8,11 @@
 
 #include <algorithm>
 #include <set>
-#include <vector>
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/command_line.h"
 #include "base/feature_list.h"
-#include "base/macros.h"
 #include "base/memory/memory_pressure_monitor.h"
 #include "base/metrics/field_trial.h"
 #include "base/metrics/histogram_macros.h"
@@ -97,31 +95,6 @@
   return -1;
 }
 
-class BoundsList {
- public:
-  BoundsList() = default;
-
-  // Returns false if a previously inserted gfx::Rect covers |bounds|.
-  // Otherwise, returns true and adds |bounds| to the list.
-  //
-  // TODO(fdoray): Handle the case where no previously inserted gfx::Rect covers
-  // |bounds| by itself but the union of all previously inserted gfx::Rects
-  // covers |bounds|.
-  bool AddBoundsIfNotCoveredByPreviousBounds(const gfx::Rect& bounds) {
-    for (const gfx::Rect& previous_bounds : bounds_list_) {
-      if (previous_bounds.Contains(bounds))
-        return false;
-    }
-    bounds_list_.push_back(bounds);
-    return true;
-  }
-
- private:
-  std::vector<gfx::Rect> bounds_list_;
-
-  DISALLOW_COPY_AND_ASSIGN(BoundsList);
-};
-
 }  // namespace
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -391,19 +364,8 @@
 
   TabStatsList stats_list;
   stats_list.reserve(32);  // 99% of users have < 30 tabs open.
-  BoundsList bounds_list;
-
-  // GetBrowserInfoList() returns a list sorted in z-order from top to bottom.
-  // This is important for the visibility calculations below.
-  for (const BrowserInfo& browser_info : GetBrowserInfoList()) {
-    const bool window_is_visible =
-        !browser_info.window_is_minimized &&
-        bounds_list.AddBoundsIfNotCoveredByPreviousBounds(
-            browser_info.window_bounds);
-    AddTabStats(browser_info.tab_strip_model, window_is_visible,
-                browser_info.window_is_active, browser_info.browser_is_app,
-                &stats_list);
-  }
+  for (const BrowserInfo& browser_info : GetBrowserInfoList())
+    AddTabStats(browser_info, &stats_list);
 
   return stats_list;
 }
@@ -632,21 +594,23 @@
   return tab_count;
 }
 
-void TabManager::AddTabStats(const TabStripModel* tab_strip_model,
-                             bool window_is_visible,
-                             bool window_is_active,
-                             bool browser_is_app,
+void TabManager::AddTabStats(const BrowserInfo& browser_info,
                              TabStatsList* stats_list) const {
+  TabStripModel* tab_strip_model = browser_info.tab_strip_model;
   for (int i = 0; i < tab_strip_model->count(); i++) {
     WebContents* contents = tab_strip_model->GetWebContentsAt(i);
     if (!contents->IsCrashed()) {
       TabStats stats;
-      stats.is_app = browser_is_app;
+      stats.is_app = browser_info.browser_is_app;
       stats.is_internal_page = IsInternalPage(contents->GetLastCommittedURL());
       stats.is_media = IsMediaTab(contents);
       stats.is_pinned = tab_strip_model->IsTabPinned(i);
-      stats.is_selected = window_is_active && tab_strip_model->IsTabSelected(i);
-      stats.is_in_visible_window = window_is_visible;
+      stats.is_selected =
+          browser_info.window_is_active && tab_strip_model->IsTabSelected(i);
+      // Only consider the window non-visible if it is minimized. The consumer
+      // of the constructed TabStatsList may update this after performing more
+      // advanced window visibility checks.
+      stats.is_in_visible_window = !browser_info.window_is_minimized;
       stats.is_discarded = GetWebContentsData(contents)->IsDiscarded();
       stats.has_form_entry =
           contents->GetPageImportanceSignals().had_form_interaction;
@@ -829,6 +793,9 @@
     // Re-setting time-to-purge every time a tab becomes inactive.
     GetWebContentsData(old_contents)
         ->set_time_to_purge(GetTimeToPurge(min_time_to_purge_));
+    // Only record switch-to-tab metrics when a switch happens, i.e.
+    // |old_contents| is set.
+    RecordSwitchToTab(new_contents);
   }
 }
 
@@ -935,7 +902,6 @@
     browser_info.tab_strip_model = browser->tab_strip_model();
     browser_info.window_is_active = browser->window()->IsActive();
     browser_info.window_is_minimized = browser->window()->IsMinimized();
-    browser_info.window_bounds = browser->window()->GetBounds();
     browser_info.browser_is_app = browser->is_app();
     browser_info_list.push_back(browser_info);
   }
@@ -943,4 +909,12 @@
   return browser_info_list;
 }
 
+void TabManager::RecordSwitchToTab(content::WebContents* contents) const {
+  if (is_session_restore_loading_tabs_) {
+    UMA_HISTOGRAM_ENUMERATION("TabManager.SessionRestore.SwitchToTab",
+                              GetWebContentsData(contents)->tab_loading_state(),
+                              TAB_LOADING_STATE_MAX);
+  }
+}
+
 }  // namespace resource_coordinator
diff --git a/chrome/browser/resource_coordinator/tab_manager.h b/chrome/browser/resource_coordinator/tab_manager.h
index 414b743..038bed63 100644
--- a/chrome/browser/resource_coordinator/tab_manager.h
+++ b/chrome/browser/resource_coordinator/tab_manager.h
@@ -27,7 +27,6 @@
 #include "chrome/browser/sessions/session_restore_observer.h"
 #include "chrome/browser/ui/browser_tab_strip_tracker.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
-#include "ui/gfx/geometry/rect.h"
 
 class BrowserList;
 class GURL;
@@ -184,13 +183,13 @@
   FRIEND_TEST_ALL_PREFIXES(TabManagerTest, FastShutdownSingleTabProcess);
   FRIEND_TEST_ALL_PREFIXES(TabManagerTest,
                            GetUnsortedTabStatsIsInVisibleWindow);
+  FRIEND_TEST_ALL_PREFIXES(TabManagerTest, HistogramsSessionRestoreSwitchToTab);
 
   // Information about a Browser.
   struct BrowserInfo {
     TabStripModel* tab_strip_model;
     bool window_is_active;
     bool window_is_minimized;
-    gfx::Rect window_bounds;
     bool browser_is_app;
   };
 
@@ -244,15 +243,8 @@
   // Returns the number of tabs open in all browser instances.
   int GetTabCount() const;
 
-  // Adds all the stats of the tabs in |tab_strip_model| into |stats_list|.
-  // |window_is_visible| indicates whether |tab_strip_model| lives in a window
-  // which is visible to the user. |window_is_active| indicates whether
-  // |tab_strip_model| lives in the currently active window. |browser_is_app|
-  // indicates whether |tab_strip_model| is in a Browser running an app.
-  void AddTabStats(const TabStripModel* tab_strip_model,
-                   bool window_is_visible,
-                   bool window_is_active,
-                   bool browser_is_app,
+  // Adds all the stats of the tabs in |browser_info| into |stats_list|.
+  void AddTabStats(const BrowserInfo& browser_info,
                    TabStatsList* stats_list) const;
 
   // Callback for when |update_timer_| fires. Takes care of executing the tasks
@@ -330,6 +322,10 @@
   void OnSessionRestoreStartedLoadingTabs();
   void OnSessionRestoreFinishedLoadingTabs();
 
+  // Records UMA histograms for the tab state when switching to a different tab
+  // during session restore.
+  void RecordSwitchToTab(content::WebContents* contents) const;
+
   // Timer to periodically update the stats of the renderers.
   base::RepeatingTimer update_timer_;
 
diff --git a/chrome/browser/resource_coordinator/tab_manager_delegate_chromeos.h b/chrome/browser/resource_coordinator/tab_manager_delegate_chromeos.h
index 025fcea..8c51eb6 100644
--- a/chrome/browser/resource_coordinator/tab_manager_delegate_chromeos.h
+++ b/chrome/browser/resource_coordinator/tab_manager_delegate_chromeos.h
@@ -10,7 +10,7 @@
 #include <utility>
 #include <vector>
 
-#include "base/containers/hash_tables.h"
+#include "base/containers/flat_map.h"
 #include "base/gtest_prod_util.h"
 #include "base/logging.h"
 #include "base/macros.h"
@@ -126,10 +126,10 @@
   typedef std::pair<int, base::ProcessHandle> ProcessInfo;
 
   // Cache OOM scores in memory.
-  typedef base::hash_map<base::ProcessHandle, int> ProcessScoreMap;
+  typedef base::flat_map<base::ProcessHandle, int> ProcessScoreMap;
 
   // A map from an ARC process name to a monotonic timestamp when it's killed.
-  typedef base::hash_map<std::string, base::TimeTicks> KilledArcProcessesMap;
+  typedef base::flat_map<std::string, base::TimeTicks> KilledArcProcessesMap;
 
   // Get the list of candidates to kill, sorted by descending importance.
   static std::vector<Candidate> GetSortedCandidates(
diff --git a/chrome/browser/resource_coordinator/tab_manager_unittest.cc b/chrome/browser/resource_coordinator/tab_manager_unittest.cc
index 238610c..2e68ed0 100644
--- a/chrome/browser/resource_coordinator/tab_manager_unittest.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_unittest.cc
@@ -14,6 +14,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/metrics/field_trial.h"
 #include "base/strings/string16.h"
+#include "base/test/histogram_tester.h"
 #include "base/test/mock_entropy_provider.h"
 #include "base/test/simple_test_tick_clock.h"
 #include "base/time/time.h"
@@ -468,7 +469,6 @@
   browser_info.tab_strip_model = &tabstrip;
   browser_info.window_is_active = true;
   browser_info.window_is_minimized = false;
-  browser_info.window_bounds = gfx::Rect(0, 0, 0, 0);
   browser_info.browser_is_app = false;
   tab_manager.test_browser_info_list_.push_back(browser_info);
 
@@ -511,10 +511,8 @@
   WebContents* web_contents1b = CreateWebContents();
   WebContents* web_contents2a = CreateWebContents();
   WebContents* web_contents2b = CreateWebContents();
-  WebContents* web_contents3a = CreateWebContents();
-  WebContents* web_contents3b = CreateWebContents();
 
-  // Create 3 TabStripModels.
+  // Create 2 TabStripModels.
   TabStripModel tab_strip1(&delegate, profile());
   tab_strip1.AppendWebContents(web_contents1a, true);
   tab_strip1.AppendWebContents(web_contents1b, false);
@@ -523,42 +521,28 @@
   tab_strip2.AppendWebContents(web_contents2a, true);
   tab_strip2.AppendWebContents(web_contents2b, false);
 
-  TabStripModel tab_strip3(&delegate, profile());
-  tab_strip3.AppendWebContents(web_contents3a, true);
-  tab_strip3.AppendWebContents(web_contents3b, false);
-
-  // Add the 3 TabStripModels to the TabManager.
-  // The window for |tab_strip1| covers the window for |tab_strip2|. The window
-  // for |tab_strip3| is minimized.
+  // Add the 2 TabStripModels to the TabManager.
+  // The window for |tab_strip1| is visible while the window for |tab_strip2| is
+  // minimized.
   TabManager::BrowserInfo browser_info1;
   browser_info1.tab_strip_model = &tab_strip1;
   browser_info1.window_is_active = true;
   browser_info1.window_is_minimized = false;
-  browser_info1.window_bounds = gfx::Rect(0, 0, 100, 100);
   browser_info1.browser_is_app = false;
   tab_manager.test_browser_info_list_.push_back(browser_info1);
 
   TabManager::BrowserInfo browser_info2;
   browser_info2.tab_strip_model = &tab_strip2;
   browser_info2.window_is_active = false;
-  browser_info2.window_is_minimized = false;
-  browser_info2.window_bounds = gfx::Rect(10, 10, 50, 50);
+  browser_info2.window_is_minimized = true;
   browser_info2.browser_is_app = false;
   tab_manager.test_browser_info_list_.push_back(browser_info2);
 
-  TabManager::BrowserInfo browser_info3;
-  browser_info3.tab_strip_model = &tab_strip3;
-  browser_info3.window_is_active = false;
-  browser_info3.window_is_minimized = true;
-  browser_info3.window_bounds = gfx::Rect();
-  browser_info3.browser_is_app = false;
-  tab_manager.test_browser_info_list_.push_back(browser_info3);
-
   // Get TabStats and verify the the |is_in_visible_window| field of each
   // TabStats is set correctly.
   auto tab_stats = tab_manager.GetUnsortedTabStats();
 
-  ASSERT_EQ(6U, tab_stats.size());
+  ASSERT_EQ(4U, tab_stats.size());
 
   EXPECT_EQ(tab_stats[0].tab_contents_id,
             tab_manager.IdFromWebContents(web_contents1a));
@@ -568,17 +552,11 @@
             tab_manager.IdFromWebContents(web_contents2a));
   EXPECT_EQ(tab_stats[3].tab_contents_id,
             tab_manager.IdFromWebContents(web_contents2b));
-  EXPECT_EQ(tab_stats[4].tab_contents_id,
-            tab_manager.IdFromWebContents(web_contents3a));
-  EXPECT_EQ(tab_stats[5].tab_contents_id,
-            tab_manager.IdFromWebContents(web_contents3b));
 
   EXPECT_TRUE(tab_stats[0].is_in_visible_window);
   EXPECT_TRUE(tab_stats[1].is_in_visible_window);
   EXPECT_FALSE(tab_stats[2].is_in_visible_window);
   EXPECT_FALSE(tab_stats[3].is_in_visible_window);
-  EXPECT_FALSE(tab_stats[4].is_in_visible_window);
-  EXPECT_FALSE(tab_stats[5].is_in_visible_window);
 }
 
 TEST_F(TabManagerTest, OnSessionRestoreStartedAndFinishedLoadingTabs) {
@@ -601,4 +579,50 @@
   EXPECT_FALSE(tab_manager->IsSessionRestoreLoadingTabs());
 }
 
+TEST_F(TabManagerTest, HistogramsSessionRestoreSwitchToTab) {
+  const char kHistogramName[] = "TabManager.SessionRestore.SwitchToTab";
+
+  TabManager tab_manager;
+  WebContents* tab = CreateWebContents();
+  auto* data = tab_manager.GetWebContentsData(tab);
+
+  base::HistogramTester histograms;
+  histograms.ExpectTotalCount(kHistogramName, 0);
+
+  data->SetTabLoadingState(TAB_IS_LOADING);
+  tab_manager.RecordSwitchToTab(tab);
+  tab_manager.RecordSwitchToTab(tab);
+
+  // Nothing should happen until we're in a session restore
+  histograms.ExpectTotalCount(kHistogramName, 0);
+
+  tab_manager.OnSessionRestoreStartedLoadingTabs();
+
+  data->SetTabLoadingState(TAB_IS_NOT_LOADING);
+  tab_manager.RecordSwitchToTab(tab);
+  tab_manager.RecordSwitchToTab(tab);
+  histograms.ExpectTotalCount(kHistogramName, 2);
+  histograms.ExpectBucketCount(kHistogramName, TAB_IS_NOT_LOADING, 2);
+
+  data->SetTabLoadingState(TAB_IS_LOADING);
+  tab_manager.RecordSwitchToTab(tab);
+  tab_manager.RecordSwitchToTab(tab);
+  tab_manager.RecordSwitchToTab(tab);
+
+  histograms.ExpectTotalCount(kHistogramName, 5);
+  histograms.ExpectBucketCount(kHistogramName, TAB_IS_NOT_LOADING, 2);
+  histograms.ExpectBucketCount(kHistogramName, TAB_IS_LOADING, 3);
+
+  data->SetTabLoadingState(TAB_IS_LOADED);
+  tab_manager.RecordSwitchToTab(tab);
+  tab_manager.RecordSwitchToTab(tab);
+  tab_manager.RecordSwitchToTab(tab);
+  tab_manager.RecordSwitchToTab(tab);
+
+  histograms.ExpectTotalCount(kHistogramName, 9);
+  histograms.ExpectBucketCount(kHistogramName, TAB_IS_NOT_LOADING, 2);
+  histograms.ExpectBucketCount(kHistogramName, TAB_IS_LOADING, 3);
+  histograms.ExpectBucketCount(kHistogramName, TAB_IS_LOADED, 4);
+}
+
 }  // namespace resource_coordinator
diff --git a/chrome/browser/resource_coordinator/tab_manager_web_contents_data.h b/chrome/browser/resource_coordinator/tab_manager_web_contents_data.h
index b77e5cb8..3ccce43 100644
--- a/chrome/browser/resource_coordinator/tab_manager_web_contents_data.h
+++ b/chrome/browser/resource_coordinator/tab_manager_web_contents_data.h
@@ -29,11 +29,13 @@
 // occurs in the main frame, which happens if the user navigates to a new page
 // and the WebContents is reused.
 //
+// These values are used in the TabManager.SessionRestore.SwitchToTab UMA.
+//
 // TODO(shaseley): *switch to the new done signal (network and cpu quiescence)
 // when available.
 //
-// TODO(shaseley): This will become an UMA histogram once the TabManager is
-// aware of session restore begin/end and background tab loading begin/end.
+// These values are written to logs.  New enum values can be added, but existing
+// enums must never be renumbered or deleted and reused.
 enum TabLoadingState {
   TAB_IS_NOT_LOADING = 0,
   TAB_IS_LOADING = 1,
@@ -129,6 +131,7 @@
   // Needed to access tab_data_.
   FRIEND_TEST_ALL_PREFIXES(TabManagerWebContentsDataTest, CopyState);
   FRIEND_TEST_ALL_PREFIXES(TabManagerWebContentsDataTest, TabLoadingState);
+  FRIEND_TEST_ALL_PREFIXES(TabManagerTest, HistogramsSessionRestoreSwitchToTab);
 
   struct Data {
     Data();
diff --git a/chrome/browser/resources/chromeos/login/images/reset_illustration_1x.png b/chrome/browser/resources/chromeos/login/images/reset_illustration_1x.png
index 3de65d5..2857574 100644
--- a/chrome/browser/resources/chromeos/login/images/reset_illustration_1x.png
+++ b/chrome/browser/resources/chromeos/login/images/reset_illustration_1x.png
Binary files differ
diff --git a/chrome/browser/resources/chromeos/login/images/reset_illustration_2x.png b/chrome/browser/resources/chromeos/login/images/reset_illustration_2x.png
index 85e2a8a3..1c43abd 100644
--- a/chrome/browser/resources/chromeos/login/images/reset_illustration_2x.png
+++ b/chrome/browser/resources/chromeos/login/images/reset_illustration_2x.png
Binary files differ
diff --git a/chrome/browser/resources/chromeos/login/offline_gaia.css b/chrome/browser/resources/chromeos/login/offline_gaia.css
index 9669aa48..715638a 100644
--- a/chrome/browser/resources/chromeos/login/offline_gaia.css
+++ b/chrome/browser/resources/chromeos/login/offline_gaia.css
@@ -10,15 +10,13 @@
   position: relative;
 }
 
-paper-dialog {
-  --paper-dialog-title: {
-    font-size: 15px;
-  };
-
+#forgotPasswordDlg {
+  color: var(--primary-text-color);
+  font-size: 15px;
   width: 384px;
 }
 
-#forgotPasswordDlg .buttons {
-  padding: 15px 24px 24px;
+oobe-dialog gaia-input-form {
+  margin: 44px 64px 0 64px;
+  width: 640px;
 }
-
diff --git a/chrome/browser/resources/chromeos/login/offline_gaia.html b/chrome/browser/resources/chromeos/login/offline_gaia.html
index 42ffc89..fb30b000 100644
--- a/chrome/browser/resources/chromeos/login/offline_gaia.html
+++ b/chrome/browser/resources/chromeos/login/offline_gaia.html
@@ -2,6 +2,8 @@
      Use of this source code is governed by a BSD-style license that can be
      found in the LICENSE file. -->
 
+<link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/classes/iron-flex-layout.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/animations/slide-from-left-animation.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/animations/slide-from-right-animation.html">
@@ -9,7 +11,7 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/animations/slide-right-animation.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/neon-animatable.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/neon-animated-pages.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-dialog/paper-dialog.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
 
 <!--
@@ -25,6 +27,7 @@
     'showEnterpriseMessage' - If the "manged by" message should be shown.
     'domain' - The enterprise domain the device is managed by.
     'emailDomain' - autocomplete domain for the email input.
+    'glif-mode' - GLIF MM mode (Gaia v2 API).
 
   Events:
     'authCompleted' - fired when user enters login and password. Fires with an
@@ -45,62 +48,136 @@
   <link rel="stylesheet" href="offline_gaia.css">
 
   <template>
-    <neon-animated-pages id="animatedPages" class="fit" attr-for-selected="id"
-        entry-animation="slide-from-right-animation"
-        exit-animation="slide-to-left-animation"
-        on-neon-animation-finish="onAnimationFinish_" selected="emailSection">
-
-      <neon-animatable id="emailSection" class="fit">
-        <gaia-card class="fit">
-          <div class="header flex vertical layout end-justified start">
-            <h1 class="welcome-message" i18n-content="loginWelcomeMessage"></h1>
-            <p id="managedBy" class="enterprise-info"
-               hidden$="[[!showEnterpriseMessage]]">
-            </p>
+    <style include="cr-shared-style"></style>
+    <link rel="stylesheet" href="oobe_dialog_host.css">
+    <link rel="stylesheet" href="oobe_dialog_parameters.css">
+    <template is="dom-if" if="[[glifMode]]" restamp>
+      <oobe-dialog role="dialog" has-buttons no-footer-padding>
+        <img src="chrome://theme/IDR_LOGO_GOOGLE_COLOR_90"
+            class="oobe-icon" alt="">
+        <div class="header">
+          <neon-animated-pages id="animatedHeaders" attr-for-selected="id"
+              entry-animation="slide-from-right-animation"
+              exit-animation="slide-to-left-animation"
+              on-neon-animation-finish="onAnimationFinish_"
+              selected="emailSection">
+            <neon-animatable id="emailSection">
+              <h1 class="title">
+                [[i18nDynamic(locale, 'loginWelcomeMessage')]]
+              </h1>
+              <p id="managedBy" class="enterprise-info"
+                  hidden$="[[!showEnterpriseMessage]]">
+              </p>
+            </neon-animatable>
+            <neon-animatable id="passwordSection">
+              <gaia-header class="title" id="passwordHeader"></gaia-header>
+            </neon-animatable>
+          </neon-animated-pages>
+        </div>
+        <div class="footer layout vertical">
+          <neon-animated-pages id="animatedPages" attr-for-selected="id"
+              entry-animation="slide-from-right-animation"
+              exit-animation="slide-to-left-animation"
+              on-neon-animation-finish="onAnimationFinish_"
+              selected="emailSection">
+            <neon-animatable id="emailSection">
+              <gaia-input-form on-submit="onEmailSubmitted_"
+                  disabled="[[disabled]]"
+                  button-text="[[i18nDynamic(locale, 'offlineLoginNextBtn')]]">
+                <gaia-input id="emailInput" type="email" required
+                    domain="[[emailDomain]]"
+                    error="[[i18nDynamic(locale, 'offlineLoginInvalidEmail')]]"
+                    label="[[i18nDynamic(locale, 'offlineLoginEmail')]]">
+                </gaia-input>
+              </gaia-input-form>
+            </neon-animatable>
+            <neon-animatable id="passwordSection">
+              <gaia-input-form class="footer" disabled="[[disabled]]"
+                  on-submit="onPasswordSubmitted_"
+                  button-text="[[i18nDynamic(locale, 'offlineLoginNextBtn')]]">
+                <gaia-input id="passwordInput" type="password" required
+                    error="[[i18nDynamic(locale,
+                                         'offlineLoginInvalidPassword')]]"
+                    label="[[i18nDynamic(locale, 'offlineLoginPassword')]]">
+                </gaia-input>
+                <gaia-button type="link" on-tap="onForgotPasswordClicked_">
+                  [[i18nDynamic(locale, 'offlineLoginForgotPasswordBtn')]]
+                </gaia-button>
+              </gaia-input-form>
+            </neon-animatable>
+          </neon-animated-pages>
+        </div>
+        <div class="bottom-buttons flex layout horizontal">
+          <oobe-back-button id="offline-gaia-back-button"
+              on-tap="onBackButtonClicked_">
+          </oobe-back-button>
+          <div class="flex">
           </div>
-          <div class="footer flex vertical layout justified">
-            <gaia-input-form on-submit="onEmailSubmitted_"
-                disabled="[[disabled]]"
-                i18n-values="button-text:offlineLoginNextBtn">
-              <gaia-input id="emailInput" type="email" required
-                  domain="[[emailDomain]]"
-                  i18n-values="error:offlineLoginInvalidEmail;
-                               label:offlineLoginEmail">
-              </gaia-input>
-            </gaia-input-form>
-            <img src="chrome://theme/IDR_LOGO_GOOGLE_COLOR_90"
-                class="self-center" alt="">
-          </div>
-        </gaia-card>
-      </neon-animatable>
+          <oobe-next-button inverse disabled>
+          </oobe-next-button>
+        </div>
+      </oobe-dialog>
+    </template>
 
-      <neon-animatable id="passwordSection" class="fit">
-        <gaia-card id="passwordCard" class="fit">
-          <gaia-header class="header flex" id="passwordHeader">
-          </gaia-header>
-          <gaia-input-form class="footer" disabled="[[disabled]]"
-              on-submit="onPasswordSubmitted_"
-              i18n-values="button-text:offlineLoginNextBtn">
-            <gaia-input id="passwordInput" type="password" required
-                i18n-values="error:offlineLoginInvalidPassword;
-                             label:offlineLoginPassword">
-            </gaia-input>
-            <gaia-button type="link" on-tap="onForgotPasswordClicked_"
-                i18n-content="offlineLoginForgotPasswordBtn">
-            </gaia-button>
-          </gaia-input-form>
-        </gaia-card>
-      </neon-animatable>
-    </neon-animated-pages>
+    <template is="dom-if" if="[[!glifMode]]" restamp>
+      <neon-animated-pages id="animatedPages" class="fit" attr-for-selected="id"
+          entry-animation="slide-from-right-animation"
+          exit-animation="slide-to-left-animation"
+          on-neon-animation-finish="onAnimationFinish_" selected="emailSection">
 
-    <paper-dialog id="forgotPasswordDlg" no-cancel-on-outside-click
-        on-iron-overlay-closed="onDialogOverlayClosed_">
-      <p i18n-content="offlineLoginForgotPasswordDlg"></p>
-      <div class="buttons">
-        <gaia-button type="dialog" dialog-confirm autofocus
-            i18n-content="offlineLoginCloseBtn">
-        </gaia-button>
+        <neon-animatable id="emailSection" class="fit">
+            <gaia-card class="fit">
+              <div class="header flex vertical layout end-justified start">
+                <h1 class="welcome-message" i18n-content="loginWelcomeMessage">
+                </h1>
+                <p id="managedBy" class="enterprise-info"
+                    hidden$="[[!showEnterpriseMessage]]">
+                </p>
+              </div>
+              <div class="footer flex vertical layout justified">
+                <gaia-input-form on-submit="onEmailSubmitted_"
+                    disabled="[[disabled]]"
+                    i18n-values="button-text:offlineLoginNextBtn">
+                  <gaia-input id="emailInput" type="email" required
+                      domain="[[emailDomain]]"
+                      i18n-values="error:offlineLoginInvalidEmail;
+                                   label:offlineLoginEmail">
+                  </gaia-input>
+                </gaia-input-form>
+                <img src="chrome://theme/IDR_LOGO_GOOGLE_COLOR_90"
+                    class="self-center" alt="">
+              </div>
+            </gaia-card>
+        </neon-animatable>
+
+        <neon-animatable id="passwordSection" class="fit">
+            <gaia-card id="passwordCard" class="fit">
+              <gaia-header class="header flex" id="passwordHeader">
+              </gaia-header>
+              <gaia-input-form class="footer" disabled="[[disabled]]"
+                  on-submit="onPasswordSubmitted_"
+                  i18n-values="button-text:offlineLoginNextBtn">
+                <gaia-input id="passwordInput" type="password" required
+                    i18n-values="error:offlineLoginInvalidPassword;
+                                 label:offlineLoginPassword">
+                </gaia-input>
+                <gaia-button type="link" on-tap="onForgotPasswordClicked_"
+                    i18n-content="offlineLoginForgotPasswordBtn">
+                </gaia-button>
+              </gaia-input-form>
+            </gaia-card>
+        </neon-animatable>
+      </neon-animated-pages>
+    </template>
+
+    <dialog is="cr-dialog" id="forgotPasswordDlg"
+        on-close="onDialogOverlayClosed_">
+      <div class="body" i18n-content="offlineLoginForgotPasswordDlg"></div>
+      <div class="button-container">
+        <paper-button autofocus on-tap="onForgotPasswordCloseTap_"
+            i18n-content="offlineLoginCloseBtn" class="action-button">
+        </paper-button>
       </div>
-    </paper-dialog>
+    </dialog>
   </template>
 </dom-module>
diff --git a/chrome/browser/resources/chromeos/login/offline_gaia.js b/chrome/browser/resources/chromeos/login/offline_gaia.js
index 30983ac..566cc45 100644
--- a/chrome/browser/resources/chromeos/login/offline_gaia.js
+++ b/chrome/browser/resources/chromeos/login/offline_gaia.js
@@ -10,6 +10,8 @@
   return {
     is: 'offline-gaia',
 
+    behaviors: [I18nBehavior],
+
     properties: {
       disabled: {type: Boolean, value: false},
 
@@ -17,7 +19,15 @@
 
       domain: {type: String, observer: 'onDomainChanged_'},
 
-      emailDomain: String
+      emailDomain: String,
+
+      /**
+       * Controls GLIF MM mode.
+       */
+      glifMode: {
+        type: Boolean,
+        value: false,
+      },
     },
 
     ready: function() {
@@ -26,7 +36,10 @@
        * https://github.com/PolymerElements/neon-animation/issues/32
        * TODO(dzhioev): Remove when fixed in Polymer.
        */
-      var pages = this.$.animatedPages;
+      var pages = this.$$('#animatedPages');
+      if (!pages)
+        return;
+
       delete pages._squelchNextFinishEvent;
       Object.defineProperty(pages, '_squelchNextFinishEvent', {
         get: function() {
@@ -37,9 +50,9 @@
 
     focus: function() {
       if (this.isEmailSectionActive_())
-        this.$.emailInput.focus();
+        this.$$('#emailInput').focus();
       else
-        this.$.passwordInput.focus();
+        this.$$('#passwordInput').focus();
     },
 
     back: function() {
@@ -47,7 +60,7 @@
     },
 
     onDomainChanged_: function() {
-      this.$.managedBy.textContent =
+      this.$$('#managedBy').textContent =
           loadTimeData.getStringF('enterpriseInfoMessage', this.domain);
       this.showEnterpriseMessage = !!this.domain.length;
     },
@@ -58,18 +71,20 @@
     },
 
     onForgotPasswordClicked_: function() {
-      this.$.forgotPasswordDlg.fitInto = this;
       this.disabled = true;
       this.fire('dialogShown');
-      this.$.forgotPasswordDlg.open();
-      this.$.passwordCard.classList.add('full-disabled');
-      this.$.forgotPasswordDlg.focus();
+      this.$$('#forgotPasswordDlg').showModal();
+      this.$$('#passwordCard').classList.add('full-disabled');
+    },
+
+    onForgotPasswordCloseTap_: function() {
+      this.$$('#.forgotPasswordDlg').close();
     },
 
     onDialogOverlayClosed_: function() {
       this.fire('dialogHidden');
       this.disabled = false;
-      this.$.passwordCard.classList.remove('full-disabled');
+      this.$$('#passwordCard').classList.remove('full-disabled');
     },
 
     setEmail: function(email) {
@@ -77,10 +92,10 @@
         if (this.emailDomain)
           email = email.replace(this.emailDomain, '');
         this.switchToPasswordCard(email, false /* animated */);
-        this.$.passwordInput.isInvalid = true;
+        this.$$('#passwordInput').isInvalid = true;
         this.fire('backButton', true);
       } else {
-        this.$.emailInput.value = '';
+        this.$$('#emailInput').value = '';
         this.switchToEmailCard(false /* animated */);
       }
     },
@@ -90,67 +105,97 @@
     },
 
     isEmailSectionActive_: function() {
-      return this.$.animatedPages.selected == 'emailSection';
+      return this.$$('#animatedPages').selected == 'emailSection';
     },
 
     switchToEmailCard(animated) {
-      this.$.passwordInput.value = '';
-      this.$.passwordInput.isInvalid = false;
-      this.$.emailInput.isInvalid = false;
+      this.$$('#passwordInput').value = '';
+      this.$$('#passwordInput').isInvalid = false;
+      this.$$('#emailInput').isInvalid = false;
       if (this.isEmailSectionActive_())
         return;
       this.setUpPageTransitions_(
           animated ? TRANSITION_TYPE.BACKWARD : TRANSITION_TYPE.NONE);
-      this.$.animatedPages.selected = 'emailSection';
+      this.$$('#animatedPages').selected = 'emailSection';
+      var animatedHeaders = this.$$('#animatedHeaders');
+      if (animatedHeaders)
+        animatedHeaders.selected = 'emailSection';
     },
 
     switchToPasswordCard(email, animated) {
-      this.$.emailInput.value = email;
+      this.$$('#emailInput').value = email;
       if (email.indexOf('@') === -1) {
         if (this.emailDomain)
           email = email + this.emailDomain;
         else
           email = email + DEFAULT_EMAIL_DOMAIN;
       }
-      this.$.passwordHeader.email = email;
+      this.$$('#passwordHeader').email = email;
       if (!this.isEmailSectionActive_())
         return;
       this.setUpPageTransitions_(
           animated ? TRANSITION_TYPE.FORWARD : TRANSITION_TYPE.NONE);
-      this.$.animatedPages.selected = 'passwordSection';
+      this.$$('#animatedPages').selected = 'passwordSection';
+      var animatedHeaders = this.$$('#animatedHeaders');
+      if (animatedHeaders)
+        animatedHeaders.selected = 'passwordSection';
     },
 
     onEmailSubmitted_: function() {
-      if (this.$.emailInput.checkValidity())
-        this.switchToPasswordCard(this.$.emailInput.value, true /* animated */);
-      else
-        this.$.emailInput.focus();
+      if (this.$$('#emailInput').checkValidity()) {
+        this.switchToPasswordCard(
+            this.$$('#emailInput').value, true /* animated */);
+      } else {
+        this.$$('#emailInput').focus();
+      }
     },
 
     onPasswordSubmitted_: function() {
-      if (!this.$.passwordInput.checkValidity())
+      if (!this.$$('#passwordInput').checkValidity())
         return;
       var msg = {
         'useOffline': true,
-        'email': this.$.passwordHeader.email,
-        'password': this.$.passwordInput.value
+        'email': this.$$('#passwordHeader').email,
+        'password': this.$$('#passwordInput').value
       };
-      this.$.passwordInput.value = '';
+      this.$$('#passwordInput').value = '';
       this.fire('authCompleted', msg);
     },
 
     setUpPageTransitions_: function(transitionType) {
+      var animatedPages = this.$$('#animatedPages');
+      var animatedHeaders = this.$$('#animatedHeaders');
       if (transitionType === TRANSITION_TYPE.NONE) {
-        this.$.animatedPages.entryAnimation = '';
-        this.$.animatedPages.exitAnimation = '';
+        animatedPages.entryAnimation = '';
+        animatedPages.exitAnimation = '';
+        if (animatedHeaders) {
+          animatedHeaders.entryAnimation = '';
+          animatedHeaders.exitAnimation = '';
+        }
         return;
       }
       var isForward = transitionType === TRANSITION_TYPE.FORWARD;
       var isRTL = this.isRTL_();
-      this.$.animatedPages.entryAnimation = 'slide-from-' +
+      var entryAnimation = 'slide-from-' +
           (isForward === isRTL ? 'left' : 'right') + '-animation';
-      this.$.animatedPages.exitAnimation =
+      var exitAnimation =
           'slide-' + (isForward === isRTL ? 'right' : 'left') + '-animation';
-    }
+      animatedPages.entryAnimation = entryAnimation;
+      animatedPages.exitAnimation = exitAnimation;
+      if (animatedHeaders) {
+        animatedHeaders.entryAnimation = entryAnimation;
+        animatedHeaders.exitAnimation = exitAnimation;
+      }
+    },
+
+    onBackButtonClicked_: function() {
+      if (!this.isEmailSectionActive_()) {
+        console.error('onBackButtonClicked_(): returning to e-mail card.');
+        this.switchToEmailCard(true);
+      } else {
+        console.error('onBackButtonClicked_(): firing cancel.');
+        this.fire('offline-gaia-cancel');
+      }
+    },
   };
 })());
diff --git a/chrome/browser/resources/chromeos/login/oobe_dialog_host.css b/chrome/browser/resources/chromeos/login/oobe_dialog_host.css
index 50cae38..7f604b1f 100644
--- a/chrome/browser/resources/chromeos/login/oobe_dialog_host.css
+++ b/chrome/browser/resources/chromeos/login/oobe_dialog_host.css
@@ -2,7 +2,11 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file. */
 
-:host {
+/* Some elements may be used both as dialogs or not as dialogs.
+ * |not-a-dialog| attribute is used to switch element "oobe-dialog-like" look.
+ */
+
+:host(:not([not-a-dialog])) {
   background-color: white;
   border-radius: 4px;
   box-shadow: 0 24px 24px rgba(0, 0, 0, .24), 0 0 24px rgba(0, 0, 0, .12);
@@ -13,7 +17,7 @@
   position: relative;
 }
 
-:host([android]) {
+:host(:not([not-a-dialog])[android]) {
   min-height: 480px;
   min-width: 576px;
 }
diff --git a/chrome/browser/resources/chromeos/login/oobe_reset_confirmation_overlay.css b/chrome/browser/resources/chromeos/login/oobe_reset_confirmation_overlay.css
index 52621fd..aaa79521 100644
--- a/chrome/browser/resources/chromeos/login/oobe_reset_confirmation_overlay.css
+++ b/chrome/browser/resources/chromeos/login/oobe_reset_confirmation_overlay.css
@@ -8,17 +8,19 @@
 
 .reset-popup {
   background: white;
+  border-radius: 2px;
   box-shadow: 0 0 16px rgba(0, 0, 0, .12), 0 16px 16px rgba(0, 0, 0, .24);
   min-height: 158px;
   position: relative;
   width: 512px;
+  z-index: 10;
 }
 
 .reset-popup h1 {
-  -webkit-margin-after: 0;
-  -webkit-margin-before: 0;
   color: var(--google-grey-900);
   font: 15px Roboto, sans-serif;
+  margin-bottom: 0;
+  margin-top: 0;
   padding: 16px 20px;
 }
 
@@ -31,8 +33,8 @@
 
 oobe-text-button {
   -webkit-margin-end: 16px;
-  -webkit-margin-after: 16px;
   color: #5a5a5a;
+  margin-bottom: 16px;
 }
 
 #cancelButton {
diff --git a/chrome/browser/resources/chromeos/login/saml_confirm_password.css b/chrome/browser/resources/chromeos/login/saml_confirm_password.css
index 3b5ce3a..d30b2ff6 100644
--- a/chrome/browser/resources/chromeos/login/saml_confirm_password.css
+++ b/chrome/browser/resources/chromeos/login/saml_confirm_password.css
@@ -16,15 +16,8 @@
   z-index: 1;
 }
 
-paper-dialog {
-  --paper-dialog-title: {
-    font-size: 15px;
-  };
-
+#cancelConfirmDlg {
+  color: var(--primary-text-color);
+  font-size: 15px;
   width: 384px;
 }
-
-#cancelConfirmDlg .buttons {
-  padding: 15px 24px 24px;
-}
-
diff --git a/chrome/browser/resources/chromeos/login/saml_confirm_password.html b/chrome/browser/resources/chromeos/login/saml_confirm_password.html
index cc4b83b8..50d94aa 100644
--- a/chrome/browser/resources/chromeos/login/saml_confirm_password.html
+++ b/chrome/browser/resources/chromeos/login/saml_confirm_password.html
@@ -2,13 +2,14 @@
      Use of this source code is governed by a BSD-style license that can be
      found in the LICENSE file. -->
 
+<link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/classes/iron-flex-layout.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/animations/fade-in-animation.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/animations/fade-out-animation.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/neon-animatable.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/neon-animated-pages.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-dialog/paper-dialog.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
 
 <!--
@@ -41,6 +42,7 @@
   <link rel="stylesheet" href="saml_confirm_password.css">
 
   <template>
+    <style include="cr-shared-style"></style>
     <neon-animated-pages id="animatedPages" class="fit"
         entry-animation="fade-in-animation" exit-animation="fade-out-animation"
         on-neon-animation-finish="onAnimationFinish_" selected="0">
@@ -75,18 +77,18 @@
         disabled="[[disabled]]">
     </navigation-bar>
 
-    <paper-dialog id="cancelConfirmDlg" no-cancel-on-outside-click
-        on-iron-overlay-closed="onDialogOverlayClosed_">
-      <h2 i18n-content="accountSetupCancelDialogTitle"></h2>
-      <div class="buttons">
-        <gaia-button type="dialog" dialog-dismiss autofocus
-            i18n-content="accountSetupCancelDialogNo">
-        </gaia-button>
-        <gaia-button type="dialog" dialog-confirm on-tap="onConfirmCancel_"
-            i18n-content="accountSetupCancelDialogYes">
-        </gaia-button>
+    <dialog is="cr-dialog" id="cancelConfirmDlg"
+        on-close="onDialogOverlayClosed_">
+      <div class="body" i18n-content="accountSetupCancelDialogTitle"></div>
+      <div class="button-container">
+        <paper-button class="action-button"
+            i18n-content="accountSetupCancelDialogNo" on-tap="onCancelNo_">
+        </paper-button>
+        <paper-button class="cancel-button"
+            i18n-content="accountSetupCancelDialogYes" on-tap="onCancelYes_">
+        </paper-button>
       </div>
-    </paper-dialog>
+    </dialog>
 
   </template>
 </dom-module>
diff --git a/chrome/browser/resources/chromeos/login/saml_confirm_password.js b/chrome/browser/resources/chromeos/login/saml_confirm_password.js
index 1a671fe..b5497ed 100644
--- a/chrome/browser/resources/chromeos/login/saml_confirm_password.js
+++ b/chrome/browser/resources/chromeos/login/saml_confirm_password.js
@@ -30,7 +30,8 @@
   },
 
   reset: function() {
-    this.$.cancelConfirmDlg.close();
+    if (this.$.cancelConfirmDlg.open)
+      this.$.cancelConfirmDlg.close();
     this.disabled = false;
     this.$.navigation.closeVisible = true;
     if (this.$.animatedPages.selected != 0)
@@ -54,11 +55,15 @@
 
   onClose_: function() {
     this.disabled = true;
-    this.$.cancelConfirmDlg.fitInto = this;
-    this.$.cancelConfirmDlg.open();
+    this.$.cancelConfirmDlg.showModal();
   },
 
-  onConfirmCancel_: function() {
+  onCancelNo_: function() {
+    this.$.cancelConfirmDlg.close();
+  },
+
+  onCancelYes_: function() {
+    this.$.cancelConfirmDlg.close();
     this.fire('cancel');
   },
 
diff --git a/chrome/browser/resources/chromeos/login/screen_gaia_signin.html b/chrome/browser/resources/chromeos/login/screen_gaia_signin.html
index e10aaca9..bee6ffd3 100644
--- a/chrome/browser/resources/chromeos/login/screen_gaia_signin.html
+++ b/chrome/browser/resources/chromeos/login/screen_gaia_signin.html
@@ -19,7 +19,7 @@
   <div id="gaia-step-contents" class="step-contents">
     <div id="gaia-signin-form-container">
       <webview id="signin-frame" name="signin-frame" hidden></webview>
-      <offline-gaia id="offline-gaia" class="fit" hidden></offline-gaia>
+      <offline-gaia id="offline-gaia" hidden></offline-gaia>
       <saml-interstitial id="saml-interstitial" class="fit" hidden>
       </saml-interstitial>
       <offline-ad-login id="offline-ad-auth" class="fit" hidden
diff --git a/chrome/browser/resources/chromeos/login/screen_gaia_signin.js b/chrome/browser/resources/chromeos/login/screen_gaia_signin.js
index fdba1a8..d61c68f 100644
--- a/chrome/browser/resources/chromeos/login/screen_gaia_signin.js
+++ b/chrome/browser/resources/chromeos/login/screen_gaia_signin.js
@@ -258,6 +258,8 @@
       $('signin-back-button')
           .addEventListener(
               'click', this.onBackButtonClicked_.bind(this, true));
+      $('offline-gaia')
+          .addEventListener('offline-gaia-cancel', this.cancel.bind(this));
 
       this.navigation_.addEventListener('close', function() {
         this.cancel();
@@ -629,8 +631,18 @@
       this.samlPasswordConfirmAttempt_ = 0;
 
       this.chromeOSApiVersion_ = data.chromeOSApiVersion;
-      if (this.chromeOSApiVersion_ == 2)
+      if (this.chromeOSApiVersion_ == 2) {
         $('signin-frame-container-v2').appendChild($('signin-frame'));
+        $('gaia-signin')
+            .insertBefore($('offline-gaia'), $('gaia-step-contents'));
+        $('offline-gaia').glifMode = true;
+        $('offline-gaia').removeAttribute('not-a-dialog');
+        $('offline-gaia').classList.toggle('fit', false);
+      } else {
+        $('offline-gaia').glifMode = false;
+        $('offline-gaia').setAttribute('not-a-dialog', true);
+        $('offline-gaia').classList.toggle('fit', true);
+      }
 
       this.updateSigninFrameContainers_();
 
@@ -681,7 +693,8 @@
     updateSigninFrameContainers_: function() {
       let old_state = this.classList.contains('v2');
       this.classList.toggle('v2', false);
-      if (this.screenMode_ == ScreenMode.DEFAULT &&
+      if ((this.screenMode_ == ScreenMode.DEFAULT ||
+           this.screenMode_ == ScreenMode.OFFLINE) &&
           this.chromeOSApiVersion_ == 2) {
         this.classList.toggle('v2', true);
       }
diff --git a/chrome/browser/resources/md_bookmarks/app.html b/chrome/browser/resources/md_bookmarks/app.html
index 9cc1c358..df448d36 100644
--- a/chrome/browser/resources/md_bookmarks/app.html
+++ b/chrome/browser/resources/md_bookmarks/app.html
@@ -5,13 +5,13 @@
 <link rel="import" href="chrome://bookmarks/command_manager.html">
 <link rel="import" href="chrome://bookmarks/constants.html">
 <link rel="import" href="chrome://bookmarks/dnd_manager.html">
+<link rel="import" href="chrome://bookmarks/folder_node.html">
 <link rel="import" href="chrome://bookmarks/list.html">
 <link rel="import" href="chrome://bookmarks/router.html">
 <link rel="import" href="chrome://bookmarks/shared_vars.html">
 <link rel="import" href="chrome://bookmarks/store.html">
 <link rel="import" href="chrome://bookmarks/toast_manager.html">
 <link rel="import" href="chrome://bookmarks/toolbar.html">
-<link rel="import" href="chrome://bookmarks/folder_node.html">
 <link rel="import" href="chrome://bookmarks/util.html">
 
 <dom-module id="bookmarks-app">
diff --git a/chrome/browser/resources/md_bookmarks/command_manager.html b/chrome/browser/resources/md_bookmarks/command_manager.html
index d83d555..49cd2a9c 100644
--- a/chrome/browser/resources/md_bookmarks/command_manager.html
+++ b/chrome/browser/resources/md_bookmarks/command_manager.html
@@ -4,6 +4,7 @@
 <link rel="import" href="chrome://resources/cr_elements/cr_lazy_render/cr_lazy_render.html">
 <link rel="import" href="chrome://resources/html/cr/ui/command.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-a11y-keys-behavior/iron-a11y-keys-behavior.html">
+<link rel="import" href="chrome://bookmarks/dialog_focus_manager.html">
 <link rel="import" href="chrome://bookmarks/edit_dialog.html">
 <link rel="import" href="chrome://bookmarks/shared_style.html">
 <link rel="import" href="chrome://bookmarks/store_client.html">
diff --git a/chrome/browser/resources/md_bookmarks/command_manager.js b/chrome/browser/resources/md_bookmarks/command_manager.js
index 790fb62d..f0b37bf 100644
--- a/chrome/browser/resources/md_bookmarks/command_manager.js
+++ b/chrome/browser/resources/md_bookmarks/command_manager.js
@@ -109,11 +109,15 @@
      */
     openCommandMenuAtPosition: function(x, y, items) {
       this.menuIds_ = items || this.getState().selection.items;
+
       var dropdown =
           /** @type {!CrActionMenuElement} */ (this.$.dropdown.get());
       // Ensure that the menu is fully rendered before trying to position it.
       Polymer.dom.flush();
-      dropdown.showAtPosition({top: y, left: x});
+      bookmarks.DialogFocusManager.getInstance().showDialog(
+          dropdown, function() {
+            dropdown.showAtPosition({top: y, left: x});
+          });
     },
 
     /**
@@ -123,11 +127,15 @@
      */
     openCommandMenuAtElement: function(target) {
       this.menuIds_ = this.getState().selection.items;
+
       var dropdown =
           /** @type {!CrActionMenuElement} */ (this.$.dropdown.get());
       // Ensure that the menu is fully rendered before trying to position it.
       Polymer.dom.flush();
-      dropdown.showAt(target);
+      bookmarks.DialogFocusManager.getInstance().showDialog(
+          dropdown, function() {
+            dropdown.showAt(target);
+          });
     },
 
     closeCommandMenu: function() {
@@ -384,7 +392,9 @@
       var dialog = this.$.openDialog.get();
       dialog.querySelector('.body').textContent =
           loadTimeData.getStringF('openDialogBody', urls.length);
-      dialog.showModal();
+
+      bookmarks.DialogFocusManager.getInstance().showDialog(
+          this.$.openDialog.get());
     },
 
     /**
diff --git a/chrome/browser/resources/md_bookmarks/compiled_resources2.gyp b/chrome/browser/resources/md_bookmarks/compiled_resources2.gyp
index 5c5d2a4..a22067e6 100644
--- a/chrome/browser/resources/md_bookmarks/compiled_resources2.gyp
+++ b/chrome/browser/resources/md_bookmarks/compiled_resources2.gyp
@@ -47,6 +47,7 @@
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
         '<(DEPTH)/ui/webui/resources/js/cr/ui/compiled_resources2.gyp:command',
         '<(EXTERNS_GYP):bookmark_manager_private',
+        'dialog_focus_manager',
         'edit_dialog',
         'store_client',
         'toast_manager'
@@ -58,6 +59,14 @@
       'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi']
     },
     {
+      'target_name': 'dialog_focus_manager',
+      'dependencies': [
+        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
+        'mouse_focus_behavior',
+      ],
+      'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
+    },
+    {
       'target_name': 'dnd_manager',
       'dependencies': [
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
@@ -77,6 +86,7 @@
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
         '<(EXTERNS_GYP):chrome_extensions',
+        'dialog_focus_manager',
         'types',
       ],
       'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi']
diff --git a/chrome/browser/resources/md_bookmarks/dialog_focus_manager.html b/chrome/browser/resources/md_bookmarks/dialog_focus_manager.html
new file mode 100644
index 0000000..9e0ea5a7
--- /dev/null
+++ b/chrome/browser/resources/md_bookmarks/dialog_focus_manager.html
@@ -0,0 +1,3 @@
+<link rel="import" href="chrome://resources/html/cr.html">
+<link rel="import" href="chrome://bookmarks/mouse_focus_behavior.html">
+<script src="chrome://bookmarks/dialog_focus_manager.js"></script>
diff --git a/chrome/browser/resources/md_bookmarks/dialog_focus_manager.js b/chrome/browser/resources/md_bookmarks/dialog_focus_manager.js
new file mode 100644
index 0000000..5b3879d
--- /dev/null
+++ b/chrome/browser/resources/md_bookmarks/dialog_focus_manager.js
@@ -0,0 +1,102 @@
+// 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.
+
+cr.define('bookmarks', function() {
+  /**
+   * Manages focus restoration for modal dialogs. After the final dialog in a
+   * stack is closed, restores focus to the element which was focused when the
+   * first dialog was opened.
+   * @constructor
+   */
+  function DialogFocusManager() {
+    /** @private {HTMLElement} */
+    this.previousFocusElement_ = null;
+
+    /** @private {boolean} */
+    this.previousMouseFocus_ = false;
+
+    /** @private {Set<HTMLDialogElement>} */
+    this.dialogs_ = new Set();
+  }
+
+  DialogFocusManager.prototype = {
+    /**
+     * @param {HTMLDialogElement} dialog
+     * @param {function()=} showFn
+     */
+    showDialog: function(dialog, showFn) {
+      if (!showFn) {
+        showFn = function() {
+          dialog.showModal();
+        };
+      }
+
+      // Update the focus if there are no open dialogs or if this is the only
+      // dialog and it's getting reshown.
+      if (!this.dialogs_.size ||
+          (this.dialogs_.has(dialog) && this.dialogs_.size == 1)) {
+        this.updatePreviousFocus_();
+      }
+
+      if (!this.dialogs_.has(dialog)) {
+        dialog.addEventListener('close', this.getCloseListener_(dialog));
+        this.dialogs_.add(dialog);
+      }
+
+      showFn();
+    },
+
+    /** @private */
+    updatePreviousFocus_: function() {
+      this.previousFocusElement_ = this.getFocusedElement_();
+      this.previousMouseFocus_ = bookmarks.MouseFocusBehavior.isMouseFocused(
+          this.previousFocusElement_);
+    },
+
+    /**
+     * @return {HTMLElement}
+     * @private
+     */
+    getFocusedElement_: function() {
+      var focus = document.activeElement;
+      while (focus.root && focus.root.activeElement)
+        focus = focus.root.activeElement;
+
+      return focus;
+    },
+
+    /**
+     * @param {HTMLDialogElement} dialog
+     * @return {function(Event)}
+     * @private
+     */
+    getCloseListener_: function(dialog) {
+      var closeListener = function(e) {
+        // If the dialog is open, then it got reshown immediately and we
+        // shouldn't clear it until it is closed again.
+        if (dialog.open)
+          return;
+
+        assert(this.dialogs_.delete(dialog));
+        // Focus the originally focused element if there are no more dialogs.
+        if (!this.dialogs_.size) {
+          this.previousFocusElement_.focus();
+          if (this.previousMouseFocus_) {
+            bookmarks.MouseFocusBehavior.addMouseFocusClass(
+                this.previousFocusElement_);
+          }
+        }
+        dialog.removeEventListener('close', closeListener);
+      }.bind(this);
+
+      return closeListener;
+    },
+  };
+
+  cr.addSingletonGetter(DialogFocusManager);
+
+  return {
+    DialogFocusManager: DialogFocusManager,
+  };
+});
diff --git a/chrome/browser/resources/md_bookmarks/edit_dialog.html b/chrome/browser/resources/md_bookmarks/edit_dialog.html
index 416f417..733b76e2 100644
--- a/chrome/browser/resources/md_bookmarks/edit_dialog.html
+++ b/chrome/browser/resources/md_bookmarks/edit_dialog.html
@@ -5,6 +5,7 @@
 <link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-input/paper-input.html">
+<link rel="import" href="chrome://bookmarks/dialog_focus_manager.html">
 
 <dom-module id="bookmarks-edit-dialog">
   <template>
diff --git a/chrome/browser/resources/md_bookmarks/edit_dialog.js b/chrome/browser/resources/md_bookmarks/edit_dialog.js
index 06f916a..582417e7 100644
--- a/chrome/browser/resources/md_bookmarks/edit_dialog.js
+++ b/chrome/browser/resources/md_bookmarks/edit_dialog.js
@@ -43,7 +43,7 @@
     this.isFolder_ = isFolder;
     this.parentId_ = parentId;
 
-    this.$.dialog.showModal();
+    bookmarks.DialogFocusManager.getInstance().showDialog(this.$.dialog);
   },
 
   /**
@@ -60,7 +60,7 @@
     if (!this.isFolder_)
       this.urlValue_ = assert(editItem.url);
 
-    this.$.dialog.showModal();
+    bookmarks.DialogFocusManager.getInstance().showDialog(this.$.dialog);
   },
 
   /**
diff --git a/chrome/browser/resources/md_bookmarks/item.js b/chrome/browser/resources/md_bookmarks/item.js
index 50fa1cd..06b29a68 100644
--- a/chrome/browser/resources/md_bookmarks/item.js
+++ b/chrome/browser/resources/md_bookmarks/item.js
@@ -67,6 +67,7 @@
    */
   onContextMenu_: function(e) {
     e.preventDefault();
+    this.focus();
     if (!this.isSelectedItem_)
       this.selectThisItem_();
 
diff --git a/chrome/browser/resources/md_bookmarks/list.html b/chrome/browser/resources/md_bookmarks/list.html
index 00c8ceaf..94b5b308 100644
--- a/chrome/browser/resources/md_bookmarks/list.html
+++ b/chrome/browser/resources/md_bookmarks/list.html
@@ -29,11 +29,13 @@
       .centered-message {
         align-items: center;
         color: #6e6e6e;
+        cursor: default;
         display: flex;
         font-size: 14px;
         font-weight: 500;
         height: 100%;
         justify-content: center;
+        user-select: none;
       }
     </style>
     <iron-list items="[[displayedList_]]" id="bookmarksCard"
diff --git a/chrome/browser/resources/md_bookmarks/mouse_focus_behavior.js b/chrome/browser/resources/md_bookmarks/mouse_focus_behavior.js
index 2aec0e9..ce62e2a 100644
--- a/chrome/browser/resources/md_bookmarks/mouse_focus_behavior.js
+++ b/chrome/browser/resources/md_bookmarks/mouse_focus_behavior.js
@@ -3,6 +3,9 @@
 // found in the LICENSE file.
 
 cr.define('bookmarks', function() {
+  /** @const */
+  var MOUSE_FOCUS_CLASS = 'mouse-focus';
+
   /**
    * Behavior which adds the 'mouse-focus' class to a target element when it
    * gains focus from the mouse, allowing the outline to be hidden without
@@ -16,12 +19,14 @@
 
       var target = this.getFocusTarget();
       target.addEventListener('mousedown', this.boundOnMousedown_);
+      target.addEventListener('contextmenu', this.boundOnMousedown_);
       target.addEventListener('blur', this.boundClearMouseFocus_);
     },
 
     detached: function() {
       var target = this.getFocusTarget();
       target.removeEventListener('mousedown', this.boundOnMousedown_);
+      target.removeEventListener('contextmenu', this.boundOnMousedown_);
       target.removeEventListener('blur', this.boundClearMouseFocus_);
     },
 
@@ -37,12 +42,25 @@
 
     /** Reset the focus state when focus leaves the target element. */
     clearMouseFocus: function() {
-      this.getFocusTarget().classList.remove('mouse-focus');
+      this.getFocusTarget().classList.remove(MOUSE_FOCUS_CLASS);
     },
 
     /** @private */
     onMousedown_: function() {
-      this.getFocusTarget().classList.add('mouse-focus');
+      this.addMouseFocusClass(this.getFocusTarget());
+    },
+
+    /**
+     * @param {HTMLElement} element
+     * @return {boolean}
+     */
+    isMouseFocused: function(element) {
+      return element.classList.contains(MOUSE_FOCUS_CLASS);
+    },
+
+    /** @param {HTMLElement} element */
+    addMouseFocusClass: function(element) {
+      element.classList.add(MOUSE_FOCUS_CLASS);
     },
   };
 
diff --git a/chrome/browser/resources/md_history/history_item.html b/chrome/browser/resources/md_history/history_item.html
index 8bbdbda..982ab92b 100644
--- a/chrome/browser/resources/md_history/history_item.html
+++ b/chrome/browser/resources/md_history/history_item.html
@@ -217,7 +217,7 @@
             aria-label$="[[getEntrySummary_(item)]]">
           <div id="checkmark"></div>
         </button>
-        <span id="time-accessed" on-mouseover="addTimeTitle_">
+        <span id="time-accessed">
           [[item.readableTimestamp]]
         </span>
         <div class="website-icon" id="icon"></div>
diff --git a/chrome/browser/resources/md_history/history_item.js b/chrome/browser/resources/md_history/history_item.js
index 646493b..36692e88 100644
--- a/chrome/browser/resources/md_history/history_item.js
+++ b/chrome/browser/resources/md_history/history_item.js
@@ -86,7 +86,7 @@
       // from the history backend, as well as fields computed by history-list.
       item: {
         type: Object,
-        observer: 'showIcon_',
+        observer: 'itemChanged_',
       },
 
       selected: {
@@ -133,6 +133,9 @@
     /** @private {?HistoryFocusRow} */
     row_: null,
 
+    /** @private {boolean} */
+    mouseDown_: false,
+
     /** @override */
     attached: function() {
       Polymer.RenderStatus.afterNextRender(this, function() {
@@ -156,6 +159,12 @@
      * @private
      */
     onFocus_: function() {
+      // Don't change the focus while the mouse is down, as it prevents text
+      // selection. Not changing focus here is acceptable because the checkbox
+      // will be focused in onItemClick_() anyway.
+      if (this.mouseDown_)
+        return;
+
       if (this.lastFocused)
         this.row_.getEquivalentElement(this.lastFocused).focus();
       else
@@ -210,6 +219,10 @@
      * @private
      */
     onItemMousedown_: function(e) {
+      this.mouseDown_ = true;
+      listenOnce(document, 'mouseup', function() {
+        this.mouseDown_ = false;
+      }.bind(this));
       // Prevent shift clicking a checkbox from selecting text.
       if (e.shiftKey)
         e.preventDefault();
@@ -303,8 +316,9 @@
      * Set the favicon image, based on the URL of the history item.
      * @private
      */
-    showIcon_: function() {
+    itemChanged_: function() {
       this.$.icon.style.backgroundImage = cr.icon.getFavicon(this.item.url);
+      this.listen(this.$['time-accessed'], 'mouseover', 'addTimeTitle_');
     },
 
     /**
diff --git a/chrome/browser/resources/md_history/history_list.js b/chrome/browser/resources/md_history/history_list.js
index d850ad6..09ac844 100644
--- a/chrome/browser/resources/md_history/history_list.js
+++ b/chrome/browser/resources/md_history/history_list.js
@@ -112,6 +112,7 @@
       if (this.historyData_)
         this.splice('historyData_', 0, this.historyData_.length);
       this.fire('unselect-all');
+      this.scrollTop = 0;
     }
 
     if (this.historyData_) {
diff --git a/chrome/browser/resources/net_internals/log_util.js b/chrome/browser/resources/net_internals/log_util.js
index 623bc27..f690352a 100644
--- a/chrome/browser/resources/net_internals/log_util.js
+++ b/chrome/browser/resources/net_internals/log_util.js
@@ -166,20 +166,29 @@
       }
     }
 
-    // Make sure the loaded log contained an export date. If not we will
-    // synthesize one. This can legitimately happen for dump files created
-    // via command line flag, or for older dump formats (before Chrome 17).
+    // Determine the export date for the loaded log.
+    //
+    // Dumps created from chrome://net-internals (Chrome 17 - Chrome 59) will
+    // have this set in constants.clientInfo.numericDate.
+    //
+    // However more recent dumping mechanisms (chrome://net-export/ and
+    // --log-net-log) write the constants object directly to a file when the
+    // dump is *started* so lack this ability.
+    //
+    // In this case, we will synthesize this field by looking at the timestamp
+    // of the last event logged. In practice this works fine since there tend
+    // to be lots of events logged.
+    //
+    // TODO(eroman): Fix the log format / writers to avoid this problem. Dumps
+    // *should* contain the time when capturing started, and when capturing
+    // ended.
     if (typeof logDump.constants.clientInfo.numericDate != 'number') {
-      errorString += 'The log file is missing clientInfo.numericDate.\n';
-
       if (validEvents.length > 0) {
-        errorString +=
-            'Synthesizing export date as time of last event captured.\n';
         var lastEvent = validEvents[validEvents.length - 1];
         ClientInfo.numericDate =
             timeutil.convertTimeTicksToDate(lastEvent.time).getTime();
       } else {
-        errorString += 'Can\'t guess export date!\n';
+        errorString += 'Can\'t guess export date as there are no events.\n';
         ClientInfo.numericDate = 0;
       }
     }
diff --git a/chrome/browser/resources/settings/appearance_page/compiled_resources2.gyp b/chrome/browser/resources/settings/appearance_page/compiled_resources2.gyp
index 67937b8..f69539b2 100644
--- a/chrome/browser/resources/settings/appearance_page/compiled_resources2.gyp
+++ b/chrome/browser/resources/settings/appearance_page/compiled_resources2.gyp
@@ -38,7 +38,7 @@
         '../compiled_resources2.gyp:route',
         '../controls/compiled_resources2.gyp:settings_dropdown_menu',
         '../settings_page/compiled_resources2.gyp:settings_animated_pages',
-        '../settings_ui/compiled_resources2.gyp:settings_ui_types',
+        '../compiled_resources2.gyp:page_visibility',
         'appearance_browser_proxy',
       ],
       'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
diff --git a/chrome/browser/resources/settings/basic_page/compiled_resources2.gyp b/chrome/browser/resources/settings/basic_page/compiled_resources2.gyp
index ac834cf..4af3263 100644
--- a/chrome/browser/resources/settings/basic_page/compiled_resources2.gyp
+++ b/chrome/browser/resources/settings/basic_page/compiled_resources2.gyp
@@ -13,7 +13,7 @@
         '../compiled_resources2.gyp:route',
         '../compiled_resources2.gyp:search_settings',
         '../settings_page/compiled_resources2.gyp:main_page_behavior',
-        '../settings_ui/compiled_resources2.gyp:settings_ui_types',
+        '../compiled_resources2.gyp:page_visibility',
       ],
       'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
     },
diff --git a/chrome/browser/resources/settings/compiled_resources2.gyp b/chrome/browser/resources/settings/compiled_resources2.gyp
index 6ed6b39c..836fde5 100644
--- a/chrome/browser/resources/settings/compiled_resources2.gyp
+++ b/chrome/browser/resources/settings/compiled_resources2.gyp
@@ -53,6 +53,14 @@
       'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
     },
     {
+      'target_name': 'page_visibility',
+      'dependencies': [
+        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
+        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
+      ],
+      'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
+    },
+    {
       'target_name': 'search_settings',
       'dependencies': [
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
diff --git a/chrome/browser/resources/settings/downloads_page/compiled_resources2.gyp b/chrome/browser/resources/settings/downloads_page/compiled_resources2.gyp
index 00906d3d..038adcc 100644
--- a/chrome/browser/resources/settings/downloads_page/compiled_resources2.gyp
+++ b/chrome/browser/resources/settings/downloads_page/compiled_resources2.gyp
@@ -18,7 +18,7 @@
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:util',
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:web_ui_listener_behavior',
-        '../settings_ui/compiled_resources2.gyp:settings_ui_types',
+        '../compiled_resources2.gyp:page_visibility',
         'downloads_browser_proxy',
       ],
       'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
diff --git a/chrome/browser/resources/settings/internet_page/internet_subpage.html b/chrome/browser/resources/settings/internet_page/internet_subpage.html
index 8fc5909..96568202 100644
--- a/chrome/browser/resources/settings/internet_page/internet_subpage.html
+++ b/chrome/browser/resources/settings/internet_page/internet_subpage.html
@@ -17,7 +17,7 @@
             var(--cr-icon-ripple-padding));
         -webkit-padding-start: var(--settings-box-row-padding);
         margin-top: var(--settings-page-vertical-margin);
-        min-height: var(--settings-box-min-height);
+        min-height: var(--settings-row-min-height);
      }
 
       #addButton {
diff --git a/chrome/browser/resources/settings/page_visibility.html b/chrome/browser/resources/settings/page_visibility.html
new file mode 100644
index 0000000..8ea50773
--- /dev/null
+++ b/chrome/browser/resources/settings/page_visibility.html
@@ -0,0 +1,3 @@
+<link rel="import" href="chrome://resources/html/cr.html">
+
+<script src="page_visibility.js"></script>
diff --git a/chrome/browser/resources/settings/page_visibility.js b/chrome/browser/resources/settings/page_visibility.js
new file mode 100644
index 0000000..0349d6c
--- /dev/null
+++ b/chrome/browser/resources/settings/page_visibility.js
@@ -0,0 +1,105 @@
+// 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.
+
+/**
+ * Specifies page visibility in guest mode in cr and cros.
+ * @typedef {{
+ *   advancedSettings: (boolean|undefined),
+ *   appearance: (boolean|undefined|AppearancePageVisibility),
+ *   dateTime: (boolean|undefined|DateTimePageVisibility),
+ *   defaultBrowser: (boolean|undefined),
+ *   downloads: (undefined|DownloadsPageVisibility),
+ *   onStartup: (boolean|undefined),
+ *   passwordsAndForms: (boolean|undefined),
+ *   people: (boolean|undefined),
+ *   privacy: (undefined|PrivacyPageVisibility),
+ *   reset:(boolean|undefined),
+ * }}
+ */
+var GuestModePageVisibility;
+
+/**
+ * @typedef {{
+ *   bookmarksBar: boolean,
+ *   homeButton: boolean,
+ *   pageZoom: boolean,
+ *   setTheme: boolean,
+ *   setWallpaper: boolean,
+ * }}
+ */
+var AppearancePageVisibility;
+
+/**
+ * @typedef {{
+ *   timeZoneSelector: boolean,
+ * }}
+ */
+var DateTimePageVisibility;
+
+/**
+ * @typedef {{
+ *   googleDrive: boolean
+ * }}
+ */
+var DownloadsPageVisibility;
+
+/**
+ * @typedef {{
+ *   networkPrediction: boolean,
+ *   searchPrediction: boolean,
+ * }}
+ */
+var PrivacyPageVisibility;
+
+cr.define('settings', function() {
+
+  /**
+   * Dictionary defining page visibility.
+   * This is only set when in guest mode. All pages are visible when not set
+   * because polymer only notifies after a property is set.
+   * @type {!GuestModePageVisibility}
+   */
+  var pageVisibility = {};
+
+  if (loadTimeData.getBoolean('isGuest')) {
+    // "if not chromeos" and "if chromeos" in two completely separate blocks
+    // to work around closure compiler.
+    // <if expr="not chromeos">
+    pageVisibility = {
+      passwordsAndForms: false,
+      people: false,
+      onStartup: false,
+      reset: false,
+      appearance: false,
+      defaultBrowser: false,
+      advancedSettings: false,
+    };
+    // </if>
+    // <if expr="chromeos">
+    pageVisibility = {
+      passwordsAndForms: false,
+      people: false,
+      onStartup: false,
+      reset: false,
+      appearance: {
+        setWallpaper: false,
+        setTheme: false,
+        homeButton: false,
+        bookmarksBar: false,
+        pageZoom: false,
+      },
+      advancedSettings: true,
+      privacy: {
+        searchPrediction: false,
+        networkPrediction: false,
+      },
+      downloads: {
+        googleDrive: false,
+      },
+    };
+    // </if>
+  }
+
+  return {pageVisibility: pageVisibility};
+});
diff --git a/chrome/browser/resources/settings/privacy_page/compiled_resources2.gyp b/chrome/browser/resources/settings/privacy_page/compiled_resources2.gyp
index e99c32e..073f1291 100644
--- a/chrome/browser/resources/settings/privacy_page/compiled_resources2.gyp
+++ b/chrome/browser/resources/settings/privacy_page/compiled_resources2.gyp
@@ -22,7 +22,7 @@
         '../compiled_resources2.gyp:route',
         '../controls/compiled_resources2.gyp:settings_toggle_button',
         '../settings_page/compiled_resources2.gyp:settings_animated_pages',
-        '../settings_ui/compiled_resources2.gyp:settings_ui_types',
+        '../compiled_resources2.gyp:page_visibility',
         '../site_settings/compiled_resources2.gyp:constants',
         '../site_settings/compiled_resources2.gyp:site_data_details_subpage',
         'privacy_page_browser_proxy',
diff --git a/chrome/browser/resources/settings/search_page/search_page.html b/chrome/browser/resources/settings/search_page/search_page.html
index 41f7b1b..0aed8e79 100644
--- a/chrome/browser/resources/settings/search_page/search_page.html
+++ b/chrome/browser/resources/settings/search_page/search_page.html
@@ -24,7 +24,7 @@
       #search-wrapper {
         align-items: center;
         display: flex;
-        min-height: var(--settings-box-min-height);
+        min-height: var(--settings-row-min-height);
       }
 
       iron-icon {
diff --git a/chrome/browser/resources/settings/settings_main/compiled_resources2.gyp b/chrome/browser/resources/settings/settings_main/compiled_resources2.gyp
index 5a1c740..1e1d0fa7 100644
--- a/chrome/browser/resources/settings/settings_main/compiled_resources2.gyp
+++ b/chrome/browser/resources/settings/settings_main/compiled_resources2.gyp
@@ -14,7 +14,7 @@
         '../about_page/compiled_resources2.gyp:about_page',
         '../basic_page/compiled_resources2.gyp:basic_page',
         '../settings_page/compiled_resources2.gyp:main_page_behavior',
-        '../settings_ui/compiled_resources2.gyp:settings_ui_types',
+        '../compiled_resources2.gyp:page_visibility',
       ],
       'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
     },
diff --git a/chrome/browser/resources/settings/settings_menu/compiled_resources2.gyp b/chrome/browser/resources/settings/settings_menu/compiled_resources2.gyp
index 9a390d60..305541d 100644
--- a/chrome/browser/resources/settings/settings_menu/compiled_resources2.gyp
+++ b/chrome/browser/resources/settings/settings_menu/compiled_resources2.gyp
@@ -8,7 +8,7 @@
       'dependencies': [
         '<(DEPTH)/third_party/polymer/v1_0/components-chromium/paper-ripple/compiled_resources2.gyp:paper-ripple-extracted',
         '../compiled_resources2.gyp:route',
-        '../settings_ui/compiled_resources2.gyp:settings_ui_types',
+        '../compiled_resources2.gyp:page_visibility',
       ],
       'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
     },
diff --git a/chrome/browser/resources/settings/settings_resources.grd b/chrome/browser/resources/settings/settings_resources.grd
index a8f79bf..5dd11199 100644
--- a/chrome/browser/resources/settings/settings_resources.grd
+++ b/chrome/browser/resources/settings/settings_resources.grd
@@ -861,6 +861,13 @@
       <structure name="IDR_SETTINGS_CLOUD_PRINTING_PAGE_JS"
                  file="printing_page/cloud_printers.js"
                  type="chrome_html" />
+      <structure name="IDR_SETTINGS_PAGE_VISIBILITY_HTML"
+                 file="page_visibility.html"
+                 type="chrome_html" />
+      <structure name="IDR_SETTINGS_PAGE_VISIBILITY_JS"
+                 file="page_visibility.js"
+                 type="chrome_html"
+                 preprocess="true" />
       <structure name="IDR_SETTINGS_PDF_DOCUMENTS_HTML"
                  file="site_settings/pdf_documents.html"
                  type="chrome_html" />
diff --git a/chrome/browser/resources/settings/settings_shared_css.html b/chrome/browser/resources/settings/settings_shared_css.html
index 395a62c..1cc949ea 100644
--- a/chrome/browser/resources/settings/settings_shared_css.html
+++ b/chrome/browser/resources/settings/settings_shared_css.html
@@ -240,16 +240,16 @@
         align-items: center;
         border-top: var(--settings-separator-line);
         display: flex;
-        min-height: var(--settings-box-min-height);
+        min-height: var(--settings-row-min-height);
         padding: 0 var(--settings-box-row-padding);
       }
 
       .settings-box.two-line {
-        min-height: var(--settings-box-two-line-min-height);
+        min-height: var(--settings-row-two-line-min-height);
       }
 
       .settings-box.three-line {
-        min-height: var(--settings-box-three-line-min-height);
+        min-height: var(--settings-row-three-line-min-height);
       }
 
       /* We use an explicit tag to remove the top border, rather than a
diff --git a/chrome/browser/resources/settings/settings_ui/compiled_resources2.gyp b/chrome/browser/resources/settings/settings_ui/compiled_resources2.gyp
index 01b520ca..4000384e 100644
--- a/chrome/browser/resources/settings/settings_ui/compiled_resources2.gyp
+++ b/chrome/browser/resources/settings/settings_ui/compiled_resources2.gyp
@@ -15,13 +15,9 @@
         '../compiled_resources2.gyp:global_scroll_target_behavior',
         '../prefs/compiled_resources2.gyp:prefs',
         '../settings_main/compiled_resources2.gyp:settings_main',
-        'settings_ui_types',
+        '../compiled_resources2.gyp:page_visibility'
       ],
       'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
     },
-    {
-      'target_name': 'settings_ui_types',
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
   ],
 }
diff --git a/chrome/browser/resources/settings/settings_ui/settings_ui.html b/chrome/browser/resources/settings/settings_ui/settings_ui.html
index 05d56eb6..2163b1e4 100644
--- a/chrome/browser/resources/settings/settings_ui/settings_ui.html
+++ b/chrome/browser/resources/settings/settings_ui/settings_ui.html
@@ -11,6 +11,7 @@
 <link rel="import" href="../settings_main/settings_main.html">
 <link rel="import" href="../settings_menu/settings_menu.html">
 <link rel="import" href="../settings_shared_css.html">
+<link rel="import" href="../page_visibility.html">
 <link rel="import" href="../prefs/prefs.html">
 <link rel="import" href="../route.html">
 <link rel="import" href="../settings_vars_css.html">
diff --git a/chrome/browser/resources/settings/settings_ui/settings_ui.js b/chrome/browser/resources/settings/settings_ui/settings_ui.js
index 66db2641..76f5b4dc 100644
--- a/chrome/browser/resources/settings/settings_ui/settings_ui.js
+++ b/chrome/browser/resources/settings/settings_ui/settings_ui.js
@@ -49,12 +49,9 @@
     },
 
     /**
-     * Dictionary defining page visibility.
-     * This is only set when in guest mode. All pages are visible when not set
-     * because polymer only notifies after a property is set.
      * @private {!GuestModePageVisibility}
      */
-    pageVisibility_: Object,
+    pageVisibility_: {type: Object, value: settings.pageVisibility},
 
     /** @private */
     showAndroidApps_: Boolean,
@@ -129,37 +126,6 @@
     };
     // </if>
 
-    if (loadTimeData.getBoolean('isGuest')) {
-      this.pageVisibility_ = {
-        passwordsAndForms: false,
-        people: false,
-        onStartup: false,
-        reset: false,
-        // <if expr="not chromeos">
-        appearance: false,
-        defaultBrowser: false,
-        advancedSettings: false,
-        // </if>
-        // <if expr="chromeos">
-        appearance: {
-          setWallpaper: false,
-          setTheme: false,
-          homeButton: false,
-          bookmarksBar: false,
-          pageZoom: false,
-        },
-        advancedSettings: true,
-        privacy: {
-          searchPrediction: false,
-          networkPrediction: false,
-        },
-        downloads: {
-          googleDrive: false,
-        },
-        // </if>
-      };
-    }
-
     this.showAndroidApps_ = loadTimeData.valueExists('androidAppsVisible') &&
         loadTimeData.getBoolean('androidAppsVisible');
     this.havePlayStoreApp_ = loadTimeData.valueExists('havePlayStoreApp') &&
diff --git a/chrome/browser/resources/settings/settings_ui/settings_ui_types.js b/chrome/browser/resources/settings/settings_ui/settings_ui_types.js
deleted file mode 100644
index 4727c62..0000000
--- a/chrome/browser/resources/settings/settings_ui/settings_ui_types.js
+++ /dev/null
@@ -1,60 +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.
-
-/**
- * @fileoverview Closure typedefs for settings_ui.
- */
-
-/**
- * Specifies page visibility in guest mode in cr and cros.
- * @typedef {{
- *   advancedSettings: (boolean|undefined),
- *   appearance: (boolean|undefined|AppearancePageVisibility),
- *   dateTime: (boolean|undefined|DateTimePageVisibility),
- *   defaultBrowser: (boolean|undefined),
- *   downloads: (undefined|DownloadsPageVisibility),
- *   onStartup: (boolean|undefined),
- *   passwordsAndForms: (boolean|undefined),
- *   people: (boolean|undefined),
- *   privacy: (undefined|PrivacyPageVisibility),
- *   reset:(boolean|undefined),
- * }}
- */
-var GuestModePageVisibility;
-
-/**
- * @typedef {{
- *   bookmarksBar: boolean,
- *   homeButton: boolean,
- *   pageZoom: boolean,
- *   setTheme: boolean,
- *   setWallpaper: boolean,
- * }}
- */
-var AppearancePageVisibility;
-
-/**
- * @typedef {{
- *   timeZoneSelector: boolean,
- * }}
- */
-var DateTimePageVisibility;
-
-/**
- * @typedef {{
- *   googleDrive: boolean
- * }}
- */
-var DownloadsPageVisibility;
-
-/**
- * @typedef {{
- *   networkPrediction: boolean,
- *   searchPrediction: boolean,
- * }}
- */
-var PrivacyPageVisibility;
-
-// TODO(mahmadi): Dummy code for closure compiler to process this file.
-(function foo() {})();
diff --git a/chrome/browser/resources/settings/settings_vars_css.html b/chrome/browser/resources/settings/settings_vars_css.html
index c93cc87..4bd940c 100644
--- a/chrome/browser/resources/settings/settings_vars_css.html
+++ b/chrome/browser/resources/settings/settings_vars_css.html
@@ -39,13 +39,7 @@
      * items etc. */
     --settings-row-min-height: 48px;
     --settings-row-two-line-min-height: 64px;
-
-    /* TODO (scottchen): re-implement with paddings instead; */
-    /* These are used for the settings-box containers, which may contain one or
-     * more "row items". */
-    --settings-box-min-height: 48px;
-    --settings-box-two-line-min-height: 64px;
-    --settings-box-three-line-min-height: 84px;
+    --settings-row-three-line-min-height: 84px;
 
     --settings-text-elide: {
       overflow: hidden;
diff --git a/chrome/browser/resources/settings/site_settings/site_details.html b/chrome/browser/resources/settings/site_settings/site_details.html
index 540c4bd..e5561de 100644
--- a/chrome/browser/resources/settings/site_settings/site_details.html
+++ b/chrome/browser/resources/settings/site_settings/site_details.html
@@ -39,9 +39,10 @@
 
     <div class="settings-box first">
       <div class="favicon-image"
-          style$="[[computeSiteIcon(site.origin)]]">
+          style$="[[computeSiteIcon(origin)]]">
       </div>
-      <div class="middle">[[site.displayName]]</div>
+      <!-- TODO(patricialor): This should show the origin's display name. -->
+      <div class="middle">[[origin]]</div>
     </div>
     <template is="dom-if" if="[[storedData_]]">
       <div id="usage">
@@ -63,55 +64,52 @@
     </div>
     <div class="list-frame">
       <site-details-permission category="{{ContentSettingsTypes.COOKIES}}"
-          icon="settings:cookie" id="cookies" label="$i18n{siteSettingsCookies}"
-          site="[[site]]">
+          icon="settings:cookie" id="cookies"
+          label="$i18n{siteSettingsCookies}">
       </site-details-permission>
       <site-details-permission category="{{ContentSettingsTypes.GEOLOCATION}}"
           icon="settings:location-on" id="geolocation"
-          label="$i18n{siteSettingsLocation}" site="[[site]]">
+          label="$i18n{siteSettingsLocation}">
       </site-details-permission>
       <site-details-permission category="{{ContentSettingsTypes.CAMERA}}"
           icon="settings:videocam" id="camera"
-          label="$i18n{siteSettingsCamera}" site="[[site]]">
+          label="$i18n{siteSettingsCamera}">
       </site-details-permission>
       <site-details-permission category="{{ContentSettingsTypes.MIC}}"
           icon="settings:mic" id="mic"
-          label="$i18n{siteSettingsMic}" site="[[site]]">
+          label="$i18n{siteSettingsMic}">
       </site-details-permission>
       <site-details-permission category="{{ContentSettingsTypes.NOTIFICATIONS}}"
           icon="settings:notifications" id="notifications"
-          label="$i18n{siteSettingsNotifications}" site="[[site]]">
+          label="$i18n{siteSettingsNotifications}">
       </site-details-permission>
       <site-details-permission category="{{ContentSettingsTypes.JAVASCRIPT}}"
           icon="settings:code" id="javascript"
-          label="$i18n{siteSettingsJavascript}" site="[[site]]">
+          label="$i18n{siteSettingsJavascript}">
       </site-details-permission>
       <site-details-permission category="{{ContentSettingsTypes.PLUGINS}}"
-          icon="cr:extension" id="plugins" label="$i18n{siteSettingsFlash}"
-          site="[[site]]">
+          icon="cr:extension" id="plugins" label="$i18n{siteSettingsFlash}">
       </site-details-permission>
       <site-details-permission category="{{ContentSettingsTypes.IMAGES}}"
-          icon="settings:photo" id="images" label="$i18n{siteSettingsImages}"
-          site="[[site]]">
+          icon="settings:photo" id="images" label="$i18n{siteSettingsImages}">
       </site-details-permission>
       <site-details-permission category="{{ContentSettingsTypes.POPUPS}}"
-          icon="cr:open-in-new" id="popups" label="$i18n{siteSettingsPopups}"
-          site="[[site]]">
+          icon="cr:open-in-new" id="popups" label="$i18n{siteSettingsPopups}">
       </site-details-permission>
       <site-details-permission
           category="{{ContentSettingsTypes.BACKGROUND_SYNC}}"
           icon="settings:sync" id="backgroundSync"
-          label="$i18n{siteSettingsBackgroundSync}" site="[[site]]">
+          label="$i18n{siteSettingsBackgroundSync}">
       </site-details-permission>
       <site-details-permission
           category="{{ContentSettingsTypes.AUTOMATIC_DOWNLOADS}}"
           icon="cr:file-download" id="automaticDownloads"
-          label="$i18n{siteSettingsAutomaticDownloads}" site="[[site]]">
+          label="$i18n{siteSettingsAutomaticDownloads}">
       </site-details-permission>
       <site-details-permission
           category="{{ContentSettingsTypes.UNSANDBOXED_PLUGINS}}"
           icon="cr:extension" id="unsandboxedPlugins"
-          label="$i18n{siteSettingsUnsandboxedPlugins}" site="[[site]]">
+          label="$i18n{siteSettingsUnsandboxedPlugins}">
       </site-details-permission>
 
       <div class="list-item">
diff --git a/chrome/browser/resources/settings/site_settings/site_details.js b/chrome/browser/resources/settings/site_settings/site_details.js
index c75cfa7..4deaf1e 100644
--- a/chrome/browser/resources/settings/site_settings/site_details.js
+++ b/chrome/browser/resources/settings/site_settings/site_details.js
@@ -14,12 +14,12 @@
 
   properties: {
     /**
-     * The site that this widget is showing details for.
-     * @type {SiteException}
+     * The origin that this widget is showing details for.
+     * @private
      */
-    site: {
-      type: Object,
-      observer: 'onSiteChanged_',
+    origin: {
+      type: String,
+      observer: 'onOriginChanged_',
     },
 
     /**
@@ -59,21 +59,36 @@
     var site = settings.getQueryParameters().get('site');
     if (!site)
       return;
-    this.browserProxy.getSiteDetails(site).then(function(siteInfo) {
-      this.site = this.expandSiteException(siteInfo);
-    }.bind(this));
+    this.origin = site;
   },
 
   /**
    * Handler for when the origin changes.
    * @private
    */
-  onSiteChanged_: function() {
-    // origin may be initially undefined if the user follows a direct
-    // link (URL) to this page.
-    var origin = this.site.origin;
-    if (origin !== undefined)
-      this.$.usageApi.fetchUsageTotal(this.toUrl(origin).hostname);
+  onOriginChanged_: function() {
+    this.$.usageApi.fetchUsageTotal(this.toUrl(this.origin).hostname);
+
+    var siteDetailsPermissions =
+        /** @type{!NodeList<!SiteDetailsPermissionElement>} */
+        (this.root.querySelectorAll('site-details-permission'));
+    var categoryList =
+        /** @type{!Array<!string>} */ (
+            Array.prototype.map.call(siteDetailsPermissions, function(element) {
+              return element.category;
+            }));
+
+    this.browserProxy.getOriginPermissions(this.origin, categoryList)
+        .then(function(exceptionList) {
+          exceptionList.forEach(function(exception, i) {
+            // |exceptionList| should be in the same order as |categoryList|,
+            // which is in the same order as |siteDetailsPermissions|.
+            var element = /** @type{!SiteDetailsPermissionElement} */ (
+                siteDetailsPermissions[i]);
+            element.site = /** @type{!SiteException} */ (
+                element.expandSiteException(exception));
+          });
+        });
   },
 
   /** @private */
@@ -89,8 +104,7 @@
   onConfirmClearStorage_: function(e) {
     e.preventDefault();
     this.confirmationDeleteMsg_ = loadTimeData.getStringF(
-        'siteSettingsSiteRemoveConfirmation',
-        this.toUrl(this.site.origin).href);
+        'siteSettingsSiteRemoveConfirmation', this.toUrl(this.origin).href);
     this.$.confirmDeleteDialog.showModal();
   },
 
@@ -99,8 +113,7 @@
    * @private
    */
   onClearStorage_: function() {
-    this.$.usageApi.clearUsage(
-        this.toUrl(this.site.origin).href, this.storageType_);
+    this.$.usageApi.clearUsage(this.toUrl(this.origin).href, this.storageType_);
   },
 
   /**
@@ -109,7 +122,7 @@
    * @private
    */
   onUsageDeleted_: function(event) {
-    if (event.detail.origin == this.toUrl(this.site.origin).href) {
+    if (event.detail.origin == this.toUrl(this.origin).href) {
       this.storedData_ = '';
       this.navigateBackIfNoData_();
     }
@@ -120,9 +133,8 @@
    * @private
    */
   onClearAndReset_: function() {
-    Array.prototype.forEach.call(
-        this.root.querySelectorAll('site-details-permission'),
-        function(element) {
+    this.root.querySelectorAll('site-details-permission')
+        .forEach(function(element) {
           element.resetPermission();
         });
 
diff --git a/chrome/browser/resources/settings/site_settings/site_details_permission.js b/chrome/browser/resources/settings/site_settings/site_details_permission.js
index 17ca6c0..2d799f5 100644
--- a/chrome/browser/resources/settings/site_settings/site_details_permission.js
+++ b/chrome/browser/resources/settings/site_settings/site_details_permission.js
@@ -48,22 +48,12 @@
   },
 
   /**
-   * Sets the site to display.
+   * Updates the drop-down value after |site| has changed.
    * @param {!SiteException} site The site to display.
    * @private
    */
   siteChanged_: function(site) {
-
-    this.browserProxy.getExceptionList(this.category)
-        .then(function(exceptionList) {
-          for (var i = 0; i < exceptionList.length; ++i) {
-            if (exceptionList[i].embeddingOrigin == site.embeddingOrigin &&
-                this.sameOrigin_(exceptionList[i].origin, site.origin)) {
-              this.$.permission.value = exceptionList[i].setting;
-              break;
-            }
-          }
-        }.bind(this));
+    this.$.permission.value = site.setting;
   },
 
   /**
diff --git a/chrome/browser/resources/settings/site_settings/site_settings_prefs_browser_proxy.js b/chrome/browser/resources/settings/site_settings/site_settings_prefs_browser_proxy.js
index acd83ba..a72a963 100644
--- a/chrome/browser/resources/settings/site_settings/site_settings_prefs_browser_proxy.js
+++ b/chrome/browser/resources/settings/site_settings/site_settings_prefs_browser_proxy.js
@@ -19,7 +19,7 @@
 };
 
 /**
- * The site exception information passed form the C++ handler.
+ * The site exception information passed from the C++ handler.
  * See also: SiteException.
  * @typedef {{embeddingOrigin: string,
  *            incognito: boolean,
@@ -126,13 +126,6 @@
     getExceptionList(contentType) {}
 
     /**
-     * Gets the exception details for a particular site.
-     * @param {string} site The name of the site.
-     * @return {!Promise<!RawSiteException>}
-     */
-    getSiteDetails(site) {}
-
-    /**
      * Resets the category permission for a given origin (expressed as primary
      *    and secondary patterns).
      * @param {string} primaryPattern The origin to change (primary pattern).
@@ -146,6 +139,17 @@
         primaryPattern, secondaryPattern, contentType, incognito) {}
 
     /**
+     * Gets a list of category permissions for a given origin. Note that this
+     * may be different to the results retrieved by getExceptionList(), since it
+     * combines different sources of data to get a permission's value.
+     * @param {string} origin The origin to look up permissions for.
+     * @param {!Array<string>} contentTypes A list of categories to retrieve
+     *     the ContentSetting for.
+     * @return {!Promise<!NodeList<!RawSiteException>>}
+     */
+    getOriginPermissions(origin, contentTypes) {}
+
+    /**
      * Sets the category permission for a given origin (expressed as primary
      *    and secondary patterns).
      * @param {string} primaryPattern The origin to change (primary pattern).
@@ -308,11 +312,6 @@
     }
 
     /** @override */
-    getSiteDetails(site) {
-      return cr.sendWithPromise('getSiteDetails', site);
-    }
-
-    /** @override */
     resetCategoryPermissionForOrigin(
         primaryPattern, secondaryPattern, contentType, incognito) {
       chrome.send(
@@ -321,6 +320,11 @@
     }
 
     /** @override */
+    getOriginPermissions(origin, contentTypes) {
+      return cr.sendWithPromise('getOriginPermissions', origin, contentTypes);
+    }
+
+    /** @override */
     setCategoryPermissionForOrigin(
         primaryPattern, secondaryPattern, contentType, value, incognito) {
       // TODO(dschuyler): It may be incorrect for JS to send the embeddingOrigin
diff --git a/chrome/browser/resources_util.cc b/chrome/browser/resources_util.cc
index 7dd7f4b..d74bc7f 100644
--- a/chrome/browser/resources_util.cc
+++ b/chrome/browser/resources_util.cc
@@ -8,7 +8,7 @@
 
 #include <utility>
 
-#include "base/containers/hash_tables.h"
+#include "base/containers/flat_map.h"
 #include "base/lazy_instance.h"
 #include "build/build_config.h"
 #include "chrome/grit/theme_resources_map.h"
@@ -21,30 +21,39 @@
 
 namespace {
 
-// A wrapper class that holds a hash_map between resource strings and resource
+// A wrapper class that holds a map between resource strings and resource
 // ids.  This is done so we can use base::LazyInstance which takes care of
-// thread safety in initializing the hash_map for us.
+// thread safety in initializing the map for us.
 class ThemeMap {
  public:
-  typedef base::hash_map<std::string, int> StringIntMap;
+  typedef base::flat_map<std::string, int> StringIntMap;
 
   ThemeMap() {
+    // Construct in one-shot from a moved vector.
+    std::vector<StringIntMap::value_type> storage;
+
     for (size_t i = 0; i < kComponentsScaledResourcesSize; ++i) {
-      id_map_[kComponentsScaledResources[i].name] =
-          kComponentsScaledResources[i].value;
+      storage.emplace_back(kComponentsScaledResources[i].name,
+                           kComponentsScaledResources[i].value);
     }
-    for (size_t i = 0; i < kThemeResourcesSize; ++i)
-      id_map_[kThemeResources[i].name] = kThemeResources[i].value;
-    for (size_t i = 0; i < kUiResourcesSize; ++i)
-      id_map_[kUiResources[i].name] = kUiResources[i].value;
+    for (size_t i = 0; i < kThemeResourcesSize; ++i) {
+      storage.emplace_back(kThemeResources[i].name, kThemeResources[i].value);
+    }
+    for (size_t i = 0; i < kUiResourcesSize; ++i) {
+      storage.emplace_back(kUiResources[i].name, kUiResources[i].value);
+    }
 #if defined(OS_CHROMEOS)
-    for (size_t i = 0; i < kUiChromeosResourcesSize; ++i)
-      id_map_[kUiChromeosResources[i].name] = kUiChromeosResources[i].value;
+    for (size_t i = 0; i < kUiChromeosResourcesSize; ++i) {
+      storage.emplace_back(kUiChromeosResources[i].name,
+                           kUiChromeosResources[i].value);
+    }
 #endif
+
+    id_map_ = StringIntMap(std::move(storage), base::KEEP_FIRST_OF_DUPES);
   }
 
   int GetId(const std::string& resource_name) {
-    StringIntMap::const_iterator it = id_map_.find(resource_name);
+    auto it = id_map_.find(resource_name);
     if (it == id_map_.end())
       return -1;
     return it->second;
diff --git a/chrome/browser/safe_browsing/download_protection_service.cc b/chrome/browser/safe_browsing/download_protection_service.cc
index 1c74ea0..82900f5 100644
--- a/chrome/browser/safe_browsing/download_protection_service.cc
+++ b/chrome/browser/safe_browsing/download_protection_service.cc
@@ -30,6 +30,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/task/cancelable_task_tracker.h"
 #include "base/task_scheduler/post_task.h"
+#include "base/task_scheduler/task_traits.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
@@ -1678,9 +1679,11 @@
       enabled_(false),
       binary_feature_extractor_(new BinaryFeatureExtractor()),
       download_request_timeout_ms_(kDownloadRequestTimeoutMs),
-      feedback_service_(
-          new DownloadFeedbackService(request_context_getter_.get(),
-                                      BrowserThread::GetBlockingPool())),
+      feedback_service_(new DownloadFeedbackService(
+          request_context_getter_.get(),
+          base::CreateSequencedTaskRunnerWithTraits(
+              {base::MayBlock(), base::TaskPriority::BACKGROUND})
+              .get())),
       whitelist_sample_rate_(kWhitelistDownloadSampleRate) {
   if (sb_service) {
     ui_manager_ = sb_service->ui_manager();
diff --git a/chrome/browser/safe_browsing/download_protection_service_unittest.cc b/chrome/browser/safe_browsing/download_protection_service_unittest.cc
index b4d7c76..021fac4 100644
--- a/chrome/browser/safe_browsing/download_protection_service_unittest.cc
+++ b/chrome/browser/safe_browsing/download_protection_service_unittest.cc
@@ -26,7 +26,7 @@
 #include "base/sha1.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
-#include "base/threading/sequenced_worker_pool.h"
+#include "base/task_scheduler/task_scheduler.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/safe_browsing/download_feedback_service.h"
@@ -355,7 +355,7 @@
 
   // Flushes any pending tasks in the message loops of all threads.
   void FlushThreadMessageLoops() {
-    BrowserThread::GetBlockingPool()->FlushForTesting();
+    base::TaskScheduler::GetInstance()->FlushForTesting();
     FlushMessageLoop(BrowserThread::IO);
     FlushMessageLoop(BrowserThread::FILE);
     RunLoop().RunUntilIdle();
diff --git a/chrome/browser/safe_browsing/local_database_manager.h b/chrome/browser/safe_browsing/local_database_manager.h
index eb5f242..604bf3977b 100644
--- a/chrome/browser/safe_browsing/local_database_manager.h
+++ b/chrome/browser/safe_browsing/local_database_manager.h
@@ -18,7 +18,6 @@
 #include <vector>
 
 #include "base/callback.h"
-#include "base/containers/hash_tables.h"
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
@@ -166,7 +165,7 @@
                            ServiceStopWithPendingChecks);
 
   typedef std::vector<SafeBrowsingCheck*> GetHashRequestors;
-  typedef base::hash_map<SBPrefix, GetHashRequestors> GetHashRequests;
+  typedef std::map<SBPrefix, GetHashRequestors> GetHashRequests;
 
   // Clients that we've queued up for checking later once the database is ready.
   struct QueuedCheck {
diff --git a/chrome/browser/safe_browsing/protocol_manager.h b/chrome/browser/safe_browsing/protocol_manager.h
index 8878df62..125d7e25 100644
--- a/chrome/browser/safe_browsing/protocol_manager.h
+++ b/chrome/browser/safe_browsing/protocol_manager.h
@@ -334,8 +334,8 @@
   // All chunk requests that need to be made.
   std::deque<ChunkUrl> chunk_request_urls_;
 
-  base::hash_map<const net::URLFetcher*,
-                 std::pair<std::unique_ptr<net::URLFetcher>, FullHashDetails>>
+  std::map<const net::URLFetcher*,
+           std::pair<std::unique_ptr<net::URLFetcher>, FullHashDetails>>
       hash_requests_;
 
   // True if the service has been given an add/sub chunk but it hasn't been
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
index ffd3558..a352c331 100644
--- a/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
@@ -135,7 +135,8 @@
         g_browser_process->safe_browsing_service()
             ->trigger_manager()
             ->StartCollectingThreatDetails(
-                web_contents, unsafe_resources[0], profile->GetRequestContext(),
+                SafeBrowsingTriggerType::SECURITY_INTERSTITIAL, web_contents,
+                unsafe_resources[0], profile->GetRequestContext(),
                 HistoryServiceFactory::GetForProfile(
                     profile, ServiceAccessType::EXPLICIT_ACCESS),
                 sb_error_ui()->get_error_display_options());
@@ -208,6 +209,7 @@
   bool report_sent = g_browser_process->safe_browsing_service()
                          ->trigger_manager()
                          ->FinishCollectingThreatDetails(
+                             SafeBrowsingTriggerType::SECURITY_INTERSTITIAL,
                              web_contents(), delay, did_proceed, num_visits,
                              sb_error_ui()->get_error_display_options());
 
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
index 4107743..ac80a07 100644
--- a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
@@ -7,6 +7,7 @@
 // "goback" or "proceed" commands and verifies they work.
 
 #include <algorithm>
+#include <map>
 
 #include "base/bind.h"
 #include "base/command_line.h"
@@ -158,7 +159,7 @@
  private:
   ~FakeSafeBrowsingDatabaseManager() override {}
 
-  base::hash_map<std::string, SBThreatType> badurls;
+  std::map<std::string, SBThreatType> badurls;
   DISALLOW_COPY_AND_ASSIGN(FakeSafeBrowsingDatabaseManager);
 };
 
diff --git a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
index e0e0087..2855832 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
@@ -8,6 +8,8 @@
 
 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
 
+#include <map>
+#include <set>
 #include <utility>
 
 #include "base/bind.h"
@@ -303,13 +305,11 @@
                    std::vector<SBPrefix>* prefix_hits) {
     bool hit = false;
     for (const GURL& url : urls) {
-      base::hash_map<std::string, Hits>::const_iterator badurls_it =
-          badurls_.find(url.spec());
-
+      const auto badurls_it = badurls_.find(url.spec());
       if (badurls_it == badurls_.end())
         continue;
 
-      std::vector<int> list_ids_for_url = badurls_it->second.list_ids;
+      const std::vector<int>& list_ids_for_url = badurls_it->second.list_ids;
       if (base::ContainsValue(list_ids_for_url, list_id0) ||
           base::ContainsValue(list_ids_for_url, list_id1)) {
         prefix_hits->insert(prefix_hits->end(),
@@ -349,9 +349,9 @@
     return hit;
   }
 
-  base::hash_map<std::string, Hits> badurls_;
-  base::hash_set<std::pair<int, SBPrefix>> bad_prefixes_;
-  base::hash_map<std::string, GURL> urls_by_hash_;
+  std::map<std::string, Hits> badurls_;
+  std::set<std::pair<int, SBPrefix>> bad_prefixes_;
+  std::map<std::string, GURL> urls_by_hash_;
 
   DISALLOW_COPY_AND_ASSIGN(TestSafeBrowsingDatabase);
 };
@@ -396,7 +396,7 @@
 
   // This function is called when there is a prefix hit in local safebrowsing
   // database and safebrowsing service issues a get hash request to backends.
-  // We return a result from the prefilled full_hashes_ hash_map to simulate
+  // We return a result from the prefilled full_hashes_ map to simulate
   // server's response. At the same time, latency is added to simulate real
   // life network issues.
   void GetFullHash(const std::vector<SBPrefix>& prefixes,
diff --git a/chrome/browser/safe_browsing/threat_details_unittest.cc b/chrome/browser/safe_browsing/threat_details_unittest.cc
index 144b16d2..a9cc9f4 100644
--- a/chrome/browser/safe_browsing/threat_details_unittest.cc
+++ b/chrome/browser/safe_browsing/threat_details_unittest.cc
@@ -270,7 +270,7 @@
     ASSERT_EQ(expected_pb.resources_size(), report_pb.resources_size());
     // Put the actual resources in a map, then iterate over the expected
     // resources, making sure each exists and is equal.
-    base::hash_map<int, const ClientSafeBrowsingReportRequest::Resource*>
+    std::map<int, const ClientSafeBrowsingReportRequest::Resource*>
         actual_resource_map;
     for (const ClientSafeBrowsingReportRequest::Resource& resource :
          report_pb.resources()) {
@@ -290,7 +290,7 @@
     ASSERT_EQ(expected_pb.dom_size(), report_pb.dom_size());
     // Put the actual elements in a map, then iterate over the expected
     // elements, making sure each exists and is equal.
-    base::hash_map<int, const HTMLElement*> actual_dom_map;
+    std::map<int, const HTMLElement*> actual_dom_map;
     for (const HTMLElement& element : report_pb.dom()) {
       actual_dom_map[element.id()] = &element;
     }
@@ -352,7 +352,7 @@
     EXPECT_THAT(element.child_ids(),
                 UnorderedPointwise(Eq(), expected.child_ids()));
     ASSERT_EQ(expected.attribute_size(), element.attribute_size());
-    base::hash_map<std::string, std::string> actual_attributes_map;
+    std::map<std::string, std::string> actual_attributes_map;
     for (const HTMLElement::Attribute& attribute : element.attribute()) {
       actual_attributes_map[attribute.name()] = attribute.value();
     }
diff --git a/chrome/browser/safe_browsing/two_phase_uploader_unittest.cc b/chrome/browser/safe_browsing/two_phase_uploader_unittest.cc
index cf556c39..c6f3990 100644
--- a/chrome/browser/safe_browsing/two_phase_uploader_unittest.cc
+++ b/chrome/browser/safe_browsing/two_phase_uploader_unittest.cc
@@ -8,6 +8,8 @@
 
 #include "base/files/file_path.h"
 #include "base/message_loop/message_loop.h"
+#include "base/task_scheduler/post_task.h"
+#include "base/task_scheduler/task_traits.h"
 #include "chrome/browser/safe_browsing/local_two_phase_testserver.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "content/public/test/test_utils.h"
@@ -72,6 +74,9 @@
   content::TestBrowserThreadBundle thread_bundle_;
 
   scoped_refptr<net::TestURLRequestContextGetter> url_request_context_getter_;
+  const scoped_refptr<base::SequencedTaskRunner> task_runner_ =
+      base::CreateSequencedTaskRunnerWithTraits(
+          {base::MayBlock(), base::TaskPriority::BACKGROUND});
 };
 
 TEST_F(TwoPhaseUploaderTest, UploadFile) {
@@ -80,8 +85,7 @@
   ASSERT_TRUE(test_server.Start());
   Delegate delegate;
   std::unique_ptr<TwoPhaseUploader> uploader(TwoPhaseUploader::Create(
-      url_request_context_getter_.get(),
-      BrowserThread::GetTaskRunnerForThread(BrowserThread::DB).get(),
+      url_request_context_getter_.get(), task_runner_.get(),
       test_server.GetURL("start"), "metadata", GetTestFilePath(),
       base::Bind(&Delegate::ProgressCallback, base::Unretained(&delegate)),
       base::Bind(&Delegate::FinishCallback, base::Unretained(&delegate),
@@ -105,8 +109,7 @@
   ASSERT_TRUE(test_server.Start());
   Delegate delegate;
   std::unique_ptr<TwoPhaseUploader> uploader(TwoPhaseUploader::Create(
-      url_request_context_getter_.get(),
-      BrowserThread::GetTaskRunnerForThread(BrowserThread::DB).get(),
+      url_request_context_getter_.get(), task_runner_.get(),
       test_server.GetURL("start?p1code=500"), "metadata", GetTestFilePath(),
       base::Bind(&Delegate::ProgressCallback, base::Unretained(&delegate)),
       base::Bind(&Delegate::FinishCallback, base::Unretained(&delegate),
@@ -126,8 +129,7 @@
   ASSERT_TRUE(test_server.Start());
   Delegate delegate;
   std::unique_ptr<TwoPhaseUploader> uploader(TwoPhaseUploader::Create(
-      url_request_context_getter_.get(),
-      BrowserThread::GetTaskRunnerForThread(BrowserThread::DB).get(),
+      url_request_context_getter_.get(), task_runner_.get(),
       test_server.GetURL("start?p2code=500"), "metadata", GetTestFilePath(),
       base::Bind(&Delegate::ProgressCallback, base::Unretained(&delegate)),
       base::Bind(&Delegate::FinishCallback, base::Unretained(&delegate),
@@ -151,8 +153,7 @@
   ASSERT_TRUE(test_server.Start());
   Delegate delegate;
   std::unique_ptr<TwoPhaseUploader> uploader(TwoPhaseUploader::Create(
-      url_request_context_getter_.get(),
-      BrowserThread::GetTaskRunnerForThread(BrowserThread::DB).get(),
+      url_request_context_getter_.get(), task_runner_.get(),
       test_server.GetURL("start?p1close=1"), "metadata", GetTestFilePath(),
       base::Bind(&Delegate::ProgressCallback, base::Unretained(&delegate)),
       base::Bind(&Delegate::FinishCallback, base::Unretained(&delegate),
@@ -172,8 +173,7 @@
   ASSERT_TRUE(test_server.Start());
   Delegate delegate;
   std::unique_ptr<TwoPhaseUploader> uploader(TwoPhaseUploader::Create(
-      url_request_context_getter_.get(),
-      BrowserThread::GetTaskRunnerForThread(BrowserThread::DB).get(),
+      url_request_context_getter_.get(), task_runner_.get(),
       test_server.GetURL("start?p2close=1"), "metadata", GetTestFilePath(),
       base::Bind(&Delegate::ProgressCallback, base::Unretained(&delegate)),
       base::Bind(&Delegate::FinishCallback, base::Unretained(&delegate),
diff --git a/chrome/browser/site_details.h b/chrome/browser/site_details.h
index f9201a59..fbc1b92 100644
--- a/chrome/browser/site_details.h
+++ b/chrome/browser/site_details.h
@@ -7,7 +7,8 @@
 
 #include <stdint.h>
 
-#include "base/containers/hash_tables.h"
+#include <map>
+
 #include "base/macros.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/site_instance.h"
@@ -23,7 +24,7 @@
   std::set<GURL> sites;
 };
 using ScenarioBrowsingInstanceMap =
-    base::hash_map<int32_t, ScenarioBrowsingInstanceInfo>;
+    std::map<int32_t, ScenarioBrowsingInstanceInfo>;
 
 // Collects metrics about an actual browsing instance in the current session.
 struct BrowsingInstanceInfo {
@@ -35,7 +36,7 @@
   int proxy_count = 0;
 };
 using BrowsingInstanceMap =
-    base::hash_map<content::SiteInstance*, BrowsingInstanceInfo>;
+    std::map<content::SiteInstance*, BrowsingInstanceInfo>;
 
 // This enum represents various alternative process model policies that we want
 // to evaluate. We'll estimate the process cost of each scenario.
@@ -80,8 +81,7 @@
 };
 
 // Maps a BrowserContext to information about the sites it contains.
-typedef base::hash_map<content::BrowserContext*, SiteData>
-    BrowserContextSiteDataMap;
+typedef std::map<content::BrowserContext*, SiteData> BrowserContextSiteDataMap;
 
 class SiteDetails {
  public:
diff --git a/chrome/browser/ssl/chrome_ssl_host_state_delegate.cc b/chrome/browser/ssl/chrome_ssl_host_state_delegate.cc
index d080dae..032c380 100644
--- a/chrome/browser/ssl/chrome_ssl_host_state_delegate.cc
+++ b/chrome/browser/ssl/chrome_ssl_host_state_delegate.cc
@@ -431,7 +431,7 @@
   scoped_refptr<net::URLRequestContextGetter> getter(
       profile_->GetRequestContext());
   getter->GetNetworkTaskRunner()->PostTask(
-      FROM_HERE, base::Bind(&CloseIdleConnections, getter));
+      FROM_HERE, base::BindOnce(&CloseIdleConnections, getter));
 }
 
 bool ChromeSSLHostStateDelegate::HasAllowException(
diff --git a/chrome/browser/ssl/security_state_tab_helper_browser_tests.cc b/chrome/browser/ssl/security_state_tab_helper_browser_tests.cc
index a16b6173..dc252aaf 100644
--- a/chrome/browser/ssl/security_state_tab_helper_browser_tests.cc
+++ b/chrome/browser/ssl/security_state_tab_helper_browser_tests.cc
@@ -838,8 +838,8 @@
     url_request_context_getter_ = browser()->profile()->GetRequestContext();
     content::BrowserThread::PostTask(
         content::BrowserThread::IO, FROM_HERE,
-        base::Bind(&PKPModelClientTest::SetUpOnIOThread,
-                   base::Unretained(this)));
+        base::BindOnce(&PKPModelClientTest::SetUpOnIOThread,
+                       base::Unretained(this)));
   }
 
   void SetUpOnIOThread() {
@@ -953,8 +953,8 @@
 
     content::BrowserThread::PostTask(
         content::BrowserThread::IO, FROM_HERE,
-        base::Bind(&InstallLoadingInterceptor,
-                   embedded_test_server()->GetURL("/title1.html").host()));
+        base::BindOnce(&InstallLoadingInterceptor,
+                       embedded_test_server()->GetURL("/title1.html").host()));
   }
 
  private:
@@ -2088,7 +2088,7 @@
     serve_file = serve_file.Append(FILE_PATH_LITERAL("title1.html"));
     content::BrowserThread::PostTask(
         content::BrowserThread::IO, FROM_HERE,
-        base::Bind(&AddNonsecureUrlHandler, serve_file, cert_));
+        base::BindOnce(&AddNonsecureUrlHandler, serve_file, cert_));
   }
 
  private:
diff --git a/chrome/browser/ssl/ssl_browser_tests.cc b/chrome/browser/ssl/ssl_browser_tests.cc
index a31095d..329bc3d 100644
--- a/chrome/browser/ssl/ssl_browser_tests.cc
+++ b/chrome/browser/ssl/ssl_browser_tests.cc
@@ -3338,8 +3338,9 @@
     // Start reading asynchronously as would a normal network request.
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
-        base::Bind(&DelayableNetworkTimeURLRequestJob::NotifyHeadersComplete,
-                   weak_factory_.GetWeakPtr()));
+        base::BindOnce(
+            &DelayableNetworkTimeURLRequestJob::NotifyHeadersComplete,
+            weak_factory_.GetWeakPtr()));
   }
 
  private:
@@ -3456,7 +3457,7 @@
 
   void TearDownOnMainThread() override {
     content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE,
-                                     base::Bind(&CleanUpOnIOThread));
+                                     base::BindOnce(&CleanUpOnIOThread));
   }
 
  protected:
@@ -3465,17 +3466,17 @@
     interceptor_ = new DelayedNetworkTimeInterceptor();
     content::BrowserThread::PostTask(
         content::BrowserThread::IO, FROM_HERE,
-        base::Bind(&SetUpNetworkTimeInterceptorOnIOThread,
-                   base::Unretained(interceptor_),
-                   g_browser_process->network_time_tracker()
-                       ->GetTimeServerURLForTesting()));
+        base::BindOnce(&SetUpNetworkTimeInterceptorOnIOThread,
+                       base::Unretained(interceptor_),
+                       g_browser_process->network_time_tracker()
+                           ->GetTimeServerURLForTesting()));
   }
 
   void TriggerTimeResponse() {
     content::BrowserThread::PostTask(
         content::BrowserThread::IO, FROM_HERE,
-        base::Bind(&ResumeDelayedNetworkTimeRequest,
-                   base::Unretained(interceptor_)));
+        base::BindOnce(&ResumeDelayedNetworkTimeRequest,
+                       base::Unretained(interceptor_)));
   }
 
   // Asserts that the first time request to the server is currently pending.
@@ -3823,12 +3824,12 @@
     host_resolver()->AddRule("*", "127.0.0.1");
     content::BrowserThread::PostTask(
         content::BrowserThread::IO, FROM_HERE,
-        base::Bind(&SetUpHttpNameMismatchPingInterceptorOnIOThread));
+        base::BindOnce(&SetUpHttpNameMismatchPingInterceptorOnIOThread));
   }
 
   void TearDownOnMainThread() override {
     content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE,
-                                     base::Bind(&CleanUpOnIOThread));
+                                     base::BindOnce(&CleanUpOnIOThread));
     CertVerifierBrowserTest::TearDownOnMainThread();
   }
 };
diff --git a/chrome/browser/ssl/ssl_client_certificate_selector_test.cc b/chrome/browser/ssl/ssl_client_certificate_selector_test.cc
index e0362ea6..904afe0 100644
--- a/chrome/browser/ssl/ssl_client_certificate_selector_test.cc
+++ b/chrome/browser/ssl/ssl_client_certificate_selector_test.cc
@@ -41,10 +41,9 @@
   url_request_context_getter_ = browser()->profile()->GetRequestContext();
 
   BrowserThread::PostTask(
-      BrowserThread::IO,
-      FROM_HERE,
-      base::Bind(&SSLClientCertificateSelectorTestBase::SetUpOnIOThread,
-                 base::Unretained(this)));
+      BrowserThread::IO, FROM_HERE,
+      base::BindOnce(&SSLClientCertificateSelectorTestBase::SetUpOnIOThread,
+                     base::Unretained(this)));
 
   io_loop_finished_event_.Wait();
 
@@ -56,10 +55,9 @@
 // it to be destroyed while the Browser and its IO thread still exist.
 void SSLClientCertificateSelectorTestBase::TearDownOnMainThread() {
   BrowserThread::PostTask(
-      BrowserThread::IO,
-      FROM_HERE,
-      base::Bind(&SSLClientCertificateSelectorTestBase::TearDownOnIOThread,
-                 base::Unretained(this)));
+      BrowserThread::IO, FROM_HERE,
+      base::BindOnce(&SSLClientCertificateSelectorTestBase::TearDownOnIOThread,
+                     base::Unretained(this)));
 
   io_loop_finished_event_.Wait();
 
diff --git a/chrome/browser/supervised_user/supervised_user_interstitial.cc b/chrome/browser/supervised_user/supervised_user_interstitial.cc
index f96fdb65..4a4c88d 100644
--- a/chrome/browser/supervised_user/supervised_user_interstitial.cc
+++ b/chrome/browser/supervised_user/supervised_user_interstitial.cc
@@ -258,12 +258,9 @@
 
   if (command == "\"feedback\"") {
     bool is_child_account = profile_->IsChild();
-    bool is_deprecated =
-        base::FeatureList::IsEnabled(features::kSupervisedUserCreation);
     base::string16 reason =
         l10n_util::GetStringUTF16(supervised_user_error_page::GetBlockMessageID(
-            reason_, is_child_account, is_deprecated,
-            second_custodian.empty()));
+            reason_, is_child_account, second_custodian.empty()));
     std::string message = l10n_util::GetStringFUTF8(
         IDS_BLOCK_INTERSTITIAL_DEFAULT_FEEDBACK_TEXT, reason);
 #if defined(OS_ANDROID)
diff --git a/chrome/browser/sync/test/integration/migration_test.cc b/chrome/browser/sync/test/integration/migration_test.cc
index 848b93b..3930e73 100644
--- a/chrome/browser/sync/test/integration/migration_test.cc
+++ b/chrome/browser/sync/test/integration/migration_test.cc
@@ -112,6 +112,9 @@
     // that it be migrated.
     preferred_data_types.Remove(syncer::ARC_PACKAGE);
 
+    // Doesn't make sense to migrate commit only types.
+    preferred_data_types.RemoveAll(syncer::CommitOnlyTypes());
+
     // Make sure all clients have the same preferred data types.
     for (int i = 1; i < num_clients(); ++i) {
       const syncer::ModelTypeSet other_preferred_data_types =
diff --git a/chrome/browser/sync/test/integration/single_client_user_events_sync_test.cc b/chrome/browser/sync/test/integration/single_client_user_events_sync_test.cc
new file mode 100644
index 0000000..8a7564c
--- /dev/null
+++ b/chrome/browser/sync/test/integration/single_client_user_events_sync_test.cc
@@ -0,0 +1,93 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/macros.h"
+#include "base/time/time.h"
+#include "chrome/browser/sync/test/integration/single_client_status_change_checker.h"
+#include "chrome/browser/sync/test/integration/status_change_checker.h"
+#include "chrome/browser/sync/test/integration/sync_test.h"
+#include "chrome/browser/sync/user_event_service_factory.h"
+#include "components/sync/protocol/user_event_specifics.pb.h"
+#include "components/sync/user_events/user_event_service.h"
+
+using fake_server::FakeServer;
+using sync_pb::UserEventSpecifics;
+using sync_pb::SyncEntity;
+
+namespace {
+
+class UserEventEqualityChecker : public SingleClientStatusChangeChecker {
+ public:
+  UserEventEqualityChecker(browser_sync::ProfileSyncService* service,
+                           FakeServer* fake_server,
+                           std::vector<UserEventSpecifics> expected_specifics)
+      : SingleClientStatusChangeChecker(service), fake_server_(fake_server) {
+    for (const UserEventSpecifics& specifics : expected_specifics) {
+      expected_specifics_[specifics.event_time_usec()] = specifics;
+    }
+  }
+
+  bool IsExitConditionSatisfied() override {
+    std::vector<SyncEntity> entities =
+        fake_server_->GetSyncEntitiesByModelType(syncer::USER_EVENTS);
+
+    // |entities.size()| is only going to grow, if |entities.size()| ever
+    // becomes bigger then all hope is lost of passing, stop now.
+    EXPECT_GE(expected_specifics_.size(), entities.size());
+
+    if (expected_specifics_.size() > entities.size()) {
+      return false;
+    }
+
+    for (const SyncEntity& entity : entities) {
+      UserEventSpecifics server_specifics = entity.specifics().user_event();
+      auto iter = expected_specifics_.find(server_specifics.event_time_usec());
+      // We don't expect to encounter id matching events with different values,
+      // this isn't going to recover so fail the test case now.
+      CHECK(expected_specifics_.end() != iter);
+      // TODO(skym): This may need to change if we start updating navigation_id
+      // based on what sessions data is committed, and end up committing the
+      // same event multiple times.
+      EXPECT_EQ(iter->second.navigation_id(), server_specifics.navigation_id());
+      EXPECT_EQ(iter->second.event_case(), server_specifics.event_case());
+    }
+
+    return true;
+  }
+
+  std::string GetDebugMessage() const override {
+    return "Waiting server side USER_EVENTS to match expected.";
+  }
+
+ private:
+  FakeServer* fake_server_;
+  std::map<int64_t, UserEventSpecifics> expected_specifics_;
+};
+
+class SingleClientUserEventsSyncTest : public SyncTest {
+ public:
+  SingleClientUserEventsSyncTest() : SyncTest(SINGLE_CLIENT) {
+    DisableVerifier();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(SingleClientUserEventsSyncTest);
+};
+
+IN_PROC_BROWSER_TEST_F(SingleClientUserEventsSyncTest, Sanity) {
+  ASSERT_TRUE(SetupSync());
+  EXPECT_EQ(
+      0u,
+      GetFakeServer()->GetSyncEntitiesByModelType(syncer::USER_EVENTS).size());
+  syncer::UserEventService* event_service =
+      browser_sync::UserEventServiceFactory::GetForProfile(GetProfile(0));
+  UserEventSpecifics specifics1;
+  specifics1.set_event_time_usec(base::Time::Now().ToInternalValue());
+  specifics1.mutable_test_event();
+  event_service->RecordUserEvent(specifics1);
+  UserEventEqualityChecker(GetSyncService(0), GetFakeServer(), {specifics1})
+      .Wait();
+}
+
+}  // namespace
diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_database_index.h b/chrome/browser/sync_file_system/drive_backend/metadata_database_index.h
index 38ff499..fedf07b 100644
--- a/chrome/browser/sync_file_system/drive_backend/metadata_database_index.h
+++ b/chrome/browser/sync_file_system/drive_backend/metadata_database_index.h
@@ -12,9 +12,9 @@
 #include <set>
 #include <string>
 #include <unordered_map>
+#include <unordered_set>
 #include <vector>
 
-#include "base/containers/hash_tables.h"
 #include "base/hash.h"
 #include "base/macros.h"
 #include "chrome/browser/sync_file_system/drive_backend/metadata_database_index_interface.h"
@@ -31,7 +31,7 @@
 }  // namespace drive_backend
 }  // namespace sync_file_system
 
-namespace BASE_HASH_NAMESPACE {
+namespace std {
 
 template<> struct hash<sync_file_system::drive_backend::ParentIDAndTitle> {
   std::size_t operator()(
@@ -40,7 +40,7 @@
   }
 };
 
-}  // namespace BASE_HASH_NAMESPACE
+}  // namespace std
 
 namespace sync_file_system {
 namespace drive_backend {
@@ -106,12 +106,12 @@
   typedef std::unordered_map<std::string, std::unique_ptr<FileMetadata>>
       MetadataByID;
   typedef std::unordered_map<int64_t, std::unique_ptr<FileTracker>> TrackerByID;
-  typedef base::hash_map<std::string, TrackerIDSet> TrackerIDsByFileID;
-  typedef base::hash_map<std::string, TrackerIDSet> TrackerIDsByTitle;
+  typedef std::unordered_map<std::string, TrackerIDSet> TrackerIDsByFileID;
+  typedef std::unordered_map<std::string, TrackerIDSet> TrackerIDsByTitle;
   typedef std::map<int64_t, TrackerIDsByTitle> TrackerIDsByParentAndTitle;
-  typedef base::hash_map<std::string, int64_t> TrackerIDByAppID;
-  typedef base::hash_set<std::string> FileIDSet;
-  typedef base::hash_set<ParentIDAndTitle> PathSet;
+  typedef std::unordered_map<std::string, int64_t> TrackerIDByAppID;
+  typedef std::unordered_set<std::string> FileIDSet;
+  typedef std::unordered_set<ParentIDAndTitle> PathSet;
   typedef std::set<int64_t> DirtyTrackers;
 
   friend class MetadataDatabaseTest;
diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_database_unittest.cc b/chrome/browser/sync_file_system/drive_backend/metadata_database_unittest.cc
index 814220b..e0ea089 100644
--- a/chrome/browser/sync_file_system/drive_backend/metadata_database_unittest.cc
+++ b/chrome/browser/sync_file_system/drive_backend/metadata_database_unittest.cc
@@ -104,8 +104,8 @@
 }
 
 template <typename Key, typename Value>
-void ExpectEquivalent(const base::hash_map<Key, Value>& left,
-                      const base::hash_map<Key, Value>& right) {
+void ExpectEquivalent(const std::unordered_map<Key, Value>& left,
+                      const std::unordered_map<Key, Value>& right) {
   // Convert from a hash container to an ordered container for comparison.
   ExpectEquivalentMaps(std::map<Key, Value>(left.begin(), left.end()),
                        std::map<Key, Value>(right.begin(), right.end()));
@@ -136,8 +136,8 @@
 }
 
 template <typename Value>
-void ExpectEquivalent(const base::hash_set<Value>& left,
-                      const base::hash_set<Value>& right) {
+void ExpectEquivalent(const std::unordered_set<Value>& left,
+                      const std::unordered_set<Value>& right) {
   // Convert from a hash container to an ordered container for comparison.
   return ExpectEquivalentSets(std::set<Value>(left.begin(), left.end()),
                               std::set<Value>(right.begin(), right.end()));
diff --git a/chrome/browser/sync_file_system/drive_backend/sync_worker.h b/chrome/browser/sync_file_system/drive_backend/sync_worker.h
index fa4d4bf..b27575c 100644
--- a/chrome/browser/sync_file_system/drive_backend/sync_worker.h
+++ b/chrome/browser/sync_file_system/drive_backend/sync_worker.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 #include <string>
+#include <unordered_map>
 
 #include "base/files/file_path.h"
 #include "base/macros.h"
@@ -110,7 +111,7 @@
     APP_STATUS_UNINSTALLED,
   };
 
-  typedef base::hash_map<std::string, AppStatus> AppStatusMap;
+  using AppStatusMap = std::unordered_map<std::string, AppStatus>;
 
   void DoDisableApp(const std::string& app_id,
                     const SyncStatusCallback& callback);
diff --git a/chrome/browser/sync_file_system/subtree_set.h b/chrome/browser/sync_file_system/subtree_set.h
index 40e232b2..190165f 100644
--- a/chrome/browser/sync_file_system/subtree_set.h
+++ b/chrome/browser/sync_file_system/subtree_set.h
@@ -7,6 +7,8 @@
 
 #include <stddef.h>
 
+#include <unordered_map>
+
 #include "base/containers/hash_tables.h"
 #include "base/files/file_path.h"
 
@@ -49,7 +51,7 @@
   };
 
   typedef base::FilePath::StringType StringType;
-  typedef base::hash_map<StringType, Node> Subtrees;
+  typedef std::unordered_map<StringType, Node> Subtrees;
 
   // Contains the root of subtrees and all upward node to root.
   // Each subtree root has |contained_as_subtree_root| flag true.
diff --git a/chrome/browser/translate/chrome_translate_client.h b/chrome/browser/translate/chrome_translate_client.h
index 3c7e052..33e890e 100644
--- a/chrome/browser/translate/chrome_translate_client.h
+++ b/chrome/browser/translate/chrome_translate_client.h
@@ -121,6 +121,10 @@
                            LanguageEventShouldRecord);
   FRIEND_TEST_ALL_PREFIXES(ChromeTranslateClientTest,
                            LanguageEventShouldNotRecord);
+  FRIEND_TEST_ALL_PREFIXES(ChromeTranslateClientTest,
+                           TranslationEventShouldRecord);
+  FRIEND_TEST_ALL_PREFIXES(ChromeTranslateClientTest,
+                           TranslationEventShouldNotRecord);
 
   // content::WebContentsObserver implementation.
   void WebContentsDestroyed() override;
diff --git a/chrome/browser/translate/chrome_translate_client_unittest.cc b/chrome/browser/translate/chrome_translate_client_unittest.cc
index 18f9cf9..f75bc45a 100644
--- a/chrome/browser/translate/chrome_translate_client_unittest.cc
+++ b/chrome/browser/translate/chrome_translate_client_unittest.cc
@@ -5,6 +5,8 @@
 #include "chrome/browser/translate/chrome_translate_client.h"
 
 #include <memory>
+#include <string>
+#include <vector>
 
 #include "base/command_line.h"
 #include "base/memory/ref_counted.h"
@@ -13,6 +15,7 @@
 #include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "chrome/browser/sync/user_event_service_factory.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
+#include "components/metrics/proto/translate_event.pb.h"
 #include "components/sync/driver/sync_driver_switches.h"
 #include "components/sync/user_events/fake_user_event_service.h"
 #include "components/translate/core/common/language_detection_details.h"
@@ -25,6 +28,17 @@
   return base::MakeUnique<syncer::FakeUserEventService>();
 }
 
+metrics::TranslateEventProto BuildTranslateEventProto(
+    const std::string& from,
+    const std::string& to,
+    const metrics::TranslateEventProto::EventType type) {
+  metrics::TranslateEventProto event;
+  event.set_source_language(from);
+  event.set_target_language(to);
+  event.set_event_type(type);
+  return event;
+}
+
 class ChromeTranslateClientTest : public ChromeRenderViewHostTestHarness {
  public:
   void SetUp() override {
@@ -34,8 +48,10 @@
             ->SetTestingFactoryAndUse(browser_context(),
                                       &BuildFakeUserEventService));
     scoped_feature_list_ = base::MakeUnique<base::test::ScopedFeatureList>();
-    scoped_feature_list_->InitAndEnableFeature(
-        switches::kSyncUserLanguageDetectionEvents);
+    scoped_feature_list_->InitWithFeatures(
+        {switches::kSyncUserLanguageDetectionEvents,
+         switches::kSyncUserTranslationEvents},
+        {});
   }
 
   void TearDown() override { ChromeRenderViewHostTestHarness::TearDown(); }
@@ -51,7 +67,7 @@
 };
 
 TEST_F(ChromeTranslateClientTest, LanguageEventShouldRecord) {
-  GURL url("http://yahoo.com");
+  const GURL url("http://yahoo.com");
   NavigateAndCommit(url);
   ChromeTranslateClient client(web_contents());
   translate::LanguageDetectionDetails details;
@@ -63,7 +79,7 @@
 }
 
 TEST_F(ChromeTranslateClientTest, LanguageEventShouldNotRecord) {
-  GURL url("about://blank");
+  const GURL url("about://blank");
   NavigateAndCommit(url);
   ChromeTranslateClient client(web_contents());
   translate::LanguageDetectionDetails details;
@@ -73,3 +89,35 @@
   client.OnLanguageDetermined(details);
   EXPECT_EQ(0u, GetUserEventService()->GetRecordedUserEvents().size());
 }
+
+TEST_F(ChromeTranslateClientTest, TranslationEventShouldRecord) {
+  const GURL url("http://yahoo.com");
+  NavigateAndCommit(url);
+  ChromeTranslateClient client(web_contents());
+  // An event we care about.
+  const metrics::TranslateEventProto& event_proto = BuildTranslateEventProto(
+      "ja", "en", metrics::TranslateEventProto::USER_ACCEPT);
+  client.RecordTranslateEvent(event_proto);
+  EXPECT_EQ(1ul, GetUserEventService()->GetRecordedUserEvents().size());
+
+  sync_pb::UserEventSpecifics::Translation expected_translation_event;
+  expected_translation_event.set_from_language_code("ja");
+  expected_translation_event.set_to_language_code("en");
+  expected_translation_event.set_interaction(
+      sync_pb::UserEventSpecifics::Translation::ACCEPT);
+  const auto& result_translation_event =
+      GetUserEventService()->GetRecordedUserEvents()[0].translation_event();
+  EXPECT_EQ(expected_translation_event.SerializeAsString(),
+            result_translation_event.SerializeAsString());
+}
+
+TEST_F(ChromeTranslateClientTest, TranslationEventShouldNotRecord) {
+  const GURL url("http://yahoo.com");
+  NavigateAndCommit(url);
+  ChromeTranslateClient client(web_contents());
+  // An event we don't care about.
+  const metrics::TranslateEventProto& event_proto = BuildTranslateEventProto(
+      "ja", "en", metrics::TranslateEventProto::UNSUPPORTED_URL);
+  client.RecordTranslateEvent(event_proto);
+  EXPECT_EQ(0u, GetUserEventService()->GetRecordedUserEvents().size());
+}
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index a91f1ba..a67bee2f 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1526,6 +1526,10 @@
       "views/extensions/extension_keybinding_registry_views.h",
       "views/frame/native_widget_mac_frameless_nswindow.h",
       "views/frame/native_widget_mac_frameless_nswindow.mm",
+      "views/fullscreen_control/fullscreen_control_host.cc",
+      "views/fullscreen_control/fullscreen_control_host.h",
+      "views/fullscreen_control/fullscreen_control_view.cc",
+      "views/fullscreen_control/fullscreen_control_view.h",
       "views/global_error_bubble_view.cc",
       "views/global_error_bubble_view.h",
       "views/harmony/chrome_layout_provider.cc",
@@ -1612,6 +1616,8 @@
       "views/permission_bubble/chooser_bubble_ui.h",
       "views/permission_bubble/permission_prompt_impl.cc",
       "views/permission_bubble/permission_prompt_impl.h",
+      "views/simple_message_box_views.cc",
+      "views/simple_message_box_views.h",
       "views/subtle_notification_view.cc",
       "views/subtle_notification_view.h",
       "views/sync/bubble_sync_promo_view.cc",
@@ -1882,7 +1888,6 @@
         "views/proximity_auth/proximity_auth_error_bubble_view.h",
         "views/session_crashed_bubble_view.cc",
         "views/session_crashed_bubble_view.h",
-        "views/simple_message_box_views.cc",
         "views/ssl_client_certificate_selector.cc",
         "views/ssl_client_certificate_selector.h",
         "views/status_bubble_views.cc",
@@ -3012,7 +3017,9 @@
         "cocoa/screen_capture_notification_ui_cocoa.h",
         "cocoa/screen_capture_notification_ui_cocoa.mm",
         "cocoa/session_crashed_bubble.mm",
-        "cocoa/simple_message_box_mac.mm",
+        "cocoa/simple_message_box_bridge_views.mm",
+        "cocoa/simple_message_box_cocoa.h",
+        "cocoa/simple_message_box_cocoa.mm",
         "cocoa/single_web_contents_dialog_manager_cocoa.h",
         "cocoa/single_web_contents_dialog_manager_cocoa.mm",
         "cocoa/spinner_view.h",
@@ -3424,6 +3431,8 @@
         "app_list/arc/arc_package_syncable_service.h",
         "app_list/arc/arc_package_syncable_service_factory.cc",
         "app_list/arc/arc_package_syncable_service_factory.h",
+        "app_list/arc/arc_pai_starter.cc",
+        "app_list/arc/arc_pai_starter.h",
         "app_list/arc/arc_playstore_app_context_menu.cc",
         "app_list/arc/arc_playstore_app_context_menu.h",
         "app_list/search/arc_app_result.cc",
diff --git a/chrome/browser/ui/app_list/arc/arc_app_unittest.cc b/chrome/browser/ui/app_list/arc/arc_app_unittest.cc
index cf34293..8341a60 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_unittest.cc
+++ b/chrome/browser/ui/app_list/arc/arc_app_unittest.cc
@@ -18,6 +18,7 @@
 #include "base/stl_util.h"
 #include "base/task_runner_util.h"
 #include "base/values.h"
+#include "chrome/browser/chromeos/arc/arc_session_manager.h"
 #include "chrome/browser/chromeos/arc/arc_support_host.h"
 #include "chrome/browser/chromeos/arc/arc_util.h"
 #include "chrome/browser/extensions/extension_service.h"
@@ -35,6 +36,7 @@
 #include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
 #include "chrome/browser/ui/app_list/arc/arc_default_app_list.h"
 #include "chrome/browser/ui/app_list/arc/arc_package_syncable_service_factory.h"
+#include "chrome/browser/ui/app_list/arc/arc_pai_starter.h"
 #include "chrome/browser/ui/app_list/test/test_app_list_controller_delegate.h"
 #include "chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.h"
 #include "chrome/common/pref_names.h"
@@ -541,6 +543,17 @@
     extension_service->AddExtension(arc_support_host_.get());
   }
 
+  void SendPlayStoreApp() {
+    arc::mojom::AppInfo app;
+    app.name = "Play Store";
+    app.package_name = arc::kPlayStorePackage;
+    app.activity = arc::kPlayStoreActivity;
+    app.sticky = GetParam() != ArcState::ARC_PERSISTENT_WITHOUT_PLAY_STORE;
+
+    app_instance()->RefreshAppList();
+    app_instance()->SendRefreshAppList({app});
+  }
+
  private:
   scoped_refptr<extensions::Extension> arc_support_host_;
 
@@ -1146,16 +1159,7 @@
     EXPECT_FALSE(app_info);
   }
 
-  arc::mojom::AppInfo app;
-  std::vector<arc::mojom::AppInfo> apps;
-  app.name = "Play Store";
-  app.package_name = arc::kPlayStorePackage;
-  app.activity = arc::kPlayStoreActivity;
-  app.sticky = GetParam() != ArcState::ARC_PERSISTENT_WITHOUT_PLAY_STORE;
-  apps.push_back(app);
-
-  app_instance()->RefreshAppList();
-  app_instance()->SendRefreshAppList(apps);
+  SendPlayStoreApp();
 
   app_info = prefs->GetApp(arc::kPlayStoreAppId);
   ASSERT_TRUE(app_info);
@@ -1175,6 +1179,48 @@
   EXPECT_TRUE(arc::IsArcPlayStoreEnabledForProfile(profile()));
 }
 
+TEST_P(ArcPlayStoreAppTest, PaiStarter) {
+  ASSERT_TRUE(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+
+  ArcAppListPrefs* prefs = ArcAppListPrefs::Get(profile_.get());
+  ASSERT_TRUE(prefs);
+
+  arc::ArcPaiStarter starter1(profile_.get());
+  arc::ArcPaiStarter starter2(profile_.get());
+  EXPECT_FALSE(starter1.started());
+  EXPECT_FALSE(starter2.started());
+  EXPECT_EQ(app_instance()->start_pai_request_count(), 0);
+
+  arc::ArcSessionManager* session_manager = arc::ArcSessionManager::Get();
+  ASSERT_TRUE(session_manager);
+
+  // PAI starter is not expected for ARC without the Play Store.
+  if (GetParam() == ArcState::ARC_PERSISTENT_WITHOUT_PLAY_STORE) {
+    EXPECT_FALSE(session_manager->pai_starter());
+    return;
+  }
+
+  ASSERT_TRUE(session_manager->pai_starter());
+  EXPECT_FALSE(session_manager->pai_starter()->started());
+
+  starter2.AcquireLock();
+
+  SendPlayStoreApp();
+
+  EXPECT_TRUE(starter1.started());
+  EXPECT_FALSE(starter2.started());
+  EXPECT_TRUE(session_manager->pai_starter()->started());
+  EXPECT_EQ(app_instance()->start_pai_request_count(), 2);
+
+  starter2.ReleaseLock();
+  EXPECT_TRUE(starter2.started());
+  EXPECT_EQ(app_instance()->start_pai_request_count(), 3);
+
+  arc::ArcPaiStarter starter3(profile_.get());
+  EXPECT_TRUE(starter3.started());
+  EXPECT_EQ(app_instance()->start_pai_request_count(), 4);
+}
+
 // Test that icon is correctly extracted for shelf group.
 TEST_P(ArcAppModelBuilderTest, IconLoaderForShelfGroup) {
   const arc::mojom::AppInfo& app = fake_apps()[0];
diff --git a/chrome/browser/ui/app_list/arc/arc_app_utils.cc b/chrome/browser/ui/app_list/arc/arc_app_utils.cc
index f3c9ed8a..971ee7d 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_utils.cc
+++ b/chrome/browser/ui/app_list/arc/arc_app_utils.cc
@@ -386,6 +386,13 @@
                                         kIntentHelperClassName, "{}");
 }
 
+void StartPaiFlow() {
+  arc::mojom::AppInstance* app_instance = GET_APP_INSTANCE(StartPaiFlow);
+  if (!app_instance)
+    return;
+  app_instance->StartPaiFlow();
+}
+
 bool CanHandleResolution(content::BrowserContext* context,
                          const std::string& app_id,
                          const gfx::Rect& rect,
diff --git a/chrome/browser/ui/app_list/arc/arc_app_utils.h b/chrome/browser/ui/app_list/arc/arc_app_utils.h
index 6ea7ba27..db5081a 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_utils.h
+++ b/chrome/browser/ui/app_list/arc/arc_app_utils.h
@@ -119,9 +119,12 @@
 // Closes the task.
 void CloseTask(int task_id);
 
-// Open TalkBack settings window.
+// Opens TalkBack settings window.
 void ShowTalkBackSettings();
 
+// Starts Play Auto Install flow.
+void StartPaiFlow();
+
 // Tests if the application can use the given target resolution.
 // The callback will receive the information once known.
 // A false will get returned if the result cannot be determined in which case
diff --git a/chrome/browser/ui/app_list/arc/arc_pai_starter.cc b/chrome/browser/ui/app_list/arc/arc_pai_starter.cc
new file mode 100644
index 0000000..341c172
--- /dev/null
+++ b/chrome/browser/ui/app_list/arc/arc_pai_starter.cc
@@ -0,0 +1,63 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/app_list/arc/arc_pai_starter.h"
+
+#include <memory>
+
+#include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
+#include "ui/events/event_constants.h"
+
+namespace arc {
+
+ArcPaiStarter::ArcPaiStarter(content::BrowserContext* context)
+    : context_(context) {
+  ArcAppListPrefs* prefs = ArcAppListPrefs::Get(context_);
+  // Prefs may not available in some unit tests.
+  if (!prefs)
+    return;
+  prefs->AddObserver(this);
+  MaybeStartPai();
+}
+
+ArcPaiStarter::~ArcPaiStarter() {
+  ArcAppListPrefs* prefs = ArcAppListPrefs::Get(context_);
+  if (!prefs)
+    return;
+  prefs->RemoveObserver(this);
+}
+
+void ArcPaiStarter::AcquireLock() {
+  DCHECK(!locked_);
+  locked_ = true;
+}
+
+void ArcPaiStarter::ReleaseLock() {
+  DCHECK(locked_);
+  locked_ = false;
+  MaybeStartPai();
+}
+
+void ArcPaiStarter::MaybeStartPai() {
+  if (started_ || locked_)
+    return;
+
+  ArcAppListPrefs* prefs = ArcAppListPrefs::Get(context_);
+  DCHECK(prefs);
+  std::unique_ptr<ArcAppListPrefs::AppInfo> app_info =
+      prefs->GetApp(kPlayStoreAppId);
+  if (!app_info || !app_info->ready)
+    return;
+
+  started_ = true;
+  StartPaiFlow();
+  prefs->RemoveObserver(this);
+}
+
+void ArcPaiStarter::OnAppReadyChanged(const std::string& app_id, bool ready) {
+  if (app_id == kPlayStoreAppId && ready)
+    MaybeStartPai();
+}
+
+}  // namespace arc
diff --git a/chrome/browser/ui/app_list/arc/arc_pai_starter.h b/chrome/browser/ui/app_list/arc/arc_pai_starter.h
new file mode 100644
index 0000000..50d4908
--- /dev/null
+++ b/chrome/browser/ui/app_list/arc/arc_pai_starter.h
@@ -0,0 +1,48 @@
+// 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 CHROME_BROWSER_UI_APP_LIST_ARC_ARC_PAI_STARTER_H_
+#define CHROME_BROWSER_UI_APP_LIST_ARC_ARC_PAI_STARTER_H_
+
+#include "base/macros.h"
+#include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
+
+namespace content {
+class BrowserContext;
+}
+
+namespace arc {
+
+// Helper class that starts Play Auto Install flow when all conditions are met:
+// The Play Store app is ready and there is no lock for PAI flow.
+class ArcPaiStarter : public ArcAppListPrefs::Observer {
+ public:
+  explicit ArcPaiStarter(content::BrowserContext* context);
+  ~ArcPaiStarter() override;
+
+  // Locks PAI to be run on the Play Store app is ready.
+  void AcquireLock();
+
+  // Unlocks PAI to be run on the Play Store app is ready. If the Play Store app
+  // is ready at this moment then PAI is started immediately.
+  void ReleaseLock();
+
+  bool started() const { return started_; }
+
+ private:
+  void MaybeStartPai();
+
+  // ArcAppListPrefs::Observer:
+  void OnAppReadyChanged(const std::string& app_id, bool ready) override;
+
+  content::BrowserContext* const context_;
+  bool locked_ = false;
+  bool started_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(ArcPaiStarter);
+};
+
+}  // namespace arc
+
+#endif  // CHROME_BROWSER_UI_APP_LIST_ARC_ARC_PAI_STARTER_H_
diff --git a/chrome/browser/ui/app_list/search/search_resource_manager.cc b/chrome/browser/ui/app_list/search/search_resource_manager.cc
index 62085af7..5c2939a 100644
--- a/chrome/browser/ui/app_list/search/search_resource_manager.cc
+++ b/chrome/browser/ui/app_list/search/search_resource_manager.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/browser/ui/app_list/search/search_resource_manager.h"
 
-#include "ash/system/devicetype_utils.h"
 #include "base/memory/ptr_util.h"
 #include "chrome/browser/ui/app_list/start_page_service.h"
 #include "chrome/grit/generated_resources.h"
@@ -39,12 +38,13 @@
                                              SearchBoxModel* search_box,
                                              SpeechUIModel* speech_ui)
     : search_box_(search_box),
-      speech_ui_(speech_ui) {
+      speech_ui_(speech_ui),
+      is_fullscreen_app_list_enabled_(features::IsFullscreenAppListEnabled()) {
   speech_ui_->AddObserver(this);
 
-  if (features::IsFullscreenAppListEnabled()) {
-    search_box_->SetAccessibleName(l10n_util::GetStringFUTF16(
-        IDS_SEARCH_BOX_HINT_FULLSCREEN, ash::GetChromeOSDeviceName()));
+  if (is_fullscreen_app_list_enabled_) {
+    search_box_->SetAccessibleName(
+        l10n_util::GetStringUTF16(IDS_SEARCH_BOX_HINT_FULLSCREEN));
   } else {
     search_box_->SetAccessibleName(
         l10n_util::GetStringUTF16(IDS_SEARCH_BOX_HINT));
@@ -58,9 +58,9 @@
 
 void SearchResourceManager::OnSpeechRecognitionStateChanged(
     SpeechRecognitionState new_state) {
-  if (features::IsFullscreenAppListEnabled()) {
-    search_box_->SetHintText(l10n_util::GetStringFUTF16(
-        IDS_SEARCH_BOX_HINT_FULLSCREEN, ash::GetChromeOSDeviceName()));
+  if (is_fullscreen_app_list_enabled_) {
+    search_box_->SetHintText(
+        l10n_util::GetStringUTF16(IDS_SEARCH_BOX_HINT_FULLSCREEN));
   } else {
     search_box_->SetHintText(l10n_util::GetStringUTF16(
         (new_state == SPEECH_RECOGNITION_HOTWORD_LISTENING)
diff --git a/chrome/browser/ui/app_list/search/search_resource_manager.h b/chrome/browser/ui/app_list/search/search_resource_manager.h
index d7b957cd..6ef71ff 100644
--- a/chrome/browser/ui/app_list/search/search_resource_manager.h
+++ b/chrome/browser/ui/app_list/search/search_resource_manager.h
@@ -31,6 +31,8 @@
   SearchBoxModel* search_box_;
   SpeechUIModel* speech_ui_;
 
+  const bool is_fullscreen_app_list_enabled_;
+
   DISALLOW_COPY_AND_ASSIGN(SearchResourceManager);
 };
 
diff --git a/chrome/browser/ui/ash/session_controller_client.cc b/chrome/browser/ui/ash/session_controller_client.cc
index 89192bc..8b26869 100644
--- a/chrome/browser/ui/ash/session_controller_client.cc
+++ b/chrome/browser/ui/ash/session_controller_client.cc
@@ -185,6 +185,10 @@
   return g_instance;
 }
 
+void SessionControllerClient::PrepareForLock(base::OnceClosure callback) {
+  session_controller_->PrepareForLock(std::move(callback));
+}
+
 void SessionControllerClient::StartLock(StartLockCallback callback) {
   session_controller_->StartLock(callback);
 }
diff --git a/chrome/browser/ui/ash/session_controller_client.h b/chrome/browser/ui/ash/session_controller_client.h
index ca85a87e3..7bfcc6c3 100644
--- a/chrome/browser/ui/ash/session_controller_client.h
+++ b/chrome/browser/ui/ash/session_controller_client.h
@@ -48,6 +48,9 @@
 
   static SessionControllerClient* Get();
 
+  // Calls SessionController to prepare locking ash.
+  void PrepareForLock(base::OnceClosure callback);
+
   // Calls SessionController to start locking ash. |callback| will be invoked
   // to indicate whether the lock is successful. If |locked| is true, the post
   // lock animation is finished and ash is fully locked. Otherwise, the lock
diff --git a/chrome/browser/ui/ash/session_controller_client_unittest.cc b/chrome/browser/ui/ash/session_controller_client_unittest.cc
index 6ec4519..0111157 100644
--- a/chrome/browser/ui/ash/session_controller_client_unittest.cc
+++ b/chrome/browser/ui/ash/session_controller_client_unittest.cc
@@ -124,6 +124,7 @@
   }
   void SetUserSessionOrder(
       const std::vector<uint32_t>& user_session_order) override {}
+  void PrepareForLock(PrepareForLockCallback callback) override {}
   void StartLock(StartLockCallback callback) override {}
   void NotifyChromeLockAnimationsComplete() override {}
   void RunUnlockAnimation(RunUnlockAnimationCallback callback) override {}
diff --git a/chrome/browser/ui/bluetooth/bluetooth_chooser_controller.cc b/chrome/browser/ui/bluetooth/bluetooth_chooser_controller.cc
index 13f85f2..ae8a004 100644
--- a/chrome/browser/ui/bluetooth/bluetooth_chooser_controller.cc
+++ b/chrome/browser/ui/bluetooth/bluetooth_chooser_controller.cc
@@ -23,7 +23,7 @@
 
 Browser* GetBrowser() {
   chrome::ScopedTabbedBrowserDisplayer browser_displayer(
-      ProfileManager::GetActiveUserProfile());
+      ProfileManager::GetLastUsedProfileAllowedByPolicy());
   DCHECK(browser_displayer.browser());
   return browser_displayer.browser();
 }
diff --git a/chrome/browser/ui/cocoa/simple_message_box_bridge_views.mm b/chrome/browser/ui/cocoa/simple_message_box_bridge_views.mm
new file mode 100644
index 0000000..2d08ddd1
--- /dev/null
+++ b/chrome/browser/ui/cocoa/simple_message_box_bridge_views.mm
@@ -0,0 +1,70 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/callback.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "chrome/browser/ui/cocoa/simple_message_box_cocoa.h"
+#include "chrome/browser/ui/simple_message_box.h"
+#include "chrome/browser/ui/views/simple_message_box_views.h"
+#include "ui/base/material_design/material_design_controller.h"
+#include "ui/base/resource/resource_bundle.h"
+
+namespace {
+
+chrome::MessageBoxResult ShowMessageBoxImpl(
+    gfx::NativeWindow parent,
+    const base::string16& title,
+    const base::string16& message,
+    chrome::MessageBoxType type,
+    const base::string16& yes_text,
+    const base::string16& no_text,
+    const base::string16& checkbox_text) {
+  // These functions may be called early in browser startup, in which case the
+  // UI thread may not be ready to run or configured fully. In that case, fall
+  // back to native Cocoa message boxes.
+  if (base::MessageLoopForUI::IsCurrent() &&
+      base::RunLoop::IsRunningOnCurrentThread() &&
+      ResourceBundle::HasSharedInstance() &&
+      ui::MaterialDesignController::IsSecondaryUiMaterial()) {
+    return SimpleMessageBoxViews::Show(parent, title, message, type, yes_text,
+                                       no_text, checkbox_text);
+  }
+  // ShowMessageBoxCocoa() and NSAlerts in general don't support most of the
+  // above options at all.
+  return chrome::ShowMessageBoxCocoa(message, type, checkbox_text);
+}
+
+}  // namespace
+
+namespace chrome {
+
+void ShowWarningMessageBox(gfx::NativeWindow parent,
+                           const base::string16& title,
+                           const base::string16& message) {
+  ShowMessageBoxImpl(parent, title, message, MESSAGE_BOX_TYPE_WARNING,
+                     base::string16(), base::string16(), base::string16());
+}
+
+void ShowWarningMessageBoxWithCheckbox(
+    gfx::NativeWindow parent,
+    const base::string16& title,
+    const base::string16& message,
+    const base::string16& checkbox_text,
+    base::OnceCallback<void(bool checked)> callback) {
+  MessageBoxResult result =
+      ShowMessageBoxImpl(parent, title, message, MESSAGE_BOX_TYPE_WARNING,
+                         base::string16(), base::string16(), checkbox_text);
+  std::move(callback).Run(result == MESSAGE_BOX_RESULT_YES);
+}
+
+MessageBoxResult ShowQuestionMessageBox(gfx::NativeWindow parent,
+                                        const base::string16& title,
+                                        const base::string16& message) {
+  return ShowMessageBoxImpl(parent, title, message, MESSAGE_BOX_TYPE_QUESTION,
+                            base::string16(), base::string16(),
+                            base::string16());
+}
+
+}  // namespace chrome
diff --git a/chrome/browser/ui/cocoa/simple_message_box_cocoa.h b/chrome/browser/ui/cocoa/simple_message_box_cocoa.h
new file mode 100644
index 0000000..087c867
--- /dev/null
+++ b/chrome/browser/ui/cocoa/simple_message_box_cocoa.h
@@ -0,0 +1,18 @@
+// 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 CHROME_BROWSER_UI_COCOA_SIMPLE_MESSAGE_BOX_COCOA_H_
+#define CHROME_BROWSER_UI_COCOA_SIMPLE_MESSAGE_BOX_COCOA_H_
+
+#include "chrome/browser/ui/simple_message_box.h"
+
+namespace chrome {
+
+MessageBoxResult ShowMessageBoxCocoa(const base::string16& message,
+                                     MessageBoxType type,
+                                     const base::string16& checkbox_text);
+
+}  // namespace chrome
+
+#endif  // CHROME_BROWSER_UI_COCOA_SIMPLE_MESSAGE_BOX_COCOA_H_
diff --git a/chrome/browser/ui/cocoa/simple_message_box_cocoa.mm b/chrome/browser/ui/cocoa/simple_message_box_cocoa.mm
new file mode 100644
index 0000000..76db36a
--- /dev/null
+++ b/chrome/browser/ui/cocoa/simple_message_box_cocoa.mm
@@ -0,0 +1,60 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/simple_message_box.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include <utility>
+
+#include "base/callback.h"
+#include "base/mac/scoped_nsobject.h"
+#include "base/strings/sys_string_conversions.h"
+#include "chrome/browser/ui/simple_message_box_internal.h"
+#include "chrome/grit/generated_resources.h"
+#include "components/startup_metric_utils/browser/startup_metric_utils.h"
+#include "components/strings/grit/components_strings.h"
+#include "ui/base/l10n/l10n_util_mac.h"
+
+namespace chrome {
+
+MessageBoxResult ShowMessageBoxCocoa(const base::string16& message,
+                                     MessageBoxType type,
+                                     const base::string16& checkbox_text) {
+  startup_metric_utils::SetNonBrowserUIDisplayed();
+  if (internal::g_should_skip_message_box_for_test)
+    return MESSAGE_BOX_RESULT_YES;
+
+  NSAlert* alert = [[[NSAlert alloc] init] autorelease];
+  [alert setMessageText:base::SysUTF16ToNSString(message)];
+  [alert setAlertStyle:NSWarningAlertStyle];
+  if (type == MESSAGE_BOX_TYPE_QUESTION) {
+    [alert addButtonWithTitle:l10n_util::GetNSString(
+                                  IDS_CONFIRM_MESSAGEBOX_YES_BUTTON_LABEL)];
+    [alert addButtonWithTitle:l10n_util::GetNSString(
+                                  IDS_CONFIRM_MESSAGEBOX_NO_BUTTON_LABEL)];
+  } else {
+    [alert addButtonWithTitle:l10n_util::GetNSString(IDS_OK)];
+  }
+
+  base::scoped_nsobject<NSButton> checkbox;
+  if (!checkbox_text.empty()) {
+    checkbox.reset([[NSButton alloc] initWithFrame:NSZeroRect]);
+    [checkbox setButtonType:NSSwitchButton];
+    [checkbox setTitle:base::SysUTF16ToNSString(checkbox_text)];
+    [checkbox sizeToFit];
+    [alert setAccessoryView:checkbox];
+  }
+
+  NSInteger result = [alert runModal];
+  if (result == NSAlertSecondButtonReturn)
+    return MESSAGE_BOX_RESULT_NO;
+
+  if (!checkbox || ([checkbox state] == NSOnState))
+    return MESSAGE_BOX_RESULT_YES;
+
+  return MESSAGE_BOX_RESULT_NO;
+}
+
+}  // namespace chrome
diff --git a/chrome/browser/ui/cocoa/simple_message_box_mac.mm b/chrome/browser/ui/cocoa/simple_message_box_mac.mm
deleted file mode 100644
index 62507b53..0000000
--- a/chrome/browser/ui/cocoa/simple_message_box_mac.mm
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/simple_message_box.h"
-
-#import <Cocoa/Cocoa.h>
-
-#include <utility>
-
-#include "base/callback.h"
-#include "base/mac/scoped_nsobject.h"
-#include "base/strings/sys_string_conversions.h"
-#include "chrome/browser/ui/simple_message_box_internal.h"
-#include "chrome/grit/generated_resources.h"
-#include "components/startup_metric_utils/browser/startup_metric_utils.h"
-#include "components/strings/grit/components_strings.h"
-#include "ui/base/l10n/l10n_util_mac.h"
-
-namespace chrome {
-
-namespace {
-
-MessageBoxResult ShowMessageBox(gfx::NativeWindow parent,
-                                const base::string16& title,
-                                const base::string16& message,
-                                const base::string16& checkbox_text,
-                                MessageBoxType type) {
-  startup_metric_utils::SetNonBrowserUIDisplayed();
-  if (internal::g_should_skip_message_box_for_test)
-    return MESSAGE_BOX_RESULT_YES;
-
-  // Ignore the title; it's the window title on other platforms and ignorable.
-  NSAlert* alert = [[[NSAlert alloc] init] autorelease];
-  [alert setMessageText:base::SysUTF16ToNSString(message)];
-  [alert setAlertStyle:NSWarningAlertStyle];
-  if (type == MESSAGE_BOX_TYPE_QUESTION) {
-    [alert addButtonWithTitle:
-        l10n_util::GetNSString(IDS_CONFIRM_MESSAGEBOX_YES_BUTTON_LABEL)];
-    [alert addButtonWithTitle:
-        l10n_util::GetNSString(IDS_CONFIRM_MESSAGEBOX_NO_BUTTON_LABEL)];
-  } else {
-    [alert addButtonWithTitle:l10n_util::GetNSString(IDS_OK)];
-  }
-
-  base::scoped_nsobject<NSButton> checkbox;
-  if (!checkbox_text.empty()) {
-    checkbox.reset([[NSButton alloc] initWithFrame:NSZeroRect]);
-    [checkbox setButtonType:NSSwitchButton];
-    [checkbox setTitle:base::SysUTF16ToNSString(checkbox_text)];
-    [checkbox sizeToFit];
-    [alert setAccessoryView:checkbox];
-  }
-
-  NSInteger result = [alert runModal];
-  if (result == NSAlertSecondButtonReturn)
-    return MESSAGE_BOX_RESULT_NO;
-
-  if (!checkbox || ([checkbox state] == NSOnState))
-    return MESSAGE_BOX_RESULT_YES;
-
-  return MESSAGE_BOX_RESULT_NO;
-}
-
-}  // namespace
-
-void ShowWarningMessageBox(gfx::NativeWindow parent,
-                           const base::string16& title,
-                           const base::string16& message) {
-  ShowMessageBox(parent, title, message, base::string16(),
-                 MESSAGE_BOX_TYPE_WARNING);
-}
-
-void ShowWarningMessageBoxWithCheckbox(
-    gfx::NativeWindow parent,
-    const base::string16& title,
-    const base::string16& message,
-    const base::string16& checkbox_text,
-    base::OnceCallback<void(bool checked)> callback) {
-  ShowMessageBox(parent, title, message, checkbox_text,
-                 MESSAGE_BOX_TYPE_WARNING);
-  std::move(callback).Run(false);
-}
-
-MessageBoxResult ShowQuestionMessageBox(gfx::NativeWindow parent,
-                                        const base::string16& title,
-                                        const base::string16& message) {
-  return ShowMessageBox(parent, title, message, base::string16(),
-                        MESSAGE_BOX_TYPE_QUESTION);
-}
-
-bool CloseMessageBoxForTest(bool accept) {
-  NOTIMPLEMENTED();
-  return false;
-}
-
-}  // namespace chrome
diff --git a/chrome/browser/ui/cocoa/status_bubble_mac_unittest.mm b/chrome/browser/ui/cocoa/status_bubble_mac_unittest.mm
index bed808e0..9d1e201 100644
--- a/chrome/browser/ui/cocoa/status_bubble_mac_unittest.mm
+++ b/chrome/browser/ui/cocoa/status_bubble_mac_unittest.mm
@@ -200,8 +200,7 @@
   bubble_->SetURL(GURL("bad url"));
   EXPECT_FALSE(IsVisible());
   bubble_->SetURL(GURL("http://"));
-  EXPECT_TRUE(IsVisible());
-  EXPECT_NSEQ(@"http:", GetURLText());
+  EXPECT_FALSE(IsVisible());
   bubble_->SetURL(GURL("about:blank"));
   EXPECT_TRUE(IsVisible());
   EXPECT_NSEQ(@"about:blank", GetURLText());
diff --git a/chrome/browser/ui/libgtkui/gtk_ui.cc b/chrome/browser/ui/libgtkui/gtk_ui.cc
index 16b161c9..a38c6b8 100644
--- a/chrome/browser/ui/libgtkui/gtk_ui.cc
+++ b/chrome/browser/ui/libgtkui/gtk_ui.cc
@@ -58,6 +58,7 @@
 #include "ui/views/controls/button/blue_button.h"
 #include "ui/views/controls/button/label_button.h"
 #include "ui/views/controls/button/label_button_border.h"
+#include "ui/views/linux_ui/device_scale_factor_observer.h"
 #include "ui/views/linux_ui/window_button_order_observer.h"
 #include "ui/views/resources/grit/views_resources.h"
 
@@ -313,17 +314,6 @@
   return params;
 }
 
-float GetRawDeviceScaleFactor() {
-  if (display::Display::HasForceDeviceScaleFactor())
-    return display::Display::GetForcedDeviceScaleFactor();
-
-  GdkScreen* screen = gdk_screen_get_default();
-  gint scale = gdk_screen_get_monitor_scale_factor(
-      screen, gdk_screen_get_primary_monitor(screen));
-  gdouble resolution = gdk_screen_get_resolution(screen);
-  return resolution <= 0 ? scale : resolution * scale / kDefaultDPI;
-}
-
 views::LinuxUI::NonClientMiddleClickAction GetDefaultMiddleClickAction() {
   std::unique_ptr<base::Environment> env(base::Environment::Create());
   switch (base::nix::GetDesktopEnvironment(env.get())) {
@@ -412,19 +402,17 @@
 #if GTK_MAJOR_VERSION == 2
   native_theme_ = NativeThemeGtk2::instance();
   fake_window_ = chrome_gtk_frame_new();
-  gtk_widget_realize(fake_window_);  // Is this necessary?
 #elif GTK_MAJOR_VERSION == 3
   native_theme_ = NativeThemeGtk3::instance();
-  (void)fake_window_;  // Silence the unused warning.
+  fake_window_ = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 #else
 #error "Unsupported GTK version"
 #endif
+  gtk_widget_realize(fake_window_);
 }
 
 GtkUi::~GtkUi() {
-#if GTK_MAJOR_VERSION == 2
   gtk_widget_destroy(fake_window_);
-#endif
 }
 
 void OnThemeChanged(GObject* obj, GParamSpec* param, GtkUi* gtkui) {
@@ -438,6 +426,17 @@
   g_signal_connect_after(settings, "notify::gtk-icon-theme-name",
                          G_CALLBACK(OnThemeChanged), this);
 
+  GdkScreen* screen = gdk_screen_get_default();
+  // Listen for DPI changes.
+  g_signal_connect_after(screen, "notify::resolution",
+                         G_CALLBACK(OnDeviceScaleFactorMaybeChangedThunk),
+                         this);
+  // Listen for scale factor changes.  We would prefer to listen on
+  // |screen|, but there is no scale-factor property, so use an
+  // unmapped window instead.
+  g_signal_connect(fake_window_, "notify::scale-factor",
+                   G_CALLBACK(OnDeviceScaleFactorMaybeChangedThunk), this);
+
   LoadGtkValues();
 
 #if BUILDFLAG(ENABLE_BASIC_PRINTING)
@@ -699,12 +698,12 @@
     observer->OnWindowButtonOrderingChange(leading_buttons_, trailing_buttons_);
   }
 
-  observer_list_.AddObserver(observer);
+  window_button_order_observer_list_.AddObserver(observer);
 }
 
 void GtkUi::RemoveWindowButtonOrderObserver(
     views::WindowButtonOrderObserver* observer) {
-  observer_list_.RemoveObserver(observer);
+  window_button_order_observer_list_.RemoveObserver(observer);
 }
 
 void GtkUi::SetWindowButtonOrdering(
@@ -713,8 +712,10 @@
   leading_buttons_ = leading_buttons;
   trailing_buttons_ = trailing_buttons;
 
-  for (views::WindowButtonOrderObserver& observer : observer_list_)
+  for (views::WindowButtonOrderObserver& observer :
+       window_button_order_observer_list_) {
     observer.OnWindowButtonOrderingChange(leading_buttons_, trailing_buttons_);
+  }
 }
 
 void GtkUi::SetNonClientMiddleClickAction(NonClientMiddleClickAction action) {
@@ -766,6 +767,16 @@
   gdk_notify_startup_complete();
 }
 
+void GtkUi::AddDeviceScaleFactorObserver(
+    views::DeviceScaleFactorObserver* observer) {
+  device_scale_factor_observer_list_.AddObserver(observer);
+}
+
+void GtkUi::RemoveDeviceScaleFactorObserver(
+    views::DeviceScaleFactorObserver* observer) {
+  device_scale_factor_observer_list_.RemoveObserver(observer);
+}
+
 bool GtkUi::MatchEvent(const ui::Event& event,
                        std::vector<ui::TextEditCommandAuraLinux>* commands) {
   // Ensure that we have a keyboard handler.
@@ -775,6 +786,10 @@
   return key_bindings_handler_->MatchEvent(event, commands);
 }
 
+void GtkUi::OnDeviceScaleFactorMaybeChanged(void*, GParamSpec*) {
+  UpdateDeviceScaleFactor();
+}
+
 void GtkUi::SetScrollbarColors() {
   thumb_active_color_ = SkColorSetRGB(244, 244, 244);
   thumb_inactive_color_ = SkColorSetRGB(234, 234, 234);
@@ -1033,14 +1048,29 @@
   native_theme_->NotifyObservers();
 }
 
-void GtkUi::UpdateDeviceScaleFactor() {
-  // Note: Linux chrome currently does not support dynamic DPI
-  // changes.  This is to allow flags to override the DPI settings
-  // during startup.
-  float scale = GetRawDeviceScaleFactor();
+float GtkUi::GetRawDeviceScaleFactor() {
+  if (display::Display::HasForceDeviceScaleFactor())
+    return display::Display::GetForcedDeviceScaleFactor();
+
+  GdkScreen* screen = gdk_screen_get_default();
+  gint scale = gtk_widget_get_scale_factor(fake_window_);
+  gdouble resolution = gdk_screen_get_resolution(screen);
+  const float scale_factor =
+      resolution <= 0 ? scale : resolution * scale / kDefaultDPI;
   // Blacklist scaling factors <120% (crbug.com/484400) and round
   // to 1 decimal to prevent rendering problems (crbug.com/485183).
-  device_scale_factor_ = scale < 1.2f ? 1.0f : roundf(scale * 10) / 10;
+  return scale_factor < 1.2f ? 1.0f : roundf(scale_factor * 10) / 10;
+}
+
+void GtkUi::UpdateDeviceScaleFactor() {
+  float old_device_scale_factor = device_scale_factor_;
+  device_scale_factor_ = GetRawDeviceScaleFactor();
+  if (device_scale_factor_ != old_device_scale_factor) {
+    for (views::DeviceScaleFactorObserver& observer :
+         device_scale_factor_observer_list_) {
+      observer.OnDeviceScaleFactorChanged();
+    }
+  }
   UpdateDefaultFont();
 }
 
diff --git a/chrome/browser/ui/libgtkui/gtk_ui.h b/chrome/browser/ui/libgtkui/gtk_ui.h
index 627aab5..aa622ad 100644
--- a/chrome/browser/ui/libgtkui/gtk_ui.h
+++ b/chrome/browser/ui/libgtkui/gtk_ui.h
@@ -18,12 +18,14 @@
 #include "ui/views/linux_ui/linux_ui.h"
 #include "ui/views/window/frame_buttons.h"
 
+typedef struct _GParamSpec GParamSpec;
 typedef struct _GtkStyle GtkStyle;
 typedef struct _GtkWidget GtkWidget;
 
 namespace libgtkui {
 class Gtk2KeyBindingsHandler;
 class GConfListener;
+class DeviceScaleFactorObserver;
 
 // Interface to GTK2 desktop features.
 //
@@ -97,6 +99,10 @@
   bool UnityIsRunning() override;
   NonClientMiddleClickAction GetNonClientMiddleClickAction() override;
   void NotifyWindowManagerStartupComplete() override;
+  void AddDeviceScaleFactorObserver(
+      views::DeviceScaleFactorObserver* observer) override;
+  void RemoveDeviceScaleFactorObserver(
+      views::DeviceScaleFactorObserver* observer) override;
 
   // ui::TextEditKeybindingDelegate:
   bool MatchEvent(const ui::Event& event,
@@ -110,6 +116,12 @@
   typedef std::map<int, SkColor> ColorMap;
   typedef std::map<int, color_utils::HSL> TintMap;
 
+  CHROMEG_CALLBACK_1(GtkUi,
+                     void,
+                     OnDeviceScaleFactorMaybeChanged,
+                     void*,
+                     GParamSpec*);
+
   // This method returns the colors webkit will use for the scrollbars. When no
   // colors are specified by the GTK+ theme, this function averages of the
   // thumb part and of the track colors.
@@ -129,9 +141,12 @@
   bool GetChromeStyleColor(const char* sytle_property,
                            SkColor* ret_color) const;
 
+  float GetRawDeviceScaleFactor();
+
   ui::NativeTheme* native_theme_;
 
-  // A GtkWindow object with the class "ChromeGtkFrame".
+  // On Gtk2, A GtkWindow object with the class "ChromeGtkFrame".  On
+  // Gtk3, a regular GtkWindow.
   GtkWidget* fake_window_;
 
   // Colors calculated by LoadGtkValues() that are given to the
@@ -171,7 +186,12 @@
   std::unique_ptr<Gtk2KeyBindingsHandler> key_bindings_handler_;
 
   // Objects to notify when the window frame button order changes.
-  base::ObserverList<views::WindowButtonOrderObserver> observer_list_;
+  base::ObserverList<views::WindowButtonOrderObserver>
+      window_button_order_observer_list_;
+
+  // Objects to notify when the device scale factor changes.
+  base::ObserverList<views::DeviceScaleFactorObserver>
+      device_scale_factor_observer_list_;
 
   // Whether we should lower the window on a middle click to the non client
   // area.
diff --git a/chrome/browser/ui/simple_message_box.h b/chrome/browser/ui/simple_message_box.h
index 1dd0ce1..ef8a75b 100644
--- a/chrome/browser/ui/simple_message_box.h
+++ b/chrome/browser/ui/simple_message_box.h
@@ -19,6 +19,10 @@
 
   // User chose YES or OK. If there's a checkbox, then the checkbox was checked.
   MESSAGE_BOX_RESULT_YES = 1,
+
+  // Message box was displayed asynchronously and is pending a real result,
+  // which will be delivered via callback.
+  MESSAGE_BOX_RESULT_DEFERRED = 2,
 };
 
 enum MessageBoxType {
diff --git a/chrome/browser/ui/tab_helpers.cc b/chrome/browser/ui/tab_helpers.cc
index 4becadd..e98dac63 100644
--- a/chrome/browser/ui/tab_helpers.cc
+++ b/chrome/browser/ui/tab_helpers.cc
@@ -22,6 +22,7 @@
 #include "chrome/browser/history/history_tab_helper.h"
 #include "chrome/browser/history/top_sites_factory.h"
 #include "chrome/browser/infobars/infobar_service.h"
+#include "chrome/browser/installable/installable_manager.h"
 #include "chrome/browser/media/media_engagement_service.h"
 #include "chrome/browser/metrics/desktop_session_duration/desktop_session_duration_observer.h"
 #include "chrome/browser/metrics/renderer_uptime_web_contents_observer.h"
@@ -202,6 +203,7 @@
                             web_contents->GetBrowserContext())).get());
   HistoryTabHelper::CreateForWebContents(web_contents);
   InfoBarService::CreateForWebContents(web_contents);
+  InstallableManager::CreateForWebContents(web_contents);
   metrics::RendererUptimeWebContentsObserver::CreateForWebContents(
       web_contents);
   if (content::IsBrowserSideNavigationEnabled())
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index a6fb085..37094f1 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -72,6 +72,7 @@
 #include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
 #include "chrome/browser/ui/views/frame/top_container_view.h"
 #include "chrome/browser/ui/views/frame/web_contents_close_handler.h"
+#include "chrome/browser/ui/views/fullscreen_control/fullscreen_control_host.h"
 #include "chrome/browser/ui/views/ime/ime_warning_bubble_view.h"
 #include "chrome/browser/ui/views/infobars/infobar_container_view.h"
 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
@@ -1645,6 +1646,19 @@
   chrome::MaybeShowInvertBubbleView(this);
 }
 
+FullscreenControlHost* BrowserView::GetFullscreenControlHost() {
+  if (!fullscreen_control_host_) {
+    // This is a do-nothing view that controls the z-order of the fullscreen
+    // control host. See DropdownBarHost::SetHostViewNative() for more details.
+    auto fullscreen_exit_host_view = base::MakeUnique<views::View>();
+    fullscreen_control_host_ = base::MakeUnique<FullscreenControlHost>(
+        this, fullscreen_exit_host_view.get());
+    AddChildView(fullscreen_exit_host_view.release());
+  }
+
+  return fullscreen_control_host_.get();
+}
+
 views::View* BrowserView::GetInitiallyFocusedView() {
   return nullptr;
 }
@@ -1951,9 +1965,25 @@
 
 void BrowserView::ViewHierarchyChanged(
     const ViewHierarchyChangedDetails& details) {
-  if (!initialized_ && details.is_add && details.child == this && GetWidget()) {
+  if (details.child != this)
+    return;
+
+  // On removal, this class may not have a widget anymore, so go to the parent.
+  auto* widget = details.is_add ? GetWidget() : details.parent->GetWidget();
+  if (!widget)
+    return;
+
+  if (!initialized_ && details.is_add) {
     InitViews();
     initialized_ = true;
+    if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+            switches::kEnableExperimentalFullscreenExitUI)) {
+      widget->GetNativeView()->AddPreTargetHandler(GetFullscreenControlHost());
+    }
+  } else if (fullscreen_control_host_) {
+    auto* native_view = widget->GetNativeView();
+    if (native_view)
+      native_view->RemovePreTargetHandler(fullscreen_control_host_.get());
   }
 }
 
@@ -2331,6 +2361,8 @@
     // Hide the fullscreen bubble as soon as possible, since the mode toggle can
     // take enough time for the user to notice.
     exclusive_access_bubble_.reset();
+    if (fullscreen_control_host_)
+      fullscreen_control_host_->Hide(false);
   }
 
   // Toggle fullscreen mode.
diff --git a/chrome/browser/ui/views/frame/browser_view.h b/chrome/browser/ui/views/frame/browser_view.h
index d340404..0a401aa 100644
--- a/chrome/browser/ui/views/frame/browser_view.h
+++ b/chrome/browser/ui/views/frame/browser_view.h
@@ -54,6 +54,7 @@
 class ContentsLayoutManager;
 class DownloadShelfView;
 class ExclusiveAccessBubbleViews;
+class FullscreenControlHost;
 class InfoBarContainerView;
 class LocationBarView;
 class NewBackShortcutBubble;
@@ -477,6 +478,10 @@
   // Called by BrowserFrame during theme changes.
   void NativeThemeUpdated(const ui::NativeTheme* theme);
 
+  // Gets the FullscreenControlHost for this BrowserView, creating it if it does
+  // not yet exist.
+  FullscreenControlHost* GetFullscreenControlHost();
+
  private:
   // Do not friend BrowserViewLayout. Use the BrowserViewLayoutDelegate
   // interface to keep these two classes decoupled and testable.
@@ -704,6 +709,8 @@
 
   std::unique_ptr<BrowserWindowHistogramHelper> histogram_helper_;
 
+  std::unique_ptr<FullscreenControlHost> fullscreen_control_host_;
+
   mutable base::WeakPtrFactory<BrowserView> activate_modal_dialog_factory_{
       this};
 
diff --git a/chrome/browser/ui/views/fullscreen_control/OWNERS b/chrome/browser/ui/views/fullscreen_control/OWNERS
new file mode 100644
index 0000000..18583cd0
--- /dev/null
+++ b/chrome/browser/ui/views/fullscreen_control/OWNERS
@@ -0,0 +1 @@
+robliao@chromium.org
diff --git a/chrome/browser/ui/views/fullscreen_control/fullscreen_control_host.cc b/chrome/browser/ui/views/fullscreen_control/fullscreen_control_host.cc
new file mode 100644
index 0000000..f55aab7
--- /dev/null
+++ b/chrome/browser/ui/views/fullscreen_control/fullscreen_control_host.cc
@@ -0,0 +1,116 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/views/fullscreen_control/fullscreen_control_host.h"
+
+#include "base/i18n/rtl.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/browser/ui/views/fullscreen_control/fullscreen_control_view.h"
+#include "ui/events/event.h"
+#include "ui/events/event_constants.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/views/view.h"
+
+namespace {
+
+// +----------------------------+
+// |                |  Control  |
+// |                |           |
+// |                +-----------+ <-- Height
+// |                            | <-- Height * kExitHeightScaleFactor
+// |          Screen            |       Buffer for mouse moves or pointer events
+// |                            |       before closing the fullscreen exit
+// |                            |       control.
+// +----------------------------+
+constexpr float kExitHeightScaleFactor = 1.5f;
+
+// +----------------------------+
+// |                            |
+// |                            |
+// |                            | <-- kShowFullscreenExitControlHeight
+// |          Screen            |       If a mouse move or pointer event is
+// |                            |       above this line, show the fullscreen
+// |                            |       exit control.
+// |                            |
+// +----------------------------+
+constexpr float kShowFullscreenExitControlHeight = 3.f;
+
+}  // namespace
+
+FullscreenControlHost::FullscreenControlHost(BrowserView* browser_view,
+                                             views::View* host_view)
+    : DropdownBarHost(browser_view),
+      browser_view_(browser_view),
+      fullscreen_control_view_(new FullscreenControlView(browser_view)) {
+  Init(host_view, fullscreen_control_view_, fullscreen_control_view_);
+}
+
+FullscreenControlHost::~FullscreenControlHost() = default;
+
+bool FullscreenControlHost::AcceleratorPressed(
+    const ui::Accelerator& accelerator) {
+  return false;
+}
+
+bool FullscreenControlHost::CanHandleAccelerators() const {
+  return false;
+}
+
+gfx::Rect FullscreenControlHost::GetDialogPosition(
+    gfx::Rect avoid_overlapping_rect) {
+  gfx::Rect widget_bounds;
+  GetWidgetBounds(&widget_bounds);
+  if (widget_bounds.IsEmpty())
+    return gfx::Rect();
+
+  // Ask the view how large an area it needs to draw on.
+  gfx::Size preferred_size = view()->GetPreferredSize();
+
+  preferred_size.SetToMin(widget_bounds.size());
+
+  // Place the view in the top right corner of the widget boundaries (top left
+  // for RTL languages).
+  gfx::Rect view_location;
+  gfx::Point origin = widget_bounds.origin();
+  if (!base::i18n::IsRTL())
+    origin.set_x(widget_bounds.right() - preferred_size.width());
+  return gfx::Rect(origin, preferred_size);
+}
+
+void FullscreenControlHost::OnMouseEvent(ui::MouseEvent* event) {
+  if (event->type() == ui::ET_MOUSE_MOVED)
+    HandleFullScreenControlVisibility(event);
+}
+
+void FullscreenControlHost::OnTouchEvent(ui::TouchEvent* event) {
+  if (event->type() == ui::ET_TOUCH_MOVED)
+    HandleFullScreenControlVisibility(event);
+}
+
+void FullscreenControlHost::OnGestureEvent(ui::GestureEvent* event) {
+  if (event->type() == ui::ET_GESTURE_LONG_PRESS && !IsAnimating() &&
+      browser_view_->IsFullscreen() && !IsVisible()) {
+    Show(true);
+  }
+}
+
+void FullscreenControlHost::HandleFullScreenControlVisibility(
+    const ui::LocatedEvent* event) {
+  if (IsAnimating())
+    return;
+
+  if (browser_view_->IsFullscreen()) {
+    if (IsVisible()) {
+      float control_height = static_cast<float>(view()->height());
+      float y_limit = control_height * kExitHeightScaleFactor;
+      if (event->y() >= y_limit)
+        Hide(true);
+    } else {
+      if (event->y() <= kShowFullscreenExitControlHeight)
+        Show(true);
+    }
+  } else if (IsVisible()) {
+    Hide(true);
+  }
+}
diff --git a/chrome/browser/ui/views/fullscreen_control/fullscreen_control_host.h b/chrome/browser/ui/views/fullscreen_control/fullscreen_control_host.h
new file mode 100644
index 0000000..0047377
--- /dev/null
+++ b/chrome/browser/ui/views/fullscreen_control/fullscreen_control_host.h
@@ -0,0 +1,58 @@
+// 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 CHROME_BROWSER_UI_VIEWS_FULLSCREEN_CONTROL_FULLSCREEN_CONTROL_HOST_H_
+#define CHROME_BROWSER_UI_VIEWS_FULLSCREEN_CONTROL_FULLSCREEN_CONTROL_HOST_H_
+
+#include "base/macros.h"
+#include "chrome/browser/ui/views/dropdown_bar_host.h"
+#include "ui/events/event_handler.h"
+
+class BrowserView;
+class FullscreenControlView;
+
+namespace ui {
+class LocatedEvent;
+class GestureEvent;
+class MouseEvent;
+class TouchEvent;
+}  // namespace ui
+
+namespace views {
+class View;
+}  // namespace views
+
+class FullscreenControlHost : public DropdownBarHost, public ui::EventHandler {
+ public:
+  // |host_view| allows the host to control the z-order of the underlying view.
+  explicit FullscreenControlHost(BrowserView* browser_view,
+                                 views::View* host_view);
+  ~FullscreenControlHost() override;
+
+  // DropdownBarHost:
+  bool AcceleratorPressed(const ui::Accelerator& accelerator) override;
+  bool CanHandleAccelerators() const override;
+  gfx::Rect GetDialogPosition(gfx::Rect avoid_overlapping_rect) override;
+
+  // ui::EventHandler:
+  void OnMouseEvent(ui::MouseEvent* event) override;
+  void OnTouchEvent(ui::TouchEvent* event) override;
+  void OnGestureEvent(ui::GestureEvent* event) override;
+
+  FullscreenControlView* fullscreen_control_view() {
+    return fullscreen_control_view_;
+  }
+
+ private:
+  void HandleFullScreenControlVisibility(const ui::LocatedEvent* event);
+
+  BrowserView* const browser_view_;
+
+  // Owned by DropdownBarHost.
+  FullscreenControlView* const fullscreen_control_view_;
+
+  DISALLOW_COPY_AND_ASSIGN(FullscreenControlHost);
+};
+
+#endif  // CHROME_BROWSER_UI_VIEWS_FULLSCREEN_CONTROL_FULLSCREEN_CONTROL_HOST_H_
diff --git a/chrome/browser/ui/views/fullscreen_control/fullscreen_control_view.cc b/chrome/browser/ui/views/fullscreen_control/fullscreen_control_view.cc
new file mode 100644
index 0000000..144c8188
--- /dev/null
+++ b/chrome/browser/ui/views/fullscreen_control/fullscreen_control_view.cc
@@ -0,0 +1,50 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/views/fullscreen_control/fullscreen_control_view.h"
+
+#include <memory>
+
+#include "base/memory/ptr_util.h"
+#include "chrome/grit/generated_resources.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/gfx/geometry/insets.h"
+#include "ui/views/background.h"
+#include "ui/views/controls/button/label_button.h"
+#include "ui/views/layout/box_layout.h"
+
+namespace {
+
+// Spacing applied to all sides of the border of the control.
+constexpr int kSpacingInsetsAllSides = 10;
+
+// Spacing applied between controls of FullscreenControlView.
+constexpr int kBetweenChildSpacing = 10;
+
+}  // namespace
+
+FullscreenControlView::FullscreenControlView(BrowserView* browser_view)
+    : browser_view_(browser_view),
+      exit_fullscreen_button_(new views::LabelButton(
+          this,
+          l10n_util::GetStringUTF16(
+              IDS_FULLSCREEN_EXIT_CONTROL_EXIT_FULLSCREEN))) {
+  AddChildView(exit_fullscreen_button_);
+  SetLayoutManager(new views::BoxLayout(views::BoxLayout::kHorizontal,
+                                        gfx::Insets(kSpacingInsetsAllSides),
+                                        kBetweenChildSpacing));
+  // TODO(robliao): If we decide to move forward with this, use themes.
+  SetBackground(views::CreateSolidBackground(SK_ColorWHITE));
+}
+
+FullscreenControlView::~FullscreenControlView() = default;
+
+void FullscreenControlView::SetFocusAndSelection(bool select_all) {}
+
+void FullscreenControlView::ButtonPressed(views::Button* sender,
+                                          const ui::Event& event) {
+  if (sender == exit_fullscreen_button_)
+    browser_view_->ExitFullscreen();
+}
diff --git a/chrome/browser/ui/views/fullscreen_control/fullscreen_control_view.h b/chrome/browser/ui/views/fullscreen_control/fullscreen_control_view.h
new file mode 100644
index 0000000..f35d012
--- /dev/null
+++ b/chrome/browser/ui/views/fullscreen_control/fullscreen_control_view.h
@@ -0,0 +1,37 @@
+// 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 CHROME_BROWSER_UI_VIEWS_FULLSCREEN_CONTROL_FULLSCREEN_CONTROL_VIEW_H_
+#define CHROME_BROWSER_UI_VIEWS_FULLSCREEN_CONTROL_FULLSCREEN_CONTROL_VIEW_H_
+
+#include "base/macros.h"
+#include "chrome/browser/ui/views/dropdown_bar_host_delegate.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/browser/ui/views/fullscreen_control/fullscreen_control_host.h"
+#include "ui/views/controls/button/button.h"
+#include "ui/views/view.h"
+
+class FullscreenControlView : public views::View,
+                              public DropdownBarHostDelegate,
+                              public views::ButtonListener {
+ public:
+  explicit FullscreenControlView(BrowserView* browser_view);
+  ~FullscreenControlView() override;
+
+  // DropdownBarHostDelegate:
+  void SetFocusAndSelection(bool select_all) override;
+
+  // views::ButtonListener:
+  void ButtonPressed(views::Button* sender, const ui::Event& event) override;
+
+  views::Button* exit_fullscreen_button() { return exit_fullscreen_button_; }
+
+ private:
+  BrowserView* const browser_view_;
+  views::Button* const exit_fullscreen_button_;
+
+  DISALLOW_COPY_AND_ASSIGN(FullscreenControlView);
+};
+
+#endif  // CHROME_BROWSER_UI_VIEWS_FULLSCREEN_CONTROL_FULLSCREEN_CONTROL_VIEW_H_
diff --git a/chrome/browser/ui/views/fullscreen_control/fullscreen_control_view_interactive_uitest.cc b/chrome/browser/ui/views/fullscreen_control/fullscreen_control_view_interactive_uitest.cc
new file mode 100644
index 0000000..ae741b6
--- /dev/null
+++ b/chrome/browser/ui/views/fullscreen_control/fullscreen_control_view_interactive_uitest.cc
@@ -0,0 +1,76 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/command_line.h"
+#include "base/macros.h"
+#include "chrome/browser/ui/exclusive_access/exclusive_access_bubble_type.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/browser/ui/views/fullscreen_control/fullscreen_control_host.h"
+#include "chrome/browser/ui/views/fullscreen_control/fullscreen_control_view.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/events/event.h"
+#include "ui/views/controls/button/button.h"
+#include "ui/views/view.h"
+#include "url/gurl.h"
+
+class FullscreenControlViewTest : public InProcessBrowserTest {
+ public:
+  FullscreenControlViewTest() = default;
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    command_line->AppendSwitch(switches::kEnableExperimentalFullscreenExitUI);
+  }
+
+ protected:
+  FullscreenControlHost* GetFullscreenControlHost() {
+    BrowserView* browser_view =
+        BrowserView::GetBrowserViewForBrowser(browser());
+    return browser_view->GetFullscreenControlHost();
+  }
+
+  FullscreenControlView* GetFullscreenControlView() {
+    return GetFullscreenControlHost()->fullscreen_control_view();
+  }
+
+  views::Button* GetFullscreenExitButton() {
+    return GetFullscreenControlView()->exit_fullscreen_button();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(FullscreenControlViewTest);
+};
+
+IN_PROC_BROWSER_TEST_F(FullscreenControlViewTest, MouseExitFullscreen) {
+  GURL blank_url("about:blank");
+  ui_test_utils::NavigateToURL(browser(), blank_url);
+  BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser());
+
+  browser_view->EnterFullscreen(
+      blank_url, ExclusiveAccessBubbleType::EXCLUSIVE_ACCESS_BUBBLE_TYPE_NONE);
+
+  ASSERT_TRUE(browser_view->IsFullscreen());
+
+  // Simulate moving the mouse to the top of the screen, which should show the
+  // fullscreen exit UI.
+  FullscreenControlHost* host = GetFullscreenControlHost();
+  EXPECT_FALSE(host->IsVisible());
+  ui::MouseEvent mouse_move(ui::ET_MOUSE_MOVED, gfx::Point(1, 1), gfx::Point(),
+                            base::TimeTicks(), 0, 0);
+  host->OnMouseEvent(&mouse_move);
+  EXPECT_TRUE(host->IsVisible());
+
+  // Simulate clicking on the fullscreen exit button, which should cause the
+  // browser to exit fullscreen and hide the fullscreen exit control.
+  ui::MouseEvent mouse_click(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
+                             base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON,
+                             ui::EF_LEFT_MOUSE_BUTTON);
+  GetFullscreenControlView()->ButtonPressed(GetFullscreenExitButton(),
+                                            mouse_click);
+
+  EXPECT_FALSE(host->IsVisible());
+  EXPECT_FALSE(browser_view->IsFullscreen());
+}
diff --git a/chrome/browser/ui/views/payments/payment_request_completion_status_metrics_browsertest.cc b/chrome/browser/ui/views/payments/payment_request_completion_status_metrics_browsertest.cc
index 08ad90c8..6e93bce 100644
--- a/chrome/browser/ui/views/payments/payment_request_completion_status_metrics_browsertest.cc
+++ b/chrome/browser/ui/views/payments/payment_request_completion_status_metrics_browsertest.cc
@@ -235,4 +235,27 @@
       JourneyLogger::ABORT_REASON_USER_NAVIGATION, 1);
 }
 
+class PaymentRequestInitiatedCompletionStatusMetricsTest
+    : public PaymentRequestBrowserTestBase {
+ protected:
+  PaymentRequestInitiatedCompletionStatusMetricsTest()
+      : PaymentRequestBrowserTestBase("/initiated_test.html") {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(PaymentRequestInitiatedCompletionStatusMetricsTest);
+};
+
+IN_PROC_BROWSER_TEST_F(PaymentRequestInitiatedCompletionStatusMetricsTest,
+                       Aborted_NotShown) {
+  // The Payment Request will have been initiated on page load, so it won't be
+  // logged.
+  base::HistogramTester histogram_tester;
+
+  // Navigate away.
+  NavigateTo("/payment_request_email_test.html");
+
+  // No abort reason should be logged.
+  histogram_tester.ExpectTotalCount("PaymentRequest.CheckoutFunnel.Aborted", 0);
+}
+
 }  // namespace payments
diff --git a/chrome/browser/ui/views/simple_message_box_views.cc b/chrome/browser/ui/views/simple_message_box_views.cc
index 8f6194e..6940d06 100644
--- a/chrome/browser/ui/views/simple_message_box_views.cc
+++ b/chrome/browser/ui/views/simple_message_box_views.cc
@@ -14,12 +14,14 @@
 #include "build/build_config.h"
 #include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/browser/ui/simple_message_box_internal.h"
+#include "chrome/browser/ui/views/simple_message_box_views.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/constrained_window/constrained_window_views.h"
 #include "components/startup_metric_utils/browser/startup_metric_utils.h"
 #include "components/strings/grit/components_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
+#include "ui/base/ui_features.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/views/controls/message_box_view.h"
 #include "ui/views/widget/widget.h"
@@ -30,102 +32,131 @@
 #include "ui/views/win/hwnd_util.h"
 #endif
 
-namespace chrome {
-
-namespace {
-
-class SimpleMessageBoxViews : public views::DialogDelegate {
- public:
-  using MessageBoxResultCallback =
-      base::OnceCallback<void(MessageBoxResult result)>;
-
-  SimpleMessageBoxViews(const base::string16& title,
-                        const base::string16& message,
-                        MessageBoxType type,
-                        const base::string16& yes_text,
-                        const base::string16& no_text,
-                        const base::string16& checkbox_text,
-                        bool is_system_modal);
-  ~SimpleMessageBoxViews() override;
-
-  void Run(MessageBoxResultCallback result_callback);
-
-  // Overridden from views::DialogDelegate:
-  int GetDialogButtons() const override;
-  base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
-  bool Cancel() override;
-  bool Accept() override;
-
-  // Overridden from views::WidgetDelegate:
-  base::string16 GetWindowTitle() const override;
-  void DeleteDelegate() override;
-  ui::ModalType GetModalType() const override;
-  views::View* GetContentsView() override;
-  views::Widget* GetWidget() override;
-  const views::Widget* GetWidget() const override;
-
- private:
-  void Done();
-
-  const base::string16 window_title_;
-  const MessageBoxType type_;
-  base::string16 yes_text_;
-  base::string16 no_text_;
-  MessageBoxResult result_;
-  views::MessageBoxView* message_box_view_;
-  MessageBoxResultCallback result_callback_;
-  bool is_system_modal_;
-
-  DISALLOW_COPY_AND_ASSIGN(SimpleMessageBoxViews);
-};
-
 // The currently showing message box, if there is one. Used for tests.
 SimpleMessageBoxViews* g_current_message_box = nullptr;
 
+namespace {
+#if defined(OS_WIN)
+UINT GetMessageBoxFlagsFromType(chrome::MessageBoxType type) {
+  UINT flags = MB_SETFOREGROUND;
+  switch (type) {
+    case chrome::MESSAGE_BOX_TYPE_WARNING:
+      return flags | MB_OK | MB_ICONWARNING;
+    case chrome::MESSAGE_BOX_TYPE_QUESTION:
+      return flags | MB_YESNO | MB_ICONQUESTION;
+  }
+  NOTREACHED();
+  return flags | MB_OK | MB_ICONWARNING;
+}
+#endif
+
+// static
+chrome::MessageBoxResult ShowSync(gfx::NativeWindow parent,
+                                  const base::string16& title,
+                                  const base::string16& message,
+                                  chrome::MessageBoxType type,
+                                  const base::string16& yes_text,
+                                  const base::string16& no_text,
+                                  const base::string16& checkbox_text) {
+  chrome::MessageBoxResult result = chrome::MESSAGE_BOX_RESULT_NO;
+
+  // TODO(pkotwicz): Exit message loop when the dialog is closed by some other
+  // means than |Cancel| or |Accept|. crbug.com/404385
+  base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
+  base::MessageLoopForUI::ScopedNestableTaskAllower allow_nested(loop);
+  base::RunLoop run_loop;
+
+  SimpleMessageBoxViews::Show(
+      parent, title, message, type, yes_text, no_text, checkbox_text,
+      base::Bind(
+          [](base::RunLoop* run_loop, chrome::MessageBoxResult* out_result,
+             chrome::MessageBoxResult messagebox_result) {
+            *out_result = messagebox_result;
+            run_loop->Quit();
+          },
+          &run_loop, &result));
+
+  run_loop.Run();
+  return result;
+}
+}  // namespace
+
 ////////////////////////////////////////////////////////////////////////////////
 // SimpleMessageBoxViews, public:
 
-SimpleMessageBoxViews::SimpleMessageBoxViews(
+// static
+chrome::MessageBoxResult SimpleMessageBoxViews::Show(
+    gfx::NativeWindow parent,
     const base::string16& title,
     const base::string16& message,
-    MessageBoxType type,
+    chrome::MessageBoxType type,
     const base::string16& yes_text,
     const base::string16& no_text,
     const base::string16& checkbox_text,
-    bool is_system_modal)
-    : window_title_(title),
-      type_(type),
-      yes_text_(yes_text),
-      no_text_(no_text),
-      result_(MESSAGE_BOX_RESULT_NO),
-      message_box_view_(new views::MessageBoxView(
-          views::MessageBoxView::InitParams(message))),
-      is_system_modal_(is_system_modal) {
-  if (yes_text_.empty()) {
-    yes_text_ =
-        type_ == MESSAGE_BOX_TYPE_QUESTION
-            ? l10n_util::GetStringUTF16(IDS_CONFIRM_MESSAGEBOX_YES_BUTTON_LABEL)
-            : l10n_util::GetStringUTF16(IDS_OK);
+    SimpleMessageBoxViews::MessageBoxResultCallback callback) {
+  if (!callback)
+    return ShowSync(parent, title, message, type, yes_text, no_text,
+                    checkbox_text);
+
+  startup_metric_utils::SetNonBrowserUIDisplayed();
+  if (chrome::internal::g_should_skip_message_box_for_test) {
+    std::move(callback).Run(chrome::MESSAGE_BOX_RESULT_YES);
+    return chrome::MESSAGE_BOX_RESULT_DEFERRED;
   }
 
-  if (no_text_.empty() && type_ == MESSAGE_BOX_TYPE_QUESTION)
-    no_text_ = l10n_util::GetStringUTF16(IDS_CANCEL);
+// Views dialogs cannot be shown outside the UI thread message loop or if the
+// ResourceBundle is not initialized yet.
+// Fallback to logging with a default response or a Windows MessageBox.
+#if defined(OS_WIN)
+  if (!base::MessageLoopForUI::IsCurrent() ||
+      !base::RunLoop::IsRunningOnCurrentThread() ||
+      !ResourceBundle::HasSharedInstance()) {
+    LOG_IF(ERROR, !checkbox_text.empty()) << "Dialog checkbox won't be shown";
+    int result = ui::MessageBox(views::HWNDForNativeWindow(parent), message,
+                                title, GetMessageBoxFlagsFromType(type));
+    std::move(callback).Run((result == IDYES || result == IDOK)
+                                ? chrome::MESSAGE_BOX_RESULT_YES
+                                : chrome::MESSAGE_BOX_RESULT_NO);
+    return chrome::MESSAGE_BOX_RESULT_DEFERRED;
+  }
+#else
+  if (!base::MessageLoopForUI::IsCurrent() ||
+      !ResourceBundle::HasSharedInstance()) {
+    LOG(ERROR) << "Unable to show a dialog outside the UI thread message loop: "
+               << title << " - " << message;
+    std::move(callback).Run(chrome::MESSAGE_BOX_RESULT_NO);
+    return chrome::MESSAGE_BOX_RESULT_DEFERRED;
+  }
+#endif
 
-  if (!checkbox_text.empty())
-    message_box_view_->SetCheckBoxLabel(checkbox_text);
-  chrome::RecordDialogCreation(chrome::DialogIdentifier::SIMPLE_MESSAGE_BOX);
-}
+  bool is_system_modal = !parent;
 
-SimpleMessageBoxViews::~SimpleMessageBoxViews() {
-}
+#if defined(OS_MACOSX)
+  // Mac does not support system modals, so never ask SimpleMessageBoxViews to
+  // be system modal.
+  is_system_modal = false;
+#endif
 
-void SimpleMessageBoxViews::Run(MessageBoxResultCallback result_callback) {
-  g_current_message_box = this;
-  result_callback_ = std::move(result_callback);
+  SimpleMessageBoxViews* dialog = new SimpleMessageBoxViews(
+      title, message, type, yes_text, no_text, checkbox_text, is_system_modal);
+  views::Widget* widget =
+      constrained_window::CreateBrowserModalDialogViews(dialog, parent);
+
+#if defined(OS_MACOSX)
+  // Mac does not support system modal dialogs. If there is no parent window to
+  // attach to, move the dialog's widget on top so other windows do not obscure
+  // it.
+  if (!parent)
+    widget->SetAlwaysOnTop(true);
+#endif
+
+  widget->Show();
+  dialog->Run(std::move(callback));
+  return chrome::MESSAGE_BOX_RESULT_DEFERRED;
 }
 
 int SimpleMessageBoxViews::GetDialogButtons() const {
-  if (type_ == MESSAGE_BOX_TYPE_QUESTION)
+  if (type_ == chrome::MESSAGE_BOX_TYPE_QUESTION)
     return ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL;
 
   return ui::DIALOG_BUTTON_OK;
@@ -139,7 +170,7 @@
 }
 
 bool SimpleMessageBoxViews::Cancel() {
-  result_ = MESSAGE_BOX_RESULT_NO;
+  result_ = chrome::MESSAGE_BOX_RESULT_NO;
   Done();
   return true;
 }
@@ -147,9 +178,9 @@
 bool SimpleMessageBoxViews::Accept() {
   if (!message_box_view_->HasCheckBox() ||
       message_box_view_->IsCheckBoxSelected()) {
-    result_ = MESSAGE_BOX_RESULT_YES;
+    result_ = chrome::MESSAGE_BOX_RESULT_YES;
   } else {
-    result_ = MESSAGE_BOX_RESULT_NO;
+    result_ = chrome::MESSAGE_BOX_RESULT_NO;
   }
 
   Done();
@@ -183,105 +214,53 @@
 ////////////////////////////////////////////////////////////////////////////////
 // SimpleMessageBoxViews, private:
 
+SimpleMessageBoxViews::SimpleMessageBoxViews(
+    const base::string16& title,
+    const base::string16& message,
+    chrome::MessageBoxType type,
+    const base::string16& yes_text,
+    const base::string16& no_text,
+    const base::string16& checkbox_text,
+    bool is_system_modal)
+    : window_title_(title),
+      type_(type),
+      yes_text_(yes_text),
+      no_text_(no_text),
+      result_(chrome::MESSAGE_BOX_RESULT_NO),
+      message_box_view_(new views::MessageBoxView(
+          views::MessageBoxView::InitParams(message))),
+      is_system_modal_(is_system_modal) {
+  if (yes_text_.empty()) {
+    yes_text_ =
+        type_ == chrome::MESSAGE_BOX_TYPE_QUESTION
+            ? l10n_util::GetStringUTF16(IDS_CONFIRM_MESSAGEBOX_YES_BUTTON_LABEL)
+            : l10n_util::GetStringUTF16(IDS_OK);
+  }
+
+  if (no_text_.empty() && type_ == chrome::MESSAGE_BOX_TYPE_QUESTION)
+    no_text_ = l10n_util::GetStringUTF16(IDS_CANCEL);
+
+  if (!checkbox_text.empty())
+    message_box_view_->SetCheckBoxLabel(checkbox_text);
+  chrome::RecordDialogCreation(chrome::DialogIdentifier::SIMPLE_MESSAGE_BOX);
+}
+
+SimpleMessageBoxViews::~SimpleMessageBoxViews() {}
+
+void SimpleMessageBoxViews::Run(MessageBoxResultCallback result_callback) {
+  g_current_message_box = this;
+  result_callback_ = std::move(result_callback);
+}
+
 void SimpleMessageBoxViews::Done() {
   CHECK(!result_callback_.is_null());
   std::move(result_callback_).Run(result_);
   g_current_message_box = nullptr;
 }
 
-#if defined(OS_WIN)
-UINT GetMessageBoxFlagsFromType(MessageBoxType type) {
-  UINT flags = MB_SETFOREGROUND;
-  switch (type) {
-    case MESSAGE_BOX_TYPE_WARNING:
-      return flags | MB_OK | MB_ICONWARNING;
-    case MESSAGE_BOX_TYPE_QUESTION:
-      return flags | MB_YESNO | MB_ICONQUESTION;
-  }
-  NOTREACHED();
-  return flags | MB_OK | MB_ICONWARNING;
-}
-#endif
+namespace chrome {
 
-void ShowMessageBoxAsyncImpl(
-    gfx::NativeWindow parent,
-    const base::string16& title,
-    const base::string16& message,
-    MessageBoxType type,
-    const base::string16& yes_text,
-    const base::string16& no_text,
-    const base::string16& checkbox_text,
-    SimpleMessageBoxViews::MessageBoxResultCallback callback) {
-  startup_metric_utils::SetNonBrowserUIDisplayed();
-  if (internal::g_should_skip_message_box_for_test) {
-    std::move(callback).Run(MESSAGE_BOX_RESULT_YES);
-    return;
-  }
-
-  // Views dialogs cannot be shown outside the UI thread message loop or if the
-  // ResourceBundle is not initialized yet.
-  // Fallback to logging with a default response or a Windows MessageBox.
-#if defined(OS_WIN)
-  if (!base::MessageLoopForUI::IsCurrent() ||
-      !base::RunLoop::IsRunningOnCurrentThread() ||
-      !ResourceBundle::HasSharedInstance()) {
-    LOG_IF(ERROR, !checkbox_text.empty()) << "Dialog checkbox won't be shown";
-    int result = ui::MessageBox(views::HWNDForNativeWindow(parent), message,
-                                title, GetMessageBoxFlagsFromType(type));
-    std::move(callback).Run((result == IDYES || result == IDOK)
-                                ? MESSAGE_BOX_RESULT_YES
-                                : MESSAGE_BOX_RESULT_NO);
-    return;
-  }
-#else
-  if (!base::MessageLoopForUI::IsCurrent() ||
-      !ResourceBundle::HasSharedInstance()) {
-    LOG(ERROR) << "Unable to show a dialog outside the UI thread message loop: "
-               << title << " - " << message;
-    std::move(callback).Run(MESSAGE_BOX_RESULT_NO);
-    return;
-  }
-#endif
-
-  SimpleMessageBoxViews* dialog =
-      new SimpleMessageBoxViews(title, message, type, yes_text, no_text,
-                                checkbox_text, !parent /* is_system_modal */);
-  constrained_window::CreateBrowserModalDialogViews(dialog, parent)->Show();
-
-  dialog->Run(std::move(callback));
-}
-
-MessageBoxResult ShowMessageBoxImpl(gfx::NativeWindow parent,
-                                    const base::string16& title,
-                                    const base::string16& message,
-                                    MessageBoxType type,
-                                    const base::string16& yes_text,
-                                    const base::string16& no_text,
-                                    const base::string16& checkbox_text) {
-  MessageBoxResult result = MESSAGE_BOX_RESULT_NO;
-
-  // TODO(pkotwicz): Exit message loop when the dialog is closed by some other
-  // means than |Cancel| or |Accept|. crbug.com/404385
-  base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
-  base::MessageLoopForUI::ScopedNestableTaskAllower allow_nested(loop);
-  base::RunLoop run_loop;
-
-  ShowMessageBoxAsyncImpl(
-      parent, title, message, type, yes_text, no_text, checkbox_text,
-      base::Bind(
-          [](base::RunLoop* run_loop, MessageBoxResult* out_result,
-             MessageBoxResult messagebox_result) {
-            *out_result = messagebox_result;
-            run_loop->Quit();
-          },
-          &run_loop, &result));
-
-  run_loop.Run();
-  return result;
-}
-
-}  // namespace
-
+#if !defined(OS_MACOSX) || BUILDFLAG(MAC_VIEWS_BROWSER)
 bool CloseMessageBoxForTest(bool accept) {
   if (!g_current_message_box)
     return false;
@@ -296,8 +275,9 @@
 void ShowWarningMessageBox(gfx::NativeWindow parent,
                            const base::string16& title,
                            const base::string16& message) {
-  ShowMessageBoxImpl(parent, title, message, MESSAGE_BOX_TYPE_WARNING,
-                     base::string16(), base::string16(), base::string16());
+  SimpleMessageBoxViews::Show(
+      parent, title, message, chrome::MESSAGE_BOX_TYPE_WARNING,
+      base::string16(), base::string16(), base::string16());
 }
 
 void ShowWarningMessageBoxWithCheckbox(
@@ -306,9 +286,9 @@
     const base::string16& message,
     const base::string16& checkbox_text,
     base::OnceCallback<void(bool checked)> callback) {
-  ShowMessageBoxAsyncImpl(
-      parent, title, message, MESSAGE_BOX_TYPE_WARNING, base::string16(),
-      base::string16(), checkbox_text,
+  SimpleMessageBoxViews::Show(
+      parent, title, message, chrome::MESSAGE_BOX_TYPE_WARNING,
+      base::string16(), base::string16(), checkbox_text,
       base::Bind(
           [](base::OnceCallback<void(bool checked)> callback,
              MessageBoxResult message_box_result) {
@@ -321,9 +301,9 @@
 MessageBoxResult ShowQuestionMessageBox(gfx::NativeWindow parent,
                                         const base::string16& title,
                                         const base::string16& message) {
-  return ShowMessageBoxImpl(parent, title, message, MESSAGE_BOX_TYPE_QUESTION,
-                            base::string16(), base::string16(),
-                            base::string16());
+  return SimpleMessageBoxViews::Show(
+      parent, title, message, chrome::MESSAGE_BOX_TYPE_QUESTION,
+      base::string16(), base::string16(), base::string16());
 }
 
 MessageBoxResult ShowMessageBoxWithButtonText(gfx::NativeWindow parent,
@@ -331,8 +311,11 @@
                                               const base::string16& message,
                                               const base::string16& yes_text,
                                               const base::string16& no_text) {
-  return ShowMessageBoxImpl(parent, title, message, MESSAGE_BOX_TYPE_QUESTION,
-                            yes_text, no_text, base::string16());
+  return SimpleMessageBoxViews::Show(parent, title, message,
+                                     chrome::MESSAGE_BOX_TYPE_QUESTION,
+                                     yes_text, no_text, base::string16());
 }
 
+#endif  // !OS_MACOSX || BUILDFLAG(MAC_VIEWS_BROWSER)
+
 }  // namespace chrome
diff --git a/chrome/browser/ui/views/simple_message_box_views.h b/chrome/browser/ui/views/simple_message_box_views.h
new file mode 100644
index 0000000..c71b6eff
--- /dev/null
+++ b/chrome/browser/ui/views/simple_message_box_views.h
@@ -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.
+
+#ifndef CHROME_BROWSER_UI_VIEWS_SIMPLE_MESSAGE_BOX_VIEWS_H_
+#define CHROME_BROWSER_UI_VIEWS_SIMPLE_MESSAGE_BOX_VIEWS_H_
+
+#include "chrome/browser/ui/simple_message_box.h"
+
+#include "ui/views/controls/message_box_view.h"
+#include "ui/views/window/dialog_delegate.h"
+
+class SimpleMessageBoxViews : public views::DialogDelegate {
+ public:
+  using MessageBoxResultCallback =
+      base::OnceCallback<void(chrome::MessageBoxResult result)>;
+
+  static chrome::MessageBoxResult Show(
+      gfx::NativeWindow parent,
+      const base::string16& title,
+      const base::string16& message,
+      chrome::MessageBoxType type,
+      const base::string16& yes_text,
+      const base::string16& no_text,
+      const base::string16& checkbox_text,
+      MessageBoxResultCallback callback = MessageBoxResultCallback());
+
+  // views::DialogDelegate:
+  int GetDialogButtons() const override;
+  base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
+  bool Cancel() override;
+  bool Accept() override;
+  base::string16 GetWindowTitle() const override;
+  void DeleteDelegate() override;
+  ui::ModalType GetModalType() const override;
+  views::View* GetContentsView() override;
+  views::Widget* GetWidget() override;
+  const views::Widget* GetWidget() const override;
+
+ private:
+  SimpleMessageBoxViews(const base::string16& title,
+                        const base::string16& message,
+                        chrome::MessageBoxType type,
+                        const base::string16& yes_text,
+                        const base::string16& no_text,
+                        const base::string16& checkbox_text,
+                        bool is_system_modal);
+  ~SimpleMessageBoxViews() override;
+
+  void Run(MessageBoxResultCallback result_callback);
+  void Done();
+
+  const base::string16 window_title_;
+  const chrome::MessageBoxType type_;
+  base::string16 yes_text_;
+  base::string16 no_text_;
+  chrome::MessageBoxResult result_;
+  views::MessageBoxView* message_box_view_;
+  MessageBoxResultCallback result_callback_;
+  bool is_system_modal_;
+
+  DISALLOW_COPY_AND_ASSIGN(SimpleMessageBoxViews);
+};
+
+#endif  // CHROME_BROWSER_UI_VIEWS_SIMPLE_MESSAGE_BOX_VIEWS_H_
diff --git a/chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.cc b/chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.cc
index c924a72..420efe93 100644
--- a/chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.cc
+++ b/chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.h"
 
+#include <memory>
 #include <set>
 #include <utility>
 
@@ -173,7 +174,7 @@
   }
 
   privet_lister_->Start();
-  privet_lister_->DiscoverNewDevices(false);
+  privet_lister_->DiscoverNewDevices();
 
 #if defined(CLOUD_PRINT_CONNECTOR_UI_AVAILABLE)
   StartCloudPrintConnector();
@@ -380,7 +381,7 @@
 void LocalDiscoveryUIHandler::DeviceCacheFlushed() {
   web_ui()->CallJavascriptFunctionUnsafe(
       "local_discovery.onDeviceCacheFlushed");
-  privet_lister_->DiscoverNewDevices(false);
+  privet_lister_->DiscoverNewDevices();
 }
 
 void LocalDiscoveryUIHandler::OnDeviceListReady(
@@ -416,7 +417,7 @@
     const std::string& service_name) {
   // HACK(noamsml): Generate network traffic so the Windows firewall doesn't
   // block the printer's announcement.
-  privet_lister_->DiscoverNewDevices(false);
+  privet_lister_->DiscoverNewDevices();
 
   DeviceDescriptionMap::iterator it = device_descriptions_.find(service_name);
 
diff --git a/chrome/browser/ui/webui/md_bookmarks/md_bookmarks_ui.cc b/chrome/browser/ui/webui/md_bookmarks/md_bookmarks_ui.cc
index 0c53db9..d16575a 100644
--- a/chrome/browser/ui/webui/md_bookmarks/md_bookmarks_ui.cc
+++ b/chrome/browser/ui/webui/md_bookmarks/md_bookmarks_ui.cc
@@ -6,6 +6,8 @@
 
 #include <algorithm>
 #include <string>
+#include <unordered_set>
+#include <utility>
 
 #include "base/strings/string16.h"
 #include "chrome/browser/profiles/profile.h"
@@ -118,6 +120,10 @@
                           IDR_MD_BOOKMARKS_COMMAND_MANAGER_JS);
   source->AddResourcePath("constants.html", IDR_MD_BOOKMARKS_CONSTANTS_HTML);
   source->AddResourcePath("constants.js", IDR_MD_BOOKMARKS_CONSTANTS_JS);
+  source->AddResourcePath("dialog_focus_manager.html",
+                          IDR_MD_BOOKMARKS_DIALOG_FOCUS_MANAGER_HTML);
+  source->AddResourcePath("dialog_focus_manager.js",
+                          IDR_MD_BOOKMARKS_DIALOG_FOCUS_MANAGER_JS);
   source->AddResourcePath("dnd_manager.html",
                           IDR_MD_BOOKMARKS_DND_MANAGER_HTML);
   source->AddResourcePath("dnd_manager.js", IDR_MD_BOOKMARKS_DND_MANAGER_JS);
diff --git a/chrome/browser/ui/webui/settings/site_settings_handler.cc b/chrome/browser/ui/webui/settings/site_settings_handler.cc
index 8d1981ca..d315350 100644
--- a/chrome/browser/ui/webui/settings/site_settings_handler.cc
+++ b/chrome/browser/ui/webui/settings/site_settings_handler.cc
@@ -18,12 +18,15 @@
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/content_settings/web_site_settings_uma_util.h"
 #include "chrome/browser/permissions/chooser_context_base.h"
+#include "chrome/browser/permissions/permission_manager.h"
+#include "chrome/browser/permissions/permission_result.h"
 #include "chrome/browser/permissions/permission_uma_util.h"
 #include "chrome/browser/permissions/permission_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/site_settings_helper.h"
 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
 #include "chrome/grit/generated_resources.h"
+#include "components/content_settings/core/browser/content_settings_utils.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/content_settings/core/common/content_settings_types.h"
 #include "components/crx_file/id_util.h"
@@ -99,6 +102,85 @@
   }
 }
 
+// Retrieves the corresponding string, according to the following precedence
+// order from highest to lowest priority:
+//    1. Kill-switch.
+//    2. Enterprise policy.
+//    3. Extensions.
+//    4. User-set per-origin setting.
+//    5. Embargo.
+//    6. User-set patterns.
+//    7. User-set global default for a ContentSettingsType.
+//    8. Chrome's built-in default.
+std::string ConvertContentSettingSourceToString(
+    content_settings::SettingSource content_settings_source,
+    PermissionStatusSource permission_status_source) {
+  // TODO(patricialor): Do some plumbing for sources #1, #2, #3, and #5 through
+  // to the Web UI. Currently there aren't strings to represent these sources.
+  if (permission_status_source == PermissionStatusSource::KILL_SWITCH)
+    return site_settings::kPreferencesSource;  // Source #1.
+
+  if (content_settings_source == content_settings::SETTING_SOURCE_POLICY ||
+      content_settings_source == content_settings::SETTING_SOURCE_SUPERVISED) {
+    return site_settings::kPolicyProviderId;  // Source #2.
+  }
+
+  if (content_settings_source == content_settings::SETTING_SOURCE_EXTENSION)
+    return site_settings::kExtensionProviderId;  // Source #3.
+
+  DCHECK_NE(content_settings::SETTING_SOURCE_NONE, content_settings_source);
+  if (content_settings_source == content_settings::SETTING_SOURCE_USER) {
+    if (permission_status_source ==
+            PermissionStatusSource::SAFE_BROWSING_BLACKLIST ||
+        permission_status_source ==
+            PermissionStatusSource::MULTIPLE_DISMISSALS ||
+        permission_status_source == PermissionStatusSource::MULTIPLE_IGNORES) {
+      return site_settings::kPreferencesSource;  // Source #5.
+    }
+    // Source #4, #6, #7, #8. When #4 is the source, |permission_status_source|
+    // won't be set to any of the source #5 enum values, as PermissionManager is
+    // aware of the difference between these two sources internally. The
+    // subtlety here should go away when PermissionManager can handle all
+    // content settings and all possible sources.
+    return site_settings::kPreferencesSource;
+  }
+
+  NOTREACHED();
+  return site_settings::kPreferencesSource;
+}
+
+ContentSetting GetContentSettingForOrigin(const GURL& origin,
+                                          ContentSettingsType content_type,
+                                          Profile* profile,
+                                          std::string* source_string) {
+  // TODO(patricialor): In future, PermissionManager should know about all
+  // content settings, not just the permissions, plus all the possible sources,
+  // and the calls to HostContentSettingsMap should be removed.
+  content_settings::SettingInfo info;
+  HostContentSettingsMap* map =
+      HostContentSettingsMapFactory::GetForProfile(profile);
+  std::unique_ptr<base::Value> value = map->GetWebsiteSetting(
+      origin, origin, content_type, std::string(), &info);
+
+  // Retrieve the content setting.
+  PermissionResult result(CONTENT_SETTING_DEFAULT,
+                          PermissionStatusSource::UNSPECIFIED);
+  if (PermissionUtil::IsPermission(content_type)) {
+    result = PermissionManager::Get(profile)->GetPermissionStatus(
+        content_type, origin, origin);
+  } else {
+    DCHECK(value.get());
+    DCHECK_EQ(base::Value::Type::INTEGER, value->GetType());
+    result.content_setting =
+        content_settings::ValueToContentSetting(value.get());
+  }
+
+  // Retrieve the source of the content setting.
+  *source_string =
+      ConvertContentSettingSourceToString(info.source, result.source);
+  return result.content_setting;
+}
+
 }  // namespace
 
 
@@ -139,6 +221,10 @@
       base::Bind(&SiteSettingsHandler::HandleGetExceptionList,
                  base::Unretained(this)));
   web_ui()->RegisterMessageCallback(
+      "getOriginPermissions",
+      base::Bind(&SiteSettingsHandler::HandleGetOriginPermissions,
+                 base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
       "resetCategoryPermissionForOrigin",
       base::Bind(&SiteSettingsHandler::HandleResetCategoryPermissionForOrigin,
                  base::Unretained(this)));
@@ -147,10 +233,6 @@
       base::Bind(&SiteSettingsHandler::HandleSetCategoryPermissionForOrigin,
                  base::Unretained(this)));
   web_ui()->RegisterMessageCallback(
-      "getSiteDetails",
-      base::Bind(&SiteSettingsHandler::HandleGetSiteDetails,
-                 base::Unretained(this)));
-  web_ui()->RegisterMessageCallback(
       "isPatternValid",
       base::Bind(&SiteSettingsHandler::HandleIsPatternValid,
                  base::Unretained(this)));
@@ -391,8 +473,7 @@
   HostContentSettingsMap* map =
       HostContentSettingsMapFactory::GetForProfile(profile);
   map->SetDefaultContentSetting(
-      static_cast<ContentSettingsType>(static_cast<int>(
-          site_settings::ContentSettingsTypeFromGroupName(content_type))),
+      site_settings::ContentSettingsTypeFromGroupName(content_type),
       default_setting);
 }
 
@@ -407,8 +488,7 @@
   CHECK(args->GetString(1, &type));
 
   ContentSettingsType content_type =
-      static_cast<ContentSettingsType>(static_cast<int>(
-          site_settings::ContentSettingsTypeFromGroupName(type)));
+      site_settings::ContentSettingsTypeFromGroupName(type);
   HostContentSettingsMap* map =
       HostContentSettingsMapFactory::GetForProfile(profile_);
 
@@ -426,8 +506,7 @@
   std::string type;
   CHECK(args->GetString(1, &type));
   ContentSettingsType content_type =
-      static_cast<ContentSettingsType>(static_cast<int>(
-          site_settings::ContentSettingsTypeFromGroupName(type)));
+      site_settings::ContentSettingsTypeFromGroupName(type);
 
   std::unique_ptr<base::ListValue> exceptions(new base::ListValue);
 
@@ -456,6 +535,48 @@
   ResolveJavascriptCallback(*callback_id, *exceptions.get());
 }
 
+void SiteSettingsHandler::HandleGetOriginPermissions(
+    const base::ListValue* args) {
+  AllowJavascript();
+
+  CHECK_EQ(3U, args->GetSize());
+  const base::Value* callback_id;
+  CHECK(args->Get(0, &callback_id));
+  std::string origin;
+  CHECK(args->GetString(1, &origin));
+  const base::ListValue* types;
+  CHECK(args->GetList(2, &types));
+
+  // Note: Invalid URLs will just result in default settings being shown.
+  const GURL origin_url(origin);
+  auto exceptions = base::MakeUnique<base::ListValue>();
+  for (size_t i = 0; i < types->GetSize(); ++i) {
+    std::string type;
+    types->GetString(i, &type);
+    ContentSettingsType content_type =
+        site_settings::ContentSettingsTypeFromGroupName(type);
+
+    std::string source_string;
+    ContentSetting content_setting = GetContentSettingForOrigin(
+        origin_url, content_type, profile_, &source_string);
+    std::string content_setting_string =
+        content_settings::ContentSettingToString(content_setting);
+
+    auto raw_site_exception = base::MakeUnique<base::DictionaryValue>();
+    raw_site_exception->SetString(site_settings::kEmbeddingOrigin, origin);
+    raw_site_exception->SetBoolean(site_settings::kIncognito,
+                                   profile_->IsOffTheRecord());
+    raw_site_exception->SetString(site_settings::kOrigin, origin);
+    raw_site_exception->SetString(site_settings::kDisplayName, origin);
+    raw_site_exception->SetString(site_settings::kSetting,
+                                  content_setting_string);
+    raw_site_exception->SetString(site_settings::kSource, source_string);
+    exceptions->Append(std::move(raw_site_exception));
+  }
+
+  ResolveJavascriptCallback(*callback_id, *exceptions);
+}
+
 void SiteSettingsHandler::HandleResetCategoryPermissionForOrigin(
     const base::ListValue* args) {
   CHECK_EQ(4U, args->GetSize());
@@ -469,8 +590,7 @@
   CHECK(args->GetBoolean(3, &incognito));
 
   ContentSettingsType content_type =
-      static_cast<ContentSettingsType>(static_cast<int>(
-          site_settings::ContentSettingsTypeFromGroupName(type)));
+      site_settings::ContentSettingsTypeFromGroupName(type);
 
   Profile* profile = nullptr;
   if (incognito) {
@@ -517,8 +637,7 @@
   CHECK(args->GetBoolean(4, &incognito));
 
   ContentSettingsType content_type =
-      static_cast<ContentSettingsType>(static_cast<int>(
-          site_settings::ContentSettingsTypeFromGroupName(type)));
+      site_settings::ContentSettingsTypeFromGroupName(type);
   ContentSetting setting;
   CHECK(content_settings::ContentSettingFromString(value, &setting));
 
@@ -551,69 +670,6 @@
   WebSiteSettingsUmaUtil::LogPermissionChange(content_type, setting);
 }
 
-void SiteSettingsHandler::HandleGetSiteDetails(
-    const base::ListValue* args) {
-  AllowJavascript();
-
-  CHECK_EQ(2U, args->GetSize());
-  const base::Value* callback_id;
-  CHECK(args->Get(0, &callback_id));
-  std::string site;
-  CHECK(args->GetString(1, &site));
-
-  // A subset of the ContentSettingsType enum that we show in the settings UI.
-  const ContentSettingsType kSettingsDetailTypes[] = {
-    CONTENT_SETTINGS_TYPE_COOKIES,
-    CONTENT_SETTINGS_TYPE_IMAGES,
-    CONTENT_SETTINGS_TYPE_JAVASCRIPT,
-    CONTENT_SETTINGS_TYPE_PLUGINS,
-    CONTENT_SETTINGS_TYPE_POPUPS,
-    CONTENT_SETTINGS_TYPE_GEOLOCATION,
-    CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
-    CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC,
-    CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA,
-    CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS,
-    CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS,
-    CONTENT_SETTINGS_TYPE_BACKGROUND_SYNC,
-    CONTENT_SETTINGS_TYPE_USB_CHOOSER_DATA,
-    CONTENT_SETTINGS_TYPE_PROMPT_NO_DECISION_COUNT,
-  };
-
-  // Create a list to be consistent with existing API, we are expecting a single
-  // element (or none).
-  std::unique_ptr<base::ListValue> exceptions(new base::ListValue);
-  for (size_t type = 0; type < arraysize(kSettingsDetailTypes); ++type) {
-    ContentSettingsType content_type = kSettingsDetailTypes[type];
-
-    HostContentSettingsMap* map =
-        HostContentSettingsMapFactory::GetForProfile(profile_);
-    const auto* extension_registry =
-        extensions::ExtensionRegistry::Get(profile_);
-    site_settings::GetExceptionsFromHostContentSettingsMap(
-        map, content_type, extension_registry, web_ui(), /*incognito=*/false,
-        /*filter=*/&site, exceptions.get());
-
-    if (profile_->HasOffTheRecordProfile()) {
-      Profile* incognito = profile_->GetOffTheRecordProfile();
-      map = HostContentSettingsMapFactory::GetForProfile(incognito);
-      extension_registry = extensions::ExtensionRegistry::Get(incognito);
-      site_settings::GetExceptionsFromHostContentSettingsMap(
-          map, content_type, extension_registry, web_ui(), /*incognito=*/true,
-          /*filter=*/&site, exceptions.get());
-    }
-  }
-
-  if (!exceptions->GetSize()) {
-    RejectJavascriptCallback(*callback_id, base::Value());
-    return;
-  }
-
-  // We only need a single response element.
-  const base::DictionaryValue* exception = nullptr;
-  exceptions->GetDictionary(0, &exception);
-  ResolveJavascriptCallback(*callback_id, *exception);
-}
-
 void SiteSettingsHandler::HandleIsPatternValid(
     const base::ListValue* args) {
   CHECK_EQ(2U, args->GetSize());
diff --git a/chrome/browser/ui/webui/settings/site_settings_handler.h b/chrome/browser/ui/webui/settings/site_settings_handler.h
index 443da67..0ccbcd4 100644
--- a/chrome/browser/ui/webui/settings/site_settings_handler.h
+++ b/chrome/browser/ui/webui/settings/site_settings_handler.h
@@ -86,12 +86,13 @@
   // Returns the list of site exceptions for a given content settings type.
   void HandleGetExceptionList(const base::ListValue* args);
 
-  // Handles setting and resetting of an origin permission.
+  // Handles setting and resetting an origin permission.
   void HandleResetCategoryPermissionForOrigin(const base::ListValue* args);
   void HandleSetCategoryPermissionForOrigin(const base::ListValue* args);
 
-  // Return site exceptions for a single site.
-  void HandleGetSiteDetails(const base::ListValue* args);
+  // Retrieves the content settings for a given list of ContentSettingTypes for
+  // an origin.
+  void HandleGetOriginPermissions(const base::ListValue* args);
 
   // Returns whether a given pattern is valid.
   void HandleIsPatternValid(const base::ListValue* args);
diff --git a/chrome/browser/ui/webui/site_settings_helper.cc b/chrome/browser/ui/webui/site_settings_helper.cc
index 4304d016..1a859e6 100644
--- a/chrome/browser/ui/webui/site_settings_helper.cc
+++ b/chrome/browser/ui/webui/site_settings_helper.cc
@@ -25,6 +25,7 @@
 const char kOrigin[] = "origin";
 const char kDisplayName[] = "displayName";
 const char kOriginForFavicon[] = "originForFavicon";
+const char kExtensionProviderId[] = "extension";
 const char kPolicyProviderId[] = "policy";
 const char kSource[] = "source";
 const char kIncognito[] = "incognito";
diff --git a/chrome/browser/ui/webui/site_settings_helper.h b/chrome/browser/ui/webui/site_settings_helper.h
index bc3b51a..d9662f6e 100644
--- a/chrome/browser/ui/webui/site_settings_helper.h
+++ b/chrome/browser/ui/webui/site_settings_helper.h
@@ -45,6 +45,7 @@
 extern const char kOrigin[];
 extern const char kDisplayName[];
 extern const char kOriginForFavicon[];
+extern const char kExtensionProviderId[];
 extern const char kPolicyProviderId[];
 extern const char kSource[];
 extern const char kIncognito[];
diff --git a/chrome/browser/usb/usb_chooser_controller.cc b/chrome/browser/usb/usb_chooser_controller.cc
index 662d292..1ed6096 100644
--- a/chrome/browser/usb/usb_chooser_controller.cc
+++ b/chrome/browser/usb/usb_chooser_controller.cc
@@ -40,7 +40,7 @@
 
 Browser* GetBrowser() {
   chrome::ScopedTabbedBrowserDisplayer browser_displayer(
-      ProfileManager::GetActiveUserProfile());
+      ProfileManager::GetLastUsedProfileAllowedByPolicy());
   DCHECK(browser_displayer.browser());
   return browser_displayer.browser();
 }
diff --git a/chrome/browser/win/jumplist.cc b/chrome/browser/win/jumplist.cc
index bbca0370..6f3aa455 100644
--- a/chrome/browser/win/jumplist.cc
+++ b/chrome/browser/win/jumplist.cc
@@ -194,9 +194,9 @@
 
 }  // namespace
 
-JumpList::UpdateResults::UpdateResults() {}
+JumpList::UpdateTransaction::UpdateTransaction() {}
 
-JumpList::UpdateResults::~UpdateResults() {}
+JumpList::UpdateTransaction::~UpdateTransaction() {}
 
 // static
 bool JumpList::Enabled() {
@@ -306,6 +306,8 @@
 }
 
 void JumpList::InitializeTimerForUpdate() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
   if (timer_.IsRunning()) {
     timer_.Reset();
   } else {
@@ -317,6 +319,7 @@
 
 void JumpList::OnDelayTimer() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(!update_in_progress_);
 
   if (updates_to_skip_ > 0) {
     --updates_to_skip_;
@@ -340,6 +343,7 @@
 
 void JumpList::ProcessTopSitesNotification() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(!update_in_progress_);
 
   // Opening the first tab in one session triggers a TopSite history sync.
   // Delay this sync till the first tab is closed to allow the "recently closed"
@@ -362,6 +366,7 @@
 
 void JumpList::ProcessTabRestoreServiceNotification() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(!update_in_progress_);
 
   // Create a list of ShellLinkItems from the "Recently Closed" pages.
   // As noted above, we create a ShellLinkItem objects with the following
@@ -500,10 +505,6 @@
       GURL(icon_urls_.front().first),
       base::Bind(&JumpList::OnFaviconDataAvailable, base::Unretained(this)),
       &cancelable_task_tracker_);
-
-  // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/717236
-  UMA_HISTOGRAM_TIMES("WinJumplist.StartLoadingFaviconDuration",
-                      timer.Elapsed());
 }
 
 void JumpList::OnFaviconDataAvailable(
@@ -528,10 +529,6 @@
     icon_urls_.pop_front();
   }
 
-  // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/717236
-  UMA_HISTOGRAM_TIMES("WinJumplist.OnFaviconDataAvailableDuration",
-                      timer.Elapsed());
-
   // Check whether we need to load more favicons.
   StartLoadingFavicon();
 }
@@ -549,51 +546,53 @@
   IncognitoModePrefs::Availability incognito_availability =
       IncognitoModePrefs::GetAvailability(profile_->GetPrefs());
 
-  // Make local copies of JumpList member variables and use them for an update.
-  ShellLinkItemList local_most_visited_pages = most_visited_pages_;
-  ShellLinkItemList local_recently_closed_pages = recently_closed_pages_;
+  auto update_transaction = base::MakeUnique<UpdateTransaction>();
+  if (most_visited_should_update_)
+    update_transaction->most_visited_icons = std::move(most_visited_icons_);
+  if (recently_closed_should_update_) {
+    update_transaction->recently_closed_icons =
+        std::move(recently_closed_icons_);
+  }
 
-  bool most_visited_should_update = most_visited_should_update_;
-  bool recently_closed_should_update = recently_closed_should_update_;
-
-  auto update_results = base::MakeUnique<UpdateResults>();
-  update_results->most_visited_icons_in_update = most_visited_icons_;
-  update_results->recently_closed_icons_in_update = recently_closed_icons_;
-
-  // Parameter evaluation order is unspecified in C++. Ensure the pointer value
-  // is obtained before base::Passed() is called.
-  auto* update_results_raw = update_results.get();
+  // Parameter evaluation order is unspecified in C++. Do the first bind and
+  // then move it into PostTaskAndReply to ensure the pointer value is obtained
+  // before base::Passed() is called.
+  auto run_update =
+      base::Bind(&JumpList::RunUpdateJumpList, app_id_, profile_dir,
+                 most_visited_pages_, recently_closed_pages_,
+                 most_visited_should_update_, recently_closed_should_update_,
+                 incognito_availability, update_transaction.get());
 
   // Post a task to update the JumpList, which consists of 1) create new icons,
-  // 2) delete old icons, 3) notify the OS.
+  // 2) notify the OS, 3) delete old icons.
   if (!update_jumplist_task_runner_->PostTaskAndReply(
-          FROM_HERE,
-          base::Bind(&JumpList::RunUpdateJumpList, app_id_, profile_dir,
-                     local_most_visited_pages, local_recently_closed_pages,
-                     most_visited_should_update, recently_closed_should_update,
-                     incognito_availability, update_results_raw),
+          FROM_HERE, std::move(run_update),
           base::Bind(&JumpList::OnRunUpdateCompletion,
                      weak_ptr_factory_.GetWeakPtr(),
-                     base::Passed(std::move(update_results))))) {
-    OnRunUpdateCompletion(base::MakeUnique<UpdateResults>());
+                     base::Passed(std::move(update_transaction))))) {
+    OnRunUpdateCompletion(base::MakeUnique<UpdateTransaction>());
   }
 }
 
 void JumpList::OnRunUpdateCompletion(
-    std::unique_ptr<UpdateResults> update_results) {
+    std::unique_ptr<UpdateTransaction> update_transaction) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   // Update JumpList member variables based on the results from the update run
   // just finished.
-  if (update_results->update_timeout)
+  if (update_transaction->update_timeout)
     updates_to_skip_ = kUpdatesToSkipUnderHeavyLoad;
 
-  if (update_results->update_success) {
-    most_visited_icons_.swap(update_results->most_visited_icons_in_update);
-    recently_closed_icons_.swap(
-        update_results->recently_closed_icons_in_update);
-    most_visited_should_update_ = false;
-    recently_closed_should_update_ = false;
+  if (update_transaction->update_success) {
+    if (most_visited_should_update_) {
+      most_visited_icons_ = std::move(update_transaction->most_visited_icons);
+      most_visited_should_update_ = false;
+    }
+    if (recently_closed_should_update_) {
+      recently_closed_icons_ =
+          std::move(update_transaction->recently_closed_icons);
+      recently_closed_should_update_ = false;
+    }
   }
 
   update_in_progress_ = false;
@@ -663,11 +662,46 @@
     bool most_visited_should_update,
     bool recently_closed_should_update,
     IncognitoModePrefs::Availability incognito_availability,
-    UpdateResults* update_results) {
+    UpdateTransaction* update_transaction) {
   if (!JumpListUpdater::IsEnabled())
     return;
 
-  DCHECK(update_results);
+  DCHECK(update_transaction);
+
+  base::FilePath most_visited_icon_dir = GenerateJumplistIconDirName(
+      profile_dir, FILE_PATH_LITERAL("MostVisited"));
+  base::FilePath recently_closed_icon_dir = GenerateJumplistIconDirName(
+      profile_dir, FILE_PATH_LITERAL("RecentClosed"));
+
+  CreateNewJumpListAndNotifyOS(
+      app_id, most_visited_icon_dir, recently_closed_icon_dir,
+      most_visited_pages, recently_closed_pages, most_visited_should_update,
+      recently_closed_should_update, incognito_availability,
+      update_transaction);
+
+  // Delete any obsolete icon files.
+  if (most_visited_should_update) {
+    DeleteIconFiles(most_visited_icon_dir,
+                    update_transaction->most_visited_icons);
+  }
+  if (recently_closed_should_update) {
+    DeleteIconFiles(recently_closed_icon_dir,
+                    update_transaction->recently_closed_icons);
+  }
+}
+
+// static
+void JumpList::CreateNewJumpListAndNotifyOS(
+    const base::string16& app_id,
+    const base::FilePath& most_visited_icon_dir,
+    const base::FilePath& recently_closed_icon_dir,
+    const ShellLinkItemList& most_visited_pages,
+    const ShellLinkItemList& recently_closed_pages,
+    bool most_visited_should_update,
+    bool recently_closed_should_update,
+    IncognitoModePrefs::Availability incognito_availability,
+    UpdateTransaction* update_transaction) {
+  DCHECK(update_transaction);
 
   JumpListUpdater jumplist_updater(app_id);
 
@@ -678,34 +712,31 @@
 
   // Discard this JumpList update if JumpListUpdater::BeginUpdate takes longer
   // than the maximum allowed time, as it's very likely the following update
-  // steps will also take a long time. As we've not updated the icons on the
-  // disk, discarding this update wont't affect the current JumpList used by OS.
+  // steps will also take a long time.
   if (begin_update_timer.Elapsed() >= kTimeOutForJumplistBeginUpdate) {
-    update_results->update_timeout = true;
+    update_transaction->update_timeout = true;
     return;
   }
 
   // Record the desired number of icons created in this JumpList update.
   int icons_created = 0;
 
+  URLIconCache most_visited_icons_next;
+  URLIconCache recently_closed_icons_next;
+
   // Update the icons for "Most Visisted" category of the JumpList if needed.
   if (most_visited_should_update) {
-    base::FilePath icon_dir_most_visited = GenerateJumplistIconDirName(
-        profile_dir, FILE_PATH_LITERAL("MostVisited"));
-
     icons_created += UpdateIconFiles(
-        icon_dir_most_visited, most_visited_pages, kMostVisitedItems,
-        &update_results->most_visited_icons_in_update);
+        most_visited_icon_dir, most_visited_pages, kMostVisitedItems,
+        &update_transaction->most_visited_icons, &most_visited_icons_next);
   }
 
   // Update the icons for "Recently Closed" category of the JumpList if needed.
   if (recently_closed_should_update) {
-    base::FilePath icon_dir_recent_closed = GenerateJumplistIconDirName(
-        profile_dir, FILE_PATH_LITERAL("RecentClosed"));
-
     icons_created += UpdateIconFiles(
-        icon_dir_recent_closed, recently_closed_pages, kRecentlyClosedItems,
-        &update_results->recently_closed_icons_in_update);
+        recently_closed_icon_dir, recently_closed_pages, kRecentlyClosedItems,
+        &update_transaction->recently_closed_icons,
+        &recently_closed_icons_next);
   }
 
   // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/40407.
@@ -732,16 +763,12 @@
     return;
   }
 
-  // If JumpListUpdater::AddCustomCategory or JumpListUpdater::CommitUpdate
-  // takes longer than the maximum allowed time, skip the next
-  // |kUpdatesToSkipUnderHeavyLoad| updates. This update should be finished
-  // because we've already updated the icons on the disk. If discarding this
-  // update from here, some items in the current JumpList may not have icons
-  // as they've been delete from the disk. In this case, the background color of
-  // the JumpList panel is used instead, which doesn't look nice.
-
-  if (add_custom_category_timer.Elapsed() >= kTimeOutForAddCustomCategory)
-    update_results->update_timeout = true;
+  // If AddCustomCategory takes longer than the maximum allowed time, abort the
+  // current update and skip the next |kUpdatesToSkipUnderHeavyLoad| updates.
+  if (add_custom_category_timer.Elapsed() >= kTimeOutForAddCustomCategory) {
+    update_transaction->update_timeout = true;
+    return;
+  }
 
   // Update the "Tasks" category of the JumpList.
   if (!UpdateTaskCategory(&jumplist_updater, incognito_availability))
@@ -750,81 +777,98 @@
   base::ElapsedTimer commit_update_timer;
 
   // Commit this transaction and send the updated JumpList to Windows.
-  if (jumplist_updater.CommitUpdate())
-    update_results->update_success = true;
+  bool commit_success = jumplist_updater.CommitUpdate();
 
+  // If CommitUpdate call takes longer than the maximum allowed time, skip the
+  // next |kUpdatesToSkipUnderHeavyLoad| updates.
   if (commit_update_timer.Elapsed() >= kTimeOutForJumplistCommitUpdate)
-    update_results->update_timeout = true;
+    update_transaction->update_timeout = true;
+
+  if (commit_success) {
+    update_transaction->update_success = true;
+
+    // The move assignments below ensure update_transaction always has the icons
+    // to keep.
+    if (most_visited_should_update) {
+      update_transaction->most_visited_icons =
+          std::move(most_visited_icons_next);
+    }
+    if (recently_closed_should_update) {
+      update_transaction->recently_closed_icons =
+          std::move(recently_closed_icons_next);
+    }
+  }
 }
 
 // static
 int JumpList::UpdateIconFiles(const base::FilePath& icon_dir,
-                              const ShellLinkItemList& page_list,
-                              size_t slot_limit,
-                              URLIconCache* icon_cache) {
-  int icons_created = 0;
+                              const ShellLinkItemList& item_list,
+                              size_t max_items,
+                              URLIconCache* icon_cur,
+                              URLIconCache* icon_next) {
+  DCHECK(icon_cur);
+  DCHECK(icon_next);
 
-  // Clear the JumpList icon folder at |icon_dir| and the cache when
-  // 1) |icon_cache| is empty. This happens when "Most visited" or "Recently
+  // Clear the JumpList icon folder at |icon_dir| and the caches when
+  // 1) |icon_cur| is empty. This happens when "Most visited" or "Recently
   //    closed" category updates for the 1st time after Chrome is launched.
   // 2) The number of icons in |icon_dir| has exceeded the limit.
-  if (icon_cache->empty() || FilesExceedLimitInDir(icon_dir, slot_limit * 2)) {
+  if (icon_cur->empty() || FilesExceedLimitInDir(icon_dir, max_items * 2)) {
     DeleteDirectoryContentAndLogRuntime(icon_dir, kFileDeleteLimit);
-    icon_cache->clear();
+    icon_cur->clear();
+    icon_next->clear();
     // Create new icons only when the directory exists and is empty.
-    if (base::CreateDirectory(icon_dir) && base::IsDirectoryEmpty(icon_dir))
-      icons_created +=
-          CreateIconFiles(icon_dir, page_list, slot_limit, icon_cache);
-  } else if (base::CreateDirectory(icon_dir)) {
-    icons_created +=
-        CreateIconFiles(icon_dir, page_list, slot_limit, icon_cache);
-    DeleteIconFiles(icon_dir, icon_cache);
+    if (!base::CreateDirectory(icon_dir) || !base::IsDirectoryEmpty(icon_dir))
+      return 0;
+  } else if (!base::CreateDirectory(icon_dir)) {
+    return 0;
   }
 
-  return icons_created;
+  return CreateIconFiles(icon_dir, item_list, max_items, *icon_cur, icon_next);
 }
 
 // static
 int JumpList::CreateIconFiles(const base::FilePath& icon_dir,
                               const ShellLinkItemList& item_list,
                               size_t max_items,
-                              URLIconCache* icon_cache) {
+                              const URLIconCache& icon_cur,
+                              URLIconCache* icon_next) {
+  DCHECK(icon_next);
+
   // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/40407.
   SCOPED_UMA_HISTOGRAM_TIMER("WinJumplist.CreateIconFilesDuration");
 
   int icons_created = 0;
 
   // Reuse icons for urls that already present in the current JumpList.
-  URLIconCache updated_map;
   for (ShellLinkItemList::const_iterator iter = item_list.begin();
        iter != item_list.end() && max_items > 0; ++iter, --max_items) {
     ShellLinkItem* item = iter->get();
-    auto cache_iter = icon_cache->find(item->url());
-    if (cache_iter != icon_cache->end()) {
+    auto cache_iter = icon_cur.find(item->url());
+    if (cache_iter != icon_cur.end()) {
       item->set_icon(cache_iter->second.value(), 0);
-      updated_map[item->url()] = cache_iter->second;
+      (*icon_next)[item->url()] = cache_iter->second;
     } else {
       base::FilePath icon_path;
       if (CreateIconFile(item->icon_image(), icon_dir, &icon_path)) {
         ++icons_created;
         item->set_icon(icon_path.value(), 0);
-        updated_map[item->url()] = icon_path;
+        (*icon_next)[item->url()] = icon_path;
       }
     }
   }
-  icon_cache->swap(updated_map);
 
   return icons_created;
 }
 
 // static
 void JumpList::DeleteIconFiles(const base::FilePath& icon_dir,
-                               URLIconCache* icon_cache) {
+                               const URLIconCache& icons_cache) {
   // Put all cached icon file paths into a set.
   base::flat_set<base::FilePath> cached_files;
-  cached_files.reserve(icon_cache->size());
+  cached_files.reserve(icons_cache.size());
 
-  for (const auto& url_path_pair : *icon_cache)
+  for (const auto& url_path_pair : icons_cache)
     cached_files.insert(url_path_pair.second);
 
   DeleteNonCachedFiles(icon_dir, cached_files);
diff --git a/chrome/browser/win/jumplist.h b/chrome/browser/win/jumplist.h
index da68edb..30df9199 100644
--- a/chrome/browser/win/jumplist.h
+++ b/chrome/browser/win/jumplist.h
@@ -71,22 +71,26 @@
   using UrlAndLinkItem = std::pair<std::string, scoped_refptr<ShellLinkItem>>;
   using URLIconCache = base::flat_map<std::string, base::FilePath>;
 
-  // Holds results of the RunUpdateJumpList run.
-  struct UpdateResults {
-    UpdateResults();
-    ~UpdateResults();
+  // Holds results of a RunUpdateJumpList run.
+  // In-out params:
+  //   |most_visited_icons|, |recently_closed_icons|
+  // Out params:
+  //   |update_success|, |update_timeout|
+  struct UpdateTransaction {
+    UpdateTransaction();
+    ~UpdateTransaction();
 
     // Icon file paths of the most visited links, indexed by tab url.
     // Holding a copy of most_visited_icons_ initially, it's updated by the
     // JumpList update run. If the update run succeeds, it overwrites
     // most_visited_icons_.
-    URLIconCache most_visited_icons_in_update;
+    URLIconCache most_visited_icons;
 
-    // icon file paths of the recently closed links, indexed by tab url.
+    // Icon file paths of the recently closed links, indexed by tab url.
     // Holding a copy of recently_closed_icons_ initially, it's updated by the
     // JumpList update run. If the update run succeeds, it overwrites
     // recently_closed_icons_.
-    URLIconCache recently_closed_icons_in_update;
+    URLIconCache recently_closed_icons;
 
     // A flag indicating if a JumpList update run is successful.
     bool update_success = false;
@@ -161,10 +165,12 @@
   // folders.
   void PostRunUpdate();
 
-  // Callback for RunUpdateJumpList that notifies when it finishes running.
-  // Updates certain JumpList member variables and/or triggers a new JumpList
-  // update based on |update_results|.
-  void OnRunUpdateCompletion(std::unique_ptr<UpdateResults> update_results);
+  // Handles the completion of an update by incorporating its results in
+  // |update_transaction| back into this instance. Additionally, a new update is
+  // triggered as needed to process notifications that arrived while the
+  // now-completed update was running.
+  void OnRunUpdateCompletion(
+      std::unique_ptr<UpdateTransaction> update_transaction);
 
   // Cancels a pending JumpList update.
   void CancelPendingUpdate();
@@ -174,42 +180,58 @@
   // the |profile_| is destroyed.
   void Terminate();
 
-  // Updates the application JumpList, which consists of 1) create new icon
-  // files; 2) delete obsolete icon files; 3) notify the OS.
-  // Note that any timeout error along the way results in the old JumpList being
-  // left as-is, while any non-timeout error results in the old JumpList being
-  // left as-is, but without icon files.
+  // Updates the application JumpList, which consists of 1) create a new
+  // JumpList along with any icons that are not in the cache; 2) notify the OS;
+  // 3) delete obsolete icon files. Any error along the way results in the old
+  // JumpList being left as-is.
   static void RunUpdateJumpList(
       const base::string16& app_id,
       const base::FilePath& profile_dir,
       const ShellLinkItemList& most_visited_pages,
       const ShellLinkItemList& recently_closed_pages,
-      bool most_visited_pages_have_updates,
-      bool recently_closed_pages_have_updates,
+      bool most_visited_should_update,
+      bool recently_closed_should_update,
       IncognitoModePrefs::Availability incognito_availability,
-      UpdateResults* update_results);
+      UpdateTransaction* update_transaction);
 
-  // Updates icon files for |page_list| in |icon_dir|, which consists of
-  // 1) creating at most |slot_limit| new icons which are not in |icon_cache|;
-  // 2) deleting old icons which are not in |icon_cache|.
-  // Returns the number of new icon files created.
+  // Creates a new JumpList along with any icons that are not in the cache,
+  // and notifies the OS.
+  static void CreateNewJumpListAndNotifyOS(
+      const base::string16& app_id,
+      const base::FilePath& most_visited_icon_dir,
+      const base::FilePath& recently_closed_icon_dir,
+      const ShellLinkItemList& most_visited_pages,
+      const ShellLinkItemList& recently_closed_pages,
+      bool most_visited_should_update,
+      bool recently_closed_should_update,
+      IncognitoModePrefs::Availability incognito_availability,
+      UpdateTransaction* update_transaction);
+
+  // Updates icon files for |item_list| in |icon_dir|, which consists of
+  // 1) If certain safe conditions are not met, clean the folder at |icon_dir|.
+  // If folder cleaning fails, skip step 2. Besides, clear |icon_cur| and
+  // |icon_next|.
+  // 2) Create at most |max_items| icon files which are not in |icon_cur| for
+  // the asynchrounously loaded icons stored in |item_list|.
   static int UpdateIconFiles(const base::FilePath& icon_dir,
-                             const ShellLinkItemList& page_list,
-                             size_t slot_limit,
-                             URLIconCache* icon_cache);
+                             const ShellLinkItemList& item_list,
+                             size_t max_items,
+                             URLIconCache* icon_cur,
+                             URLIconCache* icon_next);
 
   // In |icon_dir|, creates at most |max_items| icon files which are not in
-  // |icon_cache| for the asynchrounously loaded icons stored in |item_list|.
-  // |icon_cache| is also updated for newly created icons.
-  // Returns the number of new icon files created.
+  // |icon_cur| for the asynchrounously loaded icons stored in |item_list|.
+  // |icon_next| is updated based on the reusable icons and the newly created
+  // icons. Returns the number of new icon files created.
   static int CreateIconFiles(const base::FilePath& icon_dir,
                              const ShellLinkItemList& item_list,
                              size_t max_items,
-                             URLIconCache* icon_cache);
+                             const URLIconCache& icon_cur,
+                             URLIconCache* icon_next);
 
-  // Deletes icon files in |icon_dir| which are not in |icon_cache| anymore.
+  // Deletes icon files in |icon_dir| which are not in |icon_cache|.
   static void DeleteIconFiles(const base::FilePath& icon_dir,
-                              URLIconCache* icon_cache);
+                              const URLIconCache& icons_cache);
 
   // Tracks FaviconService tasks.
   base::CancelableTaskTracker cancelable_task_tracker_;
diff --git a/chrome/browser/win/settings_app_monitor.cc b/chrome/browser/win/settings_app_monitor.cc
index 1f67ad4..57407cc 100644
--- a/chrome/browser/win/settings_app_monitor.cc
+++ b/chrome/browser/win/settings_app_monitor.cc
@@ -800,7 +800,7 @@
 }
 
 SettingsAppMonitor::~SettingsAppMonitor() {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   // context_ is still valid when the caller destroys the instance before the
   // callback(s) have fired. In this case, delete the context on the automation
@@ -813,32 +813,32 @@
 }
 
 void SettingsAppMonitor::OnInitialized(HRESULT result) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   delegate_->OnInitialized(result);
 }
 
 void SettingsAppMonitor::OnAppFocused() {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   delegate_->OnAppFocused();
 }
 
 void SettingsAppMonitor::OnChooserInvoked() {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   delegate_->OnChooserInvoked();
 }
 
 void SettingsAppMonitor::OnBrowserChosen(const base::string16& browser_name) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   delegate_->OnBrowserChosen(browser_name);
 }
 
 void SettingsAppMonitor::OnPromoFocused() {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   delegate_->OnPromoFocused();
 }
 
 void SettingsAppMonitor::OnPromoChoiceMade(bool accept_promo) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   delegate_->OnPromoChoiceMade(accept_promo);
 }
 
diff --git a/chrome/browser/win/settings_app_monitor.h b/chrome/browser/win/settings_app_monitor.h
index 9e6ee68..90677283 100644
--- a/chrome/browser/win/settings_app_monitor.h
+++ b/chrome/browser/win/settings_app_monitor.h
@@ -10,10 +10,10 @@
 #include "base/callback_forward.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "base/sequence_checker.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_piece.h"
 #include "base/threading/thread.h"
-#include "base/threading/thread_checker.h"
 
 namespace shell_integration {
 namespace win {
@@ -65,7 +65,7 @@
   void OnPromoFocused();
   void OnPromoChoiceMade(bool accept_promo);
 
-  base::ThreadChecker thread_checker_;
+  SEQUENCE_CHECKER(sequence_checker_);
   Delegate* delegate_;
 
   // A thread in the COM MTA in which automation calls are made.
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 28d3183..99098ff 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -121,6 +121,9 @@
 const base::Feature kCheckInstallabilityForBannerOnLoad{
     "CheckInstallabilityForBannerOnLoad", base::FEATURE_DISABLED_BY_DEFAULT};
 
+const base::Feature kClickToOpenPDFPlaceholder{
+    "ClickToOpenPDFPlaceholder", base::FEATURE_DISABLED_BY_DEFAULT};
+
 #if defined(OS_ANDROID)
 // Experiment to make Geolocation permissions in the omnibox and the default
 // search engine's search page consistent.
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index 014f3fd..51579cd6 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -66,6 +66,8 @@
 
 extern const base::Feature kCheckInstallabilityForBannerOnLoad;
 
+extern const base::Feature kClickToOpenPDFPlaceholder;
+
 #if defined(OS_ANDROID)
 extern const base::Feature kConsistentOmniboxGeolocation;
 #endif
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 3f0fa05..2f4e2f1 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -320,6 +320,11 @@
 // Enables Domain Reliability Monitoring.
 const char kEnableDomainReliability[] = "enable-domain-reliability";
 
+// Enables an experimental full screen exit UI to allow exiting fullscreen from
+// mouse or touch.
+const char kEnableExperimentalFullscreenExitUI[] =
+    "enable-experimental-fullscreen-exit-ui";
+
 // Enables experimental hotword features specific to always-on.
 const char kEnableExperimentalHotwordHardware[] = "enable-hotword-hardware";
 
@@ -1101,6 +1106,9 @@
 
 // Communicates the pipe name for out-of-process memory logging.
 const char kMemlogPipe[] = "memlog-pipe";
+
+// Value passed to kProcessType switch that indicates the profiling process.
+const char kProfiling[] = "profiling";
 #endif
 
 bool ExtensionsDisabled(const base::CommandLine& command_line) {
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index dd1d5121..9551a1b 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -106,6 +106,7 @@
 extern const char kEnableDeviceDiscoveryNotifications[];
 extern const char kEnableDevToolsExperiments[];
 extern const char kEnableDomainReliability[];
+extern const char kEnableExperimentalFullscreenExitUI[];
 extern const char kEnableExperimentalHotwordHardware[];
 extern const char kEnableExtensionActivityLogging[];
 extern const char kEnableExtensionActivityLogTesting[];
@@ -348,6 +349,7 @@
 #if BUILDFLAG(ENABLE_OOP_HEAP_PROFILING)
 extern const char kMemlog[];
 extern const char kMemlogPipe[];
+extern const char kProfiling[];
 #endif
 
 bool ExtensionsDisabled(const base::CommandLine& command_line);
diff --git a/chrome/common/crash_keys.cc b/chrome/common/crash_keys.cc
index 1c4c367..51e3812 100644
--- a/chrome/common/crash_keys.cc
+++ b/chrome/common/crash_keys.cc
@@ -127,6 +127,7 @@
     {gpu::crash_keys::kGPUVendor, kSmallSize},
     {gpu::crash_keys::kGPURenderer, kSmallSize},
 #endif
+    {gpu::crash_keys::kGPUGLContextIsVirtual, kSmallSize},
 
     // content/:
     {"bad_message_reason", kSmallSize},
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index de87fe5..40319de 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -2569,6 +2569,29 @@
 
 #if BUILDFLAG(ENABLE_OFFLINE_PAGES)
 const char kOfflinePrefetchBackoff[] = "offline_prefetch.backoff";
+
+// The following set of Prefs is used by OfflineMetricsCollectorImpl to
+// backup the current Chrome usage tracking state and accumulated counters
+// of days with specific Chrome usage.
+
+// The boolean flags indicating whether the specific activity was observed
+// in Chrome during the day that started at |kOfflineUsageTrackingDay|. These
+// are used to track usage of Chrome is used while offline and how various
+// offline features affect that.
+const char kOfflineUsageStartObserved[] = "offline_pages.start_observed";
+const char kOfflineUsageOnlineObserved[] = "offline_pages.online_observed";
+const char kOfflineUsageOfflineObserved[] = "offline_pages.offline_observed";
+// A time corresponding to a midnight that starts the day for which
+// OfflineMetricsCollector tracks the Chrome usage. Once current time passes
+// 24hrs from this point, the further tracking is attributed to the next day.
+const char kOfflineUsageTrackingDay[] = "offline_pages.tracking_day";
+// Accumulated counters of days with specified Chrome usage. When there is
+// likely a network connection, these counters are reported via UMA and reset.
+const char kOfflineUsageUnusedCount[] = "offline_pages.unused_count";
+const char kOfflineUsageStartedCount[] = "offline_pages.started_count";
+const char kOfflineUsageOfflineCount[] = "offline_pages.offline_count";
+const char kOfflineUsageOnlineCount[] = "offline_pages.online_count";
+const char kOfflineUsageMixedCount[] = "offline_pages.mixed_count";
 #endif
 
 }  // namespace prefs
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index a788216a..da5aece1 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -930,6 +930,15 @@
 
 #if BUILDFLAG(ENABLE_OFFLINE_PAGES)
 extern const char kOfflinePrefetchBackoff[];
+extern const char kOfflineUsageStartObserved[];
+extern const char kOfflineUsageOnlineObserved[];
+extern const char kOfflineUsageOfflineObserved[];
+extern const char kOfflineUsageTrackingDay[];
+extern const char kOfflineUsageUnusedCount[];
+extern const char kOfflineUsageStartedCount[];
+extern const char kOfflineUsageOfflineCount[];
+extern const char kOfflineUsageOnlineCount[];
+extern const char kOfflineUsageMixedCount[];
 #endif
 
 }  // namespace prefs
diff --git a/chrome/common/profiling/memlog_sender.cc b/chrome/common/profiling/memlog_sender.cc
index 4b3160b..29d066f 100644
--- a/chrome/common/profiling/memlog_sender.cc
+++ b/chrome/common/profiling/memlog_sender.cc
@@ -5,6 +5,7 @@
 #include "chrome/common/profiling/memlog_sender.h"
 
 #include "base/command_line.h"
+#include "base/strings/utf_string_conversions.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/profiling/memlog_allocator_shim.h"
 #include "chrome/common/profiling/memlog_sender_pipe.h"
@@ -13,12 +14,13 @@
 namespace profiling {
 
 void InitMemlogSenderIfNecessary(const base::CommandLine& cmdline) {
-  base::CommandLine::StringType pipe_id =
-      cmdline.GetSwitchValueNative(switches::kMemlogPipe);
-  if (pipe_id.empty())
-    return;  // No pipe, don't run.
+  std::string pipe_id = cmdline.GetSwitchValueASCII(switches::kMemlogPipe);
+  if (!pipe_id.empty())
+    StartMemlogSender(pipe_id);
+}
 
-  static MemlogSenderPipe pipe(pipe_id);
+void StartMemlogSender(const std::string& pipe_id) {
+  static MemlogSenderPipe pipe(base::UTF8ToUTF16(pipe_id));
   pipe.Connect();
 
   StreamHeader header;
diff --git a/chrome/common/profiling/memlog_sender.h b/chrome/common/profiling/memlog_sender.h
index cda630f..bb4b509 100644
--- a/chrome/common/profiling/memlog_sender.h
+++ b/chrome/common/profiling/memlog_sender.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_COMMON_PROFILING_MEMLOG_SENDER_H_
 #define CHROME_COMMON_PROFILING_MEMLOG_SENDER_H_
 
+#include <string>
+
 namespace base {
 
 class CommandLine;
@@ -15,6 +17,8 @@
 
 void InitMemlogSenderIfNecessary(const base::CommandLine& cmdline);
 
+void StartMemlogSender(const std::string& pipe_id);
+
 }  // namespace profiling
 
 #endif  // CHROME_COMMON_PROFILING_MEMLOG_SENDER_H_
diff --git a/chrome/installer/linux/debian/expected_deps_ia32_jessie b/chrome/installer/linux/debian/expected_deps_ia32_jessie
index a35407e..14b71ac 100644
--- a/chrome/installer/linux/debian/expected_deps_ia32_jessie
+++ b/chrome/installer/linux/debian/expected_deps_ia32_jessie
@@ -1,8 +1,7 @@
 gconf-service
 libasound2 (>= 1.0.16)
 libatk1.0-0 (>= 1.12.4)
-libc6 (>= 2.3.6-6~)
-libc6 (>= 2.9)
+libc6 (>= 2.18)
 libcairo2 (>= 1.2.4)
 libcups2 (>= 1.4.0)
 libdbus-1-3 (>= 1.2.14)
@@ -17,7 +16,6 @@
 libnss3 (>= 2:3.13.4-2~)
 libpango-1.0-0 (>= 1.14.0)
 libpangocairo-1.0-0 (>= 1.14.0)
-libstdc++6 (>= 4.8.1)
 libx11-6 (>= 2:1.4.99.1)
 libx11-xcb1
 libxcb1 (>= 1.6)
diff --git a/chrome/installer/linux/debian/expected_deps_x64_jessie b/chrome/installer/linux/debian/expected_deps_x64_jessie
index 3f08359e..dcaaa2e 100644
--- a/chrome/installer/linux/debian/expected_deps_x64_jessie
+++ b/chrome/installer/linux/debian/expected_deps_x64_jessie
@@ -1,7 +1,7 @@
 gconf-service
 libasound2 (>= 1.0.16)
 libatk1.0-0 (>= 1.12.4)
-libc6 (>= 2.15)
+libc6 (>= 2.18)
 libcairo2 (>= 1.6.0)
 libcups2 (>= 1.4.0)
 libdbus-1-3 (>= 1.2.14)
@@ -16,7 +16,6 @@
 libnss3 (>= 2:3.13.4-2~)
 libpango-1.0-0 (>= 1.14.0)
 libpangocairo-1.0-0 (>= 1.14.0)
-libstdc++6 (>= 4.8.1)
 libx11-6 (>= 2:1.4.99.1)
 libx11-xcb1
 libxcb1 (>= 1.6)
diff --git a/chrome/installer/linux/rpm/build.sh b/chrome/installer/linux/rpm/build.sh
index 3714091..3a7d7f0d 100755
--- a/chrome/installer/linux/rpm/build.sh
+++ b/chrome/installer/linux/rpm/build.sh
@@ -90,7 +90,7 @@
   fi
 
   # Use find-requires script to make sure the dependencies are complete
-  # (especially libc and libstdc++ versions).
+  # (especially libc versions).
   DETECTED_DEPENDS="$(echo "${BUILDDIR}/chrome" | /usr/lib/rpm/find-requires)"
 
   # Compare the expected dependency list to the generated list.
@@ -127,8 +127,6 @@
   # libssl3.so, force the dependency on libssl3 to ensure the NSS version is
   # 3.28 or later, since libssl3 should always be packaged with libnss3.
   #
-  # libstdc++.so.6 is for C++11 support.
-  #
   # wget is for uploading crash reports with Breakpad.
   #
   # xdg-utils is still optional in LSB 4.0.
@@ -149,7 +147,6 @@
   DEPENDS="lsb >= 4.0, \
   libnss3.so(NSS_3.22)${PKG_ARCH}, \
   libssl3.so(NSS_3.28)${PKG_ARCH}, \
-  libstdc++.so.6(GLIBCXX_3.4.18)${PKG_ARCH}, \
   wget, \
   xdg-utils, \
   zlib, \
diff --git a/chrome/installer/linux/rpm/expected_deps_i386 b/chrome/installer/linux/rpm/expected_deps_i386
index 72004fb..22b82c3 100644
--- a/chrome/installer/linux/rpm/expected_deps_i386
+++ b/chrome/installer/linux/rpm/expected_deps_i386
@@ -16,13 +16,14 @@
 libasound.so.2
 libatk-1.0.so.0
 libc.so.6
-libc.so.6(GLIBC_2.0)
-libc.so.6(GLIBC_2.1)
-libc.so.6(GLIBC_2.1.3)
-libc.so.6(GLIBC_2.2)
-libc.so.6(GLIBC_2.2.3)
+libc.so.6(GLIBC_2.11)
+libc.so.6(GLIBC_2.14)
+libc.so.6(GLIBC_2.15)
+libc.so.6(GLIBC_2.18)
+libc.so.6(GLIBC_2.2.5)
 libc.so.6(GLIBC_2.3)
 libc.so.6(GLIBC_2.3.2)
+libc.so.6(GLIBC_2.3.3)
 libc.so.6(GLIBC_2.3.4)
 libc.so.6(GLIBC_2.4)
 libc.so.6(GLIBC_2.6)
@@ -37,7 +38,6 @@
 libexpat.so.1
 libfontconfig.so.1
 libgcc_s.so.1
-libgcc_s.so.1(GCC_4.0.0)
 libgcc_s.so.1(GLIBC_2.0)
 libgconf-2.so.4
 libgdk-x11-2.0.so.0
@@ -65,12 +65,4 @@
 librt.so.1
 librt.so.1(GLIBC_2.2)
 libsmime3.so
-libstdc++.so.6
-libstdc++.so.6(GLIBCXX_3.4)
-libstdc++.so.6(GLIBCXX_3.4.11)
-libstdc++.so.6(GLIBCXX_3.4.14)
-libstdc++.so.6(GLIBCXX_3.4.15)
-libstdc++.so.6(GLIBCXX_3.4.18)
-libstdc++.so.6(GLIBCXX_3.4.19)
-libstdc++.so.6(GLIBCXX_3.4.9)
 libxcb.so.1
diff --git a/chrome/installer/linux/rpm/expected_deps_x86_64 b/chrome/installer/linux/rpm/expected_deps_x86_64
index e3c3556..4e8ed436 100644
--- a/chrome/installer/linux/rpm/expected_deps_x86_64
+++ b/chrome/installer/linux/rpm/expected_deps_x86_64
@@ -18,9 +18,11 @@
 libc.so.6(GLIBC_2.11)(64bit)
 libc.so.6(GLIBC_2.14)(64bit)
 libc.so.6(GLIBC_2.15)(64bit)
+libc.so.6(GLIBC_2.18)(64bit)
 libc.so.6(GLIBC_2.2.5)(64bit)
 libc.so.6(GLIBC_2.3)(64bit)
 libc.so.6(GLIBC_2.3.2)(64bit)
+libc.so.6(GLIBC_2.3.3)(64bit)
 libc.so.6(GLIBC_2.3.4)(64bit)
 libc.so.6(GLIBC_2.4)(64bit)
 libc.so.6(GLIBC_2.6)(64bit)
@@ -35,7 +37,6 @@
 libfontconfig.so.1()(64bit)
 libgcc_s.so.1()(64bit)
 libgcc_s.so.1(GCC_3.0)(64bit)
-libgcc_s.so.1(GCC_4.0.0)(64bit)
 libgconf-2.so.4()(64bit)
 libgdk-3.so.0()(64bit)
 libgdk_pixbuf-2.0.so.0()(64bit)
@@ -58,12 +59,4 @@
 librt.so.1()(64bit)
 librt.so.1(GLIBC_2.2.5)(64bit)
 libsmime3.so()(64bit)
-libstdc++.so.6()(64bit)
-libstdc++.so.6(GLIBCXX_3.4)(64bit)
-libstdc++.so.6(GLIBCXX_3.4.11)(64bit)
-libstdc++.so.6(GLIBCXX_3.4.14)(64bit)
-libstdc++.so.6(GLIBCXX_3.4.15)(64bit)
-libstdc++.so.6(GLIBCXX_3.4.18)(64bit)
-libstdc++.so.6(GLIBCXX_3.4.19)(64bit)
-libstdc++.so.6(GLIBCXX_3.4.9)(64bit)
 libxcb.so.1()(64bit)
diff --git a/chrome/installer/mac/app/Info.plist b/chrome/installer/mac/app/Info.plist
index 7eb0404..ef2f4fc 100644
--- a/chrome/installer/mac/app/Info.plist
+++ b/chrome/installer/mac/app/Info.plist
@@ -23,7 +23,7 @@
   <key>CFBundleVersion</key>
   <string>1</string>
   <key>LSMinimumSystemVersion</key>
-  <string>10.9.0</string>
+  <string>${MACOSX_DEPLOYMENT_TARGET}</string>
   <key>NSHumanReadableCopyright</key>
   <string>Copyright © 2016 Google. All rights reserved.</string>
   <key>NSMainNibFile</key>
diff --git a/chrome/installer/zucchini/BUILD.gn b/chrome/installer/zucchini/BUILD.gn
index f3ef26bc..e74142a2 100644
--- a/chrome/installer/zucchini/BUILD.gn
+++ b/chrome/installer/zucchini/BUILD.gn
@@ -25,9 +25,14 @@
 }
 
 test("zucchini_unittests") {
-  sources = []
+  sources = [
+    "buffer_view_unittest.cc",
+  ]
 
   deps = [
+    "//base",
     "//base/test:run_all_unittests",
+    "//base/test:test_support",
+    "//testing/gtest",
   ]
 }
diff --git a/chrome/installer/zucchini/buffer_view.h b/chrome/installer/zucchini/buffer_view.h
new file mode 100644
index 0000000..f2876ae
--- /dev/null
+++ b/chrome/installer/zucchini/buffer_view.h
@@ -0,0 +1,91 @@
+// 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 CHROME_INSTALLER_ZUCCHINI_BUFFER_VIEW_H_
+#define CHROME_INSTALLER_ZUCCHINI_BUFFER_VIEW_H_
+
+#include <cstddef>
+#include <cstdint>
+#include <type_traits>
+
+#include "base/logging.h"
+
+namespace zucchini {
+namespace internal {
+
+// A class that encapsulates a contiguous sequence of raw data.
+// It does not own the memory region it encapsulates.
+// BufferViewBase should not be used directly; it is an implementation
+// used for both BufferView and MutableBufferView.
+template <class T>
+class BufferViewBase {
+ public:
+  using value_type = T;
+  using reference = T&;
+  using pointer = T*;
+  using iterator = T*;
+  using const_iterator = typename std::add_const<T>::type*;
+  using size_type = std::size_t;
+  using difference_type = std::ptrdiff_t;
+
+  static BufferViewBase FromRange(iterator first, iterator last) {
+    DCHECK(last >= first);
+    BufferViewBase ret;
+    ret.first_ = first;
+    ret.last_ = last;
+    return ret;
+  }
+
+  BufferViewBase() = default;
+
+  BufferViewBase(iterator first, size_type size)
+      : first_(first), last_(first_ + size) {}
+  BufferViewBase(const BufferViewBase&) = default;
+  BufferViewBase& operator=(const BufferViewBase&) = default;
+
+  // Iterators
+
+  iterator begin() const { return first_; }
+  iterator end() const { return last_; }
+  const_iterator cbegin() const { return begin(); }
+  const_iterator cend() const { return end(); }
+
+  // Element access
+
+  // Returns the raw value at specified location pos.
+  reference operator[](size_type pos) const {
+    DCHECK(first_ + pos < last_);
+    return first_[pos];
+  }
+
+  // Capacity
+
+  bool empty() const { return first_ == last_; }
+  size_type size() const { return last_ - first_; }
+
+  // Modifiers
+
+  void shrink(size_type new_size) {
+    DCHECK(first_ + new_size <= last_);
+    last_ = first_ + new_size;
+  }
+
+ private:
+  iterator first_ = nullptr;
+  iterator last_ = nullptr;
+};
+
+}  // namespace internal
+
+// A class that encapsulates a constant contiguous sequence of raw data.
+// It does not own the memory region it refers to.
+using BufferView = internal::BufferViewBase<const uint8_t>;
+
+// A class that encapsulates a mutable contiguous sequence of raw data.
+// It does not own the memory region it refers to.
+using MutableBufferView = internal::BufferViewBase<uint8_t>;
+
+}  // namespace zucchini
+
+#endif  // CHROME_INSTALLER_ZUCCHINI_BUFFER_VIEW_H_
diff --git a/chrome/installer/zucchini/buffer_view_unittest.cc b/chrome/installer/zucchini/buffer_view_unittest.cc
new file mode 100644
index 0000000..dbdda345
--- /dev/null
+++ b/chrome/installer/zucchini/buffer_view_unittest.cc
@@ -0,0 +1,82 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/installer/zucchini/buffer_view.h"
+
+#include <iterator>
+#include <type_traits>
+
+#include "base/test/gtest_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace zucchini {
+
+class BufferViewTest : public testing::Test {
+ protected:
+  static constexpr size_t kLen = 10;
+
+  // Some tests might modify this.
+  uint8_t bytes_[kLen] = {0x10, 0x32, 0x54, 0x76, 0x98,
+                          0xBA, 0xDC, 0xFE, 0x10, 0x00};
+};
+
+constexpr size_t BufferViewTest::kLen;
+
+TEST_F(BufferViewTest, Size) {
+  for (size_t len = 0; len <= kLen; ++len) {
+    EXPECT_EQ(len, BufferView(std::begin(bytes_), len).size());
+    EXPECT_EQ(len, MutableBufferView(std::begin(bytes_), len).size());
+  }
+}
+
+TEST_F(BufferViewTest, Empty) {
+  // Empty view.
+  EXPECT_TRUE(BufferView(std::begin(bytes_), 0).empty());
+  EXPECT_TRUE(MutableBufferView(std::begin(bytes_), 0).empty());
+
+  for (size_t len = 1; len <= kLen; ++len) {
+    EXPECT_FALSE(BufferView(std::begin(bytes_), len).empty());
+    EXPECT_FALSE(MutableBufferView(std::begin(bytes_), len).empty());
+  }
+}
+
+TEST_F(BufferViewTest, FromRange) {
+  BufferView buffer =
+      BufferView::FromRange(std::begin(bytes_), std::end(bytes_));
+  EXPECT_EQ(kLen, buffer.size());
+  EXPECT_EQ(std::begin(bytes_), buffer.begin());
+
+  EXPECT_DCHECK_DEATH(
+      BufferView::FromRange(std::end(bytes_), std::begin(bytes_)));
+
+  EXPECT_DCHECK_DEATH(
+      BufferView::FromRange(std::begin(bytes_) + 1, std::begin(bytes_)));
+}
+
+TEST_F(BufferViewTest, Subscript) {
+  BufferView view(std::begin(bytes_), kLen);
+
+  EXPECT_EQ(0x10, view[0]);
+  static_assert(!std::is_assignable<decltype(view[0]), uint8_t>::value,
+                "BufferView values should not be mutable.");
+
+  MutableBufferView mutable_view(std::begin(bytes_), kLen);
+
+  EXPECT_EQ(&bytes_[0], &mutable_view[0]);
+  mutable_view[0] = 42;
+  EXPECT_EQ(42, mutable_view[0]);
+}
+
+TEST_F(BufferViewTest, Shrink) {
+  BufferView buffer =
+      BufferView::FromRange(std::begin(bytes_), std::end(bytes_));
+
+  buffer.shrink(kLen);
+  EXPECT_EQ(kLen, buffer.size());
+  buffer.shrink(2);
+  EXPECT_EQ(size_t(2), buffer.size());
+  EXPECT_DCHECK_DEATH(buffer.shrink(kLen));
+}
+
+}  // namespace zucchini
diff --git a/chrome/profiling/memlog_stream_parser.h b/chrome/profiling/memlog_stream_parser.h
index 1418d0b..dd462d9 100644
--- a/chrome/profiling/memlog_stream_parser.h
+++ b/chrome/profiling/memlog_stream_parser.h
@@ -38,7 +38,7 @@
     READ_NO_DATA  // Not enough data, try again when we get more
   };
 
-  ~MemlogStreamParser() override;
+  ~MemlogStreamParser();
 
   // Returns true if the given number of bytes are available now.
   bool AreBytesAvailable(size_t count) const;
diff --git a/chrome/profiling/memlog_stream_receiver.h b/chrome/profiling/memlog_stream_receiver.h
index bd21d11a..8a0c9b1 100644
--- a/chrome/profiling/memlog_stream_receiver.h
+++ b/chrome/profiling/memlog_stream_receiver.h
@@ -27,7 +27,7 @@
 
  protected:
   friend class base::RefCountedThreadSafe<MemlogStreamReceiver>;
-  ~MemlogStreamReceiver() override {}
+  ~MemlogStreamReceiver() {}
 };
 
 }  // namespace profiling
diff --git a/chrome/profiling/profiling_main.cc b/chrome/profiling/profiling_main.cc
index c9c46679..e549194 100644
--- a/chrome/profiling/profiling_main.cc
+++ b/chrome/profiling/profiling_main.cc
@@ -4,17 +4,7 @@
 
 #include "chrome/profiling/profiling_main.h"
 
-#include "base/base_paths.h"
 #include "base/command_line.h"
-#include "base/files/file_path.h"
-#include "base/path_service.h"
-#include "base/process/launch.h"
-#include "base/process/process.h"
-#include "base/process/process_metrics.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
 #include "build/build_config.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/profiling/profiling_globals.h"
@@ -27,65 +17,6 @@
 
 namespace profiling {
 
-namespace {
-
-base::CommandLine MakeBrowserCommandLine(const base::CommandLine& cmdline,
-                                         const std::string& pipe_id) {
-  const base::CommandLine::StringVector& our_argv = cmdline.argv();
-
-  base::CommandLine::StringVector browser_argv;
-  browser_argv.reserve(our_argv.size());
-
-  // Program name.
-  base::FilePath child_path;
-#if defined(OS_LINUX)
-  // Use /proc/self/exe rather than our known binary path so updates
-  // can't swap out the binary from underneath us.
-  // When running under Valgrind, forking /proc/self/exe ends up forking the
-  // Valgrind executable, which then crashes. However, it's almost safe to
-  // assume that the updates won't happen while testing with Valgrind tools.
-  if (!RunningOnValgrind())
-    child_path = base::FilePath(base::kProcSelfExe);
-#endif
-
-  if (child_path.empty())
-    base::PathService::Get(base::FILE_EXE, &child_path);
-  browser_argv.push_back(child_path.value());  // Program name.
-
-  // Remove all memlog flags.
-  for (size_t i = 1; i < our_argv.size(); i++) {
-    if (!base::StartsWith(our_argv[i], FILE_PATH_LITERAL("--memlog"),
-                          base::CompareCase::SENSITIVE))
-      browser_argv.push_back(our_argv[i]);
-  }
-
-  // Append the pipe ID.
-  std::string pipe_switch("--");
-  pipe_switch.append(switches::kMemlogPipe);
-  pipe_switch.push_back('=');
-  pipe_switch.append(pipe_id);
-#if defined(OS_WIN)
-  browser_argv.push_back(base::ASCIIToUTF16(pipe_switch));
-#else
-  browser_argv.push_back(pipe_switch);
-#endif
-
-  return base::CommandLine(browser_argv);
-}
-
-bool LaunchBrowser(const base::CommandLine& our_cmdline,
-                   const std::string& pipe_id) {
-  base::CommandLine browser_cmdline =
-      MakeBrowserCommandLine(our_cmdline, pipe_id);
-
-  base::LaunchOptions options;
-  base::Process process = base::LaunchProcess(browser_cmdline, options);
-
-  return true;
-}
-
-}  // namespace
-
 int ProfilingMain(const base::CommandLine& cmdline) {
   ProfilingGlobals* globals = ProfilingGlobals::Get();
 
@@ -94,14 +25,9 @@
       globals->GetIORunner(),
       mojo::edk::ScopedIPCSupport::ShutdownPolicy::CLEAN);
 
-  base::Process process = base::Process::Current();
-  std::string pipe_id = base::IntToString(static_cast<int>(process.Pid()));
-
+  std::string pipe_id = cmdline.GetSwitchValueASCII(switches::kMemlogPipe);
   globals->GetMemlogConnectionManager()->StartConnections(pipe_id);
 
-  if (!LaunchBrowser(cmdline, pipe_id))
-    return 1;
-
   ProfilingGlobals::Get()->RunMainMessageLoop();
 
 #if defined(OS_WIN)
diff --git a/chrome/profiling/profiling_main.h b/chrome/profiling/profiling_main.h
index 0d30b02..136b867 100644
--- a/chrome/profiling/profiling_main.h
+++ b/chrome/profiling/profiling_main.h
@@ -11,6 +11,7 @@
 
 namespace profiling {
 
+// Main function for the profiling process type.
 int ProfilingMain(const base::CommandLine& cmdline);
 
 }  // namespace profiling
diff --git a/chrome/renderer/extensions/automation_internal_custom_bindings.h b/chrome/renderer/extensions/automation_internal_custom_bindings.h
index 78fb66e..f33db545 100644
--- a/chrome/renderer/extensions/automation_internal_custom_bindings.h
+++ b/chrome/renderer/extensions/automation_internal_custom_bindings.h
@@ -5,6 +5,9 @@
 #ifndef CHROME_RENDERER_EXTENSIONS_AUTOMATION_INTERNAL_CUSTOM_BINDINGS_H_
 #define CHROME_RENDERER_EXTENSIONS_AUTOMATION_INTERNAL_CUSTOM_BINDINGS_H_
 
+#include <map>
+#include <vector>
+
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "chrome/common/extensions/api/automation.h"
@@ -178,8 +181,8 @@
   void SendChildTreeIDEvent(ui::AXTree* tree, ui::AXNode* node);
   void SendNodesRemovedEvent(ui::AXTree* tree, const std::vector<int>& ids);
 
-  base::hash_map<int, TreeCache*> tree_id_to_tree_cache_map_;
-  base::hash_map<ui::AXTree*, TreeCache*> axtree_to_tree_cache_map_;
+  std::map<int, TreeCache*> tree_id_to_tree_cache_map_;
+  std::map<ui::AXTree*, TreeCache*> axtree_to_tree_cache_map_;
   scoped_refptr<AutomationMessageFilter> message_filter_;
   bool is_active_profile_;
   std::vector<TreeChangeObserver> tree_change_observers_;
diff --git a/chrome/renderer/safe_browsing/features.h b/chrome/renderer/safe_browsing/features.h
index 29fa40ca..e6f21df 100644
--- a/chrome/renderer/safe_browsing/features.h
+++ b/chrome/renderer/safe_browsing/features.h
@@ -27,8 +27,8 @@
 
 #include <stddef.h>
 #include <string>
+#include <unordered_map>
 
-#include "base/containers/hash_tables.h"
 #include "base/macros.h"
 
 namespace safe_browsing {
@@ -52,7 +52,7 @@
   bool AddRealFeature(const std::string& name, double value);
 
   // Provides read-only access to the current set of features.
-  const base::hash_map<std::string, double>& features() const {
+  const std::unordered_map<std::string, double>& features() const {
     return features_;
   }
 
@@ -65,7 +65,7 @@
   static const size_t kMaxFeatureMapSize;
 
  private:
-  base::hash_map<std::string, double> features_;
+  std::unordered_map<std::string, double> features_;
 
   DISALLOW_COPY_AND_ASSIGN(FeatureMap);
 };
diff --git a/chrome/renderer/safe_browsing/phishing_classifier.cc b/chrome/renderer/safe_browsing/phishing_classifier.cc
index 03a2caf..13902df4 100644
--- a/chrome/renderer/safe_browsing/phishing_classifier.cc
+++ b/chrome/renderer/safe_browsing/phishing_classifier.cc
@@ -194,20 +194,17 @@
     ClientPhishingRequest verdict;
     verdict.set_model_version(scorer_->model_version());
     verdict.set_url(main_frame->GetDocument().Url().GetString().Utf8());
-    for (base::hash_map<std::string, double>::const_iterator it =
-             features_->features().begin();
-         it != features_->features().end(); ++it) {
-      DVLOG(2) << "Feature: " << it->first << " = " << it->second;
+    for (const auto& it : features_->features()) {
+      DVLOG(2) << "Feature: " << it.first << " = " << it.second;
       bool result = hashed_features.AddRealFeature(
-          crypto::SHA256HashString(it->first), it->second);
+          crypto::SHA256HashString(it.first), it.second);
       DCHECK(result);
       ClientPhishingRequest::Feature* feature = verdict.add_feature_map();
-      feature->set_name(it->first);
-      feature->set_value(it->second);
+      feature->set_name(it.first);
+      feature->set_value(it.second);
     }
-    for (std::set<uint32_t>::const_iterator it = shingle_hashes_->begin();
-         it != shingle_hashes_->end(); ++it) {
-      verdict.add_shingle_hashes(*it);
+    for (const auto& it : *shingle_hashes_) {
+      verdict.add_shingle_hashes(it);
     }
     float score = static_cast<float>(scorer_->ComputeScore(hashed_features));
     verdict.set_client_score(score);
diff --git a/chrome/renderer/safe_browsing/phishing_dom_feature_extractor_browsertest.cc b/chrome/renderer/safe_browsing/phishing_dom_feature_extractor_browsertest.cc
index 7ba5f04f..b412eed0 100644
--- a/chrome/renderer/safe_browsing/phishing_dom_feature_extractor_browsertest.cc
+++ b/chrome/renderer/safe_browsing/phishing_dom_feature_extractor_browsertest.cc
@@ -5,6 +5,7 @@
 #include "chrome/renderer/safe_browsing/phishing_dom_feature_extractor.h"
 
 #include <memory>
+#include <unordered_map>
 
 #include "base/bind.h"
 #include "base/callback.h"
@@ -50,7 +51,7 @@
   void SetDocumentDomain(std::string domain) { base_domain_ = domain; }
 
   void SetURLToFrameDomainCheckingMap(
-      const base::hash_map<std::string, std::string>& checking_map) {
+      const std::unordered_map<std::string, std::string>& checking_map) {
     url_to_frame_domain_map_ = checking_map;
   }
 
@@ -122,7 +123,7 @@
   // If html contains multiple frame/iframe, we track domain of each frame by
   // using this map, where keys are the urls mentioned in the html content,
   // values are the domains of the corresponding frames.
-  base::hash_map<std::string, std::string> url_to_frame_domain_map_;
+  std::unordered_map<std::string, std::string> url_to_frame_domain_map_;
 };
 
 class TestChromeContentRendererClient : public ChromeContentRendererClient {
@@ -154,7 +155,8 @@
   void ExtractFeaturesAcrossFrames(
       const std::string& html_content,
       FeatureMap* features,
-      const base::hash_map<std::string, std::string>& url_frame_domain_map) {
+      const std::unordered_map<std::string, std::string>&
+          url_frame_domain_map) {
     extractor_->SetURLToFrameDomainCheckingMap(url_frame_domain_map);
     LoadHTML(html_content.c_str());
 
@@ -376,7 +378,7 @@
   EXPECT_CALL(clock_, Now()).WillRepeatedly(Return(base::TimeTicks::Now()));
 
   const char urlprefix[] = "data:text/html;charset=utf-8,";
-  base::hash_map<std::string, std::string> url_iframe_map;
+  std::unordered_map<std::string, std::string> url_iframe_map;
   std::string iframe1_nested_html(
       "<html><body><input type=password>"
       "<a href=\"https://host3.com/submit\">link</a>"
diff --git a/chrome/renderer/safe_browsing/scorer.cc b/chrome/renderer/safe_browsing/scorer.cc
index fc03bad..7c25f3b 100644
--- a/chrome/renderer/safe_browsing/scorer.cc
+++ b/chrome/renderer/safe_browsing/scorer.cc
@@ -7,6 +7,7 @@
 #include <math.h>
 
 #include <memory>
+#include <unordered_map>
 
 #include "base/logging.h"
 #include "base/metrics/histogram_macros.h"
@@ -114,11 +115,11 @@
 
 double Scorer::ComputeRuleScore(const ClientSideModel::Rule& rule,
                                 const FeatureMap& features) const {
-  const base::hash_map<std::string, double>& feature_map = features.features();
+  const std::unordered_map<std::string, double>& feature_map =
+      features.features();
   double rule_score = 1.0;
   for (int i = 0; i < rule.feature_size(); ++i) {
-    base::hash_map<std::string, double>::const_iterator it = feature_map.find(
-        model_.hashes(rule.feature(i)));
+    const auto it = feature_map.find(model_.hashes(rule.feature(i)));
     if (it == feature_map.end() || it->second == 0.0) {
       // If the feature of the rule does not exist in the given feature map the
       // feature weight is considered to be zero.  If the feature weight is zero
diff --git a/chrome/renderer/tts_dispatcher.cc b/chrome/renderer/tts_dispatcher.cc
index 4a01190a..4457253 100644
--- a/chrome/renderer/tts_dispatcher.cc
+++ b/chrome/renderer/tts_dispatcher.cc
@@ -86,8 +86,7 @@
 }
 
 WebSpeechSynthesisUtterance TtsDispatcher::FindUtterance(int utterance_id) {
-  base::hash_map<int, WebSpeechSynthesisUtterance>::const_iterator iter =
-      utterance_id_map_.find(utterance_id);
+  const auto iter = utterance_id_map_.find(utterance_id);
   if (iter == utterance_id_map_.end())
     return WebSpeechSynthesisUtterance();
   return iter->second;
diff --git a/chrome/renderer/tts_dispatcher.h b/chrome/renderer/tts_dispatcher.h
index 96e289d7..fa03b2c 100644
--- a/chrome/renderer/tts_dispatcher.h
+++ b/chrome/renderer/tts_dispatcher.h
@@ -5,10 +5,10 @@
 #ifndef CHROME_RENDERER_TTS_DISPATCHER_H_
 #define CHROME_RENDERER_TTS_DISPATCHER_H_
 
+#include <map>
 #include <vector>
 
 #include "base/compiler_specific.h"
-#include "base/containers/hash_tables.h"
 #include "base/macros.h"
 #include "content/public/renderer/render_thread_observer.h"
 #include "third_party/WebKit/public/platform/WebSpeechSynthesizer.h"
@@ -68,7 +68,7 @@
   static int next_utterance_id_;
 
   // Map from id to utterance objects.
-  base::hash_map<int, blink::WebSpeechSynthesisUtterance> utterance_id_map_;
+  std::map<int, blink::WebSpeechSynthesisUtterance> utterance_id_map_;
 
   DISALLOW_COPY_AND_ASSIGN(TtsDispatcher);
 };
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 588faf7..c6aef16d 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -625,6 +625,7 @@
           "../browser/ui/views/find_bar_views_interactive_uitest.cc",
           "../browser/ui/views/frame/browser_view_focus_uitest.cc",
           "../browser/ui/views/frame/browser_view_interactive_uitest.cc",
+          "../browser/ui/views/fullscreen_control/fullscreen_control_view_interactive_uitest.cc",
           "../browser/ui/views/keyboard_access_browsertest.cc",
           "../browser/ui/views/location_bar/location_icon_view_interactive_uitest.cc",
           "../browser/ui/views/location_bar/star_view_browsertest.cc",
@@ -2672,6 +2673,7 @@
       "../browser/sync/test/integration/single_client_supervised_user_settings_sync_test.cc",
       "../browser/sync/test/integration/single_client_themes_sync_test.cc",
       "../browser/sync/test/integration/single_client_typed_urls_sync_test.cc",
+      "../browser/sync/test/integration/single_client_user_events_sync_test.cc",
       "../browser/sync/test/integration/single_client_wallet_sync_test.cc",
       "../browser/sync/test/integration/single_client_wifi_credentials_sync_test.cc",
       "../browser/sync/test/integration/sync_auth_test.cc",
@@ -3523,6 +3525,7 @@
       "../browser/android/offline_pages/test_request_coordinator_builder.cc",
       "../browser/android/offline_pages/test_request_coordinator_builder.h",
       "../browser/offline_pages/background_loader_offliner_unittest.cc",
+      "../browser/offline_pages/prefetch/offline_metrics_collector_impl_unittest.cc",
       "../browser/offline_pages/prefetch/prefetch_instance_id_proxy_unittest.cc",
     ]
     deps += [
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/NewTabPageTestUtils.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/NewTabPageTestUtils.java
index 3aa174c..40bffcdb 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/NewTabPageTestUtils.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/NewTabPageTestUtils.java
@@ -7,7 +7,6 @@
 import android.annotation.TargetApi;
 import android.os.Build;
 
-import org.chromium.chrome.browser.ntp.ChromeHomeNewTabPage;
 import org.chromium.chrome.browser.ntp.IncognitoNewTabPage;
 import org.chromium.chrome.browser.ntp.NewTabPage;
 import org.chromium.chrome.browser.tab.Tab;
@@ -31,9 +30,7 @@
             public boolean isSatisfied() {
                 if (!tab.isIncognito()) {
                     // TODO(tedchoc): Make MostVisitedPage also have a isLoaded() concept.
-                    if (tab.getNativePage() instanceof ChromeHomeNewTabPage) {
-                        return true;
-                    } else if (tab.getNativePage() instanceof NewTabPage) {
+                    if (tab.getNativePage() instanceof NewTabPage) {
                         return ((NewTabPage) tab.getNativePage()).isLoadedForTests();
                     } else {
                         return false;
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py
index f6f4c3e..fee6603 100755
--- a/chrome/test/chromedriver/test/run_py_tests.py
+++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -489,6 +489,18 @@
     self._driver.ExecuteScript('parent.postMessage("remove", "*");')
     self.assertTrue(self._driver.ExecuteScript('return window.top == window'))
 
+  def testSwitchToStaleFrame(self):
+    self._driver.ExecuteScript(
+        'var frame = document.createElement("iframe");'
+        'frame.id="id";'
+        'frame.name="name";'
+        'document.body.appendChild(frame);')
+    element = self._driver.FindElement("id", "id")
+    self._driver.SwitchToFrame(element)
+    self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html'))
+    with self.assertRaises(chromedriver.StaleElementReference):
+      self._driver.SwitchToFrame(element)
+
   def testGetTitle(self):
     script = 'document.title = "title"; return 1;'
     self.assertEquals(1, self._driver.ExecuteScript(script))
diff --git a/chrome/test/chromedriver/window_commands.cc b/chrome/test/chromedriver/window_commands.cc
index 6779a83..4f5e724 100644
--- a/chrome/test/chromedriver/window_commands.cc
+++ b/chrome/test/chromedriver/window_commands.cc
@@ -366,6 +366,14 @@
   base::ListValue args;
   const base::DictionaryValue* id_dict;
   if (id->GetAsDictionary(&id_dict)) {
+    std::string element_id;
+    if (!id_dict->GetString("ELEMENT", &element_id))
+      return Status(kUnknownError, "missing 'ELEMENT'");
+    bool is_displayed = false;
+    Status status = IsElementDisplayed(
+          session, web_view, element_id, true, &is_displayed);
+    if (status.IsError())
+      return status;
     script = "function(elem) { return elem; }";
     args.Append(id_dict->CreateDeepCopy());
   } else {
diff --git a/chrome/test/data/payments/initiated.js b/chrome/test/data/payments/initiated.js
new file mode 100644
index 0000000..b72c168
--- /dev/null
+++ b/chrome/test/data/payments/initiated.js
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+/* global PaymentRequest:false */
+/* global print:false */
+
+/*
+ * The Payment Request for this page.
+ * @const
+ */
+let REQUEST = new PaymentRequest(
+        [{supportedMethods: ['https://bobpay.com', 'visa']}],
+        {total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}}});
+
+/**
+ * Show the Payment Request UI.
+ */
+function show() {  // eslint-disable-line no-unused-vars
+  try {
+    REQUEST.show()
+        .then(function(resp) {
+          resp.complete('success')
+              .then(function() {
+                print(JSON.stringify(resp, undefined, 2));
+              })
+              .catch(function(error) {
+                print(error);
+              });
+        })
+        .catch(function(error) {
+          print(error);
+        });
+  } catch (error) {
+    print(error.message);
+  }
+}
+
+/**
+ * Aborts the PaymentRequest UI.
+ */
+function abort() {  // eslint-disable-line no-unused-vars
+  try {
+    REQUEST.abort().then(() => {
+      print('Aborted');
+    }).catch(() => {
+      print('Cannot abort');
+    });
+  } catch (error) {
+    print(error.message);
+  }
+}
diff --git a/chrome/test/data/payments/initiated_test.html b/chrome/test/data/payments/initiated_test.html
new file mode 100644
index 0000000..bc8ab7e
--- /dev/null
+++ b/chrome/test/data/payments/initiated_test.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<!--
+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.
+-->
+<html>
+<head>
+<title>Initiated Test</title>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
+<link rel="stylesheet" type="text/css" href="style.css">
+</head>
+<body>
+<button onclick="show()" id="show">Show</button><div>
+<button onclick="abort()" id="abort">Abort</button><div>
+<pre id="result"></pre>
+<script src="util.js"></script>
+<script src="initiated.js"></script>
+</body>
+</html>
diff --git a/chrome/test/data/webui/cr_elements/cr_action_menu_test.js b/chrome/test/data/webui/cr_elements/cr_action_menu_test.js
index 9f3d898..06a1060 100644
--- a/chrome/test/data/webui/cr_elements/cr_action_menu_test.js
+++ b/chrome/test/data/webui/cr_elements/cr_action_menu_test.js
@@ -268,5 +268,88 @@
     assertEquals(140 - menuWidth, menu.offsetLeft);
     assertEquals('250px', menu.style.top);
     menu.close();
+    document.body.style.direction = 'ltr';
+  });
+
+  test('offscreen scroll positioning', function() {
+    var bodyHeight = 10000;
+    var bodyWidth = 20000;
+    var containerLeft = 5000;
+    var containerTop = 10000;
+    var containerWidth = 500;
+    var containerHeight = 500;
+    document.body.innerHTML = `
+      <style>
+        body {
+          height: ${bodyHeight}px;
+          width: ${bodyWidth}px;
+        }
+
+        #container {
+          overflow: auto;
+          position: absolute;
+          top: ${containerTop}px;
+          left: ${containerLeft}px;
+          height: ${containerHeight}px;
+          width: ${containerWidth}px;
+        }
+
+        #inner-container {
+          height: 1000px;
+          width: 1000px;
+        }
+      </style>
+      <div id="container">
+        <div id="inner-container">
+          <button id="dots">...</button>
+          <dialog is="cr-action-menu">
+            <button class="dropdown-item">Un</button>
+            <hr>
+            <button class="dropdown-item">Dos</button>
+            <button class="dropdown-item">Tres</button>
+          </dialog>
+        </div>
+      </div>
+    `;
+    menu = document.querySelector('dialog[is=cr-action-menu]');
+    var dots = document.querySelector('#dots');
+
+    // Show the menu, scrolling the body to the button.
+    menu.showAt(
+        dots,
+        {anchorAlignmentX: AnchorAlignment.AFTER_START});
+    assertEquals(`${containerLeft}px`, menu.style.left);
+    assertEquals(`${containerTop}px`, menu.style.top);
+    menu.close();
+
+    // Show the menu, scrolling the container to the button, and the body to the
+    // button.
+    document.body.scrollLeft = bodyWidth;
+    document.body.scrollTop = bodyHeight;
+
+    document.querySelector('#container').scrollLeft = containerLeft;
+    document.querySelector('#container').scrollTop = containerTop;
+
+    menu.showAt(dots, {anchorAlignmentX: AnchorAlignment.AFTER_START});
+    assertEquals(`${containerLeft}px`, menu.style.left);
+    assertEquals(`${containerTop}px`, menu.style.top);
+    menu.close();
+
+    // Show the menu for an already onscreen button. The anchor should be
+    // overridden so that no scrolling happens.
+    document.body.scrollLeft = 0;
+    document.body.scrollTop = 0;
+
+    var rect = dots.getBoundingClientRect();
+    document.body.scrollLeft = rect.right - document.body.clientWidth;
+    document.body.scrollTop = rect.bottom - document.body.clientHeight;
+
+    menu.showAt(dots, {anchorAlignmentX: AnchorAlignment.AFTER_START});
+    var menuWidth = menu.offsetWidth;
+    var menuHeight = menu.offsetHeight;
+    var buttonWidth = dots.offsetWidth;
+    var buttonHeight = dots.offsetHeight;
+    assertEquals(containerLeft - menuWidth + buttonWidth, menu.offsetLeft);
+    assertEquals(containerTop - menuHeight + buttonHeight, menu.offsetTop);
   });
 });
diff --git a/chrome/test/data/webui/md_bookmarks/md_bookmarks_focus_test.js b/chrome/test/data/webui/md_bookmarks/md_bookmarks_focus_test.js
index ba79c7de..db7ddc0 100644
--- a/chrome/test/data/webui/md_bookmarks/md_bookmarks_focus_test.js
+++ b/chrome/test/data/webui/md_bookmarks/md_bookmarks_focus_test.js
@@ -396,5 +396,125 @@
     });
   });
 
+  suite('DialogFocusManager', function() {
+    var list;
+    var store;
+    var items;
+    var commandManager;
+    var dialogFocusManager;
+
+    function waitForClose(el) {
+      return new Promise(function(resolve) {
+        listenOnce(el, 'close', function(e) {
+          resolve();
+        })
+      });
+    }
+
+    function keydown(el, key) {
+      MockInteractions.keyDownOn(el, '', '', key);
+    }
+
+    setup(function() {
+      store = new bookmarks.TestStore({
+        nodes: testTree(createFolder(
+            '1',
+            [
+              createItem('2'),
+              createItem('3'),
+              createItem('4'),
+              createItem('5'),
+              createItem('6'),
+              createFolder('7', []),
+            ])),
+        selectedFolder: '1',
+      });
+      store.setReducersEnabled(true);
+      store.replaceSingleton();
+
+      list = document.createElement('bookmarks-list');
+      list.style.height = '100%';
+      list.style.width = '100%';
+      list.style.position = 'absolute';
+      replaceBody(list);
+      Polymer.dom.flush();
+      items = list.root.querySelectorAll('bookmarks-item');
+
+      commandManager = new TestCommandManager();
+      document.body.appendChild(commandManager);
+
+      dialogFocusManager = new bookmarks.DialogFocusManager();
+      bookmarks.DialogFocusManager.instance_ = dialogFocusManager;
+    });
+
+    test('restores focus on dialog dismissal', function() {
+      var focusedItem = items[0];
+      focusedItem.focus();
+      assertEquals(focusedItem, dialogFocusManager.getFocusedElement_());
+
+      commandManager.openCommandMenuAtPosition(0, 0);
+      var dropdown = commandManager.$.dropdown.getIfExists();
+
+      assertTrue(dropdown.open);
+      assertNotEquals(focusedItem, dialogFocusManager.getFocusedElement_());
+
+      keydown(dropdown, 'Escape');
+      assertFalse(dropdown.open);
+
+      return waitForClose(dropdown).then(() => {
+        assertEquals(focusedItem, dialogFocusManager.getFocusedElement_());
+      });
+    });
+
+    test('restores focus after stacked dialogs', function() {
+      var focusedItem = items[0];
+      focusedItem.focus();
+      assertEquals(focusedItem, dialogFocusManager.getFocusedElement_());
+
+      commandManager.openCommandMenuAtPosition(0, 0);
+      var dropdown = commandManager.$.dropdown.getIfExists();
+      dropdown.close();
+      assertNotEquals(focusedItem, dialogFocusManager.getFocusedElement_());
+
+      var editDialog = commandManager.$.editDialog.get();
+      editDialog.showEditDialog(store.data.nodes['2']);
+
+      return waitForClose(dropdown).then(() => {
+        editDialog.onCancelButtonTap_();
+        assertNotEquals(focusedItem, dialogFocusManager.getFocusedElement_());
+
+        return waitForClose(editDialog);
+      }).then(() => {
+        assertEquals(focusedItem, dialogFocusManager.getFocusedElement_());
+      });
+    });
+
+    test('restores focus after multiple shows of same dialog', function() {
+      var focusedItem = items[0];
+      focusedItem.focus();
+      assertEquals(focusedItem, dialogFocusManager.getFocusedElement_());
+
+      commandManager.openCommandMenuAtPosition(0, 0);
+      assertNotEquals(focusedItem, dialogFocusManager.getFocusedElement_());
+      var dropdown = commandManager.$.dropdown.getIfExists();
+      dropdown.close();
+
+      focusedItem = items[3];
+      focusedItem.focus();
+      commandManager.openCommandMenuAtPosition(0, 0);
+
+      return waitForClose(dropdown).then(() => {
+        assertTrue(dropdown.open);
+        dropdown.close();
+        assertNotEquals(
+            focusedItem, dialogFocusManager.getFocusedElement_());
+
+        return waitForClose(dropdown);
+      }).then(() => {
+        assertEquals(focusedItem, dialogFocusManager.getFocusedElement_());
+      });
+    });
+  });
+
   mocha.run();
 });
diff --git a/chrome/test/data/webui/md_history/history_item_test.js b/chrome/test/data/webui/md_history/history_item_test.js
index ba6e4e8..088cabf 100644
--- a/chrome/test/data/webui/md_history/history_item_test.js
+++ b/chrome/test/data/webui/md_history/history_item_test.js
@@ -54,6 +54,17 @@
       assertEquals(item.$['checkbox'], item.root.activeElement);
     });
   });
+
+  test('title changes with item', function() {
+    var time = item.$['time-accessed'];
+    assertEquals('', time.title);
+
+    time.dispatchEvent(new CustomEvent('mouseover'));
+    var initialTitle = time.title;
+    item.item = TEST_HISTORY_RESULTS[5];
+    time.dispatchEvent(new CustomEvent('mouseover'));
+    assertNotEquals(initialTitle, time.title);
+  });
 });
 
 suite('<history-item> integration test', function() {
diff --git a/chrome/test/data/webui/net_internals/log_util.js b/chrome/test/data/webui/net_internals/log_util.js
index 3d69ffb..b43fadf 100644
--- a/chrome/test/data/webui/net_internals/log_util.js
+++ b/chrome/test/data/webui/net_internals/log_util.js
@@ -126,9 +126,7 @@
     assertEquals('string', typeof logDumpText);
     expectTrue(SourceTracker.getInstance().getPrivacyStripping());
 
-    var expectedResult = 'The log file is missing clientInfo.numericDate.\n' +
-        'Synthesizing export date as time of last event captured.\n' +
-        'Log loaded.';
+    var expectedResult = 'Log loaded.';
 
     if (this.truncate_) {
       expectedResult =
diff --git a/chrome/test/data/webui/settings/site_details_permission_tests.js b/chrome/test/data/webui/settings/site_details_permission_tests.js
index 58a654d..51bd52e7 100644
--- a/chrome/test/data/webui/settings/site_details_permission_tests.js
+++ b/chrome/test/data/webui/settings/site_details_permission_tests.js
@@ -92,19 +92,15 @@
       embeddingOrigin: '',
     };
 
-    return browserProxy.whenCalled('getExceptionList')
-        .then(function() {
-          assertFalse(testElement.$.details.hidden);
+    assertFalse(testElement.$.details.hidden);
 
-          var header = testElement.$.details.querySelector('#permissionHeader');
-          assertEquals(
-              'Camera', header.innerText.trim(),
-              'Widget should be labelled correctly');
+    var header = testElement.$.details.querySelector('#permissionHeader');
+    assertEquals(
+        'Camera', header.innerText.trim(),
+        'Widget should be labelled correctly');
 
-          // Flip the permission and validate that prefs stay in sync.
-          return validatePermissionFlipWorks(
-              origin, settings.PermissionValues.ALLOW);
-        })
+    // Flip the permission and validate that prefs stay in sync.
+    return validatePermissionFlipWorks(origin, settings.PermissionValues.ALLOW)
         .then(function() {
           return validatePermissionFlipWorks(
               origin, settings.PermissionValues.BLOCK);
@@ -125,20 +121,17 @@
       embeddingOrigin: '',
     };
 
-    return browserProxy.whenCalled('getExceptionList')
-        .then(function() {
-          assertFalse(testElement.$.details.hidden);
+    assertFalse(testElement.$.details.hidden);
 
-          var header = testElement.$.details.querySelector('#permissionHeader');
-          assertEquals(
-              'Cookies', header.innerText.trim(),
-              'Widget should be labelled correctly');
+    var header = testElement.$.details.querySelector('#permissionHeader');
+    assertEquals(
+        'Cookies', header.innerText.trim(),
+        'Widget should be labelled correctly');
 
-          return validatePermissionFlipWorks(
-              origin, settings.PermissionValues.SESSION_ONLY);
-        })
+    // Flip the permission and validate that prefs stay in sync.
+    return validatePermissionFlipWorks(
+               origin, settings.PermissionValues.SESSION_ONLY)
         .then(function() {
-          // Flip the permission and validate that prefs stay in sync.
           return validatePermissionFlipWorks(
               origin, settings.PermissionValues.ALLOW);
         })
diff --git a/chrome/test/data/webui/settings/site_details_tests.js b/chrome/test/data/webui/settings/site_details_tests.js
index 95517a1..b195082 100644
--- a/chrome/test/data/webui/settings/site_details_tests.js
+++ b/chrome/test/data/webui/settings/site_details_tests.js
@@ -36,7 +36,7 @@
           embeddingOrigin: 'https://foo-allow.com:443',
           origin: 'https://foo-allow.com:443',
           setting: 'allow',
-          source: 'preference',
+          source: 'extension',
         },
       ],
       cookies: [
@@ -51,8 +51,8 @@
         {
           embeddingOrigin: 'https://foo-allow.com:443',
           origin: 'https://foo-allow.com:443',
-          setting: 'allow',
-          source: 'preference',
+          setting: 'block',
+          source: 'policy',
         },
       ],
       images: [
@@ -141,15 +141,28 @@
     Polymer.dom(parent).appendChild(api);
 
     browserProxy.setPrefs(prefs);
-    testElement.site = {
-      origin: 'https://foo-allow.com:443',
-      displayName: 'https://foo-allow.com:443',
-      embeddingOrigin: '',
-    };
+    testElement.origin = 'https://foo-allow.com:443';
 
     Polymer.dom.flush();
 
-    // expect usage to be rendered
+    // Expect usage to be rendered.
     assertTrue(!!testElement.$$('#usage'));
   });
+
+  test('correct pref settings are shown', function() {
+    browserProxy.setPrefs(prefs);
+    testElement.origin = 'https://foo-allow.com:443';
+
+    return browserProxy.whenCalled('getOriginPermissions').then(function() {
+      testElement.root.querySelectorAll('site-details-permission')
+          .forEach(function(siteDetailsPermission) {
+            // Verify settings match the values specified in |prefs|.
+            var setting = 'allow';
+            if (siteDetailsPermission.site.category == 'location')
+              setting = 'block';
+            assertEquals(setting, siteDetailsPermission.site.setting);
+            assertEquals(setting, siteDetailsPermission.$.permission.value);
+          });
+    });
+  });
 });
diff --git a/chrome/test/data/webui/settings/test_site_settings_prefs_browser_proxy.js b/chrome/test/data/webui/settings/test_site_settings_prefs_browser_proxy.js
index bbd3864d..733ea20c3 100644
--- a/chrome/test/data/webui/settings/test_site_settings_prefs_browser_proxy.js
+++ b/chrome/test/data/webui/settings/test_site_settings_prefs_browser_proxy.js
@@ -85,6 +85,7 @@
     'getCookieDetails',
     'getDefaultValueForContentType',
     'getExceptionList',
+    'getOriginPermissions',
     'isPatternValid',
     'observeProtocolHandlers',
     'observeProtocolHandlersEnabledState',
@@ -313,6 +314,53 @@
   },
 
   /** @override */
+  getOriginPermissions: function(origin, contentTypes) {
+    this.methodCalled('getOriginPermissions', [origin, contentTypes]);
+
+    var exceptionList = [];
+    contentTypes.forEach(function(contentType) {
+      // Convert |contentType| to its corresponding pref name, if different.
+      if (contentType == settings.ContentSettingsTypes.GEOLOCATION) {
+        contentType = 'geolocation';
+      } else if (contentType == settings.ContentSettingsTypes.CAMERA) {
+        contentType = 'camera';
+      } else if (contentType == settings.ContentSettingsTypes.MIC) {
+        contentType = 'mic';
+      } else if (contentType == settings.ContentSettingsTypes.BACKGROUND_SYNC) {
+        contentType = 'background_sync';
+      } else if (
+          contentType == settings.ContentSettingsTypes.AUTOMATIC_DOWNLOADS) {
+        contentType = 'auto_downloads';
+      } else if (
+          contentType == settings.ContentSettingsTypes.UNSANDBOXED_PLUGINS) {
+        contentType = 'unsandboxed_plugins';
+      }
+
+      var setting = undefined;
+      this.prefs_.exceptions[contentType].some(function(originPrefs) {
+        if (originPrefs.origin == origin) {
+          setting = originPrefs.setting;
+          return true;
+        }
+      });
+      assert(
+          settings !== undefined,
+          'There was no exception set for origin: ' + origin +
+              ' and contentType: ' + contentType);
+
+      exceptionList.push({
+        embeddingOrigin: '',
+        incognito: false,
+        origin: origin,
+        displayName: '',
+        setting: setting,
+        source: undefined
+      })
+    }, this);
+    return Promise.resolve(exceptionList);
+  },
+
+  /** @override */
   setCategoryPermissionForOrigin: function(
       primaryPattern, secondaryPattern, contentType, value, incognito) {
     this.methodCalled('setCategoryPermissionForOrigin',
diff --git a/chrome/test/vr/perf/BUILD.gn b/chrome/test/vr/perf/BUILD.gn
index d4d724e..d9ca084 100644
--- a/chrome/test/vr/perf/BUILD.gn
+++ b/chrome/test/vr/perf/BUILD.gn
@@ -6,6 +6,7 @@
   "./__init__.py",
   "./android_vr_perf_test.py",
   "./vr_perf_test.py",
+  "./vr_test_arg_parser.py",
   "//third_party/android_tools/sdk/platform-tools/adb",
   "//third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk",
 ]
diff --git a/chrome/test/vr/perf/android_vr_perf_test.py b/chrome/test/vr/perf/android_vr_perf_test.py
index e82c704..8c2244b 100644
--- a/chrome/test/vr/perf/android_vr_perf_test.py
+++ b/chrome/test/vr/perf/android_vr_perf_test.py
@@ -50,8 +50,10 @@
 
     # Force WebVR support, remove open tabs, and don't have first run
     # experience.
-    self._SetChromeCommandLineFlags(['--enable-webvr', '--no-restore-state',
-                                     '--disable-fre'])
+    flags = ['--enable-webvr', '--no-restore-state', '--disable-fre']
+    if self._args.additional_flags:
+      flags.extend(self._args.additional_flags.split(' '))
+    self._SetChromeCommandLineFlags(flags)
     # Wake up the device and sleep, otherwise WebGL can crash on startup.
     self._Adb(['shell', 'input', 'keyevent', 'KEYCODE_WAKEUP'])
     time.sleep(1)
diff --git a/chrome/test/vr/perf/latency/run_latency_test.py b/chrome/test/vr/perf/latency/run_latency_test.py
index 3f5c747..4ec919ed 100644
--- a/chrome/test/vr/perf/latency/run_latency_test.py
+++ b/chrome/test/vr/perf/latency/run_latency_test.py
@@ -13,85 +13,15 @@
 # Must be first import in order to add parent directory to system path.
 import latency_test_config
 import android_webvr_latency_test
+import vr_test_arg_parser
 
-import argparse
-import logging
-import os
 import sys
 
-DEFAULT_ADB_PATH = os.path.realpath('../../third_party/android_tools/sdk/'
-                                    'platform-tools/adb')
-# TODO(bsheedy): See about adding tool via DEPS instead of relying on it
-# existing on the bot already.
-DEFAULT_MOTOPHO_PATH = os.path.join(os.path.expanduser('~'), 'motopho/Motopho')
-DEFAULT_NUM_SAMPLES = 10
-DEFAULT_RESULTS_FILE = 'results-chart.json'
-DEFAULT_VRCORE_VERSION_FILE = 'vrcore_version.txt'
-
-
-def GetParsedArgs():
-  """Parses the command line arguments passed to the script.
-
-  Fails if any unknown arguments are present.
-
-  Returns:
-    An object containing all known, parsed arguments.
-  """
-  parser = argparse.ArgumentParser()
-  parser.add_argument('--adb-path',
-                      type=os.path.realpath,
-                      help='The absolute path to adb',
-                      default=DEFAULT_ADB_PATH)
-  parser.add_argument('--motopho-path',
-                      type=os.path.realpath,
-                      help='The absolute path to the directory with Motopho '
-                           'scripts',
-                      default=DEFAULT_MOTOPHO_PATH)
-  parser.add_argument('--output-dir',
-                      type=os.path.realpath,
-                      help='The directory where the script\'s output files '
-                           'will be saved')
-  parser.add_argument('--platform',
-                      help='The platform the test is being run on, either '
-                           '"android" or "windows"')
-  parser.add_argument('--results-file',
-                      default=DEFAULT_RESULTS_FILE,
-                      help='The name of the JSON file the results will be '
-                           'saved to')
-  parser.add_argument('--num-samples',
-                      default=DEFAULT_NUM_SAMPLES,
-                      type=int,
-                      help='The number of times to run the test before '
-                           'the results are averaged')
-  parser.add_argument('--url',
-                      action='append',
-                      default=[],
-                      dest='urls',
-                      help='The URL of a flicker app to use. Defaults to a '
-                           'set of URLs with various CPU and GPU loads')
-  parser.add_argument('-v', '--verbose',
-                      dest='verbose_count', default=0, action='count',
-                      help='Verbose level (multiple times for more)')
-  (args, unknown_args) = parser.parse_known_args()
-  SetLogLevel(args.verbose_count)
-  if unknown_args:
-    parser.error('Received unknown arguments: %s' % ' '.join(unknown_args))
-  return args
-
-
-def SetLogLevel(verbose_count):
-  """Sets the log level based on the command line arguments."""
-  log_level = logging.WARNING
-  if verbose_count == 1:
-    log_level = logging.INFO
-  elif verbose_count >= 2:
-    log_level = logging.DEBUG
-  logger = logging.getLogger()
-  logger.setLevel(log_level)
-
 
 def main():
-  args = GetParsedArgs()
+  parser = vr_test_arg_parser.VrTestArgParser()
+  parser.AddLatencyOptions()
+  args = parser.ParseArgumentsAndSetLogLevel()
   latency_test = None
   if args.platform == 'android':
     latency_test = android_webvr_latency_test.AndroidWebVrLatencyTest(args)
diff --git a/chrome/test/vr/perf/vr_perf_test.py b/chrome/test/vr/perf/vr_perf_test.py
index 5b10ed4b..74b6c91 100644
--- a/chrome/test/vr/perf/vr_perf_test.py
+++ b/chrome/test/vr/perf/vr_perf_test.py
@@ -2,6 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import logging
 import subprocess
 
 class VrPerfTest(object):
diff --git a/chrome/test/vr/perf/vr_test_arg_parser.py b/chrome/test/vr/perf/vr_test_arg_parser.py
new file mode 100644
index 0000000..09292d5
--- /dev/null
+++ b/chrome/test/vr/perf/vr_test_arg_parser.py
@@ -0,0 +1,97 @@
+# 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 argparse
+import logging
+import os
+
+
+DEFAULT_ADB_PATH = os.path.realpath('../../third_party/android_tools/sdk/'
+                                    'platform-tools/adb')
+DEFAULT_DURATION_SECONDS = 30
+# TODO(bsheedy): See about adding tool via DEPS instead of relying on it
+# existing on the bot already.
+DEFAULT_MOTOPHO_PATH = os.path.join(os.path.expanduser('~'), 'motopho/Motopho')
+DEFAULT_NUM_SAMPLES = 10
+DEFAULT_RESULTS_FILE = 'results-chart.json'
+
+
+class VrTestArgParser(argparse.ArgumentParser):
+  def __init__(self):
+    super(VrTestArgParser, self).__init__()
+    self.AddCommonOptions()
+
+  def AddCommonOptions(self):
+    """Adds argument parsing options that are common to all VR perf tests."""
+    self.add_argument('--adb-path',
+                      type=os.path.realpath,
+                      help='The absolute path to adb',
+                      default=DEFAULT_ADB_PATH)
+    self.add_argument('--additional-flags',
+                      default=None,
+                      help='A string containing any additional Chrome command '
+                           'line flags to set for a test run')
+    self.add_argument('--output-dir',
+                      type=os.path.realpath,
+                      help='The directory where the script\'s output files '
+                           'will be saved')
+    self.add_argument('--results-file',
+                      default=DEFAULT_RESULTS_FILE,
+                      help='The name of the JSON file the results will be '
+                           'saved to')
+    self.add_argument('--url',
+                      action='append',
+                      default=[],
+                      dest='urls',
+                      help='The URL of a WebVR app to use. Defaults to a set '
+                           'of URLs with various CPU and GPU loads')
+    self.add_argument('-v', '--verbose',
+                      dest='verbose_count', default=0, action='count',
+                      help='Verbose level (multiple times for more)')
+
+  def AddFpsOptions(self):
+    """Adds argument parsing options specific to VrCore FPS tests."""
+    self.add_argument('--duration',
+                      default=DEFAULT_DURATION_SECONDS,
+                      type=int,
+                      help='The duration spent collecting data from each URL')
+
+  def AddLatencyOptions(self):
+    """Adds argument parsing options specific to motopho latency tests."""
+    self.add_argument('--motopho-path',
+                      type=os.path.realpath,
+                      help='The absolute path to the directory with Motopho '
+                           'scripts',
+                      default=DEFAULT_MOTOPHO_PATH)
+    self.add_argument('--platform',
+                      help='The platform the test is being run on, either '
+                           '"android" or "windows"')
+    self.add_argument('--num-samples',
+                      default=DEFAULT_NUM_SAMPLES,
+                      type=int,
+                      help='The number of times to run the test before the '
+                           'results are averaged')
+
+  def ParseArgumentsAndSetLogLevel(self):
+    """Parses the commandline arguments based on the options set.
+
+    Also sets the log level based on the number of -v's input.
+    Returns:
+      The parsed args from an ArgumentParser object
+    """
+    (args, unknown_args) = self.parse_known_args()
+    self.SetLogLevel(args.verbose_count)
+    if unknown_args:
+      self.error('Received unknown arguments: %s' % ' '.join(unknown_args))
+    return args
+
+  def SetLogLevel(self, verbose_count):
+    """Sets the log level based on the command line arguments."""
+    log_level = logging.WARNING
+    if verbose_count == 1:
+      log_level = logging.INFO
+    elif verbose_count >= 2:
+      log_level = logging.DEBUG
+    logger = logging.getLogger()
+    logger.setLevel(log_level)
diff --git a/chrome/test/vr/perf/vrcore_fps/run_vrcore_fps_test.py b/chrome/test/vr/perf/vrcore_fps/run_vrcore_fps_test.py
index b17bb48..d26d9937 100644
--- a/chrome/test/vr/perf/vrcore_fps/run_vrcore_fps_test.py
+++ b/chrome/test/vr/perf/vrcore_fps/run_vrcore_fps_test.py
@@ -12,72 +12,13 @@
 # Needs to be imported first in order to add the parent directory to path.
 import vrcore_fps_test_config
 import vrcore_fps_test
-
-import argparse
-import logging
-import os
-
-DEFAULT_ADB_PATH = os.path.realpath('../../third_party/android_tools/sdk/'
-                                    'platform-tools/adb')
-DEFAULT_DURATION_SECONDS = 30
-DEFAULT_RESULTS_FILE = 'results-chart.json'
-
-
-# TODO(bsheedy): Move common arg parsing code to shared file.
-def GetParsedArgs():
-  """Parses the command line arguments passed to the script.
-
-  Fails if any unknown arguments are present.
-
-  Returns:
-    An object containing all known, parsed arguments.
-  """
-  parser = argparse.ArgumentParser()
-  parser.add_argument('--adb-path',
-                      type=os.path.realpath,
-                      help='The absolute path to adb',
-                      default=DEFAULT_ADB_PATH)
-  parser.add_argument('--duration',
-                      default=DEFAULT_DURATION_SECONDS,
-                      type=int,
-                      help='The duration spent collecting data from each URL')
-  parser.add_argument('--output-dir',
-                      type=os.path.realpath,
-                      help='The directory where the script\'s output files '
-                           'will be saved')
-  parser.add_argument('--results-file',
-                      default=DEFAULT_RESULTS_FILE,
-                      help='The name of the JSON file the results will be '
-                           'saved to')
-  parser.add_argument('--url',
-                      action='append',
-                      default=[],
-                      dest='urls',
-                      help='The URL of a WebVR app to use. Defaults to a '
-                           'set of URLs with various CPU and GPU loads')
-  parser.add_argument('-v', '--verbose',
-                      dest='verbose_count', default=0, action='count',
-                      help='Verbose level (multiple times for more)')
-  (args, unknown_args) = parser.parse_known_args()
-  SetLogLevel(args.verbose_count)
-  if unknown_args:
-    parser.error('Received unknown arguments: %s' % ' '.join(unknown_args))
-  return args
-
-
-def SetLogLevel(verbose_count):
-  """Sets the log level based on the command line arguments."""
-  log_level = logging.WARNING
-  if verbose_count == 1:
-    log_level = logging.INFO
-  elif verbose_count >= 2:
-    log_level = logging.DEBUG
-  logger = logging.getLogger()
-  logger.setLevel(log_level)
+import vr_test_arg_parser
 
 
 def main():
-  args = GetParsedArgs()
+  parser = vr_test_arg_parser.VrTestArgParser()
+  parser.AddFpsOptions()
+  args = parser.ParseArgumentsAndSetLogLevel()
   test = vrcore_fps_test.VrCoreFpsTest(args)
   test.RunTests()
 
diff --git a/chrome/tools/build/win/FILES.cfg b/chrome/tools/build/win/FILES.cfg
index 58d5771..1dc822a 100644
--- a/chrome/tools/build/win/FILES.cfg
+++ b/chrome/tools/build/win/FILES.cfg
@@ -82,7 +82,7 @@
   {
     'filename': '*.manifest',
     'buildtype': ['dev', 'official'],
-    'filegroup': ['default', 'symsrc'],
+    'filegroup': ['default'],
   },
   {
     'filename': 'chrome_100_percent.pak',
diff --git a/chrome/tools/service_discovery_sniffer/service_discovery_sniffer.cc b/chrome/tools/service_discovery_sniffer/service_discovery_sniffer.cc
index 28b90767..7a15a4e4 100644
--- a/chrome/tools/service_discovery_sniffer/service_discovery_sniffer.cc
+++ b/chrome/tools/service_discovery_sniffer/service_discovery_sniffer.cc
@@ -74,7 +74,7 @@
 
 void ServiceTypePrinter::Start() {
   watcher_->Start();
-  watcher_->DiscoverNewServices(false);
+  watcher_->DiscoverNewServices();
 }
 
 ServiceTypePrinter::~ServiceTypePrinter() {
diff --git a/chrome/utility/extensions/extensions_handler.cc b/chrome/utility/extensions/extensions_handler.cc
index a55385e6..648c7782 100644
--- a/chrome/utility/extensions/extensions_handler.cc
+++ b/chrome/utility/extensions/extensions_handler.cc
@@ -24,7 +24,7 @@
 #include "ui/base/ui_base_switches.h"
 
 #if !defined(MEDIA_DISABLE_FFMPEG)
-#include "media/base/media_file_checker.h"
+#include "media/filters/media_file_checker.h"
 #endif
 
 #if defined(OS_WIN)
diff --git a/chrome/utility/media_galleries/media_metadata_parser.cc b/chrome/utility/media_galleries/media_metadata_parser.cc
index 455e68b..00576061 100644
--- a/chrome/utility/media_galleries/media_metadata_parser.cc
+++ b/chrome/utility/media_galleries/media_metadata_parser.cc
@@ -11,8 +11,8 @@
 #include "base/strings/string_util.h"
 #include "base/task_runner_util.h"
 #include "base/threading/thread.h"
-#include "media/base/audio_video_metadata_extractor.h"
 #include "media/base/data_source.h"
+#include "media/filters/audio_video_metadata_extractor.h"
 #include "net/base/mime_sniffer.h"
 
 namespace MediaGalleries = extensions::api::media_galleries;
diff --git a/chromecast/crash/cast_crash_keys.cc b/chromecast/crash/cast_crash_keys.cc
index d94a927b..97a2e43 100644
--- a/chromecast/crash/cast_crash_keys.cc
+++ b/chromecast/crash/cast_crash_keys.cc
@@ -37,6 +37,7 @@
       {gpu::crash_keys::kGPUDriverVersion, ::crash_keys::kSmallSize},
       {gpu::crash_keys::kGPUPixelShaderVersion, ::crash_keys::kSmallSize},
       {gpu::crash_keys::kGPUVertexShaderVersion, ::crash_keys::kSmallSize},
+      {gpu::crash_keys::kGPUGLContextIsVirtual, ::crash_keys::kSmallSize},
 
       // content/:
       {"bad_message_reason", ::crash_keys::kSmallSize},
diff --git a/chromecast/media/cma/backend/alsa/volume_control.cc b/chromecast/media/cma/backend/alsa/volume_control.cc
index f030c54..7ab9875 100644
--- a/chromecast/media/cma/backend/alsa/volume_control.cc
+++ b/chromecast/media/cma/backend/alsa/volume_control.cc
@@ -50,6 +50,7 @@
 constexpr char kKeyVolumeMap[] = "volume_map";
 constexpr char kKeyLevel[] = "level";
 constexpr char kKeyDb[] = "db";
+constexpr char kKeyDefaultVolume[] = "default_volume";
 
 struct LevelToDb {
   float level;
@@ -206,6 +207,26 @@
           stored_values_.SetDouble(ContentTypeToDbFSKey(type), volume);
         }
       }
+    } else {
+      // If saved_volumes does not exist, use per device default if it exists.
+      auto cast_audio_config = DeserializeJsonFromFile(
+          base::FilePath(PostProcessingPipelineParser::GetFilePath()));
+      const base::DictionaryValue* cast_audio_dict;
+      if (cast_audio_config &&
+          cast_audio_config->GetAsDictionary(&cast_audio_dict)) {
+        const base::DictionaryValue* default_volume_dict;
+        if (cast_audio_dict && cast_audio_dict->GetDictionary(
+                                   kKeyDefaultVolume, &default_volume_dict)) {
+          for (auto type : types) {
+            if (default_volume_dict->GetDouble(ContentTypeToDbFSKey(type),
+                                               &volume)) {
+              stored_values_.SetDouble(ContentTypeToDbFSKey(type), volume);
+              LOG(INFO) << "Setting default volume for "
+                        << ContentTypeToDbFSKey(type) << " to " << volume;
+            }
+          }
+        }
+      }
     }
 
     base::Thread::Options options;
diff --git a/components/arc/common/app.mojom b/components/arc/common/app.mojom
index b1e474b9..d40ed29 100644
--- a/components/arc/common/app.mojom
+++ b/components/arc/common/app.mojom
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
-// Next MinVersion: 21
+// Next MinVersion: 22
 
 module arc.mojom;
 
@@ -174,7 +174,7 @@
 };
 
 // TODO(lhchavez): Migrate all request/response messages to Mojo.
-// Next method ID: 17
+// Next method ID: 18
 // Deprecated method ID: 9
 interface AppInstance {
   Init@0(AppHost host_ptr);
@@ -243,6 +243,9 @@
   // Sets notification setting for the package.
   [MinVersion=6] SetNotificationsEnabled@10(string package_name, bool enabled);
 
+  // Sends a request to ARC to start PAI flow.
+  [MinVersion=21] StartPaiFlow@17();
+
   // Sends a request to ARC to uninstall the given package.  Error (if ever
   // happens) is ignored, and uninstall option should appear in the UI.
   [MinVersion=2] UninstallPackage@5(string package_name);
diff --git a/components/arc/test/fake_app_instance.cc b/components/arc/test/fake_app_instance.cc
index 83e4ee8..b8c0d57 100644
--- a/components/arc/test/fake_app_instance.cc
+++ b/components/arc/test/fake_app_instance.cc
@@ -280,6 +280,10 @@
   callback.Run(std::vector<arc::mojom::AppDiscoveryResultPtr>());
 }
 
+void FakeAppInstance::StartPaiFlow() {
+  ++start_pai_request_count_;
+}
+
 void FakeAppInstance::LaunchIntent(
     const std::string& intent_uri,
     const base::Optional<gfx::Rect>& dimension_on_screen) {
diff --git a/components/arc/test/fake_app_instance.h b/components/arc/test/fake_app_instance.h
index ce65bce..d2e8b7d 100644
--- a/components/arc/test/fake_app_instance.h
+++ b/components/arc/test/fake_app_instance.h
@@ -116,6 +116,7 @@
       const std::string& query,
       int32_t max_results,
       const GetRecentAndSuggestedAppsFromPlayStoreCallback& callback) override;
+  void StartPaiFlow() override;
 
   // Methods to reply messages.
   void SendRefreshAppList(const std::vector<mojom::AppInfo>& apps);
@@ -152,6 +153,8 @@
 
   int refresh_app_list_count() const { return refresh_app_list_count_; }
 
+  int start_pai_request_count() const { return start_pai_request_count_; }
+
   const std::vector<std::unique_ptr<Request>>& launch_requests() const {
     return launch_requests_;
   }
@@ -175,6 +178,8 @@
   mojom::AppHost* app_host_;
   // Number of RefreshAppList calls.
   int refresh_app_list_count_ = 0;
+  // Number of requests to start PAI flows.
+  int start_pai_request_count_ = 0;
   // Keeps information about launch requests.
   std::vector<std::unique_ptr<Request>> launch_requests_;
   // Keeps information about launch intents.
diff --git a/components/crash/content/app/breakpad_linux.cc b/components/crash/content/app/breakpad_linux.cc
index 0d3de6504..0207331 100644
--- a/components/crash/content/app/breakpad_linux.cc
+++ b/components/crash/content/app/breakpad_linux.cc
@@ -1715,6 +1715,8 @@
     static const char android_build_fp[] = "android_build_fp";
     static const char device[] = "device";
     static const char gms_core_version[] = "gms_core_version";
+    static const char installer_package_name[] = "installer_package_name";
+    static const char abi_name[] = "abi_name";
     static const char model[] = "model";
     static const char brand[] = "brand";
     static const char exception_info[] = "exception_info";
@@ -1736,6 +1738,11 @@
     writer.AddPairString(gms_core_version,
         android_build_info->gms_version_code());
     writer.AddBoundary();
+    writer.AddPairString(installer_package_name,
+                         android_build_info->installer_package_name());
+    writer.AddBoundary();
+    writer.AddPairString(abi_name, android_build_info->abi_name());
+    writer.AddBoundary();
     WriteAndroidPackage(writer, android_build_info);
     writer.AddBoundary();
     if (android_build_info->java_exception_info() != nullptr) {
diff --git a/components/cronet/android/cronet_url_request_context_adapter.cc b/components/cronet/android/cronet_url_request_context_adapter.cc
index e2b6068..53399035 100644
--- a/components/cronet/android/cronet_url_request_context_adapter.cc
+++ b/components/cronet/android/cronet_url_request_context_adapter.cc
@@ -664,7 +664,11 @@
     if (config->enable_host_cache_persistence) {
       registry->RegisterListPref(kHostCachePref);
     }
-    pref_service_ = factory.Create(registry.get());
+
+    {
+      SCOPED_UMA_HISTOGRAM_TIMER("Net.Cronet.PrefsInitTime");
+      pref_service_ = factory.Create(registry.get());
+    }
 
     // Set up the HttpServerPropertiesManager.
     std::unique_ptr<net::HttpServerPropertiesManager>
@@ -728,7 +732,8 @@
         base::MakeUnique<HostCachePersistenceManager>(
             host_cache, pref_service_.get(), kHostCachePref,
             base::TimeDelta::FromMilliseconds(
-                config->host_cache_persistence_delay_ms));
+                config->host_cache_persistence_delay_ms),
+            g_net_log.Get().net_log());
   }
 
   context_->set_check_cleartext_permitted(true);
diff --git a/components/cronet/host_cache_persistence_manager.cc b/components/cronet/host_cache_persistence_manager.cc
index 97e3bdc..a8048752 100644
--- a/components/cronet/host_cache_persistence_manager.cc
+++ b/components/cronet/host_cache_persistence_manager.cc
@@ -7,8 +7,10 @@
 #include <memory>
 
 #include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/values.h"
 #include "components/prefs/pref_service.h"
+#include "net/log/net_log.h"
 
 namespace cronet {
 
@@ -16,12 +18,16 @@
     net::HostCache* cache,
     PrefService* pref_service,
     std::string pref_name,
-    base::TimeDelta delay)
+    base::TimeDelta delay,
+    net::NetLog* net_log)
     : cache_(cache),
       pref_service_(pref_service),
       pref_name_(pref_name),
       writing_pref_(false),
       delay_(delay),
+      net_log_(net::NetLogWithSource::Make(
+          net_log,
+          net::NetLogSourceType::HOST_CACHE_PERSISTENCE_MANAGER)),
       weak_factory_(this) {
   DCHECK(cache_);
   DCHECK(pref_service_);
@@ -51,8 +57,14 @@
   if (writing_pref_)
     return;
 
+  net_log_.BeginEvent(net::NetLogEventType::HOST_CACHE_PREF_READ);
   const base::ListValue* pref_value = pref_service_->GetList(pref_name_);
-  cache_->RestoreFromListValue(*pref_value);
+  bool success = cache_->RestoreFromListValue(*pref_value);
+  net_log_.EndEvent(net::NetLogEventType::HOST_CACHE_PREF_READ,
+                    net::NetLog::BoolCallback("success", success));
+
+  UMA_HISTOGRAM_BOOLEAN("DNS.HostCache.RestoreSuccess", success);
+  UMA_HISTOGRAM_COUNTS_1000("DNS.HostCache.RestoreSize", pref_value->GetSize());
 }
 
 void HostCachePersistenceManager::ScheduleWrite() {
@@ -61,6 +73,7 @@
   if (timer_.IsRunning())
     return;
 
+  net_log_.AddEvent(net::NetLogEventType::HOST_CACHE_PERSISTENCE_START_TIMER);
   timer_.Start(FROM_HERE, delay_,
                base::Bind(&HostCachePersistenceManager::WriteToDisk,
                           weak_factory_.GetWeakPtr()));
@@ -69,6 +82,7 @@
 void HostCachePersistenceManager::WriteToDisk() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
+  net_log_.AddEvent(net::NetLogEventType::HOST_CACHE_PREF_WRITE);
   base::ListValue value;
   cache_->GetAsListValue(&value, false);
   writing_pref_ = true;
diff --git a/components/cronet/host_cache_persistence_manager.h b/components/cronet/host_cache_persistence_manager.h
index 156f96639..2b160cf 100644
--- a/components/cronet/host_cache_persistence_manager.h
+++ b/components/cronet/host_cache_persistence_manager.h
@@ -15,9 +15,14 @@
 #include "base/timer/timer.h"
 #include "components/prefs/pref_change_registrar.h"
 #include "net/dns/host_cache.h"
+#include "net/log/net_log_with_source.h"
 
 class PrefService;
 
+namespace net {
+class NetLog;
+}
+
 namespace cronet {
 // Handles the interaction between HostCache and prefs for persistence.
 // When notified of a change in the HostCache, starts a timer, or ignores if the
@@ -40,7 +45,8 @@
   HostCachePersistenceManager(net::HostCache* cache,
                               PrefService* pref_service,
                               std::string pref_name,
-                              base::TimeDelta delay);
+                              base::TimeDelta delay,
+                              net::NetLog* net_log);
   virtual ~HostCachePersistenceManager();
 
   // net::HostCache::PersistenceDelegate implementation
@@ -62,6 +68,8 @@
   const base::TimeDelta delay_;
   base::OneShotTimer timer_;
 
+  const net::NetLogWithSource net_log_;
+
   SEQUENCE_CHECKER(sequence_checker_);
   base::WeakPtrFactory<HostCachePersistenceManager> weak_factory_;
 
diff --git a/components/cronet/host_cache_persistence_manager_unittest.cc b/components/cronet/host_cache_persistence_manager_unittest.cc
index 7a8eaae..6c5845d 100644
--- a/components/cronet/host_cache_persistence_manager_unittest.cc
+++ b/components/cronet/host_cache_persistence_manager_unittest.cc
@@ -25,7 +25,7 @@
 
   void MakePersistenceManager(base::TimeDelta delay) {
     persistence_manager_ = base::MakeUnique<HostCachePersistenceManager>(
-        cache_.get(), pref_service_.get(), kPrefName, delay);
+        cache_.get(), pref_service_.get(), kPrefName, delay, nullptr);
   }
 
   // Sets an entry in the HostCache in order to trigger a pref write. The
diff --git a/components/cronet/ios/BUILD.gn b/components/cronet/ios/BUILD.gn
index e0b57e86..dfe018b5 100644
--- a/components/cronet/ios/BUILD.gn
+++ b/components/cronet/ios/BUILD.gn
@@ -294,20 +294,20 @@
   action("generate_license") {
     _license_path = "$_package_dir/LICENSE"
 
-    script = "//components/cronet/tools/cronet_licenses.py"
+    script = "//tools/licenses.py"
     inputs = [
       "//build/util/LASTCHANGE",
-      "//buildtools/$host_os/gn",
     ]
     outputs = [
       _license_path,
     ]
     args = [
-      "license",
+      "license_file",
       rebase_path(_license_path, root_build_dir),
-      "--gn",
-      "--gn-path",
-      rebase_path("//buildtools/$host_os/gn", root_build_dir),
+      "--gn-target",
+      "//components/cronet/ios:cronet_framework",
+      "--gn-out-dir",
+      ".",
     ]
   }
 
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc
index a9154966..626d794 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc
@@ -1077,6 +1077,10 @@
     return false;
   }
 
+  // AlwaysOn skips blacklist or disabled checks.
+  if (params::IsLoFiAlwaysOnViaFlags())
+    return true;
+
   if (IsBlackListedOrDisabled(request, previews_decider,
                               previews::PreviewsType::LITE_PAGE)) {
     return false;
@@ -1107,14 +1111,15 @@
     return false;
   }
 
+  // AlwaysOn skips blacklist or disabled checks.
+  if (params::IsLoFiAlwaysOnViaFlags())
+    return true;
+
   if (IsBlackListedOrDisabled(request, previews_decider,
                               previews::PreviewsType::LOFI)) {
     return false;
   }
 
-  if (params::IsLoFiAlwaysOnViaFlags())
-    return true;
-
   if (params::IsLoFiCellularOnlyViaFlags()) {
     return net::NetworkChangeNotifier::IsConnectionCellular(connection_type_);
   }
@@ -1140,14 +1145,15 @@
   DCHECK(!base::FeatureList::IsEnabled(
       features::kDataReductionProxyDecidesTransform));
 
+  // AlwaysOn skips blacklist or disabled checks.
+  if (params::IsLoFiAlwaysOnViaFlags() && params::AreLitePagesEnabledViaFlags())
+    return true;
+
   if (IsBlackListedOrDisabled(request, previews_decider,
                               previews::PreviewsType::LITE_PAGE)) {
     return false;
   }
 
-  if (params::IsLoFiAlwaysOnViaFlags() && params::AreLitePagesEnabledViaFlags())
-    return true;
-
   if (params::IsLoFiCellularOnlyViaFlags() &&
       params::AreLitePagesEnabledViaFlags()) {
     return net::NetworkChangeNotifier::IsConnectionCellular(
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc
index 3d9e073..32ac3582 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc
@@ -853,8 +853,8 @@
       },
       {
           // Lo-Fi is enabled through command line switch, but opted out. LoFi
-          // should not be used.
-          true, false, std::string(), false, false, 0,
+          // should be used.
+          true, false, std::string(), false, true, 0,
           0,  // not in enabled field trial, UMA is not recorded
           true,
       },
@@ -942,8 +942,8 @@
       },
       {
           // Lo-Fi is enabled through command line switch, but opted out. LoFi
-          // should not be used.
-          true, true, std::string(), false, false, 0,
+          // should be used.
+          true, true, std::string(), false, true, 0,
           0,  // not in enabled field trial, UMA is not recorded
           true,
       },
@@ -1574,6 +1574,12 @@
   EXPECT_TRUE(config()->ShouldAcceptServerPreview(*request.get(),
                                                   *previews_decider.get()));
 
+  // Verify PreviewsDecider check.
+  previews_decider = base::MakeUnique<TestPreviewsDecider>(true);
+  EXPECT_TRUE(config()->ShouldAcceptServerPreview(*request.get(),
+                                                  *previews_decider.get()));
+  previews_decider = base::MakeUnique<TestPreviewsDecider>(false);
+
   // Verify false for Cellular Only flag and WIFI connection.
   base::CommandLine::ForCurrentProcess()->InitFromArgv(0, NULL);
   base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
@@ -1590,8 +1596,8 @@
   EXPECT_TRUE(config()->ShouldAcceptServerPreview(*request.get(),
                                                   *previews_decider.get()));
 
-  // Verify PreviewsDecider check.
   {
+    // Verfiy true for always on.
     base::CommandLine::ForCurrentProcess()->InitFromArgv(0, NULL);
     base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
         switches::kDataReductionProxyLoFi,
@@ -1599,9 +1605,6 @@
     base::FieldTrialList field_trial_list(nullptr);
     base::FieldTrialList::CreateFieldTrial(
         "DataReductionProxyPreviewsBlackListTransition", "Enabled");
-    EXPECT_FALSE(config()->ShouldAcceptServerPreview(*request.get(),
-                                                     *previews_decider.get()));
-    previews_decider = base::MakeUnique<TestPreviewsDecider>(true);
     EXPECT_TRUE(config()->ShouldAcceptServerPreview(*request.get(),
                                                     *previews_decider.get()));
   }
diff --git a/components/data_use_measurement/core/data_use_recorder.cc b/components/data_use_measurement/core/data_use_recorder.cc
index c4230c24..6d7282b 100644
--- a/components/data_use_measurement/core/data_use_recorder.cc
+++ b/components/data_use_measurement/core/data_use_recorder.cc
@@ -17,6 +17,16 @@
   return pending_url_requests_.empty();
 }
 
+void DataUseRecorder::GetPendingURLRequests(
+    std::vector<net::URLRequest*>* requests) const {
+  // Reference to |pending_url_requests_| could be returned instead of copying
+  // to a vector. But that leads to issues when the caller calls other member
+  // functions that modify/erase the same map, while iterating.
+  requests->reserve(pending_url_requests_.size());
+  for (const auto& request : pending_url_requests_)
+    requests->push_back(request.first);
+}
+
 void DataUseRecorder::AddPendingURLRequest(net::URLRequest* request) {
   pending_url_requests_.emplace(std::piecewise_construct,
                                 std::forward_as_tuple(request),
@@ -27,8 +37,8 @@
   pending_url_requests_.erase(request);
 }
 
-void DataUseRecorder::MovePendingURLRequest(DataUseRecorder* other,
-                                            net::URLRequest* request) {
+void DataUseRecorder::MovePendingURLRequestTo(DataUseRecorder* other,
+                                              net::URLRequest* request) {
   auto request_it = pending_url_requests_.find(request);
   DCHECK(request_it != pending_url_requests_.end());
   DCHECK(other->pending_url_requests_.find(request) ==
diff --git a/components/data_use_measurement/core/data_use_recorder.h b/components/data_use_measurement/core/data_use_recorder.h
index c04f7abf..e66b8fb6 100644
--- a/components/data_use_measurement/core/data_use_recorder.h
+++ b/components/data_use_measurement/core/data_use_recorder.h
@@ -8,6 +8,7 @@
 #include <stdint.h>
 
 #include <map>
+#include <vector>
 
 #include "base/macros.h"
 #include "base/supports_user_data.h"
@@ -42,10 +43,7 @@
 
   // Returns the actual data used by the entity being tracked.
   DataUse& data_use() { return data_use_; }
-  const std::map<net::URLRequest*, URLRequestDataUse>& pending_url_requests()
-      const {
-    return pending_url_requests_;
-  }
+
   const net::URLRequest* main_url_request() const { return main_url_request_; }
 
   void set_main_url_request(const net::URLRequest* request) {
@@ -66,13 +64,19 @@
   // by the entity tracked by this recorder. For example,
   bool IsDataUseComplete();
 
+  // Populate the pending requests to |requests|.
+  // Reference to the map is not returned since other member functions that
+  // modify/erase could be called while iterating.
+  void GetPendingURLRequests(std::vector<net::URLRequest*>* requests) const;
+
   // Adds |request| to the list of pending URLRequests that ascribe data use to
   // this recorder.
   void AddPendingURLRequest(net::URLRequest* request);
 
   // Moves pending |request| from |this| recorder to |other| recorder, and
   // updates the data use for the recorders.
-  void MovePendingURLRequest(DataUseRecorder* other, net::URLRequest* request);
+  void MovePendingURLRequestTo(DataUseRecorder* other,
+                               net::URLRequest* request);
 
   // Clears the list of pending URLRequests that ascribe data use to this
   // recorder.
diff --git a/components/exo/buffer_unittest.cc b/components/exo/buffer_unittest.cc
index 69e187af..02423ea 100644
--- a/components/exo/buffer_unittest.cc
+++ b/components/exo/buffer_unittest.cc
@@ -53,7 +53,7 @@
   returned_resource.id = resource.id;
   returned_resource.sync_token = resource.mailbox_holder.sync_token;
   returned_resource.lost = false;
-  cc::ReturnedResourceArray resources = {returned_resource};
+  std::vector<cc::ReturnedResource> resources = {returned_resource};
   layer_tree_frame_sink_holder->ReclaimResources(resources);
 
   RunAllPendingInMessageLoop();
@@ -98,7 +98,7 @@
   returned_resource.id = resource_id;
   returned_resource.sync_token = gpu::SyncToken();
   returned_resource.lost = is_lost;
-  cc::ReturnedResourceArray resources = {returned_resource};
+  std::vector<cc::ReturnedResource> resources = {returned_resource};
   layer_tree_frame_sink_holder->ReclaimResources(resources);
   RunAllPendingInMessageLoop();
 
@@ -115,7 +115,7 @@
   returned_resource2.id = resource_id;
   returned_resource2.sync_token = gpu::SyncToken();
   returned_resource2.lost = false;
-  cc::ReturnedResourceArray resources2 = {returned_resource2};
+  std::vector<cc::ReturnedResource> resources2 = {returned_resource2};
   layer_tree_frame_sink_holder->ReclaimResources(resources2);
   RunAllPendingInMessageLoop();
 }
diff --git a/components/exo/layer_tree_frame_sink_holder.cc b/components/exo/layer_tree_frame_sink_holder.cc
index f7920103..a750192d 100644
--- a/components/exo/layer_tree_frame_sink_holder.cc
+++ b/components/exo/layer_tree_frame_sink_holder.cc
@@ -63,7 +63,7 @@
 }
 
 void LayerTreeFrameSinkHolder::ReclaimResources(
-    const cc::ReturnedResourceArray& resources) {
+    const std::vector<cc::ReturnedResource>& resources) {
   for (auto& resource : resources) {
     auto it = release_callbacks_.find(resource.id);
     DCHECK(it != release_callbacks_.end());
diff --git a/components/exo/layer_tree_frame_sink_holder.h b/components/exo/layer_tree_frame_sink_holder.h
index 60dd085..12b0c45 100644
--- a/components/exo/layer_tree_frame_sink_holder.h
+++ b/components/exo/layer_tree_frame_sink_holder.h
@@ -40,7 +40,8 @@
 
   // Overridden from cc::LayerTreeFrameSinkClient:
   void SetBeginFrameSource(cc::BeginFrameSource* source) override;
-  void ReclaimResources(const cc::ReturnedResourceArray& resources) override;
+  void ReclaimResources(
+      const std::vector<cc::ReturnedResource>& resources) override;
   void SetTreeActivationCallback(const base::Closure& callback) override {}
   void DidReceiveCompositorFrameAck() override;
   void DidLoseLayerTreeFrameSink() override {}
diff --git a/components/feature_engagement_tracker/public/android/java/src/org/chromium/components/feature_engagement_tracker/EventConstants.java b/components/feature_engagement_tracker/public/android/java/src/org/chromium/components/feature_engagement_tracker/EventConstants.java
index 24f03f2..cd34ad1 100644
--- a/components/feature_engagement_tracker/public/android/java/src/org/chromium/components/feature_engagement_tracker/EventConstants.java
+++ b/components/feature_engagement_tracker/public/android/java/src/org/chromium/components/feature_engagement_tracker/EventConstants.java
@@ -29,6 +29,12 @@
     public static final String DOWNLOAD_HOME_OPENED = "download_home_opened";
 
     /**
+     * Screenshot is taken with Chrome in the foreground.
+     */
+    public static final String SCREENSHOT_TAKEN_CHROME_IN_FOREGROUND =
+            "screenshot_taken_chrome_in_foreground";
+
+    /**
      * The data saver preview infobar was shown.
      */
     public static final String DATA_SAVER_PREVIEW_INFOBAR_SHOWN = "data_saver_preview_opened";
diff --git a/components/feature_engagement_tracker/public/android/java/src/org/chromium/components/feature_engagement_tracker/FeatureConstants.java b/components/feature_engagement_tracker/public/android/java/src/org/chromium/components/feature_engagement_tracker/FeatureConstants.java
index b4372a0..417a7f1 100644
--- a/components/feature_engagement_tracker/public/android/java/src/org/chromium/components/feature_engagement_tracker/FeatureConstants.java
+++ b/components/feature_engagement_tracker/public/android/java/src/org/chromium/components/feature_engagement_tracker/FeatureConstants.java
@@ -10,6 +10,7 @@
  */
 public final class FeatureConstants {
     public static final String DOWNLOAD_PAGE_FEATURE = "IPH_DownloadPage";
+    public static final String DOWNLOAD_PAGE_SCREENSHOT_FEATURE = "IPH_DownloadPageScreenshot";
     public static final String DOWNLOAD_HOME_FEATURE = "IPH_DownloadHome";
 
     public static final String DATA_SAVER_PREVIEW_FEATURE = "IPH_DataSaverPreview";
diff --git a/components/feature_engagement_tracker/public/event_constants.cc b/components/feature_engagement_tracker/public/event_constants.cc
index 4816388..54397564 100644
--- a/components/feature_engagement_tracker/public/event_constants.cc
+++ b/components/feature_engagement_tracker/public/event_constants.cc
@@ -11,6 +11,10 @@
 #if defined(OS_WIN) || defined(OS_LINUX)
 const char kNewTabOpened[] = "new_tab_opened";
 const char kOmniboxInteraction[] = "omnibox_used";
+
+const char kHistoryDeleted[] = "history_deleted";
+const char kIncognitoWindowOpened[] = "incognito_window_opened";
+
 const char kSessionTime[] = "session_time";
 #endif  // defined(OS_WIN) || defined(OS_LINUX)
 
diff --git a/components/feature_engagement_tracker/public/event_constants.h b/components/feature_engagement_tracker/public/event_constants.h
index 292d295d..0cf15a61 100644
--- a/components/feature_engagement_tracker/public/event_constants.h
+++ b/components/feature_engagement_tracker/public/event_constants.h
@@ -17,10 +17,20 @@
 
 // The user has opened a new tab.
 extern const char kNewTabOpened[];
-
 // The user has interacted with the omnibox.
 extern const char kOmniboxInteraction[];
 
+// All the events declared below are the string names
+// of deferred onboarding events for the Incognito Window
+
+// The user has deleted browsing history.
+extern const char kHistoryDeleted[];
+// The user has opened an incognito window.
+extern const char kIncognitoWindowOpened[];
+
+// All the events declared below are the string names
+// of common deferred onboarding events
+
 // The user has accumulated 2 hours of active session time (one-off event).
 extern const char kSessionTime[];
 
diff --git a/components/feature_engagement_tracker/public/feature_constants.cc b/components/feature_engagement_tracker/public/feature_constants.cc
index d9669ba..4b945a4 100644
--- a/components/feature_engagement_tracker/public/feature_constants.cc
+++ b/components/feature_engagement_tracker/public/feature_constants.cc
@@ -21,6 +21,8 @@
                                             base::FEATURE_DISABLED_BY_DEFAULT};
 const base::Feature kIPHDownloadPageFeature{"IPH_DownloadPage",
                                             base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kIPHDownloadPageScreenshotFeature{
+    "IPH_DownloadPageScreenshot", base::FEATURE_DISABLED_BY_DEFAULT};
 #endif  // defined(OS_ANDROID)
 
 #if defined(OS_WIN) || defined(OS_LINUX)
diff --git a/components/feature_engagement_tracker/public/feature_constants.h b/components/feature_engagement_tracker/public/feature_constants.h
index baf93f3..04ff61a 100644
--- a/components/feature_engagement_tracker/public/feature_constants.h
+++ b/components/feature_engagement_tracker/public/feature_constants.h
@@ -24,6 +24,7 @@
 extern const base::Feature kIPHDataSaverPreviewFeature;
 extern const base::Feature kIPHDownloadHomeFeature;
 extern const base::Feature kIPHDownloadPageFeature;
+extern const base::Feature kIPHDownloadPageScreenshotFeature;
 #endif  // defined(OS_ANDROID)
 
 #if defined(OS_WIN) || defined(OS_LINUX)
diff --git a/components/feature_engagement_tracker/public/feature_list.cc b/components/feature_engagement_tracker/public/feature_list.cc
index 976ff40..a045c43 100644
--- a/components/feature_engagement_tracker/public/feature_list.cc
+++ b/components/feature_engagement_tracker/public/feature_list.cc
@@ -19,6 +19,7 @@
     &kIPHDataSaverPreviewFeature,
     &kIPHDownloadHomeFeature,
     &kIPHDownloadPageFeature,
+    &kIPHDownloadPageScreenshotFeature,
 #endif  // defined(OS_ANDROID)
 #if defined(OS_WIN) || defined(OS_LINUX)
     &kIPHIncognitoWindowFeature,
diff --git a/components/feature_engagement_tracker/public/feature_list.h b/components/feature_engagement_tracker/public/feature_list.h
index cdb15d0..87858066 100644
--- a/components/feature_engagement_tracker/public/feature_list.h
+++ b/components/feature_engagement_tracker/public/feature_list.h
@@ -49,6 +49,8 @@
 DEFINE_VARIATION_PARAM(kIPHDataSaverPreviewFeature, "IPH_DataSaverPreview");
 DEFINE_VARIATION_PARAM(kIPHDownloadHomeFeature, "IPH_DownloadHome");
 DEFINE_VARIATION_PARAM(kIPHDownloadPageFeature, "IPH_DownloadPage");
+DEFINE_VARIATION_PARAM(kIPHDownloadPageScreenshotFeature,
+                       "IPH_DownloadPageScreenshot");
 #endif  // defined(OS_ANDROID)
 #if defined(OS_WIN) || defined(OS_LINUX)
 DEFINE_VARIATION_PARAM(kIPHIncognitoWindowFeature, "IPH_IncognitoWindow");
@@ -67,6 +69,7 @@
         VARIATION_ENTRY(kIPHDataSaverPreviewFeature),
         VARIATION_ENTRY(kIPHDownloadHomeFeature),
         VARIATION_ENTRY(kIPHDownloadPageFeature),
+        VARIATION_ENTRY(kIPHDownloadPageScreenshotFeature),
 #elif defined(OS_WIN) || defined(OS_LINUX)
         VARIATION_ENTRY(kIPHIncognitoWindowFeature),
         VARIATION_ENTRY(kIPHNewTabFeature),
diff --git a/components/metrics/proto/cast_logs.proto b/components/metrics/proto/cast_logs.proto
index 1c40c3a..171f86d 100644
--- a/components/metrics/proto/cast_logs.proto
+++ b/components/metrics/proto/cast_logs.proto
@@ -85,7 +85,7 @@
       optional string chrome_browser_version = 4;
 
       // Platform of sender device.
-      // Next tag: 7
+      // Next tag: 8
       enum Platform {
         // Any platform other then cases below.
         PLATFORM_OTHER = 0;
@@ -96,6 +96,9 @@
         PLATFORM_OSX = 4;
         PLATFORM_CHROMEOS = 5;
         PLATFORM_LINUX = 6;
+
+        // The sender is Cast device - including itself.
+        PLATFORM_CAST = 7;
       }
       optional Platform platform = 5;
 
@@ -108,6 +111,8 @@
         CONNECTION_TYPE_UNKNOWN = 0;
         CONNECTION_TYPE_LOCAL = 1;
         CONNECTION_TYPE_RELAY = 2;
+        // A connection created by receiver itself internally.
+        CONNECTION_TYPE_INTERNAL = 3;
       }
       optional ConnectionType transport_connection_type = 7;
 
diff --git a/components/navigation_metrics/BUILD.gn b/components/navigation_metrics/BUILD.gn
index 3908ff1..7325fcb 100644
--- a/components/navigation_metrics/BUILD.gn
+++ b/components/navigation_metrics/BUILD.gn
@@ -10,6 +10,7 @@
 
   deps = [
     "//base",
+    "//components/dom_distiller/core:core",
     "//url",
   ]
 }
diff --git a/components/navigation_metrics/DEPS b/components/navigation_metrics/DEPS
index f0bf3d9..7b83d07 100644
--- a/components/navigation_metrics/DEPS
+++ b/components/navigation_metrics/DEPS
@@ -1,3 +1,3 @@
 include_rules = [
-  "+components/keyed_service/core",
+  "+components/dom_distiller/core",
 ]
diff --git a/components/navigation_metrics/navigation_metrics.cc b/components/navigation_metrics/navigation_metrics.cc
index 78df324..f63b6c4 100644
--- a/components/navigation_metrics/navigation_metrics.cc
+++ b/components/navigation_metrics/navigation_metrics.cc
@@ -6,24 +6,33 @@
 
 #include "base/macros.h"
 #include "base/metrics/histogram_macros.h"
+#include "components/dom_distiller/core/url_constants.h"
 #include "url/gurl.h"
 
 namespace {
 
-// This enum is used in building the histogram. So, this is append only,
-// any new scheme should be added at the end, before SCHEME_MAX
+// These values are written to logs. New enum values can be added, but existing
+// enums must never be renumbered or deleted and reused. Any new scheme should
+// be added at the end, before SCHEME_MAX.
 enum Scheme {
-  SCHEME_UNKNOWN,
-  SCHEME_HTTP,
-  SCHEME_HTTPS,
-  SCHEME_FILE,
-  SCHEME_FTP,
-  SCHEME_DATA,
-  SCHEME_JAVASCRIPT,
-  SCHEME_ABOUT,
-  SCHEME_CHROME,
-  SCHEME_BLOB,
-  SCHEME_FILESYSTEM,
+  SCHEME_UNKNOWN = 0,
+  SCHEME_HTTP = 1,
+  SCHEME_HTTPS = 2,
+  SCHEME_FILE = 3,
+  SCHEME_FTP = 4,
+  SCHEME_DATA = 5,
+  SCHEME_JAVASCRIPT = 6,
+  SCHEME_ABOUT = 7,
+  SCHEME_CHROME = 8,
+  SCHEME_BLOB = 9,
+  SCHEME_FILESYSTEM = 10,
+  SCHEME_CHROME_NATIVE = 11,
+  SCHEME_CHROME_SEARCH = 12,
+  SCHEME_CHROME_DISTILLER = 13,
+  SCHEME_CHROME_DEVTOOLS = 14,
+  SCHEME_CHROME_EXTENSION = 15,
+  SCHEME_VIEW_SOURCE = 16,
+  SCHEME_EXTERNALFILE = 17,
   SCHEME_MAX,
 };
 
@@ -39,11 +48,17 @@
     "chrome",
     url::kBlobScheme,
     url::kFileSystemScheme,
-    "max",
+    "chrome-native",
+    "chrome-search",
+    dom_distiller::kDomDistillerScheme,
+    "chrome-devtools",
+    "chrome-extension",
+    "view-source",
+    "externalfile",
 };
 
-static_assert(arraysize(kSchemeNames) == SCHEME_MAX + 1,
-              "kSchemeNames should have SCHEME_MAX + 1 elements");
+static_assert(arraysize(kSchemeNames) == SCHEME_MAX,
+              "kSchemeNames should have SCHEME_MAX elements");
 
 }  // namespace
 
diff --git a/components/net_log/resources/net_export.html b/components/net_log/resources/net_export.html
index b612b7ea..66c2d03 100644
--- a/components/net_log/resources/net_export.html
+++ b/components/net_log/resources/net_export.html
@@ -127,7 +127,25 @@
         </if>
 
         <if expr="not(is_ios or is_android)">
-        Attach the log file to your bug report, and you are done!
+        <p>Attach the log file to your bug report, and you are done!</p>
+
+        <p>
+          If the file is too big, it can be compressed or truncated.
+          <a href="#" id="toobig-read-more-link">Read more...</a>
+        </p>
+
+        <div id="toobig-read-more">
+          <ul>
+            <li>Compressing the log file before attaching is a good idea.</li>
+            <li>If the log file is still too big, you can try capturing again,
+              but over a shorter period of time</li>
+            <li>Existing log files can be shrunk using
+              <a
+                href="https://chromium.googlesource.com/chromium/src/+/master/net/tools/truncate_net_log.py"
+                target="_blank">
+                net/tools/truncate_net_log.py</a>.</li>
+          </ul>
+        </div>
         </if>
       </div>
 
diff --git a/components/net_log/resources/net_export.js b/components/net_log/resources/net_export.js
index be7c8e2..2d81fbc 100644
--- a/components/net_log/resources/net_export.js
+++ b/components/net_log/resources/net_export.js
@@ -33,8 +33,10 @@
   var kIdCaptureModeStopped = 'capture-mode-stopped';
   var kIdFilePathStoppedLogging = 'file-path-stopped';
   var kIdStartOverButton = 'startover';
-  var kIdReadMoreLink = 'privacy-read-more-link';
-  var kIdReadMoreDiv = 'privacy-read-more'
+  var kIdPrivacyReadMoreLink = 'privacy-read-more-link';
+  var kIdPrivacyReadMoreDiv = 'privacy-read-more'
+  var kIdTooBigReadMoreLink = 'toobig-read-more-link';
+  var kIdTooBigReadMoreDiv = 'toobig-read-more'
 
   /**
    * @constructor
@@ -220,8 +222,14 @@
       $(kIdCaptureModeStopped).textContent = this.getCaptureModeText_(info);
 
       // Hook up the "read more..." link for privacy information.
-      $(kIdReadMoreLink).onclick = this.showPrivacyReadMore_.bind(this, true);
+      $(kIdPrivacyReadMoreLink).onclick =
+          this.showPrivacyReadMore_.bind(this, true);
       this.showPrivacyReadMore_(false);
+
+      // Hook up the "read more..." link for reducing log size information.
+      $(kIdTooBigReadMoreLink).onclick =
+          this.showTooBigReadMore_.bind(this, true);
+      this.showTooBigReadMore_(false);
     },
 
     /**
@@ -241,8 +249,13 @@
     },
 
     showPrivacyReadMore_: function(show) {
-      $(kIdReadMoreDiv).hidden = !show;
-      $(kIdReadMoreLink).hidden = show;
+      $(kIdPrivacyReadMoreDiv).hidden = !show;
+      $(kIdPrivacyReadMoreLink).hidden = show;
+    },
+
+    showTooBigReadMore_: function(show) {
+      $(kIdTooBigReadMoreDiv).hidden = !show;
+      $(kIdTooBigReadMoreLink).hidden = show;
     },
 
     showStateDiv_: function(divId) {
diff --git a/components/ntp_snippets/remote/remote_suggestions_provider_impl_unittest.cc b/components/ntp_snippets/remote/remote_suggestions_provider_impl_unittest.cc
index d8760fc7..2f3a222 100644
--- a/components/ntp_snippets/remote/remote_suggestions_provider_impl_unittest.cc
+++ b/components/ntp_snippets/remote/remote_suggestions_provider_impl_unittest.cc
@@ -202,6 +202,177 @@
   std::vector<std::string> category_json_;
 };
 
+class RemoteSuggestionBuilder {
+ public:
+  RemoteSuggestionBuilder() = default;
+
+  RemoteSuggestionBuilder& AddId(const std::string& id) {
+    if (!ids_) {
+      ids_ = std::vector<std::string>();
+    }
+    ids_->push_back(id);
+    return *this;
+  }
+  RemoteSuggestionBuilder& SetTitle(const std::string& title) {
+    title_ = title;
+    return *this;
+  }
+  RemoteSuggestionBuilder& SetSnippet(const std::string& snippet) {
+    snippet_ = snippet;
+    return *this;
+  }
+  RemoteSuggestionBuilder& SetImageUrl(const std::string& image_url) {
+    salient_image_url_ = image_url;
+    return *this;
+  }
+  RemoteSuggestionBuilder& SetPublishDate(const base::Time& publish_date) {
+    publish_date_ = publish_date;
+    return *this;
+  }
+  RemoteSuggestionBuilder& SetExpiryDate(const base::Time& expiry_date) {
+    expiry_date_ = expiry_date;
+    return *this;
+  }
+  RemoteSuggestionBuilder& SetScore(double score) {
+    score_ = score;
+    return *this;
+  }
+  RemoteSuggestionBuilder& SetIsDismissed(bool is_dismissed) {
+    is_dismissed_ = is_dismissed;
+    return *this;
+  }
+  RemoteSuggestionBuilder& SetRemoteCategoryId(int remote_category_id) {
+    remote_category_id_ = remote_category_id;
+    return *this;
+  }
+  RemoteSuggestionBuilder& SetUrl(const std::string& url) {
+    url_ = url;
+    return *this;
+  }
+  RemoteSuggestionBuilder& SetPublisher(const std::string& publisher) {
+    publisher_name_ = publisher;
+    return *this;
+  }
+  RemoteSuggestionBuilder& SetAmpUrl(const std::string& amp_url) {
+    amp_url_ = amp_url;
+    return *this;
+  }
+  RemoteSuggestionBuilder& SetFetchDate(const base::Time& fetch_date) {
+    fetch_date_ = fetch_date;
+    return *this;
+  }
+
+  std::unique_ptr<RemoteSuggestion> Build() const {
+    SnippetProto proto;
+    proto.set_title(title_.value_or("Title"));
+    proto.set_snippet(snippet_.value_or("Snippet"));
+    proto.set_salient_image_url(
+        salient_image_url_.value_or("http://image_url.com/"));
+    proto.set_publish_date(
+        publish_date_.value_or(GetDefaultCreationTime()).ToInternalValue());
+    proto.set_expiry_date(
+        expiry_date_.value_or(GetDefaultExpirationTime()).ToInternalValue());
+    proto.set_score(score_.value_or(1));
+    proto.set_dismissed(is_dismissed_.value_or(false));
+    proto.set_remote_category_id(remote_category_id_.value_or(1));
+    auto* source = proto.add_sources();
+    source->set_url(url_.value_or("http://url.com/"));
+    source->set_publisher_name(publisher_name_.value_or("Publisher"));
+    source->set_amp_url(amp_url_.value_or("http://amp_url.com/"));
+    proto.set_fetch_date(
+        fetch_date_.value_or(base::Time::Now()).ToInternalValue());
+    for (const auto& id :
+         ids_.value_or(std::vector<std::string>{source->url()})) {
+      proto.add_ids(id);
+    }
+    return RemoteSuggestion::CreateFromProto(proto);
+  }
+
+ private:
+  base::Optional<std::vector<std::string>> ids_;
+  base::Optional<std::string> title_;
+  base::Optional<std::string> snippet_;
+  base::Optional<std::string> salient_image_url_;
+  base::Optional<base::Time> publish_date_;
+  base::Optional<base::Time> expiry_date_;
+  base::Optional<double> score_;
+  base::Optional<bool> is_dismissed_;
+  base::Optional<int> remote_category_id_;
+  base::Optional<std::string> url_;
+  base::Optional<std::string> publisher_name_;
+  base::Optional<std::string> amp_url_;
+  base::Optional<base::Time> fetch_date_;
+};
+
+class FetchedCategoryBuilder {
+ public:
+  FetchedCategoryBuilder() = default;
+
+  FetchedCategoryBuilder& SetCategory(Category category) {
+    category_ = category;
+    return *this;
+  }
+  FetchedCategoryBuilder& SetTitle(const std::string& title) {
+    title_ = base::UTF8ToUTF16(title);
+    return *this;
+  }
+  FetchedCategoryBuilder& SetCardLayout(
+      ContentSuggestionsCardLayout card_layout) {
+    card_layout_ = card_layout;
+    return *this;
+  }
+  FetchedCategoryBuilder& SetAdditionalAction(
+      ContentSuggestionsAdditionalAction additional_action) {
+    additional_action_ = additional_action;
+    return *this;
+  }
+  FetchedCategoryBuilder& SetShowIfEmpty(bool show_if_empty) {
+    show_if_empty_ = show_if_empty;
+    return *this;
+  }
+  FetchedCategoryBuilder& SetNoSuggestionsMessage(
+      const std::string& no_suggestions_message) {
+    no_suggestions_message_ = base::UTF8ToUTF16(no_suggestions_message);
+    return *this;
+  }
+  FetchedCategoryBuilder& AddSuggestionViaBuilder(
+      const RemoteSuggestionBuilder& builder) {
+    if (!suggestion_builders_) {
+      suggestion_builders_ = std::vector<RemoteSuggestionBuilder>();
+    }
+    suggestion_builders_->push_back(builder);
+    return *this;
+  }
+
+  FetchedCategory Build() const {
+    FetchedCategory result = FetchedCategory(
+        category_.value_or(Category::FromRemoteCategory(1)),
+        CategoryInfo(
+            title_.value_or(base::UTF8ToUTF16("Category title")),
+            card_layout_.value_or(ContentSuggestionsCardLayout::FULL_CARD),
+            additional_action_.value_or(
+                ContentSuggestionsAdditionalAction::FETCH),
+            show_if_empty_.value_or(false),
+            no_suggestions_message_.value_or(
+                base::UTF8ToUTF16("No suggestions message"))));
+
+    if (suggestion_builders_) {
+      for (const auto& suggestion_builder : *suggestion_builders_)
+        result.suggestions.push_back(suggestion_builder.Build());
+    }
+    return result;
+  }
+
+ private:
+  base::Optional<Category> category_;
+  base::Optional<base::string16> title_;
+  base::Optional<ContentSuggestionsCardLayout> card_layout_;
+  base::Optional<ContentSuggestionsAdditionalAction> additional_action_;
+  base::Optional<bool> show_if_empty_;
+  base::Optional<base::string16> no_suggestions_message_;
+  base::Optional<std::vector<RemoteSuggestionBuilder>> suggestion_builders_;
+};
+
 // TODO(vitaliii): Remove these convenience functions as they do not provide
 // that much value and add additional redirections obscuring the code.
 std::string GetTestJson(const std::vector<std::string>& suggestions,
@@ -294,12 +465,6 @@
                                       GetDefaultExpirationTime());
 }
 
-std::string GetSuggestionN(int n) {
-  return GetSuggestionWithUrlAndTimes(
-      base::StringPrintf("%s/%d", kSuggestionUrl, n), GetDefaultCreationTime(),
-      GetDefaultExpirationTime());
-}
-
 std::string GetExpiredSuggestion() {
   return GetSuggestionWithTimes(GetDefaultCreationTime(), base::Time::Now());
 }
@@ -578,10 +743,11 @@
 
   void ResetSuggestionsProvider(
       std::unique_ptr<RemoteSuggestionsProviderImpl>* provider,
+      bool use_mock_suggestions_fetcher,
       bool set_empty_response) {
     provider->reset();
     observer_.reset();
-    *provider = MakeSuggestionsProvider(/*use_mock_suggestions_fetcher=*/false,
+    *provider = MakeSuggestionsProvider(use_mock_suggestions_fetcher,
                                         set_empty_response);
   }
 
@@ -639,11 +805,44 @@
                                               net::URLRequestStatus::SUCCESS);
   }
 
-  void FetchSuggestions(
+  void FetchTheseSuggestions(
       RemoteSuggestionsProviderImpl* provider,
       bool interactive_request,
-      const RemoteSuggestionsProvider::FetchStatusCallback& callback) {
-    provider->FetchSuggestions(interactive_request, callback);
+      Status status,
+      base::Optional<std::vector<FetchedCategory>> fetched_categories) {
+    auto* mock_fetcher = static_cast<StrictMock<MockRemoteSuggestionsFetcher>*>(
+        suggestions_fetcher());
+    RemoteSuggestionsFetcher::SnippetsAvailableCallback snippets_callback;
+    EXPECT_CALL(*mock_fetcher, FetchSnippets(_, _))
+        .WillOnce(MoveSecondArgumentPointeeTo(&snippets_callback))
+        .RetiresOnSaturation();
+    provider->FetchSuggestions(
+        interactive_request, RemoteSuggestionsProvider::FetchStatusCallback());
+    std::move(snippets_callback)
+        .Run(Status(StatusCode::SUCCESS, "message"),
+             std::move(fetched_categories));
+  }
+
+  void FetchMoreTheseSuggestions(
+      RemoteSuggestionsProviderImpl* provider,
+      const Category& category,
+      const std::set<std::string>& known_suggestion_ids,
+      FetchDoneCallback fetch_done_callback,
+      Status status,
+      base::Optional<std::vector<FetchedCategory>> fetched_categories) {
+    auto* mock_fetcher = static_cast<StrictMock<MockRemoteSuggestionsFetcher>*>(
+        suggestions_fetcher());
+    RemoteSuggestionsFetcher::SnippetsAvailableCallback snippets_callback;
+    EXPECT_CALL(*mock_fetcher, FetchSnippets(_, _))
+        .WillOnce(MoveSecondArgumentPointeeTo(&snippets_callback))
+        .RetiresOnSaturation();
+    EXPECT_CALL(*scheduler(), AcquireQuotaForInteractiveFetch())
+        .WillOnce(Return(true))
+        .RetiresOnSaturation();
+    provider->Fetch(category, known_suggestion_ids, fetch_done_callback);
+    std::move(snippets_callback)
+        .Run(Status(StatusCode::SUCCESS, "message"),
+             std::move(fetched_categories));
   }
 
   void LoadFromJSONString(RemoteSuggestionsProviderImpl* provider,
@@ -719,12 +918,23 @@
 };
 
 TEST_F(RemoteSuggestionsProviderImplTest, Full) {
-  std::string json_str(GetTestJson({GetSuggestion()}));
-
   auto provider = MakeSuggestionsProvider(
-      /*use_mock_suggestions_fetcher=*/false, /*set_empty_response=*/true);
+      /*use_mock_suggestions_fetcher=*/true, /*set_empty_response=*/true);
 
-  LoadFromJSONString(provider.get(), json_str);
+  std::vector<FetchedCategory> fetched_categories;
+  fetched_categories.push_back(
+      FetchedCategoryBuilder()
+          .SetCategory(articles_category())
+          .AddSuggestionViaBuilder(RemoteSuggestionBuilder()
+                                       .AddId(kSuggestionUrl)
+                                       .SetTitle(kSuggestionTitle)
+                                       .SetSnippet(kSuggestionText)
+                                       .SetPublishDate(GetDefaultCreationTime())
+                                       .SetPublisher(kSuggestionPublisherName))
+          .Build());
+  FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
+                        Status(StatusCode::SUCCESS, "message"),
+                        std::move(fetched_categories));
 
   ASSERT_THAT(observer().SuggestionsForCategory(articles_category()),
               SizeIs(1));
@@ -749,7 +959,7 @@
   // Don't send an initial response -- we want to test what happens without any
   // server status.
   auto provider = MakeSuggestionsProvider(
-      /*use_mock_suggestions_fetcher=*/false, /*set_empty_response=*/false);
+      /*use_mock_suggestions_fetcher=*/true, /*set_empty_response=*/false);
 
   // The articles category should be there by default, and have a title.
   CategoryInfo info_before = provider->GetCategoryInfo(articles_category());
@@ -759,8 +969,16 @@
               Eq(ContentSuggestionsAdditionalAction::FETCH));
   EXPECT_THAT(info_before.show_if_empty(), Eq(true));
 
-  std::string json_str_with_title(GetTestJson({GetSuggestion()}));
-  LoadFromJSONString(provider.get(), json_str_with_title);
+  std::vector<FetchedCategory> fetched_categories;
+  fetched_categories.push_back(
+      FetchedCategoryBuilder()
+          .SetCategory(articles_category())
+          .SetTitle(base::UTF16ToUTF8(test_default_title))
+          .AddSuggestionViaBuilder(RemoteSuggestionBuilder())
+          .Build());
+  FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
+                        Status(StatusCode::SUCCESS, "message"),
+                        std::move(fetched_categories));
 
   ASSERT_THAT(observer().SuggestionsForCategory(articles_category()),
               SizeIs(1));
@@ -779,13 +997,33 @@
 
 TEST_F(RemoteSuggestionsProviderImplTest, MultipleCategories) {
   auto provider = MakeSuggestionsProvider(
-      /*use_mock_suggestions_fetcher=*/false, /*set_empty_response=*/true);
-  std::string json_str =
-      MultiCategoryJsonBuilder()
-          .AddCategory({GetSuggestionN(0)}, /*remote_category_id=*/1)
-          .AddCategory({GetSuggestionN(1)}, /*remote_category_id=*/2)
-          .Build();
-  LoadFromJSONString(provider.get(), json_str);
+      /*use_mock_suggestions_fetcher=*/true, /*set_empty_response=*/true);
+  std::vector<FetchedCategory> fetched_categories;
+  fetched_categories.push_back(
+      FetchedCategoryBuilder()
+          .SetCategory(Category::FromRemoteCategory(1))
+          .AddSuggestionViaBuilder(
+              RemoteSuggestionBuilder()
+                  .AddId(base::StringPrintf("%s/%d", kSuggestionUrl, 0))
+                  .SetTitle(kSuggestionTitle)
+                  .SetSnippet(kSuggestionText)
+                  .SetPublishDate(GetDefaultCreationTime())
+                  .SetPublisher(kSuggestionPublisherName))
+          .Build());
+  fetched_categories.push_back(
+      FetchedCategoryBuilder()
+          .SetCategory(Category::FromRemoteCategory(2))
+          .AddSuggestionViaBuilder(
+              RemoteSuggestionBuilder()
+                  .AddId(base::StringPrintf("%s/%d", kSuggestionUrl, 1))
+                  .SetTitle(kSuggestionTitle)
+                  .SetSnippet(kSuggestionText)
+                  .SetPublishDate(GetDefaultCreationTime())
+                  .SetPublisher(kSuggestionPublisherName))
+          .Build());
+  FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
+                        Status(StatusCode::SUCCESS, "message"),
+                        std::move(fetched_categories));
 
   ASSERT_THAT(observer().statuses(),
               Eq(std::map<Category, CategoryStatus, Category::CompareByID>{
@@ -828,7 +1066,7 @@
 
 TEST_F(RemoteSuggestionsProviderImplTest, ArticleCategoryInfo) {
   auto provider = MakeSuggestionsProvider(
-      /*use_mock_suggestions_fetcher=*/false, /*set_empty_response=*/true);
+      /*use_mock_suggestions_fetcher=*/true, /*set_empty_response=*/true);
   CategoryInfo article_info = provider->GetCategoryInfo(articles_category());
   EXPECT_THAT(article_info.additional_action(),
               Eq(ContentSuggestionsAdditionalAction::FETCH));
@@ -837,15 +1075,24 @@
 
 TEST_F(RemoteSuggestionsProviderImplTest, ExperimentalCategoryInfo) {
   auto provider = MakeSuggestionsProvider(
-      /*use_mock_suggestions_fetcher=*/false, /*set_empty_response=*/true);
-  std::string json_str =
-      MultiCategoryJsonBuilder()
-          .AddCategory({GetSuggestionN(0)}, /*remote_category_id=*/1)
-          .AddCategory({GetSuggestionN(1)}, kUnknownRemoteCategoryId)
-          .Build();
+      /*use_mock_suggestions_fetcher=*/true, /*set_empty_response=*/true);
+  std::vector<FetchedCategory> fetched_categories;
+  fetched_categories.push_back(
+      FetchedCategoryBuilder()
+          .SetCategory(Category::FromRemoteCategory(1))
+          .AddSuggestionViaBuilder(RemoteSuggestionBuilder().AddId("1"))
+          .Build());
+  fetched_categories.push_back(
+      FetchedCategoryBuilder()
+          .SetCategory(Category::FromRemoteCategory(kUnknownRemoteCategoryId))
+          .SetAdditionalAction(ContentSuggestionsAdditionalAction::NONE)
+          .AddSuggestionViaBuilder(RemoteSuggestionBuilder().AddId("2"))
+          .Build());
   // Load data with multiple categories so that a new experimental category gets
   // registered.
-  LoadFromJSONString(provider.get(), json_str);
+  FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
+                        Status(StatusCode::SUCCESS, "message"),
+                        std::move(fetched_categories));
 
   CategoryInfo info = provider->GetCategoryInfo(unknown_category());
   EXPECT_THAT(info.additional_action(),
@@ -857,12 +1104,22 @@
   auto mock_ranker = base::MakeUnique<MockCategoryRanker>();
   MockCategoryRanker* raw_mock_ranker = mock_ranker.get();
   SetCategoryRanker(std::move(mock_ranker));
-  std::string json_str =
-      MultiCategoryJsonBuilder()
-          .AddCategory({GetSuggestionN(0)}, /*remote_category_id=*/11)
-          .AddCategory({GetSuggestionN(1)}, /*remote_category_id=*/13)
-          .AddCategory({GetSuggestionN(2)}, /*remote_category_id=*/12)
-          .Build();
+  std::vector<FetchedCategory> fetched_categories;
+  fetched_categories.push_back(
+      FetchedCategoryBuilder()
+          .SetCategory(Category::FromRemoteCategory(11))
+          .AddSuggestionViaBuilder(RemoteSuggestionBuilder().AddId("11"))
+          .Build());
+  fetched_categories.push_back(
+      FetchedCategoryBuilder()
+          .SetCategory(Category::FromRemoteCategory(13))
+          .AddSuggestionViaBuilder(RemoteSuggestionBuilder().AddId("13"))
+          .Build());
+  fetched_categories.push_back(
+      FetchedCategoryBuilder()
+          .SetCategory(Category::FromRemoteCategory(12))
+          .AddSuggestionViaBuilder(RemoteSuggestionBuilder().AddId("12"))
+          .Build());
   {
     // The order of categories is determined by the order in which they are
     // added. Thus, the latter is tested here.
@@ -875,8 +1132,10 @@
                 AppendCategoryIfNecessary(Category::FromRemoteCategory(12)));
   }
   auto provider = MakeSuggestionsProvider(
-      /*use_mock_suggestions_fetcher=*/false, /*set_empty_response=*/false);
-  LoadFromJSONString(provider.get(), json_str);
+      /*use_mock_suggestions_fetcher=*/true, /*set_empty_response=*/false);
+  FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
+                        Status(StatusCode::SUCCESS, "message"),
+                        std::move(fetched_categories));
 }
 
 TEST_F(RemoteSuggestionsProviderImplTest,
@@ -885,14 +1144,32 @@
   auto mock_ranker = base::MakeUnique<MockCategoryRanker>();
   MockCategoryRanker* raw_mock_ranker = mock_ranker.get();
   SetCategoryRanker(std::move(mock_ranker));
-  std::string json_str =
-      MultiCategoryJsonBuilder()
-          .AddCategory({GetSuggestionN(0)}, /*remote_category_id=*/14)
-          .AddCategory({GetSuggestionN(1)}, /*remote_category_id=*/13)
-          .AddCategory({GetSuggestionN(2)}, /*remote_category_id=*/1)
-          .AddCategory({GetSuggestionN(3)}, /*remote_category_id=*/12)
-          .AddCategory({GetSuggestionN(4)}, /*remote_category_id=*/11)
-          .Build();
+  std::vector<FetchedCategory> fetched_categories;
+  fetched_categories.push_back(
+      FetchedCategoryBuilder()
+          .SetCategory(Category::FromRemoteCategory(14))
+          .AddSuggestionViaBuilder(RemoteSuggestionBuilder().AddId("14"))
+          .Build());
+  fetched_categories.push_back(
+      FetchedCategoryBuilder()
+          .SetCategory(Category::FromRemoteCategory(13))
+          .AddSuggestionViaBuilder(RemoteSuggestionBuilder().AddId("13"))
+          .Build());
+  fetched_categories.push_back(
+      FetchedCategoryBuilder()
+          .SetCategory(Category::FromRemoteCategory(1))
+          .AddSuggestionViaBuilder(RemoteSuggestionBuilder().AddId("1"))
+          .Build());
+  fetched_categories.push_back(
+      FetchedCategoryBuilder()
+          .SetCategory(Category::FromRemoteCategory(12))
+          .AddSuggestionViaBuilder(RemoteSuggestionBuilder().AddId("12"))
+          .Build());
+  fetched_categories.push_back(
+      FetchedCategoryBuilder()
+          .SetCategory(Category::FromRemoteCategory(11))
+          .AddSuggestionViaBuilder(RemoteSuggestionBuilder().AddId("11"))
+          .Build());
   {
     InSequence s;
     EXPECT_CALL(*raw_mock_ranker,
@@ -909,8 +1186,10 @@
                                                articles_category()));
   }
   auto provider = MakeSuggestionsProvider(
-      /*use_mock_suggestions_fetcher=*/false, /*set_empty_response=*/false);
-  LoadFromJSONString(provider.get(), json_str);
+      /*use_mock_suggestions_fetcher=*/true, /*set_empty_response=*/false);
+  FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
+                        Status(StatusCode::SUCCESS, "message"),
+                        std::move(fetched_categories));
 }
 
 TEST_F(
@@ -920,60 +1199,73 @@
   auto mock_ranker = base::MakeUnique<MockCategoryRanker>();
   MockCategoryRanker* raw_mock_ranker = mock_ranker.get();
   SetCategoryRanker(std::move(mock_ranker));
-  std::string json_str =
-      MultiCategoryJsonBuilder()
-          .AddCategory({GetSuggestionN(0)}, /*remote_category_id=*/11)
-          .Build();
+  std::vector<FetchedCategory> fetched_categories;
+  fetched_categories.push_back(
+      FetchedCategoryBuilder()
+          .SetCategory(Category::FromRemoteCategory(11))
+          .AddSuggestionViaBuilder(RemoteSuggestionBuilder().AddId("11"))
+          .Build());
 
   EXPECT_CALL(*raw_mock_ranker, InsertCategoryBeforeIfNecessary(_, _)).Times(0);
   EXPECT_CALL(*raw_mock_ranker,
               AppendCategoryIfNecessary(Category::FromRemoteCategory(11)));
   auto provider = MakeSuggestionsProvider(
-      /*use_mock_suggestions_fetcher=*/false, /*set_empty_response=*/false);
-  LoadFromJSONString(provider.get(), json_str);
+      /*use_mock_suggestions_fetcher=*/true, /*set_empty_response=*/false);
+  FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
+                        Status(StatusCode::SUCCESS, "message"),
+                        std::move(fetched_categories));
 }
 
 TEST_F(RemoteSuggestionsProviderImplTest, PersistCategoryInfos) {
   auto provider = MakeSuggestionsProvider(
-      /*use_mock_suggestions_fetcher=*/false, /*set_empty_response=*/true);
-  // TODO(vitaliii): Use |articles_category()| instead of constant ID below.
-  std::string json_str =
-      MultiCategoryJsonBuilder()
-          .AddCategoryWithCustomTitle(
-              {GetSuggestionN(0)}, /*remote_category_id=*/1, "Articles for You")
-          .AddCategoryWithCustomTitle({GetSuggestionN(1)},
-                                      kUnknownRemoteCategoryId, "Other Things")
-          .Build();
-  LoadFromJSONString(provider.get(), json_str);
+      /*use_mock_suggestions_fetcher=*/true, /*set_empty_response=*/true);
+  std::vector<FetchedCategory> fetched_categories;
+  fetched_categories.push_back(
+      FetchedCategoryBuilder()
+          .SetCategory(articles_category())
+          .AddSuggestionViaBuilder(RemoteSuggestionBuilder().AddId("1"))
+          .Build());
+  fetched_categories.push_back(
+      FetchedCategoryBuilder()
+          .SetCategory(Category::FromRemoteCategory(kUnknownRemoteCategoryId))
+          .AddSuggestionViaBuilder(RemoteSuggestionBuilder().AddId("2"))
+          .Build());
+  FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
+                        Status(StatusCode::SUCCESS, "message"),
+                        std::move(fetched_categories));
 
   ASSERT_EQ(observer().StatusForCategory(articles_category()),
             CategoryStatus::AVAILABLE);
-  ASSERT_EQ(observer().StatusForCategory(unknown_category()),
+  ASSERT_EQ(observer().StatusForCategory(
+                Category::FromRemoteCategory(kUnknownRemoteCategoryId)),
             CategoryStatus::AVAILABLE);
 
   CategoryInfo info_articles_before =
       provider->GetCategoryInfo(articles_category());
-  CategoryInfo info_unknown_before =
-      provider->GetCategoryInfo(unknown_category());
+  CategoryInfo info_unknown_before = provider->GetCategoryInfo(
+      Category::FromRemoteCategory(kUnknownRemoteCategoryId));
 
   // Recreate the provider to simulate a Chrome restart.
-  ResetSuggestionsProvider(&provider, /*set_empty_response=*/true);
+  ResetSuggestionsProvider(&provider, /*use_mock_suggestions_fetcher=*/true,
+                           /*set_empty_response=*/true);
 
   // The categories should have been restored.
   ASSERT_NE(observer().StatusForCategory(articles_category()),
             CategoryStatus::NOT_PROVIDED);
-  ASSERT_NE(observer().StatusForCategory(unknown_category()),
+  ASSERT_NE(observer().StatusForCategory(
+                Category::FromRemoteCategory(kUnknownRemoteCategoryId)),
             CategoryStatus::NOT_PROVIDED);
 
   EXPECT_EQ(observer().StatusForCategory(articles_category()),
             CategoryStatus::AVAILABLE);
-  EXPECT_EQ(observer().StatusForCategory(unknown_category()),
+  EXPECT_EQ(observer().StatusForCategory(
+                Category::FromRemoteCategory(kUnknownRemoteCategoryId)),
             CategoryStatus::AVAILABLE);
 
   CategoryInfo info_articles_after =
       provider->GetCategoryInfo(articles_category());
-  CategoryInfo info_unknown_after =
-      provider->GetCategoryInfo(unknown_category());
+  CategoryInfo info_unknown_after = provider->GetCategoryInfo(
+      Category::FromRemoteCategory(kUnknownRemoteCategoryId));
 
   EXPECT_EQ(info_articles_before.title(), info_articles_after.title());
   EXPECT_EQ(info_unknown_before.title(), info_unknown_after.title());
@@ -981,23 +1273,37 @@
 
 TEST_F(RemoteSuggestionsProviderImplTest, PersistRemoteCategoryOrder) {
   // We create a provider with a normal ranker to store the order.
-  std::string json_str =
-      MultiCategoryJsonBuilder()
-          .AddCategory({GetSuggestionN(0)}, /*remote_category_id=*/11)
-          .AddCategory({GetSuggestionN(1)}, /*remote_category_id=*/13)
-          .AddCategory({GetSuggestionN(2)}, /*remote_category_id=*/12)
-          .Build();
   auto provider = MakeSuggestionsProvider(
-      /*use_mock_suggestions_fetcher=*/false, /*set_empty_response=*/false);
-  LoadFromJSONString(provider.get(), json_str);
+      /*use_mock_suggestions_fetcher=*/true, /*set_empty_response=*/false);
+  std::vector<FetchedCategory> fetched_categories;
+  fetched_categories.push_back(
+      FetchedCategoryBuilder()
+          .SetCategory(Category::FromRemoteCategory(11))
+          .AddSuggestionViaBuilder(RemoteSuggestionBuilder().AddId("11"))
+          .Build());
+  fetched_categories.push_back(
+      FetchedCategoryBuilder()
+          .SetCategory(Category::FromRemoteCategory(13))
+          .AddSuggestionViaBuilder(RemoteSuggestionBuilder().AddId("13"))
+          .Build());
+  fetched_categories.push_back(
+      FetchedCategoryBuilder()
+          .SetCategory(Category::FromRemoteCategory(12))
+          .AddSuggestionViaBuilder(RemoteSuggestionBuilder().AddId("12"))
+          .Build());
+  FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
+                        Status(StatusCode::SUCCESS, "message"),
+                        std::move(fetched_categories));
 
   // We manually recreate the provider to simulate Chrome restart and enforce a
-  // mock ranker. The response is cleared to ensure that the order is not
-  // fetched.
-  SetUpFetchResponse("");
+  // mock ranker.
   auto mock_ranker = base::MakeUnique<MockCategoryRanker>();
   MockCategoryRanker* raw_mock_ranker = mock_ranker.get();
   SetCategoryRanker(std::move(mock_ranker));
+  // Ensure that the order is not fetched.
+  auto* mock_fetcher = static_cast<StrictMock<MockRemoteSuggestionsFetcher>*>(
+      suggestions_fetcher());
+  EXPECT_CALL(*mock_fetcher, FetchSnippets(_, _)).Times(0);
   {
     // The order of categories is determined by the order in which they are
     // added. Thus, the latter is tested here.
@@ -1013,25 +1319,37 @@
     EXPECT_CALL(*raw_mock_ranker,
                 AppendCategoryIfNecessary(Category::FromRemoteCategory(12)));
   }
-  ResetSuggestionsProvider(&provider, /*set_empty_response=*/false);
+  ResetSuggestionsProvider(&provider, /*use_mock_suggestions_fetcher=*/true,
+                           /*set_empty_response=*/false);
 }
 
 TEST_F(RemoteSuggestionsProviderImplTest, PersistSuggestions) {
   auto provider = MakeSuggestionsProvider(
-      /*use_mock_suggestions_fetcher=*/false, /*set_empty_response=*/true);
-  std::string json_str =
-      MultiCategoryJsonBuilder()
-          .AddCategory({GetSuggestionN(0)}, /*remote_category_id=*/1)
-          .AddCategory({GetSuggestionN(2)}, /*remote_category_id=*/2)
-          .Build();
-  LoadFromJSONString(provider.get(), json_str);
+      /*use_mock_suggestions_fetcher=*/true, /*set_empty_response=*/true);
+  std::vector<FetchedCategory> fetched_categories;
+  fetched_categories.push_back(
+      FetchedCategoryBuilder()
+          .SetCategory(Category::FromRemoteCategory(1))
+          .AddSuggestionViaBuilder(
+              RemoteSuggestionBuilder().AddId("1").SetRemoteCategoryId(1))
+          .Build());
+  fetched_categories.push_back(
+      FetchedCategoryBuilder()
+          .SetCategory(Category::FromRemoteCategory(2))
+          .AddSuggestionViaBuilder(
+              RemoteSuggestionBuilder().AddId("2").SetRemoteCategoryId(2))
+          .Build());
+  FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
+                        Status(StatusCode::SUCCESS, "message"),
+                        std::move(fetched_categories));
 
   ASSERT_THAT(observer().SuggestionsForCategory(articles_category()),
               SizeIs(1));
   ASSERT_THAT(observer().SuggestionsForCategory(other_category()), SizeIs(1));
 
   // Recreate the provider to simulate a Chrome restart.
-  ResetSuggestionsProvider(&provider, /*set_empty_response=*/true);
+  ResetSuggestionsProvider(&provider, /*use_mock_suggestions_fetcher=*/true,
+                           /*set_empty_response=*/true);
 
   // The suggestions in both categories should have been restored.
   EXPECT_THAT(observer().SuggestionsForCategory(articles_category()),
@@ -1042,14 +1360,21 @@
 TEST_F(RemoteSuggestionsProviderImplTest, DontNotifyIfNotAvailable) {
   // Get some suggestions into the database.
   auto provider = MakeSuggestionsProvider(
-      /*use_mock_suggestions_fetcher=*/false, /*set_empty_response=*/true);
-  std::string json_str =
-      MultiCategoryJsonBuilder()
-          .AddCategory({GetSuggestionN(0)},
-                       /*remote_category_id=*/1)
-          .AddCategory({GetSuggestionN(1)}, /*remote_category_id=*/2)
-          .Build();
-  LoadFromJSONString(provider.get(), json_str);
+      /*use_mock_suggestions_fetcher=*/true, /*set_empty_response=*/true);
+  std::vector<FetchedCategory> fetched_categories;
+  fetched_categories.push_back(
+      FetchedCategoryBuilder()
+          .SetCategory(Category::FromRemoteCategory(1))
+          .AddSuggestionViaBuilder(RemoteSuggestionBuilder().AddId("1"))
+          .Build());
+  fetched_categories.push_back(
+      FetchedCategoryBuilder()
+          .SetCategory(Category::FromRemoteCategory(2))
+          .AddSuggestionViaBuilder(RemoteSuggestionBuilder().AddId("2"))
+          .Build());
+  FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
+                        Status(StatusCode::SUCCESS, "message"),
+                        std::move(fetched_categories));
 
   ASSERT_THAT(observer().SuggestionsForCategory(articles_category()),
               SizeIs(1));
@@ -1061,7 +1386,8 @@
   pref_service()->SetBoolean(prefs::kEnableSnippets, false);
 
   // Recreate the provider to simulate a Chrome start.
-  ResetSuggestionsProvider(&provider, /*set_empty_response=*/true);
+  ResetSuggestionsProvider(&provider, /*use_mock_suggestions_fetcher=*/true,
+                           /*set_empty_response=*/true);
 
   ASSERT_THAT(RemoteSuggestionsProviderImpl::State::DISABLED,
               Eq(provider->state_));
@@ -1074,11 +1400,18 @@
 
 TEST_F(RemoteSuggestionsProviderImplTest, Clear) {
   auto provider = MakeSuggestionsProvider(
-      /*use_mock_suggestions_fetcher=*/false, /*set_empty_response=*/true);
+      /*use_mock_suggestions_fetcher=*/true, /*set_empty_response=*/true);
 
-  std::string json_str(GetTestJson({GetSuggestion()}));
+  std::vector<FetchedCategory> fetched_categories;
+  fetched_categories.push_back(
+      FetchedCategoryBuilder()
+          .SetCategory(articles_category())
+          .AddSuggestionViaBuilder(RemoteSuggestionBuilder().AddId("1"))
+          .Build());
+  FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
+                        Status(StatusCode::SUCCESS, "message"),
+                        std::move(fetched_categories));
 
-  LoadFromJSONString(provider.get(), json_str);
   EXPECT_THAT(provider->GetSuggestionsForTesting(articles_category()),
               SizeIs(1));
 
@@ -1089,17 +1422,30 @@
 
 TEST_F(RemoteSuggestionsProviderImplTest, ReplaceSuggestions) {
   auto provider = MakeSuggestionsProvider(
-      /*use_mock_suggestions_fetcher=*/false, /*set_empty_response=*/true);
+      /*use_mock_suggestions_fetcher=*/true, /*set_empty_response=*/true);
 
   std::string first("http://first");
-  LoadFromJSONString(provider.get(),
-                     GetTestJson({GetSuggestionWithUrl(first)}));
+  std::vector<FetchedCategory> fetched_categories;
+  fetched_categories.push_back(
+      FetchedCategoryBuilder()
+          .SetCategory(articles_category())
+          .AddSuggestionViaBuilder(RemoteSuggestionBuilder().AddId(first))
+          .Build());
+  FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
+                        Status(StatusCode::SUCCESS, "message"),
+                        std::move(fetched_categories));
   EXPECT_THAT(provider->GetSuggestionsForTesting(articles_category()),
               ElementsAre(Pointee(Property(&RemoteSuggestion::id, first))));
 
   std::string second("http://second");
-  LoadFromJSONString(provider.get(),
-                     GetTestJson({GetSuggestionWithUrl(second)}));
+  fetched_categories.push_back(
+      FetchedCategoryBuilder()
+          .SetCategory(articles_category())
+          .AddSuggestionViaBuilder(RemoteSuggestionBuilder().AddId(second))
+          .Build());
+  FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
+                        Status(StatusCode::SUCCESS, "message"),
+                        std::move(fetched_categories));
   // The suggestions loaded last replace all that was loaded previously.
   EXPECT_THAT(provider->GetSuggestionsForTesting(articles_category()),
               ElementsAre(Pointee(Property(&RemoteSuggestion::id, second))));
@@ -1108,13 +1454,19 @@
 TEST_F(RemoteSuggestionsProviderImplTest,
        ShouldResolveFetchedSuggestionThumbnail) {
   auto provider = MakeSuggestionsProvider(
-      /*use_mock_suggestions_fetcher=*/false, /*set_empty_response=*/true);
+      /*use_mock_suggestions_fetcher=*/true, /*set_empty_response=*/true);
 
-  LoadFromJSONString(provider.get(),
-                     GetTestJson({GetSuggestionWithUrl("http://first")}));
-  ASSERT_THAT(
-      provider->GetSuggestionsForTesting(articles_category()),
-      ElementsAre(Pointee(Property(&RemoteSuggestion::id, "http://first"))));
+  std::vector<FetchedCategory> fetched_categories;
+  fetched_categories.push_back(
+      FetchedCategoryBuilder()
+          .SetCategory(articles_category())
+          .AddSuggestionViaBuilder(RemoteSuggestionBuilder().AddId("id"))
+          .Build());
+  FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
+                        Status(StatusCode::SUCCESS, "message"),
+                        std::move(fetched_categories));
+  ASSERT_THAT(provider->GetSuggestionsForTesting(articles_category()),
+              ElementsAre(Pointee(Property(&RemoteSuggestion::id, "id"))));
 
   image_decoder()->SetDecodedImage(gfx::test::CreateImage(1, 1));
   ServeImageCallback serve_one_by_one_image_callback =
@@ -1123,48 +1475,66 @@
       .WillOnce(WithArgs<0, 2>(
           Invoke(CreateFunctor(serve_one_by_one_image_callback))));
 
-  gfx::Image image = FetchImage(provider.get(), MakeArticleID("http://first"));
+  gfx::Image image = FetchImage(provider.get(), MakeArticleID("id"));
   ASSERT_FALSE(image.IsEmpty());
   EXPECT_EQ(1, image.Width());
 }
 
 TEST_F(RemoteSuggestionsProviderImplTest, ShouldFetchMore) {
   auto provider = MakeSuggestionsProvider(
-      /*use_mock_suggestions_fetcher=*/false, /*set_empty_response=*/true);
+      /*use_mock_suggestions_fetcher=*/true, /*set_empty_response=*/true);
 
-  LoadFromJSONString(provider.get(),
-                     GetTestJson({GetSuggestionWithUrl("http://first")}));
-  ASSERT_THAT(
-      provider->GetSuggestionsForTesting(articles_category()),
-      ElementsAre(Pointee(Property(&RemoteSuggestion::id, "http://first"))));
+  std::vector<FetchedCategory> fetched_categories;
+  fetched_categories.push_back(
+      FetchedCategoryBuilder()
+          .SetCategory(articles_category())
+          .AddSuggestionViaBuilder(RemoteSuggestionBuilder().AddId("first"))
+          .Build());
+  FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
+                        Status(StatusCode::SUCCESS, "message"),
+                        std::move(fetched_categories));
+  ASSERT_THAT(provider->GetSuggestionsForTesting(articles_category()),
+              ElementsAre(Pointee(Property(&RemoteSuggestion::id, "first"))));
 
   auto expect_only_second_suggestion_received =
       base::Bind([](Status status, std::vector<ContentSuggestion> suggestions) {
         EXPECT_THAT(suggestions, SizeIs(1));
-        EXPECT_THAT(suggestions[0].id().id_within_category(),
-                    Eq("http://second"));
+        EXPECT_THAT(suggestions[0].id().id_within_category(), Eq("second"));
       });
-  LoadMoreFromJSONString(provider.get(), articles_category(),
-                         GetTestJson({GetSuggestionWithUrl("http://second")}),
-                         /*known_ids=*/std::set<std::string>(),
-                         expect_only_second_suggestion_received);
+  fetched_categories.push_back(
+      FetchedCategoryBuilder()
+          .SetCategory(articles_category())
+          .AddSuggestionViaBuilder(RemoteSuggestionBuilder().AddId("second"))
+          .Build());
+  FetchMoreTheseSuggestions(
+      provider.get(), articles_category(),
+      /*known_suggestion_ids=*/std::set<std::string>(),
+      /*fetch_done_callback=*/expect_only_second_suggestion_received,
+      Status(StatusCode::SUCCESS, "message"), std::move(fetched_categories));
 }
 
 TEST_F(RemoteSuggestionsProviderImplTest,
        ShouldResolveFetchedMoreSuggestionThumbnail) {
   auto provider = MakeSuggestionsProvider(
-      /*use_mock_suggestions_fetcher=*/false, /*set_empty_response=*/true);
+      /*use_mock_suggestions_fetcher=*/true, /*set_empty_response=*/true);
+
+  std::vector<FetchedCategory> fetched_categories;
+  fetched_categories.push_back(
+      FetchedCategoryBuilder()
+          .SetCategory(articles_category())
+          .AddSuggestionViaBuilder(RemoteSuggestionBuilder().AddId("id"))
+          .Build());
 
   auto assert_only_first_suggestion_received =
       base::Bind([](Status status, std::vector<ContentSuggestion> suggestions) {
         ASSERT_THAT(suggestions, SizeIs(1));
-        ASSERT_THAT(suggestions[0].id().id_within_category(),
-                    Eq("http://first"));
+        ASSERT_THAT(suggestions[0].id().id_within_category(), Eq("id"));
       });
-  LoadMoreFromJSONString(provider.get(), articles_category(),
-                         GetTestJson({GetSuggestionWithUrl("http://first")}),
-                         /*known_ids=*/std::set<std::string>(),
-                         assert_only_first_suggestion_received);
+  FetchMoreTheseSuggestions(
+      provider.get(), articles_category(),
+      /*known_suggestion_ids=*/std::set<std::string>(),
+      /*fetch_done_callback=*/assert_only_first_suggestion_received,
+      Status(StatusCode::SUCCESS, "message"), std::move(fetched_categories));
 
   image_decoder()->SetDecodedImage(gfx::test::CreateImage(1, 1));
   ServeImageCallback serve_one_by_one_image_callback =
@@ -1173,7 +1543,7 @@
       .WillOnce(WithArgs<0, 2>(
           Invoke(CreateFunctor(serve_one_by_one_image_callback))));
 
-  gfx::Image image = FetchImage(provider.get(), MakeArticleID("http://first"));
+  gfx::Image image = FetchImage(provider.get(), MakeArticleID("id"));
   ASSERT_FALSE(image.IsEmpty());
   EXPECT_EQ(1, image.Width());
 }
@@ -1189,25 +1559,16 @@
                                            /*set_empty_response=*/true);
 
   // Fetch a suggestion.
-  auto* mock_fetcher = static_cast<StrictMock<MockRemoteSuggestionsFetcher>*>(
-      suggestions_fetcher());
   std::vector<FetchedCategory> fetched_categories;
-  fetched_categories.push_back(FetchedCategory(
-      articles_category(),
-      BuildRemoteCategoryInfo(base::UTF8ToUTF16("title"),
-                              /*allow_fetching_more_results=*/true)));
-  fetched_categories[0].suggestions.push_back(
-      CreateTestRemoteSuggestion("http://old.com/"));
-
-  RemoteSuggestionsFetcher::SnippetsAvailableCallback snippets_callback;
-  EXPECT_CALL(*mock_fetcher, FetchSnippets(_, _))
-      .WillOnce(MoveSecondArgumentPointeeTo(&snippets_callback))
-      .RetiresOnSaturation();
-  FetchSuggestions(provider.get(), /*interactive_request=*/true,
-                   RemoteSuggestionsProvider::FetchStatusCallback());
-  std::move(snippets_callback)
-      .Run(Status(StatusCode::SUCCESS, "message"),
-           std::move(fetched_categories));
+  fetched_categories.push_back(
+      FetchedCategoryBuilder()
+          .SetCategory(articles_category())
+          .AddSuggestionViaBuilder(
+              RemoteSuggestionBuilder().AddId("http://old.com/"))
+          .Build());
+  FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
+                        Status(StatusCode::SUCCESS, "message"),
+                        std::move(fetched_categories));
 
   ASSERT_THAT(
       observer().SuggestionsForCategory(articles_category()),
@@ -1216,12 +1577,12 @@
                                     "http://old.com/"))));
 
   // Now fetch more, but first prepare a response.
-  fetched_categories.push_back(FetchedCategory(
-      articles_category(),
-      BuildRemoteCategoryInfo(base::UTF8ToUTF16("title"),
-                              /*allow_fetching_more_results=*/true)));
-  fetched_categories[0].suggestions.push_back(
-      CreateTestRemoteSuggestion("http://fetched-more.com/"));
+  fetched_categories.push_back(
+      FetchedCategoryBuilder()
+          .SetCategory(articles_category())
+          .AddSuggestionViaBuilder(
+              RemoteSuggestionBuilder().AddId("http://fetched-more.com/"))
+          .Build());
 
   // The surface issuing the fetch more gets response via callback.
   auto assert_receiving_one_new_suggestion =
@@ -1230,18 +1591,12 @@
         ASSERT_THAT(suggestions[0].id().id_within_category(),
                     Eq("http://fetched-more.com/"));
       });
-  EXPECT_CALL(*mock_fetcher, FetchSnippets(_, _))
-      .WillOnce(MoveSecondArgumentPointeeTo(&snippets_callback))
-      .RetiresOnSaturation();
-  EXPECT_CALL(*scheduler(), AcquireQuotaForInteractiveFetch())
-      .WillOnce(Return(true))
-      .RetiresOnSaturation();
-  provider->Fetch(articles_category(),
-                  /*known_suggestion_ids=*/{"http://old.com/"},
-                  assert_receiving_one_new_suggestion);
-  std::move(snippets_callback)
-      .Run(Status(StatusCode::SUCCESS, "message"),
-           std::move(fetched_categories));
+  FetchMoreTheseSuggestions(
+      provider.get(), articles_category(),
+      /*known_suggestion_ids=*/{"http://old.com/"},
+      /*fetch_done_callback=*/assert_receiving_one_new_suggestion,
+      Status(StatusCode::SUCCESS, "message"), std::move(fetched_categories));
+
   // Other surfaces should remain the same.
   EXPECT_THAT(
       observer().SuggestionsForCategory(articles_category()),
@@ -1422,18 +1777,11 @@
        ShouldNotAddNewSuggestionsAfterFetchError) {
   auto provider = MakeSuggestionsProvider(
       /*use_mock_suggestions_fetcher=*/true, /*set_empty_response=*/true);
-  auto* mock_fetcher = static_cast<StrictMock<MockRemoteSuggestionsFetcher>*>(
-      suggestions_fetcher());
 
-  RemoteSuggestionsFetcher::SnippetsAvailableCallback snippets_callback;
-  MockFunction<void(Status, const std::vector<ContentSuggestion>&)> loaded;
-  EXPECT_CALL(*mock_fetcher, FetchSnippets(_, _))
-      .WillOnce(MoveSecondArgumentPointeeTo(&snippets_callback));
-  FetchSuggestions(provider.get(), /*interactive_request=*/false,
-                   RemoteSuggestionsProvider::FetchStatusCallback());
-  std::move(snippets_callback)
-      .Run(Status(StatusCode::TEMPORARY_ERROR, "Received invalid JSON"),
-           base::nullopt);
+  FetchTheseSuggestions(
+      provider.get(), /*interactive_request=*/false,
+      Status(StatusCode::TEMPORARY_ERROR, "Received invalid JSON"),
+      base::nullopt);
   EXPECT_THAT(provider->GetSuggestionsForTesting(articles_category()),
               IsEmpty());
 }
@@ -1442,8 +1790,6 @@
        ShouldNotClearOldSuggestionsAfterFetchError) {
   auto provider = MakeSuggestionsProvider(
       /*use_mock_suggestions_fetcher=*/true, /*set_empty_response=*/true);
-  auto* mock_fetcher = static_cast<StrictMock<MockRemoteSuggestionsFetcher>*>(
-      suggestions_fetcher());
 
   std::vector<FetchedCategory> fetched_categories;
   fetched_categories.push_back(FetchedCategory(
@@ -1452,26 +1798,18 @@
                               /*allow_fetching_more_results=*/true)));
   fetched_categories[0].suggestions.push_back(
       CreateTestRemoteSuggestion(base::StringPrintf("http://abc.com/")));
-  RemoteSuggestionsFetcher::SnippetsAvailableCallback snippets_callback;
-  EXPECT_CALL(*mock_fetcher, FetchSnippets(_, _))
-      .WillOnce(MoveSecondArgumentPointeeTo(&snippets_callback));
-  FetchSuggestions(provider.get(), /*interactive_request=*/false,
-                   RemoteSuggestionsProvider::FetchStatusCallback());
-  std::move(snippets_callback)
-      .Run(Status(StatusCode::SUCCESS, "success message"),
-           std::move(fetched_categories));
+  FetchTheseSuggestions(provider.get(), /*interactive_request=*/false,
+                        Status(StatusCode::SUCCESS, "success message"),
+                        std::move(fetched_categories));
 
   ASSERT_THAT(
       provider->GetSuggestionsForTesting(articles_category()),
       ElementsAre(Pointee(Property(&RemoteSuggestion::id, "http://abc.com/"))));
 
-  EXPECT_CALL(*mock_fetcher, FetchSnippets(_, _))
-      .WillOnce(MoveSecondArgumentPointeeTo(&snippets_callback));
-  FetchSuggestions(provider.get(), /*interactive_request=*/false,
-                   RemoteSuggestionsProvider::FetchStatusCallback());
-  std::move(snippets_callback)
-      .Run(Status(StatusCode::TEMPORARY_ERROR, "Received invalid JSON"),
-           base::nullopt);
+  FetchTheseSuggestions(
+      provider.get(), /*interactive_request=*/false,
+      Status(StatusCode::TEMPORARY_ERROR, "Received invalid JSON"),
+      base::nullopt);
   // This should not have changed the existing suggestions.
   EXPECT_THAT(
       provider->GetSuggestionsForTesting(articles_category()),
@@ -1524,7 +1862,8 @@
               IsEmpty());
 
   // The suggestion should stay dismissed even after re-creating the provider.
-  ResetSuggestionsProvider(&provider, /*set_empty_response=*/true);
+  ResetSuggestionsProvider(&provider, /*use_mock_suggestions_fetcher=*/false,
+                           /*set_empty_response=*/true);
   LoadFromJSONString(provider.get(), json_str);
   EXPECT_THAT(provider->GetSuggestionsForTesting(articles_category()),
               IsEmpty());
@@ -1910,7 +2249,8 @@
   // The image should still be available until a restart happens.
   EXPECT_FALSE(
       FetchImage(provider.get(), MakeArticleID(kSuggestionUrl)).IsEmpty());
-  ResetSuggestionsProvider(&provider, /*set_empty_response=*/true);
+  ResetSuggestionsProvider(&provider, /*use_mock_suggestions_fetcher=*/false,
+                           /*set_empty_response=*/true);
   // After the restart, the image should be garbage collected.
   EXPECT_TRUE(
       FetchImage(provider.get(), MakeArticleID(kSuggestionUrl)).IsEmpty());
@@ -2095,17 +2435,9 @@
       CreateTestRemoteSuggestion("http://abc.com/"));
   ASSERT_TRUE(fetched_categories[0].suggestions[0]->is_complete());
 
-  // Fetch the suggestion.
-  RemoteSuggestionsFetcher::SnippetsAvailableCallback snippets_callback;
-  EXPECT_CALL(*mock_fetcher, FetchSnippets(_, _))
-      .WillOnce(MoveSecondArgumentPointeeTo(&snippets_callback))
-      .RetiresOnSaturation();
-  FetchSuggestions(provider.get(), /*interactive_request=*/true,
-                   RemoteSuggestionsProvider::FetchStatusCallback());
-  std::move(snippets_callback)
-      .Run(Status(StatusCode::SUCCESS, "message"),
-           std::move(fetched_categories));
-
+  FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
+                        Status(StatusCode::SUCCESS, "message"),
+                        std::move(fetched_categories));
   provider->DismissSuggestion(MakeArticleID("http://abc.com/"));
 
   std::set<std::string> expected_excluded_ids({"http://abc.com/"});
@@ -2145,17 +2477,9 @@
         base::StringPrintf("http://abc.com/%d/", i)));
   }
 
-  // Fetch the suggestions.
-  RemoteSuggestionsFetcher::SnippetsAvailableCallback snippets_callback;
-  EXPECT_CALL(*mock_fetcher, FetchSnippets(_, _))
-      .WillOnce(MoveSecondArgumentPointeeTo(&snippets_callback))
-      .RetiresOnSaturation();
-  FetchSuggestions(provider.get(), /*interactive_request=*/true,
-                   RemoteSuggestionsProvider::FetchStatusCallback());
-  std::move(snippets_callback)
-      .Run(Status(StatusCode::SUCCESS, "message"),
-           std::move(fetched_categories));
-
+  FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
+                        Status(StatusCode::SUCCESS, "message"),
+                        std::move(fetched_categories));
   // Dismiss them.
   for (int i = 0; i < kSuggestionsCount; ++i) {
     provider->DismissSuggestion(
@@ -2199,16 +2523,9 @@
         base::StringPrintf("http://abc.com/%d/", i)));
   }
 
-  // Fetch the suggestions.
-  RemoteSuggestionsFetcher::SnippetsAvailableCallback snippets_callback;
-  EXPECT_CALL(*mock_fetcher, FetchSnippets(_, _))
-      .WillOnce(MoveSecondArgumentPointeeTo(&snippets_callback))
-      .RetiresOnSaturation();
-  FetchSuggestions(provider.get(), /*interactive_request=*/true,
-                   RemoteSuggestionsProvider::FetchStatusCallback());
-  std::move(snippets_callback)
-      .Run(Status(StatusCode::SUCCESS, "message"),
-           std::move(fetched_categories));
+  FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
+                        Status(StatusCode::SUCCESS, "message"),
+                        std::move(fetched_categories));
 
   // Dismiss them in reverse order.
   std::string first_dismissed_suggestion_id;
@@ -2269,16 +2586,9 @@
         base::StringPrintf("http://other.com/%d/", i)));
   }
 
-  // Fetch the suggestions.
-  RemoteSuggestionsFetcher::SnippetsAvailableCallback snippets_callback;
-  EXPECT_CALL(*mock_fetcher, FetchSnippets(_, _))
-      .WillOnce(MoveSecondArgumentPointeeTo(&snippets_callback))
-      .RetiresOnSaturation();
-  FetchSuggestions(provider.get(), /*interactive_request=*/true,
-                   RemoteSuggestionsProvider::FetchStatusCallback());
-  std::move(snippets_callback)
-      .Run(Status(StatusCode::SUCCESS, "message"),
-           std::move(fetched_categories));
+  FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
+                        Status(StatusCode::SUCCESS, "message"),
+                        std::move(fetched_categories));
 
   // Dismiss all suggestions.
   std::set<std::string> expected_excluded_ids;
@@ -2336,16 +2646,9 @@
   fetched_categories[1].suggestions.push_back(
       CreateTestRemoteSuggestion("http://other.com/"));
 
-  // Fetch the suggestions.
-  RemoteSuggestionsFetcher::SnippetsAvailableCallback snippets_callback;
-  EXPECT_CALL(*mock_fetcher, FetchSnippets(_, _))
-      .WillOnce(MoveSecondArgumentPointeeTo(&snippets_callback))
-      .RetiresOnSaturation();
-  FetchSuggestions(provider.get(), /*interactive_request=*/true,
-                   RemoteSuggestionsProvider::FetchStatusCallback());
-  std::move(snippets_callback)
-      .Run(Status(StatusCode::SUCCESS, "message"),
-           std::move(fetched_categories));
+  FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
+                        Status(StatusCode::SUCCESS, "message"),
+                        std::move(fetched_categories));
 
   // Dismiss article suggestions first.
   for (int i = 0; i < kMaxExcludedDismissedIds; ++i) {
diff --git a/components/offline_pages/core/background/request_queue_store_sql.cc b/components/offline_pages/core/background/request_queue_store_sql.cc
index 87dc3bf..406d3d7 100644
--- a/components/offline_pages/core/background/request_queue_store_sql.cc
+++ b/components/offline_pages/core/background/request_queue_store_sql.cc
@@ -44,7 +44,8 @@
                       " url VARCHAR NOT NULL,"
                       " client_namespace VARCHAR NOT NULL,"
                       " client_id VARCHAR NOT NULL,"
-                      " original_url VARCHAR NOT NULL DEFAULT ''"
+                      " original_url VARCHAR NOT NULL DEFAULT '',"
+                      " request_origin VARCHAR NOT NULL DEFAULT ''"
                       ")";
   return db->Execute(kSql);
 }
@@ -75,6 +76,20 @@
   return UpgradeWithQuery(db, kSql);
 }
 
+bool UpgradeFrom58(sql::Connection* db) {
+  const char kSql[] =
+      "INSERT INTO " REQUEST_QUEUE_TABLE_NAME
+      " (request_id, creation_time, activation_time, last_attempt_time, "
+      "started_attempt_count, completed_attempt_count, state, url, "
+      "client_namespace, client_id, original_url) "
+      "SELECT "
+      "request_id, creation_time, activation_time, last_attempt_time, "
+      "started_attempt_count, completed_attempt_count, state, url, "
+      "client_namespace, client_id, original_url "
+      "FROM temp_" REQUEST_QUEUE_TABLE_NAME;
+  return UpgradeWithQuery(db, kSql);
+}
+
 bool CreateSchema(sql::Connection* db) {
   sql::Transaction transaction(db);
   if (!transaction.Begin())
@@ -85,7 +100,7 @@
       return false;
   }
 
-  // If there is not already a state column, we need to drop the old table.  We
+  // If there is not already a state column, we need to drop the old table. We
   // are choosing to drop instead of upgrade since the feature is not yet
   // released, so we don't try to migrate it.
   if (!db->DoesColumnExist(REQUEST_QUEUE_TABLE_NAME, "state")) {
@@ -96,6 +111,9 @@
   if (!db->DoesColumnExist(REQUEST_QUEUE_TABLE_NAME, "original_url")) {
     if (!UpgradeFrom57(db))
       return false;
+  } else if (!db->DoesColumnExist(REQUEST_QUEUE_TABLE_NAME, "request_origin")) {
+    if (!UpgradeFrom58(db))
+      return false;
   }
 
   // This would be a great place to add indices when we need them.
@@ -120,11 +138,13 @@
   const ClientId client_id(statement.ColumnString(8),
                            statement.ColumnString(9));
   const GURL original_url(statement.ColumnString(10));
+  const std::string request_origin(statement.ColumnString(11));
 
   DVLOG(2) << "making save page request - id " << id << " url " << url
            << " client_id " << client_id.name_space << "-" << client_id.id
            << " creation time " << creation_time << " user requested "
-           << kUserRequested << " original_url " << original_url;
+           << kUserRequested << " original_url " << original_url
+           << " request_origin " << request_origin;
 
   std::unique_ptr<SavePageRequest> request(
       new SavePageRequest(id, url, client_id, creation_time, kUserRequested));
@@ -133,6 +153,7 @@
   request->set_completed_attempt_count(completed_attempt_count);
   request->set_request_state(state);
   request->set_original_url(original_url);
+  request->set_request_origin(request_origin);
   return request;
 }
 
@@ -142,7 +163,7 @@
   const char kSql[] =
       "SELECT request_id, creation_time, activation_time,"
       " last_attempt_time, started_attempt_count, completed_attempt_count,"
-      " state, url, client_namespace, client_id, original_url"
+      " state, url, client_namespace, client_id, original_url, request_origin"
       " FROM " REQUEST_QUEUE_TABLE_NAME " WHERE request_id=?";
 
   sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
@@ -170,9 +191,10 @@
       "INSERT OR IGNORE INTO " REQUEST_QUEUE_TABLE_NAME
       " (request_id, creation_time, activation_time,"
       " last_attempt_time, started_attempt_count, completed_attempt_count,"
-      " state, url, client_namespace, client_id, original_url)"
+      " state, url, client_namespace, client_id, original_url, "
+      "request_origin)"
       " VALUES "
-      " (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
+      " (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
 
   sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
   statement.BindInt64(0, request.request_id());
@@ -186,6 +208,7 @@
   statement.BindString(8, request.client_id().name_space);
   statement.BindString(9, request.client_id().id);
   statement.BindString(10, request.original_url().spec());
+  statement.BindString(11, request.request_origin());
 
   if (!statement.Run())
     return ItemActionStatus::STORE_ERROR;
@@ -199,7 +222,8 @@
       "UPDATE OR IGNORE " REQUEST_QUEUE_TABLE_NAME
       " SET creation_time = ?, activation_time = ?, last_attempt_time = ?,"
       " started_attempt_count = ?, completed_attempt_count = ?, state = ?,"
-      " url = ?, client_namespace = ?, client_id = ?, original_url = ?"
+      " url = ?, client_namespace = ?, client_id = ?, original_url = ?,"
+      "request_origin = ?"
       " WHERE request_id = ?";
 
   sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
@@ -213,7 +237,8 @@
   statement.BindString(7, request.client_id().name_space);
   statement.BindString(8, request.client_id().id);
   statement.BindString(9, request.original_url().spec());
-  statement.BindInt64(10, request.request_id());
+  statement.BindString(10, request.request_origin());
+  statement.BindInt64(11, request.request_id());
 
   if (!statement.Run())
     return ItemActionStatus::STORE_ERROR;
@@ -276,7 +301,7 @@
   const char kSql[] =
       "SELECT request_id, creation_time, activation_time,"
       " last_attempt_time, started_attempt_count, completed_attempt_count,"
-      " state, url, client_namespace, client_id, original_url"
+      " state, url, client_namespace, client_id, original_url, request_origin"
       " FROM " REQUEST_QUEUE_TABLE_NAME;
 
   sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
diff --git a/components/offline_pages/core/background/request_queue_store_unittest.cc b/components/offline_pages/core/background/request_queue_store_unittest.cc
index 9b0009fd..385bc78d 100644
--- a/components/offline_pages/core/background/request_queue_store_unittest.cc
+++ b/components/offline_pages/core/background/request_queue_store_unittest.cc
@@ -34,6 +34,7 @@
 const ClientId kClientId("bookmark", "1234");
 const ClientId kClientId2("async", "5678");
 const bool kUserRequested = true;
+const std::string kRequestOrigin = "abc.xyz";
 
 enum class LastResult {
   RESULT_NONE,
@@ -86,6 +87,53 @@
       connection.DoesColumnExist(REQUEST_QUEUE_TABLE_NAME, "original_url"));
 }
 
+void BuildTestStoreWithSchemaFromM58(const base::FilePath& file) {
+  sql::Connection connection;
+  ASSERT_TRUE(
+      connection.Open(file.Append(FILE_PATH_LITERAL("RequestQueue.db"))));
+  ASSERT_TRUE(connection.is_open());
+  ASSERT_TRUE(connection.BeginTransaction());
+  ASSERT_TRUE(
+      connection.Execute("CREATE TABLE " REQUEST_QUEUE_TABLE_NAME
+                         " (request_id INTEGER PRIMARY KEY NOT NULL,"
+                         " creation_time INTEGER NOT NULL,"
+                         " activation_time INTEGER NOT NULL DEFAULT 0,"
+                         " last_attempt_time INTEGER NOT NULL DEFAULT 0,"
+                         " started_attempt_count INTEGER NOT NULL,"
+                         " completed_attempt_count INTEGER NOT NULL,"
+                         " state INTEGER NOT NULL DEFAULT 0,"
+                         " url VARCHAR NOT NULL,"
+                         " client_namespace VARCHAR NOT NULL,"
+                         " client_id VARCHAR NOT NULL,"
+                         " original_url VARCHAR NOT NULL"
+                         ")"));
+
+  ASSERT_TRUE(connection.CommitTransaction());
+  sql::Statement statement(connection.GetUniqueStatement(
+      "INSERT OR IGNORE INTO " REQUEST_QUEUE_TABLE_NAME
+      " (request_id, creation_time, activation_time,"
+      " last_attempt_time, started_attempt_count, completed_attempt_count,"
+      " state, url, client_namespace, client_id, original_url)"
+      " VALUES "
+      " (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"));
+
+  statement.BindInt64(0, kRequestId);
+  statement.BindInt64(1, 0);
+  statement.BindInt64(2, 0);
+  statement.BindInt64(3, 0);
+  statement.BindInt64(4, 0);
+  statement.BindInt64(5, 0);
+  statement.BindInt64(6, 0);
+  statement.BindString(7, kUrl.spec());
+  statement.BindString(8, kClientId.name_space);
+  statement.BindString(9, kClientId.id);
+  statement.BindString(10, kUrl2.spec());
+  ASSERT_TRUE(statement.Run());
+  ASSERT_TRUE(connection.DoesTableExist(REQUEST_QUEUE_TABLE_NAME));
+  ASSERT_FALSE(
+      connection.DoesColumnExist(REQUEST_QUEUE_TABLE_NAME, "request_origin"));
+}
+
 }  // namespace
 
 // Class that serves as a base for testing different implementations of the
@@ -233,8 +281,11 @@
 
   RequestQueueStore* BuildStoreWithOldSchema(const base::FilePath& path,
                                              int version) override {
-    EXPECT_EQ(57, version);
-    BuildTestStoreWithSchemaFromM57(path);
+    if (version == 57) {
+      BuildTestStoreWithSchemaFromM57(path);
+    } else if (version == 58) {
+      BuildTestStoreWithSchemaFromM58(path);
+    }
 
     RequestQueueStore* store =
         new RequestQueueStoreSQL(base::ThreadTaskRunnerHandle::Get(), path);
@@ -295,6 +346,24 @@
   EXPECT_EQ(GURL(), this->last_requests()[0]->original_url());
 }
 
+TYPED_TEST(RequestQueueStoreTest, UpgradeFromVersion58Store) {
+  std::unique_ptr<RequestQueueStore> store(this->BuildStoreWithOldSchema(58));
+  // In-memory store does not support upgrading.
+  if (!store)
+    return;
+  this->InitializeStore(store.get());
+
+  store->GetRequests(base::Bind(&RequestQueueStoreTestBase::GetRequestsDone,
+                                base::Unretained(this)));
+  this->PumpLoop();
+  ASSERT_EQ(LastResult::RESULT_TRUE, this->last_result());
+  ASSERT_EQ(1u, this->last_requests().size());
+  EXPECT_EQ(kRequestId, this->last_requests()[0]->request_id());
+  EXPECT_EQ(kUrl, this->last_requests()[0]->url());
+  EXPECT_EQ(kUrl2, this->last_requests()[0]->original_url());
+  EXPECT_EQ("", this->last_requests()[0]->request_origin());
+}
+
 TYPED_TEST(RequestQueueStoreTest, GetRequestsEmpty) {
   std::unique_ptr<RequestQueueStore> store(this->BuildStore());
   this->InitializeStore(store.get());
@@ -432,6 +501,7 @@
   SavePageRequest updated_request(kRequestId, kUrl, kClientId,
                                   new_creation_time, kUserRequested);
   updated_request.set_original_url(kUrl2);
+  updated_request.set_request_origin(kRequestOrigin);
   // Try to update a non-existing request.
   SavePageRequest updated_request2(kRequestId2, kUrl, kClientId,
                                    new_creation_time, kUserRequested);
diff --git a/components/offline_pages/core/prefetch/BUILD.gn b/components/offline_pages/core/prefetch/BUILD.gn
index b45caac..ec22924 100644
--- a/components/offline_pages/core/prefetch/BUILD.gn
+++ b/components/offline_pages/core/prefetch/BUILD.gn
@@ -93,6 +93,7 @@
     "//components/gcm_driver/instance_id",
     "//components/keyed_service/core",
     "//components/offline_pages/core",
+    "//components/prefs:test_support",
     "//components/version_info:channel",
     "//net:test_support",
   ]
diff --git a/components/offline_pages/core/prefetch/prefetch_service_test_taco.cc b/components/offline_pages/core/prefetch/prefetch_service_test_taco.cc
index d18c8b9..e74c98a 100644
--- a/components/offline_pages/core/prefetch/prefetch_service_test_taco.cc
+++ b/components/offline_pages/core/prefetch/prefetch_service_test_taco.cc
@@ -26,8 +26,8 @@
 }  // namespace
 
 PrefetchServiceTestTaco::PrefetchServiceTestTaco() {
-  metrics_collector_ = base::MakeUnique<TestOfflineMetricsCollector>();
   dispatcher_ = base::MakeUnique<TestPrefetchDispatcher>();
+  metrics_collector_ = base::MakeUnique<TestOfflineMetricsCollector>(nullptr);
   gcm_handler_ = base::MakeUnique<TestPrefetchGCMHandler>();
   network_request_factory_ =
       base::MakeUnique<TestPrefetchNetworkRequestFactory>();
diff --git a/components/offline_pages/core/prefetch/test_offline_metrics_collector.h b/components/offline_pages/core/prefetch/test_offline_metrics_collector.h
index f3c679333c..14d68bc 100644
--- a/components/offline_pages/core/prefetch/test_offline_metrics_collector.h
+++ b/components/offline_pages/core/prefetch/test_offline_metrics_collector.h
@@ -7,12 +7,14 @@
 
 #include "components/offline_pages/core/prefetch/offline_metrics_collector.h"
 
+class PrefService;
+
 namespace offline_pages {
 
 // Testing metrics collector that does nothing.
 class TestOfflineMetricsCollector : public OfflineMetricsCollector {
  public:
-  TestOfflineMetricsCollector() = default;
+  explicit TestOfflineMetricsCollector(PrefService*) {}
   ~TestOfflineMetricsCollector() override = default;
 
   void OnAppStartupOrResume() override {}
diff --git a/components/omnibox/browser/autocomplete_match.cc b/components/omnibox/browser/autocomplete_match.cc
index dd0eaf0..5837c8d0 100644
--- a/components/omnibox/browser/autocomplete_match.cc
+++ b/components/omnibox/browser/autocomplete_match.cc
@@ -24,7 +24,6 @@
 #include "components/omnibox/browser/suggestion_answer.h"
 #include "components/search_engines/template_url.h"
 #include "components/search_engines/template_url_service.h"
-#include "components/url_formatter/url_formatter.h"
 #include "ui/gfx/vector_icon_types.h"
 
 #if !defined(OS_ANDROID) && !defined(OS_IOS)
@@ -489,66 +488,16 @@
 }
 
 // static
-base::string16 AutocompleteMatch::FormatUrlForSuggestionDisplay(
-    const GURL& url,
-    bool trim_scheme,
-    size_t* offset_for_adjustment) {
-  std::vector<size_t> offsets;
-  if (offset_for_adjustment)
-    offsets.push_back(*offset_for_adjustment);
-  base::string16 result =
-      FormatUrlForSuggestionDisplayWithOffsets(url, trim_scheme, &offsets);
-  if (offset_for_adjustment)
-    *offset_for_adjustment = offsets[0];
-  return result;
-}
-
-// static
-base::string16 AutocompleteMatch::FormatUrlForSuggestionDisplayWithOffsets(
-    const GURL& url,
-    bool trim_scheme,
-    std::vector<size_t>* offsets_for_adjustment) {
-  base::OffsetAdjuster::Adjustments adjustments;
-  const base::string16& format_url_return_value =
-      FormatUrlForSuggestionDisplayWithAdjustments(url, trim_scheme,
-                                                   &adjustments);
-  base::OffsetAdjuster::AdjustOffsets(adjustments, offsets_for_adjustment);
-  if (offsets_for_adjustment) {
-    std::for_each(
-        offsets_for_adjustment->begin(), offsets_for_adjustment->end(),
-        base::LimitOffset<std::string>(format_url_return_value.length()));
+url_formatter::FormatUrlTypes AutocompleteMatch::GetFormatTypes(
+    bool trim_scheme) {
+  auto format_types = url_formatter::kFormatUrlOmitAll;
+  if (!trim_scheme) {
+    format_types &= ~url_formatter::kFormatUrlOmitHTTP;
+  } else if (base::FeatureList::IsEnabled(
+                 omnibox::kUIExperimentHideSuggestionUrlScheme)) {
+    format_types |= url_formatter::kFormatUrlExperimentalOmitHTTPS;
   }
-  return format_url_return_value;
-}
-
-// static
-base::string16 AutocompleteMatch::FormatUrlForSuggestionDisplayWithAdjustments(
-    const GURL& url,
-    bool trim_scheme,
-    base::OffsetAdjuster::Adjustments* adjustments) {
-  const url_formatter::FormatUrlTypes format_types =
-      url_formatter::kFormatUrlOmitAll &
-      ~(trim_scheme ? 0 : url_formatter::kFormatUrlOmitHTTP);
-  base::string16 result = url_formatter::FormatUrlWithAdjustments(
-      url, format_types, net::UnescapeRule::SPACES, nullptr, nullptr,
-      adjustments);
-
-  // Also trim HTTPS if experiment is enabled. Note this intentionally has
-  // no effect on view-source URLs.
-  if (trim_scheme && base::FeatureList::IsEnabled(
-                         omnibox::kUIExperimentHideSuggestionUrlScheme)) {
-    // TODO(tommycli): If this becomes enabled by default, investigate
-    // folding this logic into url_formatter::FormatUrlWithAdjustments.
-    if (url.SchemeIs(url::kHttpsScheme)) {
-      const size_t kHTTPSSize =
-          strlen(url::kHttpsScheme) + strlen(url::kStandardSchemeSeparator);
-      result = result.substr(kHTTPSSize);
-      adjustments->insert(adjustments->begin(),
-                          base::OffsetAdjuster::Adjustment(0, kHTTPSSize, 0));
-    }
-  }
-
-  return result;
+  return format_types;
 }
 
 void AutocompleteMatch::ComputeStrippedDestinationURL(
diff --git a/components/omnibox/browser/autocomplete_match.h b/components/omnibox/browser/autocomplete_match.h
index b8659cd..ffbd5c72 100644
--- a/components/omnibox/browser/autocomplete_match.h
+++ b/components/omnibox/browser/autocomplete_match.h
@@ -16,6 +16,7 @@
 #include "components/omnibox/browser/autocomplete_input.h"
 #include "components/omnibox/browser/autocomplete_match_type.h"
 #include "components/search_engines/template_url.h"
+#include "components/url_formatter/url_formatter.h"
 #include "ui/base/page_transition_types.h"
 #include "url/gurl.h"
 
@@ -208,23 +209,10 @@
                                  TemplateURLService* template_url_service,
                                  const base::string16& keyword);
 
-  // These are convenience functions for formatting a URL into an abridged form
-  // for display within the Omnibox suggestions dropdown.
-  //
-  // The results are explicitly for non-security surfaces. Do not use the
-  // results for anything other than the Omnibox dropdown.
-  static base::string16 FormatUrlForSuggestionDisplay(
-      const GURL& url,
-      bool trim_scheme,
-      size_t* offset_for_adjustment);
-  static base::string16 FormatUrlForSuggestionDisplayWithOffsets(
-      const GURL& url,
-      bool trim_scheme,
-      std::vector<size_t>* offsets_for_adjustment);
-  static base::string16 FormatUrlForSuggestionDisplayWithAdjustments(
-      const GURL& url,
-      bool trim_scheme,
-      base::OffsetAdjuster::Adjustments* adjustments);
+  // Gets the formatting flags used for display of suggestions. This method
+  // encapsulates the return of experimental flags too, so any URLs displayed
+  // as an Omnibox suggestion should use this method.
+  static url_formatter::FormatUrlTypes GetFormatTypes(bool trim_scheme);
 
   // Computes the stripped destination URL (via GURLToStrippedGURL()) and
   // stores the result in |stripped_destination_url|.  |input| is used for the
diff --git a/components/omnibox/browser/autocomplete_match_unittest.cc b/components/omnibox/browser/autocomplete_match_unittest.cc
index dc0eb464..e6627425 100644
--- a/components/omnibox/browser/autocomplete_match_unittest.cc
+++ b/components/omnibox/browser/autocomplete_match_unittest.cc
@@ -115,55 +115,44 @@
   struct FormatUrlTestData {
     const std::string url;
     bool trim_scheme;
-    size_t offset_for_adjustment;
     const std::string expected_result;
-    size_t expected_adjusted_offset;
 
     void Validate() {
       SCOPED_TRACE(testing::Message()
                    << " url= " << url << " trim_scheme=" << trim_scheme
-                   << " offset_for_adjustment=" << offset_for_adjustment
-                   << " expected_result=" << expected_result
-                   << " expected_adjusted_offset=" << expected_adjusted_offset);
-
-      size_t offset_result = offset_for_adjustment;
-      base::string16 result = AutocompleteMatch::FormatUrlForSuggestionDisplay(
-          GURL(url), trim_scheme, &offset_result);
-
-      EXPECT_EQ(expected_result, base::UTF16ToASCII(result));
-      EXPECT_EQ(expected_adjusted_offset, offset_result);
+                   << " expected_result=" << expected_result);
+      auto format_types = AutocompleteMatch::GetFormatTypes(trim_scheme);
+      EXPECT_EQ(expected_result,
+                base::UTF16ToASCII(url_formatter::FormatUrl(
+                    GURL(url), format_types, net::UnescapeRule::SPACES, nullptr,
+                    nullptr, nullptr)));
     };
   };
 
+  // Sanity check that the trim_strings parameter works.
   FormatUrlTestData normal_cases[] = {
-      {"http://google.com", true, 9, "google.com", 2},
-      {"https://google.com", true, 9, "https://google.com", 9},
-      {"http://google.com", false, 9, "http://google.com", 9},
-      {"https://google.com", false, 9, "https://google.com", 9},
+      {"http://google.com", true, "google.com"},
+      {"https://google.com", true, "https://google.com"},
+      {"http://google.com", false, "http://google.com"},
+      {"https://google.com", false, "https://google.com"},
   };
-  for (size_t i = 0; i < arraysize(normal_cases); ++i) {
-    normal_cases[i].Validate();
-  }
+  for (FormatUrlTestData& test_case : normal_cases)
+    test_case.Validate();
 
+  // Test the hide-scheme feature flag.
   std::unique_ptr<base::test::ScopedFeatureList> feature_list(
       new base::test::ScopedFeatureList);
   feature_list->InitAndEnableFeature(
       omnibox::kUIExperimentHideSuggestionUrlScheme);
 
   FormatUrlTestData omit_scheme_cases[] = {
-      {"http://google.com", true, 9, "google.com", 2},
-      {"https://google.com", true, 9, "google.com", 1},
-      {"https://username:password@google.com", true, 9, "google.com",
-       base::string16::npos},
-      {"https://username:password@google.com", true, 29, "google.com", 3},
-      {"http://google.com", false, 9, "http://google.com", 9},
-      {"https://google.com", false, 9, "https://google.com", 9},
-      {"http://username:password@google.com", false, 9, "http://google.com",
-       base::string16::npos},
+      {"http://google.com", true, "google.com"},
+      {"https://google.com", true, "google.com"},
+      {"http://google.com", false, "http://google.com"},
+      {"https://google.com", false, "https://google.com"},
   };
-  for (size_t i = 0; i < arraysize(omit_scheme_cases); ++i) {
-    omit_scheme_cases[i].Validate();
-  }
+  for (FormatUrlTestData& test_case : omit_scheme_cases)
+    test_case.Validate();
 }
 
 TEST(AutocompleteMatchTest, SupportsDeletion) {
diff --git a/components/omnibox/browser/clipboard_url_provider.cc b/components/omnibox/browser/clipboard_url_provider.cc
index b3729328..5c3b079 100644
--- a/components/omnibox/browser/clipboard_url_provider.cc
+++ b/components/omnibox/browser/clipboard_url_provider.cc
@@ -86,8 +86,9 @@
   // Add the clipboard match. The relevance is 800 to beat ZeroSuggest results.
   AutocompleteMatch match(this, 800, false, AutocompleteMatchType::CLIPBOARD);
   match.destination_url = url;
-  match.contents.assign(AutocompleteMatch::FormatUrlForSuggestionDisplay(
-      url, true /* trim_scheme */, nullptr));
+  auto format_types = AutocompleteMatch::GetFormatTypes(true);
+  match.contents.assign(url_formatter::FormatUrl(
+      url, format_types, net::UnescapeRule::SPACES, nullptr, nullptr, nullptr));
   AutocompleteMatch::ClassifyLocationInString(
       base::string16::npos, 0, match.contents.length(),
       ACMatchClassification::URL, &match.contents_class);
diff --git a/components/omnibox/browser/history_quick_provider.cc b/components/omnibox/browser/history_quick_provider.cc
index f8b9a76..2768387e 100644
--- a/components/omnibox/browser/history_quick_provider.cc
+++ b/components/omnibox/browser/history_quick_provider.cc
@@ -201,9 +201,11 @@
       false, base::UTF8ToUTF16(info.url().spec()));
 
   base::OffsetAdjuster::Adjustments adjustments;
-  match.contents =
-      AutocompleteMatch::FormatUrlForSuggestionDisplayWithAdjustments(
-          info.url(), !history_match.match_in_scheme, &adjustments);
+  auto format_types =
+      AutocompleteMatch::GetFormatTypes(!history_match.match_in_scheme);
+  match.contents = url_formatter::FormatUrlWithAdjustments(
+      info.url(), format_types, net::UnescapeRule::SPACES, nullptr, nullptr,
+      &adjustments);
   match.fill_into_edit =
       AutocompleteInput::FormattedStringWithEquivalentMeaning(
           info.url(), match.contents, client()->GetSchemeClassifier());
diff --git a/components/omnibox/browser/history_url_provider.cc b/components/omnibox/browser/history_url_provider.cc
index d9f6b7e..2691564d 100644
--- a/components/omnibox/browser/history_url_provider.cc
+++ b/components/omnibox/browser/history_url_provider.cc
@@ -571,9 +571,10 @@
     // Trim off "http://" if the user didn't type it.
     DCHECK(!trim_http ||
            !AutocompleteInput::HasHTTPScheme(input.text()));
-    base::string16 display_string(
-        AutocompleteMatch::FormatUrlForSuggestionDisplay(
-            destination_url, false /* trim_scheme */, nullptr));
+    auto format_types = AutocompleteMatch::GetFormatTypes(false);
+    base::string16 display_string(url_formatter::FormatUrl(
+        destination_url, format_types, net::UnescapeRule::SPACES, nullptr,
+        nullptr, nullptr));
     const size_t offset = trim_http ? TrimHttpPrefix(&display_string) : 0;
     match.fill_into_edit =
         AutocompleteInput::FormattedStringWithEquivalentMeaning(
@@ -1141,15 +1142,16 @@
   DCHECK(match.destination_url.is_valid());
   size_t inline_autocomplete_offset =
       history_match.input_location + params.input.text().length();
-  const url_formatter::FormatUrlTypes format_types =
-      url_formatter::kFormatUrlOmitAll &
-      ~((params.trim_http && !history_match.match_in_scheme)
-            ? 0
-            : url_formatter::kFormatUrlOmitHTTP);
+
+  auto format_types = AutocompleteMatch::GetFormatTypes(
+      params.trim_http && !history_match.match_in_scheme);
+  // Never omit HTTPS from fill_into_edit lest it be misinterpreted.
+  auto fill_into_edit_format_types =
+      format_types & ~url_formatter::kFormatUrlExperimentalOmitHTTPS;
   match.fill_into_edit =
       AutocompleteInput::FormattedStringWithEquivalentMeaning(
           info.url(),
-          url_formatter::FormatUrl(info.url(), format_types,
+          url_formatter::FormatUrl(info.url(), fill_into_edit_format_types,
                                    net::UnescapeRule::SPACES, nullptr, nullptr,
                                    &inline_autocomplete_offset),
           client()->GetSchemeClassifier());
@@ -1173,9 +1175,9 @@
        (inline_autocomplete_offset >= match.fill_into_edit.length()));
 
   size_t match_start = history_match.input_location;
-  match.contents = AutocompleteMatch::FormatUrlForSuggestionDisplay(
-      info.url(), params.trim_http && !history_match.match_in_scheme,
-      &match_start);
+  match.contents = url_formatter::FormatUrl(info.url(), format_types,
+                                            net::UnescapeRule::SPACES, nullptr,
+                                            nullptr, &match_start);
   if ((match_start != base::string16::npos) && autocomplete_offset_valid &&
       (inline_autocomplete_offset != match_start)) {
     DCHECK(inline_autocomplete_offset > match_start);
diff --git a/components/omnibox/browser/titled_url_match_utils.cc b/components/omnibox/browser/titled_url_match_utils.cc
index 8c60630..e585081 100644
--- a/components/omnibox/browser/titled_url_match_utils.cc
+++ b/components/omnibox/browser/titled_url_match_utils.cc
@@ -85,8 +85,9 @@
   // |offsets|, compute how everything is transformed, then remove it from the
   // end.
   offsets.push_back(inline_autocomplete_offset);
-  match.contents = AutocompleteMatch::FormatUrlForSuggestionDisplayWithOffsets(
-      url, trim_http, &offsets);
+  auto format_types = AutocompleteMatch::GetFormatTypes(trim_http);
+  match.contents = url_formatter::FormatUrlWithOffsets(
+      url, format_types, net::UnescapeRule::SPACES, nullptr, nullptr, &offsets);
   inline_autocomplete_offset = offsets.back();
   offsets.pop_back();
   TitledUrlMatch::MatchPositions new_url_match_positions =
diff --git a/components/omnibox/browser/zero_suggest_provider.cc b/components/omnibox/browser/zero_suggest_provider.cc
index 11fe0a0e..45e7d86 100644
--- a/components/omnibox/browser/zero_suggest_provider.cc
+++ b/components/omnibox/browser/zero_suggest_provider.cc
@@ -375,8 +375,10 @@
   match.destination_url = navigation.url();
 
   // Zero suggest results should always omit protocols and never appear bold.
-  match.contents = AutocompleteMatch::FormatUrlForSuggestionDisplay(
-      navigation.url(), true /* trim_scheme */, nullptr);
+  auto format_types = AutocompleteMatch::GetFormatTypes(true);
+  match.contents = url_formatter::FormatUrl(navigation.url(), format_types,
+                                            net::UnescapeRule::SPACES, nullptr,
+                                            nullptr, nullptr);
   match.fill_into_edit +=
       AutocompleteInput::FormattedStringWithEquivalentMeaning(
           navigation.url(), match.contents, client()->GetSchemeClassifier());
diff --git a/components/payments/core/journey_logger.cc b/components/payments/core/journey_logger.cc
index e98bcec3..c2170ac 100644
--- a/components/payments/core/journey_logger.cc
+++ b/components/payments/core/journey_logger.cc
@@ -113,8 +113,11 @@
 }
 
 void JourneyLogger::SetAborted(AbortReason reason) {
-  base::UmaHistogramEnumeration("PaymentRequest.CheckoutFunnel.Aborted", reason,
-                                ABORT_REASON_MAX);
+  // Don't log abort reasons if the Payment Request was not shown to the user.
+  if (was_show_called_) {
+    base::UmaHistogramEnumeration("PaymentRequest.CheckoutFunnel.Aborted",
+                                  reason, ABORT_REASON_MAX);
+  }
 
   if (reason == ABORT_REASON_ABORTED_BY_USER ||
       reason == ABORT_REASON_USER_NAVIGATION)
@@ -198,6 +201,11 @@
 }
 
 void JourneyLogger::RecordRequestedInformationMetrics() {
+  if (!was_show_called_) {
+    return;
+  }
+
+  DCHECK(requested_information_ != REQUESTED_INFORMATION_MAX);
   UMA_HISTOGRAM_ENUMERATION("PaymentRequest.RequestedInformation",
                             requested_information_, REQUESTED_INFORMATION_MAX);
 }
diff --git a/components/payments/core/journey_logger_unittest.cc b/components/payments/core/journey_logger_unittest.cc
index 941fccb..26211be 100644
--- a/components/payments/core/journey_logger_unittest.cc
+++ b/components/payments/core/journey_logger_unittest.cc
@@ -54,6 +54,7 @@
   // The merchant does not query CanMakePayment, show the PaymentRequest and the
   // user aborts it.
   logger.SetShowCalled();
+  logger.SetRequestedInformation(true, false, false, false);
   logger.SetAborted(JourneyLogger::ABORT_REASON_ABORTED_BY_USER);
 
   histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
@@ -83,6 +84,7 @@
   // The merchant does not query CanMakePayment, show the PaymentRequest and
   // there is an abort not initiated by the user.
   logger.SetShowCalled();
+  logger.SetRequestedInformation(true, false, false, false);
   logger.SetAborted(JourneyLogger::ABORT_REASON_OTHER);
 
   histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
@@ -112,6 +114,7 @@
   // The merchant does not query CanMakePayment, show the PaymentRequest and the
   // user completes it.
   logger.SetShowCalled();
+  logger.SetRequestedInformation(true, false, false, false);
   logger.SetCompleted();
 
   histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
@@ -207,6 +210,7 @@
 
   // The user cannot make payment and the PaymentRequest is not shown.
   logger.SetShowCalled();
+  logger.SetRequestedInformation(true, false, false, false);
   logger.SetCanMakePaymentValue(false);
   logger.SetAborted(JourneyLogger::ABORT_REASON_ABORTED_BY_USER);
 
@@ -240,6 +244,7 @@
 
   // The user cannot make payment and the PaymentRequest is not shown.
   logger.SetShowCalled();
+  logger.SetRequestedInformation(true, false, false, false);
   logger.SetCanMakePaymentValue(false);
   logger.SetAborted(JourneyLogger::ABORT_REASON_OTHER);
 
@@ -273,6 +278,7 @@
 
   // The user cannot make payment and the PaymentRequest is not shown.
   logger.SetShowCalled();
+  logger.SetRequestedInformation(true, false, false, false);
   logger.SetCanMakePaymentValue(false);
   logger.SetCompleted();
 
@@ -307,6 +313,7 @@
 
   // The user cannot make payment and the PaymentRequest is not shown.
   logger.SetShowCalled();
+  logger.SetRequestedInformation(true, false, false, false);
   logger.SetCanMakePaymentValue(true);
   logger.SetAborted(JourneyLogger::ABORT_REASON_ABORTED_BY_USER);
 
@@ -342,6 +349,7 @@
 
   // The user cannot make payment and the PaymentRequest is not shown.
   logger.SetShowCalled();
+  logger.SetRequestedInformation(true, false, false, false);
   logger.SetCanMakePaymentValue(true);
   logger.SetAborted(JourneyLogger::ABORT_REASON_OTHER);
 
@@ -377,6 +385,7 @@
 
   // The user cannot make payment and the PaymentRequest is not shown.
   logger.SetShowCalled();
+  logger.SetRequestedInformation(true, false, false, false);
   logger.SetCanMakePaymentValue(true);
   logger.SetCompleted();
 
@@ -412,6 +421,7 @@
 
   // The user cannot make payment and the PaymentRequest is not shown.
   logger.SetShowCalled();
+  logger.SetRequestedInformation(true, false, false, false);
   logger.SetCanMakePaymentValue(true);
   logger.SetCompleted();
 
@@ -630,7 +640,9 @@
 
   // Make the two loggers have different data.
   logger1.SetShowCalled();
+  logger1.SetRequestedInformation(true, true, false, false);
   logger2.SetShowCalled();
+  logger2.SetRequestedInformation(true, false, false, false);
 
   logger1.SetCanMakePaymentValue(true);
 
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index 233cd9b..452bfb5 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -8178,9 +8178,8 @@
     {
       'name': 'ForceBrowserSignin',
       'type': 'main',
-      'future': True,
       'schema': { 'type': 'boolean' },
-      'supported_on': ['chrome.*:55-', 'android:57-'],
+      'supported_on': ['chrome.win:61-', 'chrome.linux:61-', 'android:63-'],
       'features': {
         'dynamic_refresh': False,
         'per_profile': False,
diff --git a/components/printing/browser/print_manager.cc b/components/printing/browser/print_manager.cc
index 1094a260..6dbe709 100644
--- a/components/printing/browser/print_manager.cc
+++ b/components/printing/browser/print_manager.cc
@@ -50,20 +50,20 @@
     return;
   }
 #if defined(OS_ANDROID)
-  PdfWritingDone(false);
+  PdfWritingDone(0);
 #endif
 }
 
 void PrintManager::PrintingRenderFrameDeleted() {
 #if defined(OS_ANDROID)
-  PdfWritingDone(false);
+  PdfWritingDone(0);
 #endif
 }
 
 #if defined(OS_ANDROID)
-void PrintManager::PdfWritingDone(bool result) {
+void PrintManager::PdfWritingDone(int page_count) {
   if (!pdf_writing_done_callback_.is_null())
-    pdf_writing_done_callback_.Run(file_descriptor().fd, result);
+    pdf_writing_done_callback_.Run(file_descriptor().fd, page_count);
   // Invalidate the file descriptor so it doesn't get reused.
   file_descriptor_ = base::FileDescriptor(-1, false);
 }
diff --git a/components/printing/browser/print_manager.h b/components/printing/browser/print_manager.h
index 8fdba95..1635d368 100644
--- a/components/printing/browser/print_manager.h
+++ b/components/printing/browser/print_manager.h
@@ -22,9 +22,9 @@
 
 #if defined(OS_ANDROID)
   // TODO(timvolodine): consider introducing PrintManagerAndroid (crbug/500960)
-  typedef base::Callback<void(int, bool)> PdfWritingDoneCallback;
+  using PdfWritingDoneCallback = base::Callback<void(int, int)>;
 
-  void PdfWritingDone(bool result);
+  void PdfWritingDone(int page_count);
 
   // Sets the file descriptor into which the PDF will be written.
   void set_file_descriptor(const base::FileDescriptor& file_descriptor) {
diff --git a/components/printing/common/print_messages.h b/components/printing/common/print_messages.h
index 32b0451..fd39591 100644
--- a/components/printing/common/print_messages.h
+++ b/components/printing/common/print_messages.h
@@ -398,9 +398,10 @@
                             int /* render_frame_id */,
                             base::FileDescriptor /* temp file fd */,
                             int /* fd in browser*/)
-IPC_MESSAGE_CONTROL2(PrintHostMsg_TempFileForPrintingWritten,
+IPC_MESSAGE_CONTROL3(PrintHostMsg_TempFileForPrintingWritten,
                      int /* render_frame_id */,
-                     int /* fd in browser */)
+                     int /* fd in browser */,
+                     int /* page count */)
 #endif  // defined(OS_ANDROID)
 
 #if BUILDFLAG(ENABLE_PRINT_PREVIEW)
diff --git a/components/printing/renderer/print_web_view_helper_linux.cc b/components/printing/renderer/print_web_view_helper_linux.cc
index 910c471..024ff6a 100644
--- a/components/printing/renderer/print_web_view_helper_linux.cc
+++ b/components/printing/renderer/print_web_view_helper_linux.cc
@@ -76,8 +76,8 @@
     return false;
 
   // Tell the browser we've finished writing the file.
-  Send(new PrintHostMsg_TempFileForPrintingWritten(routing_id(),
-                                                   sequence_number));
+  Send(new PrintHostMsg_TempFileForPrintingWritten(
+      routing_id(), sequence_number, printed_pages.size()));
   return true;
 #else
   PrintHostMsg_DidPrintPage_Params printed_page_params;
diff --git a/components/proximity_auth/proximity_auth_system.cc b/components/proximity_auth/proximity_auth_system.cc
index 1129cba3..86af9753 100644
--- a/components/proximity_auth/proximity_auth_system.cc
+++ b/components/proximity_auth/proximity_auth_system.cc
@@ -4,12 +4,14 @@
 
 #include "components/proximity_auth/proximity_auth_system.h"
 
+#include "base/command_line.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/default_clock.h"
 #include "components/proximity_auth/logging/logging.h"
 #include "components/proximity_auth/proximity_auth_client.h"
 #include "components/proximity_auth/proximity_auth_pref_manager.h"
 #include "components/proximity_auth/remote_device_life_cycle_impl.h"
+#include "components/proximity_auth/switches.h"
 #include "components/proximity_auth/unlock_manager_impl.h"
 
 namespace proximity_auth {
@@ -191,6 +193,10 @@
 }
 
 bool ProximityAuthSystem::ShouldForcePassword() {
+  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+          proximity_auth::switches::kEnableForcePasswordReauth))
+    return false;
+
   // TODO(tengs): We need to properly propagate the last login time to the login
   // screen.
   if (screenlock_type_ == ScreenlockType::SIGN_IN)
diff --git a/components/proximity_auth/proximity_auth_system_unittest.cc b/components/proximity_auth/proximity_auth_system_unittest.cc
index 1bd8c716..2b57e76 100644
--- a/components/proximity_auth/proximity_auth_system_unittest.cc
+++ b/components/proximity_auth/proximity_auth_system_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "components/proximity_auth/proximity_auth_system.h"
 
+#include "base/command_line.h"
 #include "base/test/simple_test_clock.h"
 #include "base/test/test_simple_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
@@ -13,6 +14,7 @@
 #include "components/proximity_auth/logging/logging.h"
 #include "components/proximity_auth/mock_proximity_auth_client.h"
 #include "components/proximity_auth/proximity_auth_pref_manager.h"
+#include "components/proximity_auth/switches.h"
 #include "components/proximity_auth/unlock_manager.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -427,6 +429,8 @@
 }
 
 TEST_F(ProximityAuthSystemTest, ForcePasswordReauth) {
+  base::CommandLine::ForCurrentProcess()->AppendSwitch(
+      proximity_auth::switches::kEnableForcePasswordReauth);
   ON_CALL(*pref_manager_, GetLastPasswordEntryTimestampMs())
       .WillByDefault(Return(kTimestampAfterReauthMs));
   EXPECT_CALL(proximity_auth_client_,
diff --git a/components/proximity_auth/switches.cc b/components/proximity_auth/switches.cc
index abc1e93..69f739a 100644
--- a/components/proximity_auth/switches.cc
+++ b/components/proximity_auth/switches.cc
@@ -15,6 +15,10 @@
 extern const char kEnableChromeOSLogin[] =
     "enable-proximity-auth-chromeos-login";
 
+// Enables forcing the user to reauth with their password after X hours (e.g.
+// 20) without password entry.
+const char kEnableForcePasswordReauth[] = "force-password-reauth";
+
 // Enables close proximity detection. This allows the user to set a setting to
 // require very close proximity between the remote device and the local device
 // in order to unlock the local device, which trades off convenience for
diff --git a/components/proximity_auth/switches.h b/components/proximity_auth/switches.h
index f29b42d19..60c9264 100644
--- a/components/proximity_auth/switches.h
+++ b/components/proximity_auth/switches.h
@@ -10,6 +10,7 @@
 
 extern const char kEnableBluetoothLowEnergyDiscovery[];
 extern const char kEnableChromeOSLogin[];
+extern const char kEnableForcePasswordReauth[];
 extern const char kEnableProximityDetection[];
 extern const char kForceLoadEasyUnlockAppInTests[];
 
diff --git a/components/proximity_auth/webui/proximity_auth_webui_handler.cc b/components/proximity_auth/webui/proximity_auth_webui_handler.cc
index a2fccec..ec4fcc1 100644
--- a/components/proximity_auth/webui/proximity_auth_webui_handler.cc
+++ b/components/proximity_auth/webui/proximity_auth_webui_handler.cc
@@ -539,14 +539,15 @@
   // the corresponding local device data (e.g. connection status and remote
   // status updates).
   std::string public_key = device_info.public_key();
+  std::vector<cryptauth::ExternalDeviceInfo> unlock_keys =
+      device_manager->GetUnlockKeys();
   auto iterator = std::find_if(
-      device_manager->GetUnlockKeys().begin(),
-      device_manager->GetUnlockKeys().end(),
+      unlock_keys.begin(), unlock_keys.end(),
       [&public_key](const cryptauth::ExternalDeviceInfo& unlock_key) {
         return unlock_key.public_key() == public_key;
       });
 
-  if (iterator == device_manager->GetUnlockKeys().end() ||
+  if (iterator == unlock_keys.end() ||
       selected_remote_device_.public_key != device_info.public_key())
     return dictionary;
 
diff --git a/components/safe_browsing/triggers/trigger_manager.cc b/components/safe_browsing/triggers/trigger_manager.cc
index a8bccd7..6899ff15 100644
--- a/components/safe_browsing/triggers/trigger_manager.cc
+++ b/components/safe_browsing/triggers/trigger_manager.cc
@@ -36,6 +36,9 @@
 
 }  // namespace
 
+DataCollectorsContainer::DataCollectorsContainer() {}
+DataCollectorsContainer::~DataCollectorsContainer() {}
+
 TriggerManager::TriggerManager(BaseUIManager* ui_manager)
     : ui_manager_(ui_manager) {}
 
@@ -56,6 +59,7 @@
 }
 
 bool TriggerManager::StartCollectingThreatDetails(
+    const SafeBrowsingTriggerType trigger_type,
     content::WebContents* web_contents,
     const security_interstitials::UnsafeResource& resource,
     net::URLRequestContextGetter* request_context_getter,
@@ -67,16 +71,21 @@
     return false;
 
   // Ensure we're not already collecting data on this tab.
+  // TODO(lpz): this check should be more specific to check that this type of
+  // data collector is not running on this tab (once additional data collectors
+  // exist).
   if (base::ContainsKey(data_collectors_map_, web_contents))
     return false;
 
-  data_collectors_map_[web_contents] = scoped_refptr<ThreatDetails>(
+  DataCollectorsContainer* collectors = &data_collectors_map_[web_contents];
+  collectors->threat_details = scoped_refptr<ThreatDetails>(
       ThreatDetails::NewThreatDetails(ui_manager_, web_contents, resource,
                                       request_context_getter, history_service));
   return true;
 }
 
 bool TriggerManager::FinishCollectingThreatDetails(
+    const SafeBrowsingTriggerType trigger_type,
     content::WebContents* web_contents,
     const base::TimeDelta& delay,
     bool did_proceed,
@@ -85,19 +94,22 @@
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   // Make sure there's a data collector running on this tab.
+  // TODO(lpz): this check should be more specific to check that the right type
+  // of data collector is running on this tab (once additional data collectors
+  // exist).
   if (!base::ContainsKey(data_collectors_map_, web_contents))
     return false;
 
   // Determine whether a report should be sent.
   bool should_send_report = CanSendReport(error_display_options);
 
+  DataCollectorsContainer* collectors = &data_collectors_map_[web_contents];
   // Find the data collector and tell it to finish collecting data, and then
   // remove it from our map. We release ownership of the data collector here but
   // it will live until the end of the FinishCollection call because it
   // implements RefCountedThreadSafe.
   if (should_send_report) {
-    scoped_refptr<ThreatDetails> threat_details =
-        data_collectors_map_[web_contents];
+    scoped_refptr<ThreatDetails> threat_details = collectors->threat_details;
     content::BrowserThread::PostDelayedTask(
         content::BrowserThread::IO, FROM_HERE,
         base::BindOnce(&ThreatDetails::FinishCollection, threat_details,
@@ -107,6 +119,7 @@
 
   // Regardless of whether the report got sent, clean up the data collector on
   // this tab.
+  collectors->threat_details = nullptr;
   data_collectors_map_.erase(web_contents);
 
   return should_send_report;
diff --git a/components/safe_browsing/triggers/trigger_manager.h b/components/safe_browsing/triggers/trigger_manager.h
index 9176d56..f78ce60 100644
--- a/components/safe_browsing/triggers/trigger_manager.h
+++ b/components/safe_browsing/triggers/trigger_manager.h
@@ -28,12 +28,31 @@
 class BaseUIManager;
 class ThreatDetails;
 
+enum class SafeBrowsingTriggerType {
+  SECURITY_INTERSTITIAL,
+};
+
+// A wrapper around different kinds of data collectors that can be active on a
+// given browser tab. Any given field can be null or empty if the associated
+// data is not being collected.
+struct DataCollectorsContainer {
+ public:
+  DataCollectorsContainer();
+  ~DataCollectorsContainer();
+
+  // Note: new data collection types should be added below as additional fields.
+
+  // Collects ThreatDetails which contains resource URLs and partial DOM.
+  scoped_refptr<ThreatDetails> threat_details;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DataCollectorsContainer);
+};
+
 // Stores the data collectors that are active on each WebContents (ie: browser
 // tab).
-// TODO(lpz): This will be a multi-level map in the future so different
-// collectors can be active on the same tab.
 using DataCollectorsMap =
-    std::unordered_map<content::WebContents*, scoped_refptr<ThreatDetails>>;
+    std::unordered_map<content::WebContents*, DataCollectorsContainer>;
 
 using SBErrorOptions =
     security_interstitials::BaseSafeBrowsingErrorUI::SBErrorDisplayOptions;
@@ -67,6 +86,7 @@
   // should be created by TriggerManager::GetSBErrorDisplayOptions().
   // Returns true if the collection began, or false if it didn't.
   bool StartCollectingThreatDetails(
+      const SafeBrowsingTriggerType trigger_type,
       content::WebContents* web_contents,
       const security_interstitials::UnsafeResource& resource,
       net::URLRequestContextGetter* request_context_getter,
@@ -84,6 +104,7 @@
   // Returns true if the report was completed and sent, or false otherwise (eg:
   // the user was not opted-in to extended reporting after collection began).
   bool FinishCollectingThreatDetails(
+      const SafeBrowsingTriggerType trigger_type,
       content::WebContents* web_contents,
       const base::TimeDelta& delay,
       bool did_proceed,
diff --git a/components/safe_browsing/triggers/trigger_manager_unittest.cc b/components/safe_browsing/triggers/trigger_manager_unittest.cc
index 76f81cb6..7261abdab 100644
--- a/components/safe_browsing/triggers/trigger_manager_unittest.cc
+++ b/components/safe_browsing/triggers/trigger_manager_unittest.cc
@@ -82,21 +82,23 @@
     SBErrorOptions options =
         TriggerManager::GetSBErrorDisplayOptions(pref_service_, *web_contents);
     return trigger_manager_.StartCollectingThreatDetails(
-        web_contents, security_interstitials::UnsafeResource(), nullptr,
-        nullptr, options);
+        SafeBrowsingTriggerType::SECURITY_INTERSTITIAL, web_contents,
+        security_interstitials::UnsafeResource(), nullptr, nullptr, options);
   }
 
   bool FinishCollectingThreatDetails(content::WebContents* web_contents,
                                      bool expect_report_sent) {
     if (expect_report_sent) {
       MockThreatDetails* threat_details = static_cast<MockThreatDetails*>(
-          trigger_manager_.data_collectors_map_[web_contents].get());
+          trigger_manager_.data_collectors_map_[web_contents]
+              .threat_details.get());
       EXPECT_CALL(*threat_details, FinishCollection(_, _)).Times(1);
     }
     SBErrorOptions options =
         TriggerManager::GetSBErrorDisplayOptions(pref_service_, *web_contents);
     return trigger_manager_.FinishCollectingThreatDetails(
-        web_contents, base::TimeDelta(), false, 0, options);
+        SafeBrowsingTriggerType::SECURITY_INTERSTITIAL, web_contents,
+        base::TimeDelta(), false, 0, options);
   }
 
   const DataCollectorsMap& data_collectors_map() {
diff --git a/components/search_engines/prepopulated_engines.json b/components/search_engines/prepopulated_engines.json
index da820086..02999b5 100644
--- a/components/search_engines/prepopulated_engines.json
+++ b/components/search_engines/prepopulated_engines.json
@@ -592,6 +592,7 @@
       "name": "\u042f\u043d\u0434\u0435\u043a\u0441",
       "keyword": "yandex.by",
       "favicon_url": "https://yastatic.net/lego/_/pDu9OWAQKB0s2J9IojKpiS_Eho.ico",
+      "logo_url": "https://storage.ape.yandex.net/get/browser/Doodles/yandex/drawable-xxhdpi/yandex.png",
       "search_url": "https://yandex.by/{yandex:searchPath}?text={searchTerms}",
       "suggest_url": "https://suggest.yandex.by/suggest-ff.cgi?part={searchTerms}",
       "image_url": "https://yandex.by/images/search/?rpt=imageview",
@@ -605,6 +606,7 @@
       "name": "\u042f\u043d\u0434\u0435\u043a\u0441",
       "keyword": "yandex.kz",
       "favicon_url": "https://yastatic.net/lego/_/pDu9OWAQKB0s2J9IojKpiS_Eho.ico",
+      "logo_url": "https://storage.ape.yandex.net/get/browser/Doodles/yandex/drawable-xxhdpi/yandex.png",
       "search_url": "https://yandex.kz/{yandex:searchPath}?text={searchTerms}",
       "suggest_url": "https://suggest.yandex.kz/suggest-ff.cgi?part={searchTerms}",
       "image_url": "https://yandex.kz/images/search/?rpt=imageview",
@@ -618,6 +620,7 @@
       "name": "\u042f\u043d\u0434\u0435\u043a\u0441",
       "keyword": "yandex.ru",
       "favicon_url": "https://yastatic.net/lego/_/pDu9OWAQKB0s2J9IojKpiS_Eho.ico",
+      "logo_url": "https://storage.ape.yandex.net/get/browser/Doodles/yandex/drawable-xxhdpi/yandex.png",
       "search_url": "https://yandex.ru/{yandex:searchPath}?text={searchTerms}&{yandex:referralID}",
       "suggest_url": "https://suggest.yandex.ru/suggest-ff.cgi?part={searchTerms}",
       "image_url": "https://yandex.ru/images/search/?rpt=imageview",
@@ -644,6 +647,7 @@
       "name": "\u042f\u043d\u0434\u0435\u043a\u0441",
       "keyword": "yandex.ua",
       "favicon_url": "https://yastatic.net/lego/_/pDu9OWAQKB0s2J9IojKpiS_Eho.ico",
+      "logo_url": "https://storage.ape.yandex.net/get/browser/Doodles/yandex/drawable-xxhdpi/yandex.png",
       "search_url": "https://yandex.ua/{yandex:searchPath}?text={searchTerms}",
       "suggest_url": "https://suggest.yandex.ua/suggest-ff.cgi?part={searchTerms}",
       "image_url": "https://yandex.ua/images/search/?rpt=imageview",
diff --git a/components/supervised_user_error_page/supervised_user_error_page.cc b/components/supervised_user_error_page/supervised_user_error_page.cc
index 7baabc9..6763db5a 100644
--- a/components/supervised_user_error_page/supervised_user_error_page.cc
+++ b/components/supervised_user_error_page/supervised_user_error_page.cc
@@ -39,14 +39,7 @@
 
 int GetBlockMessageID(FilteringBehaviorReason reason,
                       bool is_child_account,
-                      bool is_deprecated,
                       bool single_parent) {
-  if (is_deprecated) {
-    // The deprecation message is specific to Supervised Users.
-    DCHECK(!is_child_account);
-    return IDS_BLOCK_INTERSTITIAL_MESSAGE_SUPERVISED_USERS_DEPRECATED;
-  }
-
   switch (reason) {
     case DEFAULT:
       if (!is_child_account)
@@ -121,14 +114,18 @@
   } else {
     block_header = l10n_util::GetStringUTF16(
         IDS_BLOCK_INTERSTITIAL_HEADER_ACCESS_REQUESTS_DISABLED);
-    // If access requests are disabled, there is no block message.
+
+    if (is_deprecated) {
+      DCHECK(!is_child_account);
+      block_message = l10n_util::GetStringUTF16(
+          IDS_BLOCK_INTERSTITIAL_MESSAGE_SUPERVISED_USERS_DEPRECATED);
+    }
   }
   strings.SetString("blockPageHeader", block_header);
   strings.SetString("blockPageMessage", block_message);
-  strings.SetString(
-      "blockReasonMessage",
-      l10n_util::GetStringUTF16(GetBlockMessageID(
-          reason, is_child_account, is_deprecated, second_custodian.empty())));
+  strings.SetString("blockReasonMessage",
+                    l10n_util::GetStringUTF16(GetBlockMessageID(
+                        reason, is_child_account, second_custodian.empty())));
   strings.SetString("blockReasonHeader", l10n_util::GetStringUTF16(
                                              IDS_SUPERVISED_USER_BLOCK_HEADER));
   bool show_feedback = ReasonIsAutomatic(reason);
diff --git a/components/supervised_user_error_page/supervised_user_error_page.h b/components/supervised_user_error_page/supervised_user_error_page.h
index 4bb6708..0950ada42 100644
--- a/components/supervised_user_error_page/supervised_user_error_page.h
+++ b/components/supervised_user_error_page/supervised_user_error_page.h
@@ -23,7 +23,6 @@
 int GetBlockMessageID(
     supervised_user_error_page::FilteringBehaviorReason reason,
     bool is_child_account,
-    bool is_deprecated,
     bool single_parent);
 
 std::string BuildHtml(bool allow_access_requests,
diff --git a/components/supervised_user_error_page/supervised_user_error_page_unittest.cc b/components/supervised_user_error_page/supervised_user_error_page_unittest.cc
index b2f432d0..873c850 100644
--- a/components/supervised_user_error_page/supervised_user_error_page_unittest.cc
+++ b/components/supervised_user_error_page/supervised_user_error_page_unittest.cc
@@ -18,7 +18,6 @@
 struct BlockMessageIDTestParameter {
   FilteringBehaviorReason reason;
   bool is_child_account;
-  bool is_deprecated;
   bool single_parent;
   int expected_result;
 };
@@ -30,36 +29,24 @@
   BlockMessageIDTestParameter param = GetParam();
   EXPECT_EQ(param.expected_result,
             GetBlockMessageID(param.reason, param.is_child_account,
-                              param.is_deprecated, param.single_parent))
+                              param.single_parent))
       << "reason = " << param.reason
       << " is_child_account = " << param.is_child_account
       << " single parent = " << param.single_parent;
 }
 
 BlockMessageIDTestParameter block_message_id_test_params[] = {
-    {DEFAULT, false, false, false, IDS_SUPERVISED_USER_BLOCK_MESSAGE_DEFAULT},
-    {DEFAULT, false, false, true, IDS_SUPERVISED_USER_BLOCK_MESSAGE_DEFAULT},
-    {DEFAULT, false, true, false,
-     IDS_BLOCK_INTERSTITIAL_MESSAGE_SUPERVISED_USERS_DEPRECATED},
-    {DEFAULT, false, true, true,
-     IDS_BLOCK_INTERSTITIAL_MESSAGE_SUPERVISED_USERS_DEPRECATED},
-    {DEFAULT, true, false, true, IDS_CHILD_BLOCK_MESSAGE_DEFAULT_SINGLE_PARENT},
-    {DEFAULT, true, false, false, IDS_CHILD_BLOCK_MESSAGE_DEFAULT_MULTI_PARENT},
+    {DEFAULT, false, false, IDS_SUPERVISED_USER_BLOCK_MESSAGE_DEFAULT},
+    {DEFAULT, false, true, IDS_SUPERVISED_USER_BLOCK_MESSAGE_DEFAULT},
+    {DEFAULT, true, true, IDS_CHILD_BLOCK_MESSAGE_DEFAULT_SINGLE_PARENT},
+    {DEFAULT, true, false, IDS_CHILD_BLOCK_MESSAGE_DEFAULT_MULTI_PARENT},
     // SafeSites is not enabled for supervised users.
-    {ASYNC_CHECKER, true, false, true,
-     IDS_SUPERVISED_USER_BLOCK_MESSAGE_SAFE_SITES},
-    {ASYNC_CHECKER, true, false, false,
-     IDS_SUPERVISED_USER_BLOCK_MESSAGE_SAFE_SITES},
-    {MANUAL, false, false, false, IDS_SUPERVISED_USER_BLOCK_MESSAGE_MANUAL},
-    {MANUAL, false, false, true, IDS_SUPERVISED_USER_BLOCK_MESSAGE_MANUAL},
-    {MANUAL, false, true, false,
-     IDS_BLOCK_INTERSTITIAL_MESSAGE_SUPERVISED_USERS_DEPRECATED},
-    {MANUAL, false, true, true,
-     IDS_BLOCK_INTERSTITIAL_MESSAGE_SUPERVISED_USERS_DEPRECATED},
-    {MANUAL, true, false, true, IDS_CHILD_BLOCK_MESSAGE_MANUAL_SINGLE_PARENT},
-    {MANUAL, true, false, false, IDS_CHILD_BLOCK_MESSAGE_MANUAL_MULTI_PARENT},
-    // |is_child_account| and |is_deprecated| are mutually exclusive, so skip
-    // test cases where both are true.
+    {ASYNC_CHECKER, true, true, IDS_SUPERVISED_USER_BLOCK_MESSAGE_SAFE_SITES},
+    {ASYNC_CHECKER, true, false, IDS_SUPERVISED_USER_BLOCK_MESSAGE_SAFE_SITES},
+    {MANUAL, false, false, IDS_SUPERVISED_USER_BLOCK_MESSAGE_MANUAL},
+    {MANUAL, false, true, IDS_SUPERVISED_USER_BLOCK_MESSAGE_MANUAL},
+    {MANUAL, true, true, IDS_CHILD_BLOCK_MESSAGE_MANUAL_SINGLE_PARENT},
+    {MANUAL, true, false, IDS_CHILD_BLOCK_MESSAGE_MANUAL_MULTI_PARENT},
 };
 
 INSTANTIATE_TEST_CASE_P(GetBlockMessageIDParameterized,
@@ -206,6 +193,8 @@
      "custodian2_email", true, false, DEFAULT, true},
     {false, "url1", "url2", "custodian", "custodian_email", "custodian2",
      "custodian2_email", true, false, DEFAULT, true},
+    {false, "url1", "url2", "custodian", "custodian_email", "custodian2",
+     "custodian2_email", false, true, DEFAULT, true},
     {true, "url1", "url2", "custodian", "custodian_email", "custodian2",
      "custodian2_email", false, false, DEFAULT, true},
     {true, "url1", "url2", "custodian", "custodian_email", "custodian2",
diff --git a/components/supervised_user_error_page_strings.grdp b/components/supervised_user_error_page_strings.grdp
index d8d589a4..e8c4362 100644
--- a/components/supervised_user_error_page_strings.grdp
+++ b/components/supervised_user_error_page_strings.grdp
@@ -19,6 +19,9 @@
       <message name="IDS_CHILD_BLOCK_INTERSTITIAL_MESSAGE" desc="A message for the child user when they attempt to visit a site that is not permitted by their parent.">
         Looks like you need permission to visit this site
       </message>
+      <message name="IDS_BLOCK_INTERSTITIAL_MESSAGE_SUPERVISED_USERS_DEPRECATED" desc="Message to be shown to a supervised user directing them to the supervisor.">
+        Questions? Contact the person who supervises your profile.
+      </message>
       <message name="IDS_BACK_BUTTON" desc="A button for going back to the last safe url after being blocked.">
         Go back
       </message>
@@ -79,8 +82,5 @@
       <message name="IDS_SUPERVISED_USER_NOT_SIGNED_IN" desc="Message to be shown to a supervised user who is not signed in to Chrome">
         Please start and sign in to Chrome so that Chrome can check whether you are allowed to access this site.
       </message>
-      <message name="IDS_BLOCK_INTERSTITIAL_MESSAGE_SUPERVISED_USERS_DEPRECATED" desc="Message to be shown to a supervised user to inform them that the feature is deprecated.">
-        Supervised users are deprecated. Restrictions remain in place and cannot be changed by the custodian after September 30, 2017.
-      </message>
 
 </grit-part>
diff --git a/components/sync/test/fake_server/fake_server.cc b/components/sync/test/fake_server/fake_server.cc
index de1cb20..8eb3dcc 100644
--- a/components/sync/test/fake_server/fake_server.cc
+++ b/components/sync/test/fake_server/fake_server.cc
@@ -370,20 +370,19 @@
   }
 
   std::unique_ptr<FakeServerEntity> entity;
+  syncer::ModelType type = GetModelType(client_entity);
   if (client_entity.deleted()) {
     entity = TombstoneEntity::Create(client_entity.id_string(),
                                      client_entity.client_defined_unique_tag());
     DeleteChildren(client_entity.id_string());
-  } else if (GetModelType(client_entity) == syncer::NIGORI) {
+  } else if (type == syncer::NIGORI) {
     // NIGORI is the only permanent item type that should be updated by the
     // client.
     EntityMap::const_iterator iter = entities_.find(client_entity.id_string());
     CHECK(iter != entities_.end());
     entity = PermanentEntity::CreateUpdatedNigoriEntity(client_entity,
                                                         *iter->second);
-  } else if (client_entity.has_client_defined_unique_tag()) {
-    entity = UniqueClientEntity::Create(client_entity);
-  } else {
+  } else if (type == syncer::BOOKMARKS) {
     // TODO(pvalenzuela): Validate entity's parent ID.
     EntityMap::const_iterator iter = entities_.find(client_entity.id_string());
     if (iter != entities_.end()) {
@@ -392,12 +391,8 @@
     } else {
       entity = BookmarkEntity::CreateNew(client_entity, parent_id, client_guid);
     }
-  }
-
-  if (!entity) {
-    // TODO(pvalenzuela): Add logging so that it is easier to determine why
-    // creation failed.
-    return string();
+  } else {
+    entity = UniqueClientEntity::Create(client_entity);
   }
 
   const std::string id = entity->id();
diff --git a/components/sync/test/fake_server/unique_client_entity.cc b/components/sync/test/fake_server/unique_client_entity.cc
index 346a2ae..b090d64 100644
--- a/components/sync/test/fake_server/unique_client_entity.cc
+++ b/components/sync/test/fake_server/unique_client_entity.cc
@@ -5,6 +5,8 @@
 #include "components/sync/test/fake_server/unique_client_entity.h"
 
 #include "base/guid.h"
+#include "base/rand_util.h"
+#include "base/strings/string_number_conversions.h"
 #include "components/sync/base/hash_util.h"
 #include "components/sync/protocol/sync.pb.h"
 #include "components/sync/test/fake_server/permanent_entity.h"
@@ -51,15 +53,23 @@
 // static
 std::unique_ptr<FakeServerEntity> UniqueClientEntity::Create(
     const sync_pb::SyncEntity& client_entity) {
-  CHECK(client_entity.has_client_defined_unique_tag())
-      << "A UniqueClientEntity must have a client-defined unique tag.";
   ModelType model_type =
       syncer::GetModelTypeFromSpecifics(client_entity.specifics());
-  string id = EffectiveIdForClientTaggedEntity(client_entity);
+  CHECK_NE(client_entity.has_client_defined_unique_tag(),
+           syncer::CommitOnlyTypes().Has(model_type))
+      << "A UniqueClientEntity should have a client-defined unique tag iff it "
+         "is not a CommitOnly type.";
+  // Without model type specific logic for each CommitOnly type, we cannot infer
+  // a reasonable tag from the specifics. We need uniqueness for how the server
+  // holds onto all objects, so simply make a new tag from a random  number.
+  string effective_tag = client_entity.has_client_defined_unique_tag()
+                             ? client_entity.client_defined_unique_tag()
+                             : base::Uint64ToString(base::RandUint64());
+  string id = FakeServerEntity::CreateId(model_type, effective_tag);
   return std::unique_ptr<FakeServerEntity>(new UniqueClientEntity(
-      id, client_entity.client_defined_unique_tag(), model_type,
-      client_entity.version(), client_entity.name(), client_entity.specifics(),
-      client_entity.ctime(), client_entity.mtime()));
+      id, effective_tag, model_type, client_entity.version(),
+      client_entity.name(), client_entity.specifics(), client_entity.ctime(),
+      client_entity.mtime()));
 }
 
 // static
@@ -74,14 +84,6 @@
       entity_specifics, kDefaultTime, kDefaultTime));
 }
 
-// static
-std::string UniqueClientEntity::EffectiveIdForClientTaggedEntity(
-    const sync_pb::SyncEntity& entity) {
-  return FakeServerEntity::CreateId(
-      syncer::GetModelTypeFromSpecifics(entity.specifics()),
-      entity.client_defined_unique_tag());
-}
-
 bool UniqueClientEntity::RequiresParentId() const {
   return false;
 }
diff --git a/components/sync/test/fake_server/unique_client_entity.h b/components/sync/test/fake_server/unique_client_entity.h
index 5fe819d..c9c4245 100644
--- a/components/sync/test/fake_server/unique_client_entity.h
+++ b/components/sync/test/fake_server/unique_client_entity.h
@@ -48,10 +48,6 @@
       const std::string& name,
       const sync_pb::EntitySpecifics& entity_specifics);
 
-  // Derives an ID from a unique client tagged entity.
-  static std::string EffectiveIdForClientTaggedEntity(
-      const sync_pb::SyncEntity& entity);
-
   // FakeServerEntity implementation.
   bool RequiresParentId() const override;
   std::string GetParentId() const override;
diff --git a/components/toolbar/BUILD.gn b/components/toolbar/BUILD.gn
index 0f1cc9f0..9416363 100644
--- a/components/toolbar/BUILD.gn
+++ b/components/toolbar/BUILD.gn
@@ -2,9 +2,16 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/buildflag_header.gni")
 import("//build/config/ui.gni")
+import("//device/vr/features/features.gni")
 import("//ui/vector_icons/vector_icons.gni")
 
+buildflag_header("build_features") {
+  header = "features.h"
+  flags = [ "ENABLE_VR=$enable_vr" ]
+}
+
 aggregate_vector_icons("toolbar_vector_icons") {
   icon_directory = "vector_icons"
 
@@ -36,6 +43,7 @@
 
 static_library("toolbar") {
   sources = [
+    "features.h",
     "toolbar_model.h",
     "toolbar_model_delegate.h",
     "toolbar_model_impl.cc",
@@ -49,6 +57,7 @@
   ]
 
   deps = [
+    ":build_features",
     "//components/google/core/browser",
     "//components/prefs",
     "//components/resources",
@@ -59,7 +68,7 @@
     "//ui/gfx",
   ]
 
-  if (!is_android && !is_ios) {
+  if ((!is_android || enable_vr) && !is_ios) {
     deps += [ ":vector_icons" ]
   }
 }
diff --git a/components/toolbar/toolbar_model_impl.cc b/components/toolbar/toolbar_model_impl.cc
index fee722b..6111f92c 100644
--- a/components/toolbar/toolbar_model_impl.cc
+++ b/components/toolbar/toolbar_model_impl.cc
@@ -11,6 +11,7 @@
 #include "components/prefs/pref_service.h"
 #include "components/security_state/core/security_state.h"
 #include "components/strings/grit/components_strings.h"
+#include "components/toolbar/features.h"
 #include "components/toolbar/toolbar_model_delegate.h"
 #include "components/url_formatter/elide_url.h"
 #include "components/url_formatter/url_formatter.h"
@@ -21,7 +22,7 @@
 #include "ui/gfx/text_elider.h"
 #include "ui/gfx/vector_icon_types.h"
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if (!defined(OS_ANDROID) || BUILDFLAG(ENABLE_VR)) && !defined(OS_IOS)
 #include "components/toolbar/vector_icons.h"  // nogncheck
 #include "ui/vector_icons/vector_icons.h"     // nogncheck
 #endif
@@ -73,7 +74,7 @@
 }
 
 const gfx::VectorIcon& ToolbarModelImpl::GetVectorIcon() const {
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if (!defined(OS_ANDROID) || BUILDFLAG(ENABLE_VR)) && !defined(OS_IOS)
   auto* const icon_override = delegate_->GetVectorIconOverride();
   if (icon_override)
     return *icon_override;
diff --git a/components/update_client/background_downloader_win.cc b/components/update_client/background_downloader_win.cc
index a04923bb..0abf44a 100644
--- a/components/update_client/background_downloader_win.cc
+++ b/components/update_client/background_downloader_win.cc
@@ -255,9 +255,13 @@
   return S_OK;
 }
 
-HRESULT GetJobDescription(IBackgroundCopyJob* job, const base::string16* name) {
+HRESULT GetJobDescription(IBackgroundCopyJob* job, base::string16* name) {
   ScopedCoMem<base::char16> description;
-  return job->GetDescription(&description);
+  const HRESULT hr = job->GetDescription(&description);
+  if (FAILED(hr))
+    return hr;
+  *name = description.get();
+  return S_OK;
 }
 
 // Returns the job error code in |error_code| if the job is in the transient
diff --git a/components/url_formatter/url_formatter.cc b/components/url_formatter/url_formatter.cc
index 154cbf7..9364828 100644
--- a/components/url_formatter/url_formatter.cc
+++ b/components/url_formatter/url_formatter.cc
@@ -361,6 +361,7 @@
     kFormatUrlOmitUsernamePassword | kFormatUrlOmitHTTP |
     kFormatUrlOmitTrailingSlashOnBareHostname;
 const FormatUrlType kFormatUrlExperimentalElideAfterHost = 1 << 3;
+const FormatUrlType kFormatUrlExperimentalOmitHTTPS = 1 << 4;
 
 base::string16 FormatUrl(const GURL& url,
                          FormatUrlTypes format_types,
@@ -432,22 +433,10 @@
   const url::Parsed& parsed = url.parsed_for_possibly_invalid_spec();
 
   // Scheme & separators.  These are ASCII.
+  const size_t scheme_size = static_cast<size_t>(parsed.CountCharactersBefore(
+      url::Parsed::USERNAME, true /* include_delimiter */));
   base::string16 url_string;
-  url_string.insert(
-      url_string.end(), spec.begin(),
-      spec.begin() + parsed.CountCharactersBefore(url::Parsed::USERNAME, true));
-  const char kHTTP[] = "http://";
-  const char kFTP[] = "ftp.";
-  // url_formatter::FixupURL() treats "ftp.foo.com" as ftp://ftp.foo.com.  This
-  // means that if we trim "http://" off a URL whose host starts with "ftp." and
-  // the user inputs this into any field subject to fixup (which is basically
-  // all input fields), the meaning would be changed.  (In fact, often the
-  // formatted URL is directly pre-filled into an input field.)  For this reason
-  // we avoid stripping "http://" in this case.
-  bool omit_http =
-      (format_types & kFormatUrlOmitHTTP) &&
-      base::EqualsASCII(url_string, kHTTP) &&
-      !base::StartsWith(url.host(), kFTP, base::CompareCase::SENSITIVE);
+  url_string.insert(url_string.end(), spec.begin(), spec.begin() + scheme_size);
   new_parsed->scheme = parsed.scheme;
 
   // Username & password.
@@ -558,20 +547,32 @@
                              &url_string, &new_parsed->ref, adjustments);
   }
 
-  // If we need to strip out http do it after the fact.
-  if (omit_http && base::StartsWith(url_string, base::ASCIIToUTF16(kHTTP),
-                                    base::CompareCase::SENSITIVE)) {
-    const size_t kHTTPSize = arraysize(kHTTP) - 1;
-    url_string = url_string.substr(kHTTPSize);
+  // url_formatter::FixupURL() treats "ftp.foo.com" as ftp://ftp.foo.com.  This
+  // means that if we trim the scheme off a URL whose host starts with "ftp."
+  // and the user inputs this into any field subject to fixup (which is
+  // basically all input fields), the meaning would be changed.  (In fact, often
+  // the formatted URL is directly pre-filled into an input field.)  For this
+  // reason we avoid stripping schemes in this case.
+  const char kFTP[] = "ftp.";
+  bool strip_scheme =
+      !base::StartsWith(url.host(), kFTP, base::CompareCase::SENSITIVE) &&
+      (((format_types & kFormatUrlOmitHTTP) &&
+        url.SchemeIs(url::kHttpScheme)) ||
+       ((format_types & kFormatUrlExperimentalOmitHTTPS) &&
+        url.SchemeIs(url::kHttpsScheme)));
+
+  // If we need to strip out schemes do it after the fact.
+  if (strip_scheme) {
+    url_string.erase(0, scheme_size);
     // Because offsets in the |adjustments| are already calculated with respect
     // to the string with the http:// prefix in it, those offsets remain correct
     // after stripping the prefix.  The only thing necessary is to add an
     // adjustment to reflect the stripped prefix.
     adjustments->insert(adjustments->begin(),
-                        base::OffsetAdjuster::Adjustment(0, kHTTPSize, 0));
+                        base::OffsetAdjuster::Adjustment(0, scheme_size, 0));
 
     if (prefix_end)
-      *prefix_end -= kHTTPSize;
+      *prefix_end -= scheme_size;
 
     // Adjust new_parsed.
     DCHECK(new_parsed->scheme.is_valid());
diff --git a/components/url_formatter/url_formatter.h b/components/url_formatter/url_formatter.h
index 3e01b2ef..fac0d84 100644
--- a/components/url_formatter/url_formatter.h
+++ b/components/url_formatter/url_formatter.h
@@ -59,6 +59,10 @@
 // kFormatUrlOmitAll.
 extern const FormatUrlType kFormatUrlExperimentalElideAfterHost;
 
+// If the scheme is 'https://', it's removed. Experimental and not in
+// kFormatUrlOmitAll.
+extern const FormatUrlType kFormatUrlExperimentalOmitHTTPS;
+
 // Creates a string representation of |url|. The IDN host name is turned to
 // Unicode if the Unicode representation is deemed safe. |format_type| is a
 // bitmask of FormatUrlTypes, see it for details. |unescape_rules| defines how
diff --git a/components/url_formatter/url_formatter_unittest.cc b/components/url_formatter/url_formatter_unittest.cc
index fc80118..3ba5e36 100644
--- a/components/url_formatter/url_formatter_unittest.cc
+++ b/components/url_formatter/url_formatter_unittest.cc
@@ -825,12 +825,15 @@
       // Disabled: the resultant URL becomes "...user%253A:%2540passwd...".
 
       // -------- omit http: --------
-      {"omit http with user name", "http://user@example.com/foo",
-       kFormatUrlOmitAll, net::UnescapeRule::NORMAL, L"example.com/foo", 0},
-
       {"omit http", "http://www.google.com/", kFormatUrlOmitHTTP,
        net::UnescapeRule::NORMAL, L"www.google.com/", 0},
 
+      {"omit http on bare scheme", "http://", kFormatUrlOmitAll,
+       net::UnescapeRule::NORMAL, L"", 0},
+
+      {"omit http with user name", "http://user@example.com/foo",
+       kFormatUrlOmitAll, net::UnescapeRule::NORMAL, L"example.com/foo", 0},
+
       {"omit http with https", "https://www.google.com/", kFormatUrlOmitHTTP,
        net::UnescapeRule::NORMAL, L"https://www.google.com/", 8},
 
@@ -913,6 +916,24 @@
        "http://google.com////???####",
        kFormatUrlOmitAll | kFormatUrlExperimentalElideAfterHost,
        net::UnescapeRule::NORMAL, L"google.com/\x2026\x0000", 0},
+
+      // -------- omit https --------
+      {"omit https", "https://www.google.com/", kFormatUrlExperimentalOmitHTTPS,
+       net::UnescapeRule::NORMAL, L"www.google.com/", 0},
+      {"omit https but do not omit http", "http://www.google.com/",
+       kFormatUrlExperimentalOmitHTTPS, net::UnescapeRule::NORMAL,
+       L"http://www.google.com/", 7},
+      {"omit https, username, and password",
+       "https://user:password@example.com/foo",
+       kFormatUrlOmitAll | kFormatUrlExperimentalOmitHTTPS,
+       net::UnescapeRule::NORMAL, L"example.com/foo", 0},
+      {"omit https, but preserve user name and password",
+       "https://user:password@example.com/foo", kFormatUrlExperimentalOmitHTTPS,
+       net::UnescapeRule::NORMAL, L"user:password@example.com/foo", 14},
+      {"omit https should not affect hosts starting with ftp.",
+       "https://ftp.google.com/",
+       kFormatUrlOmitHTTP | kFormatUrlExperimentalOmitHTTPS,
+       net::UnescapeRule::NORMAL, L"https://ftp.google.com/", 8},
   };
 
   for (size_t i = 0; i < arraysize(tests); ++i) {
@@ -1277,6 +1298,21 @@
   CheckAdjustedOffsets("http://foo.com//??###",
                        kFormatUrlOmitAll | kFormatUrlExperimentalElideAfterHost,
                        net::UnescapeRule::NORMAL, elide_after_host_offsets);
+
+  const size_t omit_https_offsets[] = {
+      0, kNpos, kNpos, kNpos, kNpos, kNpos, kNpos, kNpos, 0,  1,  2, 3,
+      4, 5,     6,     7,     8,     9,     10,    11,    12, 13, 14};
+  CheckAdjustedOffsets("https://www.google.com/",
+                       kFormatUrlExperimentalOmitHTTPS,
+                       net::UnescapeRule::NORMAL, omit_https_offsets);
+
+  const size_t omit_https_with_auth_offsets[] = {
+      0,     kNpos, kNpos, kNpos, kNpos, kNpos, kNpos, kNpos, 0,
+      kNpos, kNpos, kNpos, 0,     1,     2,     3,     4,     5,
+      6,     7,     8,     9,     10,    11,    12,    13,    14};
+  CheckAdjustedOffsets("https://u:p@www.google.com/",
+                       kFormatUrlOmitAll | kFormatUrlExperimentalOmitHTTPS,
+                       net::UnescapeRule::NORMAL, omit_https_with_auth_offsets);
 }
 
 }  // namespace
diff --git a/components/viz/client/client_layer_tree_frame_sink.cc b/components/viz/client/client_layer_tree_frame_sink.cc
index 421af8c..795f7d2 100644
--- a/components/viz/client/client_layer_tree_frame_sink.cc
+++ b/components/viz/client/client_layer_tree_frame_sink.cc
@@ -126,7 +126,7 @@
 }
 
 void ClientLayerTreeFrameSink::DidReceiveCompositorFrameAck(
-    const cc::ReturnedResourceArray& resources) {
+    const std::vector<cc::ReturnedResource>& resources) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   client_->ReclaimResources(resources);
   client_->DidReceiveCompositorFrameAck();
@@ -139,7 +139,7 @@
 }
 
 void ClientLayerTreeFrameSink::ReclaimResources(
-    const cc::ReturnedResourceArray& resources) {
+    const std::vector<cc::ReturnedResource>& resources) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   client_->ReclaimResources(resources);
 }
diff --git a/components/viz/client/client_layer_tree_frame_sink.h b/components/viz/client/client_layer_tree_frame_sink.h
index a32c772..5a380bb 100644
--- a/components/viz/client/client_layer_tree_frame_sink.h
+++ b/components/viz/client/client_layer_tree_frame_sink.h
@@ -58,9 +58,10 @@
  private:
   // cc::mojom::CompositorFrameSinkClient implementation:
   void DidReceiveCompositorFrameAck(
-      const cc::ReturnedResourceArray& resources) override;
+      const std::vector<cc::ReturnedResource>& resources) override;
   void OnBeginFrame(const cc::BeginFrameArgs& begin_frame_args) override;
-  void ReclaimResources(const cc::ReturnedResourceArray& resources) override;
+  void ReclaimResources(
+      const std::vector<cc::ReturnedResource>& resources) override;
 
   // cc::ExternalBeginFrameSourceClient implementation.
   void OnNeedsBeginFrames(bool needs_begin_frames) override;
diff --git a/components/viz/host/host_frame_sink_manager_unittests.cc b/components/viz/host/host_frame_sink_manager_unittests.cc
index b113e87..9c24966 100644
--- a/components/viz/host/host_frame_sink_manager_unittests.cc
+++ b/components/viz/host/host_frame_sink_manager_unittests.cc
@@ -42,9 +42,10 @@
  private:
   // cc::mojom::CompositorFrameSinkClient:
   void DidReceiveCompositorFrameAck(
-      const cc::ReturnedResourceArray& resources) override {}
+      const std::vector<cc::ReturnedResource>& resources) override {}
   void OnBeginFrame(const cc::BeginFrameArgs& begin_frame_args) override {}
-  void ReclaimResources(const cc::ReturnedResourceArray& resources) override {}
+  void ReclaimResources(
+      const std::vector<cc::ReturnedResource>& resources) override {}
 
   mojo::Binding<cc::mojom::CompositorFrameSinkClient> binding_;
 
diff --git a/components/viz/service/frame_sinks/gpu_compositor_frame_sink.cc b/components/viz/service/frame_sinks/gpu_compositor_frame_sink.cc
index 931ec20d..427cc86 100644
--- a/components/viz/service/frame_sinks/gpu_compositor_frame_sink.cc
+++ b/components/viz/service/frame_sinks/gpu_compositor_frame_sink.cc
@@ -58,7 +58,7 @@
 }
 
 void GpuCompositorFrameSink::DidReceiveCompositorFrameAck(
-    const cc::ReturnedResourceArray& resources) {
+    const std::vector<cc::ReturnedResource>& resources) {
   if (client_)
     client_->DidReceiveCompositorFrameAck(resources);
 }
@@ -79,7 +79,7 @@
 }
 
 void GpuCompositorFrameSink::ReclaimResources(
-    const cc::ReturnedResourceArray& resources) {
+    const std::vector<cc::ReturnedResource>& resources) {
   if (client_)
     client_->ReclaimResources(resources);
 }
diff --git a/components/viz/service/frame_sinks/gpu_compositor_frame_sink.h b/components/viz/service/frame_sinks/gpu_compositor_frame_sink.h
index e517f7ba..b711cec 100644
--- a/components/viz/service/frame_sinks/gpu_compositor_frame_sink.h
+++ b/components/viz/service/frame_sinks/gpu_compositor_frame_sink.h
@@ -50,9 +50,10 @@
  private:
   // cc::CompositorFrameSinkSupportClient implementation:
   void DidReceiveCompositorFrameAck(
-      const cc::ReturnedResourceArray& resources) override;
+      const std::vector<cc::ReturnedResource>& resources) override;
   void OnBeginFrame(const cc::BeginFrameArgs& args) override;
-  void ReclaimResources(const cc::ReturnedResourceArray& resources) override;
+  void ReclaimResources(
+      const std::vector<cc::ReturnedResource>& resources) override;
   void WillDrawSurface(const cc::LocalSurfaceId& local_surface_id,
                        const gfx::Rect& damage_rect) override;
 
diff --git a/components/viz/service/frame_sinks/gpu_root_compositor_frame_sink.cc b/components/viz/service/frame_sinks/gpu_root_compositor_frame_sink.cc
index 9f6cd290..bb04a8f 100644
--- a/components/viz/service/frame_sinks/gpu_root_compositor_frame_sink.cc
+++ b/components/viz/service/frame_sinks/gpu_root_compositor_frame_sink.cc
@@ -122,7 +122,7 @@
 void GpuRootCompositorFrameSink::DisplayDidDrawAndSwap() {}
 
 void GpuRootCompositorFrameSink::DidReceiveCompositorFrameAck(
-    const cc::ReturnedResourceArray& resources) {
+    const std::vector<cc::ReturnedResource>& resources) {
   if (client_)
     client_->DidReceiveCompositorFrameAck(resources);
 }
@@ -133,7 +133,7 @@
 }
 
 void GpuRootCompositorFrameSink::ReclaimResources(
-    const cc::ReturnedResourceArray& resources) {
+    const std::vector<cc::ReturnedResource>& resources) {
   if (client_)
     client_->ReclaimResources(resources);
 }
diff --git a/components/viz/service/frame_sinks/gpu_root_compositor_frame_sink.h b/components/viz/service/frame_sinks/gpu_root_compositor_frame_sink.h
index 700e92e..aee3e1ea 100644
--- a/components/viz/service/frame_sinks/gpu_root_compositor_frame_sink.h
+++ b/components/viz/service/frame_sinks/gpu_root_compositor_frame_sink.h
@@ -76,9 +76,10 @@
 
   // cc::CompositorFrameSinkSupportClient:
   void DidReceiveCompositorFrameAck(
-      const cc::ReturnedResourceArray& resources) override;
+      const std::vector<cc::ReturnedResource>& resources) override;
   void OnBeginFrame(const cc::BeginFrameArgs& args) override;
-  void ReclaimResources(const cc::ReturnedResourceArray& resources) override;
+  void ReclaimResources(
+      const std::vector<cc::ReturnedResource>& resources) override;
   void WillDrawSurface(const cc::LocalSurfaceId& local_surface_id,
                        const gfx::Rect& damage_rect) override;
 
diff --git a/content/browser/android/synchronous_compositor_host.cc b/content/browser/android/synchronous_compositor_host.cc
index c99d24c8..dd08611 100644
--- a/content/browser/android/synchronous_compositor_host.cc
+++ b/content/browser/android/synchronous_compositor_host.cc
@@ -314,7 +314,7 @@
 
 void SynchronousCompositorHost::ReturnResources(
     uint32_t layer_tree_frame_sink_id,
-    const cc::ReturnedResourceArray& resources) {
+    const std::vector<cc::ReturnedResource>& resources) {
   DCHECK(!resources.empty());
   sender_->Send(new SyncCompositorMsg_ReclaimResources(
       routing_id_, layer_tree_frame_sink_id, resources));
diff --git a/content/browser/android/synchronous_compositor_host.h b/content/browser/android/synchronous_compositor_host.h
index 1ac04e5..53d6a54 100644
--- a/content/browser/android/synchronous_compositor_host.h
+++ b/content/browser/android/synchronous_compositor_host.h
@@ -54,8 +54,9 @@
       const gfx::Rect& viewport_rect_for_tile_priority,
       const gfx::Transform& transform_for_tile_priority) override;
   bool DemandDrawSw(SkCanvas* canvas) override;
-  void ReturnResources(uint32_t layer_tree_frame_sink_id,
-                       const cc::ReturnedResourceArray& resources) override;
+  void ReturnResources(
+      uint32_t layer_tree_frame_sink_id,
+      const std::vector<cc::ReturnedResource>& resources) override;
   void SetMemoryPolicy(size_t bytes_limit) override;
   void DidChangeRootLayerScrollOffset(
       const gfx::ScrollOffset& root_offset) override;
diff --git a/content/browser/blob_storage/chrome_blob_storage_context.cc b/content/browser/blob_storage/chrome_blob_storage_context.cc
index 6dfe51c..843dabcd 100644
--- a/content/browser/blob_storage/chrome_blob_storage_context.cc
+++ b/content/browser/blob_storage/chrome_blob_storage_context.cc
@@ -19,11 +19,11 @@
 #include "base/task_runner.h"
 #include "base/task_scheduler/post_task.h"
 #include "content/browser/resource_context_impl.h"
-#include "content/common/resource_request_body_impl.h"
 #include "content/public/browser/blob_handle.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/common/content_features.h"
+#include "content/public/common/resource_request_body.h"
 #include "storage/browser/blob/blob_data_builder.h"
 #include "storage/browser/blob/blob_memory_controller.h"
 #include "storage/browser/blob/blob_registry_impl.h"
@@ -210,7 +210,7 @@
   return blob_storage_context->context();
 }
 
-bool GetBodyBlobDataHandles(ResourceRequestBodyImpl* body,
+bool GetBodyBlobDataHandles(ResourceRequestBody* body,
                             ResourceContext* resource_context,
                             BlobHandles* blob_handles) {
   blob_handles->clear();
@@ -220,8 +220,8 @@
 
   DCHECK(blob_context);
   for (size_t i = 0; i < body->elements()->size(); ++i) {
-    const ResourceRequestBodyImpl::Element& element = (*body->elements())[i];
-    if (element.type() != ResourceRequestBodyImpl::Element::TYPE_BLOB)
+    const ResourceRequestBody::Element& element = (*body->elements())[i];
+    if (element.type() != ResourceRequestBody::Element::TYPE_BLOB)
       continue;
     std::unique_ptr<storage::BlobDataHandle> handle =
         blob_context->GetBlobDataFromUUID(element.blob_uuid());
diff --git a/content/browser/blob_storage/chrome_blob_storage_context.h b/content/browser/blob_storage/chrome_blob_storage_context.h
index 9c0312f..87702d1 100644
--- a/content/browser/blob_storage/chrome_blob_storage_context.h
+++ b/content/browser/blob_storage/chrome_blob_storage_context.h
@@ -34,7 +34,7 @@
 class BlobHandle;
 class BrowserContext;
 struct ChromeBlobStorageContextDeleter;
-class ResourceRequestBodyImpl;
+class ResourceRequestBody;
 class ResourceContext;
 
 // A context class that keeps track of BlobStorageController used by the chrome.
@@ -103,7 +103,7 @@
 // Attempts to create a vector of BlobDataHandles that ensure any blob data
 // associated with |body| isn't cleaned up until the handles are destroyed.
 // Returns false on failure. This is used for POST and PUT requests.
-bool GetBodyBlobDataHandles(ResourceRequestBodyImpl* body,
+bool GetBodyBlobDataHandles(ResourceRequestBody* body,
                             ResourceContext* resource_context,
                             BlobHandles* blob_handles);
 
diff --git a/content/browser/cache_storage/cache_storage_cache.cc b/content/browser/cache_storage/cache_storage_cache.cc
index 141944f..c06ef710 100644
--- a/content/browser/cache_storage/cache_storage_cache.cc
+++ b/content/browser/cache_storage/cache_storage_cache.cc
@@ -490,6 +490,12 @@
       &CacheStorageCache::BatchDidOneOperation, weak_ptr_factory_.GetWeakPtr(),
       barrier_closure, callback_copy);
 
+  // Operations may synchronously invoke |callback| which could release the
+  // last reference to this instance. Hold a handle for the duration of this
+  // loop. (Asynchronous tasks scheduled by the operations use weak ptrs which
+  // will no-op automatically.)
+  std::unique_ptr<CacheStorageCacheHandle> handle = CreateCacheHandle();
+
   for (const auto& operation : operations) {
     switch (operation.operation_type) {
       case CACHE_STORAGE_CACHE_OPERATION_TYPE_PUT:
diff --git a/content/browser/child_process_security_policy_impl.cc b/content/browser/child_process_security_policy_impl.cc
index 210a3c3..94af97e 100644
--- a/content/browser/child_process_security_policy_impl.cc
+++ b/content/browser/child_process_security_policy_impl.cc
@@ -18,7 +18,6 @@
 #include "base/strings/string_util.h"
 #include "build/build_config.h"
 #include "content/browser/site_instance_impl.h"
-#include "content/common/resource_request_body_impl.h"
 #include "content/common/site_isolation_policy.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
@@ -27,6 +26,7 @@
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/common/bindings_policy.h"
+#include "content/public/common/resource_request_body.h"
 #include "content/public/common/url_constants.h"
 #include "net/base/filename_util.h"
 #include "net/url_request/url_request.h"
@@ -763,40 +763,40 @@
 bool ChildProcessSecurityPolicyImpl::CanReadRequestBody(
     int child_id,
     const storage::FileSystemContext* file_system_context,
-    const scoped_refptr<ResourceRequestBodyImpl>& body) {
+    const scoped_refptr<ResourceRequestBody>& body) {
   if (!body)
     return true;
 
-  for (const ResourceRequestBodyImpl::Element& element : *body->elements()) {
+  for (const ResourceRequestBody::Element& element : *body->elements()) {
     switch (element.type()) {
-      case ResourceRequestBodyImpl::Element::TYPE_FILE:
+      case ResourceRequestBody::Element::TYPE_FILE:
         if (!CanReadFile(child_id, element.path()))
           return false;
         break;
 
-      case ResourceRequestBodyImpl::Element::TYPE_FILE_FILESYSTEM:
+      case ResourceRequestBody::Element::TYPE_FILE_FILESYSTEM:
         if (!CanReadFileSystemFile(child_id, file_system_context->CrackURL(
                                                  element.filesystem_url())))
           return false;
         break;
 
-      case ResourceRequestBodyImpl::Element::TYPE_DISK_CACHE_ENTRY:
+      case ResourceRequestBody::Element::TYPE_DISK_CACHE_ENTRY:
         // TYPE_DISK_CACHE_ENTRY can't be sent via IPC according to
         // content/common/resource_messages.cc
         NOTREACHED();
         return false;
 
-      case ResourceRequestBodyImpl::Element::TYPE_BYTES:
-      case ResourceRequestBodyImpl::Element::TYPE_BYTES_DESCRIPTION:
+      case ResourceRequestBody::Element::TYPE_BYTES:
+      case ResourceRequestBody::Element::TYPE_BYTES_DESCRIPTION:
         // Data is self-contained within |body| - no need to check access.
         break;
 
-      case ResourceRequestBodyImpl::Element::TYPE_BLOB:
+      case ResourceRequestBody::Element::TYPE_BLOB:
         // No need to validate - the unguessability of the uuid of the blob is a
         // sufficient defense against access from an unrelated renderer.
         break;
 
-      case ResourceRequestBodyImpl::Element::TYPE_UNKNOWN:
+      case ResourceRequestBody::Element::TYPE_UNKNOWN:
       default:
         // Fail safe - deny access.
         NOTREACHED();
@@ -808,7 +808,7 @@
 
 bool ChildProcessSecurityPolicyImpl::CanReadRequestBody(
     SiteInstance* site_instance,
-    const scoped_refptr<ResourceRequestBodyImpl>& body) {
+    const scoped_refptr<ResourceRequestBody>& body) {
   DCHECK(site_instance);
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
diff --git a/content/browser/child_process_security_policy_impl.h b/content/browser/child_process_security_policy_impl.h
index 82a5e81..c276ebd8 100644
--- a/content/browser/child_process_security_policy_impl.h
+++ b/content/browser/child_process_security_policy_impl.h
@@ -36,7 +36,7 @@
 namespace content {
 
 class SiteInstance;
-class ResourceRequestBodyImpl;
+class ResourceRequestBody;
 
 class CONTENT_EXPORT ChildProcessSecurityPolicyImpl
     : NON_EXPORTED_BASE(public ChildProcessSecurityPolicy) {
@@ -99,13 +99,13 @@
   // data in the POST body specified by |body|.  Can be called on any thread.
   bool CanReadRequestBody(int child_id,
                           const storage::FileSystemContext* file_system_context,
-                          const scoped_refptr<ResourceRequestBodyImpl>& body);
+                          const scoped_refptr<ResourceRequestBody>& body);
 
   // Validate that the renderer process for |site_instance| is allowed to access
   // data in the POST body specified by |body|.  Has to be called on the UI
   // thread.
   bool CanReadRequestBody(SiteInstance* site_instance,
-                          const scoped_refptr<ResourceRequestBodyImpl>& body);
+                          const scoped_refptr<ResourceRequestBody>& body);
 
   // Pseudo schemes are treated differently than other schemes because they
   // cannot be requested like normal URLs.  There is no mechanism for revoking
diff --git a/content/browser/compositor/gpu_vsync_begin_frame_source.cc b/content/browser/compositor/gpu_vsync_begin_frame_source.cc
index e4f039a7..7e43be47 100644
--- a/content/browser/compositor/gpu_vsync_begin_frame_source.cc
+++ b/content/browser/compositor/gpu_vsync_begin_frame_source.cc
@@ -22,7 +22,7 @@
   if (!needs_begin_frames_)
     return;
 
-  base::TimeTicks now = Now();
+  base::TimeTicks now = base::TimeTicks::Now();
   base::TimeTicks deadline = now.SnappedToNextTick(timestamp, interval);
 
   TRACE_EVENT1("cc", "GpuVSyncBeginFrameSource::OnVSync", "latency",
@@ -39,43 +39,4 @@
   vsync_control_->SetNeedsVSync(needs_begin_frames);
 }
 
-base::TimeTicks GpuVSyncBeginFrameSource::Now() const {
-  return base::TimeTicks::Now();
-}
-
-cc::BeginFrameArgs GpuVSyncBeginFrameSource::GetMissedBeginFrameArgs(
-    cc::BeginFrameObserver* obs) {
-  if (!last_begin_frame_args_.IsValid())
-    return cc::BeginFrameArgs();
-
-  base::TimeTicks now = Now();
-  base::TimeTicks estimated_next_timestamp = now.SnappedToNextTick(
-      last_begin_frame_args_.frame_time, last_begin_frame_args_.interval);
-  base::TimeTicks missed_timestamp =
-      estimated_next_timestamp - last_begin_frame_args_.interval;
-
-  if (missed_timestamp > last_begin_frame_args_.frame_time) {
-    // The projected missed timestamp is newer than the last known timestamp.
-    // In this case create BeginFrameArgs with a new sequence number.
-    next_sequence_number_++;
-    last_begin_frame_args_ = cc::BeginFrameArgs::Create(
-        BEGINFRAME_FROM_HERE, source_id(), next_sequence_number_,
-        missed_timestamp, estimated_next_timestamp,
-        last_begin_frame_args_.interval, cc::BeginFrameArgs::MISSED);
-    return last_begin_frame_args_;
-  }
-
-  // The last known args object is up-to-date. Skip sending notification
-  // if the observer has already seen it.
-  const cc::BeginFrameArgs& last_observer_args = obs->LastUsedBeginFrameArgs();
-  if (last_observer_args.IsValid() &&
-      last_begin_frame_args_.frame_time <= last_observer_args.frame_time) {
-    return cc::BeginFrameArgs();
-  }
-
-  cc::BeginFrameArgs missed_args = last_begin_frame_args_;
-  missed_args.type = cc::BeginFrameArgs::MISSED;
-  return missed_args;
-}
-
 }  // namespace content
diff --git a/content/browser/compositor/gpu_vsync_begin_frame_source.h b/content/browser/compositor/gpu_vsync_begin_frame_source.h
index 9df2f07..a3ddd6b 100644
--- a/content/browser/compositor/gpu_vsync_begin_frame_source.h
+++ b/content/browser/compositor/gpu_vsync_begin_frame_source.h
@@ -8,21 +8,19 @@
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
 #include "cc/scheduler/begin_frame_source.h"
-#include "content/common/content_export.h"
 
 namespace content {
 
 // This class is used to control VSync production on GPU side.
-class CONTENT_EXPORT GpuVSyncControl {
+class GpuVSyncControl {
  public:
   virtual void SetNeedsVSync(bool needs_vsync) = 0;
 };
 
 // This is a type of ExternalBeginFrameSource where VSync signals are
 // generated externally on GPU side.
-class CONTENT_EXPORT GpuVSyncBeginFrameSource
-    : public cc::ExternalBeginFrameSource,
-      public cc::ExternalBeginFrameSourceClient {
+class GpuVSyncBeginFrameSource : public cc::ExternalBeginFrameSource,
+                                 cc::ExternalBeginFrameSourceClient {
  public:
   explicit GpuVSyncBeginFrameSource(GpuVSyncControl* vsync_control);
   ~GpuVSyncBeginFrameSource() override;
@@ -32,14 +30,7 @@
 
   void OnVSync(base::TimeTicks timestamp, base::TimeDelta interval);
 
- protected:
-  // Virtual for testing.
-  virtual base::TimeTicks Now() const;
-
  private:
-  cc::BeginFrameArgs GetMissedBeginFrameArgs(
-      cc::BeginFrameObserver* obs) override;
-
   GpuVSyncControl* const vsync_control_;
   bool needs_begin_frames_;
   uint64_t next_sequence_number_;
diff --git a/content/browser/compositor/gpu_vsync_begin_frame_source_unittest.cc b/content/browser/compositor/gpu_vsync_begin_frame_source_unittest.cc
deleted file mode 100644
index 75fca12..0000000
--- a/content/browser/compositor/gpu_vsync_begin_frame_source_unittest.cc
+++ /dev/null
@@ -1,185 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/compositor/gpu_vsync_begin_frame_source.h"
-
-#include "base/macros.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace content {
-namespace {
-
-class TestBeginFrameObserver : public cc::BeginFrameObserverBase {
- public:
-  TestBeginFrameObserver() = default;
-
-  int begin_frame_count() { return begin_frame_count_; }
-
- private:
-  bool OnBeginFrameDerivedImpl(const cc::BeginFrameArgs& args) override {
-    begin_frame_count_++;
-    return true;
-  }
-
-  void OnBeginFrameSourcePausedChanged(bool paused) override {}
-
-  int begin_frame_count_ = 0;
-
-  DISALLOW_COPY_AND_ASSIGN(TestBeginFrameObserver);
-};
-
-class TestGpuVSyncBeginFrameSource : public GpuVSyncBeginFrameSource {
- public:
-  explicit TestGpuVSyncBeginFrameSource(GpuVSyncControl* vsync_control)
-      : GpuVSyncBeginFrameSource(vsync_control) {}
-
-  void SetNow(base::TimeTicks now) { now_ = now; }
-
- private:
-  base::TimeTicks Now() const override { return now_; }
-
-  base::TimeTicks now_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestGpuVSyncBeginFrameSource);
-};
-
-class GpuVSyncBeginFrameSourceTest : public testing::Test,
-                                     public GpuVSyncControl {
- public:
-  GpuVSyncBeginFrameSourceTest() = default;
-  ~GpuVSyncBeginFrameSourceTest() override = default;
-
- protected:
-  void SetNeedsVSync(bool needs_vsync) override { needs_vsync_ = needs_vsync; }
-
-  bool needs_vsync_ = false;
-
-  DISALLOW_COPY_AND_ASSIGN(GpuVSyncBeginFrameSourceTest);
-};
-
-// Test that an observer can be added to BFS and that it receives OnBeginFrame
-// notification.
-TEST_F(GpuVSyncBeginFrameSourceTest, BasicTest) {
-  TestBeginFrameObserver observer;
-  TestGpuVSyncBeginFrameSource begin_frame_source(this);
-
-  base::TimeTicks now = base::TimeTicks() + base::TimeDelta::FromHours(2);
-  begin_frame_source.SetNow(now);
-
-  EXPECT_FALSE(needs_vsync_);
-
-  begin_frame_source.AddObserver(&observer);
-
-  EXPECT_TRUE(needs_vsync_);
-  EXPECT_FALSE(observer.LastUsedBeginFrameArgs().IsValid());
-
-  base::TimeTicks frame_time = now - base::TimeDelta::FromSeconds(1);
-  base::TimeDelta interval = base::TimeDelta::FromSeconds(2);
-
-  begin_frame_source.OnVSync(frame_time, interval);
-
-  EXPECT_EQ(1, observer.begin_frame_count());
-
-  cc::BeginFrameArgs args = observer.LastUsedBeginFrameArgs();
-  EXPECT_TRUE(args.IsValid());
-  EXPECT_EQ(frame_time, args.frame_time);
-  EXPECT_EQ(interval, args.interval);
-  EXPECT_EQ(frame_time + interval, args.deadline);
-  EXPECT_EQ(cc::BeginFrameArgs::kStartingFrameNumber + 1, args.sequence_number);
-  EXPECT_EQ(cc::BeginFrameArgs::NORMAL, args.type);
-  EXPECT_EQ(begin_frame_source.source_id(), args.source_id);
-
-  // Make sure that the deadline time is correctly advanced forward to be after
-  // 'now' when frame time is way behind.
-  now += base::TimeDelta::FromSeconds(10);
-  begin_frame_source.SetNow(now);
-  // Frame time is 5 seconds behind but the deadline should be 1 second after
-  // 'now' considering the 2 second interval.
-  frame_time = now - base::TimeDelta::FromSeconds(5);
-
-  begin_frame_source.OnVSync(frame_time, interval);
-
-  EXPECT_EQ(2, observer.begin_frame_count());
-
-  args = observer.LastUsedBeginFrameArgs();
-  EXPECT_TRUE(args.IsValid());
-  EXPECT_EQ(frame_time, args.frame_time);
-  EXPECT_EQ(interval, args.interval);
-  EXPECT_EQ(now + base::TimeDelta::FromSeconds(1), args.deadline);
-  EXPECT_EQ(cc::BeginFrameArgs::kStartingFrameNumber + 2, args.sequence_number);
-  EXPECT_EQ(cc::BeginFrameArgs::NORMAL, args.type);
-  EXPECT_EQ(begin_frame_source.source_id(), args.source_id);
-
-  begin_frame_source.RemoveObserver(&observer);
-
-  EXPECT_EQ(2, observer.begin_frame_count());
-  EXPECT_FALSE(needs_vsync_);
-}
-
-// Test that MISSED OnBeginFrame is produced as expected.
-TEST_F(GpuVSyncBeginFrameSourceTest, MissedBeginFrameArgs) {
-  TestBeginFrameObserver observer1;
-  TestBeginFrameObserver observer2;
-  TestGpuVSyncBeginFrameSource begin_frame_source(this);
-
-  base::TimeTicks now = base::TimeTicks() + base::TimeDelta::FromHours(2);
-  begin_frame_source.SetNow(now);
-
-  begin_frame_source.AddObserver(&observer1);
-
-  // The observer shouldn't be getting any BeginFrame at this point.
-  EXPECT_EQ(0, observer1.begin_frame_count());
-
-  base::TimeDelta interval = base::TimeDelta::FromSeconds(2);
-
-  // Trigger first OnBeginFrame 5 seconds behind now.
-  begin_frame_source.OnVSync(now - base::TimeDelta::FromSeconds(5), interval);
-
-  // The observer should get a NORMAL BeginFrame notification which is covered
-  // by BasicTest above.
-  EXPECT_EQ(1, observer1.begin_frame_count());
-  EXPECT_EQ(cc::BeginFrameArgs::NORMAL,
-            observer1.LastUsedBeginFrameArgs().type);
-
-  // Remove the first observer and add it back. It should get a more
-  // recent missed notification calculated from the projection of the previous
-  // notification.
-  begin_frame_source.RemoveObserver(&observer1);
-  begin_frame_source.AddObserver(&observer1);
-
-  EXPECT_EQ(2, observer1.begin_frame_count());
-
-  // The projected MISSED frame_time should be 1 second behind 'now'.
-  base::TimeTicks timestamp1 = now - base::TimeDelta::FromSeconds(1);
-  cc::BeginFrameArgs args1 = observer1.LastUsedBeginFrameArgs();
-  EXPECT_TRUE(args1.IsValid());
-  EXPECT_EQ(timestamp1, args1.frame_time);
-  EXPECT_EQ(timestamp1 + interval, args1.deadline);
-  EXPECT_EQ(cc::BeginFrameArgs::kStartingFrameNumber + 2,
-            args1.sequence_number);
-  EXPECT_EQ(cc::BeginFrameArgs::MISSED, args1.type);
-
-  // Add second observer which should receive the same notification.
-  begin_frame_source.AddObserver(&observer2);
-
-  EXPECT_EQ(1, observer2.begin_frame_count());
-
-  cc::BeginFrameArgs args2 = observer2.LastUsedBeginFrameArgs();
-  EXPECT_TRUE(args2.IsValid());
-  EXPECT_EQ(timestamp1, args2.frame_time);
-  EXPECT_EQ(timestamp1 + interval, args2.deadline);
-  EXPECT_EQ(cc::BeginFrameArgs::kStartingFrameNumber + 2,
-            args2.sequence_number);
-  EXPECT_EQ(cc::BeginFrameArgs::MISSED, args2.type);
-
-  // Adding and removing the second observer shouldn't produce any
-  // new notifications.
-  begin_frame_source.RemoveObserver(&observer2);
-  begin_frame_source.AddObserver(&observer2);
-
-  EXPECT_EQ(1, observer2.begin_frame_count());
-}
-
-}  // namespace
-}  // namespace content
diff --git a/content/browser/compositor/surface_utils.cc b/content/browser/compositor/surface_utils.cc
index 67347b8..04184659 100644
--- a/content/browser/compositor/surface_utils.cc
+++ b/content/browser/compositor/surface_utils.cc
@@ -169,7 +169,7 @@
   return CompositorImpl::GetSurfaceManager();
 #else
   ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
-  if (!factory)
+  if (factory == NULL)
     return nullptr;
   return factory->GetContextFactoryPrivate()->GetSurfaceManager();
 #endif
@@ -179,10 +179,7 @@
 #if defined(OS_ANDROID)
   return CompositorImpl::GetHostFrameSinkManager();
 #else
-  ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
-  if (!factory)
-    return nullptr;
-  return factory->GetContextFactoryPrivate()->GetHostFrameSinkManager();
+  return BrowserMainLoop::GetInstance()->host_frame_sink_manager();
 #endif
 }
 
diff --git a/content/browser/devtools/devtools_url_interceptor_request_job.cc b/content/browser/devtools/devtools_url_interceptor_request_job.cc
index ef62d008..8db9c692 100644
--- a/content/browser/devtools/devtools_url_interceptor_request_job.cc
+++ b/content/browser/devtools/devtools_url_interceptor_request_job.cc
@@ -9,6 +9,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "content/browser/devtools/protocol/network_handler.h"
 #include "content/browser/devtools/protocol/page.h"
+#include "content/browser/loader/resource_request_info_impl.h"
 #include "net/base/elements_upload_data_stream.h"
 #include "net/base/io_buffer.h"
 #include "net/base/upload_bytes_element_reader.h"
@@ -674,6 +675,38 @@
   request_->set_method(request_details.method);
   request_->SetExtraRequestHeaders(request_details.extra_request_headers);
 
+  // Mimic the ResourceRequestInfoImpl of the original request.
+  const ResourceRequestInfoImpl* resource_request_info =
+      static_cast<const ResourceRequestInfoImpl*>(
+          ResourceRequestInfo::ForRequest(
+              devtools_interceptor_request_job->request()));
+  ResourceRequestInfoImpl* extra_data = new ResourceRequestInfoImpl(
+      resource_request_info->requester_info(),
+      resource_request_info->GetRouteID(),
+      resource_request_info->GetFrameTreeNodeId(),
+      resource_request_info->GetOriginPID(),
+      resource_request_info->GetRequestID(),
+      resource_request_info->GetRenderFrameID(),
+      resource_request_info->IsMainFrame(),
+      resource_request_info->ParentIsMainFrame(),
+      resource_request_info->GetResourceType(),
+      resource_request_info->GetPageTransition(),
+      resource_request_info->should_replace_current_entry(),
+      resource_request_info->IsDownload(), resource_request_info->is_stream(),
+      resource_request_info->allow_download(),
+      resource_request_info->HasUserGesture(),
+      resource_request_info->is_load_timing_enabled(),
+      resource_request_info->is_upload_progress_enabled(),
+      resource_request_info->do_not_prompt_for_login(),
+      resource_request_info->GetReferrerPolicy(),
+      resource_request_info->GetVisibilityState(),
+      resource_request_info->GetContext(),
+      resource_request_info->ShouldReportRawHeaders(),
+      resource_request_info->IsAsync(),
+      resource_request_info->GetPreviewsState(), resource_request_info->body(),
+      resource_request_info->initiated_in_secure_context());
+  extra_data->AssociateWithRequest(request_.get());
+
   if (request_details.post_data)
     request_->set_upload(std::move(request_details.post_data));
 
diff --git a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
index addd4e1..a2a43d6 100644
--- a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
+++ b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
@@ -1611,6 +1611,7 @@
   std::set<std::string> ids;
   std::unique_ptr<base::DictionaryValue> command_params;
   std::unique_ptr<base::DictionaryValue> params;
+  bool is_attached;
 
   ASSERT_TRUE(embedded_test_server()->Start());
   GURL first_url = embedded_test_server()->GetURL("/devtools/navigation.html");
@@ -1621,22 +1622,28 @@
   NavigateToURLBlockUntilNavigationsComplete(second, second_url, 1);
 
   Attach();
+  int attached_count = 0;
   command_params.reset(new base::DictionaryValue());
   command_params->SetBoolean("discover", true);
   SendCommand("Target.setDiscoverTargets", std::move(command_params), true);
   params = WaitForNotification("Target.targetCreated", true);
   EXPECT_TRUE(params->GetString("targetInfo.type", &temp));
   EXPECT_EQ("page", temp);
+  EXPECT_TRUE(params->GetBoolean("targetInfo.attached", &is_attached));
+  attached_count += is_attached ? 1 : 0;
   EXPECT_TRUE(params->GetString("targetInfo.targetId", &temp));
   EXPECT_TRUE(ids.find(temp) == ids.end());
   ids.insert(temp);
   params = WaitForNotification("Target.targetCreated", true);
   EXPECT_TRUE(params->GetString("targetInfo.type", &temp));
   EXPECT_EQ("page", temp);
+  EXPECT_TRUE(params->GetBoolean("targetInfo.attached", &is_attached));
+  attached_count += is_attached ? 1 : 0;
   EXPECT_TRUE(params->GetString("targetInfo.targetId", &temp));
   EXPECT_TRUE(ids.find(temp) == ids.end());
   ids.insert(temp);
   EXPECT_TRUE(notifications_.empty());
+  EXPECT_EQ(1, attached_count);
 
   GURL third_url = embedded_test_server()->GetURL("/devtools/navigation.html");
   Shell* third = CreateBrowser();
@@ -1646,6 +1653,8 @@
   EXPECT_EQ("page", temp);
   EXPECT_TRUE(params->GetString("targetInfo.targetId", &temp));
   EXPECT_TRUE(ids.find(temp) == ids.end());
+  EXPECT_TRUE(params->GetBoolean("targetInfo.attached", &is_attached));
+  EXPECT_FALSE(is_attached);
   std::string attached_id = temp;
   ids.insert(temp);
   EXPECT_TRUE(notifications_.empty());
@@ -1661,6 +1670,11 @@
   command_params.reset(new base::DictionaryValue());
   command_params->SetString("targetId", attached_id);
   SendCommand("Target.attachToTarget", std::move(command_params), true);
+  params = WaitForNotification("Target.targetInfoChanged", true);
+  EXPECT_TRUE(params->GetString("targetInfo.targetId", &temp));
+  EXPECT_EQ(attached_id, temp);
+  EXPECT_TRUE(params->GetBoolean("targetInfo.attached", &is_attached));
+  EXPECT_TRUE(is_attached);
   params = WaitForNotification("Target.attachedToTarget", true);
   EXPECT_TRUE(params->GetString("targetInfo.targetId", &temp));
   EXPECT_EQ(attached_id, temp);
diff --git a/content/browser/devtools/protocol/target_handler.cc b/content/browser/devtools/protocol/target_handler.cc
index dd1b8b8..2cbdaffc 100644
--- a/content/browser/devtools/protocol/target_handler.cc
+++ b/content/browser/devtools/protocol/target_handler.cc
@@ -89,6 +89,7 @@
       .SetTitle(host->GetTitle())
       .SetUrl(host->GetURL().spec())
       .SetType(host->GetType())
+      .SetAttached(host->IsAttached())
       .Build();
 }
 
@@ -213,8 +214,13 @@
   reported_hosts_[host->GetId()] = host;
 }
 
-void TargetHandler::TargetDestroyedInternal(
-    DevToolsAgentHost* host) {
+void TargetHandler::TargetInfoChangedInternal(DevToolsAgentHost* host) {
+  if (reported_hosts_.find(host->GetId()) == reported_hosts_.end())
+    return;
+  frontend_->TargetInfoChanged(CreateInfo(host));
+}
+
+void TargetHandler::TargetDestroyedInternal(DevToolsAgentHost* host) {
   auto it = reported_hosts_.find(host->GetId());
   if (it == reported_hosts_.end())
     return;
@@ -419,8 +425,6 @@
 }
 
 void TargetHandler::DevToolsAgentHostCreated(DevToolsAgentHost* agent_host) {
-  if (agent_host->GetType() == "node" && agent_host->IsAttached())
-    return;
   // If we start discovering late, all existing agent hosts will be reported,
   // but we could have already attached to some.
   TargetCreatedInternal(agent_host);
@@ -432,19 +436,11 @@
 }
 
 void TargetHandler::DevToolsAgentHostAttached(DevToolsAgentHost* host) {
-  if (host->GetType() == "node" &&
-      reported_hosts_.find(host->GetId()) != reported_hosts_.end() &&
-      attached_hosts_.find(host->GetId()) == attached_hosts_.end()) {
-    TargetDestroyedInternal(host);
-  }
+  TargetInfoChangedInternal(host);
 }
 
 void TargetHandler::DevToolsAgentHostDetached(DevToolsAgentHost* host) {
-  if (host->GetType() == "node" &&
-      reported_hosts_.find(host->GetId()) == reported_hosts_.end() &&
-      attached_hosts_.find(host->GetId()) == attached_hosts_.end()) {
-    TargetCreatedInternal(host);
-  }
+  TargetInfoChangedInternal(host);
 }
 
 // -------- ServiceWorkerDevToolsManager::Observer ----------
diff --git a/content/browser/devtools/protocol/target_handler.h b/content/browser/devtools/protocol/target_handler.h
index 6a0b02c6..e932461 100644
--- a/content/browser/devtools/protocol/target_handler.h
+++ b/content/browser/devtools/protocol/target_handler.h
@@ -78,6 +78,7 @@
                              const std::string& type,
                              bool waiting_for_debugger);
   void TargetCreatedInternal(DevToolsAgentHost* host);
+  void TargetInfoChangedInternal(DevToolsAgentHost* host);
   void TargetDestroyedInternal(DevToolsAgentHost* host);
   bool AttachToTargetInternal(DevToolsAgentHost* host,
                               bool waiting_for_debugger);
diff --git a/content/browser/download/download_browsertest.cc b/content/browser/download/download_browsertest.cc
index 5c470de..5a8281a5 100644
--- a/content/browser/download/download_browsertest.cc
+++ b/content/browser/download/download_browsertest.cc
@@ -2490,6 +2490,27 @@
   ASSERT_TRUE(origin_two.ShutdownAndWaitUntilComplete());
 }
 
+// Test that the suggested filename for data: URLs works.
+IN_PROC_BROWSER_TEST_F(DownloadContentTest, DownloadAttributeDataUrl) {
+  net::EmbeddedTestServer server;
+  ASSERT_TRUE(server.InitializeAndListen());
+
+  GURL url = server.GetURL(std::string(
+      "/download-attribute.html?target=data:application/octet-stream, ..."));
+  server.ServeFilesFromDirectory(GetTestFilePath("download", ""));
+  server.StartAcceptingConnections();
+
+  NavigateToURLAndWaitForDownload(shell(), url, DownloadItem::COMPLETE);
+
+  std::vector<DownloadItem*> downloads;
+  DownloadManagerForShell(shell())->GetAllDownloads(&downloads);
+  ASSERT_EQ(1u, downloads.size());
+
+  EXPECT_EQ(FILE_PATH_LITERAL("suggested-filename"),
+            downloads[0]->GetTargetFilePath().BaseName().value());
+  ASSERT_TRUE(server.ShutdownAndWaitUntilComplete());
+}
+
 // A request for a non-existent resource should still result in a DownloadItem
 // that's created in an interrupted state.
 IN_PROC_BROWSER_TEST_F(DownloadContentTest, DownloadAttributeServerError) {
diff --git a/content/browser/frame_host/frame_navigation_entry.cc b/content/browser/frame_host/frame_navigation_entry.cc
index 3a46ef6f..947ee988 100644
--- a/content/browser/frame_host/frame_navigation_entry.cc
+++ b/content/browser/frame_host/frame_navigation_entry.cc
@@ -97,8 +97,7 @@
   document_sequence_number_ = exploded_state.top.document_sequence_number;
 }
 
-scoped_refptr<ResourceRequestBodyImpl> FrameNavigationEntry::GetPostData()
-    const {
+scoped_refptr<ResourceRequestBody> FrameNavigationEntry::GetPostData() const {
   if (method_ != "POST")
     return nullptr;
 
diff --git a/content/browser/frame_host/frame_navigation_entry.h b/content/browser/frame_host/frame_navigation_entry.h
index eca2712..443dec47 100644
--- a/content/browser/frame_host/frame_navigation_entry.h
+++ b/content/browser/frame_host/frame_navigation_entry.h
@@ -10,9 +10,9 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "content/browser/site_instance_impl.h"
-#include "content/common/resource_request_body_impl.h"
 #include "content/public/common/page_state.h"
 #include "content/public/common/referrer.h"
+#include "content/public/common/resource_request_body.h"
 
 namespace content {
 
@@ -132,7 +132,7 @@
 
   // The data sent during a POST navigation. Returns nullptr if the navigation
   // is not a POST.
-  scoped_refptr<ResourceRequestBodyImpl> GetPostData() const;
+  scoped_refptr<ResourceRequestBody> GetPostData() const;
 
  private:
   friend class base::RefCounted<FrameNavigationEntry>;
diff --git a/content/browser/frame_host/navigation_entry_impl.cc b/content/browser/frame_host/navigation_entry_impl.cc
index 4c3ffa73..b9e02560 100644
--- a/content/browser/frame_host/navigation_entry_impl.cc
+++ b/content/browser/frame_host/navigation_entry_impl.cc
@@ -19,7 +19,6 @@
 #include "content/common/content_constants_internal.h"
 #include "content/common/navigation_params.h"
 #include "content/common/page_state_serialization.h"
-#include "content/common/resource_request_body_impl.h"
 #include "content/common/site_isolation_policy.h"
 #include "content/public/browser/reload_type.h"
 #include "content/public/common/browser_side_navigation_policy.h"
@@ -490,7 +489,7 @@
 
 void NavigationEntryImpl::SetPostData(
     const scoped_refptr<ResourceRequestBody>& data) {
-  post_data_ = static_cast<ResourceRequestBodyImpl*>(data.get());
+  post_data_ = static_cast<ResourceRequestBody*>(data.get());
 }
 
 scoped_refptr<ResourceRequestBody> NavigationEntryImpl::GetPostData() const {
@@ -657,7 +656,7 @@
 
 CommonNavigationParams NavigationEntryImpl::ConstructCommonNavigationParams(
     const FrameNavigationEntry& frame_entry,
-    const scoped_refptr<ResourceRequestBodyImpl>& post_body,
+    const scoped_refptr<ResourceRequestBody>& post_body,
     const GURL& dest_url,
     const Referrer& dest_referrer,
     FrameMsg_Navigate_Type::Value navigation_type,
diff --git a/content/browser/frame_host/navigation_entry_impl.h b/content/browser/frame_host/navigation_entry_impl.h
index a102742a..83f058ed 100644
--- a/content/browser/frame_host/navigation_entry_impl.h
+++ b/content/browser/frame_host/navigation_entry_impl.h
@@ -19,7 +19,6 @@
 #include "content/browser/frame_host/frame_tree_node.h"
 #include "content/browser/site_instance_impl.h"
 #include "content/common/frame_message_enums.h"
-#include "content/common/resource_request_body_impl.h"
 #include "content/public/browser/favicon_status.h"
 #include "content/public/browser/global_request_id.h"
 #include "content/public/browser/navigation_entry.h"
@@ -28,9 +27,10 @@
 #include "content/public/browser/ssl_status.h"
 #include "content/public/common/page_state.h"
 #include "content/public/common/previews_state.h"
+#include "content/public/common/resource_request_body.h"
 
 namespace content {
-class ResourceRequestBodyImpl;
+class ResourceRequestBody;
 struct CommonNavigationParams;
 struct RequestNavigationParams;
 struct StartNavigationParams;
@@ -178,7 +178,7 @@
   // NavigationEntry.
   CommonNavigationParams ConstructCommonNavigationParams(
       const FrameNavigationEntry& frame_entry,
-      const scoped_refptr<ResourceRequestBodyImpl>& post_body,
+      const scoped_refptr<ResourceRequestBody>& post_body,
       const GURL& dest_url,
       const Referrer& dest_referrer,
       FrameMsg_Navigate_Type::Value navigation_type,
@@ -456,7 +456,7 @@
   // If the post request succeeds, this field is cleared since the same
   // information is stored in PageState. It is also only shallow copied with
   // compiler provided copy constructor.  Cleared in |ResetForCommit|.
-  scoped_refptr<ResourceRequestBodyImpl> post_data_;
+  scoped_refptr<ResourceRequestBody> post_data_;
 
   // This is also a transient member (i.e. is not persisted with session
   // restore). The screenshot of a page is taken when navigating away from the
diff --git a/content/browser/frame_host/navigation_handle_impl.cc b/content/browser/frame_host/navigation_handle_impl.cc
index cb8deac..789bf9b 100644
--- a/content/browser/frame_host/navigation_handle_impl.cc
+++ b/content/browser/frame_host/navigation_handle_impl.cc
@@ -27,13 +27,13 @@
 #include "content/browser/service_worker/service_worker_navigation_handle.h"
 #include "content/common/child_process_host_impl.h"
 #include "content/common/frame_messages.h"
-#include "content/common/resource_request_body_impl.h"
 #include "content/common/site_isolation_policy.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/navigation_ui_data.h"
 #include "content/public/browser/site_instance.h"
 #include "content/public/common/browser_side_navigation_policy.h"
 #include "content/public/common/content_client.h"
+#include "content/public/common/resource_request_body.h"
 #include "content/public/common/url_constants.h"
 #include "net/base/net_errors.h"
 #include "net/url_request/redirect_info.h"
@@ -424,13 +424,13 @@
     bool is_external_protocol) {
   NavigationThrottle::ThrottleCheckResult result = NavigationThrottle::DEFER;
 
-  scoped_refptr<ResourceRequestBodyImpl> resource_request_body;
+  scoped_refptr<ResourceRequestBody> resource_request_body;
   std::string method = "GET";
   if (is_post) {
     method = "POST";
 
     std::string body = "test=body";
-    resource_request_body = new ResourceRequestBodyImpl();
+    resource_request_body = new ResourceRequestBody();
     resource_request_body->AppendBytes(body.data(), body.size());
   }
 
@@ -552,7 +552,7 @@
 
 void NavigationHandleImpl::WillStartRequest(
     const std::string& method,
-    scoped_refptr<content::ResourceRequestBodyImpl> resource_request_body,
+    scoped_refptr<content::ResourceRequestBody> resource_request_body,
     const Referrer& sanitized_referrer,
     bool has_user_gesture,
     ui::PageTransition transition,
diff --git a/content/browser/frame_host/navigation_handle_impl.h b/content/browser/frame_host/navigation_handle_impl.h
index f98451b..03ebb11 100644
--- a/content/browser/frame_host/navigation_handle_impl.h
+++ b/content/browser/frame_host/navigation_handle_impl.h
@@ -38,7 +38,7 @@
 class ChromeAppCacheService;
 class NavigationUIData;
 class NavigatorDelegate;
-class ResourceRequestBodyImpl;
+class ResourceRequestBody;
 class ServiceWorkerContextWrapper;
 class ServiceWorkerNavigationHandle;
 
@@ -239,7 +239,7 @@
   // Returns the POST body associated with this navigation.  This will be
   // null for GET and/or other non-POST requests (or if a response to a POST
   // request was a redirect that changed the method to GET - for example 302).
-  const scoped_refptr<ResourceRequestBodyImpl>& resource_request_body() const {
+  const scoped_refptr<ResourceRequestBody>& resource_request_body() const {
     return resource_request_body_;
   }
 
@@ -264,7 +264,7 @@
   // the caller to cancel the navigation or let it proceed.
   void WillStartRequest(
       const std::string& method,
-      scoped_refptr<content::ResourceRequestBodyImpl> resource_request_body,
+      scoped_refptr<content::ResourceRequestBody> resource_request_body,
       const Referrer& sanitized_referrer,
       bool has_user_gesture,
       ui::PageTransition transition,
@@ -465,7 +465,7 @@
   // The POST body associated with this navigation.  This will be null for GET
   // and/or other non-POST requests (or if a response to a POST request was a
   // redirect that changed the method to GET - for example 302).
-  scoped_refptr<ResourceRequestBodyImpl> resource_request_body_;
+  scoped_refptr<ResourceRequestBody> resource_request_body_;
 
   // The state the navigation is in.
   State state_;
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc
index 95bc35f..dfdff523 100644
--- a/content/browser/frame_host/navigation_request.cc
+++ b/content/browser/frame_host/navigation_request.cc
@@ -26,7 +26,6 @@
 #include "content/browser/service_worker/service_worker_navigation_handle.h"
 #include "content/browser/site_instance_impl.h"
 #include "content/common/appcache_interfaces.h"
-#include "content/common/resource_request_body_impl.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/content_browser_client.h"
@@ -41,6 +40,7 @@
 #include "content/public/common/content_client.h"
 #include "content/public/common/origin_util.h"
 #include "content/public/common/request_context_type.h"
+#include "content/public/common/resource_request_body.h"
 #include "content/public/common/resource_response.h"
 #include "content/public/common/url_constants.h"
 #include "content/public/common/web_preferences.h"
@@ -200,13 +200,13 @@
     PreviewsState previews_state,
     bool is_same_document_history_load,
     bool is_history_navigation_in_new_child,
-    const scoped_refptr<ResourceRequestBodyImpl>& post_body,
+    const scoped_refptr<ResourceRequestBody>& post_body,
     const base::TimeTicks& navigation_start,
     NavigationControllerImpl* controller) {
   // A form submission happens either because the navigation is a
   // renderer-initiated form submission that took the OpenURL path or a
   // back/forward/reload navigation the does a form resubmission.
-  scoped_refptr<ResourceRequestBodyImpl> request_body;
+  scoped_refptr<ResourceRequestBody> request_body;
   if (post_body) {
     // Standard form submission from the renderer.
     request_body = post_body;
diff --git a/content/browser/frame_host/navigation_request.h b/content/browser/frame_host/navigation_request.h
index a4b2e01..27568dc 100644
--- a/content/browser/frame_host/navigation_request.h
+++ b/content/browser/frame_host/navigation_request.h
@@ -83,7 +83,7 @@
       PreviewsState previews_state,
       bool is_same_document_history_load,
       bool is_history_navigation_in_new_child,
-      const scoped_refptr<ResourceRequestBodyImpl>& post_body,
+      const scoped_refptr<ResourceRequestBody>& post_body,
       const base::TimeTicks& navigation_start,
       NavigationControllerImpl* controller);
 
diff --git a/content/browser/frame_host/navigation_request_info.h b/content/browser/frame_host/navigation_request_info.h
index ce81bb8..cdfc8dc 100644
--- a/content/browser/frame_host/navigation_request_info.h
+++ b/content/browser/frame_host/navigation_request_info.h
@@ -10,7 +10,6 @@
 #include "base/memory/ref_counted.h"
 #include "content/common/content_export.h"
 #include "content/common/navigation_params.h"
-#include "content/common/resource_request_body_impl.h"
 #include "content/public/common/referrer.h"
 #include "third_party/WebKit/public/platform/WebPageVisibilityState.h"
 #include "url/gurl.h"
diff --git a/content/browser/frame_host/navigator.cc b/content/browser/frame_host/navigator.cc
index aee61f6..c1fc47b 100644
--- a/content/browser/frame_host/navigator.cc
+++ b/content/browser/frame_host/navigator.cc
@@ -5,7 +5,6 @@
 #include "content/browser/frame_host/navigator.h"
 
 #include "base/time/time.h"
-#include "content/common/resource_request_body_impl.h"
 #include "content/public/browser/stream_handle.h"
 
 namespace content {
diff --git a/content/browser/frame_host/navigator.h b/content/browser/frame_host/navigator.h
index c21d286..76148e6 100644
--- a/content/browser/frame_host/navigator.h
+++ b/content/browser/frame_host/navigator.h
@@ -28,7 +28,7 @@
 class FrameTreeNode;
 class NavigationRequest;
 class RenderFrameHostImpl;
-class ResourceRequestBodyImpl;
+class ResourceRequestBody;
 struct BeginNavigationParams;
 struct CommonNavigationParams;
 
@@ -118,7 +118,7 @@
       RenderFrameHostImpl* render_frame_host,
       const GURL& url,
       bool uses_post,
-      const scoped_refptr<ResourceRequestBodyImpl>& body,
+      const scoped_refptr<ResourceRequestBody>& body,
       const std::string& extra_headers,
       const Referrer& referrer,
       WindowOpenDisposition disposition,
@@ -141,7 +141,7 @@
       const GlobalRequestID& transferred_global_request_id,
       bool should_replace_current_entry,
       const std::string& method,
-      scoped_refptr<ResourceRequestBodyImpl> post_body,
+      scoped_refptr<ResourceRequestBody> post_body,
       const std::string& extra_headers) {}
 
   // PlzNavigate
diff --git a/content/browser/frame_host/navigator_impl.cc b/content/browser/frame_host/navigator_impl.cc
index 9f9285ee..e7f78f4 100644
--- a/content/browser/frame_host/navigator_impl.cc
+++ b/content/browser/frame_host/navigator_impl.cc
@@ -307,7 +307,7 @@
     bool is_same_document_history_load,
     bool is_history_navigation_in_new_child,
     bool is_pending_entry,
-    const scoped_refptr<ResourceRequestBodyImpl>& post_body) {
+    const scoped_refptr<ResourceRequestBody>& post_body) {
   TRACE_EVENT0("browser,navigation", "NavigatorImpl::NavigateToEntry");
 
   GURL dest_url = frame_entry.url();
@@ -719,7 +719,7 @@
     RenderFrameHostImpl* render_frame_host,
     const GURL& url,
     bool uses_post,
-    const scoped_refptr<ResourceRequestBodyImpl>& body,
+    const scoped_refptr<ResourceRequestBody>& body,
     const std::string& extra_headers,
     const Referrer& referrer,
     WindowOpenDisposition disposition,
@@ -816,7 +816,7 @@
     const GlobalRequestID& transferred_global_request_id,
     bool should_replace_current_entry,
     const std::string& method,
-    scoped_refptr<ResourceRequestBodyImpl> post_body,
+    scoped_refptr<ResourceRequestBody> post_body,
     const std::string& extra_headers) {
   // |method != "POST"| should imply absence of |post_body|.
   if (method != "POST" && post_body) {
@@ -1138,7 +1138,7 @@
     PreviewsState previews_state,
     bool is_same_document_history_load,
     bool is_history_navigation_in_new_child,
-    const scoped_refptr<ResourceRequestBodyImpl>& post_body,
+    const scoped_refptr<ResourceRequestBody>& post_body,
     base::TimeTicks navigation_start) {
   CHECK(IsBrowserSideNavigationEnabled());
   DCHECK(frame_tree_node);
diff --git a/content/browser/frame_host/navigator_impl.h b/content/browser/frame_host/navigator_impl.h
index 32fabc7..4ada17f 100644
--- a/content/browser/frame_host/navigator_impl.h
+++ b/content/browser/frame_host/navigator_impl.h
@@ -23,7 +23,7 @@
 
 class NavigationControllerImpl;
 class NavigatorDelegate;
-class ResourceRequestBodyImpl;
+class ResourceRequestBody;
 struct LoadCommittedDetails;
 
 // This class is an implementation of Navigator, responsible for managing
@@ -68,7 +68,7 @@
       RenderFrameHostImpl* render_frame_host,
       const GURL& url,
       bool uses_post,
-      const scoped_refptr<ResourceRequestBodyImpl>& body,
+      const scoped_refptr<ResourceRequestBody>& body,
       const std::string& extra_headers,
       const Referrer& referrer,
       WindowOpenDisposition disposition,
@@ -85,7 +85,7 @@
                           const GlobalRequestID& transferred_global_request_id,
                           bool should_replace_current_entry,
                           const std::string& method,
-                          scoped_refptr<ResourceRequestBodyImpl> post_body,
+                          scoped_refptr<ResourceRequestBody> post_body,
                           const std::string& extra_headers) override;
   void OnBeforeUnloadACK(FrameTreeNode* frame_tree_node,
                          bool proceed,
@@ -120,25 +120,24 @@
                        bool is_same_document_history_load,
                        bool is_history_navigation_in_new_child,
                        bool is_pending_entry,
-                       const scoped_refptr<ResourceRequestBodyImpl>& post_body);
+                       const scoped_refptr<ResourceRequestBody>& post_body);
 
   bool ShouldAssignSiteForURL(const GURL& url);
 
   // PlzNavigate: if needed, sends a BeforeUnload IPC to the renderer to ask it
   // to execute the beforeUnload event. Otherwise, the navigation request will
   // be started.
-  void RequestNavigation(
-      FrameTreeNode* frame_tree_node,
-      const GURL& dest_url,
-      const Referrer& dest_referrer,
-      const FrameNavigationEntry& frame_entry,
-      const NavigationEntryImpl& entry,
-      ReloadType reload_type,
-      PreviewsState previews_state,
-      bool is_same_document_history_load,
-      bool is_history_navigation_in_new_child,
-      const scoped_refptr<ResourceRequestBodyImpl>& post_body,
-      base::TimeTicks navigation_start);
+  void RequestNavigation(FrameTreeNode* frame_tree_node,
+                         const GURL& dest_url,
+                         const Referrer& dest_referrer,
+                         const FrameNavigationEntry& frame_entry,
+                         const NavigationEntryImpl& entry,
+                         ReloadType reload_type,
+                         PreviewsState previews_state,
+                         bool is_same_document_history_load,
+                         bool is_history_navigation_in_new_child,
+                         const scoped_refptr<ResourceRequestBody>& post_body,
+                         base::TimeTicks navigation_start);
 
   void RecordNavigationMetrics(
       const LoadCommittedDetails& details,
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index bb9ac746..b352e00 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -3712,7 +3712,7 @@
 }
 
 void RenderFrameHostImpl::GrantFileAccessFromResourceRequestBody(
-    const ResourceRequestBodyImpl& body) {
+    const ResourceRequestBody& body) {
   GrantFileAccess(GetProcess()->GetID(), body.GetReferencedFiles());
 }
 
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index 58b1813b..9a1a5ac 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -866,8 +866,7 @@
   // |body|.  It is important that the ResourceRequestBody has been validated
   // upon receipt from the renderer process to prevent it from forging access to
   // files without the user's consent.
-  void GrantFileAccessFromResourceRequestBody(
-      const ResourceRequestBodyImpl& body);
+  void GrantFileAccessFromResourceRequestBody(const ResourceRequestBody& body);
 
   void UpdatePermissionsForNavigation(
       const CommonNavigationParams& common_params,
diff --git a/content/browser/frame_host/render_widget_host_view_child_frame.cc b/content/browser/frame_host/render_widget_host_view_child_frame.cc
index 0e0e30a2..d2d540f 100644
--- a/content/browser/frame_host/render_widget_host_view_child_frame.cc
+++ b/content/browser/frame_host/render_widget_host_view_child_frame.cc
@@ -18,7 +18,6 @@
 #include "cc/surfaces/compositor_frame_sink_support.h"
 #include "cc/surfaces/surface.h"
 #include "cc/surfaces/surface_manager.h"
-#include "components/viz/host/host_frame_sink_manager.h"
 #include "content/browser/accessibility/browser_accessibility_manager.h"
 #include "content/browser/browser_plugin/browser_plugin_guest.h"
 #include "content/browser/compositor/surface_utils.h"
@@ -107,8 +106,8 @@
   if (frame_connector_) {
     if (parent_frame_sink_id_.is_valid() &&
         !service_manager::ServiceManagerIsRemote()) {
-      GetHostFrameSinkManager()->UnregisterFrameSinkHierarchy(
-          parent_frame_sink_id_, frame_sink_id_);
+      GetSurfaceManager()->UnregisterFrameSinkHierarchy(parent_frame_sink_id_,
+                                                        frame_sink_id_);
     }
     parent_frame_sink_id_ = cc::FrameSinkId();
     local_surface_id_ = cc::LocalSurfaceId();
@@ -125,8 +124,8 @@
       parent_frame_sink_id_ = parent_view->GetFrameSinkId();
       DCHECK(parent_frame_sink_id_.is_valid());
       if (!service_manager::ServiceManagerIsRemote()) {
-        GetHostFrameSinkManager()->RegisterFrameSinkHierarchy(
-            parent_frame_sink_id_, frame_sink_id_);
+        GetSurfaceManager()->RegisterFrameSinkHierarchy(parent_frame_sink_id_,
+                                                        frame_sink_id_);
       }
     }
 
@@ -421,7 +420,7 @@
 }
 
 void RenderWidgetHostViewChildFrame::DidReceiveCompositorFrameAck(
-    const cc::ReturnedResourceArray& resources) {
+    const std::vector<cc::ReturnedResource>& resources) {
   renderer_compositor_frame_sink_->DidReceiveCompositorFrameAck(resources);
 }
 
@@ -729,7 +728,7 @@
 }
 
 void RenderWidgetHostViewChildFrame::ReclaimResources(
-    const cc::ReturnedResourceArray& resources) {
+    const std::vector<cc::ReturnedResource>& resources) {
   renderer_compositor_frame_sink_->ReclaimResources(resources);
 }
 
@@ -806,7 +805,7 @@
 
 cc::SurfaceId RenderWidgetHostViewChildFrame::SurfaceIdForTesting() const {
   return cc::SurfaceId(frame_sink_id_, local_surface_id_);
-}
+};
 
 void RenderWidgetHostViewChildFrame::CreateCompositorFrameSinkSupport() {
   if (service_manager::ServiceManagerIsRemote())
@@ -820,8 +819,8 @@
       this, GetSurfaceManager(), frame_sink_id_, is_root,
       handles_frame_sink_id_invalidation, needs_sync_points);
   if (parent_frame_sink_id_.is_valid()) {
-    GetHostFrameSinkManager()->RegisterFrameSinkHierarchy(parent_frame_sink_id_,
-                                                          frame_sink_id_);
+    GetSurfaceManager()->RegisterFrameSinkHierarchy(parent_frame_sink_id_,
+                                                    frame_sink_id_);
   }
   if (host_->needs_begin_frames())
     support_->SetNeedsBeginFrame(true);
@@ -831,8 +830,8 @@
   if (!support_)
     return;
   if (parent_frame_sink_id_.is_valid()) {
-    GetHostFrameSinkManager()->UnregisterFrameSinkHierarchy(
-        parent_frame_sink_id_, frame_sink_id_);
+    GetSurfaceManager()->UnregisterFrameSinkHierarchy(parent_frame_sink_id_,
+                                                      frame_sink_id_);
   }
   support_.reset();
 }
diff --git a/content/browser/frame_host/render_widget_host_view_child_frame.h b/content/browser/frame_host/render_widget_host_view_child_frame.h
index 30be4ba6..0d382b7 100644
--- a/content/browser/frame_host/render_widget_host_view_child_frame.h
+++ b/content/browser/frame_host/render_widget_host_view_child_frame.h
@@ -173,9 +173,10 @@
 
   // cc::CompositorFrameSinkSupportClient implementation.
   void DidReceiveCompositorFrameAck(
-      const cc::ReturnedResourceArray& resources) override;
+      const std::vector<cc::ReturnedResource>& resources) override;
   void OnBeginFrame(const cc::BeginFrameArgs& args) override;
-  void ReclaimResources(const cc::ReturnedResourceArray& resources) override;
+  void ReclaimResources(
+      const std::vector<cc::ReturnedResource>& resources) override;
   void WillDrawSurface(const cc::LocalSurfaceId& id,
                        const gfx::Rect& damage_rect) override {}
 
diff --git a/content/browser/gpu/browser_gpu_memory_buffer_manager.cc b/content/browser/gpu/browser_gpu_memory_buffer_manager.cc
index 9db43c7..9331063 100644
--- a/content/browser/gpu/browser_gpu_memory_buffer_manager.cc
+++ b/content/browser/gpu/browser_gpu_memory_buffer_manager.cc
@@ -17,13 +17,10 @@
 #include "build/build_config.h"
 #include "content/browser/gpu/gpu_process_host.h"
 #include "content/common/child_process_host_impl.h"
-#include "content/common/generic_shared_memory_id_generator.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/common/content_switches.h"
-#include "gpu/GLES2/gl2extchromium.h"
 #include "gpu/ipc/client/gpu_memory_buffer_impl.h"
 #include "gpu/ipc/client/gpu_memory_buffer_impl_shared_memory.h"
-#include "gpu/ipc/common/gpu_memory_buffer_support.h"
 #include "ui/gfx/buffer_format_util.h"
 #include "ui/gfx/gpu_memory_buffer_tracing.h"
 #include "ui/gl/gl_switches.h"
@@ -262,8 +259,7 @@
     CreateGpuMemoryBufferRequest* request) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
-  gfx::GpuMemoryBufferId new_id = content::GetNextGenericSharedMemoryId();
-
+  gfx::GpuMemoryBufferId new_id(next_gpu_memory_id_++);
   // Use service side allocation for native configurations.
   if (IsNativeGpuMemoryBufferConfiguration(request->format, request->usage)) {
     // Note: Unretained is safe as this is only used for synchronous allocation
diff --git a/content/browser/gpu/browser_gpu_memory_buffer_manager.h b/content/browser/gpu/browser_gpu_memory_buffer_manager.h
index a58d5931..a6c05b73 100644
--- a/content/browser/gpu/browser_gpu_memory_buffer_manager.h
+++ b/content/browser/gpu/browser_gpu_memory_buffer_manager.h
@@ -123,6 +123,7 @@
   const gpu::GpuMemoryBufferConfigurationSet native_configurations_;
   const int gpu_client_id_;
   const uint64_t gpu_client_tracing_id_;
+  int next_gpu_memory_id_ = 1;
 
   // Stores info about buffers for all clients. This should only be accessed
   // on the IO thread.
diff --git a/content/browser/loader/DEPS b/content/browser/loader/DEPS
index 6a53b48c..dd055ee 100644
--- a/content/browser/loader/DEPS
+++ b/content/browser/loader/DEPS
@@ -127,7 +127,6 @@
     "+content/browser/loader/throttling_resource_handler.h",
     "+content/browser/loader/wake_lock_resource_throttle.h",
     "+content/common/resource_request_body.h",
-    "+content/common/resource_request_body_impl.h",
     "+content/common/url_loader.mojom.h",
     "+content/public/browser/global_request_id.h",
     "+content/public/browser/resource_dispatcher_host.h",
@@ -135,6 +134,7 @@
     "+content/public/browser/resource_request_info.h",
     "+content/public/browser/resource_throttle.h",
     "+content/public/common/previews_state.h",
+    "+content/public/common/resource_request_body.h",
 
     # TODO: These all have to be removed.
     "+content/browser/appcache/appcache_interceptor.h",
@@ -230,12 +230,12 @@
     "+content/browser/loader/resource_request_info_impl.h",
     "+content/browser/loader/resource_requester_info.h",
     "+content/common/content_export.h",
-    "+content/common/resource_request_body_impl.h",
     "+content/common/url_loader.mojom.h",
     "+content/public/browser/global_request_id.h",
     "+content/public/browser/resource_request_info.h",
     "+content/public/common/previews_state.h",
     "+content/public/common/referrer.h",
+    "+content/public/common/resource_request_body.h",
     "+content/public/common/resource_type.h",
 
     # TODO: these all have to be removed.
diff --git a/content/browser/loader/navigation_resource_throttle.cc b/content/browser/loader/navigation_resource_throttle.cc
index dcdceae..950ffe2b 100644
--- a/content/browser/loader/navigation_resource_throttle.cc
+++ b/content/browser/loader/navigation_resource_throttle.cc
@@ -93,8 +93,7 @@
     int render_process_id,
     int render_frame_host_id,
     const std::string& method,
-    const scoped_refptr<content::ResourceRequestBodyImpl>&
-        resource_request_body,
+    const scoped_refptr<content::ResourceRequestBody>& resource_request_body,
     const Referrer& sanitized_referrer,
     bool has_user_gesture,
     ui::PageTransition transition,
diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc
index 0bfe5f2..e1e9112 100644
--- a/content/browser/loader/resource_dispatcher_host_impl.cc
+++ b/content/browser/loader/resource_dispatcher_host_impl.cc
@@ -75,7 +75,6 @@
 #include "content/common/net/url_request_service_worker_data.h"
 #include "content/common/resource_messages.h"
 #include "content/common/resource_request.h"
-#include "content/common/resource_request_body_impl.h"
 #include "content/common/resource_request_completion_status.h"
 #include "content/common/site_isolation_policy.h"
 #include "content/common/view_messages.h"
@@ -91,6 +90,7 @@
 #include "content/public/common/browser_side_navigation_policy.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
+#include "content/public/common/resource_request_body.h"
 #include "ipc/ipc_message_macros.h"
 #include "ipc/ipc_message_start.h"
 #include "net/base/auth.h"
@@ -2116,7 +2116,7 @@
       GetChromeBlobStorageContextForResourceContext(resource_context));
 
   // Resolve elements from request_body and prepare upload data.
-  ResourceRequestBodyImpl* body = info.common_params.post_data.get();
+  ResourceRequestBody* body = info.common_params.post_data.get();
   BlobHandles blob_handles;
   if (body) {
     if (!GetBodyBlobDataHandles(body, resource_context, &blob_handles)) {
diff --git a/content/browser/loader/resource_request_info_impl.cc b/content/browser/loader/resource_request_info_impl.cc
index 439278d..f81f45fe 100644
--- a/content/browser/loader/resource_request_info_impl.cc
+++ b/content/browser/loader/resource_request_info_impl.cc
@@ -150,7 +150,7 @@
     bool report_raw_headers,
     bool is_async,
     PreviewsState previews_state,
-    const scoped_refptr<ResourceRequestBodyImpl> body,
+    const scoped_refptr<ResourceRequestBody> body,
     bool initiated_in_secure_context)
     : detachable_handler_(NULL),
       requester_info_(std::move(requester_info)),
diff --git a/content/browser/loader/resource_request_info_impl.h b/content/browser/loader/resource_request_info_impl.h
index 5aabe8bc..e03a6876 100644
--- a/content/browser/loader/resource_request_info_impl.h
+++ b/content/browser/loader/resource_request_info_impl.h
@@ -16,12 +16,12 @@
 #include "base/supports_user_data.h"
 #include "content/browser/blob_storage/chrome_blob_storage_context.h"
 #include "content/browser/loader/resource_requester_info.h"
-#include "content/common/resource_request_body_impl.h"
 #include "content/common/url_loader.mojom.h"
 #include "content/public/browser/navigation_ui_data.h"
 #include "content/public/browser/resource_request_info.h"
 #include "content/public/common/previews_state.h"
 #include "content/public/common/referrer.h"
+#include "content/public/common/resource_request_body.h"
 #include "content/public/common/resource_type.h"
 #include "net/base/load_states.h"
 
@@ -73,7 +73,7 @@
       bool report_raw_headers,
       bool is_async,
       PreviewsState previews_state,
-      const scoped_refptr<ResourceRequestBodyImpl> body,
+      const scoped_refptr<ResourceRequestBody> body,
       bool initiated_in_secure_context);
   ~ResourceRequestInfoImpl() override;
 
@@ -115,7 +115,9 @@
   // request).
   int frame_tree_node_id() const { return frame_tree_node_id_; }
 
-  ResourceRequesterInfo* requester_info() { return requester_info_.get(); }
+  ResourceRequesterInfo* requester_info() const {
+    return requester_info_.get();
+  }
 
   // Updates the data associated with this request after it is is transferred
   // to a new renderer process.  Not all data will change during a transfer.
@@ -182,7 +184,7 @@
     do_not_prompt_for_login_ = do_not_prompt;
   }
 
-  const scoped_refptr<ResourceRequestBodyImpl>& body() const { return body_; }
+  const scoped_refptr<ResourceRequestBody>& body() const { return body_; }
   void ResetBody();
 
   bool initiated_in_secure_context() const {
@@ -238,7 +240,7 @@
   bool report_raw_headers_;
   bool is_async_;
   PreviewsState previews_state_;
-  scoped_refptr<ResourceRequestBodyImpl> body_;
+  scoped_refptr<ResourceRequestBody> body_;
   bool initiated_in_secure_context_;
   std::unique_ptr<NavigationUIData> navigation_ui_data_;
 
diff --git a/content/browser/loader/upload_data_stream_builder.cc b/content/browser/loader/upload_data_stream_builder.cc
index 389a8e9..b830ba52 100644
--- a/content/browser/loader/upload_data_stream_builder.cc
+++ b/content/browser/loader/upload_data_stream_builder.cc
@@ -16,7 +16,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/single_thread_task_runner.h"
 #include "content/browser/fileapi/upload_file_system_file_element_reader.h"
-#include "content/common/resource_request_body_impl.h"
+#include "content/public/common/resource_request_body.h"
 #include "net/base/elements_upload_data_stream.h"
 #include "net/base/upload_bytes_element_reader.h"
 #include "net/base/upload_file_element_reader.h"
@@ -37,46 +37,46 @@
 namespace {
 
 // A subclass of net::UploadBytesElementReader which owns
-// ResourceRequestBodyImpl.
+// ResourceRequestBody.
 class BytesElementReader : public net::UploadBytesElementReader {
  public:
-  BytesElementReader(ResourceRequestBodyImpl* resource_request_body,
-                     const ResourceRequestBodyImpl::Element& element)
+  BytesElementReader(ResourceRequestBody* resource_request_body,
+                     const ResourceRequestBody::Element& element)
       : net::UploadBytesElementReader(element.bytes(), element.length()),
         resource_request_body_(resource_request_body) {
-    DCHECK_EQ(ResourceRequestBodyImpl::Element::TYPE_BYTES, element.type());
+    DCHECK_EQ(ResourceRequestBody::Element::TYPE_BYTES, element.type());
   }
 
   ~BytesElementReader() override {}
 
  private:
-  scoped_refptr<ResourceRequestBodyImpl> resource_request_body_;
+  scoped_refptr<ResourceRequestBody> resource_request_body_;
 
   DISALLOW_COPY_AND_ASSIGN(BytesElementReader);
 };
 
 // A subclass of net::UploadFileElementReader which owns
-// ResourceRequestBodyImpl.
+// ResourceRequestBody.
 // This class is necessary to ensure the BlobData and any attached shareable
 // files survive until upload completion.
 class FileElementReader : public net::UploadFileElementReader {
  public:
-  FileElementReader(ResourceRequestBodyImpl* resource_request_body,
+  FileElementReader(ResourceRequestBody* resource_request_body,
                     base::TaskRunner* task_runner,
-                    const ResourceRequestBodyImpl::Element& element)
+                    const ResourceRequestBody::Element& element)
       : net::UploadFileElementReader(task_runner,
                                      element.path(),
                                      element.offset(),
                                      element.length(),
                                      element.expected_modification_time()),
         resource_request_body_(resource_request_body) {
-    DCHECK_EQ(ResourceRequestBodyImpl::Element::TYPE_FILE, element.type());
+    DCHECK_EQ(ResourceRequestBody::Element::TYPE_FILE, element.type());
   }
 
   ~FileElementReader() override {}
 
  private:
-  scoped_refptr<ResourceRequestBodyImpl> resource_request_body_;
+  scoped_refptr<ResourceRequestBody> resource_request_body_;
 
   DISALLOW_COPY_AND_ASSIGN(FileElementReader);
 };
@@ -84,22 +84,22 @@
 }  // namespace
 
 std::unique_ptr<net::UploadDataStream> UploadDataStreamBuilder::Build(
-    ResourceRequestBodyImpl* body,
+    ResourceRequestBody* body,
     storage::BlobStorageContext* blob_context,
     storage::FileSystemContext* file_system_context,
     base::SingleThreadTaskRunner* file_task_runner) {
   std::vector<std::unique_ptr<net::UploadElementReader>> element_readers;
   for (const auto& element : *body->elements()) {
     switch (element.type()) {
-      case ResourceRequestBodyImpl::Element::TYPE_BYTES:
+      case ResourceRequestBody::Element::TYPE_BYTES:
         element_readers.push_back(
             base::MakeUnique<BytesElementReader>(body, element));
         break;
-      case ResourceRequestBodyImpl::Element::TYPE_FILE:
+      case ResourceRequestBody::Element::TYPE_FILE:
         element_readers.push_back(base::MakeUnique<FileElementReader>(
             body, file_task_runner, element));
         break;
-      case ResourceRequestBodyImpl::Element::TYPE_FILE_FILESYSTEM:
+      case ResourceRequestBody::Element::TYPE_FILE_FILESYSTEM:
         // If |body| contains any filesystem URLs, the caller should have
         // supplied a FileSystemContext.
         DCHECK(file_system_context);
@@ -108,7 +108,7 @@
                 file_system_context, element.filesystem_url(), element.offset(),
                 element.length(), element.expected_modification_time()));
         break;
-      case ResourceRequestBodyImpl::Element::TYPE_BLOB: {
+      case ResourceRequestBody::Element::TYPE_BLOB: {
         DCHECK_EQ(std::numeric_limits<uint64_t>::max(), element.length());
         DCHECK_EQ(0ul, element.offset());
         std::unique_ptr<storage::BlobDataHandle> handle =
@@ -118,9 +118,9 @@
                 std::move(handle), file_system_context, file_task_runner));
         break;
       }
-      case ResourceRequestBodyImpl::Element::TYPE_DISK_CACHE_ENTRY:
-      case ResourceRequestBodyImpl::Element::TYPE_BYTES_DESCRIPTION:
-      case ResourceRequestBodyImpl::Element::TYPE_UNKNOWN:
+      case ResourceRequestBody::Element::TYPE_DISK_CACHE_ENTRY:
+      case ResourceRequestBody::Element::TYPE_BYTES_DESCRIPTION:
+      case ResourceRequestBody::Element::TYPE_UNKNOWN:
         NOTREACHED();
         break;
     }
diff --git a/content/browser/loader/upload_data_stream_builder.h b/content/browser/loader/upload_data_stream_builder.h
index 9b2bfcb..fae5f3a 100644
--- a/content/browser/loader/upload_data_stream_builder.h
+++ b/content/browser/loader/upload_data_stream_builder.h
@@ -27,7 +27,7 @@
 
 namespace content {
 
-class ResourceRequestBodyImpl;
+class ResourceRequestBody;
 
 class CONTENT_EXPORT UploadDataStreamBuilder {
  public:
@@ -35,14 +35,14 @@
   //
   // If |body| contains any blob references, the caller is responsible for
   // making sure them outlive the returned value of UploadDataStream. We do this
-  // by binding the BlobDataHandles of them to ResourceRequestBodyImpl in
+  // by binding the BlobDataHandles of them to ResourceRequestBody in
   // ResourceDispatcherHostImpl::BeginRequest().
   //
   // |file_system_context| is used to create a FileStreamReader for files with
   // filesystem URLs.  |file_task_runner| is used to perform file operations
   // when the data gets uploaded.
   static std::unique_ptr<net::UploadDataStream> Build(
-      ResourceRequestBodyImpl* body,
+      ResourceRequestBody* body,
       storage::BlobStorageContext* blob_context,
       storage::FileSystemContext* file_system_context,
       base::SingleThreadTaskRunner* file_task_runner);
diff --git a/content/browser/loader/upload_data_stream_builder_unittest.cc b/content/browser/loader/upload_data_stream_builder_unittest.cc
index 26058d7..678cb97 100644
--- a/content/browser/loader/upload_data_stream_builder_unittest.cc
+++ b/content/browser/loader/upload_data_stream_builder_unittest.cc
@@ -16,7 +16,7 @@
 #include "base/run_loop.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
-#include "content/common/resource_request_body_impl.h"
+#include "content/public/common/resource_request_body.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
 #include "net/base/test_completion_callback.h"
@@ -40,8 +40,7 @@
 TEST(UploadDataStreamBuilderTest, CreateUploadDataStream) {
   base::MessageLoop message_loop;
   {
-    scoped_refptr<ResourceRequestBodyImpl> request_body =
-        new ResourceRequestBodyImpl;
+    scoped_refptr<ResourceRequestBody> request_body = new ResourceRequestBody;
 
     const std::string kBlob = "blobuuid";
     const std::string kBlobData = "blobdata";
@@ -119,14 +118,13 @@
     std::unique_ptr<BlobDataHandle> handle =
         blob_storage_context.AddFinishedBlob(blob_data_builder.get());
 
-    scoped_refptr<ResourceRequestBodyImpl> request_body(
-        new ResourceRequestBodyImpl());
+    scoped_refptr<ResourceRequestBody> request_body(new ResourceRequestBody());
     std::unique_ptr<net::UploadDataStream> upload(
         UploadDataStreamBuilder::Build(
             request_body.get(), &blob_storage_context, NULL,
             base::ThreadTaskRunnerHandle::Get().get()));
 
-    request_body = new ResourceRequestBodyImpl();
+    request_body = new ResourceRequestBody();
     request_body->AppendBlob(blob_id);
     request_body->AppendBlob(blob_id);
     request_body->AppendBlob(blob_id);
@@ -165,8 +163,7 @@
 TEST(UploadDataStreamBuilderTest, ResetUploadStreamWithBlob) {
   base::MessageLoopForIO message_loop;
   {
-    scoped_refptr<ResourceRequestBodyImpl> request_body =
-        new ResourceRequestBodyImpl;
+    scoped_refptr<ResourceRequestBody> request_body = new ResourceRequestBody;
 
     const std::string kBlob = "blobuuid";
     const std::string kBlobData = "blobdata";
diff --git a/content/browser/presentation/presentation_service_impl.cc b/content/browser/presentation/presentation_service_impl.cc
index 6fb5641c..c6ed491 100644
--- a/content/browser/presentation/presentation_service_impl.cc
+++ b/content/browser/presentation/presentation_service_impl.cc
@@ -59,8 +59,10 @@
 
   render_process_id_ = render_frame_host->GetProcess()->GetID();
   render_frame_id_ = render_frame_host->GetRoutingID();
-  DVLOG(2) << "PresentationServiceImpl: "
-           << render_process_id_ << ", " << render_frame_id_;
+  is_main_frame_ = !render_frame_host->GetParent();
+
+  DVLOG(2) << "PresentationServiceImpl: " << render_process_id_ << ", "
+           << render_frame_id_ << " is main frame: " << is_main_frame_;
 
   if (auto* delegate = GetPresentationServiceDelegate())
     delegate->AddObserver(render_process_id_, render_frame_id_, this);
@@ -114,7 +116,7 @@
   // TODO(imcheng): Set ErrorHandler to listen for errors.
   client_ = std::move(client);
 
-  if (receiver_delegate_) {
+  if (receiver_delegate_ && is_main_frame_) {
     receiver_delegate_->RegisterReceiverConnectionAvailableCallback(
         base::Bind(&PresentationServiceImpl::OnReceiverConnectionAvailable,
                    weak_factory_.GetWeakPtr()));
@@ -428,8 +430,11 @@
 void PresentationServiceImpl::Reset() {
   DVLOG(2) << "PresentationServiceImpl::Reset";
 
-  if (auto* delegate = GetPresentationServiceDelegate())
-    delegate->Reset(render_process_id_, render_frame_id_);
+  if (controller_delegate_)
+    controller_delegate_->Reset(render_process_id_, render_frame_id_);
+
+  if (receiver_delegate_ && is_main_frame_)
+    receiver_delegate_->Reset(render_process_id_, render_frame_id_);
 
   default_presentation_urls_.clear();
 
diff --git a/content/browser/presentation/presentation_service_impl.h b/content/browser/presentation/presentation_service_impl.h
index c097ad9..4c6393d 100644
--- a/content/browser/presentation/presentation_service_impl.h
+++ b/content/browser/presentation/presentation_service_impl.h
@@ -103,6 +103,8 @@
                            MaxPendingReconnectPresentationRequests);
   FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
                            ReceiverPresentationServiceDelegate);
+  FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
+                           ReceiverDelegateOnSubFrame);
 
   // Maximum number of pending ReconnectPresentation requests at any given time.
   static const int kMaxQueuedRequests = 10;
@@ -278,6 +280,9 @@
   int render_process_id_;
   int render_frame_id_;
 
+  // If current frame is top level frame.
+  bool is_main_frame_;
+
   // NOTE: Weak pointers must be invalidated before all other member variables.
   base::WeakPtrFactory<PresentationServiceImpl> weak_factory_;
 
diff --git a/content/browser/presentation/presentation_service_impl_unittest.cc b/content/browser/presentation/presentation_service_impl_unittest.cc
index d582207..beb33bb4 100644
--- a/content/browser/presentation/presentation_service_impl_unittest.cc
+++ b/content/browser/presentation/presentation_service_impl_unittest.cc
@@ -644,14 +644,13 @@
 }
 
 TEST_F(PresentationServiceImplTest, ReceiverPresentationServiceDelegate) {
-  MockReceiverPresentationServiceDelegate mock_receiver_delegate;
-  EXPECT_CALL(mock_receiver_delegate, AddObserver(_, _, _)).Times(1);
+  EXPECT_CALL(mock_receiver_delegate_, AddObserver(_, _, _)).Times(1);
 
   PresentationServiceImpl service_impl(main_rfh(), contents(), nullptr,
-                                       &mock_receiver_delegate);
+                                       &mock_receiver_delegate_);
 
   ReceiverConnectionAvailableCallback callback;
-  EXPECT_CALL(mock_receiver_delegate,
+  EXPECT_CALL(mock_receiver_delegate_,
               RegisterReceiverConnectionAvailableCallback(_))
       .WillOnce(SaveArg<0>(&callback));
 
@@ -677,7 +676,32 @@
                mojo::MakeRequest(&receiver_connection));
   base::RunLoop().RunUntilIdle();
 
-  EXPECT_CALL(mock_receiver_delegate, RemoveObserver(_, _)).Times(1);
+  EXPECT_CALL(mock_receiver_delegate_, RemoveObserver(_, _)).Times(1);
+}
+
+TEST_F(PresentationServiceImplTest, ReceiverDelegateOnSubFrame) {
+  EXPECT_CALL(mock_receiver_delegate_, AddObserver(_, _, _)).Times(1);
+
+  PresentationServiceImpl service_impl(main_rfh(), contents(), nullptr,
+                                       &mock_receiver_delegate_);
+  service_impl.is_main_frame_ = false;
+
+  ReceiverConnectionAvailableCallback callback;
+  EXPECT_CALL(mock_receiver_delegate_,
+              RegisterReceiverConnectionAvailableCallback(_))
+      .Times(0);
+
+  blink::mojom::PresentationServiceClientPtr client_ptr;
+  client_binding_.reset(
+      new mojo::Binding<blink::mojom::PresentationServiceClient>(
+          &mock_client_, mojo::MakeRequest(&client_ptr)));
+  service_impl.controller_delegate_ = nullptr;
+  service_impl.SetClient(std::move(client_ptr));
+
+  EXPECT_CALL(mock_receiver_delegate_, Reset(_, _)).Times(0);
+  service_impl.Reset();
+
+  EXPECT_CALL(mock_receiver_delegate_, RemoveObserver(_, _)).Times(1);
 }
 
 }  // namespace content
diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc
index ce101b0..e0b8c93 100644
--- a/content/browser/renderer_host/compositor_impl_android.cc
+++ b/content/browser/renderer_host/compositor_impl_android.cc
@@ -890,8 +890,8 @@
 
 void CompositorImpl::AddChildFrameSink(const cc::FrameSinkId& frame_sink_id) {
   if (has_layer_tree_frame_sink_) {
-    GetHostFrameSinkManager()->RegisterFrameSinkHierarchy(frame_sink_id_,
-                                                          frame_sink_id);
+    GetSurfaceManager()->RegisterFrameSinkHierarchy(frame_sink_id_,
+                                                    frame_sink_id);
   } else {
     pending_child_frame_sink_ids_.insert(frame_sink_id);
   }
@@ -904,8 +904,8 @@
     pending_child_frame_sink_ids_.erase(it);
     return;
   }
-  GetHostFrameSinkManager()->UnregisterFrameSinkHierarchy(frame_sink_id_,
-                                                          frame_sink_id);
+  GetSurfaceManager()->UnregisterFrameSinkHierarchy(frame_sink_id_,
+                                                    frame_sink_id);
 }
 
 bool CompositorImpl::HavePendingReadbacks() {
diff --git a/content/browser/renderer_host/delegated_frame_host.cc b/content/browser/renderer_host/delegated_frame_host.cc
index b20728e..383015a 100644
--- a/content/browser/renderer_host/delegated_frame_host.cc
+++ b/content/browser/renderer_host/delegated_frame_host.cc
@@ -411,8 +411,8 @@
       gfx::ConvertRectToDIP(frame_device_scale_factor, damage_rect);
 
   if (ShouldSkipFrame(frame_size_in_dip)) {
-    cc::ReturnedResourceArray resources;
-    cc::TransferableResource::ReturnResources(frame.resource_list, &resources);
+    std::vector<cc::ReturnedResource> resources =
+        cc::TransferableResource::ReturnResources(frame.resource_list);
 
     skipped_latency_info_list_.insert(skipped_latency_info_list_.end(),
                                       frame.metadata.latency_info.begin(),
@@ -500,12 +500,12 @@
 }
 
 void DelegatedFrameHost::DidReceiveCompositorFrameAck(
-    const cc::ReturnedResourceArray& resources) {
+    const std::vector<cc::ReturnedResource>& resources) {
   renderer_compositor_frame_sink_->DidReceiveCompositorFrameAck(resources);
 }
 
 void DelegatedFrameHost::ReclaimResources(
-    const cc::ReturnedResourceArray& resources) {
+    const std::vector<cc::ReturnedResource>& resources) {
   renderer_compositor_frame_sink_->ReclaimResources(resources);
 }
 
diff --git a/content/browser/renderer_host/delegated_frame_host.h b/content/browser/renderer_host/delegated_frame_host.h
index a418dcc7..1a3e82e 100644
--- a/content/browser/renderer_host/delegated_frame_host.h
+++ b/content/browser/renderer_host/delegated_frame_host.h
@@ -110,9 +110,10 @@
 
   // cc::CompositorFrameSinkSupportClient implementation.
   void DidReceiveCompositorFrameAck(
-      const cc::ReturnedResourceArray& resources) override;
+      const std::vector<cc::ReturnedResource>& resources) override;
   void OnBeginFrame(const cc::BeginFrameArgs& args) override;
-  void ReclaimResources(const cc::ReturnedResourceArray& resources) override;
+  void ReclaimResources(
+      const std::vector<cc::ReturnedResource>& resources) override;
   void WillDrawSurface(const cc::LocalSurfaceId& id,
                        const gfx::Rect& damage_rect) override;
 
@@ -282,7 +283,7 @@
   std::unique_ptr<cc::CompositorFrameSinkSupport> support_;
   gfx::Size current_surface_size_;
   float current_scale_factor_;
-  cc::ReturnedResourceArray surface_returned_resources_;
+  std::vector<cc::ReturnedResource> surface_returned_resources_;
 
   // This lock is the one waiting for a frame of the right size to come back
   // from the renderer/GPU process. It is set from the moment the aura window
diff --git a/content/browser/renderer_host/offscreen_canvas_provider_impl_unittest.cc b/content/browser/renderer_host/offscreen_canvas_provider_impl_unittest.cc
index 05246d3..18c4afd4 100644
--- a/content/browser/renderer_host/offscreen_canvas_provider_impl_unittest.cc
+++ b/content/browser/renderer_host/offscreen_canvas_provider_impl_unittest.cc
@@ -81,9 +81,10 @@
  private:
   // cc::mojom::CompositorFrameSinkClient:
   void DidReceiveCompositorFrameAck(
-      const cc::ReturnedResourceArray& resources) override {}
+      const std::vector<cc::ReturnedResource>& resources) override {}
   void OnBeginFrame(const cc::BeginFrameArgs& begin_frame_args) override {}
-  void ReclaimResources(const cc::ReturnedResourceArray& resources) override {}
+  void ReclaimResources(
+      const std::vector<cc::ReturnedResource>& resources) override {}
 
   mojo::Binding<cc::mojom::CompositorFrameSinkClient> binding_;
 
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index d177e31..0b90774 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -2631,8 +2631,8 @@
     view_->SubmitCompositorFrame(local_surface_id, std::move(frame));
     view_->DidReceiveRendererFrame();
   } else {
-    cc::ReturnedResourceArray resources;
-    cc::TransferableResource::ReturnResources(frame.resource_list, &resources);
+    std::vector<cc::ReturnedResource> resources =
+        cc::TransferableResource::ReturnResources(frame.resource_list);
     renderer_compositor_frame_sink_->DidReceiveCompositorFrameAck(resources);
   }
 
diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc
index 4e63e2f0..b11b0aa 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.cc
+++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -1170,7 +1170,7 @@
 }
 
 void RenderWidgetHostViewAndroid::ReclaimResources(
-    const cc::ReturnedResourceArray& resources) {
+    const std::vector<cc::ReturnedResource>& resources) {
   if (resources.empty())
     return;
   std::copy(resources.begin(), resources.end(),
diff --git a/content/browser/renderer_host/render_widget_host_view_android.h b/content/browser/renderer_host/render_widget_host_view_android.h
index c85662a8..df19e6808 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.h
+++ b/content/browser/renderer_host/render_widget_host_view_android.h
@@ -228,7 +228,8 @@
   // DelegatedFrameHostAndroid::Client implementation.
   void SetBeginFrameSource(cc::BeginFrameSource* begin_frame_source) override;
   void DidReceiveCompositorFrameAck() override;
-  void ReclaimResources(const cc::ReturnedResourceArray& resources) override;
+  void ReclaimResources(
+      const std::vector<cc::ReturnedResource>& resources) override;
 
   // cc::BeginFrameObserver implementation.
   void OnBeginFrame(const cc::BeginFrameArgs& args) override;
@@ -393,7 +394,7 @@
   // Manages the Compositor Frames received from the renderer.
   std::unique_ptr<ui::DelegatedFrameHostAndroid> delegated_frame_host_;
 
-  cc::ReturnedResourceArray surface_returned_resources_;
+  std::vector<cc::ReturnedResource> surface_returned_resources_;
 
   // The most recent surface size that was pushed to the surface layer.
   gfx::Size current_surface_size_;
diff --git a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
index 43b4eaf0..96696118b 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
@@ -472,7 +472,7 @@
     return GetDelegatedFrameHost()->ReleasedFrontLockActiveForTesting();
   }
 
-  void ReclaimResources(const cc::ReturnedResourceArray& resources) {
+  void ReclaimResources(const std::vector<cc::ReturnedResource>& resources) {
     GetDelegatedFrameHost()->ReclaimResources(resources);
   }
 
@@ -2377,7 +2377,7 @@
   sink_->ClearMessages();
 
   // Accumulate some returned resources. This should trigger an IPC.
-  cc::ReturnedResourceArray resources;
+  std::vector<cc::ReturnedResource> resources;
   cc::ReturnedResource resource;
   resource.id = 1;
   resources.push_back(resource);
diff --git a/content/browser/renderer_host/render_widget_host_view_event_handler.cc b/content/browser/renderer_host/render_widget_host_view_event_handler.cc
index 213ed4a..5052626 100644
--- a/content/browser/renderer_host/render_widget_host_view_event_handler.cc
+++ b/content/browser/renderer_host/render_widget_host_view_event_handler.cc
@@ -294,6 +294,12 @@
 
 void RenderWidgetHostViewEventHandler::OnMouseEvent(ui::MouseEvent* event) {
   TRACE_EVENT0("input", "RenderWidgetHostViewBase::OnMouseEvent");
+
+  // CrOS will send a mouse exit event to update hover state when mouse is
+  // hidden which we want to filter out in renderer. crbug.com/723535.
+  if (event->flags() & ui::EF_CURSOR_HIDE)
+    return;
+
   ForwardMouseEventToParent(event);
   // TODO(mgiuca): Return if event->handled() returns true. This currently
   // breaks drop-down lists which means something is incorrectly setting
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.mm b/content/browser/renderer_host/render_widget_host_view_mac.mm
index a4d10aa..2d542fb5 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac.mm
+++ b/content/browser/renderer_host/render_widget_host_view_mac.mm
@@ -2454,8 +2454,17 @@
   if (!widgetHost)
     return;
 
+  int32_t targetWidgetProcessId = widgetHost->GetProcess()->GetID();
+  int32_t targetWidgetRoutingId = widgetHost->GetRoutingID();
   TextInputClientMac::GetInstance()->GetStringFromRange(
       widgetHost, range, ^(NSAttributedString* string, NSPoint baselinePoint) {
+        if (!content::RenderWidgetHost::FromID(targetWidgetProcessId,
+                                               targetWidgetRoutingId)) {
+          // By the time we get here |widgetHost| might have been destroyed.
+          // (See https://crbug.com/737032).
+          return;
+        }
+
         if (auto* rwhv = widgetHost->GetView()) {
           gfx::Point pointInRootView = rwhv->TransformPointToRootCoordSpace(
               gfx::Point(baselinePoint.x, baselinePoint.y));
@@ -2485,9 +2494,18 @@
   if (!widgetHost)
     return;
 
+  int32_t targetWidgetProcessId = widgetHost->GetProcess()->GetID();
+  int32_t targetWidgetRoutingId = widgetHost->GetRoutingID();
   TextInputClientMac::GetInstance()->GetStringAtPoint(
       widgetHost, transformedPoint,
       ^(NSAttributedString* string, NSPoint baselinePoint) {
+        if (!content::RenderWidgetHost::FromID(targetWidgetProcessId,
+                                               targetWidgetRoutingId)) {
+          // By the time we get here |widgetHost| might have been destroyed.
+          // (See https://crbug.com/737032).
+          return;
+        }
+
         if (auto* rwhv = widgetHost->GetView()) {
           gfx::Point pointInRootView = rwhv->TransformPointToRootCoordSpace(
               gfx::Point(baselinePoint.x, baselinePoint.y));
diff --git a/content/browser/security_exploit_browsertest.cc b/content/browser/security_exploit_browsertest.cc
index 43f8dc2..d1450ae 100644
--- a/content/browser/security_exploit_browsertest.cc
+++ b/content/browser/security_exploit_browsertest.cc
@@ -34,6 +34,7 @@
 #include "content/public/common/browser_side_navigation_policy.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/file_chooser_params.h"
+#include "content/public/common/resource_request_body.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/content_browser_test.h"
 #include "content/public/test/content_browser_test_utils.h"
@@ -591,7 +592,7 @@
   FrameHostMsg_OpenURL_Params params;
   params.url = target_url;
   params.uses_post = true;
-  params.resource_request_body = new ResourceRequestBodyImpl;
+  params.resource_request_body = new ResourceRequestBody;
   params.resource_request_body->AppendFileRange(
       file_path, 0, file_content.size(), base::Time());
   params.disposition = WindowOpenDisposition::CURRENT_TAB;
diff --git a/content/browser/service_worker/foreign_fetch_request_handler.cc b/content/browser/service_worker/foreign_fetch_request_handler.cc
index 5005b3e..a3dea63 100644
--- a/content/browser/service_worker/foreign_fetch_request_handler.cc
+++ b/content/browser/service_worker/foreign_fetch_request_handler.cc
@@ -14,7 +14,6 @@
 #include "content/browser/service_worker/service_worker_context_wrapper.h"
 #include "content/browser/service_worker/service_worker_response_info.h"
 #include "content/browser/service_worker/service_worker_url_request_job.h"
-#include "content/common/resource_request_body_impl.h"
 #include "content/common/service_worker/service_worker_types.h"
 #include "content/common/service_worker/service_worker_utils.h"
 #include "content/public/browser/content_browser_client.h"
@@ -22,6 +21,7 @@
 #include "content/public/common/content_client.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/origin_trial_policy.h"
+#include "content/public/common/resource_request_body.h"
 #include "net/url_request/url_request.h"
 #include "net/url_request/url_request_interceptor.h"
 #include "storage/browser/blob/blob_storage_context.h"
@@ -79,7 +79,7 @@
     ResourceType resource_type,
     RequestContextType request_context_type,
     RequestContextFrameType frame_type,
-    scoped_refptr<ResourceRequestBodyImpl> body,
+    scoped_refptr<ResourceRequestBody> body,
     bool initiated_in_secure_context) {
   if (!IsForeignFetchEnabled())
     return;
@@ -204,7 +204,7 @@
     ResourceType resource_type,
     RequestContextType request_context_type,
     RequestContextFrameType frame_type,
-    scoped_refptr<ResourceRequestBodyImpl> body,
+    scoped_refptr<ResourceRequestBody> body,
     const base::Optional<base::TimeDelta>& timeout)
     : context_(context),
       blob_storage_context_(blob_storage_context),
diff --git a/content/browser/service_worker/foreign_fetch_request_handler.h b/content/browser/service_worker/foreign_fetch_request_handler.h
index 2283fa9..9ba33da 100644
--- a/content/browser/service_worker/foreign_fetch_request_handler.h
+++ b/content/browser/service_worker/foreign_fetch_request_handler.h
@@ -32,7 +32,7 @@
 namespace content {
 
 class ResourceContext;
-class ResourceRequestBodyImpl;
+class ResourceRequestBody;
 class ServiceWorkerContextWrapper;
 class ServiceWorkerRegistration;
 
@@ -65,7 +65,7 @@
       ResourceType resource_type,
       RequestContextType request_context_type,
       RequestContextFrameType frame_type,
-      scoped_refptr<ResourceRequestBodyImpl> body,
+      scoped_refptr<ResourceRequestBody> body,
       bool initiated_in_secure_context);
 
   // Returns the handler attached to |request|. This may return null
@@ -95,7 +95,7 @@
       ResourceType resource_type,
       RequestContextType request_context_type,
       RequestContextFrameType frame_type,
-      scoped_refptr<ResourceRequestBodyImpl> body,
+      scoped_refptr<ResourceRequestBody> body,
       const base::Optional<base::TimeDelta>& timeout);
 
   // Called when a ServiceWorkerRegistration has (or hasn't) been found for the
@@ -128,7 +128,7 @@
   FetchRedirectMode redirect_mode_;
   RequestContextType request_context_type_;
   RequestContextFrameType frame_type_;
-  scoped_refptr<ResourceRequestBodyImpl> body_;
+  scoped_refptr<ResourceRequestBody> body_;
   ResourceContext* resource_context_;
   base::Optional<base::TimeDelta> timeout_;
 
diff --git a/content/browser/service_worker/service_worker_controllee_request_handler.cc b/content/browser/service_worker/service_worker_controllee_request_handler.cc
index cf3b98eb..a82a44e 100644
--- a/content/browser/service_worker/service_worker_controllee_request_handler.cc
+++ b/content/browser/service_worker/service_worker_controllee_request_handler.cc
@@ -16,7 +16,6 @@
 #include "content/browser/service_worker/service_worker_response_info.h"
 #include "content/browser/service_worker/service_worker_url_job_wrapper.h"
 #include "content/browser/service_worker/service_worker_url_request_job.h"
-#include "content/common/resource_request_body_impl.h"
 #include "content/common/service_worker/service_worker_types.h"
 #include "content/common/service_worker/service_worker_utils.h"
 #include "content/public/browser/content_browser_client.h"
@@ -25,6 +24,7 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/browser_side_navigation_policy.h"
 #include "content/public/common/content_client.h"
+#include "content/public/common/resource_request_body.h"
 #include "content/public/common/resource_response_info.h"
 #include "net/base/load_flags.h"
 #include "net/base/url_util.h"
@@ -63,7 +63,7 @@
     ResourceType resource_type,
     RequestContextType request_context_type,
     RequestContextFrameType frame_type,
-    scoped_refptr<ResourceRequestBodyImpl> body)
+    scoped_refptr<ResourceRequestBody> body)
     : ServiceWorkerRequestHandler(context,
                                   provider_host,
                                   blob_storage_context,
diff --git a/content/browser/service_worker/service_worker_controllee_request_handler.h b/content/browser/service_worker/service_worker_controllee_request_handler.h
index 29683bf0..f0a4619 100644
--- a/content/browser/service_worker/service_worker_controllee_request_handler.h
+++ b/content/browser/service_worker/service_worker_controllee_request_handler.h
@@ -30,7 +30,7 @@
 
 namespace content {
 
-class ResourceRequestBodyImpl;
+class ResourceRequestBody;
 class ServiceWorkerRegistration;
 class ServiceWorkerVersion;
 
@@ -52,7 +52,7 @@
       ResourceType resource_type,
       RequestContextType request_context_type,
       RequestContextFrameType frame_type,
-      scoped_refptr<ResourceRequestBodyImpl> body);
+      scoped_refptr<ResourceRequestBody> body);
   ~ServiceWorkerControlleeRequestHandler() override;
 
   // Called via custom URLRequestJobFactory.
@@ -128,7 +128,7 @@
   FetchRedirectMode redirect_mode_;
   RequestContextType request_context_type_;
   RequestContextFrameType frame_type_;
-  scoped_refptr<ResourceRequestBodyImpl> body_;
+  scoped_refptr<ResourceRequestBody> body_;
   ResourceContext* resource_context_;
   GURL stripped_url_;
   bool force_update_started_;
diff --git a/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc b/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc
index 5c4be2f..fae6421c 100644
--- a/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc
+++ b/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc
@@ -18,12 +18,12 @@
 #include "content/browser/service_worker/service_worker_registration.h"
 #include "content/browser/service_worker/service_worker_test_utils.h"
 #include "content/browser/service_worker/service_worker_url_request_job.h"
-#include "content/common/resource_request_body_impl.h"
 #include "content/common/service_worker/service_worker_types.h"
 #include "content/common/service_worker/service_worker_utils.h"
 #include "content/public/browser/resource_context.h"
 #include "content/public/common/request_context_frame_type.h"
 #include "content/public/common/request_context_type.h"
+#include "content/public/common/resource_request_body.h"
 #include "content/public/common/resource_type.h"
 #include "content/public/test/mock_resource_context.h"
 #include "content/public/test/test_browser_thread_bundle.h"
@@ -66,7 +66,7 @@
               type,
               REQUEST_CONTEXT_TYPE_HYPERLINK,
               REQUEST_CONTEXT_FRAME_TYPE_TOP_LEVEL,
-              scoped_refptr<ResourceRequestBodyImpl>())),
+              scoped_refptr<ResourceRequestBody>())),
           job_(nullptr) {}
 
     ServiceWorkerURLRequestJob* MaybeCreateJob() {
diff --git a/content/browser/service_worker/service_worker_data_pipe_reader_unittest.cc b/content/browser/service_worker/service_worker_data_pipe_reader_unittest.cc
index cdfe5a9..f916b5b0 100644
--- a/content/browser/service_worker/service_worker_data_pipe_reader_unittest.cc
+++ b/content/browser/service_worker/service_worker_data_pipe_reader_unittest.cc
@@ -11,6 +11,7 @@
 #include "content/browser/service_worker/service_worker_registration.h"
 #include "content/browser/service_worker/service_worker_url_request_job.h"
 #include "content/browser/service_worker/service_worker_version.h"
+#include "content/public/common/resource_request_body.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "net/base/io_buffer.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -38,7 +39,7 @@
                                    RESOURCE_TYPE_MAIN_FRAME,
                                    REQUEST_CONTEXT_TYPE_HYPERLINK,
                                    REQUEST_CONTEXT_FRAME_TYPE_TOP_LEVEL,
-                                   scoped_refptr<ResourceRequestBodyImpl>(),
+                                   scoped_refptr<ResourceRequestBody>(),
                                    ServiceWorkerFetchType::FETCH,
                                    base::Optional<base::TimeDelta>(),
                                    delegate),
diff --git a/content/browser/service_worker/service_worker_provider_host.cc b/content/browser/service_worker/service_worker_provider_host.cc
index 34be8dd..33b03804 100644
--- a/content/browser/service_worker/service_worker_provider_host.cc
+++ b/content/browser/service_worker/service_worker_provider_host.cc
@@ -19,7 +19,6 @@
 #include "content/browser/service_worker/service_worker_handle.h"
 #include "content/browser/service_worker/service_worker_registration_handle.h"
 #include "content/browser/service_worker/service_worker_version.h"
-#include "content/common/resource_request_body_impl.h"
 #include "content/common/service_worker/service_worker_messages.h"
 #include "content/common/service_worker/service_worker_types.h"
 #include "content/common/service_worker/service_worker_utils.h"
@@ -29,6 +28,7 @@
 #include "content/public/common/content_client.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/origin_util.h"
+#include "content/public/common/resource_request_body.h"
 #include "mojo/public/cpp/bindings/strong_associated_binding.h"
 #include "net/base/url_util.h"
 
@@ -443,7 +443,7 @@
     RequestContextType request_context_type,
     RequestContextFrameType frame_type,
     base::WeakPtr<storage::BlobStorageContext> blob_storage_context,
-    scoped_refptr<ResourceRequestBodyImpl> body,
+    scoped_refptr<ResourceRequestBody> body,
     bool skip_service_worker) {
   // |skip_service_worker| is meant to apply to requests that could be handled
   // by a service worker, as opposed to requests for the service worker script
diff --git a/content/browser/service_worker/service_worker_provider_host.h b/content/browser/service_worker/service_worker_provider_host.h
index f2ed389..ca5cf726 100644
--- a/content/browser/service_worker/service_worker_provider_host.h
+++ b/content/browser/service_worker/service_worker_provider_host.h
@@ -38,7 +38,7 @@
 namespace content {
 
 class MessagePort;
-class ResourceRequestBodyImpl;
+class ResourceRequestBody;
 class ServiceWorkerContextCore;
 class ServiceWorkerDispatcherHost;
 class ServiceWorkerRequestHandler;
@@ -212,7 +212,7 @@
       RequestContextType request_context_type,
       RequestContextFrameType frame_type,
       base::WeakPtr<storage::BlobStorageContext> blob_storage_context,
-      scoped_refptr<ResourceRequestBodyImpl> body,
+      scoped_refptr<ResourceRequestBody> body,
       bool skip_service_worker);
 
   // Used to get a ServiceWorkerObjectInfo to send to the renderer. Finds an
diff --git a/content/browser/service_worker/service_worker_request_handler.cc b/content/browser/service_worker/service_worker_request_handler.cc
index f27f2420..876144e 100644
--- a/content/browser/service_worker/service_worker_request_handler.cc
+++ b/content/browser/service_worker/service_worker_request_handler.cc
@@ -16,7 +16,6 @@
 #include "content/browser/service_worker/service_worker_provider_host.h"
 #include "content/browser/service_worker/service_worker_registration.h"
 #include "content/browser/service_worker/service_worker_url_request_job.h"
-#include "content/common/resource_request_body_impl.h"
 #include "content/common/service_worker/service_worker_types.h"
 #include "content/common/service_worker/service_worker_utils.h"
 #include "content/public/browser/resource_context.h"
@@ -24,6 +23,7 @@
 #include "content/public/common/child_process_host.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/origin_util.h"
+#include "content/public/common/resource_request_body.h"
 #include "ipc/ipc_message.h"
 #include "net/base/url_util.h"
 #include "net/url_request/url_request.h"
@@ -70,7 +70,7 @@
     RequestContextType request_context_type,
     RequestContextFrameType frame_type,
     bool is_parent_frame_secure,
-    scoped_refptr<ResourceRequestBodyImpl> body,
+    scoped_refptr<ResourceRequestBody> body,
     const base::Callback<WebContents*(void)>& web_contents_getter) {
   CHECK(IsBrowserSideNavigationEnabled());
 
@@ -127,7 +127,7 @@
     RequestContextType request_context_type,
     RequestContextFrameType frame_type,
     bool is_parent_frame_secure,
-    scoped_refptr<ResourceRequestBodyImpl> body,
+    scoped_refptr<ResourceRequestBody> body,
     const base::Callback<WebContents*(void)>& web_contents_getter) {
   DCHECK(IsBrowserSideNavigationEnabled() &&
          base::CommandLine::ForCurrentProcess()->HasSwitch(
@@ -182,7 +182,7 @@
     ResourceType resource_type,
     RequestContextType request_context_type,
     RequestContextFrameType frame_type,
-    scoped_refptr<ResourceRequestBodyImpl> body) {
+    scoped_refptr<ResourceRequestBody> body) {
   // Create the handler even for insecure HTTP since it's used in the
   // case of redirect to HTTPS.
   if (!request->url().SchemeIsHTTPOrHTTPS() &&
diff --git a/content/browser/service_worker/service_worker_request_handler.h b/content/browser/service_worker/service_worker_request_handler.h
index d193eee5..20ca7ee9 100644
--- a/content/browser/service_worker/service_worker_request_handler.h
+++ b/content/browser/service_worker/service_worker_request_handler.h
@@ -34,7 +34,7 @@
 namespace content {
 
 class ResourceContext;
-class ResourceRequestBodyImpl;
+class ResourceRequestBody;
 class ServiceWorkerContextCore;
 class ServiceWorkerContextWrapper;
 class ServiceWorkerNavigationHandleCore;
@@ -59,7 +59,7 @@
       RequestContextType request_context_type,
       RequestContextFrameType frame_type,
       bool is_parent_frame_secure,
-      scoped_refptr<ResourceRequestBodyImpl> body,
+      scoped_refptr<ResourceRequestBody> body,
       const base::Callback<WebContents*(void)>& web_contents_getter);
 
   // PlzNavigate and --enable-network-service.
@@ -76,7 +76,7 @@
       RequestContextType request_context_type,
       RequestContextFrameType frame_type,
       bool is_parent_frame_secure,
-      scoped_refptr<ResourceRequestBodyImpl> body,
+      scoped_refptr<ResourceRequestBody> body,
       const base::Callback<WebContents*(void)>& web_contents_getter);
 
   // Attaches a newly created handler if the given |request| needs to
@@ -98,7 +98,7 @@
       ResourceType resource_type,
       RequestContextType request_context_type,
       RequestContextFrameType frame_type,
-      scoped_refptr<ResourceRequestBodyImpl> body);
+      scoped_refptr<ResourceRequestBody> body);
 
   // Returns the handler attached to |request|. This may return NULL
   // if no handler is attached.
diff --git a/content/browser/service_worker/service_worker_request_handler_unittest.cc b/content/browser/service_worker/service_worker_request_handler_unittest.cc
index 86f0d4d..3b7f797 100644
--- a/content/browser/service_worker/service_worker_request_handler_unittest.cc
+++ b/content/browser/service_worker/service_worker_request_handler_unittest.cc
@@ -12,7 +12,6 @@
 #include "content/browser/service_worker/service_worker_context_wrapper.h"
 #include "content/browser/service_worker/service_worker_provider_host.h"
 #include "content/browser/service_worker/service_worker_test_utils.h"
-#include "content/common/resource_request_body_impl.h"
 #include "content/common/service_worker/service_worker_utils.h"
 #include "content/public/common/request_context_frame_type.h"
 #include "content/public/common/request_context_type.h"
diff --git a/content/browser/service_worker/service_worker_url_request_job.cc b/content/browser/service_worker/service_worker_url_request_job.cc
index 922e1f8..06d182f 100644
--- a/content/browser/service_worker/service_worker_url_request_job.cc
+++ b/content/browser/service_worker/service_worker_url_request_job.cc
@@ -33,7 +33,6 @@
 #include "content/browser/service_worker/service_worker_fetch_dispatcher.h"
 #include "content/browser/service_worker/service_worker_provider_host.h"
 #include "content/browser/service_worker/service_worker_response_info.h"
-#include "content/common/resource_request_body_impl.h"
 #include "content/common/service_worker/service_worker_types.h"
 #include "content/common/service_worker/service_worker_utils.h"
 #include "content/public/browser/blob_handle.h"
@@ -41,6 +40,7 @@
 #include "content/public/browser/resource_request_info.h"
 #include "content/public/browser/service_worker_context.h"
 #include "content/public/common/referrer.h"
+#include "content/public/common/resource_request_body.h"
 #include "net/base/net_errors.h"
 #include "net/http/http_request_headers.h"
 #include "net/http/http_response_headers.h"
@@ -157,10 +157,9 @@
     callback_ = callback;
 
     std::vector<base::FilePath> file_paths;
-    for (ResourceRequestBodyImpl::Element& element :
-         *body_->elements_mutable()) {
-      if (element.type() == ResourceRequestBodyImpl::Element::TYPE_FILE &&
-          element.length() == ResourceRequestBodyImpl::Element::kUnknownSize) {
+    for (ResourceRequestBody::Element& element : *body_->elements_mutable()) {
+      if (element.type() == ResourceRequestBody::Element::TYPE_FILE &&
+          element.length() == ResourceRequestBody::Element::kUnknownSize) {
         file_elements_.push_back(&element);
         file_paths.push_back(element.path());
       }
@@ -187,7 +186,7 @@
       DCHECK_EQ(sizes.size(), file_elements_.size());
       size_t num_elements = file_elements_.size();
       for (size_t i = 0; i < num_elements; i++) {
-        ResourceRequestBodyImpl::Element* element = file_elements_[i];
+        ResourceRequestBody::Element* element = file_elements_[i];
         element->SetToFilePathRange(element->path(), element->offset(),
                                     base::checked_cast<uint64_t>(sizes[i]),
                                     element->expected_modification_time());
@@ -207,8 +206,8 @@
   // Owns and must outlive |this|.
   ServiceWorkerURLRequestJob* owner_;
 
-  scoped_refptr<ResourceRequestBodyImpl> body_;
-  std::vector<ResourceRequestBodyImpl::Element*> file_elements_;
+  scoped_refptr<ResourceRequestBody> body_;
+  std::vector<ResourceRequestBody::Element*> file_elements_;
   base::Callback<void(bool)> callback_;
   Phase phase_ = Phase::INITIAL;
   base::WeakPtrFactory<FileSizeResolver> weak_factory_;
@@ -319,7 +318,7 @@
     ResourceType resource_type,
     RequestContextType request_context_type,
     RequestContextFrameType frame_type,
-    scoped_refptr<ResourceRequestBodyImpl> body,
+    scoped_refptr<ResourceRequestBody> body,
     ServiceWorkerFetchType fetch_type,
     const base::Optional<base::TimeDelta>& timeout,
     Delegate* delegate)
@@ -594,7 +593,7 @@
                                                        uint64_t* blob_size) {
   DCHECK(HasRequestBody());
   storage::BlobDataBuilder blob_builder(base::GenerateGUID());
-  for (const ResourceRequestBodyImpl::Element& element : (*body_->elements())) {
+  for (const ResourceRequestBody::Element& element : (*body_->elements())) {
     blob_builder.AppendIPCDataElement(element);
   }
 
diff --git a/content/browser/service_worker/service_worker_url_request_job.h b/content/browser/service_worker/service_worker_url_request_job.h
index ee7fd80..b4e9536 100644
--- a/content/browser/service_worker/service_worker_url_request_job.h
+++ b/content/browser/service_worker/service_worker_url_request_job.h
@@ -49,7 +49,7 @@
 namespace content {
 
 class ResourceContext;
-class ResourceRequestBodyImpl;
+class ResourceRequestBody;
 class ServiceWorkerBlobReader;
 class ServiceWorkerDataPipeReader;
 class ServiceWorkerFetchDispatcher;
@@ -71,7 +71,7 @@
       ResourceType resource_type,
       RequestContextType request_context_type,
       RequestContextFrameType frame_type,
-      scoped_refptr<ResourceRequestBodyImpl> body,
+      scoped_refptr<ResourceRequestBody> body,
       ServiceWorkerFetchType fetch_type,
       const base::Optional<base::TimeDelta>& timeout,
       Delegate* delegate);
@@ -306,7 +306,7 @@
   bool fall_back_required_;
   // ResourceRequestBody has a collection of BlobDataHandles attached to it
   // using the userdata mechanism. So we have to keep it not to free the blobs.
-  scoped_refptr<ResourceRequestBodyImpl> body_;
+  scoped_refptr<ResourceRequestBody> body_;
   std::unique_ptr<storage::BlobDataHandle> request_body_blob_data_handle_;
   ServiceWorkerFetchType fetch_type_;
   base::Optional<base::TimeDelta> timeout_;
diff --git a/content/browser/service_worker/service_worker_url_request_job_unittest.cc b/content/browser/service_worker/service_worker_url_request_job_unittest.cc
index 54ab731..01daa9d 100644
--- a/content/browser/service_worker/service_worker_url_request_job_unittest.cc
+++ b/content/browser/service_worker/service_worker_url_request_job_unittest.cc
@@ -31,7 +31,6 @@
 #include "content/browser/service_worker/service_worker_response_info.h"
 #include "content/browser/service_worker/service_worker_test_utils.h"
 #include "content/browser/service_worker/service_worker_version.h"
-#include "content/common/resource_request_body_impl.h"
 #include "content/common/service_worker/service_worker_messages.h"
 #include "content/common/service_worker/service_worker_status_code.h"
 #include "content/common/service_worker/service_worker_types.h"
@@ -39,6 +38,7 @@
 #include "content/public/common/browser_side_navigation_policy.h"
 #include "content/public/common/request_context_frame_type.h"
 #include "content/public/common/request_context_type.h"
+#include "content/public/common/resource_request_body.h"
 #include "content/public/common/resource_type.h"
 #include "content/public/test/mock_resource_context.h"
 #include "content/public/test/test_browser_context.h"
@@ -110,7 +110,7 @@
         FETCH_CREDENTIALS_MODE_OMIT, FetchRedirectMode::FOLLOW_MODE,
         resource_type_, REQUEST_CONTEXT_TYPE_HYPERLINK,
         REQUEST_CONTEXT_FRAME_TYPE_TOP_LEVEL,
-        scoped_refptr<ResourceRequestBodyImpl>(), ServiceWorkerFetchType::FETCH,
+        scoped_refptr<ResourceRequestBody>(), ServiceWorkerFetchType::FETCH,
         custom_timeout_, delegate_);
     if (simulate_navigation_preload_) {
       job_->set_simulate_navigation_preload_for_test();
diff --git a/content/browser/service_worker/service_worker_write_to_cache_job_unittest.cc b/content/browser/service_worker/service_worker_write_to_cache_job_unittest.cc
index 317ade5..6e770e0 100644
--- a/content/browser/service_worker/service_worker_write_to_cache_job_unittest.cc
+++ b/content/browser/service_worker/service_worker_write_to_cache_job_unittest.cc
@@ -20,8 +20,8 @@
 #include "content/browser/service_worker/service_worker_provider_host.h"
 #include "content/browser/service_worker/service_worker_registration.h"
 #include "content/browser/service_worker/service_worker_test_utils.h"
-#include "content/common/resource_request_body_impl.h"
 #include "content/common/service_worker/service_worker_utils.h"
+#include "content/public/common/resource_request_body.h"
 #include "content/public/test/mock_resource_context.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "net/base/io_buffer.h"
@@ -323,8 +323,7 @@
         provider_id, false, FETCH_REQUEST_MODE_NO_CORS,
         FETCH_CREDENTIALS_MODE_OMIT, FetchRedirectMode::FOLLOW_MODE,
         RESOURCE_TYPE_SERVICE_WORKER, REQUEST_CONTEXT_TYPE_SERVICE_WORKER,
-        REQUEST_CONTEXT_FRAME_TYPE_NONE,
-        scoped_refptr<ResourceRequestBodyImpl>());
+        REQUEST_CONTEXT_FRAME_TYPE_NONE, scoped_refptr<ResourceRequestBody>());
   }
 
   int NextProviderId() { return next_provider_id_++; }
diff --git a/content/browser/webrtc/webrtc_media_recorder_browsertest.cc b/content/browser/webrtc/webrtc_media_recorder_browsertest.cc
index 071bf9ca..2a51201 100644
--- a/content/browser/webrtc/webrtc_media_recorder_browsertest.cc
+++ b/content/browser/webrtc/webrtc_media_recorder_browsertest.cc
@@ -73,7 +73,13 @@
   MakeTypicalCall("testStartStopAndRecorderState();", kMediaRecorderHtmlFile);
 }
 
-IN_PROC_BROWSER_TEST_P(WebRtcMediaRecorderTest, StartAndDataAvailable) {
+// Flaky on Linux Tsan (crbug.com/736268)
+#if defined(THREAD_SANITIZER)
+#define MAYBE_StartAndDataAvailable DISABLED_StartAndDataAvailable
+#else
+#define MAYBE_StartAndDataAvailable StartAndDataAvailable
+#endif
+IN_PROC_BROWSER_TEST_P(WebRtcMediaRecorderTest, MAYBE_StartAndDataAvailable) {
   MaybeForceDisableEncodeAccelerator(GetParam().disable_accelerator);
   MakeTypicalCall(base::StringPrintf("testStartAndDataAvailable(\"%s\");",
                                      GetParam().mime_type.c_str()),
@@ -144,12 +150,27 @@
                   kMediaRecorderHtmlFile);
 }
 
-IN_PROC_BROWSER_TEST_F(WebRtcMediaRecorderTest, IllegalStopThrowsDOMError) {
+// Flaky on Linux Tsan (crbug.com/736268)
+#if defined(THREAD_SANITIZER)
+#define MAYBE_IllegalStopThrowsDOMError DISABLED_IllegalStopThrowsDOMError
+#else
+#define MAYBE_IllegalStopThrowsDOMError IllegalStopThrowsDOMError
+#endif
+IN_PROC_BROWSER_TEST_F(WebRtcMediaRecorderTest,
+                       MAYBE_IllegalStopThrowsDOMError) {
   MakeTypicalCall("testIllegalStopThrowsDOMError();", kMediaRecorderHtmlFile);
 }
 
+// Flaky on Linux Tsan (crbug.com/736268)
+#if defined(THREAD_SANITIZER)
+#define MAYBE_IllegalStartWhileRecordingThrowsDOMError \
+  DISABLED_IllegalStartWhileRecordingThrowsDOMError
+#else
+#define MAYBE_IllegalStartWhileRecordingThrowsDOMError \
+  IllegalStartWhileRecordingThrowsDOMError
+#endif
 IN_PROC_BROWSER_TEST_F(WebRtcMediaRecorderTest,
-                       IllegalStartWhileRecordingThrowsDOMError) {
+                       MAYBE_IllegalStartWhileRecordingThrowsDOMError) {
   MakeTypicalCall("testIllegalStartInRecordingStateThrowsDOMError();",
                   kMediaRecorderHtmlFile);
 }
diff --git a/content/child/resource_dispatcher_unittest.cc b/content/child/resource_dispatcher_unittest.cc
index 1b3e0a7a..fc5d41e 100644
--- a/content/child/resource_dispatcher_unittest.cc
+++ b/content/child/resource_dispatcher_unittest.cc
@@ -32,6 +32,7 @@
 #include "content/public/child/resource_dispatcher_delegate.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/request_context_frame_type.h"
+#include "content/public/common/resource_request_body.h"
 #include "content/public/common/resource_response.h"
 #include "net/base/net_errors.h"
 #include "net/base/request_priority.h"
@@ -223,7 +224,7 @@
   ResourceDispatcher* dispatcher() { return dispatcher_.get(); }
 
   int StartAsync(std::unique_ptr<ResourceRequest> request,
-                 ResourceRequestBodyImpl* request_body,
+                 ResourceRequestBody* request_body,
                  TestRequestPeer::Context* peer_context) {
     std::unique_ptr<TestRequestPeer> peer(
         new TestRequestPeer(dispatcher(), peer_context));
diff --git a/content/child/web_url_loader_impl.cc b/content/child/web_url_loader_impl.cc
index 956cf1eae..4df5a085 100644
--- a/content/child/web_url_loader_impl.cc
+++ b/content/child/web_url_loader_impl.cc
@@ -35,12 +35,12 @@
 #include "content/child/weburlresponse_extradata_impl.h"
 #include "content/common/resource_messages.h"
 #include "content/common/resource_request.h"
-#include "content/common/resource_request_body_impl.h"
 #include "content/common/service_worker/service_worker_types.h"
 #include "content/common/url_loader.mojom.h"
 #include "content/public/child/fixed_received_data.h"
 #include "content/public/child/request_peer.h"
 #include "content/public/common/browser_side_navigation_policy.h"
+#include "content/public/common/resource_request_body.h"
 #include "net/base/data_url.h"
 #include "net/base/filename_util.h"
 #include "net/base/net_errors.h"
diff --git a/content/child/web_url_request_util.cc b/content/child/web_url_request_util.cc
index 47fcfe6..d19aef2 100644
--- a/content/child/web_url_request_util.cc
+++ b/content/child/web_url_request_util.cc
@@ -232,17 +232,17 @@
 }
 
 WebHTTPBody GetWebHTTPBodyForRequestBody(
-    const scoped_refptr<ResourceRequestBodyImpl>& input) {
+    const scoped_refptr<ResourceRequestBody>& input) {
   WebHTTPBody http_body;
   http_body.Initialize();
   http_body.SetIdentifier(input->identifier());
   http_body.SetContainsPasswordData(input->contains_sensitive_info());
   for (const auto& element : *input->elements()) {
     switch (element.type()) {
-      case ResourceRequestBodyImpl::Element::TYPE_BYTES:
+      case ResourceRequestBody::Element::TYPE_BYTES:
         http_body.AppendData(WebData(element.bytes(), element.length()));
         break;
-      case ResourceRequestBodyImpl::Element::TYPE_FILE:
+      case ResourceRequestBody::Element::TYPE_FILE:
         http_body.AppendFileRange(
             blink::FilePathToWebString(element.path()), element.offset(),
             (element.length() != std::numeric_limits<uint64_t>::max())
@@ -250,7 +250,7 @@
                 : -1,
             element.expected_modification_time().ToDoubleT());
         break;
-      case ResourceRequestBodyImpl::Element::TYPE_FILE_FILESYSTEM:
+      case ResourceRequestBody::Element::TYPE_FILE_FILESYSTEM:
         http_body.AppendFileSystemURLRange(
             element.filesystem_url(), element.offset(),
             (element.length() != std::numeric_limits<uint64_t>::max())
@@ -258,11 +258,11 @@
                 : -1,
             element.expected_modification_time().ToDoubleT());
         break;
-      case ResourceRequestBodyImpl::Element::TYPE_BLOB:
+      case ResourceRequestBody::Element::TYPE_BLOB:
         http_body.AppendBlob(WebString::FromASCII(element.blob_uuid()));
         break;
-      case ResourceRequestBodyImpl::Element::TYPE_BYTES_DESCRIPTION:
-      case ResourceRequestBodyImpl::Element::TYPE_DISK_CACHE_ENTRY:
+      case ResourceRequestBody::Element::TYPE_BYTES_DESCRIPTION:
+      case ResourceRequestBody::Element::TYPE_DISK_CACHE_ENTRY:
       default:
         NOTREACHED();
         break;
@@ -271,9 +271,9 @@
   return http_body;
 }
 
-scoped_refptr<ResourceRequestBodyImpl> GetRequestBodyForWebURLRequest(
+scoped_refptr<ResourceRequestBody> GetRequestBodyForWebURLRequest(
     const blink::WebURLRequest& request) {
-  scoped_refptr<ResourceRequestBodyImpl> request_body;
+  scoped_refptr<ResourceRequestBody> request_body;
 
   if (request.HttpBody().IsNull()) {
     return request_body;
@@ -286,10 +286,9 @@
   return GetRequestBodyForWebHTTPBody(request.HttpBody());
 }
 
-scoped_refptr<ResourceRequestBodyImpl> GetRequestBodyForWebHTTPBody(
+scoped_refptr<ResourceRequestBody> GetRequestBodyForWebHTTPBody(
     const blink::WebHTTPBody& httpBody) {
-  scoped_refptr<ResourceRequestBodyImpl> request_body =
-      new ResourceRequestBodyImpl();
+  scoped_refptr<ResourceRequestBody> request_body = new ResourceRequestBody();
   size_t i = 0;
   WebHTTPBody::Element element;
   while (httpBody.ElementAt(i++, element)) {
diff --git a/content/child/web_url_request_util.h b/content/child/web_url_request_util.h
index 050aae1..2374782 100644
--- a/content/child/web_url_request_util.h
+++ b/content/child/web_url_request_util.h
@@ -8,10 +8,10 @@
 #include <string>
 
 #include "content/common/content_export.h"
-#include "content/common/resource_request_body_impl.h"
 #include "content/common/service_worker/service_worker_types.h"
 #include "content/public/common/request_context_frame_type.h"
 #include "content/public/common/request_context_type.h"
+#include "content/public/common/resource_request_body.h"
 #include "content/public/common/resource_type.h"
 #include "third_party/WebKit/public/platform/WebMixedContentContextType.h"
 
@@ -31,18 +31,18 @@
 
 int GetLoadFlagsForWebURLRequest(const blink::WebURLRequest& request);
 
-// Takes a ResourceRequestBodyImpl and converts into WebHTTPBody.
+// Takes a ResourceRequestBody and converts into WebHTTPBody.
 blink::WebHTTPBody GetWebHTTPBodyForRequestBody(
-    const scoped_refptr<ResourceRequestBodyImpl>& input);
+    const scoped_refptr<ResourceRequestBody>& input);
 
-// Takes a WebHTTPBody and converts into a ResourceRequestBodyImpl.
-scoped_refptr<ResourceRequestBodyImpl> GetRequestBodyForWebHTTPBody(
+// Takes a WebHTTPBody and converts into a ResourceRequestBody.
+scoped_refptr<ResourceRequestBody> GetRequestBodyForWebHTTPBody(
     const blink::WebHTTPBody& httpBody);
 
 // Takes a WebURLRequest and sets the appropriate information
-// in a ResourceRequestBodyImpl structure. Returns an empty scoped_refptr
+// in a ResourceRequestBody structure. Returns an empty scoped_refptr
 // if the request body is not present.
-scoped_refptr<ResourceRequestBodyImpl> GetRequestBodyForWebURLRequest(
+scoped_refptr<ResourceRequestBody> GetRequestBodyForWebURLRequest(
     const blink::WebURLRequest& request);
 
 // Helper functions to convert enums from the blink type to the content
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index 063b613..4e113f56 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -147,8 +147,6 @@
     "frame_owner_properties.h",
     "frame_replication_state.cc",
     "frame_replication_state.h",
-    "generic_shared_memory_id_generator.cc",
-    "generic_shared_memory_id_generator.h",
     "gin_java_bridge_messages.h",
     "in_process_child_thread_params.cc",
     "in_process_child_thread_params.h",
@@ -282,8 +280,6 @@
     "resource_messages.h",
     "resource_request.cc",
     "resource_request.h",
-    "resource_request_body_impl.cc",
-    "resource_request_body_impl.h",
     "resource_request_completion_status.cc",
     "resource_request_completion_status.h",
     "sandbox_init_mac.cc",
diff --git a/content/common/android/resource_request_body_android.cc b/content/common/android/resource_request_body_android.cc
index 7abf4e8..08e747a 100644
--- a/content/common/android/resource_request_body_android.cc
+++ b/content/common/android/resource_request_body_android.cc
@@ -23,7 +23,7 @@
 
 base::android::ScopedJavaLocalRef<jbyteArray>
 ConvertResourceRequestBodyToJavaArray(JNIEnv* env,
-                                      const ResourceRequestBodyImpl& body) {
+                                      const ResourceRequestBody& body) {
   std::string encoded = EncodeResourceRequestBody(body);
   return base::android::ToJavaByteArray(
       env, reinterpret_cast<const uint8_t*>(encoded.data()), encoded.size());
@@ -51,13 +51,13 @@
           reinterpret_cast<const char*>(post_data.data()), post_data.size());
 
   return ConvertResourceRequestBodyToJavaArray(
-      env, static_cast<const ResourceRequestBodyImpl&>(*body));
+      env, static_cast<const ResourceRequestBody&>(*body));
 }
 
 base::android::ScopedJavaLocalRef<jobject>
 ConvertResourceRequestBodyToJavaObject(
     JNIEnv* env,
-    const scoped_refptr<ResourceRequestBodyImpl>& body) {
+    const scoped_refptr<ResourceRequestBody>& body) {
   if (!body)
     return base::android::ScopedJavaLocalRef<jobject>();
 
@@ -69,7 +69,7 @@
   return Java_ResourceRequestBody_createFromEncodedNativeForm(env, j_encoded);
 }
 
-scoped_refptr<ResourceRequestBodyImpl> ExtractResourceRequestBodyFromJavaObject(
+scoped_refptr<ResourceRequestBody> ExtractResourceRequestBodyFromJavaObject(
     JNIEnv* env,
     const base::android::JavaParamRef<jobject>& j_body) {
   if (!j_body)
diff --git a/content/common/android/resource_request_body_android.h b/content/common/android/resource_request_body_android.h
index 70373ebf..1c35733 100644
--- a/content/common/android/resource_request_body_android.h
+++ b/content/common/android/resource_request_body_android.h
@@ -12,7 +12,7 @@
 
 namespace content {
 
-class ResourceRequestBodyImpl;
+class ResourceRequestBody;
 
 bool RegisterResourceRequestBody(JNIEnv* env);
 
@@ -21,12 +21,12 @@
 base::android::ScopedJavaLocalRef<jobject>
 ConvertResourceRequestBodyToJavaObject(
     JNIEnv* env,
-    const scoped_refptr<ResourceRequestBodyImpl>& native_object);
+    const scoped_refptr<ResourceRequestBody>& native_object);
 
 // Reconstructs the native C++ content::ResourceRequestBody object based on
 // org.chromium.content_public.common.ResourceRequestBody (|java_object|) passed
 // in as an argument.
-scoped_refptr<ResourceRequestBodyImpl> ExtractResourceRequestBodyFromJavaObject(
+scoped_refptr<ResourceRequestBody> ExtractResourceRequestBodyFromJavaObject(
     JNIEnv* env,
     const base::android::JavaParamRef<jobject>& java_object);
 
diff --git a/content/common/android/sync_compositor_messages.h b/content/common/android/sync_compositor_messages.h
index d370ed4..346c6e4 100644
--- a/content/common/android/sync_compositor_messages.h
+++ b/content/common/android/sync_compositor_messages.h
@@ -156,7 +156,7 @@
 
 IPC_MESSAGE_ROUTED2(SyncCompositorMsg_ReclaimResources,
                     uint32_t /* layer_tree_frame_sink_id */,
-                    cc::ReturnedResourceArray /* resources */);
+                    std::vector<cc::ReturnedResource> /* resources */);
 
 IPC_MESSAGE_ROUTED1(SyncCompositorMsg_SetScroll, gfx::ScrollOffset);
 
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h
index ca9e36cf..03413d0 100644
--- a/content/common/frame_messages.h
+++ b/content/common/frame_messages.h
@@ -451,7 +451,7 @@
 IPC_STRUCT_BEGIN(FrameHostMsg_OpenURL_Params)
   IPC_STRUCT_MEMBER(GURL, url)
   IPC_STRUCT_MEMBER(bool, uses_post)
-  IPC_STRUCT_MEMBER(scoped_refptr<content::ResourceRequestBodyImpl>,
+  IPC_STRUCT_MEMBER(scoped_refptr<content::ResourceRequestBody>,
                     resource_request_body)
   IPC_STRUCT_MEMBER(std::string, extra_headers)
   IPC_STRUCT_MEMBER(content::Referrer, referrer)
diff --git a/content/common/generic_shared_memory_id_generator.cc b/content/common/generic_shared_memory_id_generator.cc
deleted file mode 100644
index c912bc2..0000000
--- a/content/common/generic_shared_memory_id_generator.cc
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/common/generic_shared_memory_id_generator.h"
-
-#include "base/atomic_sequence_num.h"
-
-namespace content {
-namespace {
-
-// Global atomic to generate gpu memory buffer unique IDs.
-base::StaticAtomicSequenceNumber g_next_generic_shared_memory_id;
-
-}  // namespace
-
-gfx::GenericSharedMemoryId GetNextGenericSharedMemoryId() {
-  return gfx::GenericSharedMemoryId(g_next_generic_shared_memory_id.GetNext());
-}
-
-}  // namespace content
diff --git a/content/common/generic_shared_memory_id_generator.h b/content/common/generic_shared_memory_id_generator.h
deleted file mode 100644
index 4640cc1..0000000
--- a/content/common/generic_shared_memory_id_generator.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_COMMON_GENERIC_SHARED_MEMORY_ID_GENERATOR_H_
-#define CONTENT_COMMON_GENERIC_SHARED_MEMORY_ID_GENERATOR_H_
-
-#include "ui/gfx/generic_shared_memory_id.h"
-#include "content/common/content_export.h"
-
-namespace content {
-
-// Returns the next GenericSharedMemoryId for the current process. This should
-// be used anywhere a new GenericSharedMemoryId is needed.
-CONTENT_EXPORT gfx::GenericSharedMemoryId GetNextGenericSharedMemoryId();
-
-}  // namespace content
-
-#endif  // CONTENT_COMMON_GENERIC_SHARED_MEMORY_ID_GENERATOR_H_
diff --git a/content/common/navigation_params.cc b/content/common/navigation_params.cc
index 5881d58..df4dd2b 100644
--- a/content/common/navigation_params.cc
+++ b/content/common/navigation_params.cc
@@ -78,7 +78,7 @@
     PreviewsState previews_state,
     const base::TimeTicks& navigation_start,
     std::string method,
-    const scoped_refptr<ResourceRequestBodyImpl>& post_data,
+    const scoped_refptr<ResourceRequestBody>& post_data,
     base::Optional<SourceLocation> source_location,
     CSPDisposition should_check_main_world_csp)
     : url(url),
diff --git a/content/common/navigation_params.h b/content/common/navigation_params.h
index 4490035..c9439ee 100644
--- a/content/common/navigation_params.h
+++ b/content/common/navigation_params.h
@@ -17,11 +17,11 @@
 #include "content/common/content_export.h"
 #include "content/common/content_security_policy/csp_disposition_enum.h"
 #include "content/common/frame_message_enums.h"
-#include "content/common/resource_request_body_impl.h"
 #include "content/public/common/page_state.h"
 #include "content/public/common/previews_state.h"
 #include "content/public/common/referrer.h"
 #include "content/public/common/request_context_type.h"
+#include "content/public/common/resource_request_body.h"
 #include "content/public/common/resource_response.h"
 #include "net/url_request/redirect_info.h"
 #include "third_party/WebKit/public/platform/WebMixedContentContextType.h"
@@ -61,23 +61,22 @@
 // Used by all navigation IPCs.
 struct CONTENT_EXPORT CommonNavigationParams {
   CommonNavigationParams();
-  CommonNavigationParams(
-      const GURL& url,
-      const Referrer& referrer,
-      ui::PageTransition transition,
-      FrameMsg_Navigate_Type::Value navigation_type,
-      bool allow_download,
-      bool should_replace_current_entry,
-      base::TimeTicks ui_timestamp,
-      FrameMsg_UILoadMetricsReportType::Value report_type,
-      const GURL& base_url_for_data_url,
-      const GURL& history_url_for_data_url,
-      PreviewsState previews_state,
-      const base::TimeTicks& navigation_start,
-      std::string method,
-      const scoped_refptr<ResourceRequestBodyImpl>& post_data,
-      base::Optional<SourceLocation> source_location,
-      CSPDisposition should_check_main_world_csp);
+  CommonNavigationParams(const GURL& url,
+                         const Referrer& referrer,
+                         ui::PageTransition transition,
+                         FrameMsg_Navigate_Type::Value navigation_type,
+                         bool allow_download,
+                         bool should_replace_current_entry,
+                         base::TimeTicks ui_timestamp,
+                         FrameMsg_UILoadMetricsReportType::Value report_type,
+                         const GURL& base_url_for_data_url,
+                         const GURL& history_url_for_data_url,
+                         PreviewsState previews_state,
+                         const base::TimeTicks& navigation_start,
+                         std::string method,
+                         const scoped_refptr<ResourceRequestBody>& post_data,
+                         base::Optional<SourceLocation> source_location,
+                         CSPDisposition should_check_main_world_csp);
   CommonNavigationParams(const CommonNavigationParams& other);
   ~CommonNavigationParams();
 
@@ -137,7 +136,7 @@
   std::string method;
 
   // Body of HTTP POST request.
-  scoped_refptr<ResourceRequestBodyImpl> post_data;
+  scoped_refptr<ResourceRequestBody> post_data;
 
   // PlzNavigate
   // Information about the Javascript source for this navigation. Used for
diff --git a/content/common/page_state_serialization.cc b/content/common/page_state_serialization.cc
index 41da923..c4289a5 100644
--- a/content/common/page_state_serialization.cc
+++ b/content/common/page_state_serialization.cc
@@ -15,7 +15,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
-#include "content/common/resource_request_body_impl.h"
+#include "content/public/common/resource_request_body.h"
 #include "ui/display/display.h"
 #include "ui/display/screen.h"
 
@@ -29,14 +29,14 @@
 //-----------------------------------------------------------------------------
 
 void AppendDataToRequestBody(
-    const scoped_refptr<ResourceRequestBodyImpl>& request_body,
+    const scoped_refptr<ResourceRequestBody>& request_body,
     const char* data,
     int data_length) {
   request_body->AppendBytes(data, data_length);
 }
 
 void AppendFileRangeToRequestBody(
-    const scoped_refptr<ResourceRequestBodyImpl>& request_body,
+    const scoped_refptr<ResourceRequestBody>& request_body,
     const base::NullableString16& file_path,
     int file_start,
     int file_length,
@@ -48,7 +48,7 @@
 }
 
 void AppendURLRangeToRequestBody(
-    const scoped_refptr<ResourceRequestBodyImpl>& request_body,
+    const scoped_refptr<ResourceRequestBody>& request_body,
     const GURL& url,
     int file_start,
     int file_length,
@@ -60,7 +60,7 @@
 }
 
 void AppendBlobToRequestBody(
-    const scoped_refptr<ResourceRequestBodyImpl>& request_body,
+    const scoped_refptr<ResourceRequestBody>& request_body,
     const std::string& uuid) {
   request_body->AppendBlob(uuid);
 }
@@ -68,10 +68,10 @@
 //----------------------------------------------------------------------------
 
 void AppendReferencedFilesFromHttpBody(
-    const std::vector<ResourceRequestBodyImpl::Element>& elements,
+    const std::vector<ResourceRequestBody::Element>& elements,
     std::vector<base::NullableString16>* referenced_files) {
   for (size_t i = 0; i < elements.size(); ++i) {
-    if (elements[i].type() == ResourceRequestBodyImpl::Element::TYPE_FILE)
+    if (elements[i].type() == ResourceRequestBody::Element::TYPE_FILE)
       referenced_files->push_back(
           base::NullableString16(elements[i].path().AsUTF16Unsafe(), false));
   }
@@ -393,16 +393,16 @@
     (*result)[i] = ReadString(obj);
 }
 
-void WriteResourceRequestBody(const ResourceRequestBodyImpl& request_body,
+void WriteResourceRequestBody(const ResourceRequestBody& request_body,
                               SerializeObject* obj) {
   WriteAndValidateVectorSize(*request_body.elements(), obj);
   for (const auto& element : *request_body.elements()) {
     switch (element.type()) {
-      case ResourceRequestBodyImpl::Element::TYPE_BYTES:
+      case ResourceRequestBody::Element::TYPE_BYTES:
         WriteInteger(blink::WebHTTPBody::Element::kTypeData, obj);
         WriteData(element.bytes(), static_cast<int>(element.length()), obj);
         break;
-      case ResourceRequestBodyImpl::Element::TYPE_FILE:
+      case ResourceRequestBody::Element::TYPE_FILE:
         WriteInteger(blink::WebHTTPBody::Element::kTypeFile, obj);
         WriteString(
             base::NullableString16(element.path().AsUTF16Unsafe(), false), obj);
@@ -410,19 +410,19 @@
         WriteInteger64(static_cast<int64_t>(element.length()), obj);
         WriteReal(element.expected_modification_time().ToDoubleT(), obj);
         break;
-      case ResourceRequestBodyImpl::Element::TYPE_FILE_FILESYSTEM:
+      case ResourceRequestBody::Element::TYPE_FILE_FILESYSTEM:
         WriteInteger(blink::WebHTTPBody::Element::kTypeFileSystemURL, obj);
         WriteGURL(element.filesystem_url(), obj);
         WriteInteger64(static_cast<int64_t>(element.offset()), obj);
         WriteInteger64(static_cast<int64_t>(element.length()), obj);
         WriteReal(element.expected_modification_time().ToDoubleT(), obj);
         break;
-      case ResourceRequestBodyImpl::Element::TYPE_BLOB:
+      case ResourceRequestBody::Element::TYPE_BLOB:
         WriteInteger(blink::WebHTTPBody::Element::kTypeBlob, obj);
         WriteStdString(element.blob_uuid(), obj);
         break;
-      case ResourceRequestBodyImpl::Element::TYPE_BYTES_DESCRIPTION:
-      case ResourceRequestBodyImpl::Element::TYPE_DISK_CACHE_ENTRY:
+      case ResourceRequestBody::Element::TYPE_BYTES_DESCRIPTION:
+      case ResourceRequestBody::Element::TYPE_DISK_CACHE_ENTRY:
       default:
         NOTREACHED();
         continue;
@@ -433,7 +433,7 @@
 
 void ReadResourceRequestBody(
     SerializeObject* obj,
-    const scoped_refptr<ResourceRequestBodyImpl>& request_body) {
+    const scoped_refptr<ResourceRequestBody>& request_body) {
   int num_elements = ReadInteger(obj);
   for (int i = 0; i < num_elements; ++i) {
     int type = ReadInteger(obj);
@@ -487,7 +487,7 @@
   if (!ReadBoolean(obj))
     return;
 
-  http_body->request_body = new ResourceRequestBodyImpl();
+  http_body->request_body = new ResourceRequestBody();
   ReadResourceRequestBody(obj, http_body->request_body);
 
   if (obj->version >= 12)
@@ -781,10 +781,9 @@
   return rv;
 }
 
-scoped_refptr<ResourceRequestBodyImpl> DecodeResourceRequestBody(
-    const char* data,
-    size_t size) {
-  scoped_refptr<ResourceRequestBodyImpl> result = new ResourceRequestBodyImpl();
+scoped_refptr<ResourceRequestBody> DecodeResourceRequestBody(const char* data,
+                                                             size_t size) {
+  scoped_refptr<ResourceRequestBody> result = new ResourceRequestBody();
   SerializeObject obj(data, static_cast<int>(size));
   ReadResourceRequestBody(&obj, result);
   // Please see the EncodeResourceRequestBody() function below for information
@@ -795,7 +794,7 @@
 }
 
 std::string EncodeResourceRequestBody(
-    const ResourceRequestBodyImpl& resource_request_body) {
+    const ResourceRequestBody& resource_request_body) {
   SerializeObject obj;
   obj.version = kCurrentVersion;
   WriteResourceRequestBody(resource_request_body, &obj);
diff --git a/content/common/page_state_serialization.h b/content/common/page_state_serialization.h
index 9c1642da..d7a0bf3 100644
--- a/content/common/page_state_serialization.h
+++ b/content/common/page_state_serialization.h
@@ -13,7 +13,7 @@
 #include "base/strings/nullable_string16.h"
 #include "build/build_config.h"
 #include "content/common/content_export.h"
-#include "content/common/resource_request_body_impl.h"
+#include "content/public/common/resource_request_body.h"
 #include "third_party/WebKit/public/platform/WebHTTPBody.h"
 #include "third_party/WebKit/public/platform/WebHistoryScrollRestorationType.h"
 #include "third_party/WebKit/public/platform/WebReferrerPolicy.h"
@@ -25,7 +25,7 @@
 
 struct CONTENT_EXPORT ExplodedHttpBody {
   base::NullableString16 http_content_type;
-  scoped_refptr<ResourceRequestBodyImpl> request_body;
+  scoped_refptr<ResourceRequestBody> request_body;
   bool contains_passwords;
 
   ExplodedHttpBody();
@@ -82,15 +82,14 @@
     ExplodedPageState* exploded);
 
 // Converts results of EncodeResourceRequestBody (passed in as a pair of |data|
-// + |size|) back into a ResourceRequestBodyImpl.  Returns nullptr if the
+// + |size|) back into a ResourceRequestBody.  Returns nullptr if the
 // decoding fails (e.g. if |data| is malformed).
-scoped_refptr<ResourceRequestBodyImpl> DecodeResourceRequestBody(
-    const char* data,
-    size_t size);
+scoped_refptr<ResourceRequestBody> DecodeResourceRequestBody(const char* data,
+                                                             size_t size);
 
 // Encodes |resource_request_body| into |encoded|.
 std::string EncodeResourceRequestBody(
-    const ResourceRequestBodyImpl& resource_request_body);
+    const ResourceRequestBody& resource_request_body);
 #endif
 
 }  // namespace content
diff --git a/content/common/page_state_serialization_unittest.cc b/content/common/page_state_serialization_unittest.cc
index e5c42a22..bd44937 100644
--- a/content/common/page_state_serialization_unittest.cc
+++ b/content/common/page_state_serialization_unittest.cc
@@ -41,11 +41,11 @@
 }
 
 template <>
-void ExpectEquality(const ResourceRequestBodyImpl::Element& a,
-                    const ResourceRequestBodyImpl::Element& b) {
+void ExpectEquality(const ResourceRequestBody::Element& a,
+                    const ResourceRequestBody::Element& b) {
   EXPECT_EQ(a.type(), b.type());
-  if (a.type() == ResourceRequestBodyImpl::Element::TYPE_BYTES &&
-      b.type() == ResourceRequestBodyImpl::Element::TYPE_BYTES) {
+  if (a.type() == ResourceRequestBody::Element::TYPE_BYTES &&
+      b.type() == ResourceRequestBody::Element::TYPE_BYTES) {
     EXPECT_EQ(std::string(a.bytes(), a.length()),
               std::string(b.bytes(), b.length()));
   }
@@ -119,7 +119,7 @@
 
   void PopulateHttpBody(ExplodedHttpBody* http_body,
                         std::vector<base::NullableString16>* referenced_files) {
-    http_body->request_body = new ResourceRequestBodyImpl();
+    http_body->request_body = new ResourceRequestBody();
     http_body->request_body->set_identifier(12345);
     http_body->contains_passwords = false;
     http_body->http_content_type = NS16("text/foo");
@@ -163,7 +163,7 @@
 
     if (!is_child) {
       frame_state->http_body.http_content_type = NS16("foo/bar");
-      frame_state->http_body.request_body = new ResourceRequestBodyImpl();
+      frame_state->http_body.request_body = new ResourceRequestBody();
       frame_state->http_body.request_body->set_identifier(789);
 
       std::string test_body("first data block");
diff --git a/content/common/resource_messages.cc b/content/common/resource_messages.cc
index bff3c18..a6a4391 100644
--- a/content/common/resource_messages.cc
+++ b/content/common/resource_messages.cc
@@ -529,7 +529,7 @@
   l->append(")");
 }
 
-void ParamTraits<scoped_refptr<content::ResourceRequestBodyImpl>>::GetSize(
+void ParamTraits<scoped_refptr<content::ResourceRequestBody>>::GetSize(
     base::PickleSizer* s,
     const param_type& p) {
   GetParamSize(s, p.get() != NULL);
@@ -540,7 +540,7 @@
   }
 }
 
-void ParamTraits<scoped_refptr<content::ResourceRequestBodyImpl>>::Write(
+void ParamTraits<scoped_refptr<content::ResourceRequestBody>>::Write(
     base::Pickle* m,
     const param_type& p) {
   WriteParam(m, p.get() != NULL);
@@ -551,7 +551,7 @@
   }
 }
 
-bool ParamTraits<scoped_refptr<content::ResourceRequestBodyImpl>>::Read(
+bool ParamTraits<scoped_refptr<content::ResourceRequestBody>>::Read(
     const base::Pickle* m,
     base::PickleIterator* iter,
     param_type* r) {
@@ -569,17 +569,17 @@
   bool contains_sensitive_info;
   if (!ReadParam(m, iter, &contains_sensitive_info))
     return false;
-  *r = new content::ResourceRequestBodyImpl;
+  *r = new content::ResourceRequestBody;
   (*r)->swap_elements(&elements);
   (*r)->set_identifier(identifier);
   (*r)->set_contains_sensitive_info(contains_sensitive_info);
   return true;
 }
 
-void ParamTraits<scoped_refptr<content::ResourceRequestBodyImpl>>::Log(
+void ParamTraits<scoped_refptr<content::ResourceRequestBody>>::Log(
     const param_type& p,
     std::string* l) {
-  l->append("<ResourceRequestBodyImpl>");
+  l->append("<ResourceRequestBody>");
 }
 
 void ParamTraits<scoped_refptr<net::ct::SignedCertificateTimestamp>>::GetSize(
diff --git a/content/common/resource_messages.h b/content/common/resource_messages.h
index 0d0f797..66406d5 100644
--- a/content/common/resource_messages.h
+++ b/content/common/resource_messages.h
@@ -15,10 +15,10 @@
 #include "content/common/content_param_traits_macros.h"
 #include "content/common/navigation_params.h"
 #include "content/common/resource_request.h"
-#include "content/common/resource_request_body_impl.h"
 #include "content/common/resource_request_completion_status.h"
 #include "content/common/service_worker/service_worker_types.h"
 #include "content/public/common/common_param_traits.h"
+#include "content/public/common/resource_request_body.h"
 #include "content/public/common/resource_response.h"
 #include "ipc/ipc_message_macros.h"
 #include "net/base/request_priority.h"
@@ -110,8 +110,8 @@
 };
 
 template <>
-struct ParamTraits<scoped_refptr<content::ResourceRequestBodyImpl>> {
-  typedef scoped_refptr<content::ResourceRequestBodyImpl> param_type;
+struct ParamTraits<scoped_refptr<content::ResourceRequestBody>> {
+  typedef scoped_refptr<content::ResourceRequestBody> param_type;
   static void GetSize(base::PickleSizer* s, const param_type& p);
   static void Write(base::Pickle* m, const param_type& p);
   static bool Read(const base::Pickle* m,
diff --git a/content/common/resource_request.h b/content/common/resource_request.h
index 21219fbd..517622c 100644
--- a/content/common/resource_request.h
+++ b/content/common/resource_request.h
@@ -12,12 +12,12 @@
 #include "base/optional.h"
 #include "content/common/content_export.h"
 #include "content/common/navigation_params.h"
-#include "content/common/resource_request_body_impl.h"
 #include "content/common/service_worker/service_worker_types.h"
 #include "content/public/common/appcache_info.h"
 #include "content/public/common/previews_state.h"
 #include "content/public/common/request_context_frame_type.h"
 #include "content/public/common/request_context_type.h"
+#include "content/public/common/resource_request_body.h"
 #include "content/public/common/resource_type.h"
 #include "net/base/request_priority.h"
 #include "third_party/WebKit/public/platform/WebMixedContentContextType.h"
@@ -128,7 +128,7 @@
       REQUEST_CONTEXT_FRAME_TYPE_AUXILIARY;
 
   // Optional resource request body (may be null).
-  scoped_refptr<ResourceRequestBodyImpl> request_body;
+  scoped_refptr<ResourceRequestBody> request_body;
 
   // If true, then the response body will be downloaded to a file and the path
   // to that file will be provided in ResponseInfo::download_file_path.
diff --git a/content/common/resource_request_body_impl.cc b/content/common/resource_request_body_impl.cc
deleted file mode 100644
index 2484aec..0000000
--- a/content/common/resource_request_body_impl.cc
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/common/resource_request_body_impl.h"
-
-#include "base/strings/utf_string_conversions.h"
-#include "content/common/page_state_serialization.h"
-
-using blink::WebHTTPBody;
-using blink::WebString;
-
-namespace content {
-
-ResourceRequestBodyImpl::ResourceRequestBodyImpl()
-    : identifier_(0),
-      contains_sensitive_info_(false) {}
-
-void ResourceRequestBodyImpl::AppendBytes(const char* bytes, int bytes_len) {
-  if (bytes_len > 0) {
-    elements_.push_back(Element());
-    elements_.back().SetToBytes(bytes, bytes_len);
-  }
-}
-
-void ResourceRequestBodyImpl::AppendFileRange(
-    const base::FilePath& file_path,
-    uint64_t offset,
-    uint64_t length,
-    const base::Time& expected_modification_time) {
-  elements_.push_back(Element());
-  elements_.back().SetToFilePathRange(file_path, offset, length,
-                                      expected_modification_time);
-}
-
-void ResourceRequestBodyImpl::AppendBlob(const std::string& uuid) {
-  elements_.push_back(Element());
-  elements_.back().SetToBlob(uuid);
-}
-
-void ResourceRequestBodyImpl::AppendFileSystemFileRange(
-    const GURL& url,
-    uint64_t offset,
-    uint64_t length,
-    const base::Time& expected_modification_time) {
-  elements_.push_back(Element());
-  elements_.back().SetToFileSystemUrlRange(url, offset, length,
-                                           expected_modification_time);
-}
-
-std::vector<base::FilePath> ResourceRequestBodyImpl::GetReferencedFiles()
-    const {
-  std::vector<base::FilePath> result;
-  for (const auto& element : *elements()) {
-    if (element.type() == Element::TYPE_FILE)
-      result.push_back(element.path());
-  }
-  return result;
-}
-
-ResourceRequestBodyImpl::~ResourceRequestBodyImpl() {}
-
-}  // namespace content
diff --git a/content/common/resource_request_body_impl.h b/content/common/resource_request_body_impl.h
deleted file mode 100644
index 969f74d..0000000
--- a/content/common/resource_request_body_impl.h
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2014 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 CONTENT_COMMON_RESOURCE_REQUEST_BODY_IMPL_H_
-#define CONTENT_COMMON_RESOURCE_REQUEST_BODY_IMPL_H_
-
-#include <stdint.h>
-
-#include <vector>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "content/common/content_export.h"
-#include "content/public/common/resource_request_body.h"
-#include "storage/common/data_element.h"
-#include "url/gurl.h"
-
-namespace base {
-class FilePath;
-}
-
-namespace content {
-
-// A struct used to represent upload data. The data field is populated by
-// WebURLLoader from the data given as WebHTTPBody.
-class CONTENT_EXPORT ResourceRequestBodyImpl : public ResourceRequestBody {
- public:
-  typedef storage::DataElement Element;
-
-  ResourceRequestBodyImpl();
-
-  void AppendBytes(const char* bytes, int bytes_len);
-  void AppendFileRange(const base::FilePath& file_path,
-                       uint64_t offset,
-                       uint64_t length,
-                       const base::Time& expected_modification_time);
-  void AppendBlob(const std::string& uuid);
-  void AppendFileSystemFileRange(const GURL& url,
-                                 uint64_t offset,
-                                 uint64_t length,
-                                 const base::Time& expected_modification_time);
-
-  const std::vector<Element>* elements() const { return &elements_; }
-  std::vector<Element>* elements_mutable() { return &elements_; }
-  void swap_elements(std::vector<Element>* elements) {
-    elements_.swap(*elements);
-  }
-
-  // Identifies a particular upload instance, which is used by the cache to
-  // formulate a cache key.  This value should be unique across browser
-  // sessions.  A value of 0 is used to indicate an unspecified identifier.
-  void set_identifier(int64_t id) { identifier_ = id; }
-  int64_t identifier() const { return identifier_; }
-
-  // Returns paths referred to by |elements| of type Element::TYPE_FILE.
-  std::vector<base::FilePath> GetReferencedFiles() const;
-
-  // Sets the flag which indicates whether the post data contains sensitive
-  // information like passwords.
-  void set_contains_sensitive_info(bool contains_sensitive_info) {
-    contains_sensitive_info_ = contains_sensitive_info;
-  }
-  bool contains_sensitive_info() const { return contains_sensitive_info_; }
-
- private:
-  ~ResourceRequestBodyImpl() override;
-
-  std::vector<Element> elements_;
-  int64_t identifier_;
-
-  bool contains_sensitive_info_;
-
-  DISALLOW_COPY_AND_ASSIGN(ResourceRequestBodyImpl);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_COMMON_RESOURCE_REQUEST_BODY_IMPL_H_
diff --git a/content/network/url_loader_impl.cc b/content/network/url_loader_impl.cc
index 6cf3b40..6ecf2b73 100644
--- a/content/network/url_loader_impl.cc
+++ b/content/network/url_loader_impl.cc
@@ -73,75 +73,75 @@
 }
 
 // A subclass of net::UploadBytesElementReader which owns
-// ResourceRequestBodyImpl.
+// ResourceRequestBody.
 class BytesElementReader : public net::UploadBytesElementReader {
  public:
-  BytesElementReader(ResourceRequestBodyImpl* resource_request_body,
-                     const ResourceRequestBodyImpl::Element& element)
+  BytesElementReader(ResourceRequestBody* resource_request_body,
+                     const ResourceRequestBody::Element& element)
       : net::UploadBytesElementReader(element.bytes(), element.length()),
         resource_request_body_(resource_request_body) {
-    DCHECK_EQ(ResourceRequestBodyImpl::Element::TYPE_BYTES, element.type());
+    DCHECK_EQ(ResourceRequestBody::Element::TYPE_BYTES, element.type());
   }
 
   ~BytesElementReader() override {}
 
  private:
-  scoped_refptr<ResourceRequestBodyImpl> resource_request_body_;
+  scoped_refptr<ResourceRequestBody> resource_request_body_;
 
   DISALLOW_COPY_AND_ASSIGN(BytesElementReader);
 };
 
 // A subclass of net::UploadFileElementReader which owns
-// ResourceRequestBodyImpl.
+// ResourceRequestBody.
 // This class is necessary to ensure the BlobData and any attached shareable
 // files survive until upload completion.
 class FileElementReader : public net::UploadFileElementReader {
  public:
-  FileElementReader(ResourceRequestBodyImpl* resource_request_body,
+  FileElementReader(ResourceRequestBody* resource_request_body,
                     base::TaskRunner* task_runner,
-                    const ResourceRequestBodyImpl::Element& element)
+                    const ResourceRequestBody::Element& element)
       : net::UploadFileElementReader(task_runner,
                                      element.path(),
                                      element.offset(),
                                      element.length(),
                                      element.expected_modification_time()),
         resource_request_body_(resource_request_body) {
-    DCHECK_EQ(ResourceRequestBodyImpl::Element::TYPE_FILE, element.type());
+    DCHECK_EQ(ResourceRequestBody::Element::TYPE_FILE, element.type());
   }
 
   ~FileElementReader() override {}
 
  private:
-  scoped_refptr<ResourceRequestBodyImpl> resource_request_body_;
+  scoped_refptr<ResourceRequestBody> resource_request_body_;
 
   DISALLOW_COPY_AND_ASSIGN(FileElementReader);
 };
 
 // TODO: copied from content/browser/loader/upload_data_stream_builder.cc.
 std::unique_ptr<net::UploadDataStream> CreateUploadDataStream(
-    ResourceRequestBodyImpl* body,
+    ResourceRequestBody* body,
     base::SequencedTaskRunner* file_task_runner) {
   std::vector<std::unique_ptr<net::UploadElementReader>> element_readers;
   for (const auto& element : *body->elements()) {
     switch (element.type()) {
-      case ResourceRequestBodyImpl::Element::TYPE_BYTES:
+      case ResourceRequestBody::Element::TYPE_BYTES:
         element_readers.push_back(
             base::MakeUnique<BytesElementReader>(body, element));
         break;
-      case ResourceRequestBodyImpl::Element::TYPE_FILE:
+      case ResourceRequestBody::Element::TYPE_FILE:
         element_readers.push_back(base::MakeUnique<FileElementReader>(
             body, file_task_runner, element));
         break;
-      case ResourceRequestBodyImpl::Element::TYPE_FILE_FILESYSTEM:
+      case ResourceRequestBody::Element::TYPE_FILE_FILESYSTEM:
         NOTIMPLEMENTED();
         break;
-      case ResourceRequestBodyImpl::Element::TYPE_BLOB: {
+      case ResourceRequestBody::Element::TYPE_BLOB: {
         NOTIMPLEMENTED();
         break;
       }
-      case ResourceRequestBodyImpl::Element::TYPE_DISK_CACHE_ENTRY:
-      case ResourceRequestBodyImpl::Element::TYPE_BYTES_DESCRIPTION:
-      case ResourceRequestBodyImpl::Element::TYPE_UNKNOWN:
+      case ResourceRequestBody::Element::TYPE_DISK_CACHE_ENTRY:
+      case ResourceRequestBody::Element::TYPE_BYTES_DESCRIPTION:
+      case ResourceRequestBody::Element::TYPE_UNKNOWN:
         NOTREACHED();
         break;
     }
diff --git a/content/public/android/java/src/org/chromium/content/app/ContentChildProcessServiceDelegate.java b/content/public/android/java/src/org/chromium/content/app/ContentChildProcessServiceDelegate.java
index db4404d..2cc9ea4 100644
--- a/content/public/android/java/src/org/chromium/content/app/ContentChildProcessServiceDelegate.java
+++ b/content/public/android/java/src/org/chromium/content/app/ContentChildProcessServiceDelegate.java
@@ -88,7 +88,8 @@
     public boolean loadNativeLibrary(Context hostContext) {
         String processType =
                 CommandLine.getInstance().getSwitchValue(ContentSwitches.SWITCH_PROCESS_TYPE);
-        if (ContentSwitches.SWITCH_RENDERER_PROCESS.equals(processType)) {
+        // Enable selective JNI registration when the process is not the browser process.
+        if (processType != null) {
             JNIUtils.enableSelectiveJniRegistration();
         }
 
diff --git a/content/public/browser/android/synchronous_compositor.h b/content/public/browser/android/synchronous_compositor.h
index c9de9136..fca00ba 100644
--- a/content/public/browser/android/synchronous_compositor.h
+++ b/content/public/browser/android/synchronous_compositor.h
@@ -93,8 +93,9 @@
 
   // For delegated rendering, return resources from parent compositor to this.
   // Note that all resources must be returned before ReleaseHwDraw.
-  virtual void ReturnResources(uint32_t layer_tree_frame_sink_id,
-                               const cc::ReturnedResourceArray& resources) = 0;
+  virtual void ReturnResources(
+      uint32_t layer_tree_frame_sink_id,
+      const std::vector<cc::ReturnedResource>& resources) = 0;
 
   // "On demand" SW draw, into the supplied canvas (observing the transform
   // and clip set there-in).
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index 7f74100..5baebb3 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -149,7 +149,7 @@
 
 // Enables the old algorithm for processing audio constraints in getUserMedia().
 const base::Feature kMediaStreamOldAudioConstraints{
-    "MediaStreamOldAudioConstraints", base::FEATURE_ENABLED_BY_DEFAULT};
+    "MediaStreamOldAudioConstraints", base::FEATURE_DISABLED_BY_DEFAULT};
 
 // Enables the old algorithm for processing video constraints in getUserMedia().
 const base::Feature kMediaStreamOldVideoConstraints{
diff --git a/content/public/common/page_state.cc b/content/public/common/page_state.cc
index 5c58920..add79b76 100644
--- a/content/public/common/page_state.cc
+++ b/content/public/common/page_state.cc
@@ -10,6 +10,7 @@
 #include "base/strings/nullable_string16.h"
 #include "base/strings/utf_string_conversions.h"
 #include "content/common/page_state_serialization.h"
+#include "content/public/common/resource_request_body.h"
 
 namespace content {
 namespace {
@@ -85,12 +86,12 @@
   if (optional_body_data || optional_body_file_path) {
     if (optional_body_data) {
       std::string body_data(optional_body_data);
-      state.top.http_body.request_body = new ResourceRequestBodyImpl();
+      state.top.http_body.request_body = new ResourceRequestBody();
       state.top.http_body.request_body->AppendBytes(body_data.data(),
                                                     body_data.size());
     }
     if (optional_body_file_path) {
-      state.top.http_body.request_body = new ResourceRequestBodyImpl();
+      state.top.http_body.request_body = new ResourceRequestBody();
       state.top.http_body.request_body->AppendFileRange(
           *optional_body_file_path,
           0, std::numeric_limits<uint64_t>::max(),
diff --git a/content/public/common/resource_request_body.cc b/content/public/common/resource_request_body.cc
index e273b9e..3e0a8c8 100644
--- a/content/public/common/resource_request_body.cc
+++ b/content/public/common/resource_request_body.cc
@@ -4,23 +4,20 @@
 
 #include "content/public/common/resource_request_body.h"
 
-#include "content/common/resource_request_body_impl.h"
-
 #if defined(OS_ANDROID)
 #include "content/common/android/resource_request_body_android.h"
 #endif
 
 namespace content {
 
-ResourceRequestBody::ResourceRequestBody() {}
-
-ResourceRequestBody::~ResourceRequestBody() {}
+ResourceRequestBody::ResourceRequestBody()
+    : identifier_(0), contains_sensitive_info_(false) {}
 
 // static
 scoped_refptr<ResourceRequestBody> ResourceRequestBody::CreateFromBytes(
     const char* bytes,
     size_t length) {
-  scoped_refptr<ResourceRequestBodyImpl> result = new ResourceRequestBodyImpl();
+  scoped_refptr<ResourceRequestBody> result = new ResourceRequestBody();
   result->AppendBytes(bytes, length);
   return result;
 }
@@ -29,7 +26,7 @@
 base::android::ScopedJavaLocalRef<jobject> ResourceRequestBody::ToJavaObject(
     JNIEnv* env) {
   return ConvertResourceRequestBodyToJavaObject(
-      env, static_cast<ResourceRequestBodyImpl*>(this));
+      env, static_cast<ResourceRequestBody*>(this));
 }
 
 // static
@@ -40,4 +37,47 @@
 }
 #endif
 
+void ResourceRequestBody::AppendBytes(const char* bytes, int bytes_len) {
+  if (bytes_len > 0) {
+    elements_.push_back(Element());
+    elements_.back().SetToBytes(bytes, bytes_len);
+  }
+}
+
+void ResourceRequestBody::AppendFileRange(
+    const base::FilePath& file_path,
+    uint64_t offset,
+    uint64_t length,
+    const base::Time& expected_modification_time) {
+  elements_.push_back(Element());
+  elements_.back().SetToFilePathRange(file_path, offset, length,
+                                      expected_modification_time);
+}
+
+void ResourceRequestBody::AppendBlob(const std::string& uuid) {
+  elements_.push_back(Element());
+  elements_.back().SetToBlob(uuid);
+}
+
+void ResourceRequestBody::AppendFileSystemFileRange(
+    const GURL& url,
+    uint64_t offset,
+    uint64_t length,
+    const base::Time& expected_modification_time) {
+  elements_.push_back(Element());
+  elements_.back().SetToFileSystemUrlRange(url, offset, length,
+                                           expected_modification_time);
+}
+
+std::vector<base::FilePath> ResourceRequestBody::GetReferencedFiles() const {
+  std::vector<base::FilePath> result;
+  for (const auto& element : *elements()) {
+    if (element.type() == Element::TYPE_FILE)
+      result.push_back(element.path());
+  }
+  return result;
+}
+
+ResourceRequestBody::~ResourceRequestBody() {}
+
 }  // namespace content
diff --git a/content/public/common/resource_request_body.h b/content/public/common/resource_request_body.h
index 606c319..bf2bf5d5 100644
--- a/content/public/common/resource_request_body.h
+++ b/content/public/common/resource_request_body.h
@@ -14,6 +14,8 @@
 #include "base/memory/ref_counted.h"
 #include "build/build_config.h"
 #include "content/common/content_export.h"
+#include "storage/common/data_element.h"
+#include "url/gurl.h"
 
 #if defined(OS_ANDROID)
 #include <jni.h>
@@ -23,22 +25,13 @@
 namespace content {
 
 // ResourceRequestBody represents body (i.e. upload data) of a HTTP request.
-//
-// This class is intentionally opaque:
-// *) Embedders cannot inspect the payload of ResourceRequestBody.  Only the
-//    //content layer can decompose ResourceRequestBody into references to file
-//    ranges, byte vectors, blob uris, etc.
-// *) Embedders can get instances of ResourceRequestBody only by
-//    - receiving an instance created inside //content layer (e.g. receiving it
-//      via content::OpenURLParams),
-//    - calling CreateFromBytes with a vector of bytes (e.g. to support
-//      Android's WebView::postUrl API, to support DoSearchByImageInNewTab and
-//      to support test code).
-// *) Embedders typically end up passing ResourceRequestBody back into the
-//    //content layer via content::NavigationController::LoadUrlParams.
 class CONTENT_EXPORT ResourceRequestBody
     : public base::RefCountedThreadSafe<ResourceRequestBody> {
  public:
+  typedef storage::DataElement Element;
+
+  ResourceRequestBody();
+
   // Creates ResourceRequestBody that holds a copy of |bytes|.
   static scoped_refptr<ResourceRequestBody> CreateFromBytes(const char* bytes,
                                                             size_t length);
@@ -55,12 +48,50 @@
       const base::android::JavaParamRef<jobject>& java_object);
 #endif
 
- protected:
-  ResourceRequestBody();
-  virtual ~ResourceRequestBody();
+  void AppendBytes(const char* bytes, int bytes_len);
+  void AppendFileRange(const base::FilePath& file_path,
+                       uint64_t offset,
+                       uint64_t length,
+                       const base::Time& expected_modification_time);
+
+  void AppendBlob(const std::string& uuid);
+  void AppendFileSystemFileRange(const GURL& url,
+                                 uint64_t offset,
+                                 uint64_t length,
+                                 const base::Time& expected_modification_time);
+
+  const std::vector<Element>* elements() const { return &elements_; }
+  std::vector<Element>* elements_mutable() { return &elements_; }
+  void swap_elements(std::vector<Element>* elements) {
+    elements_.swap(*elements);
+  }
+
+  // Identifies a particular upload instance, which is used by the cache to
+  // formulate a cache key.  This value should be unique across browser
+  // sessions.  A value of 0 is used to indicate an unspecified identifier.
+  void set_identifier(int64_t id) { identifier_ = id; }
+  int64_t identifier() const { return identifier_; }
+
+  // Returns paths referred to by |elements| of type Element::TYPE_FILE.
+  std::vector<base::FilePath> GetReferencedFiles() const;
+
+  // Sets the flag which indicates whether the post data contains sensitive
+  // information like passwords.
+  void set_contains_sensitive_info(bool contains_sensitive_info) {
+    contains_sensitive_info_ = contains_sensitive_info;
+  }
+  bool contains_sensitive_info() const { return contains_sensitive_info_; }
 
  private:
   friend class base::RefCountedThreadSafe<ResourceRequestBody>;
+
+  ~ResourceRequestBody();
+
+  std::vector<Element> elements_;
+  int64_t identifier_;
+
+  bool contains_sensitive_info_;
+
   DISALLOW_COPY_AND_ASSIGN(ResourceRequestBody);
 };
 
diff --git a/content/public/test/navigation_simulator.cc b/content/public/test/navigation_simulator.cc
index 70ba319..06dc98a 100644
--- a/content/public/test/navigation_simulator.cc
+++ b/content/public/test/navigation_simulator.cc
@@ -13,6 +13,7 @@
 #include "content/public/browser/navigation_throttle.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/browser_side_navigation_policy.h"
+#include "content/public/common/resource_request_body.h"
 #include "content/test/test_navigation_url_loader.h"
 #include "content/test/test_render_frame_host.h"
 #include "net/base/load_flags.h"
@@ -145,7 +146,7 @@
         std::vector<GURL>(), base::TimeTicks::Now()));
     DCHECK_EQ(handle_, render_frame_host_->navigation_handle());
     handle_->WillStartRequest(
-        "GET", scoped_refptr<content::ResourceRequestBodyImpl>(), referrer_,
+        "GET", scoped_refptr<content::ResourceRequestBody>(), referrer_,
         true /* user_gesture */, transition_, false /* is_external_protocol */,
         REQUEST_CONTEXT_TYPE_LOCATION,
         blink::WebMixedContentContextType::kNotMixedContent,
diff --git a/content/public/test/test_synchronous_compositor_android.cc b/content/public/test/test_synchronous_compositor_android.cc
index c368865c..990ead5 100644
--- a/content/public/test/test_synchronous_compositor_android.cc
+++ b/content/public/test/test_synchronous_compositor_android.cc
@@ -43,7 +43,7 @@
 
 void TestSynchronousCompositor::ReturnResources(
     uint32_t layer_tree_frame_sink_id,
-    const cc::ReturnedResourceArray& resources) {
+    const std::vector<cc::ReturnedResource>& resources) {
   ReturnedResources returned_resources;
   returned_resources.layer_tree_frame_sink_id = layer_tree_frame_sink_id;
   returned_resources.resources = resources;
diff --git a/content/public/test/test_synchronous_compositor_android.h b/content/public/test/test_synchronous_compositor_android.h
index 8bc14bbd..51f8534 100644
--- a/content/public/test/test_synchronous_compositor_android.h
+++ b/content/public/test/test_synchronous_compositor_android.h
@@ -32,8 +32,9 @@
       const gfx::Size& viewport_size,
       const gfx::Rect& viewport_rect_for_tile_priority,
       const gfx::Transform& transform_for_tile_priority) override;
-  void ReturnResources(uint32_t layer_tree_frame_sink_id,
-                       const cc::ReturnedResourceArray& resources) override;
+  void ReturnResources(
+      uint32_t layer_tree_frame_sink_id,
+      const std::vector<cc::ReturnedResource>& resources) override;
   bool DemandDrawSw(SkCanvas* canvas) override;
   void SetMemoryPolicy(size_t bytes_limit) override {}
   void DidChangeRootLayerScrollOffset(
@@ -51,7 +52,7 @@
     ~ReturnedResources();
 
     uint32_t layer_tree_frame_sink_id;
-    cc::ReturnedResourceArray resources;
+    std::vector<cc::ReturnedResource> resources;
   };
   using FrameAckArray = std::vector<ReturnedResources>;
   void SwapReturnedResources(FrameAckArray* array);
diff --git a/content/public/test/text_input_test_utils.cc b/content/public/test/text_input_test_utils.cc
index 17d1cca..19527714 100644
--- a/content/public/test/text_input_test_utils.cc
+++ b/content/public/test/text_input_test_utils.cc
@@ -6,6 +6,8 @@
 
 #include <unordered_set>
 
+#include "content/browser/frame_host/frame_tree.h"
+#include "content/browser/frame_host/frame_tree_node.h"
 #include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_view_aura.h"
@@ -307,6 +309,25 @@
       selection_end);
 }
 
+bool DestroyRenderWidgetHost(int32_t process_id,
+                             int32_t local_root_routing_id) {
+  RenderFrameHostImpl* rfh =
+      RenderFrameHostImpl::FromID(process_id, local_root_routing_id);
+  if (!rfh)
+    return false;
+
+  while (!rfh->is_local_root())
+    rfh = rfh->GetParent();
+
+  FrameTreeNode* ftn = rfh->frame_tree_node();
+  if (ftn->IsMainFrame()) {
+    WebContents::FromRenderFrameHost(rfh)->Close();
+  } else {
+    ftn->frame_tree()->RemoveFrame(ftn);
+  }
+  return true;
+}
+
 size_t GetRegisteredViewsCountFromTextInputManager(WebContents* web_contents) {
   std::unordered_set<RenderWidgetHostView*> views;
   TextInputManager* manager =
diff --git a/content/public/test/text_input_test_utils.h b/content/public/test/text_input_test_utils.h
index ec3f134..8538b18 100644
--- a/content/public/test/text_input_test_utils.h
+++ b/content/public/test/text_input_test_utils.h
@@ -88,6 +88,10 @@
     int selection_start,
     int selection_end);
 
+// Immediately destroys the RenderWidgetHost corresponding to the local root
+// which is identified by the given process ID and RenderFrameHost routing ID.
+bool DestroyRenderWidgetHost(int32_t process_id, int32_t local_root_routing_id);
+
 // This class provides the necessary API for accessing the state of and also
 // observing the TextInputManager for WebContents.
 class TextInputManagerTester {
@@ -236,6 +240,11 @@
   // BrowserMessageFilter overrides.
   bool OnMessageReceived(const IPC::Message& message) override;
 
+  // Sets a callback for the string for range IPC arriving from the renderer.
+  // The callback is invoked before that of TextInputClientMac and is handled on
+  // UI thread.
+  void SetStringForRangeCallback(const base::Closure& callback);
+
   RenderProcessHost* process() const { return host_; }
   std::string string_from_range() { return string_from_range_; }
 
@@ -244,6 +253,7 @@
   RenderProcessHost* const host_;
   std::string string_from_range_;
   bool received_string_from_range_;
+  base::Closure string_for_range_callback_;
   scoped_refptr<MessageLoopRunner> message_loop_runner_;
 
   DISALLOW_COPY_AND_ASSIGN(TestTextInputClientMessageFilter);
diff --git a/content/public/test/text_input_test_utils_mac.mm b/content/public/test/text_input_test_utils_mac.mm
index 29de863..a07f17c 100644
--- a/content/public/test/text_input_test_utils_mac.mm
+++ b/content/public/test/text_input_test_utils_mac.mm
@@ -38,7 +38,13 @@
 
 bool TestTextInputClientMessageFilter::OnMessageReceived(
     const IPC::Message& message) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
   if (message.type() == TextInputClientReplyMsg_GotStringForRange::ID) {
+    if (!string_for_range_callback_.is_null()) {
+      BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+                              string_for_range_callback_);
+    }
+
     received_string_from_range_ = true;
 
     // Now decode the string to get the word.
@@ -61,6 +67,11 @@
   return false;
 }
 
+void TestTextInputClientMessageFilter::SetStringForRangeCallback(
+    const base::Closure& callback) {
+  string_for_range_callback_ = callback;
+}
+
 void AskForLookUpDictionaryForRange(RenderWidgetHostView* tab_view,
                                     const gfx::Range& range) {
   RenderWidgetHostViewCocoa* cocoa_view =
diff --git a/content/renderer/android/synchronous_layer_tree_frame_sink.cc b/content/renderer/android/synchronous_layer_tree_frame_sink.cc
index 2237321..c007c2d 100644
--- a/content/renderer/android/synchronous_layer_tree_frame_sink.cc
+++ b/content/renderer/android/synchronous_layer_tree_frame_sink.cc
@@ -229,7 +229,7 @@
 
   if (fallback_tick_running_) {
     DCHECK(frame.resource_list.empty());
-    cc::ReturnedResourceArray return_resources;
+    std::vector<cc::ReturnedResource> return_resources;
     ReclaimResources(return_resources);
     did_submit_frame_ = true;
     return;
@@ -427,7 +427,7 @@
 
 void SynchronousLayerTreeFrameSink::OnReclaimResources(
     uint32_t layer_tree_frame_sink_id,
-    const cc::ReturnedResourceArray& resources) {
+    const std::vector<cc::ReturnedResource>& resources) {
   // Ignore message if it's a stale one coming from a different output surface
   // (e.g. after a lost context).
   if (layer_tree_frame_sink_id != layer_tree_frame_sink_id_)
@@ -484,7 +484,7 @@
 }
 
 void SynchronousLayerTreeFrameSink::DidReceiveCompositorFrameAck(
-    const cc::ReturnedResourceArray& resources) {
+    const std::vector<cc::ReturnedResource>& resources) {
   ReclaimResources(resources);
 }
 
@@ -492,7 +492,7 @@
     const cc::BeginFrameArgs& args) {}
 
 void SynchronousLayerTreeFrameSink::ReclaimResources(
-    const cc::ReturnedResourceArray& resources) {
+    const std::vector<cc::ReturnedResource>& resources) {
   DCHECK(resources.empty());
   client_->ReclaimResources(resources);
 }
diff --git a/content/renderer/android/synchronous_layer_tree_frame_sink.h b/content/renderer/android/synchronous_layer_tree_frame_sink.h
index cef49ac..19e9831 100644
--- a/content/renderer/android/synchronous_layer_tree_frame_sink.h
+++ b/content/renderer/android/synchronous_layer_tree_frame_sink.h
@@ -97,9 +97,10 @@
 
   // CompositorFrameSinkSupportClient implementation.
   void DidReceiveCompositorFrameAck(
-      const cc::ReturnedResourceArray& resources) override;
+      const std::vector<cc::ReturnedResource>& resources) override;
   void OnBeginFrame(const cc::BeginFrameArgs& args) override;
-  void ReclaimResources(const cc::ReturnedResourceArray& resources) override;
+  void ReclaimResources(
+      const std::vector<cc::ReturnedResource>& resources) override;
   void WillDrawSurface(const cc::LocalSurfaceId& local_surface_id,
                        const gfx::Rect& damage_rect) override;
 
@@ -119,7 +120,7 @@
   // IPC handlers.
   void SetMemoryPolicy(size_t bytes_limit);
   void OnReclaimResources(uint32_t layer_tree_frame_sink_id,
-                          const cc::ReturnedResourceArray& resources);
+                          const std::vector<cc::ReturnedResource>& resources);
 
   const int routing_id_;
   const uint32_t layer_tree_frame_sink_id_;
diff --git a/content/renderer/media/renderer_gpu_video_accelerator_factories.cc b/content/renderer/media/renderer_gpu_video_accelerator_factories.cc
index 9ba79d4a..44dc391e 100644
--- a/content/renderer/media/renderer_gpu_video_accelerator_factories.cc
+++ b/content/renderer/media/renderer_gpu_video_accelerator_factories.cc
@@ -243,6 +243,16 @@
   gles2->ShallowFlushCHROMIUM();
 }
 
+void RendererGpuVideoAcceleratorFactories::ShallowFlushCHROMIUM() {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+  if (CheckContextLost())
+    return;
+
+  cc::ContextProvider::ScopedContextLock lock(context_provider_);
+  gpu::gles2::GLES2Interface* gles2 = lock.ContextGL();
+  gles2->ShallowFlushCHROMIUM();
+}
+
 std::unique_ptr<gfx::GpuMemoryBuffer>
 RendererGpuVideoAcceleratorFactories::CreateGpuMemoryBuffer(
     const gfx::Size& size,
diff --git a/content/renderer/media/renderer_gpu_video_accelerator_factories.h b/content/renderer/media/renderer_gpu_video_accelerator_factories.h
index c638902..ba1d212 100644
--- a/content/renderer/media/renderer_gpu_video_accelerator_factories.h
+++ b/content/renderer/media/renderer_gpu_video_accelerator_factories.h
@@ -75,6 +75,7 @@
   void DeleteTexture(uint32_t texture_id) override;
   gpu::SyncToken CreateSyncToken() override;
   void WaitSyncToken(const gpu::SyncToken& sync_token) override;
+  void ShallowFlushCHROMIUM() override;
 
   std::unique_ptr<gfx::GpuMemoryBuffer> CreateGpuMemoryBuffer(
       const gfx::Size& size,
diff --git a/content/renderer/media_recorder/video_track_recorder.cc b/content/renderer/media_recorder/video_track_recorder.cc
index 6c7a21f4..d128bd7c 100644
--- a/content/renderer/media_recorder/video_track_recorder.cc
+++ b/content/renderer/media_recorder/video_track_recorder.cc
@@ -75,6 +75,14 @@
                   static_cast<int>(CodecId::LAST),
               "|kPreferredCodecIdAndVEAProfiles| should consider all CodecIds");
 
+// The maximum number of frames that we keep the reference alive for encode.
+// This guarantees that there is limit on the number of frames in a FIFO queue
+// that are being encoded and frames coming after this limit is reached are
+// dropped.
+// TODO(emircan): Make this a LIFO queue that has different sizes for each
+// encoder implementation.
+const int kMaxNumberOfFramesInEncode = 10;
+
 // Class to encapsulate the enumeration of CodecIds/VideoCodecProfiles supported
 // by the VEA underlying platform. Provides methods to query the preferred
 // CodecId and to check if a given CodecId is supported.
@@ -168,7 +176,8 @@
       encoding_task_runner_(encoding_task_runner),
       paused_(false),
       on_encoded_video_callback_(on_encoded_video_callback),
-      bits_per_second_(bits_per_second) {
+      bits_per_second_(bits_per_second),
+      num_frames_in_encode_(0) {
   DCHECK(!on_encoded_video_callback_.is_null());
   if (encoding_task_runner_)
     return;
@@ -200,6 +209,11 @@
     return;
   }
 
+  if (num_frames_in_encode_ > kMaxNumberOfFramesInEncode) {
+    DLOG(WARNING) << "Too many frames are queued up. Dropping this one.";
+    return;
+  }
+
   if (video_frame->HasTextures()) {
     main_task_runner_->PostTask(
         FROM_HERE, base::Bind(&Encoder::RetrieveFrameOnMainThread, this,
@@ -207,14 +221,23 @@
     return;
   }
 
-  scoped_refptr<media::VideoFrame> frame = video_frame;
+  scoped_refptr<media::VideoFrame> wrapped_frame;
   // Drop alpha channel if the encoder does not support it yet.
-  if (!CanEncodeAlphaChannel() && frame->format() == media::PIXEL_FORMAT_YV12A)
-    frame = media::WrapAsI420VideoFrame(video_frame);
+  if (!CanEncodeAlphaChannel() &&
+      video_frame->format() == media::PIXEL_FORMAT_YV12A) {
+    wrapped_frame = media::WrapAsI420VideoFrame(video_frame);
+  } else {
+    wrapped_frame = media::VideoFrame::WrapVideoFrame(
+        video_frame, video_frame->format(), video_frame->visible_rect(),
+        video_frame->natural_size());
+  }
+  wrapped_frame->AddDestructionObserver(media::BindToCurrentLoop(base::Bind(
+      &VideoTrackRecorder::Encoder::FrameReleased, this, video_frame)));
+  ++num_frames_in_encode_;
 
   encoding_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&Encoder::EncodeOnEncodingTaskRunner, this, frame,
-                            capture_timestamp));
+      FROM_HERE, base::Bind(&Encoder::EncodeOnEncodingTaskRunner, this,
+                            wrapped_frame, capture_timestamp));
 }
 
 void VideoTrackRecorder::Encoder::RetrieveFrameOnMainThread(
@@ -330,6 +353,12 @@
   return false;
 }
 
+void VideoTrackRecorder::Encoder::FrameReleased(
+    const scoped_refptr<VideoFrame>& frame) {
+  DCHECK(origin_task_runner_->BelongsToCurrentThread());
+  --num_frames_in_encode_;
+}
+
 // static
 VideoTrackRecorder::CodecId VideoTrackRecorder::GetPreferredCodecId() {
   return GetCodecEnumerator()->GetPreferredCodecId();
diff --git a/content/renderer/media_recorder/video_track_recorder.h b/content/renderer/media_recorder/video_track_recorder.h
index 282c6df7..9efa4e61 100644
--- a/content/renderer/media_recorder/video_track_recorder.h
+++ b/content/renderer/media_recorder/video_track_recorder.h
@@ -116,12 +116,17 @@
 
    protected:
     friend class base::RefCountedThreadSafe<Encoder>;
+    friend class VideoTrackRecorderTest;
+
     virtual ~Encoder();
 
     virtual void EncodeOnEncodingTaskRunner(
         scoped_refptr<media::VideoFrame> frame,
         base::TimeTicks capture_timestamp) = 0;
 
+    // Called when the frame reference is released after encode.
+    void FrameReleased(const scoped_refptr<media::VideoFrame>& frame);
+
     // Used to shutdown properly on the same thread we were created.
     const scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
 
@@ -144,6 +149,9 @@
     // Target bitrate for video encoding. If 0, a standard bitrate is used.
     const int32_t bits_per_second_;
 
+    // Number of frames that we keep the reference alive for encode.
+    uint32_t num_frames_in_encode_;
+
     // Used to retrieve incoming opaque VideoFrames (i.e. VideoFrames backed by
     // textures). Created on-demand on |main_task_runner_|.
     std::unique_ptr<media::SkCanvasVideoRenderer> video_renderer_;
diff --git a/content/renderer/media_recorder/video_track_recorder_unittest.cc b/content/renderer/media_recorder/video_track_recorder_unittest.cc
index ee70c84..287127c 100644
--- a/content/renderer/media_recorder/video_track_recorder_unittest.cc
+++ b/content/renderer/media_recorder/video_track_recorder_unittest.cc
@@ -129,6 +129,10 @@
     return video_track_recorder_->encoder_.get() != nullptr;
   }
 
+  uint32_t NumFramesInEncode() {
+    return video_track_recorder_->encoder_->num_frames_in_encode_;
+  }
+
   // A ChildProcess and a MessageLoopForUI are both needed to fool the Tracks
   // and Sources below into believing they are on the right threads.
   const base::MessageLoopForUI message_loop_;
@@ -325,6 +329,26 @@
   Mock::VerifyAndClearExpectations(this);
 }
 
+// Inserts a frame for encode and makes sure that it is released properly and
+// NumFramesInEncode() is updated.
+TEST_F(VideoTrackRecorderTest, ReleasesFrame) {
+  InitializeRecorder(VideoTrackRecorder::CodecId::VP8);
+
+  const gfx::Size& frame_size = kTrackRecorderTestSize[0];
+  scoped_refptr<VideoFrame> video_frame =
+      VideoFrame::CreateBlackFrame(frame_size);
+
+  base::RunLoop run_loop;
+  video_frame->AddDestructionObserver(run_loop.QuitClosure());
+  EXPECT_CALL(*this, DoOnEncodedVideo(_, _, _, _, true)).Times(1);
+  Encode(video_frame, base::TimeTicks::Now());
+  video_frame = nullptr;
+  run_loop.Run();
+  EXPECT_EQ(0u, NumFramesInEncode());
+
+  Mock::VerifyAndClearExpectations(this);
+}
+
 INSTANTIATE_TEST_CASE_P(,
                         VideoTrackRecorderTest,
                         ::testing::Combine(ValuesIn(kTrackRecorderTestCodec),
diff --git a/content/renderer/media_recorder/vpx_encoder.cc b/content/renderer/media_recorder/vpx_encoder.cc
index 65cb740..7c9484e 100644
--- a/content/renderer/media_recorder/vpx_encoder.cc
+++ b/content/renderer/media_recorder/vpx_encoder.cc
@@ -70,7 +70,7 @@
   DCHECK(encoding_task_runner_->BelongsToCurrentThread());
 
   const gfx::Size frame_size = frame->visible_rect().size();
-  const base::TimeDelta duration = EstimateFrameDuration(frame);
+  base::TimeDelta duration = EstimateFrameDuration(frame);
   const media::WebmMuxer::VideoParameters video_params(frame);
 
   if (!IsInitialized(codec_config_) ||
@@ -79,6 +79,8 @@
   }
 
   const bool frame_has_alpha = frame->format() == media::PIXEL_FORMAT_YV12A;
+  // Split the duration between two encoder instances if alpha is encoded.
+  duration = frame_has_alpha ? duration / 2 : duration;
   if (frame_has_alpha && (!IsInitialized(alpha_codec_config_) ||
                           gfx::Size(alpha_codec_config_.g_w,
                                     alpha_codec_config_.g_h) != frame_size)) {
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 7820e498..8e48441 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -5874,7 +5874,7 @@
 void RenderFrameImpl::OpenURL(
     const GURL& url,
     bool uses_post,
-    const scoped_refptr<ResourceRequestBodyImpl>& resource_request_body,
+    const scoped_refptr<ResourceRequestBody>& resource_request_body,
     const std::string& extra_headers,
     const Referrer& referrer,
     WebNavigationPolicy policy,
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index f756ebb9..2b33676a 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -148,7 +148,7 @@
 class RenderViewImpl;
 class RenderWidget;
 class RenderWidgetFullscreenPepper;
-class ResourceRequestBodyImpl;
+class ResourceRequestBody;
 class ScreenOrientationDispatcher;
 class SharedWorkerRepository;
 class UserMediaClientImpl;
@@ -970,16 +970,15 @@
   // |is_history_navigation_in_new_child| is true, the browser process should
   // look for a matching FrameNavigationEntry in the last committed entry to use
   // instead of |url|.
-  void OpenURL(
-      const GURL& url,
-      bool uses_post,
-      const scoped_refptr<ResourceRequestBodyImpl>& resource_request_body,
-      const std::string& extra_headers,
-      const Referrer& referrer,
-      blink::WebNavigationPolicy policy,
-      bool should_replace_current_entry,
-      bool is_history_navigation_in_new_child,
-      blink::WebTriggeringEventInfo triggering_event_info);
+  void OpenURL(const GURL& url,
+               bool uses_post,
+               const scoped_refptr<ResourceRequestBody>& resource_request_body,
+               const std::string& extra_headers,
+               const Referrer& referrer,
+               blink::WebNavigationPolicy policy,
+               bool should_replace_current_entry,
+               bool is_history_navigation_in_new_child,
+               blink::WebTriggeringEventInfo triggering_event_info);
 
   // Performs a navigation in the frame. This provides a unified function for
   // the current code path and the browser-side navigation path (in
diff --git a/content/renderer/render_view_browsertest.cc b/content/renderer/render_view_browsertest.cc
index c1b14ad..934b624 100644
--- a/content/renderer/render_view_browsertest.cc
+++ b/content/renderer/render_view_browsertest.cc
@@ -39,6 +39,7 @@
 #include "content/public/common/browser_side_navigation_policy.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/page_zoom.h"
+#include "content/public/common/resource_request_body.h"
 #include "content/public/common/url_constants.h"
 #include "content/public/common/url_utils.h"
 #include "content/public/renderer/content_renderer_client.h"
@@ -609,7 +610,7 @@
   // Set up post data.
   const char raw_data[] = "post \0\ndata";
   const size_t length = arraysize(raw_data);
-  scoped_refptr<ResourceRequestBodyImpl> post_data(new ResourceRequestBodyImpl);
+  scoped_refptr<ResourceRequestBody> post_data(new ResourceRequestBody);
   post_data->AppendBytes(raw_data, length);
   common_params.post_data = post_data;
 
diff --git a/content/shell/BUILD.gn b/content/shell/BUILD.gn
index 21fb08f3..785bd7a 100644
--- a/content/shell/BUILD.gn
+++ b/content/shell/BUILD.gn
@@ -222,7 +222,6 @@
     "//base/third_party/dynamic_annotations",
     "//cc",
     "//components/cdm/renderer",
-    "//components/crash/content/app:app_breakpad_mac_win_to_be_deleted",
     "//components/keyed_service/content",
     "//components/network_session_configurator/common",
     "//components/plugins/renderer",
@@ -280,6 +279,11 @@
     "//v8",
   ]
 
+  if (!is_fuchsia) {
+    deps +=
+        [ "//components/crash/content/app:app_breakpad_mac_win_to_be_deleted" ]
+  }
+
   # Annoyingly, this target and layouttest_support have circular includes.
   allow_circular_includes_from = [ "//content/test:layouttest_support" ]
 
@@ -327,7 +331,7 @@
     ]
   }
 
-  if (is_posix && !is_mac) {
+  if (is_posix && !is_mac && !is_fuchsia) {
     deps += [
       "//components/crash/content/app",
       "//components/crash/content/browser",
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 7ea62c4..3098a8e 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1112,7 +1112,6 @@
     "../browser/cache_storage/cache_storage_scheduler_unittest.cc",
     "../browser/child_process_security_policy_unittest.cc",
     "../browser/cocoa/system_hotkey_map_unittest.mm",
-    "../browser/compositor/gpu_vsync_begin_frame_source_unittest.cc",
     "../browser/compositor/reflector_impl_unittest.cc",
     "../browser/compositor/software_browser_compositor_output_surface_unittest.cc",
     "../browser/compositor/software_output_device_mac_unittest.mm",
@@ -1832,7 +1831,6 @@
   }
   if (!use_aura && !is_mac) {
     sources -= [
-      "../browser/compositor/gpu_vsync_begin_frame_source_unittest.cc",
       "../browser/compositor/reflector_impl_unittest.cc",
       "../browser/compositor/software_browser_compositor_output_surface_unittest.cc",
       "../browser/renderer_host/compositor_resize_lock_unittest.cc",
diff --git a/content/test/fake_renderer_compositor_frame_sink.cc b/content/test/fake_renderer_compositor_frame_sink.cc
index 9ae044e..a6c3efc 100644
--- a/content/test/fake_renderer_compositor_frame_sink.cc
+++ b/content/test/fake_renderer_compositor_frame_sink.cc
@@ -14,13 +14,13 @@
 FakeRendererCompositorFrameSink::~FakeRendererCompositorFrameSink() = default;
 
 void FakeRendererCompositorFrameSink::DidReceiveCompositorFrameAck(
-    const cc::ReturnedResourceArray& resources) {
+    const std::vector<cc::ReturnedResource>& resources) {
   ReclaimResources(resources);
   did_receive_ack_ = true;
 }
 
 void FakeRendererCompositorFrameSink::ReclaimResources(
-    const cc::ReturnedResourceArray& resources) {
+    const std::vector<cc::ReturnedResource>& resources) {
   last_reclaimed_resources_ = resources;
 }
 
diff --git a/content/test/fake_renderer_compositor_frame_sink.h b/content/test/fake_renderer_compositor_frame_sink.h
index 0f16c881..5e2655b 100644
--- a/content/test/fake_renderer_compositor_frame_sink.h
+++ b/content/test/fake_renderer_compositor_frame_sink.h
@@ -21,15 +21,16 @@
   ~FakeRendererCompositorFrameSink() override;
 
   bool did_receive_ack() { return did_receive_ack_; }
-  cc::ReturnedResourceArray& last_reclaimed_resources() {
+  std::vector<cc::ReturnedResource>& last_reclaimed_resources() {
     return last_reclaimed_resources_;
   }
 
   // cc::mojom::CompositorFrameSinkClient implementation.
   void DidReceiveCompositorFrameAck(
-      const cc::ReturnedResourceArray& resources) override;
+      const std::vector<cc::ReturnedResource>& resources) override;
   void OnBeginFrame(const cc::BeginFrameArgs& args) override {}
-  void ReclaimResources(const cc::ReturnedResourceArray& resources) override;
+  void ReclaimResources(
+      const std::vector<cc::ReturnedResource>& resources) override;
 
   // Resets test data.
   void Reset();
@@ -41,7 +42,7 @@
   mojo::Binding<cc::mojom::CompositorFrameSinkClient> binding_;
   cc::mojom::CompositorFrameSinkPtr sink_;
   bool did_receive_ack_ = false;
-  cc::ReturnedResourceArray last_reclaimed_resources_;
+  std::vector<cc::ReturnedResource> last_reclaimed_resources_;
 
   DISALLOW_COPY_AND_ASSIGN(FakeRendererCompositorFrameSink);
 };
diff --git a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
index e6e85e3c..9cee0c6 100644
--- a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
@@ -737,6 +737,9 @@
     self.Flaky('deqp/functional/gles3/texturespecification/' +
         'random_teximage2d_2d.html',
         ['linux', 'amd', 'intel'], bug=618447)
+    self.Fail('conformance2/renderbuffers/' +
+        'multisampled-depth-renderbuffer-initialization.html',
+        ['linux', 'amd', 'intel'], bug=738244) # WebGL 2.0.1
     self.Fail('conformance2/rendering/clipping-wide-points.html',
         ['linux', 'amd', 'intel'], bug=662644) # WebGL 2.0.1
 
diff --git a/content/test/test_render_frame.cc b/content/test/test_render_frame.cc
index 3cdc37d..2a04a5da 100644
--- a/content/test/test_render_frame.cc
+++ b/content/test/test_render_frame.cc
@@ -9,7 +9,6 @@
 #include "content/child/web_url_loader_impl.h"
 #include "content/common/frame_messages.h"
 #include "content/common/navigation_params.h"
-#include "content/common/resource_request_body_impl.h"
 #include "content/public/common/associated_interface_provider.h"
 #include "content/public/common/browser_side_navigation_policy.h"
 #include "content/public/common/resource_response.h"
diff --git a/docs/es6_chromium.md b/docs/es6_chromium.md
index f4a2843..d042f85f 100644
--- a/docs/es6_chromium.md
+++ b/docs/es6_chromium.md
@@ -110,7 +110,7 @@
 
 The following features are allowed in Chromium development.
 
-## `=>` (Arrow Functions)
+## => (Arrow Functions)
 
 Arrow functions provide a concise syntax to create a function, and fix a number
 of difficulties with `this` (e.g. eliminating the need to write `const self =
@@ -150,7 +150,7 @@
 
 ---
 
-## `Promise`
+## Promise
 
 The Promise object is used for asynchronous computations. A Promise represents a
 value which may be available now, or in the future, or never.
@@ -224,6 +224,63 @@
 
 ---
 
+## Map
+
+A simple key/value map in which any value (both objects and primitive values)
+may be used as either a key or a value.
+
+**Usage Example:**
+
+```js
+var map = new Map();
+map.size === 0;  // true
+map.get('foo');  // undefined
+
+var key = 54;
+map.set(key, 123);
+map.size === 1;  // true
+map.has(key);  // true
+map.get(key);  // 123
+
+map.delete(key);
+map.has(key);  // false
+map.size === 0;  // true
+```
+
+**Documentation:** [link](http://www.ecma-international.org/ecma-262/6.0/#sec-map-objects)
+[link](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map)
+
+**Discussion Notes:** Feature already extensively used prior to creation of
+this document.
+
+---
+
+## Set
+
+An object that lets you store unique values of any type, whether primitive
+values or object references.
+
+**Usage Example:**
+
+```js
+var set = new Set();
+
+set.add(123);
+set.size();  // 1
+set.has(123);  // true
+
+set.add(123);
+set.size();  // 1
+```
+
+**Documentation:** [link](http://www.ecma-international.org/ecma-262/6.0/#sec-set-objects)
+[link](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set)
+
+**Discussion Notes:** Feature already extensively used prior to creation of
+this document.
+
+---
+
 # Banned Features
 
 The following features are banned for Chromium development.
@@ -234,7 +291,7 @@
 how to propose moving a feature from this list into the allowed or banned
 sections.
 
-## `let` (Block-Scoped Variables)
+## let (Block-Scoped Variables)
 
 `let` declares a variable within the scope of a block.  This differs from `var`,
 which uses function level scope.
@@ -277,7 +334,7 @@
 
 ---
 
-## `const` (Block-Scoped Constants)
+## const (Block-Scoped Constants)
 
 Constants (also known as "immutable variables") are variables which cannot be
 re-assigned new content. Note that if the value is an object, the object itself
@@ -619,7 +676,7 @@
 
 ---
 
-## `for ...of` Loops
+## for...of Loops
 
 Convenient operator to iterate over all values in an iterable collection. This
 differs from `for ...in`, which iterates over all iterable properties.
@@ -781,62 +838,7 @@
 
 ---
 
-## `Map`
-
-A simple key/value map in which any value (both objects and primitive values)
-may be used as either a key or a value.
-
-**Usage Example:**
-
-```js
-var map = new Map();
-map.size === 0;  // true
-map.get('foo');  // undefined
-
-var key = {};
-map.set(key, 123);
-map.size === 1;  // true
-map.has(key);  // true
-map.get(key);  // 123
-
-map.delete(key);
-map.has(key);  // false
-map.size === 0;  // true
-```
-
-**Documentation:** [link](http://www.ecma-international.org/ecma-262/6.0/#sec-map-objects)
-[link](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map)
-
-**Discussion Notes / Link to Thread:**
-
----
-
-## `Set`
-
-An object that lets you store unique values of any type, whether primitive
-values or object references.
-
-**Usage Example:**
-
-```js
-var set = new Set();
-
-set.add(123);
-set.size();  // 1
-set.has(123);  // true
-
-set.add(123);
-set.size();  // 1
-```
-
-**Documentation:** [link](http://www.ecma-international.org/ecma-262/6.0/#sec-set-objects)
-[link](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set)
-
-**Discussion Notes / Link to Thread:**
-
----
-
-## `WeakMap`
+## WeakMap
 
 WeakMap does not prevent garbage collection if nothing else refers to an object
 within the collection.
@@ -858,7 +860,7 @@
 
 ---
 
-## `WeakSet`
+## WeakSet
 
 WeakSet does not prevent garbage collection if nothing else refers to an object
 within the collection.
@@ -900,7 +902,7 @@
 
 ---
 
-## `Proxy`
+## Proxy
 
 Hooking into runtime-level object meta-operations.
 
@@ -932,7 +934,7 @@
 
 ---
 
-## `Reflection`
+## Reflection
 
 Make calls corresponding to the object meta-operations.
 
diff --git a/docs/speed/perf_bot_sheriffing.md b/docs/speed/perf_bot_sheriffing.md
index ab28765..f5b3573 100644
--- a/docs/speed/perf_bot_sheriffing.md
+++ b/docs/speed/perf_bot_sheriffing.md
@@ -11,6 +11,9 @@
 *   [Handle Test Failures](#Handle-Test-Failures)
 *   [Follow up on failures](#Follow-up-on-failures)
 
+## Table of Contents
+[TOC]
+
 ## Understanding the Waterfall State
 
 **[Sheriff-O-Matic](https://sheriff-o-matic.appspot.com/chromium.perf)** is (as of
@@ -62,16 +65,72 @@
 **[perf-sheriffs@chromium.org](https://groups.google.com/a/chromium.org/forum/#!forum/perf-sheriffs)**
 postings for important announcements about bot turndowns and other known issues.
 
+## Swarming
+As of Q2 2017 all desktop and android bots have been moved to the swarming.
+There is now one machine on the chromium.perf waterfall for each desktop
+configuration that is triggering test tasks on 5 corresponding swarming bots.
+All of our swarming bots exist in the [chrome-perf swarming pool](https://chromium-swarm.appspot.com/botlist?c=id&c=os&c=task&c=status&f=pool%3AChrome-perf&l=100&s=id%3Aasc)
+
+Some things have probably changed about sheriffing since we migrated from
+buildbot. Here's a partial list:
+1.  Buildbot status pages
+    *   Every test that is run now has 2-3 recipe steps on the buildbot status
+        page associated with it
+        1.  '[trigger] <test_name>' step (you can mostly ignore this)
+        2.  '<test_name>' This is the test that was run on the swarming bot,
+            'shard #0' link on the step takes you to the swarming task page
+        3.  '<test_name> Dashboard Upload' This is the upload of the perf tests
+            results to the perf dashboard.  This will not be present if the test
+            was disabled.
+    *   We now run most benchmark tests even if they are disabled, but disabled
+        tests will always return success and you can ignore them.  You can
+        identify these by the 'DISABLED_BENCHMARK' link under the step and the
+        fact that they don’t have an upload step after them.
+        *  Some tests aren't run, if it's possible for us to tell that it would
+           just be disabled. Right now, we don't trigger "mobile" benchmarks for
+           desktop bots.
+2.  Debugging Expiring Jobs on the waterfall
+    *   You can tell a job is expiring in one of two ways:
+        1.  Click on the 'shard #0' link of the failed test and you will see
+            EXPIRED on the swarming task page
+        2.  If there is a 'no_results_exc' and an 'invalid_results_exc' link on
+            the buildbot failing test step with the dashboard upload step
+            failing (Note: this could be an EXPIRED job or a TIMEOUT.  An
+            Expired job means the task never got scheduled within the 5 hour
+            swarming timeout and TIMEOUT means it started running but couldn’t
+            finish before the 5 hour swarming timeout)
+    *   You can quickly see what bots the jobs are expiring/timing out on with
+        the ‘Bot id’ annotation on the failing test step
+    *   Troubleshooting why they are expiring
+        1.  Bot might be down, check the chrome-perf pool for that bot-id and
+            file a ticket with go/bugatrooper if the bot is down. [Example bot
+            page](https://chromium-swarm.appspot.com/bot?id=build73-b1--device1&sort_stats=total%3Adesc)
+            *   Can also identify a down bot through [viceroy](https://viceroy.corp.google.com/chrome_infra/Machines/per_machine)
+                Search for a bot id and if the graph stops it tells you the bot
+                is down
+        2.  Otherwise check the bots swarming page task list for each bot that
+            has failing jobs and examine what might be going on  (good [video](https://youtu.be/gRa0LvICthk)
+            from maruel@ on the swarming ui and how to filter and search bot
+            task lists.  For example you can filter on bot-id and name to
+            examine the last n runs of a test).
+            *   A test might be timing out on a bot that is causing subsequent
+                tests to expire even though they would pass normally but never
+                get scheduled due to that timing out test.  Debug the timing out
+                test.
+            *   A test might be taking a longer time than normal but still
+                passing, but the extra execution time causes other unrelated
+                tests to fail.  Examine the last passing run to the first
+                failing run and see if you can see a test that is taking a
+                significantly longer time and debug that issue. If you need help
+                with this, martiniss@ can get some useful data.
+
+
 ## Handle Device and Bot Failures
 
 ### Offline Buildslaves
 
-Some build configurations, in particular the perf builders and trybots, have
-multiple machines attached. If one or more of the machines go down, there are
-still other machines running, so the console or waterfall view will still show
-green, but those configs will run at reduced throughput. At least once during
-your shift, you should check the lists of buildslaves and ensure they're all
-running.
+At least once during your shift, you should check the lists of buildslaves and
+ensure they're all running.
 
 *   [chromium.perf buildslaves](https://build.chromium.org/p/chromium.perf/buildslaves)
 *   [tryserver.chromium.perf buildslaves](https://build.chromium.org/p/tryserver.chromium.perf/buildslaves)
@@ -107,26 +166,19 @@
 
 ### Android Device failures
 
-There are three types of device failures:
+Android device failures will mainly manifest by turning a bunch of steps on a
+builder purple. Failures of this type are expected to be purple. This will
+manifest itself as a string of tests failing, all with the same device id.
+Sheriff-o-matic will try to do this grouping for you, and it will make an entry
+in sheriff-o-matic with a title like `bot affinity build123-b1 is broken on
+chromium.perf/Linux Perf, affecting 10 tests`.
 
-1.  A device is blacklisted in the `device_status` step. Device failures of this
-    type are expected to be purple. You can look at the buildbot status page to
-    see how many devices were listed as online during this step. You should
-    always see 7 devices online. If you see fewer than 7 devices online, there
-    is a problem in the lab.
-2.  A device is passing `device_status` but still in poor health. The
-    symptom of this is that all the tests are failing on it. You can see that on
-    the buildbot status page by looking at the `Device Affinity`. If all tests
-    with the same device affinity number are failing, it's probably a device
-    failure.
-3.  A device has completely disappeared from `device_status` step. You should
-    always see 7 total devices on a bot in one of three statuses: online,
-    misisng, or blacklisted. If you see fewer than 7 devices it means there is
-    a problem with the known devices persistent file and the device is
-    unreachable via adb. This usually means the known devices file was cleared
-    while a device was unreachable. A bug should be filed saying that there is a
-    missing device. Going through previous logs will usually yield a device ID
-    for the missing device.
+These issues are usually automatically handled by the labs team.
+If you are a Googler, you can see a list of tickets [here](https://gutsv3.corp.google.com/#adhoc/core.requester%3A%22chrome-infra-prod-borg%22%20AND%20Android%20Devices/0)
+which have been auto-filed by Chrome Infra. These are filed twice a day, and
+usually get attention from people in the lab, who can fix these bugs quickly.
+Check this list to see if a device is on there. If it isn't, then follow the
+instructions below to file a ticket with the labs team.
 
 For these types of failures, please file a bug with
 [this template](https://bugs.chromium.org/p/chromium/issues/entry?components=Infra%3ELabs&labels=Pri-1,Performance-Sheriff-BotHealth,OS-Android&comment=Link+to+buildbot+status+page:&summary=Device+offline+on+chromium.perf)
@@ -140,7 +192,6 @@
     priority issues, like a build breakage. Please add a comment explaining what
     you want the trooper to do.
 
-
 Here are the common components you should also use:
 
 *   **Infra>Labs** adds the bug to the labs queue. If there is a hardware
@@ -278,124 +329,6 @@
     Click link under _"stack tool with logcat dump"_ to see symbolized Android
     crashes.
 
-## Swarming Bots
-As of Q4 2016 all desktop bots have been moved to the swarming pool with a goal
-of moving all android bots to swarming in early 2017.  There is now one machine
-on the chromium.perf waterfall for each desktop configuration that is triggering
-test tasks on 5 corresponding swarming bots.  All of our swarming bots exists in
-the [chrome-perf swarming pool](https://chromium-swarm.appspot.com/botlist?c=id&c=os&c=task&c=status&f=pool%3AChrome-perf&l=100&s=id%3Aasc)
-
-1.  Buildbot status page FYIs
-    *   Every test that is run now has 2-3 recipe steps on the buildbot status
-        page associated with it
-        1.  '[trigger] <test_name>' step (you can mostly ignore this)
-        2.  '<test_name>' This is the test that was run on the swarming bot,
-            'shard #0' link on the step takes you to the swarming task page
-        3.  '<test_name> Dashboard Upload' This is the upload of the perf tests
-            results to the perf dashboard.  This will not be present if the test
-            was disabled.
-    *   We now run all benchmark tests even if they are disabled, but disabled
-        tests will always return success and you can ignore them.  You can
-        identify these by the 'DISABLED_BENCHMARK' link under the step and the
-        fact that they don’t have an upload step after them
-2.  Debugging Expiring Jobs on the waterfall
-    *   You can tell a job is expiring in one of two ways:
-        1.  Click on the 'shard #0' link of the failed test and you will see
-            EXPIRED on the swarming task page
-        2.  If there is a 'no_results_exc' and an 'invalid_results_exc' link on
-            the buildbot failing test step with the dashboard upload step
-            failing (Note: this could be an EXPIRED job or a TIMEOUT.  An
-            Expired job means the task never got scheduled within the 5 hour
-            swarming timeout and TIMEOUT means it started running but couldn’t
-            finish before the 5 hour swarming timeout)
-    *   You can quickly see what bots the jobs are expiring/timing out on with
-        the ‘Bot id’ annotation on the failing test step
-    *   Troubleshooting why they are expiring
-        1.  Bot might be down, check the chrome-perf pool for that bot-id and
-            file a ticket with go/bugatrooper if the bot is down.
-            *   Can also identify a down bot through [viceroy](https://viceroy.corp.google.com/chrome_infra/Machines/per_machine)
-                Search for a bot id and if the graph stops it tells you the bot
-                is down
-        2.  Otherwise check the bots swarming page task list for each bot that
-            has failing jobs and examine what might be going on  (good [video](https://youtu.be/gRa0LvICthk)
-            from maruel@ on the swarming ui and how to filter and search bot
-            task lists.  For example you can filter on bot-id and name to
-            examine the last n runs of a test).
-            *   A test might be timing out on a bot that is causing subsequent
-                tests to expire even though they would pass normally but never
-                get scheduled due to that timing out test.  Debug the timing out
-                test.
-            *   A test might be taking a longer time than normal but still
-                passing, but the extra execution time causes other unrelated
-                tests to fail.  Examine the last passing run to the first
-                failing run and see if you can see a test that is taking a
-                significantly longer time and debug that issue.
-3.  Reproducing swarming task runs
-    *   Reproduce on local machine using same inputs as bot
-        1.  Note that the local machines spec must roughly match that of the
-            swarming bot
-        2.  See 'Reproducing the task locally' on swarming task page
-        3.  First run the command under
-            'Download input files into directory foo'
-        4.  cd into foo/out/Release if those downloaded inputs
-        5.  Execute test from this directory.  Command you are looking for
-            should be at the top of the logs, you just need to update the
-            `--isolated-script-test-output=/b/s/w/ioFB73Qz/output.json` and
-            `--isolated-script-test-chartjson-output=/b/s/w/ioFB73Qz/chartjson-output.json`
-            flags to be a local path
-        6.  Example with tmp as locally created dir:
-            `/usr/bin/python ../../testing/scripts/run_telemetry_benchmark_as_googletest.py ../../tools/perf/run_benchmark speedometer -v --upload-results --output-format=chartjson --browser=release --isolated-script-test-output=tmp/output.json --isolated-script-test-chartjson-output=tmp/chartjson-output.json`
-    *   ssh into swarming bot and run test on that machine
-        1.  NOTE: this should be a last resort since it will cause a fifth of
-            the benchmarks to continuously fail on the waterfall
-        2   First you need to decommission the swarming bot so other jobs don’t
-            interfere, file a ticket with go/bugatrooper
-        3.  See [remote access to bots](https://sites.google.com/a/google.com/chrome-infrastructure/golo/remote-access?pli=1)
-            on how to ssh into the bot and then run the test.
-            Rough overview for build161-m1
-            *   prodaccess --chromegolo_ssh
-            *   Ssh build161-m1.golo
-            *   Password is in valentine
-                "Chrome Golo, Perf, GPU bots - chrome-bot"
-            *   File a bug to reboot the machine to get it online in the
-                swarming pool again
-4. Running local changes on swarming bot
-    *   Using sunspider as example benchmark since it is a quick one
-    *   First, run test locally to make sure there is no issue with the binary
-        or the script running the test on the swarming bot.  Make sure dir foo
-        exists:
-        `python testing/scripts/run_telemetry_benchmark_as_googletest.py tools/perf/run_benchmark sunspider -v --output-format=chartjson --upload-results --browser=reference --output-trace-tag=_ref --isolated-script-test-output=foo/output.json --isolated-script-test-chartjson-output=foo/chart-output.json`
-    *   Build any dependencies needed in isolate:
-        1.  ninja -C out/Release chrome/test:telemetry_perf_tests
-        2.  This target should be enough if you are running a benchmark,
-            otherwise build any targets that they say are missing when building
-            the isolate in step #2.
-        3.   Make sure [compiler proxy is running](https://sites.google.com/a/google.com/goma/how-to-use-goma/how-to-use-goma-for-chrome-team?pli=1)
-            *   ./goma_ctl.py ensure_start from goma directory
-    *   Build the isolate
-        1. `python tools/mb/mb.py isolate //out/Release -m chromium.perf -b "Linux Builder" telemetry_perf_tests`
-            *   -m is the master
-            *   -b is the builder name from mb_config.pyl that corresponds to
-                the platform you are running this command on
-            *   telemetry_perf_tests is the isolate name
-            *   Might run into internal source deps when building the isolate,
-                depending on the isolate.  Might need to update the entry in
-                mb_config.pyl for this builder to not be an official built so
-                src/internal isn’t required
-    *   Archive and create the isolate hash
-        1.  `python tools/swarming_client/isolate.py archive -I isolateserver.appspot.com -i out/Release/telemetry_perf_tests.isolate -s out/Release/telemetry_perf_tests.isolated`
-    *   Run the test with the has from step #3
-        1.  Run hash locally
-            *   Note output paths are local
-            *   `./tools/swarming_client/run_isolated.py -I https://isolateserver.appspot.com -s <insert_hash_here> -- sunspider -v --upload-results --output-format=chartjson --browser=reference --output-trace-tag=_ref --isolated-script-test-output=/usr/local/google/home/eyaich/projects/chromium/src/tmp/output.json`
-        2.  Trigger on swarming bot
-            *   Note paths are using swarming output dir environment variable
-                ISOLATED_OUTDIR and dimensions are based on the bot and os you
-                are triggering the job on
-            *   `python tools/swarming_client/swarming.py trigger -v --isolate-server isolateserver.appspot.com -S chromium-swarm.appspot.com -d id build150-m1 -d pool Chrome-perf -d os Linux -s <insert_hash_here> -- sunspider -v --upload-results --output-format=chartjson --browser=reference --output-trace-tag=_ref -isolated-script-test-output='${ISOLATED_OUTDIR}/output.json' --isolated-script-test-chartjson-output='${ISOLATED_OUTDIR}/chart-output.json'`
-            *   All args after the '--' are for the swarming task and not for
-                the trigger command.  The output dirs must be in quotes when
-                triggering on swarming bot
 
 ### Disabling Telemetry Tests
 
@@ -479,6 +412,77 @@
 any highlights or lowlights from your sheriffing shift as well as any other
 feedback you may have that could improve future sheriffing shifts.
 
+
+## Miscellaneous
+
+###  Reproducing swarming task runs
+*   Reproduce on local machine using same inputs as bot
+    1.  Note that the local machines spec must roughly match that of the
+        swarming bot
+    2.  See 'Reproducing the task locally' on swarming task page
+    3.  First run the command under
+        'Download input files into directory foo'
+    4.  cd into foo/out/Release of those downloaded inputs
+    5.  Execute test from this directory.  Command you are looking for
+        should be at the top of the logs, you just need to update the
+        `--isolated-script-test-output=/b/s/w/ioFB73Qz/output.json` and
+        `--isolated-script-test-chartjson-output=/b/s/w/ioFB73Qz/chartjson-output.json`
+        flags to be a local path
+    6.  Example with tmp as locally created dir:
+        `/usr/bin/python ../../testing/scripts/run_telemetry_benchmark_as_googletest.py ../../tools/perf/run_benchmark speedometer -v --upload-results --output-format=chartjson --browser=release --isolated-script-test-output=tmp/output.json --isolated-script-test-chartjson-output=tmp/chartjson-output.json`
+*   ssh into swarming bot and run test on that machine
+    1.  NOTE: this should be a last resort since it will cause a fifth of
+        the benchmarks to continuously fail on the waterfall. Notify to
+        nednguyen@ or sullivan@ if you are going to do this.
+    2   First you need to decommission the swarming bot so other jobs don’t
+        interfere, file a ticket with go/bugatrooper
+    3.  See [remote access to bots](https://sites.google.com/a/google.com/chrome-infrastructure/golo/remote-access?pli=1)
+        on how to ssh into the bot and then run the test.
+        Rough overview for build161-m1
+        *   prodaccess --chromegolo_ssh
+        *   Ssh build161-m1.golo
+        *   Password is in valentine
+            "Chrome Golo, Perf, GPU bots - chrome-bot"
+        *   File a bug to reboot the machine to get it online in the
+            swarming pool again
+* Running local changes on swarming bot
+    *   Using sunspider as example benchmark since it is a quick one
+    *   First, run test locally to make sure there is no issue with the binary
+        or the script running the test on the swarming bot.  Make sure dir foo
+        exists:
+        `python testing/scripts/run_telemetry_benchmark_as_googletest.py tools/perf/run_benchmark sunspider -v --output-format=chartjson --upload-results --browser=reference --output-trace-tag=_ref --isolated-script-test-output=foo/output.json --isolated-script-test-chartjson-output=foo/chart-output.json`
+    *   Build any dependencies needed in isolate:
+        1.  ninja -C out/Release chrome/test:telemetry_perf_tests
+        2.  This target should be enough if you are running a benchmark,
+            otherwise build any targets that they say are missing when building
+            the isolate in step #2.
+        3.   Make sure [compiler proxy is running](https://sites.google.com/a/google.com/goma/how-to-use-goma/how-to-use-goma-for-chrome-team?pli=1)
+            *   ./goma_ctl.py ensure_start from goma directory
+    *   Build the isolate
+        1. `python tools/mb/mb.py isolate //out/Release -m chromium.perf -b "Linux Builder" telemetry_perf_tests`
+            *   -m is the master
+            *   -b is the builder name from mb_config.pyl that corresponds to
+                the platform you are running this command on
+            *   telemetry_perf_tests is the isolate name
+            *   Might run into internal source deps when building the isolate,
+                depending on the isolate.  Might need to update the entry in
+                mb_config.pyl for this builder to not be an official built so
+                src/internal isn’t required
+    *   Archive and create the isolate hash
+        1.  `python tools/swarming_client/isolate.py archive -I isolateserver.appspot.com -i out/Release/telemetry_perf_tests.isolate -s out/Release/telemetry_perf_tests.isolated`
+    *   Run the test with the has from step #3
+        1.  Run hash locally
+            *   Note output paths are local
+            *   `./tools/swarming_client/run_isolated.py -I https://isolateserver.appspot.com -s <insert_hash_here> -- sunspider -v --upload-results --output-format=chartjson --browser=reference --output-trace-tag=_ref --isolated-script-test-output=/usr/local/google/home/eyaich/projects/chromium/src/tmp/output.json`
+        2.  Trigger on swarming bot
+            *   Note paths are using swarming output dir environment variable
+                ISOLATED_OUTDIR and dimensions are based on the bot and os you
+                are triggering the job on
+            *   `python tools/swarming_client/swarming.py trigger -v --isolate-server isolateserver.appspot.com -S chromium-swarm.appspot.com -d id build150-m1 -d pool Chrome-perf -d os Linux -s <insert_hash_here> -- sunspider -v --upload-results --output-format=chartjson --browser=reference --output-trace-tag=_ref -isolated-script-test-output='${ISOLATED_OUTDIR}/output.json' --isolated-script-test-chartjson-output='${ISOLATED_OUTDIR}/chart-output.json'`
+            *   All args after the '--' are for the swarming task and not for
+                the trigger command.  The output dirs must be in quotes when
+                triggering on swarming bot
+
 <!-- Unresolved issues:
 1. Do perf sheriffs watch the bisect waterfall?
 2. Do perf sheriffs watch the internal clank waterfall?
diff --git a/extensions/renderer/resources/binding.js b/extensions/renderer/resources/binding.js
index d25353b5..d0b7e61b 100644
--- a/extensions/renderer/resources/binding.js
+++ b/extensions/renderer/resources/binding.js
@@ -70,36 +70,6 @@
     });
 };
 
-APIFunctions.prototype.setHandleRequestWithPromise =
-    function(apiName, customizedFunction) {
-  var prefix = this.namespace;
-  return this.setHook_(apiName, 'handleRequest', function() {
-      var name = prefix + '.' + apiName;
-      logActivity.LogAPICall(extensionId, name, $Array.slice(arguments));
-      var stack = exceptionHandler.getExtensionStackTrace();
-      var callback = arguments[arguments.length - 1];
-      var args = $Array.slice(arguments, 0, arguments.length - 1);
-      var keepAlivePromise = requireAsync('keep_alive').then(function(module) {
-        return module.createKeepAlive();
-      });
-      $Function.apply(customizedFunction, this, args).then(function(result) {
-        if (callback) {
-          exceptionHandler.safeCallbackApply(name, {'stack': stack}, callback,
-                                             [result]);
-        }
-      }).catch(function(error) {
-        if (callback) {
-          var message = exceptionHandler.safeErrorToString(error, true);
-          lastError.run(name, message, stack, callback);
-        }
-      }).then(function() {
-        keepAlivePromise.then(function(keepAlive) {
-          keepAlive.close();
-        });
-      });
-    });
-};
-
 APIFunctions.prototype.setUpdateArgumentsPostValidate =
     function(apiName, customizedFunction) {
   return this.setHook_(
diff --git a/extensions/renderer/resources/mime_handler_private_custom_bindings.js b/extensions/renderer/resources/mime_handler_private_custom_bindings.js
index 1fa03663..bb04683e 100644
--- a/extensions/renderer/resources/mime_handler_private_custom_bindings.js
+++ b/extensions/renderer/resources/mime_handler_private_custom_bindings.js
@@ -6,7 +6,9 @@
  * Custom bindings for the mime handler API.
  */
 
-var binding = require('binding').Binding.create('mimeHandlerPrivate');
+var binding =
+    apiBridge || require('binding').Binding.create('mimeHandlerPrivate');
+var utils = require('utils');
 
 var NO_STREAM_ERROR =
     'Streams are only available from a mime handler view guest.';
@@ -57,17 +59,22 @@
 
 binding.registerCustomHook(function(bindingsAPI) {
   var apiFunctions = bindingsAPI.apiFunctions;
-  apiFunctions.setHandleRequestWithPromise('getStreamInfo', function() {
+  utils.handleRequestWithPromiseDoNotUse(
+      apiFunctions, 'mimeHandlerPrivate', 'getStreamInfo',
+      function() {
     if (!streamInfoPromise)
       streamInfoPromise = createStreamInfoPromise();
     return streamInfoPromise.then(constructStreamInfoDict);
   });
 
-  apiFunctions.setHandleRequestWithPromise('abortStream', function() {
+  utils.handleRequestWithPromiseDoNotUse(
+      apiFunctions, 'mimeHandlerPrivate', 'abortStream',
+      function() {
     return servicePromise.then(function(service) {
       return service.abortStream().then(function() {});
     }).catch(throwNoStreamError);
   });
 });
 
-exports.$set('binding', binding.generate());
+if (!apiBridge)
+  exports.$set('binding', binding.generate());
diff --git a/extensions/renderer/resources/utils.js b/extensions/renderer/resources/utils.js
index 3b5a68d6..0ec387b 100644
--- a/extensions/renderer/resources/utils.js
+++ b/extensions/renderer/resources/utils.js
@@ -4,6 +4,22 @@
 
 var nativeDeepCopy = requireNative('utils').deepCopy;
 var DCHECK = requireNative('logging').DCHECK;
+var WARNING = requireNative('logging').WARNING;
+var logActivity = requireNative('activityLogger');
+var exceptionHandler = require('uncaught_exception_handler');
+
+var runCallbackWithLastError;
+if (bindingUtil) {
+  runCallbackWithLastError = function(name, message, stack, callback, args) {
+    bindingUtil.runCallbackWithLastError(message, function() {
+      $Function.apply(callback, null, args);
+    });
+  }
+} else {
+  var lastError = require('lastError');
+  if (lastError)  // lastError can be undefined in unittests.
+    runCallbackWithLastError = lastError.run;
+}
 
 /**
  * An object forEach. Calls |f| with each (key, value) pair of |obj|, using
@@ -206,9 +222,43 @@
   });
 }
 
+// DO NOT USE. This causes problems with safe builtins, and makes migration to
+// native bindings more difficult.
+function handleRequestWithPromiseDoNotUse(
+    binding, apiName, methodName, customizedFunction) {
+  var fullName = apiName + '.' + methodName;
+  var extensionId = requireNative('process').GetExtensionId();
+  binding.setHandleRequest(methodName, function() {
+    logActivity.LogAPICall(extensionId, fullName, $Array.slice(arguments));
+    var stack = exceptionHandler.getExtensionStackTrace();
+    var callback = arguments[arguments.length - 1];
+    var args = $Array.slice(arguments, 0, arguments.length - 1);
+    var keepAlivePromise = requireAsync('keep_alive').then(function(module) {
+      return module.createKeepAlive();
+    });
+    $Function.apply(customizedFunction, this, args).then(function(result) {
+      if (callback) {
+        exceptionHandler.safeCallbackApply(
+            fullName, {__proto__: null, stack: stack}, callback, [result]);
+      }
+    }).catch(function(error) {
+      if (callback) {
+        var message = exceptionHandler.safeErrorToString(error, true);
+        runCallbackWithLastError(fullName, message, stack, callback);
+      }
+    }).then(function() {
+      keepAlivePromise.then(function(keepAlive) {
+        keepAlive.close();
+      });
+    });
+  });
+};
+
 exports.$set('forEach', forEach);
 exports.$set('lookup', lookup);
 exports.$set('defineProperty', defineProperty);
 exports.$set('expose', expose);
 exports.$set('deepCopy', deepCopy);
 exports.$set('promise', promise);
+exports.$set('handleRequestWithPromiseDoNotUse',
+             handleRequestWithPromiseDoNotUse);
diff --git a/extensions/shell/app/app-Info.plist b/extensions/shell/app/app-Info.plist
index 269fd96..e415a0f 100644
--- a/extensions/shell/app/app-Info.plist
+++ b/extensions/shell/app/app-Info.plist
@@ -25,7 +25,7 @@
 	<key>NSPrincipalClass</key>
 	<string>NSApplication</string>
 	<key>LSMinimumSystemVersion</key>
-	<string>${MACOSX_DEPLOYMENT_TARGET}.0</string>
+	<string>${MACOSX_DEPLOYMENT_TARGET}</string>
 	<key>LSFileQuarantineEnabled</key>
 	<true/>
 	<key>NSSupportsAutomaticGraphicsSwitching</key>
diff --git a/extensions/shell/app/helper-Info.plist b/extensions/shell/app/helper-Info.plist
index dd654f1..ccd54a59 100644
--- a/extensions/shell/app/helper-Info.plist
+++ b/extensions/shell/app/helper-Info.plist
@@ -21,7 +21,7 @@
 	<key>LSFileQuarantineEnabled</key>
 	<true/>
 	<key>LSMinimumSystemVersion</key>
-	<string>${MACOSX_DEPLOYMENT_TARGET}.0</string>
+	<string>${MACOSX_DEPLOYMENT_TARGET}</string>
 	<key>LSUIElement</key>
 	<string>1</string>
 	<key>NSSupportsAutomaticGraphicsSwitching</key>
diff --git a/extensions/shell/installer/linux/debian/expected_deps_x64_jessie b/extensions/shell/installer/linux/debian/expected_deps_x64_jessie
index 5fc6eff..3c5e6112 100644
--- a/extensions/shell/installer/linux/debian/expected_deps_x64_jessie
+++ b/extensions/shell/installer/linux/debian/expected_deps_x64_jessie
@@ -1,8 +1,8 @@
 gconf-service
 libasound2 (>= 1.0.16)
 libatk1.0-0 (>= 1.12.4)
-libc6 (>= 2.15)
-libdbus-1-3 (>= 1.1.4)
+libc6 (>= 2.18)
+libdbus-1-3 (>= 1.2.14)
 libexpat1 (>= 2.0.1)
 libfontconfig1 (>= 2.11)
 libgcc1 (>= 1:4.1.1)
@@ -12,7 +12,6 @@
 libnss3 (>= 2:3.13.4-2~)
 libpango-1.0-0 (>= 1.14.0)
 libpangocairo-1.0-0 (>= 1.14.0)
-libstdc++6 (>= 4.8.1)
 libx11-6 (>= 2:1.4.99.1)
 libx11-xcb1
 libxcb1 (>= 1.6)
@@ -22,7 +21,7 @@
 libxext6
 libxfixes3
 libxi6 (>= 2:1.2.99.4)
-libxrandr2
+libxrandr2 (>= 2:1.2.99.3)
 libxrender1
 libxss1
 libxtst6
diff --git a/extensions/test/data/keep_alive_client_unittest.js b/extensions/test/data/keep_alive_client_unittest.js
index 7b88fb0..97ddba54 100644
--- a/extensions/test/data/keep_alive_client_unittest.js
+++ b/extensions/test/data/keep_alive_client_unittest.js
@@ -18,8 +18,8 @@
 // simple signature.
 var binding = require('binding').Binding.create('serial');
 binding.registerCustomHook(function(bindingsAPI) {
-  bindingsAPI.apiFunctions.setHandleRequestWithPromise('getDevices',
-      function() {
+  utils.handleRequestWithPromiseDoNotUse(bindingsAPI.apiFunctions,
+                                         'serial', 'getDevices', function() {
     if (shouldSucceed)
       return Promise.resolve([]);
     else
diff --git a/gpu/config/BUILD.gn b/gpu/config/BUILD.gn
index 1a980af..d9db427 100644
--- a/gpu/config/BUILD.gn
+++ b/gpu/config/BUILD.gn
@@ -65,6 +65,8 @@
     args += [ "android" ]
   } else if (is_chromeos) {
     args += [ "chromeos" ]
+  } else if (is_fuchsia) {
+    args += [ "fuchsia" ]
   } else {
     args += [ "linux" ]
   }
diff --git a/gpu/config/gpu_crash_keys.cc b/gpu/config/gpu_crash_keys.cc
index 394ee038..3ff2b3a 100644
--- a/gpu/config/gpu_crash_keys.cc
+++ b/gpu/config/gpu_crash_keys.cc
@@ -20,6 +20,7 @@
 const char kGPUVendor[] = "gpu-gl-vendor";
 const char kGPURenderer[] = "gpu-gl-renderer";
 #endif
+const char kGPUGLContextIsVirtual[] = "gpu-gl-context-is-virtual";
 
 }  // namespace crash_keys
 }  // namespace gpu
diff --git a/gpu/config/gpu_crash_keys.h b/gpu/config/gpu_crash_keys.h
index 0f181300..7d5a9ec2 100644
--- a/gpu/config/gpu_crash_keys.h
+++ b/gpu/config/gpu_crash_keys.h
@@ -24,6 +24,7 @@
 extern const char kGPUVendor[];
 extern const char kGPURenderer[];
 #endif
+extern const char kGPUGLContextIsVirtual[];
 
 }  // namespace crash_keys
 }  // namespace gpu
diff --git a/gpu/config/gpu_driver_bug_list.json b/gpu/config/gpu_driver_bug_list.json
index fc000b88..d20ca2f 100644
--- a/gpu/config/gpu_driver_bug_list.json
+++ b/gpu/config/gpu_driver_bug_list.json
@@ -1,6 +1,6 @@
 {
   "name": "gpu driver bug list",
-  "version": "10.17",
+  "version": "10.16",
   "entries": [
     {
       "id": 1,
@@ -2552,27 +2552,6 @@
       "disabled_extensions": [
         "EGL_EXT_image_flush_external"
       ]
-    },
-    {
-      "id": 235,
-      "description": "Adreno 4xx support for EXT_multisampled_render_to_texture is broken on Android 8.0",
-      "comment": [
-        "EXT_multisampled_render_to_texture is broken on Adreno 4xx GPUs in Android 8.0"
-      ],
-      "cr_bugs": [722962],
-      "os": {
-        "type": "android",
-        "version": {
-          "op": "between",
-          "value": "8.0.0",
-          "value2": "8.0.99",
-          "comment": "Only initial version of O."
-        }
-      },
-      "gl_renderer": "Adreno \\(TM\\) 4.*",
-      "disabled_extensions": [
-        "GL_EXT_multisampled_render_to_texture"
-      ]
     }
   ],
   "comment": [
diff --git a/gpu/ipc/BUILD.gn b/gpu/ipc/BUILD.gn
index 61afbc6f..57571f8ae 100644
--- a/gpu/ipc/BUILD.gn
+++ b/gpu/ipc/BUILD.gn
@@ -38,6 +38,7 @@
     "//gpu/command_buffer/common:common_sources",
     "//gpu/command_buffer/service:service_sources",
     "//gpu/config:config_sources",
+    "//gpu/config:crash_keys",
     "//gpu/ipc/client:ipc_client_sources",
     "//gpu/ipc/service:ipc_service_sources",
     "//ui/gfx",
diff --git a/gpu/ipc/in_process_command_buffer.cc b/gpu/ipc/in_process_command_buffer.cc
index 3b28b89a..9918275 100644
--- a/gpu/ipc/in_process_command_buffer.cc
+++ b/gpu/ipc/in_process_command_buffer.cc
@@ -14,6 +14,7 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/command_line.h"
+#include "base/debug/crash_logging.h"
 #include "base/lazy_instance.h"
 #include "base/location.h"
 #include "base/logging.h"
@@ -39,6 +40,7 @@
 #include "gpu/command_buffer/service/service_utils.h"
 #include "gpu/command_buffer/service/sync_point_manager.h"
 #include "gpu/command_buffer/service/transfer_buffer_manager.h"
+#include "gpu/config/gpu_crash_keys.h"
 #include "gpu/config/gpu_feature_info.h"
 #include "gpu/ipc/gpu_in_process_thread_service.h"
 #include "gpu/ipc/service/image_transport_surface.h"
@@ -336,11 +338,17 @@
           GetNamespaceID(), GetCommandBufferID(),
           sync_point_order_data_->sequence_id());
 
-  if (service_->UseVirtualizedGLContexts() ||
-      decoder_->GetContextGroup()
-          ->feature_info()
-          ->workarounds()
-          .use_virtualized_gl_contexts) {
+  use_virtualized_gl_context_ =
+      service_->UseVirtualizedGLContexts() || decoder_->GetContextGroup()
+                                                  ->feature_info()
+                                                  ->workarounds()
+                                                  .use_virtualized_gl_contexts;
+
+  // TODO(sunnyps): Should this use ScopedCrashKey instead?
+  base::debug::SetCrashKeyValue(crash_keys::kGPUGLContextIsVirtual,
+                                use_virtualized_gl_context_ ? "1" : "0");
+
+  if (use_virtualized_gl_context_) {
     context_ = gl_share_group_->GetSharedContext(surface_.get());
     if (!context_.get()) {
       context_ = gl::init::CreateGLContext(
@@ -496,6 +504,9 @@
 }
 
 void InProcessCommandBuffer::ProcessTasksOnGpuThread() {
+  // TODO(sunnyps): Should this use ScopedCrashKey instead?
+  base::debug::SetCrashKeyValue(crash_keys::kGPUGLContextIsVirtual,
+                                use_virtualized_gl_context_ ? "1" : "0");
   while (command_buffer_->scheduled()) {
     base::AutoLock lock(task_queue_lock_);
     if (task_queue_.empty())
@@ -570,6 +581,9 @@
   CheckSequencedThread();
   delayed_work_pending_ = false;
   base::AutoLock lock(command_buffer_lock_);
+  // TODO(sunnyps): Should this use ScopedCrashKey instead?
+  base::debug::SetCrashKeyValue(crash_keys::kGPUGLContextIsVirtual,
+                                use_virtualized_gl_context_ ? "1" : "0");
   if (MakeCurrent()) {
     decoder_->PerformIdleWork();
     decoder_->ProcessPendingQueries(false);
diff --git a/gpu/ipc/in_process_command_buffer.h b/gpu/ipc/in_process_command_buffer.h
index d36f0c71..c8ca507 100644
--- a/gpu/ipc/in_process_command_buffer.h
+++ b/gpu/ipc/in_process_command_buffer.h
@@ -305,6 +305,7 @@
   // Members accessed on the gpu thread (possibly with the exception of
   // creation):
   bool waiting_for_sync_point_ = false;
+  bool use_virtualized_gl_context_ = false;
 
   scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_;
   std::unique_ptr<TransferBufferManager> transfer_buffer_manager_;
diff --git a/gpu/ipc/service/BUILD.gn b/gpu/ipc/service/BUILD.gn
index 686c4a9..faeaefd 100644
--- a/gpu/ipc/service/BUILD.gn
+++ b/gpu/ipc/service/BUILD.gn
@@ -74,6 +74,7 @@
     "//gpu/command_buffer/common:common_sources",
     "//gpu/command_buffer/service:service_sources",
     "//gpu/config:config_sources",
+    "//gpu/config:crash_keys",
     "//gpu/ipc/common:ipc_common_sources",
   ]
   libs = []
diff --git a/gpu/ipc/service/gpu_command_buffer_stub.cc b/gpu/ipc/service/gpu_command_buffer_stub.cc
index cf8634c..e53e5b6 100644
--- a/gpu/ipc/service/gpu_command_buffer_stub.cc
+++ b/gpu/ipc/service/gpu_command_buffer_stub.cc
@@ -8,6 +8,7 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/debug/crash_logging.h"
 #include "base/hash.h"
 #include "base/json/json_writer.h"
 #include "base/macros.h"
@@ -35,6 +36,7 @@
 #include "gpu/command_buffer/service/service_utils.h"
 #include "gpu/command_buffer/service/sync_point_manager.h"
 #include "gpu/command_buffer/service/transfer_buffer_manager.h"
+#include "gpu/config/gpu_crash_keys.h"
 #include "gpu/ipc/common/gpu_messages.h"
 #include "gpu/ipc/service/gpu_channel.h"
 #include "gpu/ipc/service/gpu_channel_manager.h"
@@ -269,6 +271,10 @@
                "data", DevToolsChannelData::CreateForChannel(channel()));
   FastSetActiveURL(active_url_, active_url_hash_, channel_);
 
+  // TODO(sunnyps): Should this use ScopedCrashKey instead?
+  base::debug::SetCrashKeyValue(crash_keys::kGPUGLContextIsVirtual,
+                                use_virtualized_gl_context_ ? "1" : "0");
+
   bool have_context = false;
   // Ensure the appropriate GL context is current before handling any IPC
   // messages directed at the command buffer. This ensures that the message
@@ -408,6 +414,11 @@
   TRACE_EVENT0("gpu", "GpuCommandBufferStub::PerformWork");
 
   FastSetActiveURL(active_url_, active_url_hash_, channel_);
+
+  // TODO(sunnyps): Should this use ScopedCrashKey instead?
+  base::debug::SetCrashKeyValue(crash_keys::kGPUGLContextIsVirtual,
+                                use_virtualized_gl_context_ ? "1" : "0");
+
   if (decoder_.get() && !MakeCurrent())
     return;
 
@@ -702,6 +713,10 @@
     share_group_ = channel_->share_group();
   }
 
+  // TODO(sunnyps): Should this use ScopedCrashKey instead?
+  base::debug::SetCrashKeyValue(crash_keys::kGPUGLContextIsVirtual,
+                                use_virtualized_gl_context_ ? "1" : "0");
+
   scoped_refptr<gl::GLContext> context;
   if (use_virtualized_gl_context_ && share_group_) {
     context = share_group_->GetSharedContext(surface_.get());
diff --git a/headless/lib/frame_id_browsertest.cc b/headless/lib/frame_id_browsertest.cc
index a5651a28..6a383333 100644
--- a/headless/lib/frame_id_browsertest.cc
+++ b/headless/lib/frame_id_browsertest.cc
@@ -103,7 +103,7 @@
       const Request* request = pending_request->GetRequest();
       std::string url = request->GetURLRequest()->url().spec();
       int frame_tree_node_id = request->GetFrameTreeNodeId();
-      DCHECK_NE(frame_tree_node_id, -1);
+      DCHECK_NE(frame_tree_node_id, -1) << " For url " << url;
       protocol_handler_->url_to_frame_tree_node_id_[url] = frame_tree_node_id;
       pending_request->AllowRequest();
     }
@@ -190,15 +190,25 @@
 }  // namespace
 
 class FrameIdTest : public HeadlessAsyncDevTooledBrowserTest,
-                    public network::Observer,
+                    public network::ExperimentalObserver,
                     public page::Observer {
  public:
   void RunDevTooledTest() override {
     http_handler_->SetHeadlessBrowserContext(browser_context_);
 
     EXPECT_TRUE(embedded_test_server()->Start());
-    devtools_client_->GetNetwork()->AddObserver(this);
+    devtools_client_->GetNetwork()->GetExperimental()->AddObserver(this);
     devtools_client_->GetNetwork()->Enable();
+
+    if (EnableInterception()) {
+      devtools_client_->GetNetwork()
+          ->GetExperimental()
+          ->EnableRequestInterception(
+              network::EnableRequestInterceptionParams::Builder()
+                  .SetEnabled(true)
+                  .Build());
+    }
+
     devtools_client_->GetPage()->AddObserver(this);
 
     base::RunLoop run_loop;
@@ -253,6 +263,8 @@
     FinishAsynchronousTest();
   }
 
+  virtual bool EnableInterception() const { return false; }
+
  private:
   std::map<std::string, std::string> url_to_frame_id_;
   TestProtocolHandler* http_handler_;  // NOT OWNED
@@ -260,4 +272,23 @@
 
 HEADLESS_ASYNC_DEVTOOLED_TEST_F(FrameIdTest);
 
+// Frame IDs should still be available with network request interception enabled
+class FrameIdWithDevtoolsRequestInterceptionTest : public FrameIdTest {
+ public:
+  void OnRequestIntercepted(
+      const network::RequestInterceptedParams& params) override {
+    // Allow the request to continue.
+    devtools_client_->GetNetwork()
+        ->GetExperimental()
+        ->ContinueInterceptedRequest(
+            network::ContinueInterceptedRequestParams::Builder()
+                .SetInterceptionId(params.GetInterceptionId())
+                .Build());
+  }
+
+  bool EnableInterception() const override { return true; }
+};
+
+HEADLESS_ASYNC_DEVTOOLED_TEST_F(FrameIdWithDevtoolsRequestInterceptionTest);
+
 }  // namespace headless
diff --git a/ios/build/tools/convert_gn_xcodeproj.py b/ios/build/tools/convert_gn_xcodeproj.py
index 0e1af63..50161b1 100755
--- a/ios/build/tools/convert_gn_xcodeproj.py
+++ b/ios/build/tools/convert_gn_xcodeproj.py
@@ -129,7 +129,7 @@
 
       build_config_template = project.objects[value['buildConfigurations'][0]]
       build_config_template['buildSettings']['CONFIGURATION_BUILD_DIR'] = \
-          '../$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)'
+          '$(PROJECT_DIR)/../$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)'
 
       value['buildConfigurations'] = []
       for configuration in configurations:
diff --git a/ios/chrome/browser/DEPS b/ios/chrome/browser/DEPS
index ab359780..640e4637 100644
--- a/ios/chrome/browser/DEPS
+++ b/ios/chrome/browser/DEPS
@@ -20,6 +20,7 @@
   "+components/favicon/core",
   "+components/favicon/ios",
   "+components/favicon_base",
+  "+components/feature_engagement_tracker",
   "+components/flags_ui",
   "+components/gcm_driver",
   "+components/google/core/browser",
diff --git a/ios/chrome/browser/browser_state/BUILD.gn b/ios/chrome/browser/browser_state/BUILD.gn
index 13ee4c3c..109d33e 100644
--- a/ios/chrome/browser/browser_state/BUILD.gn
+++ b/ios/chrome/browser/browser_state/BUILD.gn
@@ -85,6 +85,7 @@
     "//ios/chrome/browser/desktop_promotion",
     "//ios/chrome/browser/dom_distiller",
     "//ios/chrome/browser/favicon",
+    "//ios/chrome/browser/feature_engagement_tracker",
     "//ios/chrome/browser/google",
     "//ios/chrome/browser/google:google_logo",
     "//ios/chrome/browser/history",
diff --git a/ios/chrome/browser/browser_state/browser_state_keyed_service_factories.mm b/ios/chrome/browser/browser_state/browser_state_keyed_service_factories.mm
index 4bfa06a..68412f6 100644
--- a/ios/chrome/browser/browser_state/browser_state_keyed_service_factories.mm
+++ b/ios/chrome/browser/browser_state/browser_state_keyed_service_factories.mm
@@ -17,6 +17,7 @@
 #include "ios/chrome/browser/favicon/ios_chrome_favicon_loader_factory.h"
 #include "ios/chrome/browser/favicon/ios_chrome_large_icon_cache_factory.h"
 #include "ios/chrome/browser/favicon/ios_chrome_large_icon_service_factory.h"
+#include "ios/chrome/browser/feature_engagement_tracker/feature_engagement_tracker_factory.h"
 #include "ios/chrome/browser/google/google_logo_service_factory.h"
 #include "ios/chrome/browser/google/google_url_tracker_factory.h"
 #include "ios/chrome/browser/history/history_service_factory.h"
@@ -100,6 +101,7 @@
   IOSChromeProfileInvalidationProviderFactory::GetInstance();
   IOSChromeProfileSyncServiceFactory::GetInstance();
   IOSUserEventServiceFactory::GetInstance();
+  FeatureEngagementTrackerFactory::GetInstance();
   GoogleLogoServiceFactory::GetInstance();
   OAuth2TokenServiceFactory::GetInstance();
   ReadingListModelFactory::GetInstance();
diff --git a/ios/chrome/browser/content_suggestions/BUILD.gn b/ios/chrome/browser/content_suggestions/BUILD.gn
index 7aebf2d1..06a438a 100644
--- a/ios/chrome/browser/content_suggestions/BUILD.gn
+++ b/ios/chrome/browser/content_suggestions/BUILD.gn
@@ -5,9 +5,6 @@
 source_set("content_suggestions") {
   configs += [ "//build/config/compiler:enable_arc" ]
   sources = [
-    "content_suggestions_alert_commands.h",
-    "content_suggestions_alert_factory.h",
-    "content_suggestions_alert_factory.mm",
     "content_suggestions_category_wrapper.h",
     "content_suggestions_category_wrapper.mm",
     "content_suggestions_coordinator.h",
@@ -76,27 +73,3 @@
   ]
   configs += [ "//build/config/compiler:enable_arc" ]
 }
-
-source_set("eg_tests") {
-  configs += [ "//build/config/compiler:enable_arc" ]
-  testonly = true
-  sources = [
-    "content_suggestions_alert_egtest.mm",
-  ]
-  deps = [
-    ":content_suggestions",
-    "//base",
-    "//base/test:test_support",
-    "//ios/chrome/app/strings",
-    "//ios/chrome/browser/ui/alert_coordinator",
-    "//ios/chrome/browser/ui/alert_coordinator",
-    "//ios/chrome/browser/ui/collection_view/cells",
-    "//ios/chrome/browser/ui/util",
-    "//ios/chrome/test/earl_grey:test_support",
-    "//ui/strings",
-  ]
-  libs = [
-    "UIKit.framework",
-    "XCTest.framework",
-  ]
-}
diff --git a/ios/chrome/browser/content_suggestions/content_suggestions_alert_commands.h b/ios/chrome/browser/content_suggestions/content_suggestions_alert_commands.h
deleted file mode 100644
index d734e65..0000000
--- a/ios/chrome/browser/content_suggestions/content_suggestions_alert_commands.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// 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_BROWSER_CONTENT_SUGGESTIONS_CONTENT_SUGGESTIONS_ALERT_COMMANDS_H_
-#define IOS_CHROME_BROWSER_CONTENT_SUGGESTIONS_CONTENT_SUGGESTIONS_ALERT_COMMANDS_H_
-
-#import <UIKit/UIKit.h>
-
-@class CollectionViewItem;
-
-// Command protocol for the ContentSuggestionsAlertFactory, handling the
-// callbacks from the alerts.
-@protocol ContentSuggestionsAlertCommands
-
-// Opens the URL corresponding to the |item| in a new tab, |incognito| or not.
-// The item has to be a suggestion item.
-- (void)openNewTabWithSuggestionsItem:(nonnull CollectionViewItem*)item
-                            incognito:(BOOL)incognito;
-
-// Adds the |item| to the reading list. The item has to be a suggestion item.
-- (void)addItemToReadingList:(nonnull CollectionViewItem*)item;
-
-// Dismiss the |item| at |indexPath|. The item has to be a suggestion item.
-- (void)dismissSuggestion:(nonnull CollectionViewItem*)item
-              atIndexPath:(nonnull NSIndexPath*)indexPath;
-
-// Open the URL corresponding to the |item| in a new tab, |incognito| or not.
-// The item has to be a Most Visited item.
-- (void)openNewTabWithMostVisitedItem:(nonnull CollectionViewItem*)item
-                            incognito:(BOOL)incognito
-                              atIndex:(NSInteger)mostVisitedIndex;
-
-// Removes the most visited |item|.
-- (void)removeMostVisited:(nonnull CollectionViewItem*)item;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_CONTENT_SUGGESTIONS_CONTENT_SUGGESTIONS_ALERT_COMMANDS_H_
diff --git a/ios/chrome/browser/content_suggestions/content_suggestions_alert_egtest.mm b/ios/chrome/browser/content_suggestions/content_suggestions_alert_egtest.mm
deleted file mode 100644
index 05399ae1..0000000
--- a/ios/chrome/browser/content_suggestions/content_suggestions_alert_egtest.mm
+++ /dev/null
@@ -1,95 +0,0 @@
-// 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/browser/content_suggestions/content_suggestions_alert_factory.h"
-
-#import <EarlGrey/EarlGrey.h>
-#import <XCTest/XCTest.h>
-
-#import "ios/chrome/browser/content_suggestions/content_suggestions_alert_commands.h"
-#import "ios/chrome/browser/ui/alert_coordinator/alert_coordinator.h"
-#import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h"
-#import "ios/chrome/browser/ui/util/top_view_controller.h"
-#include "ios/chrome/grit/ios_strings.h"
-#import "ios/chrome/test/earl_grey/chrome_matchers.h"
-#import "ios/chrome/test/earl_grey/chrome_test_case.h"
-#include "ui/strings/grit/ui_strings.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-@interface ContentSuggestionsAlertFactoryTestCase : XCTestCase
-
-@end
-
-@implementation ContentSuggestionsAlertFactoryTestCase
-
-- (void)testSuggestionsAlert {
-  UIViewController* viewController =
-      top_view_controller::TopPresentedViewController();
-  AlertCoordinator* coordinator = [ContentSuggestionsAlertFactory
-      alertCoordinatorForSuggestionItem:nil
-                       onViewController:viewController
-                                atPoint:CGPointMake(50, 50)
-                            atIndexPath:nil
-                         commandHandler:nil];
-  [coordinator start];
-
-  [[EarlGrey
-      selectElementWithMatcher:chrome_test_util::ButtonWithAccessibilityLabelId(
-                                   IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWTAB)]
-      assertWithMatcher:grey_interactable()];
-  [[EarlGrey selectElementWithMatcher:
-                 chrome_test_util::ButtonWithAccessibilityLabelId(
-                     IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWINCOGNITOTAB)]
-      assertWithMatcher:grey_interactable()];
-  [[EarlGrey
-      selectElementWithMatcher:chrome_test_util::ButtonWithAccessibilityLabelId(
-                                   IDS_IOS_CONTENT_SUGGESTIONS_REMOVE)]
-      assertWithMatcher:grey_interactable()];
-  [[EarlGrey
-      selectElementWithMatcher:chrome_test_util::ButtonWithAccessibilityLabelId(
-                                   IDS_IOS_CONTENT_CONTEXT_ADDTOREADINGLIST)]
-      assertWithMatcher:grey_interactable()];
-  [[EarlGrey
-      selectElementWithMatcher:chrome_test_util::ButtonWithAccessibilityLabelId(
-                                   IDS_APP_CANCEL)]
-      assertWithMatcher:grey_interactable()];
-
-  [coordinator stop];
-}
-
-- (void)testMostVisitedAlert {
-  UIViewController* viewController =
-      top_view_controller::TopPresentedViewController();
-  AlertCoordinator* coordinator = [ContentSuggestionsAlertFactory
-      alertCoordinatorForSuggestionItem:nil
-                       onViewController:viewController
-                                atPoint:CGPointMake(50, 50)
-                            atIndexPath:nil
-                         commandHandler:nil];
-  [coordinator start];
-
-  [[EarlGrey
-      selectElementWithMatcher:chrome_test_util::ButtonWithAccessibilityLabelId(
-                                   IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWTAB)]
-      assertWithMatcher:grey_interactable()];
-  [[EarlGrey selectElementWithMatcher:
-                 chrome_test_util::ButtonWithAccessibilityLabelId(
-                     IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWINCOGNITOTAB)]
-      assertWithMatcher:grey_interactable()];
-  [[EarlGrey
-      selectElementWithMatcher:chrome_test_util::ButtonWithAccessibilityLabelId(
-                                   IDS_IOS_CONTENT_SUGGESTIONS_REMOVE)]
-      assertWithMatcher:grey_interactable()];
-  [[EarlGrey
-      selectElementWithMatcher:chrome_test_util::ButtonWithAccessibilityLabelId(
-                                   IDS_APP_CANCEL)]
-      assertWithMatcher:grey_interactable()];
-
-  [coordinator stop];
-}
-
-@end
diff --git a/ios/chrome/browser/content_suggestions/content_suggestions_alert_factory.h b/ios/chrome/browser/content_suggestions/content_suggestions_alert_factory.h
deleted file mode 100644
index accca13..0000000
--- a/ios/chrome/browser/content_suggestions/content_suggestions_alert_factory.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// 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_BROWSER_CONTENT_SUGGESTIONS_CONTENT_SUGGESTIONS_ALERT_FACTORY_H_
-#define IOS_CHROME_BROWSER_CONTENT_SUGGESTIONS_CONTENT_SUGGESTIONS_ALERT_FACTORY_H_
-
-#import <UIKit/UIKit.h>
-
-@class AlertCoordinator;
-@class CollectionViewItem;
-@protocol ContentSuggestionsAlertCommands;
-
-// Factory for AlertCoordinators for ContentSuggestions.
-@interface ContentSuggestionsAlertFactory : NSObject
-
-// Returns an AlertCoordinator for a suggestions |item| with the indexPath
-// |indexPath|. The alert will be presented on the |viewController| at the
-// |touchLocation|, in the coordinates of the |viewController|'s view. The
-// |commandHandler| will receive callbacks when the user chooses one of the
-// options displayed by the alert.
-+ (AlertCoordinator*)
-alertCoordinatorForSuggestionItem:(CollectionViewItem*)item
-                 onViewController:(UIViewController*)viewController
-                          atPoint:(CGPoint)touchLocation
-                      atIndexPath:(NSIndexPath*)indexPath
-                   commandHandler:
-                       (id<ContentSuggestionsAlertCommands>)commandHandler;
-
-// Same as above but for a MostVisited item.
-+ (AlertCoordinator*)
-alertCoordinatorForMostVisitedItem:(CollectionViewItem*)item
-                  onViewController:(UIViewController*)viewController
-                           atPoint:(CGPoint)touchLocation
-                       atIndexPath:(NSIndexPath*)indexPath
-                    commandHandler:
-                        (id<ContentSuggestionsAlertCommands>)commandHandler;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_CONTENT_SUGGESTIONS_CONTENT_SUGGESTIONS_ALERT_FACTORY_H_
diff --git a/ios/chrome/browser/content_suggestions/content_suggestions_alert_factory.mm b/ios/chrome/browser/content_suggestions/content_suggestions_alert_factory.mm
deleted file mode 100644
index 1deedfb5..0000000
--- a/ios/chrome/browser/content_suggestions/content_suggestions_alert_factory.mm
+++ /dev/null
@@ -1,167 +0,0 @@
-// 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/browser/content_suggestions/content_suggestions_alert_factory.h"
-
-#import "ios/chrome/browser/content_suggestions/content_suggestions_alert_commands.h"
-#import "ios/chrome/browser/ui/alert_coordinator/action_sheet_coordinator.h"
-#import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h"
-#include "ios/chrome/grit/ios_strings.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/strings/grit/ui_strings.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-@implementation ContentSuggestionsAlertFactory
-
-+ (AlertCoordinator*)
-alertCoordinatorForSuggestionItem:(CollectionViewItem*)item
-                 onViewController:(UIViewController*)viewController
-                          atPoint:(CGPoint)touchLocation
-                      atIndexPath:(NSIndexPath*)indexPath
-                   commandHandler:
-                       (id<ContentSuggestionsAlertCommands>)commandHandler {
-  AlertCoordinator* alertCoordinator = [[ActionSheetCoordinator alloc]
-      initWithBaseViewController:viewController
-                           title:nil
-                         message:nil
-                            rect:CGRectMake(touchLocation.x, touchLocation.y, 0,
-                                            0)
-                            view:[viewController view]];
-
-  __weak CollectionViewItem* weakItem = item;
-  __weak id<ContentSuggestionsAlertCommands> weakCommandHandler =
-      commandHandler;
-
-  NSString* openInNewTabTitle =
-      l10n_util::GetNSString(IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWTAB);
-  [alertCoordinator addItemWithTitle:openInNewTabTitle
-                              action:^{
-                                CollectionViewItem* strongItem = weakItem;
-                                if (strongItem) {
-                                  // TODO(crbug.com/691979): Add metrics.
-                                  [weakCommandHandler
-                                      openNewTabWithSuggestionsItem:strongItem
-                                                          incognito:NO];
-                                }
-                              }
-                               style:UIAlertActionStyleDefault];
-
-  NSString* openInNewTabIncognitoTitle =
-      l10n_util::GetNSString(IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWINCOGNITOTAB);
-  [alertCoordinator addItemWithTitle:openInNewTabIncognitoTitle
-                              action:^{
-                                CollectionViewItem* strongItem = weakItem;
-                                if (strongItem) {
-                                  // TODO(crbug.com/691979): Add metrics.
-                                  [weakCommandHandler
-                                      openNewTabWithSuggestionsItem:strongItem
-                                                          incognito:YES];
-                                }
-                              }
-                               style:UIAlertActionStyleDefault];
-
-  NSString* readLaterTitle =
-      l10n_util::GetNSString(IDS_IOS_CONTENT_CONTEXT_ADDTOREADINGLIST);
-  [alertCoordinator
-      addItemWithTitle:readLaterTitle
-                action:^{
-                  CollectionViewItem* strongItem = weakItem;
-                  if (strongItem) {
-                    // TODO(crbug.com/691979): Add metrics.
-                    [weakCommandHandler addItemToReadingList:strongItem];
-                  }
-                }
-                 style:UIAlertActionStyleDefault];
-
-  NSString* deleteTitle =
-      l10n_util::GetNSString(IDS_IOS_CONTENT_SUGGESTIONS_REMOVE);
-  [alertCoordinator addItemWithTitle:deleteTitle
-                              action:^{
-                                CollectionViewItem* strongItem = weakItem;
-                                if (strongItem) {
-                                  // TODO(crbug.com/691979): Add metrics.
-                                  [weakCommandHandler
-                                      dismissSuggestion:strongItem
-                                            atIndexPath:indexPath];
-                                }
-                              }
-                               style:UIAlertActionStyleDestructive];
-
-  [alertCoordinator addItemWithTitle:l10n_util::GetNSString(IDS_APP_CANCEL)
-                              action:^{
-                                // TODO(crbug.com/691979): Add metrics.
-                              }
-                               style:UIAlertActionStyleCancel];
-  return alertCoordinator;
-}
-
-+ (AlertCoordinator*)
-alertCoordinatorForMostVisitedItem:(CollectionViewItem*)item
-                  onViewController:(UIViewController*)viewController
-                           atPoint:(CGPoint)touchLocation
-                       atIndexPath:(NSIndexPath*)indexPath
-                    commandHandler:
-                        (id<ContentSuggestionsAlertCommands>)commandHandler {
-  AlertCoordinator* alertCoordinator = [[ActionSheetCoordinator alloc]
-      initWithBaseViewController:viewController
-                           title:nil
-                         message:nil
-                            rect:CGRectMake(touchLocation.x, touchLocation.y, 0,
-                                            0)
-                            view:[viewController view]];
-
-  __weak CollectionViewItem* weakItem = item;
-  __weak id<ContentSuggestionsAlertCommands> weakCommandHandler =
-      commandHandler;
-
-  [alertCoordinator
-      addItemWithTitle:l10n_util::GetNSStringWithFixup(
-                           IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWTAB)
-                action:^{
-                  CollectionViewItem* strongItem = weakItem;
-                  if (strongItem) {
-                    [weakCommandHandler
-                        openNewTabWithMostVisitedItem:strongItem
-                                            incognito:NO
-                                              atIndex:indexPath.item];
-                  }
-                }
-                 style:UIAlertActionStyleDefault];
-
-  [alertCoordinator
-      addItemWithTitle:l10n_util::GetNSStringWithFixup(
-                           IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWINCOGNITOTAB)
-                action:^{
-                  CollectionViewItem* strongItem = weakItem;
-                  if (strongItem) {
-                    [weakCommandHandler
-                        openNewTabWithMostVisitedItem:strongItem
-                                            incognito:YES
-                                              atIndex:indexPath.item];
-                  }
-                }
-                 style:UIAlertActionStyleDefault];
-
-  [alertCoordinator
-      addItemWithTitle:l10n_util::GetNSStringWithFixup(
-                           IDS_IOS_CONTENT_SUGGESTIONS_REMOVE)
-                action:^{
-                  CollectionViewItem* strongItem = weakItem;
-                  if (strongItem) {
-                    [weakCommandHandler removeMostVisited:strongItem];
-                  }
-                }
-                 style:UIAlertActionStyleDestructive];
-
-  [alertCoordinator addItemWithTitle:l10n_util::GetNSString(IDS_APP_CANCEL)
-                              action:nil
-                               style:UIAlertActionStyleCancel];
-
-  return alertCoordinator;
-}
-
-@end
diff --git a/ios/chrome/browser/content_suggestions/content_suggestions_coordinator.mm b/ios/chrome/browser/content_suggestions/content_suggestions_coordinator.mm
index c42c369..2d3ee36 100644
--- a/ios/chrome/browser/content_suggestions/content_suggestions_coordinator.mm
+++ b/ios/chrome/browser/content_suggestions/content_suggestions_coordinator.mm
@@ -16,8 +16,6 @@
 #include "components/reading_list/core/reading_list_model.h"
 #include "components/strings/grit/components_strings.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
-#import "ios/chrome/browser/content_suggestions/content_suggestions_alert_commands.h"
-#import "ios/chrome/browser/content_suggestions/content_suggestions_alert_factory.h"
 #import "ios/chrome/browser/content_suggestions/content_suggestions_header_controller.h"
 #import "ios/chrome/browser/content_suggestions/content_suggestions_mediator.h"
 #include "ios/chrome/browser/favicon/ios_chrome_large_icon_service_factory.h"
@@ -25,7 +23,7 @@
 #include "ios/chrome/browser/ntp_snippets/ios_chrome_content_suggestions_service_factory.h"
 #include "ios/chrome/browser/ntp_tiles/ios_most_visited_sites_factory.h"
 #include "ios/chrome/browser/reading_list/reading_list_model_factory.h"
-#import "ios/chrome/browser/ui/alert_coordinator/alert_coordinator.h"
+#import "ios/chrome/browser/ui/alert_coordinator/action_sheet_coordinator.h"
 #import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h"
 #import "ios/chrome/browser/ui/commands/generic_chrome_command.h"
 #include "ios/chrome/browser/ui/commands/ios_command_ids.h"
@@ -54,7 +52,6 @@
 #endif
 
 @interface ContentSuggestionsCoordinator ()<
-    ContentSuggestionsAlertCommands,
     ContentSuggestionsCommands,
     ContentSuggestionsHeaderCommands,
     ContentSuggestionsViewControllerDelegate,
@@ -74,6 +71,13 @@
 // |YES| if the fakebox header should be animated on scroll.
 @property(nonatomic, assign) BOOL animateHeader;
 
+// Opens the |URL| in a new tab |incognito| or not.
+- (void)openNewTabWithURL:(const GURL&)URL incognito:(BOOL)incognito;
+// Dismisses the |article|, removing it from the content service, and dismisses
+// the item at |indexPath| in the view controller.
+- (void)dismissArticle:(ContentSuggestionsItem*)article
+           atIndexPath:(NSIndexPath*)indexPath;
+
 @end
 
 @implementation ContentSuggestionsCoordinator
@@ -165,6 +169,8 @@
                  referrer:web::Referrer()
                transition:ui::PAGE_TRANSITION_AUTO_BOOKMARK
         rendererInitiated:NO];
+
+  [self stop];
 }
 
 - (void)openMostVisitedItem:(CollectionViewItem*)item
@@ -178,17 +184,85 @@
                  referrer:web::Referrer()
                transition:ui::PAGE_TRANSITION_AUTO_BOOKMARK
         rendererInitiated:NO];
+
+  [self stop];
 }
 
 - (void)displayContextMenuForArticle:(CollectionViewItem*)item
                              atPoint:(CGPoint)touchLocation
                          atIndexPath:(NSIndexPath*)indexPath {
-  self.alertCoordinator = [ContentSuggestionsAlertFactory
-      alertCoordinatorForSuggestionItem:item
-                       onViewController:self.suggestionsViewController
-                                atPoint:touchLocation
-                            atIndexPath:indexPath
-                         commandHandler:self];
+  ContentSuggestionsItem* articleItem =
+      base::mac::ObjCCastStrict<ContentSuggestionsItem>(item);
+  self.alertCoordinator = [[ActionSheetCoordinator alloc]
+      initWithBaseViewController:self.suggestionsViewController
+                           title:nil
+                         message:nil
+                            rect:CGRectMake(touchLocation.x, touchLocation.y, 0,
+                                            0)
+                            view:self.suggestionsViewController.collectionView];
+
+  __weak ContentSuggestionsCoordinator* weakSelf = self;
+  GURL articleURL = articleItem.URL;
+  NSString* articleTitle = articleItem.title;
+  __weak ContentSuggestionsItem* weakArticle = articleItem;
+
+  NSString* openInNewTabTitle =
+      l10n_util::GetNSString(IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWTAB);
+  [self.alertCoordinator
+      addItemWithTitle:openInNewTabTitle
+                action:^{
+                  // TODO(crbug.com/691979): Add metrics.
+                  [weakSelf openNewTabWithURL:articleURL incognito:NO];
+                }
+                 style:UIAlertActionStyleDefault];
+
+  NSString* openInNewTabIncognitoTitle =
+      l10n_util::GetNSString(IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWINCOGNITOTAB);
+  [self.alertCoordinator
+      addItemWithTitle:openInNewTabIncognitoTitle
+                action:^{
+                  // TODO(crbug.com/691979): Add metrics.
+                  [weakSelf openNewTabWithURL:articleURL incognito:YES];
+                }
+                 style:UIAlertActionStyleDefault];
+
+  NSString* readLaterTitle =
+      l10n_util::GetNSString(IDS_IOS_CONTENT_CONTEXT_ADDTOREADINGLIST);
+  [self.alertCoordinator
+      addItemWithTitle:readLaterTitle
+                action:^{
+                  ContentSuggestionsCoordinator* strongSelf = weakSelf;
+                  if (!strongSelf)
+                    return;
+
+                  base::RecordAction(
+                      base::UserMetricsAction("MobileReadingListAdd"));
+                  // TODO(crbug.com/691979): Add metrics.
+
+                  ReadingListModel* readingModel =
+                      ReadingListModelFactory::GetForBrowserState(
+                          strongSelf.browserState);
+                  readingModel->AddEntry(articleURL,
+                                         base::SysNSStringToUTF8(articleTitle),
+                                         reading_list::ADDED_VIA_CURRENT_APP);
+                }
+                 style:UIAlertActionStyleDefault];
+
+  NSString* deleteTitle =
+      l10n_util::GetNSString(IDS_IOS_CONTENT_SUGGESTIONS_REMOVE);
+  [self.alertCoordinator addItemWithTitle:deleteTitle
+                                   action:^{
+                                     // TODO(crbug.com/691979): Add metrics.
+                                     [weakSelf dismissArticle:weakArticle
+                                                  atIndexPath:indexPath];
+                                   }
+                                    style:UIAlertActionStyleDestructive];
+
+  [self.alertCoordinator addItemWithTitle:l10n_util::GetNSString(IDS_APP_CANCEL)
+                                   action:^{
+                                     // TODO(crbug.com/691979): Add metrics.
+                                   }
+                                    style:UIAlertActionStyleCancel];
 
   [self.alertCoordinator start];
 }
@@ -196,12 +270,68 @@
 - (void)displayContextMenuForMostVisitedItem:(CollectionViewItem*)item
                                      atPoint:(CGPoint)touchLocation
                                  atIndexPath:(NSIndexPath*)indexPath {
-  self.alertCoordinator = [ContentSuggestionsAlertFactory
-      alertCoordinatorForMostVisitedItem:item
-                        onViewController:self.suggestionsViewController
-                                 atPoint:touchLocation
-                             atIndexPath:indexPath
-                          commandHandler:self];
+  ContentSuggestionsMostVisitedItem* mostVisitedItem =
+      base::mac::ObjCCastStrict<ContentSuggestionsMostVisitedItem>(item);
+  self.alertCoordinator = [[ActionSheetCoordinator alloc]
+      initWithBaseViewController:self.suggestionsViewController
+                           title:nil
+                         message:nil
+                            rect:CGRectMake(touchLocation.x, touchLocation.y, 0,
+                                            0)
+                            view:self.suggestionsViewController.collectionView];
+
+  __weak ContentSuggestionsCoordinator* weakSelf = self;
+  __weak ContentSuggestionsMostVisitedItem* weakItem = mostVisitedItem;
+
+  [self.alertCoordinator
+      addItemWithTitle:l10n_util::GetNSStringWithFixup(
+                           IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWTAB)
+                action:^{
+                  ContentSuggestionsCoordinator* strongSelf = weakSelf;
+                  ContentSuggestionsMostVisitedItem* strongItem = weakItem;
+                  if (!strongSelf || !strongItem)
+                    return;
+                  [strongSelf logMostVisitedOpening:strongItem
+                                            atIndex:indexPath.item];
+                  [strongSelf openNewTabWithURL:strongItem.URL incognito:NO];
+                }
+                 style:UIAlertActionStyleDefault];
+
+  if (!self.browserState->IsOffTheRecord()) {
+    [self.alertCoordinator
+        addItemWithTitle:l10n_util::GetNSStringWithFixup(
+                             IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWINCOGNITOTAB)
+                  action:^{
+                    ContentSuggestionsCoordinator* strongSelf = weakSelf;
+                    ContentSuggestionsMostVisitedItem* strongItem = weakItem;
+                    if (!strongSelf || !strongItem)
+                      return;
+                    [strongSelf logMostVisitedOpening:strongItem
+                                              atIndex:indexPath.item];
+                    [strongSelf openNewTabWithURL:strongItem.URL incognito:YES];
+                  }
+                   style:UIAlertActionStyleDefault];
+  }
+
+  [self.alertCoordinator
+      addItemWithTitle:l10n_util::GetNSStringWithFixup(
+                           IDS_IOS_CONTENT_SUGGESTIONS_REMOVE)
+                action:^{
+                  ContentSuggestionsCoordinator* strongSelf = weakSelf;
+                  ContentSuggestionsMostVisitedItem* strongItem = weakItem;
+                  if (!strongSelf || !strongItem)
+                    return;
+                  base::RecordAction(
+                      base::UserMetricsAction("MostVisited_UrlBlacklisted"));
+                  [strongSelf.contentSuggestionsMediator
+                      blacklistMostVisitedURL:strongItem.URL];
+                  [strongSelf showMostVisitedUndoForURL:strongItem.URL];
+                }
+                 style:UIAlertActionStyleDestructive];
+
+  [self.alertCoordinator addItemWithTitle:l10n_util::GetNSString(IDS_APP_CANCEL)
+                                   action:nil
+                                    style:UIAlertActionStyleCancel];
 
   [self.alertCoordinator start];
 }
@@ -234,54 +364,6 @@
   NOTREACHED();
 }
 
-#pragma mark - ContentSuggestionsAlertCommands
-
-- (void)openNewTabWithSuggestionsItem:(CollectionViewItem*)item
-                            incognito:(BOOL)incognito {
-  ContentSuggestionsItem* suggestionsItem =
-      base::mac::ObjCCastStrict<ContentSuggestionsItem>(item);
-  [self openNewTabWithURL:suggestionsItem.URL incognito:incognito];
-}
-
-- (void)addItemToReadingList:(CollectionViewItem*)item {
-  ContentSuggestionsItem* suggestionsItem =
-      base::mac::ObjCCastStrict<ContentSuggestionsItem>(item);
-  base::RecordAction(base::UserMetricsAction("MobileReadingListAdd"));
-  ReadingListModel* readingModel =
-      ReadingListModelFactory::GetForBrowserState(self.browserState);
-  readingModel->AddEntry(suggestionsItem.URL,
-                         base::SysNSStringToUTF8(suggestionsItem.title),
-                         reading_list::ADDED_VIA_CURRENT_APP);
-}
-
-- (void)dismissSuggestion:(CollectionViewItem*)item
-              atIndexPath:(NSIndexPath*)indexPath {
-  ContentSuggestionsItem* suggestionsItem =
-      base::mac::ObjCCastStrict<ContentSuggestionsItem>(item);
-
-  // TODO(crbug.com/691979): Add metrics.
-  [self.contentSuggestionsMediator
-      dismissSuggestion:suggestionsItem.suggestionIdentifier];
-  [self.suggestionsViewController dismissEntryAtIndexPath:indexPath];
-}
-
-- (void)openNewTabWithMostVisitedItem:(CollectionViewItem*)item
-                            incognito:(BOOL)incognito
-                              atIndex:(NSInteger)index {
-  ContentSuggestionsMostVisitedItem* mostVisitedItem =
-      base::mac::ObjCCastStrict<ContentSuggestionsMostVisitedItem>(item);
-  [self logMostVisitedOpening:mostVisitedItem atIndex:index];
-  [self openNewTabWithURL:mostVisitedItem.URL incognito:incognito];
-}
-
-- (void)removeMostVisited:(CollectionViewItem*)item {
-  ContentSuggestionsMostVisitedItem* mostVisitedItem =
-      base::mac::ObjCCastStrict<ContentSuggestionsMostVisitedItem>(item);
-  base::RecordAction(base::UserMetricsAction("MostVisited_UrlBlacklisted"));
-  [self.contentSuggestionsMediator blacklistMostVisitedURL:mostVisitedItem.URL];
-  [self showMostVisitedUndoForURL:mostVisitedItem.URL];
-}
-
 #pragma mark - ContentSuggestionsHeaderCommands
 
 - (void)updateFakeOmniboxForScrollView:(UIScrollView*)scrollView {
@@ -405,7 +487,6 @@
 
 #pragma mark - Private
 
-// Opens the |URL| in a new tab |incognito| or not.
 - (void)openNewTabWithURL:(const GURL&)URL incognito:(BOOL)incognito {
   // TODO(crbug.com/691979): Add metrics.
 
@@ -414,6 +495,19 @@
                          inIncognito:incognito
                         inBackground:NO
                             appendTo:kCurrentTab];
+
+  [self stop];
+}
+
+- (void)dismissArticle:(ContentSuggestionsItem*)article
+           atIndexPath:(NSIndexPath*)indexPath {
+  if (!article)
+    return;
+
+  // TODO(crbug.com/691979): Add metrics.
+  [self.contentSuggestionsMediator
+      dismissSuggestion:article.suggestionIdentifier];
+  [self.suggestionsViewController dismissEntryAtIndexPath:indexPath];
 }
 
 // Logs a histogram due to a Most Visited item being opened.
diff --git a/ios/chrome/browser/feature_engagement_tracker/BUILD.gn b/ios/chrome/browser/feature_engagement_tracker/BUILD.gn
new file mode 100644
index 0000000..480b628c
--- /dev/null
+++ b/ios/chrome/browser/feature_engagement_tracker/BUILD.gn
@@ -0,0 +1,20 @@
+# 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.
+
+source_set("feature_engagement_tracker") {
+  sources = [
+    "feature_engagement_tracker_factory.h",
+    "feature_engagement_tracker_factory.mm",
+  ]
+
+  configs += [ "//build/config/compiler:enable_arc" ]
+
+  deps = [
+    "//base",
+    "//components/feature_engagement_tracker",
+    "//components/keyed_service/ios",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/browser_state",
+  ]
+}
diff --git a/ios/chrome/browser/feature_engagement_tracker/OWNERS b/ios/chrome/browser/feature_engagement_tracker/OWNERS
new file mode 100644
index 0000000..b5a2453
--- /dev/null
+++ b/ios/chrome/browser/feature_engagement_tracker/OWNERS
@@ -0,0 +1,2 @@
+edchin@chromium.org
+gchatz@chromium.org
diff --git a/ios/chrome/browser/feature_engagement_tracker/feature_engagement_tracker_factory.h b/ios/chrome/browser/feature_engagement_tracker/feature_engagement_tracker_factory.h
new file mode 100644
index 0000000..2a7286ae
--- /dev/null
+++ b/ios/chrome/browser/feature_engagement_tracker/feature_engagement_tracker_factory.h
@@ -0,0 +1,54 @@
+// 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_BROWSER_FEATURE_ENGAGEMENT_TRACKER_FEATURE_ENGAGEMENT_TRACKER_FACTORY_H_
+#define IOS_CHROME_BROWSER_FEATURE_ENGAGEMENT_TRACKER_FEATURE_ENGAGEMENT_TRACKER_FACTORY_H_
+
+#include "base/macros.h"
+#include "components/keyed_service/ios/browser_state_keyed_service_factory.h"
+
+namespace feature_engagement_tracker {
+class FeatureEngagementTracker;
+}  // namespace feature_engagement_tracker
+
+namespace base {
+template <typename T>
+struct DefaultSingletonTraits;
+}  // namespace base
+
+namespace ios {
+class ChromeBrowserState;
+}  // namespace ios
+
+// FeatureEngagementTrackerFactory is the main class for interacting with the
+// feature_engagement_tracker component. It uses the KeyedService API to
+// expose functions to associate and retrieve a FeatureEngagementTracker object
+// with a given ios::ChromeBrowserState object.
+class FeatureEngagementTrackerFactory : public BrowserStateKeyedServiceFactory {
+ public:
+  // Returns the FeatureEngagementTrackerFactory singleton object.
+  static FeatureEngagementTrackerFactory* GetInstance();
+
+  // Retrieves the FeatureEngagementTracker object associated with a given
+  // browser state. It is created if it does not already exist.
+  static feature_engagement_tracker::FeatureEngagementTracker*
+  GetForBrowserState(ios::ChromeBrowserState* browser_state);
+
+ protected:
+  // BrowserStateKeyedServiceFactory implementation.
+  std::unique_ptr<KeyedService> BuildServiceInstanceFor(
+      web::BrowserState* context) const override;
+  web::BrowserState* GetBrowserStateToUse(
+      web::BrowserState* context) const override;
+
+ private:
+  friend struct base::DefaultSingletonTraits<FeatureEngagementTrackerFactory>;
+
+  FeatureEngagementTrackerFactory();
+  ~FeatureEngagementTrackerFactory() override;
+
+  DISALLOW_COPY_AND_ASSIGN(FeatureEngagementTrackerFactory);
+};
+
+#endif  // IOS_CHROME_BROWSER_FEATURE_ENGAGEMENT_TRACKER_FEATURE_ENGAGEMENT_TRACKER_FACTORY_H_
diff --git a/ios/chrome/browser/feature_engagement_tracker/feature_engagement_tracker_factory.mm b/ios/chrome/browser/feature_engagement_tracker/feature_engagement_tracker_factory.mm
new file mode 100644
index 0000000..d4cec7e
--- /dev/null
+++ b/ios/chrome/browser/feature_engagement_tracker/feature_engagement_tracker_factory.mm
@@ -0,0 +1,74 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ios/chrome/browser/feature_engagement_tracker/feature_engagement_tracker_factory.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/singleton.h"
+#include "base/sequenced_task_runner.h"
+#include "base/task_scheduler/post_task.h"
+#include "components/feature_engagement_tracker/public/feature_engagement_tracker.h"
+#include "components/keyed_service/ios/browser_state_dependency_manager.h"
+#include "ios/chrome/browser/browser_state/browser_state_otr_helper.h"
+#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
+#include "ios/chrome/browser/chrome_constants.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+
+const base::FilePath::CharType kIOSFeatureEngagementTrackerStorageDirname[] =
+    FILE_PATH_LITERAL("Feature Engagement Tracker");
+
+}  // namespace
+
+// static
+FeatureEngagementTrackerFactory*
+FeatureEngagementTrackerFactory::GetInstance() {
+  return base::Singleton<FeatureEngagementTrackerFactory>::get();
+}
+
+// static
+feature_engagement_tracker::FeatureEngagementTracker*
+FeatureEngagementTrackerFactory::GetForBrowserState(
+    ios::ChromeBrowserState* browser_state) {
+  return static_cast<feature_engagement_tracker::FeatureEngagementTracker*>(
+      GetInstance()->GetServiceForBrowserState(browser_state, true));
+}
+
+FeatureEngagementTrackerFactory::FeatureEngagementTrackerFactory()
+    : BrowserStateKeyedServiceFactory(
+          "FeatureEngagementTracker",
+          BrowserStateDependencyManager::GetInstance()) {}
+
+FeatureEngagementTrackerFactory::~FeatureEngagementTrackerFactory() = default;
+
+std::unique_ptr<KeyedService>
+FeatureEngagementTrackerFactory::BuildServiceInstanceFor(
+    web::BrowserState* context) const {
+  ios::ChromeBrowserState* browser_state =
+      ios::ChromeBrowserState::FromBrowserState(context);
+
+  scoped_refptr<base::SequencedTaskRunner> background_task_runner =
+      base::CreateSequencedTaskRunnerWithTraits(
+          {base::MayBlock(), base::TaskPriority::BACKGROUND});
+
+  base::FilePath storage_dir = browser_state->GetStatePath().Append(
+      kIOSFeatureEngagementTrackerStorageDirname);
+
+  return base::WrapUnique(
+      feature_engagement_tracker::FeatureEngagementTracker::Create(
+          storage_dir, background_task_runner));
+}
+
+// Finds which browser state to use. If |context| is an incognito browser
+// state, it returns the non-incognito state. Thus, feature engagement events
+// are tracked even in incognito tabs.
+web::BrowserState* FeatureEngagementTrackerFactory::GetBrowserStateToUse(
+    web::BrowserState* context) const {
+  return GetBrowserStateRedirectedInIncognito(context);
+}
diff --git a/ios/chrome/browser/payments/BUILD.gn b/ios/chrome/browser/payments/BUILD.gn
index d98a6d1..67b7de5 100644
--- a/ios/chrome/browser/payments/BUILD.gn
+++ b/ios/chrome/browser/payments/BUILD.gn
@@ -7,6 +7,8 @@
 source_set("payments") {
   configs += [ "//build/config/compiler:enable_arc" ]
   sources = [
+    "ios_can_make_payment_query_factory.cc",
+    "ios_can_make_payment_query_factory.h",
     "payment_request.h",
     "payment_request.mm",
     "payment_request_util.h",
@@ -15,10 +17,12 @@
   deps = [
     "//base",
     "//components/autofill/core/browser",
+    "//components/keyed_service/ios",
     "//components/payments/core",
     "//components/strings:components_strings_grit",
     "//ios/chrome/browser",
     "//ios/chrome/browser/autofill",
+    "//ios/chrome/browser/browser_state",
     "//ios/web",
     "//ui/base",
   ]
diff --git a/ios/chrome/browser/payments/ios_can_make_payment_query_factory.cc b/ios/chrome/browser/payments/ios_can_make_payment_query_factory.cc
new file mode 100644
index 0000000..bbd68fc
--- /dev/null
+++ b/ios/chrome/browser/payments/ios_can_make_payment_query_factory.cc
@@ -0,0 +1,37 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ios/chrome/browser/payments/ios_can_make_payment_query_factory.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/memory/singleton.h"
+#include "components/keyed_service/ios/browser_state_dependency_manager.h"
+#include "components/payments/core/can_make_payment_query.h"
+#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
+#include "ios/web/public/browser_state.h"
+
+// static
+IOSCanMakePaymentQueryFactory* IOSCanMakePaymentQueryFactory::GetInstance() {
+  return base::Singleton<IOSCanMakePaymentQueryFactory>::get();
+}
+
+payments::CanMakePaymentQuery*
+IOSCanMakePaymentQueryFactory::GetForBrowserState(
+    ios::ChromeBrowserState* browser_state) {
+  return static_cast<payments::CanMakePaymentQuery*>(
+      GetInstance()->GetServiceForBrowserState(browser_state, true));
+}
+
+IOSCanMakePaymentQueryFactory::IOSCanMakePaymentQueryFactory()
+    : BrowserStateKeyedServiceFactory(
+          "CanMakePaymentQuery",
+          BrowserStateDependencyManager::GetInstance()) {}
+
+IOSCanMakePaymentQueryFactory::~IOSCanMakePaymentQueryFactory() {}
+
+std::unique_ptr<KeyedService>
+IOSCanMakePaymentQueryFactory::BuildServiceInstanceFor(
+    web::BrowserState* context) const {
+  return base::WrapUnique(new payments::CanMakePaymentQuery);
+}
diff --git a/ios/chrome/browser/payments/ios_can_make_payment_query_factory.h b/ios/chrome/browser/payments/ios_can_make_payment_query_factory.h
new file mode 100644
index 0000000..e3549e38
--- /dev/null
+++ b/ios/chrome/browser/payments/ios_can_make_payment_query_factory.h
@@ -0,0 +1,47 @@
+// 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_BROWSER_PAYMENTS_IOS_CAN_MAKE_PAYMENT_QUERY_FACTORY_H_
+#define IOS_CHROME_BROWSER_PAYMENTS_IOS_CAN_MAKE_PAYMENT_QUERY_FACTORY_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "components/keyed_service/ios/browser_state_keyed_service_factory.h"
+
+namespace base {
+template <typename T>
+struct DefaultSingletonTraits;
+}  // namespace base
+
+namespace ios {
+class ChromeBrowserState;
+}  // namespace ios
+
+namespace payments {
+class CanMakePaymentQuery;
+}  // namespace payments
+
+// Ensures that there's only one instance of CanMakePaymentQuery per browser
+// state.
+class IOSCanMakePaymentQueryFactory : public BrowserStateKeyedServiceFactory {
+ public:
+  static IOSCanMakePaymentQueryFactory* GetInstance();
+  payments::CanMakePaymentQuery* GetForBrowserState(
+      ios::ChromeBrowserState* browser_state);
+
+ private:
+  friend struct base::DefaultSingletonTraits<IOSCanMakePaymentQueryFactory>;
+
+  IOSCanMakePaymentQueryFactory();
+  ~IOSCanMakePaymentQueryFactory() override;
+
+  // BrowserStateKeyedServiceFactory implementation.
+  std::unique_ptr<KeyedService> BuildServiceInstanceFor(
+      web::BrowserState* context) const override;
+
+  DISALLOW_COPY_AND_ASSIGN(IOSCanMakePaymentQueryFactory);
+};
+
+#endif  // IOS_CHROME_BROWSER_PAYMENTS_IOS_CAN_MAKE_PAYMENT_QUERY_FACTORY_H_
diff --git a/ios/chrome/browser/payments/payment_request.h b/ios/chrome/browser/payments/payment_request.h
index f2a70a8..b91b47a 100644
--- a/ios/chrome/browser/payments/payment_request.h
+++ b/ios/chrome/browser/payments/payment_request.h
@@ -5,6 +5,7 @@
 #ifndef IOS_CHROME_BROWSER_PAYMENTS_PAYMENT_REQUEST_H_
 #define IOS_CHROME_BROWSER_PAYMENTS_PAYMENT_REQUEST_H_
 
+#include <map>
 #include <memory>
 #include <set>
 #include <string>
@@ -29,6 +30,10 @@
 class CurrencyFormatter;
 }  // namespace payments
 
+namespace ios {
+class ChromeBrowserState;
+}  // namepsace ios
+
 // A protocol implementd by any UI classes that the PaymentRequest object
 // needs to communicate with in order to perform certain actions such as
 // initiating UI to request full card details for payment.
@@ -48,6 +53,7 @@
  public:
   // |personal_data_manager| should not be null and should outlive this object.
   PaymentRequest(const web::PaymentRequest& web_payment_request,
+                 ios::ChromeBrowserState* browser_state_,
                  autofill::PersonalDataManager* personal_data_manager,
                  id<PaymentRequestUIDelegate> payment_request_ui_delegate);
   ~PaymentRequest() override;
@@ -149,6 +155,11 @@
     return basic_card_specified_networks_;
   }
 
+  const std::map<std::string, std::set<std::string>>& stringified_method_data()
+      const {
+    return stringified_method_data_;
+  }
+
   // Adds |credit_card| to the list of cached credit cards, updates the list of
   // available credit cards, and returns a reference to the cached copy of
   // |credit_card|.
@@ -218,6 +229,9 @@
   web::PaymentRequest web_payment_request_;
 
   // Never null and outlives this object.
+  ios::ChromeBrowserState* browser_state_;
+
+  // Never null and outlives this object.
   autofill::PersonalDataManager* personal_data_manager_;
 
   // The PaymentRequestUIDelegate as provided by the UI object that originally
@@ -259,6 +273,10 @@
   // use |supported_card_networks_| for merchant support checks.
   std::set<std::string> basic_card_specified_networks_;
 
+  // A mapping of the payment method names to the corresponding JSON-stringified
+  // payment method specific data.
+  std::map<std::string, std::set<std::string>> stringified_method_data_;
+
   // A vector of pointers to the shipping options in |web_payment_request_|.
   std::vector<web::PaymentShippingOption*> shipping_options_;
   web::PaymentShippingOption* selected_shipping_option_;
diff --git a/ios/chrome/browser/payments/payment_request.mm b/ios/chrome/browser/payments/payment_request.mm
index 21c3ef5..27463c6 100644
--- a/ios/chrome/browser/payments/payment_request.mm
+++ b/ios/chrome/browser/payments/payment_request.mm
@@ -21,6 +21,7 @@
 #include "components/payments/core/payment_request_data_util.h"
 #include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/autofill/validation_rules_storage_factory.h"
+#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #import "ios/chrome/browser/payments/payment_request_util.h"
 #include "ios/web/public/payments/payment_request.h"
 #include "third_party/libaddressinput/chromium/chrome_metadata_source.h"
@@ -48,9 +49,11 @@
 
 PaymentRequest::PaymentRequest(
     const web::PaymentRequest& web_payment_request,
+    ios::ChromeBrowserState* browser_state,
     autofill::PersonalDataManager* personal_data_manager,
     id<PaymentRequestUIDelegate> payment_request_ui_delegate)
     : web_payment_request_(web_payment_request),
+      browser_state_(browser_state),
       personal_data_manager_(personal_data_manager),
       payment_request_ui_delegate_(payment_request_ui_delegate),
       address_normalizer_(new payments::AddressNormalizerImpl(
@@ -109,8 +112,7 @@
 }
 
 bool PaymentRequest::IsIncognito() const {
-  NOTREACHED() << "Implementation is never used";
-  return false;
+  return browser_state_->IsOffTheRecord();
 }
 
 bool PaymentRequest::IsSslCertificateValid() {
@@ -273,6 +275,13 @@
 }
 
 void PaymentRequest::PopulateCreditCardCache() {
+  for (const payments::PaymentMethodData& method_data_entry :
+       web_payment_request_.method_data) {
+    for (const std::string& method : method_data_entry.supported_methods) {
+      stringified_method_data_[method].insert(method_data_entry.data);
+    }
+  }
+
   // TODO(crbug.com/709036): Validate method data.
   payments::data_util::ParseBasicCardSupportedNetworks(
       web_payment_request_.method_data, &supported_card_networks_,
diff --git a/ios/chrome/browser/payments/test_payment_request.h b/ios/chrome/browser/payments/test_payment_request.h
index b86f5889..5435eb9d 100644
--- a/ios/chrome/browser/payments/test_payment_request.h
+++ b/ios/chrome/browser/payments/test_payment_request.h
@@ -13,6 +13,10 @@
 class RegionDataLoader;
 }  // namespace autofill
 
+namespace ios {
+class ChromeBrowserState;
+}  // namespace ios
+
 namespace payments {
 class PaymentsProfileComparator;
 }  // namespace payments
@@ -27,9 +31,11 @@
  public:
   // |personal_data_manager| should not be null and should outlive this object.
   TestPaymentRequest(const web::PaymentRequest& web_payment_request,
+                     ios::ChromeBrowserState* browser_state,
                      autofill::PersonalDataManager* personal_data_manager,
                      id<PaymentRequestUIDelegate> payment_request_ui_delegate)
       : PaymentRequest(web_payment_request,
+                       browser_state,
                        personal_data_manager,
                        payment_request_ui_delegate),
         region_data_loader_(nullptr),
@@ -37,7 +43,10 @@
 
   TestPaymentRequest(const web::PaymentRequest& web_payment_request,
                      autofill::PersonalDataManager* personal_data_manager)
-      : TestPaymentRequest(web_payment_request, personal_data_manager, nil) {}
+      : TestPaymentRequest(web_payment_request,
+                           nil,
+                           personal_data_manager,
+                           nil) {}
 
   ~TestPaymentRequest() override {}
 
diff --git a/ios/chrome/browser/ui/dialogs/dialog_presenter.h b/ios/chrome/browser/ui/dialogs/dialog_presenter.h
index 33d38b8..fc939cb 100644
--- a/ios/chrome/browser/ui/dialogs/dialog_presenter.h
+++ b/ios/chrome/browser/ui/dialogs/dialog_presenter.h
@@ -77,9 +77,6 @@
 // view controller.
 - (void)tryToPresent;
 
-// Create an title for the alert base on the URL.
-+ (NSString*)localizedTitleForJavaScriptAlertFromPage:(const GURL&)pageURL;
-
 @end
 
 @interface DialogPresenter (ExposedForTesting)
diff --git a/ios/chrome/browser/ui/dialogs/dialog_presenter.mm b/ios/chrome/browser/ui/dialogs/dialog_presenter.mm
index 123efba..fb530ba 100644
--- a/ios/chrome/browser/ui/dialogs/dialog_presenter.mm
+++ b/ios/chrome/browser/ui/dialogs/dialog_presenter.mm
@@ -91,6 +91,12 @@
 // The block to use for the JavaScript dialog blocking option for |coordinator|.
 - (ProceduralBlock)blockingActionForCoordinator:(AlertCoordinator*)coordinator;
 
+// Creates a title for the alert based on the URL (|pageURL|), and its
+// relationship to the |mainFrameURL| (typically these are identical except for
+// when posting alerts from an embedded iframe).
++ (NSString*)localizedTitleForJavaScriptAlertFromPage:(const GURL&)pageURL
+                                         mainFrameURL:(const GURL&)mainFrameURL;
+
 @end
 
 @implementation DialogPresenter
@@ -134,8 +140,9 @@
                                 requestURL:(const GURL&)requestURL
                                   webState:(web::WebState*)webState
                          completionHandler:(void (^)(void))completionHandler {
-  NSString* title =
-      [DialogPresenter localizedTitleForJavaScriptAlertFromPage:requestURL];
+  NSString* title = [DialogPresenter
+      localizedTitleForJavaScriptAlertFromPage:requestURL
+                                  mainFrameURL:webState->GetLastCommittedURL()];
   AlertCoordinator* alertCoordinator =
       [[AlertCoordinator alloc] initWithBaseViewController:self.viewController
                                                      title:title
@@ -170,8 +177,9 @@
                                     webState:(web::WebState*)webState
                            completionHandler:
                                (void (^)(BOOL isConfirmed))completionHandler {
-  NSString* title =
-      [DialogPresenter localizedTitleForJavaScriptAlertFromPage:requestURL];
+  NSString* title = [DialogPresenter
+      localizedTitleForJavaScriptAlertFromPage:requestURL
+                                  mainFrameURL:webState->GetLastCommittedURL()];
   AlertCoordinator* alertCoordinator =
       [[AlertCoordinator alloc] initWithBaseViewController:self.viewController
                                                      title:title
@@ -207,8 +215,9 @@
                                      webState:(web::WebState*)webState
                             completionHandler:
                                 (void (^)(NSString* input))completionHandler {
-  NSString* title =
-      [DialogPresenter localizedTitleForJavaScriptAlertFromPage:requestURL];
+  NSString* title = [DialogPresenter
+      localizedTitleForJavaScriptAlertFromPage:requestURL
+                                  mainFrameURL:webState->GetLastCommittedURL()];
   InputAlertCoordinator* alertCoordinator = [[InputAlertCoordinator alloc]
       initWithBaseViewController:self.viewController
                            title:title
@@ -349,10 +358,15 @@
     [self showNextDialog];
 }
 
-+ (NSString*)localizedTitleForJavaScriptAlertFromPage:(const GURL&)pageURL {
++ (NSString*)localizedTitleForJavaScriptAlertFromPage:(const GURL&)pageURL
+                                         mainFrameURL:
+                                             (const GURL&)mainFrameURL {
   NSString* localizedTitle = nil;
   NSString* hostname = base::SysUTF8ToNSString(pageURL.host());
-  if (!hostname.length) {
+
+  bool sameOriginAsMainFrame = pageURL.GetOrigin() == mainFrameURL.GetOrigin();
+
+  if (!sameOriginAsMainFrame) {
     localizedTitle = l10n_util::GetNSString(
         IDS_JAVASCRIPT_MESSAGEBOX_TITLE_NONSTANDARD_URL_IFRAME);
   } else {
diff --git a/ios/chrome/browser/ui/dialogs/dialog_presenter_unittest.mm b/ios/chrome/browser/ui/dialogs/dialog_presenter_unittest.mm
index 2bd6df4..0e933b3 100644
--- a/ios/chrome/browser/ui/dialogs/dialog_presenter_unittest.mm
+++ b/ios/chrome/browser/ui/dialogs/dialog_presenter_unittest.mm
@@ -4,13 +4,16 @@
 
 #import "ios/chrome/browser/ui/dialogs/dialog_presenter.h"
 
+#include "base/strings/sys_string_conversions.h"
 #include "base/time/time.h"
+#include "components/strings/grit/components_strings.h"
 #import "ios/chrome/browser/ui/alert_coordinator/alert_coordinator.h"
 #import "ios/web/public/test/fakes/test_web_state.h"
 #include "ios/web/public/web_state/web_state_observer.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/gtest_mac.h"
 #include "testing/platform_test.h"
+#include "ui/base/l10n/l10n_util.h"
 #include "url/gurl.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -97,6 +100,43 @@
   EXPECT_EQ(&webState, delegate().presentedWebStates.front());
 }
 
+// Test that javascript dialogs are presented with a different title when they
+// are presented from a URL with a different origin to the webstate origin.
+TEST_F(DialogPresenterTest, IFrameTest) {
+  DialogPresenterTestWebState web_state;
+  GURL foo_url = GURL("http://foo.com");
+  GURL bar_url = GURL("http://bar.com");
+
+  web_state.SetCurrentURL(foo_url);
+  [presenter() runJavaScriptAlertPanelWithMessage:@""
+                                       requestURL:foo_url
+                                         webState:&web_state
+                                completionHandler:nil];
+
+  // Ensure alerts from the same domain have a correct title.
+  NSString* same_origin_title =
+      [presenter() presentedDialogCoordinator].alertController.title;
+  NSString* hostname = base::SysUTF8ToNSString(foo_url.host());
+  NSString* expected_title = l10n_util::GetNSStringF(
+      IDS_JAVASCRIPT_MESSAGEBOX_TITLE, base::SysNSStringToUTF16(hostname));
+  EXPECT_NSEQ(expected_title, same_origin_title);
+
+  [presenter() cancelAllDialogs];
+
+  // Ensure that alerts from an embedded iframe with a different domain have
+  // a title and it's different to the same-origin title.
+  web_state.SetCurrentURL(bar_url);
+  [presenter() runJavaScriptAlertPanelWithMessage:@""
+                                       requestURL:foo_url
+                                         webState:&web_state
+                                completionHandler:nil];
+  NSString* different_origin_title =
+      [presenter() presentedDialogCoordinator].alertController.title;
+  expected_title = l10n_util::GetNSString(
+      IDS_JAVASCRIPT_MESSAGEBOX_TITLE_NONSTANDARD_URL_IFRAME);
+  EXPECT_NSEQ(expected_title, different_origin_title);
+}
+
 // Tests that multiple JavaScript dialogs are queued
 TEST_F(DialogPresenterTest, QueueTest) {
   // Tests that the dialog for |webState1| has been shown.
diff --git a/ios/chrome/browser/ui/dialogs/javascript_dialog_egtest.mm b/ios/chrome/browser/ui/dialogs/javascript_dialog_egtest.mm
index 9d4f449..7f957a9 100644
--- a/ios/chrome/browser/ui/dialogs/javascript_dialog_egtest.mm
+++ b/ios/chrome/browser/ui/dialogs/javascript_dialog_egtest.mm
@@ -200,11 +200,14 @@
              @"Alert with title was not present: %@", alert_label);
 }
 
-void WaitForJavaScripDialogToBeShown() {
-  NSString* alert_label = [DialogPresenter
-      localizedTitleForJavaScriptAlertFromPage:HttpServer::MakeUrl(
-                                                   kJavaScriptTestURL)];
-  WaitForAlertToBeShown(alert_label);
+void WaitForJavaScriptDialogToBeShown() {
+  GURL javaScriptURL = HttpServer::MakeUrl(kJavaScriptTestURL);
+
+  NSString* hostname = base::SysUTF8ToNSString(javaScriptURL.host());
+  NSString* expectedTitle = l10n_util::GetNSStringF(
+      IDS_JAVASCRIPT_MESSAGEBOX_TITLE, base::SysNSStringToUTF16(hostname));
+
+  WaitForAlertToBeShown(expectedTitle);
 }
 
 // Injects JavaScript to show a dialog with |type|, verifying that it was
@@ -212,7 +215,7 @@
 void ShowJavaScriptDialog(JavaScriptAlertType type) {
   DisplayJavaScriptAlert(type);
 
-  WaitForJavaScripDialogToBeShown();
+  WaitForJavaScriptDialogToBeShown();
 
   // Check the message of the alert.
   id<GREYMatcher> messageLabel =
@@ -226,11 +229,13 @@
 void AssertJavaScriptAlertNotPresent() {
   ConditionBlock condition = ^{
     NSError* error = nil;
-    NSString* alertLabel = [DialogPresenter
-        localizedTitleForJavaScriptAlertFromPage:HttpServer::MakeUrl(
-                                                     kJavaScriptTestURL)];
+    GURL javaScriptURL = HttpServer::MakeUrl(kJavaScriptTestURL);
+    NSString* hostname = base::SysUTF8ToNSString(javaScriptURL.host());
+    NSString* expectedTitle = l10n_util::GetNSStringF(
+        IDS_JAVASCRIPT_MESSAGEBOX_TITLE, base::SysNSStringToUTF16(hostname));
+
     id<GREYMatcher> titleLabel =
-        chrome_test_util::StaticTextWithAccessibilityLabel(alertLabel);
+        chrome_test_util::StaticTextWithAccessibilityLabel(expectedTitle);
     [[EarlGrey selectElementWithMatcher:titleLabel] assertWithMatcher:grey_nil()
                                                                 error:&error];
     return !error;
@@ -443,10 +448,10 @@
   web::WebState* webState = chrome_test_util::GetCurrentWebState();
   NSString* script = GetJavaScriptAlertLoopScript();
   webState->ExecuteJavaScript(base::SysNSStringToUTF16(script));
-  WaitForJavaScripDialogToBeShown();
+  WaitForJavaScriptDialogToBeShown();
 
   [[EarlGrey selectElementWithMatcher:OKButton()] performAction:grey_tap()];
-  WaitForJavaScripDialogToBeShown();
+  WaitForJavaScriptDialogToBeShown();
 
   // Tap the suppress dialogs button.
   TapSuppressDialogsButton();
@@ -495,7 +500,7 @@
       performAction:grey_tap()];
 
   // Make sure the alert is present.
-  WaitForJavaScripDialogToBeShown();
+  WaitForJavaScriptDialogToBeShown();
 
   [[EarlGrey selectElementWithMatcher:OKButton()] performAction:grey_tap()];
 
@@ -574,10 +579,12 @@
   }
 
   // Wait for the alert to be shown.
-  NSString* alertLabel = [DialogPresenter
-      localizedTitleForJavaScriptAlertFromPage:HttpServer::MakeUrl(
-                                                   kJavaScriptTestURL)];
-  WaitForAlertToBeShown(alertLabel);
+  GURL javaScriptURL = HttpServer::MakeUrl(kJavaScriptTestURL);
+  NSString* hostname = base::SysUTF8ToNSString(javaScriptURL.host());
+  NSString* expectedTitle = l10n_util::GetNSStringF(
+      IDS_JAVASCRIPT_MESSAGEBOX_TITLE, base::SysNSStringToUTF16(hostname));
+
+  WaitForAlertToBeShown(expectedTitle);
 
   // Verify that the omnibox shows the correct URL when the dialog is visible.
   GURL onloadURL = HttpServer::MakeUrl(kOnLoadAlertURL);
diff --git a/ios/chrome/browser/ui/ntp/google_landing_mediator.mm b/ios/chrome/browser/ui/ntp/google_landing_mediator.mm
index ef06b35d..693d450 100644
--- a/ios/chrome/browser/ui/ntp/google_landing_mediator.mm
+++ b/ios/chrome/browser/ui/ntp/google_landing_mediator.mm
@@ -116,45 +116,51 @@
   // Most visited data from the MostVisitedSites service currently in use.
   ntp_tiles::NTPTilesVector _mostVisitedData;
 
+  // Most visited data from the MostVisitedSites service (copied upon receiving
+  // the callback), not yet used by the collection. It will be used after a user
+  // interaction.
+  ntp_tiles::NTPTilesVector _freshMostVisitedData;
+
+  // Most visited data used for logging the tiles impression. The data are
+  // copied when receiving the first non-empty data. This copy is used to make
+  // sure only the data received the first time are logged, and only once.
+  ntp_tiles::NTPTilesVector _mostVisitedDataForLogging;
+
   // Observes the WebStateList so that this mediator can update the UI when the
   // active WebState changes.
   std::unique_ptr<WebStateListObserverBridge> _webStateListObserver;
 
   // What's new promo.
-  std::unique_ptr<NotificationPromoWhatsNew> _notification_promo;
+  std::unique_ptr<NotificationPromoWhatsNew> _notificationPromo;
 
   // Used to cancel tasks for the LargeIconService.
   base::CancelableTaskTracker _cancelable_task_tracker;
+
+  // Consumer to handle google landing update notifications.
+  base::WeakNSProtocol<id<GoogleLandingConsumer>> _consumer;
+
+  // Dispatcher for this mediator.
+  base::WeakNSProtocol<id<ChromeExecuteCommand, UrlLoader>> _dispatcher;
 }
 
 // Consumer to handle google landing update notifications.
-@property(nonatomic) id<GoogleLandingConsumer> consumer;
+@property(nonatomic, assign, readonly) id<GoogleLandingConsumer> consumer;
 
 // The WebStateList that is being observed by this mediator.
-@property(nonatomic, assign) WebStateList* webStateList;
+@property(nonatomic, assign, readonly) WebStateList* webStateList;
 
 // The dispatcher for this mediator.
-@property(nonatomic, assign) id<ChromeExecuteCommand, UrlLoader> dispatcher;
-
-// Most visited data from the MostVisitedSites service (copied upon receiving
-// the callback), not yet used.
-@property(nonatomic, assign) ntp_tiles::NTPTilesVector freshMostVisitedData;
+@property(nonatomic, assign, readonly) id<ChromeExecuteCommand, UrlLoader>
+    dispatcher;
 
 // Perform initial setup.
 - (void)setUp;
 
-// If there is some fresh most visited tiles, they become the current tiles and
-// the consumer gets notified.
-- (void)useFreshData;
-
 @end
 
 @implementation GoogleLandingMediator
 
-@synthesize consumer = _consumer;
-@synthesize dispatcher = _dispatcher;
 @synthesize webStateList = _webStateList;
-@synthesize freshMostVisitedData = _freshMostVisitedData;
 
 - (instancetype)initWithConsumer:(id<GoogleLandingConsumer>)consumer
                     browserState:(ios::ChromeBrowserState*)browserState
@@ -162,9 +168,9 @@
                     webStateList:(WebStateList*)webStateList {
   self = [super init];
   if (self) {
-    _consumer = consumer;
+    _consumer.reset(consumer);
     _browserState = browserState;
-    _dispatcher = dispatcher;
+    _dispatcher.reset(dispatcher);
     _webStateList = webStateList;
 
     _webStateListObserver = base::MakeUnique<WebStateListObserverBridge>(self);
@@ -178,20 +184,21 @@
 - (void)shutdown {
   _webStateList->RemoveObserver(_webStateListObserver.get());
   [[NSNotificationCenter defaultCenter] removeObserver:self.consumer];
+  _observer.reset();
 }
 
 - (void)setUp {
-  [_consumer setVoiceSearchIsEnabled:ios::GetChromeBrowserProvider()
-                                         ->GetVoiceSearchProvider()
-                                         ->IsVoiceSearchEnabled()];
-  [_consumer
+  [self.consumer setVoiceSearchIsEnabled:ios::GetChromeBrowserProvider()
+                                             ->GetVoiceSearchProvider()
+                                             ->IsVoiceSearchEnabled()];
+  [self.consumer
       setMaximumMostVisitedSitesShown:[GoogleLandingMediator maxSitesShown]];
-  [_consumer setTabCount:self.webStateList->count()];
+  [self.consumer setTabCount:self.webStateList->count()];
   web::WebState* webState = _webStateList->GetActiveWebState();
   if (webState) {
     web::NavigationManager* nav = webState->GetNavigationManager();
-    [_consumer setCanGoForward:nav->CanGoForward()];
-    [_consumer setCanGoBack:nav->CanGoBack()];
+    [self.consumer setCanGoForward:nav->CanGoForward()];
+    [self.consumer setCanGoBack:nav->CanGoBack()];
   }
 
   // Set up template URL service to listen for default search engine changes.
@@ -202,7 +209,7 @@
   _templateURLService->Load();
   _doodleController.reset(ios::GetChromeBrowserProvider()->CreateLogoVendor(
       _browserState, self.dispatcher));
-  [_consumer setLogoVendor:_doodleController];
+  [self.consumer setLogoVendor:_doodleController];
   [self updateShowLogo];
 
   // Set up most visited sites.  This call may have the side effect of
@@ -218,24 +225,24 @@
   // Set up notifications;
   NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter];
   [defaultCenter
-      addObserver:_consumer
+      addObserver:self.consumer
          selector:@selector(locationBarBecomesFirstResponder)
              name:ios_internal::kLocationBarBecomesFirstResponderNotification
            object:nil];
   [defaultCenter
-      addObserver:_consumer
+      addObserver:self.consumer
          selector:@selector(locationBarResignsFirstResponder)
              name:ios_internal::kLocationBarResignsFirstResponderNotification
            object:nil];
 
   // Set up what's new.
-  _notification_promo.reset(
+  _notificationPromo.reset(
       new NotificationPromoWhatsNew(GetApplicationContext()->GetLocalState()));
-  _notification_promo->Init();
-  [_consumer setPromoText:[base::SysUTF8ToNSString(
-                              _notification_promo->promo_text()) copy]];
-  [_consumer setPromoIcon:_notification_promo->icon()];
-  [_consumer setPromoCanShow:_notification_promo->CanShow()];
+  _notificationPromo->Init();
+  [self.consumer setPromoText:[base::SysUTF8ToNSString(
+                                  _notificationPromo->promo_text()) copy]];
+  [self.consumer setPromoIcon:_notificationPromo->icon()];
+  [self.consumer setPromoCanShow:_notificationPromo->CanShow()];
 }
 
 - (void)updateShowLogo {
@@ -260,7 +267,7 @@
   if (_mostVisitedData.size() > 0) {
     // If some content is already displayed to the user, do not update it to
     // prevent updating the all the tiles without any action from the user.
-    self.freshMostVisitedData = data;
+    _freshMostVisitedData = data;
     return;
   }
 
@@ -269,12 +276,7 @@
 
   if (data.size() && !_recordedPageImpression) {
     _recordedPageImpression = YES;
-    int index = 0;
-    for (const ntp_tiles::NTPTile& ntpTile : data) {
-      ntp_tiles::metrics::RecordTileImpression(
-          index++, ntpTile.source, ntp_tiles::UNKNOWN_TILE_TYPE, ntpTile.url,
-          GetApplicationContext()->GetRapporServiceImpl());
-    }
+    _mostVisitedDataForLogging = data;
     ntp_tiles::metrics::RecordPageImpression(data.size());
   }
 }
@@ -300,6 +302,8 @@
 
   void (^faviconBlock)(const favicon_base::LargeIconResult&) = ^(
       const favicon_base::LargeIconResult& result) {
+    ntp_tiles::TileVisualType tileType;
+
     if (result.bitmap.is_valid()) {
       scoped_refptr<base::RefCountedMemory> data =
           result.bitmap.bitmap_data.get();
@@ -307,6 +311,7 @@
           imageWithData:[NSData dataWithBytes:data->front() length:data->size()]
                   scale:[UIScreen mainScreen].scale];
       imageCallback(favicon);
+      tileType = ntp_tiles::TileVisualType::ICON_REAL;
     } else if (result.fallback_icon_style) {
       UIColor* backgroundColor = skia::UIColorFromSkColor(
           result.fallback_icon_style->background_color);
@@ -315,12 +320,16 @@
       BOOL isDefaultColor =
           result.fallback_icon_style->is_default_background_color;
       fallbackCallback(textColor, backgroundColor, isDefaultColor);
+      fallbackCallback(backgroundColor, textColor, isDefaultColor);
+      tileType = isDefaultColor ? ntp_tiles::TileVisualType::ICON_DEFAULT
+                                : ntp_tiles::TileVisualType::ICON_COLOR;
     }
 
     base::scoped_nsobject<GoogleLandingMediator> strongSelf([weakSelf retain]);
-    if (strongSelf &&
-        (result.bitmap.is_valid() || result.fallback_icon_style)) {
-      [strongSelf largeIconCache]->SetCachedResult(URL, result);
+    if (strongSelf) {
+      if ((result.bitmap.is_valid() || result.fallback_icon_style))
+        [strongSelf largeIconCache]->SetCachedResult(URL, result);
+      [strongSelf faviconOfType:tileType fetchedForURL:URL];
     }
   };
 
@@ -411,28 +420,28 @@
 }
 
 - (void)promoViewed {
-  DCHECK(_notification_promo);
-  _notification_promo->HandleViewed();
-  [self.consumer setPromoCanShow:_notification_promo->CanShow()];
+  DCHECK(_notificationPromo);
+  _notificationPromo->HandleViewed();
+  [self.consumer setPromoCanShow:_notificationPromo->CanShow()];
 }
 
 - (void)promoTapped {
-  DCHECK(_notification_promo);
-  _notification_promo->HandleClosed();
-  [self.consumer setPromoCanShow:_notification_promo->CanShow()];
+  DCHECK(_notificationPromo);
+  _notificationPromo->HandleClosed();
+  [self.consumer setPromoCanShow:_notificationPromo->CanShow()];
 
-  if (_notification_promo->IsURLPromo()) {
-    [self.dispatcher webPageOrderedOpen:_notification_promo->url()
+  if (_notificationPromo->IsURLPromo()) {
+    [self.dispatcher webPageOrderedOpen:_notificationPromo->url()
                                referrer:web::Referrer()
                            inBackground:NO
                                appendTo:kCurrentTab];
     return;
   }
 
-  if (_notification_promo->IsChromeCommand()) {
+  if (_notificationPromo->IsChromeCommand()) {
     base::scoped_nsobject<GenericChromeCommand> command(
         [[GenericChromeCommand alloc]
-            initWithTag:_notification_promo->command_id()]);
+            initWithTag:_notificationPromo->command_id()]);
     [self.dispatcher chromeExecuteCommand:command];
     return;
   }
@@ -441,9 +450,38 @@
 
 #pragma mark - Private
 
+// If there is some fresh most visited tiles, they become the current tiles and
+// the consumer gets notified.
 - (void)useFreshData {
-  _mostVisitedData = self.freshMostVisitedData;
+  _mostVisitedData = _freshMostVisitedData;
   [self.consumer mostVisitedDataUpdated];
 }
 
+// If it is the first time we see the favicon corresponding to |URL|, we log the
+// |tileType| impression.
+- (void)faviconOfType:(ntp_tiles::TileVisualType)tileType
+        fetchedForURL:(const GURL&)URL {
+  for (size_t i = 0; i < _mostVisitedDataForLogging.size(); ++i) {
+    ntp_tiles::NTPTile& ntpTile = _mostVisitedDataForLogging[i];
+    if (ntpTile.url == URL) {
+      ntp_tiles::metrics::RecordTileImpression(
+          i, ntpTile.source, tileType, URL,
+          GetApplicationContext()->GetRapporServiceImpl());
+      // Reset the URL to be sure to log the impression only once.
+      ntpTile.url = GURL();
+      break;
+    }
+  }
+}
+
+#pragma mark - Properties
+
+- (id<GoogleLandingConsumer>)consumer {
+  return _consumer.get();
+}
+
+- (id<ChromeExecuteCommand, UrlLoader>)dispatcher {
+  return _dispatcher.get();
+}
+
 @end
diff --git a/ios/chrome/browser/ui/ntp/incognito_panel_controller.mm b/ios/chrome/browser/ui/ntp/incognito_panel_controller.mm
index 4c1a7e5..855f90c 100644
--- a/ios/chrome/browser/ui/ntp/incognito_panel_controller.mm
+++ b/ios/chrome/browser/ui/ntp/incognito_panel_controller.mm
@@ -116,8 +116,7 @@
     [learnMore setTranslatesAutoresizingMaskIntoConstraints:NO];
     [learnMore setTitle:l10n_util::GetNSString(IDS_NEW_TAB_OTR_LEARN_MORE_LINK)
                forState:UIControlStateNormal];
-    [learnMore setTitleColor:UIColorFromRGB(kLinkColor)
-                    forState:UIControlStateNormal];
+    [learnMore setCustomTitleColor:UIColorFromRGB(kLinkColor)];
     UIFont* buttonFont = [[MDCTypography fontLoader] boldFontOfSize:14];
     [[learnMore titleLabel] setFont:buttonFont];
     [learnMore addTarget:self
diff --git a/ios/chrome/browser/ui/payments/credit_card_edit_coordinator_unittest.mm b/ios/chrome/browser/ui/payments/credit_card_edit_coordinator_unittest.mm
index bab831b..282645f0 100644
--- a/ios/chrome/browser/ui/payments/credit_card_edit_coordinator_unittest.mm
+++ b/ios/chrome/browser/ui/payments/credit_card_edit_coordinator_unittest.mm
@@ -12,8 +12,8 @@
 #include "base/test/scoped_task_environment.h"
 #include "components/autofill/core/browser/credit_card.h"
 #include "components/autofill/core/browser/test_personal_data_manager.h"
-#include "ios/chrome/browser/payments/payment_request.h"
 #include "ios/chrome/browser/payments/payment_request_test_util.h"
+#include "ios/chrome/browser/payments/test_payment_request.h"
 #import "ios/chrome/browser/ui/autofill/autofill_ui_type.h"
 #import "ios/chrome/browser/ui/payments/payment_request_editor_field.h"
 #import "ios/chrome/test/scoped_key_window.h"
@@ -35,14 +35,11 @@
   MOCK_METHOD1(UpdateCreditCard, void(const autofill::CreditCard&));
 };
 
-class MockPaymentRequest : public PaymentRequest {
+class MockPaymentRequest : public TestPaymentRequest {
  public:
   MockPaymentRequest(web::PaymentRequest web_payment_request,
-                     autofill::PersonalDataManager* personal_data_manager,
-                     id<PaymentRequestUIDelegate> payment_request_ui_delegate)
-      : PaymentRequest(web_payment_request,
-                       personal_data_manager,
-                       payment_request_ui_delegate) {}
+                     autofill::PersonalDataManager* personal_data_manager)
+      : TestPaymentRequest(web_payment_request, personal_data_manager) {}
   MOCK_METHOD1(AddCreditCard,
                autofill::CreditCard*(const autofill::CreditCard&));
 };
@@ -111,7 +108,7 @@
   PaymentRequestCreditCardEditCoordinatorTest() {
     payment_request_ = base::MakeUnique<MockPaymentRequest>(
         payment_request_test_util::CreateTestWebPaymentRequest(),
-        &personal_data_manager_, nil);
+        &personal_data_manager_);
   }
 
   base::test::ScopedTaskEnvironment scoped_task_evironment_;
diff --git a/ios/chrome/browser/ui/payments/js_payment_request_manager.h b/ios/chrome/browser/ui/payments/js_payment_request_manager.h
index f1a573d3..81d319c 100644
--- a/ios/chrome/browser/ui/payments/js_payment_request_manager.h
+++ b/ios/chrome/browser/ui/payments/js_payment_request_manager.h
@@ -51,6 +51,14 @@
                             completionHandler:
                                 (ProceduralBlockWithBool)completionHandler;
 
+// Rejects the JavaScript promise returned by the call to canMakePayment on the
+// current PaymentRequest, with the supplied |errorMessage|. If
+// |completionHandler| is not nil, it will be invoked with YES after the
+// operation has completed successfully or with NO otherwise.
+- (void)rejectCanMakePaymentPromiseWithErrorMessage:(NSString*)errorMessage
+                                  completionHandler:(ProceduralBlockWithBool)
+                                                        completionHandler;
+
 // Resolves the promise returned by PaymentRequest.prototype.abort.
 - (void)resolveAbortPromiseWithCompletionHandler:
     (ProceduralBlockWithBool)completionHandler;
diff --git a/ios/chrome/browser/ui/payments/js_payment_request_manager.mm b/ios/chrome/browser/ui/payments/js_payment_request_manager.mm
index 882e260..3d4f1aec9 100644
--- a/ios/chrome/browser/ui/payments/js_payment_request_manager.mm
+++ b/ios/chrome/browser/ui/payments/js_payment_request_manager.mm
@@ -71,10 +71,20 @@
 - (void)resolveCanMakePaymentPromiseWithValue:(bool)value
                             completionHandler:
                                 (ProceduralBlockWithBool)completionHandler {
-  NSString* script = value ? @"__gCrWeb['paymentRequestManager']."
-                             @"resolveCanMakePaymentPromise(true)"
-                           : @"__gCrWeb['paymentRequestManager']."
-                             @"resolveCanMakePaymentPromise(false)";
+  NSString* script = [NSString
+      stringWithFormat:
+          @"__gCrWeb['paymentRequestManager'].resolveCanMakePaymentPromise(%@)",
+          value ? @"true" : @"false"];
+  [self executeScript:script completionHandler:completionHandler];
+}
+
+- (void)rejectCanMakePaymentPromiseWithErrorMessage:(NSString*)errorMessage
+                                  completionHandler:(ProceduralBlockWithBool)
+                                                        completionHandler {
+  NSString* script = [NSString
+      stringWithFormat:
+          @"__gCrWeb['paymentRequestManager'].rejectCanMakePaymentPromise(%@)",
+          JSONEscape(errorMessage)];
   [self executeScript:script completionHandler:completionHandler];
 }
 
diff --git a/ios/chrome/browser/ui/payments/payment_request_manager.mm b/ios/chrome/browser/ui/payments/payment_request_manager.mm
index 19dd775b..d5251d4f 100644
--- a/ios/chrome/browser/ui/payments/payment_request_manager.mm
+++ b/ios/chrome/browser/ui/payments/payment_request_manager.mm
@@ -4,6 +4,8 @@
 
 #import "ios/chrome/browser/ui/payments/payment_request_manager.h"
 
+#include <string>
+
 #include "base/ios/block_types.h"
 #include "base/ios/ios_util.h"
 #import "base/mac/bind_objc_block.h"
@@ -20,6 +22,7 @@
 #include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/autofill/ios/browser/autofill_driver_ios.h"
 #include "components/payments/core/address_normalization_manager.h"
+#include "components/payments/core/can_make_payment_query.h"
 #include "components/payments/core/payment_address.h"
 #include "components/payments/core/payment_request_base_delegate.h"
 #include "components/payments/core/payment_request_data_util.h"
@@ -27,6 +30,7 @@
 #include "ios/chrome/browser/autofill/personal_data_manager_factory.h"
 #include "ios/chrome/browser/autofill/validation_rules_storage_factory.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
+#include "ios/chrome/browser/payments/ios_can_make_payment_query_factory.h"
 #include "ios/chrome/browser/payments/payment_request.h"
 #include "ios/chrome/browser/procedural_block_types.h"
 #import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h"
@@ -404,7 +408,7 @@
   }
 
   _paymentRequest = base::MakeUnique<PaymentRequest>(
-      webPaymentRequest, _personalDataManager, self);
+      webPaymentRequest, _browserState, _personalDataManager, self);
 
   return YES;
 }
@@ -475,15 +479,39 @@
 
 - (BOOL)handleCanMakePayment:(const base::DictionaryValue&)message {
   if (![self createPaymentRequestFromMessage:message]) {
-    return NO;
+    // TODO(crbug.com/602666): Reject the promise with an error of
+    // "InvalidStateError" type.
+    [_paymentRequestJsManager
+        rejectCanMakePaymentPromiseWithErrorMessage:@"Invalid state error"
+                                  completionHandler:nil];
+    return YES;
   }
 
-  // TODO(crbug.com/602666): reject the promise if quota (TBD) was exceeded.
+  if (_paymentRequest->IsIncognito()) {
+    [_paymentRequestJsManager resolveCanMakePaymentPromiseWithValue:YES
+                                                  completionHandler:nil];
+    return YES;
+  }
 
-  [_paymentRequestJsManager
-      resolveCanMakePaymentPromiseWithValue:_paymentRequest->CanMakePayment()
-                          completionHandler:nil];
+  BOOL canMakePayment = _paymentRequest->CanMakePayment();
 
+  payments::CanMakePaymentQuery* canMakePaymentQuery =
+      IOSCanMakePaymentQueryFactory::GetInstance()->GetForBrowserState(
+          _browserState);
+  DCHECK(canMakePaymentQuery);
+  if (canMakePaymentQuery->CanQuery(
+          [self webState]->GetLastCommittedURL().GetOrigin(),
+          _paymentRequest->stringified_method_data())) {
+    [_paymentRequestJsManager
+        resolveCanMakePaymentPromiseWithValue:canMakePayment
+                            completionHandler:nil];
+    // TODO(crbug.com/602666): Warn on console if origin is localhost or file.
+  } else {
+    [_paymentRequestJsManager
+        rejectCanMakePaymentPromiseWithErrorMessage:
+            @"Not allowed to check whether can make payment"
+                                  completionHandler:nil];
+  }
   return YES;
 }
 
diff --git a/ios/chrome/browser/ui/qr_scanner/qr_scanner_view_controller_egtest.mm b/ios/chrome/browser/ui/qr_scanner/qr_scanner_view_controller_egtest.mm
index a1b4787..ef08816 100644
--- a/ios/chrome/browser/ui/qr_scanner/qr_scanner_view_controller_egtest.mm
+++ b/ios/chrome/browser/ui/qr_scanner/qr_scanner_view_controller_egtest.mm
@@ -12,6 +12,7 @@
 #include "components/version_info/version_info.h"
 #import "ios/chrome/app/main_controller.h"
 #include "ios/chrome/browser/chrome_switches.h"
+#include "ios/chrome/browser/experimental_flags.h"
 #import "ios/chrome/browser/ui/browser_view_controller.h"
 #import "ios/chrome/browser/ui/commands/generic_chrome_command.h"
 #include "ios/chrome/browser/ui/commands/ios_command_ids.h"
@@ -111,12 +112,31 @@
       grey_accessibilityTrait(UIAccessibilityTraitStaticText), nil);
 }
 
-// Opens the QR Scanner view using a command.
-// TODO(crbug.com/629776): Replace the command call with a UI action.
-void ShowQRScannerWithCommand() {
-  GenericChromeCommand* command =
-      [[GenericChromeCommand alloc] initWithTag:IDC_SHOW_QR_SCANNER];
-  chrome_test_util::RunCommandWithActiveViewController(command);
+// Opens the QR Scanner view.
+void ShowQRScanner() {
+  // TODO(crbug.com/738106): only show the QR Scanner via the Keyboard Accessory
+  // View.
+  if (experimental_flags::IsKeyboardAccessoryViewWithCameraSearchEnabled()) {
+    // Tap the omnibox to get the keyboard accessory view to show up.
+    id<GREYMatcher> locationbarButton = grey_allOf(
+        grey_accessibilityLabel(l10n_util::GetNSString(IDS_OMNIBOX_EMPTY_HINT)),
+        grey_minimumVisiblePercent(0.2), nil);
+    [[EarlGrey selectElementWithMatcher:locationbarButton]
+        assertWithMatcher:grey_text(@"Search or type URL")];
+    [[EarlGrey selectElementWithMatcher:locationbarButton]
+        performAction:grey_tap()];
+
+    // Tap the QR Code scanner button in the keyboard accessory view.
+    id<GREYMatcher> matcher =
+        grey_allOf(grey_accessibilityLabel(@"QR code Search"),
+                   grey_kindOfClass([UIButton class]), nil);
+
+    [[EarlGrey selectElementWithMatcher:matcher] performAction:grey_tap()];
+  } else {
+    GenericChromeCommand* command =
+        [[GenericChromeCommand alloc] initWithTag:IDC_SHOW_QR_SCANNER];
+    chrome_test_util::RunCommandWithActiveViewController(command);
+  }
 }
 
 // Taps the |button|.
@@ -251,7 +271,7 @@
   [self assertModalOfClass:[UIAlertController class] isNotPresentedBy:bvc];
 
   [self addCameraControllerInitializationExpectations:mock];
-  ShowQRScannerWithCommand();
+  ShowQRScanner();
   [self waitForModalOfClass:[QRScannerViewController class] toAppearAbove:bvc];
   [self assertQRScannerUIIsVisibleWithTorch:NO];
   [self assertModalOfClass:[UIAlertController class]
@@ -632,7 +652,7 @@
                 AVAuthorizationStatusDenied];
   [self swizzleCameraController:cameraControllerMock];
 
-  ShowQRScannerWithCommand();
+  ShowQRScanner();
   [self assertModalOfClass:[QRScannerViewController class]
           isNotPresentedBy:bvc];
   [self waitForModalOfClass:[UIAlertController class] toAppearAbove:bvc];
diff --git a/ios/chrome/browser/ui/toolbar/toolbar_egtest.mm b/ios/chrome/browser/ui/toolbar/toolbar_egtest.mm
index 96f6bd9..9322f86 100644
--- a/ios/chrome/browser/ui/toolbar/toolbar_egtest.mm
+++ b/ios/chrome/browser/ui/toolbar/toolbar_egtest.mm
@@ -471,4 +471,40 @@
 
   SelectNewTabPagePanel(NewTabPage::kMostVisitedPanel);
 }
+
+// Tests typing in the omnibox using the keyboard accessory view.
+- (void)testToolbarOmniboxKeyboardAccessoryView {
+  // Select the omnibox to get the keyboard up.
+  id<GREYMatcher> locationbarButton = grey_allOf(
+      grey_accessibilityLabel(l10n_util::GetNSString(IDS_OMNIBOX_EMPTY_HINT)),
+      grey_minimumVisiblePercent(0.2), nil);
+  [[EarlGrey selectElementWithMatcher:locationbarButton]
+      assertWithMatcher:grey_text(@"Search or type URL")];
+  [[EarlGrey selectElementWithMatcher:locationbarButton]
+      performAction:grey_tap()];
+
+  // Tap the "/" keyboard accessory button.
+  id<GREYMatcher> slashButtonMatcher = grey_allOf(
+      grey_accessibilityLabel(@"/"), grey_kindOfClass([UIButton class]), nil);
+
+  [[EarlGrey selectElementWithMatcher:slashButtonMatcher]
+      performAction:grey_tap()];
+
+  // Tap the ".com" keyboard accessory button.
+  id<GREYMatcher> dotComButtonMatcher =
+      grey_allOf(grey_accessibilityLabel(@".com"),
+                 grey_kindOfClass([UIButton class]), nil);
+
+  [[EarlGrey selectElementWithMatcher:dotComButtonMatcher]
+      performAction:grey_tap()];
+
+  // Verify that the omnibox contains "/.com"
+  [[EarlGrey
+      selectElementWithMatcher:grey_allOf(grey_accessibilityLabel(@"/.com"),
+                                          grey_kindOfClass(
+                                              [OmniboxPopupMaterialRow class]),
+                                          nil)]
+      assertWithMatcher:grey_sufficientlyVisible()];
+}
+
 @end
diff --git a/ios/chrome/browser/web/resources/payment_request.js b/ios/chrome/browser/web/resources/payment_request.js
index 0132b91..ed564ad2 100644
--- a/ios/chrome/browser/web/resources/payment_request.js
+++ b/ios/chrome/browser/web/resources/payment_request.js
@@ -304,7 +304,7 @@
   /**
    * Rejects the pending PaymentRequest.
    * @param {string} message An error message explaining why the Promise is
-   * being rejected.
+   *     being rejected.
    */
   __gCrWeb['paymentRequestManager'].rejectRequestPromise = function(message) {
     if (!__gCrWeb['paymentRequestManager'].requestPromiseResolver) {
diff --git a/ios/chrome/test/earl_grey/BUILD.gn b/ios/chrome/test/earl_grey/BUILD.gn
index 07a9fd3..d497f3cd 100644
--- a/ios/chrome/test/earl_grey/BUILD.gn
+++ b/ios/chrome/test/earl_grey/BUILD.gn
@@ -46,7 +46,6 @@
 chrome_ios_eg_test("ios_chrome_ui_egtests") {
   deps = [
     "//ios/chrome/app/safe_mode:eg_tests",
-    "//ios/chrome/browser/content_suggestions:eg_tests",
     "//ios/chrome/browser/ui:eg_tests",
     "//ios/chrome/browser/ui/activity_services:eg_tests",
     "//ios/chrome/browser/ui/alert_coordinator:eg_tests",
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index 61ee232..3e2f9597 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -4788,15 +4788,24 @@
     [self setDocumentURL:webViewURL];
     [self webPageChanged];
 
-    web::NavigationContextImpl* context =
+    web::NavigationContextImpl* existingContext =
         [self contextForPendingNavigationWithURL:webViewURL];
-    // Same document navigation does not contain response headers.
-    net::HttpResponseHeaders* headers =
-        isSameDocumentNavigation ? nullptr
-                                 : _webStateImpl->GetHttpResponseHeaders();
-    context->SetResponseHeaders(headers);
-    context->SetIsSameDocument(isSameDocumentNavigation);
-    _webStateImpl->OnNavigationFinished(context);
+    if (!existingContext && isSameDocumentNavigation) {
+      // This is a renderer-initiated same-document navigation, which needs to
+      // be registered.
+      std::unique_ptr<web::NavigationContextImpl> newContext =
+          [self registerLoadRequestForURL:webViewURL];
+      newContext->SetIsSameDocument(true);
+      _webStateImpl->OnNavigationFinished(newContext.get());
+    } else {
+      // Same document navigation does not contain response headers.
+      net::HttpResponseHeaders* headers =
+          isSameDocumentNavigation ? nullptr
+                                   : _webStateImpl->GetHttpResponseHeaders();
+      existingContext->SetResponseHeaders(headers);
+      existingContext->SetIsSameDocument(isSameDocumentNavigation);
+      _webStateImpl->OnNavigationFinished(existingContext);
+    }
   }
 
   [self updateSSLStatusForCurrentNavigationItem];
diff --git a/ipc/BUILD.gn b/ipc/BUILD.gn
index a2da06e2..c776d582 100644
--- a/ipc/BUILD.gn
+++ b/ipc/BUILD.gn
@@ -104,6 +104,15 @@
     ]
   }
 
+  if (is_fuchsia) {
+    sources += [
+      "handle_attachment_fuchsia.cc",
+      "handle_attachment_fuchsia.h",
+      "handle_fuchsia.cc",
+      "handle_fuchsia.h",
+    ]
+  }
+
   defines = [ "IPC_IMPLEMENTATION" ]
 
   public_deps = [
diff --git a/ipc/handle_attachment_fuchsia.cc b/ipc/handle_attachment_fuchsia.cc
new file mode 100644
index 0000000..2778002
--- /dev/null
+++ b/ipc/handle_attachment_fuchsia.cc
@@ -0,0 +1,43 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ipc/handle_attachment_fuchsia.h"
+
+#include <magenta/syscalls.h>
+#include <magenta/types.h>
+
+namespace IPC {
+namespace internal {
+
+HandleAttachmentFuchsia::HandleAttachmentFuchsia(
+    const mx_handle_t& handle,
+    HandleFuchsia::Permissions permissions)
+    : handle_(MX_HANDLE_INVALID),
+      permissions_(HandleFuchsia::INVALID),
+      owns_handle_(true) {
+  mx_handle_t duplicated_handle;
+  if (mx_handle_duplicate(handle, MX_RIGHT_SAME_RIGHTS, &duplicated_handle) ==
+      MX_OK) {
+    handle_ = duplicated_handle;
+    permissions_ = permissions;
+  }
+}
+
+HandleAttachmentFuchsia::HandleAttachmentFuchsia(const mx_handle_t& handle,
+                                                 FromWire from_wire)
+    : handle_(handle),
+      permissions_(HandleFuchsia::INVALID),
+      owns_handle_(true) {}
+
+HandleAttachmentFuchsia::~HandleAttachmentFuchsia() {
+  if (handle_ != MX_HANDLE_INVALID && owns_handle_)
+    mx_handle_close(handle_);
+}
+
+MessageAttachment::Type HandleAttachmentFuchsia::GetType() const {
+  return Type::FUCHSIA_HANDLE;
+}
+
+}  // namespace internal
+}  // namespace IPC
diff --git a/ipc/handle_attachment_fuchsia.h b/ipc/handle_attachment_fuchsia.h
new file mode 100644
index 0000000..a01c802
--- /dev/null
+++ b/ipc/handle_attachment_fuchsia.h
@@ -0,0 +1,59 @@
+// 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 IPC_HANDLE_ATTACHMENT_FUCHSIA_H_
+#define IPC_HANDLE_ATTACHMENT_FUCHSIA_H_
+
+#include <stdint.h>
+
+#include "base/process/process_handle.h"
+#include "ipc/handle_fuchsia.h"
+#include "ipc/ipc_export.h"
+#include "ipc/ipc_message_attachment.h"
+
+namespace IPC {
+namespace internal {
+
+// This class represents a Fuchsia mx_handle_t attached to a Chrome IPC message.
+class IPC_EXPORT HandleAttachmentFuchsia : public MessageAttachment {
+ public:
+  // This constructor makes a copy of |handle| and takes ownership of the
+  // result. Should only be called by the sender of a Chrome IPC message.
+  HandleAttachmentFuchsia(const mx_handle_t& handle,
+                          HandleFuchsia::Permissions permissions);
+
+  enum FromWire {
+    FROM_WIRE,
+  };
+  // This constructor takes ownership of |handle|. Should only be called by the
+  // receiver of a Chrome IPC message.
+  HandleAttachmentFuchsia(const mx_handle_t& handle, FromWire from_wire);
+
+  Type GetType() const override;
+
+  mx_handle_t get_handle() const { return handle_; }
+
+  // The caller of this method has taken ownership of |handle_|.
+  void reset_handle_ownership() {
+    owns_handle_ = false;
+    handle_ = MX_HANDLE_INVALID;
+  }
+
+ private:
+  ~HandleAttachmentFuchsia() override;
+  mx_handle_t handle_;
+  HandleFuchsia::Permissions permissions_;
+
+  // In the sender process, the attachment owns the mx_handle_t of a newly
+  // created message. The attachment broker will eventually take ownership, and
+  // set this member to |false|. In the destination process, the attachment owns
+  // the handle until a call to ParamTraits<HandleFuchsia>::Read() takes
+  // ownership.
+  bool owns_handle_;
+};
+
+}  // namespace internal
+}  // namespace IPC
+
+#endif  // IPC_HANDLE_ATTACHMENT_FUCHSIA_H_
diff --git a/ipc/handle_fuchsia.cc b/ipc/handle_fuchsia.cc
new file mode 100644
index 0000000..8b3cc51
--- /dev/null
+++ b/ipc/handle_fuchsia.cc
@@ -0,0 +1,57 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ipc/handle_fuchsia.h"
+
+#include <utility>
+
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "ipc/handle_attachment_fuchsia.h"
+#include "ipc/ipc_message.h"
+
+namespace IPC {
+
+HandleFuchsia::HandleFuchsia()
+    : handle_(MX_HANDLE_INVALID), permissions_(INVALID) {}
+
+HandleFuchsia::HandleFuchsia(const mx_handle_t& handle, Permissions permissions)
+    : handle_(handle), permissions_(permissions) {}
+
+// static
+void ParamTraits<HandleFuchsia>::Write(base::Pickle* m, const param_type& p) {
+  scoped_refptr<IPC::internal::HandleAttachmentFuchsia> attachment(
+      new IPC::internal::HandleAttachmentFuchsia(p.get_handle(),
+                                                 p.get_permissions()));
+  if (!m->WriteAttachment(std::move(attachment)))
+    NOTREACHED();
+}
+
+// static
+bool ParamTraits<HandleFuchsia>::Read(const base::Pickle* m,
+                                      base::PickleIterator* iter,
+                                      param_type* r) {
+  scoped_refptr<base::Pickle::Attachment> base_attachment;
+  if (!m->ReadAttachment(iter, &base_attachment))
+    return false;
+  MessageAttachment* attachment =
+      static_cast<MessageAttachment*>(base_attachment.get());
+  if (attachment->GetType() != MessageAttachment::Type::FUCHSIA_HANDLE)
+    return false;
+  IPC::internal::HandleAttachmentFuchsia* handle_attachment =
+      static_cast<IPC::internal::HandleAttachmentFuchsia*>(attachment);
+  r->set_handle(handle_attachment->get_handle());
+  handle_attachment->reset_handle_ownership();
+  return true;
+}
+
+// static
+void ParamTraits<HandleFuchsia>::Log(const param_type& p, std::string* l) {
+  l->append(base::StringPrintf("0x%x", p.get_handle()));
+  l->append(base::IntToString(p.get_permissions()));
+}
+
+}  // namespace IPC
diff --git a/ipc/handle_fuchsia.h b/ipc/handle_fuchsia.h
new file mode 100644
index 0000000..2ff6b539
--- /dev/null
+++ b/ipc/handle_fuchsia.h
@@ -0,0 +1,61 @@
+// 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 IPC_HANDLE_FUCHSIA_H_
+#define IPC_HANDLE_FUCHSIA_H_
+
+#include <magenta/types.h>
+
+#include <string>
+
+#include "ipc/ipc_export.h"
+#include "ipc/ipc_param_traits.h"
+
+namespace base {
+class Pickle;
+class PickleIterator;
+}  // namespace base
+
+namespace IPC {
+
+class IPC_EXPORT HandleFuchsia {
+ public:
+  enum Permissions {
+    // A placeholder value to be used by the receiving IPC channel, since the
+    // permissions information is only used by the broker process.
+    INVALID,
+    // The new mx_handle_t will have the same permissions as the old
+    // mx_handle_t.
+    DUPLICATE,
+    // The new mx_handle_t will have file read and write permissions.
+    FILE_READ_WRITE,
+    MAX_PERMISSIONS = FILE_READ_WRITE
+  };
+
+  // Default constructor makes an invalid mx_handle_t.
+  HandleFuchsia();
+  HandleFuchsia(const mx_handle_t& handle, Permissions permissions);
+
+  mx_handle_t get_handle() const { return handle_; }
+  void set_handle(mx_handle_t handle) { handle_ = handle; }
+  Permissions get_permissions() const { return permissions_; }
+
+ private:
+  mx_handle_t handle_;
+  Permissions permissions_;
+};
+
+template <>
+struct IPC_EXPORT ParamTraits<HandleFuchsia> {
+  typedef HandleFuchsia param_type;
+  static void Write(base::Pickle* m, const param_type& p);
+  static bool Read(const base::Pickle* m,
+                   base::PickleIterator* iter,
+                   param_type* p);
+  static void Log(const param_type& p, std::string* l);
+};
+
+}  // namespace IPC
+
+#endif  // IPC_HANDLE_FUCHSIA_H_
diff --git a/ipc/ipc.mojom b/ipc/ipc.mojom
index 0a4fcfa..f986c47 100644
--- a/ipc/ipc.mojom
+++ b/ipc/ipc.mojom
@@ -15,6 +15,7 @@
     PLATFORM_FILE,
     WIN_HANDLE,
     MACH_PORT,
+    FUCHSIA_HANDLE,
   };
 
   Type type;
diff --git a/ipc/ipc_message_attachment_set.cc b/ipc/ipc_message_attachment_set.cc
index b9a990da..58dd6ca 100644
--- a/ipc/ipc_message_attachment_set.cc
+++ b/ipc/ipc_message_attachment_set.cc
@@ -75,6 +75,7 @@
     case MessageAttachment::Type::MOJO_HANDLE:
     case MessageAttachment::Type::WIN_HANDLE:
     case MessageAttachment::Type::MACH_PORT:
+    case MessageAttachment::Type::FUCHSIA_HANDLE:
       attachments_.push_back(attachment);
       *index = attachments_.size() - 1;
       return true;
diff --git a/ipc/ipc_message_utils.cc b/ipc/ipc_message_utils.cc
index 8179cd4..1a7966e8 100644
--- a/ipc/ipc_message_utils.cc
+++ b/ipc/ipc_message_utils.cc
@@ -38,6 +38,10 @@
 #include "ipc/ipc_platform_file.h"
 #endif
 
+#if defined(OS_FUCHSIA)
+#include "ipc/handle_fuchsia.h"
+#endif
+
 namespace IPC {
 
 namespace {
@@ -753,6 +757,10 @@
   HandleWin handle_win;
   if (!ReadParam(m, iter, &handle_win))
     return false;
+#elif defined(OS_FUCHSIA)
+  HandleFuchsia handle_fuchsia;
+  if (!ReadParam(m, iter, &handle_fuchsia))
+    return false;
 #else
   scoped_refptr<base::Pickle::Attachment> attachment;
   if (!m->ReadAttachment(iter, &attachment))
@@ -776,6 +784,9 @@
 #elif defined(OS_WIN)
   *r = base::SharedMemoryHandle(handle_win.get_handle(),
                                 static_cast<size_t>(size), guid);
+#elif defined(OS_FUCHSIA)
+  *r = base::SharedMemoryHandle(handle_fuchsia.get_handle(),
+                                static_cast<size_t>(size), guid);
 #else
   *r = base::SharedMemoryHandle(
       base::FileDescriptor(
diff --git a/media/BUILD.gn b/media/BUILD.gn
index 6fbd5a7d..5436d6f3 100644
--- a/media/BUILD.gn
+++ b/media/BUILD.gn
@@ -91,120 +91,14 @@
   ]
 }
 
-# TODO(jrummell): This should be in media/filters/BUILD.gn (which doesn't
-# currently exist). http://crbug.com/613033
-source_set("filters_common") {
-  sources = [
-    "filters/file_data_source.h",
-  ]
-  if (media_use_ffmpeg) {
-    sources += [
-      "filters/blocking_url_protocol.h",
-      "filters/ffmpeg_glue.h",
-    ]
-  }
-}
-
 # TODO(jrummell): Each subdirectory should have it's own BUILD.gn, and then
 # this component can depend on them.  http://crbug.com/613033
 component("media") {
   sources = [
-    "cdm/aes_decryptor.cc",
-    "cdm/aes_decryptor.h",
-    "cdm/cdm_adapter.cc",
-    "cdm/cdm_adapter.h",
-    "cdm/cdm_allocator.cc",
-    "cdm/cdm_allocator.h",
-    "cdm/cdm_file_adapter.cc",
-    "cdm/cdm_file_adapter.h",
-    "cdm/cdm_file_io.cc",
-    "cdm/cdm_file_io.h",
-    "cdm/cdm_helpers.cc",
-    "cdm/cdm_helpers.h",
-    "cdm/cdm_wrapper.h",
-    "cdm/default_cdm_factory.cc",
-    "cdm/default_cdm_factory.h",
-    "cdm/json_web_key.cc",
-    "cdm/json_web_key.h",
-    "cdm/player_tracker_impl.cc",
-    "cdm/player_tracker_impl.h",
-    "cdm/supported_cdm_versions.cc",
-    "cdm/supported_cdm_versions.h",
     "device_monitors/device_monitor_mac.h",
     "device_monitors/device_monitor_mac.mm",
     "device_monitors/system_message_window_win.cc",
     "device_monitors/system_message_window_win.h",
-    "filters/audio_clock.cc",
-    "filters/audio_clock.h",
-    "filters/audio_renderer_algorithm.cc",
-    "filters/audio_renderer_algorithm.h",
-    "filters/audio_timestamp_validator.cc",
-    "filters/audio_timestamp_validator.h",
-    "filters/chunk_demuxer.cc",
-    "filters/chunk_demuxer.h",
-    "filters/context_3d.h",
-    "filters/decoder_selector.cc",
-    "filters/decoder_selector.h",
-    "filters/decoder_stream.cc",
-    "filters/decoder_stream.h",
-    "filters/decoder_stream_traits.cc",
-    "filters/decoder_stream_traits.h",
-    "filters/decrypting_audio_decoder.cc",
-    "filters/decrypting_audio_decoder.h",
-    "filters/decrypting_demuxer_stream.cc",
-    "filters/decrypting_demuxer_stream.h",
-    "filters/decrypting_video_decoder.cc",
-    "filters/decrypting_video_decoder.h",
-    "filters/file_data_source.cc",
-    "filters/frame_processor.cc",
-    "filters/frame_processor.h",
-    "filters/gpu_video_decoder.cc",
-    "filters/gpu_video_decoder.h",
-    "filters/h264_bit_reader.cc",
-    "filters/h264_bit_reader.h",
-    "filters/h264_parser.cc",
-    "filters/h264_parser.h",
-    "filters/ivf_parser.cc",
-    "filters/ivf_parser.h",
-    "filters/jpeg_parser.cc",
-    "filters/jpeg_parser.h",
-    "filters/memory_data_source.cc",
-    "filters/memory_data_source.h",
-    "filters/opus_constants.cc",
-    "filters/opus_constants.h",
-    "filters/pipeline_controller.cc",
-    "filters/pipeline_controller.h",
-    "filters/source_buffer_range.cc",
-    "filters/source_buffer_range.h",
-    "filters/source_buffer_state.cc",
-    "filters/source_buffer_state.h",
-    "filters/source_buffer_stream.cc",
-    "filters/source_buffer_stream.h",
-    "filters/stream_parser_factory.cc",
-    "filters/stream_parser_factory.h",
-    "filters/video_cadence_estimator.cc",
-    "filters/video_cadence_estimator.h",
-    "filters/video_renderer_algorithm.cc",
-    "filters/video_renderer_algorithm.h",
-    "filters/vp8_bool_decoder.cc",
-    "filters/vp8_bool_decoder.h",
-    "filters/vp8_parser.cc",
-    "filters/vp8_parser.h",
-    "filters/vp9_bool_decoder.cc",
-    "filters/vp9_bool_decoder.h",
-    "filters/vp9_compressed_header_parser.cc",
-    "filters/vp9_compressed_header_parser.h",
-    "filters/vp9_parser.cc",
-    "filters/vp9_parser.h",
-    "filters/vp9_raw_bits_reader.cc",
-    "filters/vp9_raw_bits_reader.h",
-    "filters/vp9_uncompressed_header_parser.cc",
-    "filters/vp9_uncompressed_header_parser.h",
-    "filters/webvtt_util.h",
-    "filters/wsola_internals.cc",
-    "filters/wsola_internals.h",
-    "muxers/webm_muxer.cc",
-    "muxers/webm_muxer.h",
     "renderers/audio_renderer_impl.cc",
     "renderers/audio_renderer_impl.h",
     "renderers/default_renderer_factory.cc",
@@ -218,22 +112,6 @@
     "renderers/video_overlay_factory.h",
     "renderers/video_renderer_impl.cc",
     "renderers/video_renderer_impl.h",
-    "video/fake_video_encode_accelerator.cc",
-    "video/fake_video_encode_accelerator.h",
-    "video/gpu_memory_buffer_video_frame_pool.cc",
-    "video/gpu_memory_buffer_video_frame_pool.h",
-    "video/h264_poc.cc",
-    "video/h264_poc.h",
-    "video/half_float_maker.cc",
-    "video/half_float_maker.h",
-    "video/jpeg_decode_accelerator.cc",
-    "video/jpeg_decode_accelerator.h",
-    "video/picture.cc",
-    "video/picture.h",
-    "video/video_decode_accelerator.cc",
-    "video/video_decode_accelerator.h",
-    "video/video_encode_accelerator.cc",
-    "video/video_encode_accelerator.h",
   ]
 
   configs += [
@@ -257,12 +135,9 @@
     "//base:i18n",
     "//base/third_party/dynamic_annotations",
     "//cc/paint",
-    "//crypto",
     "//crypto:platform",
     "//gpu/command_buffer/client:gles2_interface",
     "//gpu/command_buffer/common",
-    "//skia",
-    "//third_party/libwebm",
     "//third_party/libyuv",
     "//ui/events:events_base",
     "//ui/gfx",
@@ -273,96 +148,19 @@
 
   public_configs = [ "//third_party/libwebm:libwebm_config" ]
   public_deps = [
-    ":filters_common",
     ":media_features",
     ":shared_memory_support",
-    "//media/audio",
+    "//media/filters",
     "//media/formats",
     "//ui/gfx:color_space",
   ]
 
   include_dirs = [ "." ]
-  if (media_use_ffmpeg) {
-    public_deps += [ "//media/ffmpeg" ]
-    deps += [
-      "//third_party/ffmpeg",
-      "//third_party/ffmpeg:ffmpeg_features",
-      "//third_party/opus",
-    ]
-    sources += [
-      "filters/audio_file_reader.cc",
-      "filters/audio_file_reader.h",
-      "filters/blocking_url_protocol.cc",
-      "filters/ffmpeg_audio_decoder.cc",
-      "filters/ffmpeg_audio_decoder.h",
-      "filters/ffmpeg_bitstream_converter.h",
-      "filters/ffmpeg_demuxer.cc",
-      "filters/ffmpeg_demuxer.h",
-      "filters/ffmpeg_glue.cc",
-      "filters/in_memory_url_protocol.cc",
-      "filters/in_memory_url_protocol.h",
-    ]
-    if (!disable_ffmpeg_video_decoders) {
-      sources += [
-        "filters/ffmpeg_video_decoder.cc",
-        "filters/ffmpeg_video_decoder.h",
-      ]
-    }
-    if (proprietary_codecs) {
-      sources += [
-        "filters/ffmpeg_aac_bitstream_converter.cc",
-        "filters/ffmpeg_aac_bitstream_converter.h",
-        "filters/ffmpeg_h264_to_annex_b_bitstream_converter.cc",
-        "filters/ffmpeg_h264_to_annex_b_bitstream_converter.h",
-      ]
-    }
-  }
-
-  if (proprietary_codecs && enable_hevc_demuxing) {
-    sources += [
-      "filters/h265_parser.cc",
-      "filters/h265_parser.h",
-    ]
-    if (media_use_ffmpeg) {
-      sources += [
-        "filters/ffmpeg_h265_to_annex_b_bitstream_converter.cc",
-        "filters/ffmpeg_h265_to_annex_b_bitstream_converter.h",
-      ]
-    }
-  }
 
   if (current_cpu == "arm" && arm_use_neon) {
     defines += [ "USE_NEON" ]
   }
 
-  if (media_use_libvpx) {
-    sources += [
-      "filters/vpx_video_decoder.cc",
-      "filters/vpx_video_decoder.h",
-    ]
-    deps += [ "//third_party/libvpx" ]
-  }
-
-  if (is_android) {
-    sources -= [
-      "filters/decrypting_audio_decoder.cc",
-      "filters/decrypting_audio_decoder.h",
-      "filters/decrypting_video_decoder.cc",
-      "filters/decrypting_video_decoder.h",
-    ]
-    sources += [
-      "filters/android/media_codec_audio_decoder.cc",
-      "filters/android/media_codec_audio_decoder.h",
-    ]
-  }
-
-  if (current_cpu != "arm" && is_chromeos) {
-    sources += [
-      "filters/h264_bitstream_buffer.cc",
-      "filters/h264_bitstream_buffer.h",
-    ]
-  }
-
   if (is_mac) {
     public_deps += [ "//media/base/mac" ]
 
@@ -378,27 +176,6 @@
     deps += [ "//media/base/win" ]
   }
 
-  if (proprietary_codecs) {
-    sources += [
-      "cdm/cenc_utils.cc",
-      "cdm/cenc_utils.h",
-      "filters/h264_to_annex_b_bitstream_converter.cc",
-      "filters/h264_to_annex_b_bitstream_converter.h",
-    ]
-  }
-
-  if (use_low_memory_buffer) {
-    sources += [
-      "filters/source_buffer_platform.h",
-      "filters/source_buffer_platform_lowmem.cc",
-    ]
-  } else {
-    sources += [
-      "filters/source_buffer_platform.cc",
-      "filters/source_buffer_platform.h",
-    ]
-  }
-
   if (use_udev) {
     deps += [ "//device/udev_linux" ]
     sources += [
@@ -501,6 +278,21 @@
     "filters/vp8_parser_unittest.cc",
     "filters/vp9_parser_unittest.cc",
     "filters/vp9_raw_bits_reader_unittest.cc",
+    "formats/ac3/ac3_util_unittest.cc",
+    "formats/common/offset_byte_queue_unittest.cc",
+    "formats/webm/cluster_builder.cc",
+    "formats/webm/cluster_builder.h",
+    "formats/webm/opus_packet_builder.cc",
+    "formats/webm/opus_packet_builder.h",
+    "formats/webm/tracks_builder.cc",
+    "formats/webm/tracks_builder.h",
+    "formats/webm/webm_cluster_parser_unittest.cc",
+    "formats/webm/webm_content_encodings_client_unittest.cc",
+    "formats/webm/webm_crypto_helpers_unittest.cc",
+    "formats/webm/webm_parser_unittest.cc",
+    "formats/webm/webm_stream_parser_unittest.cc",
+    "formats/webm/webm_tracks_parser_unittest.cc",
+    "formats/webm/webm_webvtt_parser_unittest.cc",
     "muxers/webm_muxer_unittest.cc",
     "renderers/audio_renderer_impl_unittest.cc",
     "renderers/renderer_impl_unittest.cc",
@@ -530,7 +322,6 @@
     "//gpu/command_buffer/common",
     "//media/audio:test_support",
     "//media/base:test_support",
-    "//media/formats:unit_tests",
     "//ppapi/features",
     "//skia",  # Direct dependency required to inherit config.
     "//testing/gmock",
@@ -577,6 +368,15 @@
       "//third_party/opus",
     ]
 
+    # Even if FFmpeg is enabled on Android we don't want these.
+    # TODO(watk): Refactor tests that could be made to run on Android.
+    if (!is_android) {
+      sources += [
+        "filters/audio_video_metadata_extractor_unittest.cc",
+        "filters/media_file_checker_unittest.cc",
+      ]
+    }
+
     if (!disable_ffmpeg_video_decoders) {
       # FFmpeg on Android does not include video decoders.
       sources += [ "filters/ffmpeg_video_decoder_unittest.cc" ]
@@ -592,6 +392,33 @@
   }
 
   if (proprietary_codecs) {
+    sources += [
+      "cdm/cenc_utils_unittest.cc",
+      "filters/h264_to_annex_b_bitstream_converter_unittest.cc",
+      "formats/common/stream_parser_test_base.cc",
+      "formats/common/stream_parser_test_base.h",
+      "formats/mp4/aac_unittest.cc",
+      "formats/mp4/avc_unittest.cc",
+      "formats/mp4/box_reader_unittest.cc",
+      "formats/mp4/es_descriptor_unittest.cc",
+      "formats/mp4/mp4_stream_parser_unittest.cc",
+      "formats/mp4/sample_to_group_iterator_unittest.cc",
+      "formats/mp4/track_run_iterator_unittest.cc",
+      "formats/mpeg/adts_stream_parser_unittest.cc",
+      "formats/mpeg/mpeg1_audio_stream_parser_unittest.cc",
+    ]
+    if (enable_mse_mpeg2ts_stream_parser) {
+      sources += [
+        "formats/mp2t/es_adapter_video_unittest.cc",
+        "formats/mp2t/es_parser_adts_unittest.cc",
+        "formats/mp2t/es_parser_h264_unittest.cc",
+        "formats/mp2t/es_parser_mpeg1audio_unittest.cc",
+        "formats/mp2t/es_parser_test_base.cc",
+        "formats/mp2t/es_parser_test_base.h",
+        "formats/mp2t/mp2t_stream_parser_unittest.cc",
+        "formats/mp2t/timestamp_unroller_unittest.cc",
+      ]
+    }
     if (media_use_ffmpeg) {
       sources += [
         "filters/ffmpeg_aac_bitstream_converter_unittest.cc",
@@ -604,6 +431,9 @@
     if (enable_hls_sample_aes) {
       deps += [ "//third_party/boringssl" ]
     }
+    if (enable_dolby_vision_demuxing) {
+      sources += [ "formats/mp4/dolby_vision_unittest.cc" ]
+    }
   }
 
   if (is_mac || is_ios) {
diff --git a/media/README.md b/media/README.md
index b3814a9..f601eee 100644
--- a/media/README.md
+++ b/media/README.md
@@ -145,4 +145,8 @@
 media::VideoRenderer will talk to the media::AudioRenderer through a
 media::TimeSource for coordinating audio and video sync.
 
-With that we've covered the basic flow of a typical playback.
+With that we've covered the basic flow of a typical playback. When debugging
+issues, it's helpful to review the internal logs at chrome://media-internals.
+The internals page contains information about active media::WebMediaPlayerImpl,
+media::AudioInputController, media::AudioOutputController, and
+media::AudioOutputStream instances.
diff --git a/media/base/BUILD.gn b/media/base/BUILD.gn
index 9a8cd1f..58b9323 100644
--- a/media/base/BUILD.gn
+++ b/media/base/BUILD.gn
@@ -29,6 +29,7 @@
 } else {
   link_target_type = "static_library"
 }
+
 target(link_target_type, "base") {
   # This should only be depended on by "media" target. Other targets should
   # depend on "media" target directly.
@@ -298,19 +299,13 @@
   configs += [ ":base_config" ]
 
   if (media_use_ffmpeg) {
-    if (!is_android) {
-      sources += [
-        "audio_video_metadata_extractor.cc",
-        "audio_video_metadata_extractor.h",
-        "media_file_checker.cc",
-        "media_file_checker.h",
-      ]
-      deps += [ "//media:filters_common" ]
-    }
-
     deps += [ "//third_party/ffmpeg" ]
   }
 
+  if (media_use_libvpx) {
+    deps += [ "//third_party/libvpx" ]
+  }
+
   if (is_android) {
     public_deps += [
       "//media/base/android",
@@ -500,15 +495,6 @@
     "//third_party/libyuv",
   ]
 
-  # Even if FFmpeg is enabled on Android we don't want these.
-  # TODO(watk): Refactor tests that could be made to run on Android.
-  if (media_use_ffmpeg && !is_android) {
-    sources += [
-      "audio_video_metadata_extractor_unittest.cc",
-      "media_file_checker_unittest.cc",
-    ]
-  }
-
   if (is_android) {
     deps += [
       "//media/base/android:unit_tests",
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc
index d7cada6d..7031e095 100644
--- a/media/base/media_switches.cc
+++ b/media/base/media_switches.cc
@@ -243,6 +243,10 @@
 const base::Feature kVideoColorManagement{"video-color-management",
                                           base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Use SurfaceLayer instead of VideoLayer.
+const base::Feature kUseSurfaceLayerForVideo{"UseSurfaceLayerForVideo",
+                                             base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Inform video blitter of video color space.
 const base::Feature kVideoBlitColorAccuracy{"video-blit-color-accuracy",
                                             base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/media/base/media_switches.h b/media/base/media_switches.h
index 14e4ac3..8691c07 100644
--- a/media/base/media_switches.h
+++ b/media/base/media_switches.h
@@ -119,6 +119,7 @@
 MEDIA_EXPORT extern const base::Feature kUseNewMediaCache;
 MEDIA_EXPORT extern const base::Feature kVideoBlitColorAccuracy;
 MEDIA_EXPORT extern const base::Feature kVideoColorManagement;
+MEDIA_EXPORT extern const base::Feature kUseSurfaceLayerForVideo;
 MEDIA_EXPORT extern const base::Feature kMediaEngagement;
 
 #if defined(OS_ANDROID)
diff --git a/media/base/vector_math.cc b/media/base/vector_math.cc
index 57829053..bafb7f0 100644
--- a/media/base/vector_math.cc
+++ b/media/base/vector_math.cc
@@ -15,7 +15,9 @@
 #include <xmmintrin.h>
 // Don't use custom SSE versions where the auto-vectorized C version performs
 // better, which is anywhere clang is used.
-#if !defined(__clang__)
+// TODO(pcc): Linux currently uses ThinLTO which has broken auto-vectorization
+// in clang, so use our intrinsic version for now. http://crbug.com/738085
+#if !defined(__clang__) || defined(OS_LINUX)
 #define FMAC_FUNC FMAC_SSE
 #define FMUL_FUNC FMUL_SSE
 #else
diff --git a/media/blink/watch_time_reporter.cc b/media/blink/watch_time_reporter.cc
index b92f567..d85801f 100644
--- a/media/blink/watch_time_reporter.cc
+++ b/media/blink/watch_time_reporter.cc
@@ -16,7 +16,7 @@
     base::TimeDelta::FromSeconds(limits::kMinimumElapsedWatchTimeSecs);
 
 // The minimum width and height of videos to report watch time metrics for.
-constexpr gfx::Size kMinimumVideoSize = gfx::Size(200, 200);
+constexpr gfx::Size kMinimumVideoSize = gfx::Size(200, 140);
 
 static bool IsOnBatteryPower() {
   if (base::PowerMonitor* pm = base::PowerMonitor::Get())
diff --git a/media/filters/BUILD.gn b/media/filters/BUILD.gn
new file mode 100644
index 0000000..a89ce0f3
--- /dev/null
+++ b/media/filters/BUILD.gn
@@ -0,0 +1,278 @@
+# 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("//media/media_options.gni")
+
+source_set("filters") {
+  visibility = [ "//media/*" ]
+
+  sources = [
+    "audio_clock.cc",
+    "audio_clock.h",
+    "audio_renderer_algorithm.cc",
+    "audio_renderer_algorithm.h",
+    "audio_timestamp_validator.cc",
+    "audio_timestamp_validator.h",
+    "chunk_demuxer.cc",
+    "chunk_demuxer.h",
+    "context_3d.h",
+    "decoder_selector.cc",
+    "decoder_selector.h",
+    "decoder_stream.cc",
+    "decoder_stream.h",
+    "decoder_stream_traits.cc",
+    "decoder_stream_traits.h",
+    "decrypting_audio_decoder.cc",
+    "decrypting_audio_decoder.h",
+    "decrypting_demuxer_stream.cc",
+    "decrypting_demuxer_stream.h",
+    "decrypting_video_decoder.cc",
+    "decrypting_video_decoder.h",
+    "file_data_source.cc",
+    "file_data_source.h",
+    "frame_processor.cc",
+    "frame_processor.h",
+    "gpu_video_decoder.cc",
+    "gpu_video_decoder.h",
+    "h264_bit_reader.cc",
+    "h264_bit_reader.h",
+    "h264_parser.cc",
+    "h264_parser.h",
+    "ivf_parser.cc",
+    "ivf_parser.h",
+    "jpeg_parser.cc",
+    "jpeg_parser.h",
+    "memory_data_source.cc",
+    "memory_data_source.h",
+    "opus_constants.cc",
+    "opus_constants.h",
+    "pipeline_controller.cc",
+    "pipeline_controller.h",
+    "source_buffer_range.cc",
+    "source_buffer_range.h",
+    "source_buffer_state.cc",
+    "source_buffer_state.h",
+    "source_buffer_stream.cc",
+    "source_buffer_stream.h",
+    "stream_parser_factory.cc",
+    "stream_parser_factory.h",
+    "video_cadence_estimator.cc",
+    "video_cadence_estimator.h",
+    "video_renderer_algorithm.cc",
+    "video_renderer_algorithm.h",
+    "vp8_bool_decoder.cc",
+    "vp8_bool_decoder.h",
+    "vp8_parser.cc",
+    "vp8_parser.h",
+    "vp9_bool_decoder.cc",
+    "vp9_bool_decoder.h",
+    "vp9_compressed_header_parser.cc",
+    "vp9_compressed_header_parser.h",
+    "vp9_parser.cc",
+    "vp9_parser.h",
+    "vp9_raw_bits_reader.cc",
+    "vp9_raw_bits_reader.h",
+    "vp9_uncompressed_header_parser.cc",
+    "vp9_uncompressed_header_parser.h",
+    "webvtt_util.h",
+    "wsola_internals.cc",
+    "wsola_internals.h",
+  ]
+
+  # TODO(wolenetz): Fix size_t to int truncation in win64.
+  # See http://crbug.com/171009
+  configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
+
+  # TODO(a.suchit): Needs to create separate BUILD.gn file for muxers.
+  sources += [
+    "//media/muxers/webm_muxer.cc",
+    "//media/muxers/webm_muxer.h",
+  ]
+
+  # TODO(a.suchit): Needs to create separate BUILD.gn file for cdm.
+  sources += [
+    "//media/cdm/aes_decryptor.cc",
+    "//media/cdm/aes_decryptor.h",
+    "//media/cdm/cdm_adapter.cc",
+    "//media/cdm/cdm_adapter.h",
+    "//media/cdm/cdm_allocator.cc",
+    "//media/cdm/cdm_allocator.h",
+    "//media/cdm/cdm_file_adapter.cc",
+    "//media/cdm/cdm_file_adapter.h",
+    "//media/cdm/cdm_file_io.cc",
+    "//media/cdm/cdm_file_io.h",
+    "//media/cdm/cdm_helpers.cc",
+    "//media/cdm/cdm_helpers.h",
+    "//media/cdm/cdm_wrapper.h",
+    "//media/cdm/default_cdm_factory.cc",
+    "//media/cdm/default_cdm_factory.h",
+    "//media/cdm/json_web_key.cc",
+    "//media/cdm/json_web_key.h",
+    "//media/cdm/player_tracker_impl.cc",
+    "//media/cdm/player_tracker_impl.h",
+    "//media/cdm/supported_cdm_versions.cc",
+    "//media/cdm/supported_cdm_versions.h",
+  ]
+
+  # TODO(a.suchit): Needs to create separate BUILD.gn file for video.
+  sources += [
+    "//media/video/fake_video_encode_accelerator.cc",
+    "//media/video/fake_video_encode_accelerator.h",
+    "//media/video/gpu_memory_buffer_video_frame_pool.cc",
+    "//media/video/gpu_memory_buffer_video_frame_pool.h",
+    "//media/video/h264_poc.cc",
+    "//media/video/h264_poc.h",
+    "//media/video/half_float_maker.cc",
+    "//media/video/half_float_maker.h",
+    "//media/video/jpeg_decode_accelerator.cc",
+    "//media/video/jpeg_decode_accelerator.h",
+    "//media/video/picture.cc",
+    "//media/video/picture.h",
+    "//media/video/video_decode_accelerator.cc",
+    "//media/video/video_decode_accelerator.h",
+    "//media/video/video_encode_accelerator.cc",
+    "//media/video/video_encode_accelerator.h",
+  ]
+
+  configs += [
+    "//media:media_config",
+    "//media:media_implementation",
+  ]
+  all_dependent_configs = [ "//media:media_dependent_config" ]
+
+  deps = [
+    "//media/formats",
+    "//skia",
+    "//third_party/libyuv",
+  ]
+
+  libs = []
+
+  # //media/muxers dependencies
+  deps += [ "//third_party/libwebm" ]
+
+  # //media/cdm dependencies
+  deps += [ "//crypto" ]
+
+  public_deps = [
+    "//media:media_features",
+    "//media/audio",
+  ]
+
+  if (proprietary_codecs) {
+    sources += [
+      "h264_to_annex_b_bitstream_converter.cc",
+      "h264_to_annex_b_bitstream_converter.h",
+    ]
+  }
+
+  # TODO(a.suchit): Needs to create separate BUILD.gn file for cdm.
+  if (proprietary_codecs) {
+    sources += [
+      "//media/cdm/cenc_utils.cc",
+      "//media/cdm/cenc_utils.h",
+    ]
+  }
+
+  if (media_use_ffmpeg) {
+    public_deps += [ "//media/ffmpeg" ]
+    deps += [
+      "//third_party/ffmpeg",
+      "//third_party/opus",
+    ]
+    sources += [
+      "audio_file_reader.cc",
+      "audio_file_reader.h",
+      "blocking_url_protocol.cc",
+      "blocking_url_protocol.h",
+      "ffmpeg_audio_decoder.cc",
+      "ffmpeg_audio_decoder.h",
+      "ffmpeg_bitstream_converter.h",
+      "ffmpeg_demuxer.cc",
+      "ffmpeg_demuxer.h",
+      "ffmpeg_glue.cc",
+      "ffmpeg_glue.h",
+      "in_memory_url_protocol.cc",
+      "in_memory_url_protocol.h",
+    ]
+    if (!is_android) {
+      sources += [
+        "audio_video_metadata_extractor.cc",
+        "audio_video_metadata_extractor.h",
+        "media_file_checker.cc",
+        "media_file_checker.h",
+      ]
+    }
+  }
+
+  if (media_use_libvpx) {
+    sources += [
+      "vpx_video_decoder.cc",
+      "vpx_video_decoder.h",
+    ]
+    deps += [ "//third_party/libvpx" ]
+  }
+
+  if (proprietary_codecs && media_use_ffmpeg) {
+    sources += [
+      "ffmpeg_aac_bitstream_converter.cc",
+      "ffmpeg_aac_bitstream_converter.h",
+      "ffmpeg_h264_to_annex_b_bitstream_converter.cc",
+      "ffmpeg_h264_to_annex_b_bitstream_converter.h",
+    ]
+  }
+
+  if (proprietary_codecs && enable_hevc_demuxing) {
+    sources += [
+      "h265_parser.cc",
+      "h265_parser.h",
+    ]
+  }
+
+  if (media_use_ffmpeg && !disable_ffmpeg_video_decoders) {
+    sources += [
+      "ffmpeg_video_decoder.cc",
+      "ffmpeg_video_decoder.h",
+    ]
+  }
+
+  if (proprietary_codecs && media_use_ffmpeg && enable_hevc_demuxing) {
+    sources += [
+      "ffmpeg_h265_to_annex_b_bitstream_converter.cc",
+      "ffmpeg_h265_to_annex_b_bitstream_converter.h",
+    ]
+  }
+
+  if (is_android) {
+    sources -= [
+      "decrypting_audio_decoder.cc",
+      "decrypting_audio_decoder.h",
+      "decrypting_video_decoder.cc",
+      "decrypting_video_decoder.h",
+    ]
+    sources += [
+      "android/media_codec_audio_decoder.cc",
+      "android/media_codec_audio_decoder.h",
+    ]
+  }
+
+  if (current_cpu != "arm" && is_chromeos) {
+    sources += [
+      "h264_bitstream_buffer.cc",
+      "h264_bitstream_buffer.h",
+    ]
+  }
+
+  if (use_low_memory_buffer) {
+    sources += [
+      "source_buffer_platform.h",
+      "source_buffer_platform_lowmem.cc",
+    ]
+  } else {
+    sources += [
+      "source_buffer_platform.cc",
+      "source_buffer_platform.h",
+    ]
+  }
+}
diff --git a/media/base/audio_video_metadata_extractor.cc b/media/filters/audio_video_metadata_extractor.cc
similarity index 82%
rename from media/base/audio_video_metadata_extractor.cc
rename to media/filters/audio_video_metadata_extractor.cc
index 9e493601a..f97cfe9 100644
--- a/media/base/audio_video_metadata_extractor.cc
+++ b/media/filters/audio_video_metadata_extractor.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "media/base/audio_video_metadata_extractor.h"
+#include "media/filters/audio_video_metadata_extractor.h"
 
 #include "base/bind.h"
 #include "base/strings/string_number_conversions.h"
@@ -21,7 +21,8 @@
 }
 
 // Returns true if the |tag| matches |expected_key|.
-bool ExtractString(AVDictionaryEntry* tag, const char* expected_key,
+bool ExtractString(AVDictionaryEntry* tag,
+                   const char* expected_key,
                    std::string* destination) {
   if (!base::LowerCaseEqualsASCII(std::string(tag->key), expected_key))
     return false;
@@ -33,7 +34,8 @@
 }
 
 // Returns true if the |tag| matches |expected_key|.
-bool ExtractInt(AVDictionaryEntry* tag, const char* expected_key,
+bool ExtractInt(AVDictionaryEntry* tag,
+                const char* expected_key,
                 int* destination) {
   if (!base::LowerCaseEqualsASCII(std::string(tag->key), expected_key))
     return false;
@@ -66,11 +68,9 @@
       height_(-1),
       disc_(-1),
       rotation_(-1),
-      track_(-1) {
-}
+      track_(-1) {}
 
-AudioVideoMetadataExtractor::~AudioVideoMetadataExtractor() {
-}
+AudioVideoMetadataExtractor::~AudioVideoMetadataExtractor() {}
 
 bool AudioVideoMetadataExtractor::Extract(DataSource* source,
                                           bool extract_attached_images) {
@@ -234,8 +234,8 @@
   return attached_images_bytes_;
 }
 
-void AudioVideoMetadataExtractor::ExtractDictionary(
-    AVDictionary* metadata, TagDictionary* raw_tags) {
+void AudioVideoMetadataExtractor::ExtractDictionary(AVDictionary* metadata,
+                                                    TagDictionary* raw_tags) {
   if (!metadata)
     return;
 
@@ -245,19 +245,32 @@
     if (raw_tags->find(tag->key) == raw_tags->end())
       (*raw_tags)[tag->key] = tag->value;
 
-    if (ExtractInt(tag, "rotate", &rotation_)) continue;
-    if (ExtractString(tag, "album", &album_)) continue;
-    if (ExtractString(tag, "artist", &artist_)) continue;
-    if (ExtractString(tag, "comment", &comment_)) continue;
-    if (ExtractString(tag, "copyright", &copyright_)) continue;
-    if (ExtractString(tag, "date", &date_)) continue;
-    if (ExtractInt(tag, "disc", &disc_)) continue;
-    if (ExtractString(tag, "encoder", &encoder_)) continue;
-    if (ExtractString(tag, "encoded_by", &encoded_by_)) continue;
-    if (ExtractString(tag, "genre", &genre_)) continue;
-    if (ExtractString(tag, "language", &language_)) continue;
-    if (ExtractString(tag, "title", &title_)) continue;
-    if (ExtractInt(tag, "track", &track_)) continue;
+    if (ExtractInt(tag, "rotate", &rotation_))
+      continue;
+    if (ExtractString(tag, "album", &album_))
+      continue;
+    if (ExtractString(tag, "artist", &artist_))
+      continue;
+    if (ExtractString(tag, "comment", &comment_))
+      continue;
+    if (ExtractString(tag, "copyright", &copyright_))
+      continue;
+    if (ExtractString(tag, "date", &date_))
+      continue;
+    if (ExtractInt(tag, "disc", &disc_))
+      continue;
+    if (ExtractString(tag, "encoder", &encoder_))
+      continue;
+    if (ExtractString(tag, "encoded_by", &encoded_by_))
+      continue;
+    if (ExtractString(tag, "genre", &genre_))
+      continue;
+    if (ExtractString(tag, "language", &language_))
+      continue;
+    if (ExtractString(tag, "title", &title_))
+      continue;
+    if (ExtractInt(tag, "track", &track_))
+      continue;
   }
 }
 
diff --git a/media/base/audio_video_metadata_extractor.h b/media/filters/audio_video_metadata_extractor.h
similarity index 100%
rename from media/base/audio_video_metadata_extractor.h
rename to media/filters/audio_video_metadata_extractor.h
diff --git a/media/base/audio_video_metadata_extractor_unittest.cc b/media/filters/audio_video_metadata_extractor_unittest.cc
similarity index 98%
rename from media/base/audio_video_metadata_extractor_unittest.cc
rename to media/filters/audio_video_metadata_extractor_unittest.cc
index 084e0ed..9d555d7 100644
--- a/media/base/audio_video_metadata_extractor_unittest.cc
+++ b/media/filters/audio_video_metadata_extractor_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "media/base/audio_video_metadata_extractor.h"
+#include "media/filters/audio_video_metadata_extractor.h"
 
 #include <memory>
 
diff --git a/media/filters/gpu_video_decoder.cc b/media/filters/gpu_video_decoder.cc
index 308ccb7..a218682 100644
--- a/media/filters/gpu_video_decoder.cc
+++ b/media/filters/gpu_video_decoder.cc
@@ -387,6 +387,7 @@
     for (uint32_t id : kv.second.client_texture_ids())
       factories_->DeleteTexture(id);
   }
+  factories_->ShallowFlushCHROMIUM();
 
   buffers->clear();
 }
@@ -719,6 +720,9 @@
   // because GpuVideoDecoder was destructed.
   for (uint32_t id : ids)
     factories->DeleteTexture(id);
+
+  // Flush the delete(s) to the server, to avoid crbug.com/737992 .
+  factories->ShallowFlushCHROMIUM();
 }
 
 void GpuVideoDecoder::ReusePictureBuffer(int64_t picture_buffer_id) {
diff --git a/media/base/media_file_checker.cc b/media/filters/media_file_checker.cc
similarity index 95%
rename from media/base/media_file_checker.cc
rename to media/filters/media_file_checker.cc
index e8ccc7f..14bbda0 100644
--- a/media/base/media_file_checker.cc
+++ b/media/filters/media_file_checker.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "media/base/media_file_checker.h"
+#include "media/filters/media_file_checker.h"
 
 #include <stddef.h>
 #include <stdint.h>
@@ -28,8 +28,7 @@
 
 MediaFileChecker::MediaFileChecker(base::File file) : file_(std::move(file)) {}
 
-MediaFileChecker::~MediaFileChecker() {
-}
+MediaFileChecker::~MediaFileChecker() {}
 
 bool MediaFileChecker::Start(base::TimeDelta check_time) {
   media::FileDataSource source(std::move(file_));
@@ -69,7 +68,8 @@
   std::unique_ptr<AVFrame, media::ScopedPtrAVFreeFrame> frame(av_frame_alloc());
   int result = 0;
 
-  const base::TimeTicks deadline = base::TimeTicks::Now() +
+  const base::TimeTicks deadline =
+      base::TimeTicks::Now() +
       std::min(check_time,
                base::TimeDelta::FromSeconds(kMaxCheckTimeInSeconds));
   do {
diff --git a/media/base/media_file_checker.h b/media/filters/media_file_checker.h
similarity index 100%
rename from media/base/media_file_checker.h
rename to media/filters/media_file_checker.h
diff --git a/media/base/media_file_checker_unittest.cc b/media/filters/media_file_checker_unittest.cc
similarity index 96%
rename from media/base/media_file_checker_unittest.cc
rename to media/filters/media_file_checker_unittest.cc
index 4832506..c04e780 100644
--- a/media/base/media_file_checker_unittest.cc
+++ b/media/filters/media_file_checker_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "media/base/media_file_checker.h"
+#include "media/filters/media_file_checker.h"
 
 #include <utility>
 
diff --git a/media/filters/vpx_video_decoder.cc b/media/filters/vpx_video_decoder.cc
index 31c039a..8968c2a 100644
--- a/media/filters/vpx_video_decoder.cc
+++ b/media/filters/vpx_video_decoder.cc
@@ -52,6 +52,8 @@
 
 namespace media {
 
+constexpr base::TimeDelta kStaleFrameLimit = base::TimeDelta::FromSeconds(10);
+
 // High resolution VP9 decodes can block the main task runner for too long,
 // preventing demuxing, audio decoding, and other control activities.  In those
 // cases share a thread per process for higher resolution decodes.
@@ -385,7 +387,7 @@
   --frame_buffer->ref_cnt;
 
   if (in_shutdown_) {
-    DCHECK(!frame_buffer->ref_cnt);
+    // If we're in shutdown we can be sure that libvpx has been destroyed.
     EraseUnusedResources();
     return;
   }
@@ -396,8 +398,6 @@
 
   base::EraseIf(
       frame_buffers_, [now](const std::unique_ptr<VP9FrameBuffer>& buf) {
-        constexpr base::TimeDelta kStaleFrameLimit =
-            base::TimeDelta::FromSeconds(10);
         return !buf->ref_cnt && now - buf->last_use_time > kStaleFrameLimit;
       });
 }
diff --git a/media/formats/BUILD.gn b/media/formats/BUILD.gn
index cbdc95d..ebc1b0bce 100644
--- a/media/formats/BUILD.gn
+++ b/media/formats/BUILD.gn
@@ -146,69 +146,3 @@
     ]
   }
 }
-
-source_set("unit_tests") {
-  testonly = true
-
-  visibility = [ "//media/*" ]
-
-  sources = [
-    "ac3/ac3_util_unittest.cc",
-    "common/offset_byte_queue_unittest.cc",
-    "webm/cluster_builder.cc",
-    "webm/cluster_builder.h",
-    "webm/opus_packet_builder.cc",
-    "webm/opus_packet_builder.h",
-    "webm/tracks_builder.cc",
-    "webm/tracks_builder.h",
-    "webm/webm_cluster_parser_unittest.cc",
-    "webm/webm_content_encodings_client_unittest.cc",
-    "webm/webm_crypto_helpers_unittest.cc",
-    "webm/webm_parser_unittest.cc",
-    "webm/webm_stream_parser_unittest.cc",
-    "webm/webm_tracks_parser_unittest.cc",
-    "webm/webm_webvtt_parser_unittest.cc",
-  ]
-
-  deps = [
-    "//skia",
-    "//testing/gmock",
-  ]
-
-  # TODO(wolenetz): Fix size_t to int truncation in win64.
-  # See http://crbug.com/171009
-  configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
-
-  if (proprietary_codecs) {
-    sources += [
-      "common/stream_parser_test_base.cc",
-      "common/stream_parser_test_base.h",
-      "mp4/aac_unittest.cc",
-      "mp4/avc_unittest.cc",
-      "mp4/box_reader_unittest.cc",
-      "mp4/es_descriptor_unittest.cc",
-      "mp4/mp4_stream_parser_unittest.cc",
-      "mp4/sample_to_group_iterator_unittest.cc",
-      "mp4/track_run_iterator_unittest.cc",
-      "mpeg/adts_stream_parser_unittest.cc",
-      "mpeg/mpeg1_audio_stream_parser_unittest.cc",
-    ]
-  }
-
-  if (proprietary_codecs && enable_mse_mpeg2ts_stream_parser) {
-    sources += [
-      "mp2t/es_adapter_video_unittest.cc",
-      "mp2t/es_parser_adts_unittest.cc",
-      "mp2t/es_parser_h264_unittest.cc",
-      "mp2t/es_parser_mpeg1audio_unittest.cc",
-      "mp2t/es_parser_test_base.cc",
-      "mp2t/es_parser_test_base.h",
-      "mp2t/mp2t_stream_parser_unittest.cc",
-      "mp2t/timestamp_unroller_unittest.cc",
-    ]
-  }
-
-  if (proprietary_codecs && enable_dolby_vision_demuxing) {
-    sources += [ "mp4/dolby_vision_unittest.cc" ]
-  }
-}
diff --git a/media/media_options.gni b/media/media_options.gni
index 23cfa2f..cf001b4e 100644
--- a/media/media_options.gni
+++ b/media/media_options.gni
@@ -79,7 +79,7 @@
 
   # Alsa should be used on non-Android, non-Mac POSIX systems.
   # Alsa should be used on desktop Chromecast and audio-only Chromecast builds.
-  if (is_posix && !is_android && !is_mac &&
+  if (is_posix && !is_android && !is_mac && !is_fuchsia &&
       (!is_chromecast || is_cast_desktop_build || is_cast_audio_only)) {
     use_alsa = true
 
diff --git a/media/renderers/gpu_video_accelerator_factories.h b/media/renderers/gpu_video_accelerator_factories.h
index ad27ada..b32d7ac 100644
--- a/media/renderers/gpu_video_accelerator_factories.h
+++ b/media/renderers/gpu_video_accelerator_factories.h
@@ -96,6 +96,7 @@
                               uint32_t texture_target) = 0;
   virtual void DeleteTexture(uint32_t texture_id) = 0;
   virtual gpu::SyncToken CreateSyncToken() = 0;
+  virtual void ShallowFlushCHROMIUM() = 0;
 
   virtual void WaitSyncToken(const gpu::SyncToken& sync_token) = 0;
 
diff --git a/media/renderers/mock_gpu_video_accelerator_factories.h b/media/renderers/mock_gpu_video_accelerator_factories.h
index ef4c799d..8efad627 100644
--- a/media/renderers/mock_gpu_video_accelerator_factories.h
+++ b/media/renderers/mock_gpu_video_accelerator_factories.h
@@ -48,6 +48,7 @@
   MOCK_METHOD1(DeleteTexture, void(uint32_t texture_id));
   MOCK_METHOD0(CreateSyncToken, gpu::SyncToken());
   MOCK_METHOD1(WaitSyncToken, void(const gpu::SyncToken& sync_token));
+  MOCK_METHOD0(ShallowFlushCHROMIUM, void());
   MOCK_METHOD0(GetTaskRunner, scoped_refptr<base::SingleThreadTaskRunner>());
   MOCK_METHOD0(GetVideoDecodeAcceleratorCapabilities,
                VideoDecodeAccelerator::Capabilities());
diff --git a/mojo/edk/embedder/platform_channel_utils_posix.cc b/mojo/edk/embedder/platform_channel_utils_posix.cc
index 689b6ee..e01b39f 100644
--- a/mojo/edk/embedder/platform_channel_utils_posix.cc
+++ b/mojo/edk/embedder/platform_channel_utils_posix.cc
@@ -99,7 +99,7 @@
 //    - Mac: 2.21 s, 2.91 s, 2.98 s, 3.08 s, 3.59 s, 4.74 s
 
 // Flags to use with calling |send()| or |sendmsg()| (see above).
-#if defined(OS_MACOSX)
+#if defined(OS_MACOSX) || defined(OS_FUCHSIA)
 const int kSendFlags = 0;
 #else
 const int kSendFlags = MSG_NOSIGNAL;
diff --git a/mojo/edk/embedder/platform_shared_buffer.cc b/mojo/edk/embedder/platform_shared_buffer.cc
index 0f8b8b0..d94affb 100644
--- a/mojo/edk/embedder/platform_shared_buffer.cc
+++ b/mojo/edk/embedder/platform_shared_buffer.cc
@@ -241,7 +241,7 @@
     ScopedPlatformHandle platform_handle) {
   DCHECK(!shared_memory_);
 
-#if defined(OS_WIN)
+#if defined(OS_WIN) || defined(OS_FUCHSIA)
   base::SharedMemoryHandle handle(platform_handle.release().handle, num_bytes_,
                                   guid);
 #elif defined(OS_MACOSX) && !defined(OS_IOS)
@@ -266,12 +266,12 @@
   return false;
 #else  // defined(OS_MACOSX)
 
-#if defined(OS_WIN)
+#if defined(OS_WIN) || defined(OS_FUCHSIA)
   base::SharedMemoryHandle handle(rw_platform_handle.release().handle,
                                   num_bytes_, guid);
   base::SharedMemoryHandle ro_handle(ro_platform_handle.release().handle,
                                      num_bytes_, guid);
-#else   // defined(OS_WIN)
+#else  // defined(OS_WIN) || defined(OS_FUCHSIA)
   base::SharedMemoryHandle handle(
       base::FileDescriptor(rw_platform_handle.release().handle, false),
       num_bytes_, guid);
diff --git a/mojo/public/c/system/platform_handle.h b/mojo/public/c/system/platform_handle.h
index 8ecff2b9..b58b538 100644
--- a/mojo/public/c/system/platform_handle.h
+++ b/mojo/public/c/system/platform_handle.h
@@ -30,6 +30,8 @@
 //   |MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT| - A Mach port. Only valid on OS X.
 //   |MOJO_PLATFORM_HANDLE_TYPE_WINDOWS_HANDLE| - A Windows HANDLE value. Only
 //       valid on Windows.
+//   |MOJO_PLATFORM_HANDLE_TYPE_FUCHSIA_HANDLE| - A Fuchsia mx_handle_t value.
+//       Only valid on Fuchsia.
 
 typedef uint32_t MojoPlatformHandleType;
 
@@ -38,11 +40,13 @@
 const MojoPlatformHandleType MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR = 1;
 const MojoPlatformHandleType MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT = 2;
 const MojoPlatformHandleType MOJO_PLATFORM_HANDLE_TYPE_WINDOWS_HANDLE = 3;
+const MojoPlatformHandleType MOJO_PLATFORM_HANDLE_TYPE_FUCHSIA_HANDLE = 4;
 #else
 #define MOJO_PLATFORM_HANDLE_TYPE_INVALID ((MojoPlatformHandleType)0)
 #define MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR ((MojoPlatformHandleType)1)
 #define MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT ((MojoPlatformHandleType)2)
 #define MOJO_PLATFORM_HANDLE_TYPE_WINDOWS_HANDLE ((MojoPlatformHandleType)3)
+#define MOJO_PLATFORM_HANDLE_TYPE_FUCHSIA_HANDLE ((MojoPlatformHandleType)4)
 #endif
 
 // |MojoPlatformHandle|: A handle to a native platform object.
diff --git a/mojo/public/cpp/bindings/BUILD.gn b/mojo/public/cpp/bindings/BUILD.gn
index 26fe476..ef91acc 100644
--- a/mojo/public/cpp/bindings/BUILD.gn
+++ b/mojo/public/cpp/bindings/BUILD.gn
@@ -56,6 +56,7 @@
     "lib/associated_group.cc",
     "lib/associated_group_controller.cc",
     "lib/associated_interface_ptr.cc",
+    "lib/associated_interface_ptr_state.cc",
     "lib/associated_interface_ptr_state.h",
     "lib/binding_state.cc",
     "lib/binding_state.h",
diff --git a/mojo/public/cpp/bindings/lib/array_serialization.h b/mojo/public/cpp/bindings/lib/array_serialization.h
index 044b9d0..9396237 100644
--- a/mojo/public/cpp/bindings/lib/array_serialization.h
+++ b/mojo/public/cpp/bindings/lib/array_serialization.h
@@ -505,7 +505,7 @@
   static size_t PrepareToSerialize(MaybeConstUserType& input,
                                    SerializationContext* context) {
     const bool is_null = CallIsNullIfExists<Traits>(input);
-    context->null_states.container().push_back(is_null);
+    context->PushNextNullState(is_null);
     if (is_null)
       return 0;
     ArrayIterator<Traits, MaybeConstUserType> iterator(input);
diff --git a/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.cc b/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.cc
new file mode 100644
index 0000000..a239f19
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.cc
@@ -0,0 +1,79 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h"
+
+namespace mojo {
+namespace internal {
+
+AssociatedInterfacePtrStateBase::AssociatedInterfacePtrStateBase() = default;
+
+AssociatedInterfacePtrStateBase::~AssociatedInterfacePtrStateBase() = default;
+
+void AssociatedInterfacePtrStateBase::QueryVersion(
+    const base::Callback<void(uint32_t)>& callback) {
+  // It is safe to capture |this| because the callback won't be run after this
+  // object goes away.
+  endpoint_client_->QueryVersion(
+      base::Bind(&AssociatedInterfacePtrStateBase::OnQueryVersion,
+                 base::Unretained(this), callback));
+}
+
+void AssociatedInterfacePtrStateBase::RequireVersion(uint32_t version) {
+  if (version <= version_)
+    return;
+
+  version_ = version;
+  endpoint_client_->RequireVersion(version);
+}
+
+void AssociatedInterfacePtrStateBase::OnQueryVersion(
+    const base::Callback<void(uint32_t)>& callback,
+    uint32_t version) {
+  version_ = version;
+  callback.Run(version);
+}
+
+void AssociatedInterfacePtrStateBase::FlushForTesting() {
+  endpoint_client_->FlushForTesting();
+}
+
+void AssociatedInterfacePtrStateBase::CloseWithReason(
+    uint32_t custom_reason,
+    const std::string& description) {
+  endpoint_client_->CloseWithReason(custom_reason, description);
+}
+
+void AssociatedInterfacePtrStateBase::Swap(
+    AssociatedInterfacePtrStateBase* other) {
+  using std::swap;
+  swap(other->endpoint_client_, endpoint_client_);
+  swap(other->version_, version_);
+}
+
+void AssociatedInterfacePtrStateBase::Bind(
+    ScopedInterfaceEndpointHandle handle,
+    uint32_t version,
+    std::unique_ptr<MessageReceiver> validator,
+    scoped_refptr<base::SequencedTaskRunner> runner) {
+  DCHECK(!endpoint_client_);
+  DCHECK_EQ(0u, version_);
+  DCHECK(handle.is_valid());
+
+  version_ = version;
+  // The version is only queried from the client so the value passed here
+  // will not be used.
+  endpoint_client_ = base::MakeUnique<InterfaceEndpointClient>(
+      std::move(handle), nullptr, std::move(validator), false,
+      std::move(runner), 0u);
+}
+
+ScopedInterfaceEndpointHandle AssociatedInterfacePtrStateBase::PassHandle() {
+  auto handle = endpoint_client_->PassHandle();
+  endpoint_client_.reset();
+  return handle;
+}
+
+}  // namespace internal
+}  // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h b/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h
index e726a699..3c2086b9 100644
--- a/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h
+++ b/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h
@@ -20,6 +20,7 @@
 #include "base/sequenced_task_runner.h"
 #include "mojo/public/cpp/bindings/associated_group.h"
 #include "mojo/public/cpp/bindings/associated_interface_ptr_info.h"
+#include "mojo/public/cpp/bindings/bindings_export.h"
 #include "mojo/public/cpp/bindings/connection_error_callback.h"
 #include "mojo/public/cpp/bindings/interface_endpoint_client.h"
 #include "mojo/public/cpp/bindings/interface_id.h"
@@ -29,77 +30,17 @@
 namespace mojo {
 namespace internal {
 
-template <typename Interface>
-class AssociatedInterfacePtrState {
+class MOJO_CPP_BINDINGS_EXPORT AssociatedInterfacePtrStateBase {
  public:
-  AssociatedInterfacePtrState() : version_(0u) {}
-
-  ~AssociatedInterfacePtrState() {
-    endpoint_client_.reset();
-    proxy_.reset();
-  }
-
-  Interface* instance() {
-    // This will be null if the object is not bound.
-    return proxy_.get();
-  }
+  AssociatedInterfacePtrStateBase();
+  ~AssociatedInterfacePtrStateBase();
 
   uint32_t version() const { return version_; }
 
-  void QueryVersion(const base::Callback<void(uint32_t)>& callback) {
-    // It is safe to capture |this| because the callback won't be run after this
-    // object goes away.
-    endpoint_client_->QueryVersion(
-        base::Bind(&AssociatedInterfacePtrState::OnQueryVersion,
-                   base::Unretained(this), callback));
-  }
-
-  void RequireVersion(uint32_t version) {
-    if (version <= version_)
-      return;
-
-    version_ = version;
-    endpoint_client_->RequireVersion(version);
-  }
-
-  void FlushForTesting() { endpoint_client_->FlushForTesting(); }
-
-  void CloseWithReason(uint32_t custom_reason, const std::string& description) {
-    endpoint_client_->CloseWithReason(custom_reason, description);
-  }
-
-  void Swap(AssociatedInterfacePtrState* other) {
-    using std::swap;
-    swap(other->endpoint_client_, endpoint_client_);
-    swap(other->proxy_, proxy_);
-    swap(other->version_, version_);
-  }
-
-  void Bind(AssociatedInterfacePtrInfo<Interface> info,
-            scoped_refptr<base::SequencedTaskRunner> runner) {
-    DCHECK(!endpoint_client_);
-    DCHECK(!proxy_);
-    DCHECK_EQ(0u, version_);
-    DCHECK(info.is_valid());
-
-    version_ = info.version();
-    // The version is only queried from the client so the value passed here
-    // will not be used.
-    endpoint_client_.reset(new InterfaceEndpointClient(
-        info.PassHandle(), nullptr,
-        base::WrapUnique(new typename Interface::ResponseValidator_()), false,
-        std::move(runner), 0u));
-    proxy_.reset(new Proxy(endpoint_client_.get()));
-  }
-
-  // After this method is called, the object is in an invalid state and
-  // shouldn't be reused.
-  AssociatedInterfacePtrInfo<Interface> PassInterface() {
-    ScopedInterfaceEndpointHandle handle = endpoint_client_->PassHandle();
-    endpoint_client_.reset();
-    proxy_.reset();
-    return AssociatedInterfacePtrInfo<Interface>(std::move(handle), version_);
-  }
+  void QueryVersion(const base::Callback<void(uint32_t)>& callback);
+  void RequireVersion(uint32_t version);
+  void FlushForTesting();
+  void CloseWithReason(uint32_t custom_reason, const std::string& description);
 
   bool is_bound() const { return !!endpoint_client_; }
 
@@ -135,20 +76,63 @@
     endpoint_client_->AcceptWithResponder(&message, std::move(responder));
   }
 
+ protected:
+  void Swap(AssociatedInterfacePtrStateBase* other);
+  void Bind(ScopedInterfaceEndpointHandle handle,
+            uint32_t version,
+            std::unique_ptr<MessageReceiver> validator,
+            scoped_refptr<base::SequencedTaskRunner> runner);
+  ScopedInterfaceEndpointHandle PassHandle();
+
+  InterfaceEndpointClient* endpoint_client() { return endpoint_client_.get(); }
+
+ private:
+  void OnQueryVersion(const base::Callback<void(uint32_t)>& callback,
+                      uint32_t version);
+
+  std::unique_ptr<InterfaceEndpointClient> endpoint_client_;
+  uint32_t version_ = 0;
+};
+
+template <typename Interface>
+class AssociatedInterfacePtrState : public AssociatedInterfacePtrStateBase {
+ public:
+  AssociatedInterfacePtrState() {}
+  ~AssociatedInterfacePtrState() = default;
+
+  Interface* instance() {
+    // This will be null if the object is not bound.
+    return proxy_.get();
+  }
+
+  void Swap(AssociatedInterfacePtrState* other) {
+    AssociatedInterfacePtrStateBase::Swap(other);
+    std::swap(other->proxy_, proxy_);
+  }
+
+  void Bind(AssociatedInterfacePtrInfo<Interface> info,
+            scoped_refptr<base::SequencedTaskRunner> runner) {
+    DCHECK(!proxy_);
+    AssociatedInterfacePtrStateBase::Bind(
+        info.PassHandle(), info.version(),
+        base::MakeUnique<typename Interface::ResponseValidator_>(),
+        std::move(runner));
+    proxy_.reset(new Proxy(endpoint_client()));
+  }
+
+  // After this method is called, the object is in an invalid state and
+  // shouldn't be reused.
+  AssociatedInterfacePtrInfo<Interface> PassInterface() {
+    AssociatedInterfacePtrInfo<Interface> info(PassHandle(), version());
+    proxy_.reset();
+    return info;
+  }
+
  private:
   using Proxy = typename Interface::Proxy_;
 
-  void OnQueryVersion(const base::Callback<void(uint32_t)>& callback,
-                      uint32_t version) {
-    version_ = version;
-    callback.Run(version);
-  }
-
-  std::unique_ptr<InterfaceEndpointClient> endpoint_client_;
   std::unique_ptr<Proxy> proxy_;
 
-  uint32_t version_;
-
   DISALLOW_COPY_AND_ASSIGN(AssociatedInterfacePtrState);
 };
 
diff --git a/mojo/public/cpp/bindings/lib/bindings_internal.h b/mojo/public/cpp/bindings/lib/bindings_internal.h
index 6f73ee6a..f761145 100644
--- a/mojo/public/cpp/bindings/lib/bindings_internal.h
+++ b/mojo/public/cpp/bindings/lib/bindings_internal.h
@@ -10,6 +10,7 @@
 #include <functional>
 #include <type_traits>
 
+#include "mojo/public/cpp/bindings/enum_traits.h"
 #include "mojo/public/cpp/bindings/interface_id.h"
 #include "mojo/public/cpp/bindings/lib/template_util.h"
 #include "mojo/public/cpp/system/core.h"
@@ -330,6 +331,14 @@
   }
 };
 
+template <typename MojomType, typename T>
+T ConvertEnumValue(MojomType input) {
+  T output;
+  bool result = EnumTraits<MojomType, T>::FromMojom(input, &output);
+  DCHECK(result);
+  return output;
+}
+
 }  // namespace internal
 }  // namespace mojo
 
diff --git a/mojo/public/cpp/bindings/lib/handle_interface_serialization.h b/mojo/public/cpp/bindings/lib/handle_interface_serialization.h
index cfc2fd9f..661519b4 100644
--- a/mojo/public/cpp/bindings/lib/handle_interface_serialization.h
+++ b/mojo/public/cpp/bindings/lib/handle_interface_serialization.h
@@ -26,40 +26,30 @@
                   AssociatedInterfacePtrInfo<T>> {
   static_assert(std::is_base_of<Base, T>::value, "Interface type mismatch.");
 
-  static size_t PrepareToSerialize(const AssociatedInterfacePtrInfo<T>& input,
+  static size_t PrepareToSerialize(AssociatedInterfacePtrInfo<T>& input,
                                    SerializationContext* context) {
-    if (input.handle().is_valid())
-      context->associated_endpoint_count++;
+    DCHECK(!input.handle().is_valid() || input.handle().pending_association());
+    context->AddAssociatedInterfaceInfo(input.PassHandle(), input.version());
     return 0;
   }
 
-  static void Serialize(AssociatedInterfacePtrInfo<T>& input,
+  static void Serialize(const AssociatedInterfacePtrInfo<T>& input,
                         AssociatedInterface_Data* output,
                         SerializationContext* context) {
-    DCHECK(!input.handle().is_valid() || input.handle().pending_association());
-    if (input.handle().is_valid()) {
-      // Set to the index of the element pushed to the back of the vector.
-      output->handle.value =
-          static_cast<uint32_t>(context->associated_endpoint_handles.size());
-      context->associated_endpoint_handles.push_back(input.PassHandle());
-    } else {
-      output->handle.value = kEncodedInvalidHandleValue;
-    }
-    output->version = input.version();
+    DCHECK(!input.is_valid());
+    context->ConsumeNextSerializedAssociatedInterfaceInfo(output);
   }
 
   static bool Deserialize(AssociatedInterface_Data* input,
                           AssociatedInterfacePtrInfo<T>* output,
                           SerializationContext* context) {
-    if (input->handle.is_valid()) {
-      DCHECK_LT(input->handle.value,
-                context->associated_endpoint_handles.size());
-      output->set_handle(
-          std::move(context->associated_endpoint_handles[input->handle.value]));
+    auto handle = context->TakeAssociatedEndpointHandle(input->handle);
+    if (!handle.is_valid()) {
+      *output = AssociatedInterfacePtrInfo<T>();
     } else {
-      output->set_handle(ScopedInterfaceEndpointHandle());
+      output->set_handle(std::move(handle));
+      output->set_version(input->version);
     }
-    output->set_version(input->version);
     return true;
   }
 };
@@ -69,37 +59,28 @@
                   AssociatedInterfaceRequest<T>> {
   static_assert(std::is_base_of<Base, T>::value, "Interface type mismatch.");
 
-  static size_t PrepareToSerialize(const AssociatedInterfaceRequest<T>& input,
+  static size_t PrepareToSerialize(AssociatedInterfaceRequest<T>& input,
                                    SerializationContext* context) {
-    if (input.handle().is_valid())
-      context->associated_endpoint_count++;
+    DCHECK(!input.handle().is_valid() || input.handle().pending_association());
+    context->AddAssociatedEndpoint(input.PassHandle());
     return 0;
   }
 
-  static void Serialize(AssociatedInterfaceRequest<T>& input,
+  static void Serialize(const AssociatedInterfaceRequest<T>& input,
                         AssociatedEndpointHandle_Data* output,
                         SerializationContext* context) {
-    DCHECK(!input.handle().is_valid() || input.handle().pending_association());
-    if (input.handle().is_valid()) {
-      // Set to the index of the element pushed to the back of the vector.
-      output->value =
-          static_cast<uint32_t>(context->associated_endpoint_handles.size());
-      context->associated_endpoint_handles.push_back(input.PassHandle());
-    } else {
-      output->value = kEncodedInvalidHandleValue;
-    }
+    DCHECK(!input.handle().is_valid());
+    context->ConsumeNextSerializedAssociatedEndpoint(output);
   }
 
   static bool Deserialize(AssociatedEndpointHandle_Data* input,
                           AssociatedInterfaceRequest<T>* output,
                           SerializationContext* context) {
-    if (input->is_valid()) {
-      DCHECK_LT(input->value, context->associated_endpoint_handles.size());
-      *output = AssociatedInterfaceRequest<T>(
-          std::move(context->associated_endpoint_handles[input->value]));
-    } else {
+    auto handle = context->TakeAssociatedEndpointHandle(*input);
+    if (!handle.is_valid())
       *output = AssociatedInterfaceRequest<T>();
-    }
+    else
+      *output = AssociatedInterfaceRequest<T>(std::move(handle));
     return true;
   }
 };
@@ -111,7 +92,7 @@
   static size_t PrepareToSerialize(InterfacePtr<T>& input,
                                    SerializationContext* context) {
     InterfacePtrInfo<T> info = input.PassInterface();
-    context->handles.AddInterfaceInfo(info.PassHandle(), info.version());
+    context->AddInterfaceInfo(info.PassHandle(), info.version());
     return 0;
   }
 
@@ -119,14 +100,14 @@
                         Interface_Data* output,
                         SerializationContext* context) {
     DCHECK(!input.is_bound());
-    context->handles.ConsumeNextSerializedInterfaceInfo(output);
+    context->ConsumeNextSerializedInterfaceInfo(output);
   }
 
   static bool Deserialize(Interface_Data* input,
                           InterfacePtr<T>* output,
                           SerializationContext* context) {
     output->Bind(InterfacePtrInfo<T>(
-        context->handles.TakeHandleAs<mojo::MessagePipeHandle>(input->handle),
+        context->TakeHandleAs<mojo::MessagePipeHandle>(input->handle),
         input->version));
     return true;
   }
@@ -138,7 +119,7 @@
 
   static size_t PrepareToSerialize(InterfaceRequest<T>& input,
                                    SerializationContext* context) {
-    context->handles.AddHandle(ScopedHandle::From(input.PassMessagePipe()));
+    context->AddHandle(ScopedHandle::From(input.PassMessagePipe()));
     return 0;
   }
 
@@ -146,14 +127,14 @@
                         Handle_Data* output,
                         SerializationContext* context) {
     DCHECK(!input.is_pending());
-    context->handles.ConsumeNextSerializedHandle(output);
+    context->ConsumeNextSerializedHandle(output);
   }
 
   static bool Deserialize(Handle_Data* input,
                           InterfaceRequest<T>* output,
                           SerializationContext* context) {
-    *output = InterfaceRequest<T>(
-        context->handles.TakeHandleAs<MessagePipeHandle>(*input));
+    *output =
+        InterfaceRequest<T>(context->TakeHandleAs<MessagePipeHandle>(*input));
     return true;
   }
 };
@@ -162,7 +143,7 @@
 struct Serializer<ScopedHandleBase<T>, ScopedHandleBase<T>> {
   static size_t PrepareToSerialize(ScopedHandleBase<T>& input,
                                    SerializationContext* context) {
-    context->handles.AddHandle(ScopedHandle::From(std::move(input)));
+    context->AddHandle(ScopedHandle::From(std::move(input)));
     return 0;
   }
 
@@ -170,13 +151,13 @@
                         Handle_Data* output,
                         SerializationContext* context) {
     DCHECK(!input.is_valid());
-    context->handles.ConsumeNextSerializedHandle(output);
+    context->ConsumeNextSerializedHandle(output);
   }
 
   static bool Deserialize(Handle_Data* input,
                           ScopedHandleBase<T>* output,
                           SerializationContext* context) {
-    *output = context->handles.TakeHandleAs<T>(*input);
+    *output = context->TakeHandleAs<T>(*input);
     return true;
   }
 };
diff --git a/mojo/public/cpp/bindings/lib/map_serialization.h b/mojo/public/cpp/bindings/lib/map_serialization.h
index 08287608..23b0a12 100644
--- a/mojo/public/cpp/bindings/lib/map_serialization.h
+++ b/mojo/public/cpp/bindings/lib/map_serialization.h
@@ -98,7 +98,7 @@
   static size_t PrepareToSerialize(MaybeConstUserType& input,
                                    SerializationContext* context) {
     const bool is_null = CallIsNullIfExists<Traits>(input);
-    context->null_states.container().push_back(is_null);
+    context->PushNextNullState(is_null);
     if (is_null)
       return 0;
 
diff --git a/mojo/public/cpp/bindings/lib/serialization_context.cc b/mojo/public/cpp/bindings/lib/serialization_context.cc
index 5748d10..8921a0e 100644
--- a/mojo/public/cpp/bindings/lib/serialization_context.cc
+++ b/mojo/public/cpp/bindings/lib/serialization_context.cc
@@ -13,11 +13,32 @@
 namespace mojo {
 namespace internal {
 
-SerializedHandleVector::SerializedHandleVector() = default;
+SerializationContext::SerializationContext() = default;
 
-SerializedHandleVector::~SerializedHandleVector() = default;
+SerializationContext::~SerializationContext() {
+  DCHECK(custom_contexts_.empty() ||
+         custom_context_index_ == custom_contexts_.size());
+}
 
-void SerializedHandleVector::AddHandle(mojo::ScopedHandle handle) {
+void SerializationContext::PushNextNullState(bool is_null) {
+  null_states_.container().push_back(is_null);
+}
+
+bool SerializationContext::IsNextFieldNull() {
+  DCHECK_LT(null_state_index_, null_states_.container().size());
+  return null_states_.container()[null_state_index_++];
+}
+
+void SerializationContext::PushCustomContext(void* custom_context) {
+  custom_contexts_.emplace_back(custom_context);
+}
+
+void* SerializationContext::ConsumeNextCustomContext() {
+  DCHECK_LT(custom_context_index_, custom_contexts_.size());
+  return custom_contexts_[custom_context_index_++];
+}
+
+void SerializationContext::AddHandle(mojo::ScopedHandle handle) {
   Handle_Data data;
   if (!handle.is_valid()) {
     data.value = kEncodedInvalidHandleValue;
@@ -29,20 +50,19 @@
   serialized_handles_.emplace_back(data);
 }
 
-void SerializedHandleVector::AddInterfaceInfo(
+void SerializationContext::ConsumeNextSerializedHandle(Handle_Data* out_data) {
+  DCHECK_LT(next_serialized_handle_index_, serialized_handles_.size());
+  *out_data = serialized_handles_[next_serialized_handle_index_++];
+}
+
+void SerializationContext::AddInterfaceInfo(
     mojo::ScopedMessagePipeHandle handle,
     uint32_t version) {
   AddHandle(ScopedHandle::From(std::move(handle)));
   serialized_interface_versions_.emplace_back(version);
 }
 
-void SerializedHandleVector::ConsumeNextSerializedHandle(
-    Handle_Data* out_data) {
-  DCHECK_LT(next_serialized_handle_index_, serialized_handles_.size());
-  *out_data = serialized_handles_[next_serialized_handle_index_++];
-}
-
-void SerializedHandleVector::ConsumeNextSerializedInterfaceInfo(
+void SerializationContext::ConsumeNextSerializedInterfaceInfo(
     Interface_Data* out_data) {
   ConsumeNextSerializedHandle(&out_data->handle);
   DCHECK_LT(next_serialized_version_index_,
@@ -51,7 +71,61 @@
       serialized_interface_versions_[next_serialized_version_index_++];
 }
 
-mojo::ScopedHandle SerializedHandleVector::TakeHandle(
+void SerializationContext::AddAssociatedEndpoint(
+    ScopedInterfaceEndpointHandle handle) {
+  AssociatedEndpointHandle_Data data;
+  if (!handle.is_valid()) {
+    data.value = kEncodedInvalidHandleValue;
+  } else {
+    DCHECK_LT(associated_endpoint_handles_.size(),
+              std::numeric_limits<uint32_t>::max());
+    data.value = static_cast<uint32_t>(associated_endpoint_handles_.size());
+    associated_endpoint_handles_.emplace_back(std::move(handle));
+  }
+  serialized_associated_endpoint_handles_.emplace_back(data);
+}
+
+void SerializationContext::ConsumeNextSerializedAssociatedEndpoint(
+    AssociatedEndpointHandle_Data* out_data) {
+  DCHECK_LT(next_serialized_associated_endpoint_handle_index_,
+            serialized_associated_endpoint_handles_.size());
+  *out_data = serialized_associated_endpoint_handles_
+      [next_serialized_associated_endpoint_handle_index_++];
+}
+
+void SerializationContext::AddAssociatedInterfaceInfo(
+    ScopedInterfaceEndpointHandle handle,
+    uint32_t version) {
+  AddAssociatedEndpoint(std::move(handle));
+  serialized_interface_versions_.emplace_back(version);
+}
+
+void SerializationContext::ConsumeNextSerializedAssociatedInterfaceInfo(
+    AssociatedInterface_Data* out_data) {
+  ConsumeNextSerializedAssociatedEndpoint(&out_data->handle);
+  DCHECK_LT(next_serialized_version_index_,
+            serialized_interface_versions_.size());
+  out_data->version =
+      serialized_interface_versions_[next_serialized_version_index_++];
+}
+
+void SerializationContext::PrepareMessage(uint32_t message_name,
+                                          uint32_t flags,
+                                          size_t payload_size,
+                                          Message* message) {
+  *message = Message(message_name, flags, payload_size,
+                     associated_endpoint_handles_.size(), &handles_);
+  associated_endpoint_handles_.swap(
+      *message->mutable_associated_endpoint_handles());
+}
+
+void SerializationContext::TakeHandlesFromMessage(Message* message) {
+  handles_.swap(*message->mutable_handles());
+  associated_endpoint_handles_.swap(
+      *message->mutable_associated_endpoint_handles());
+}
+
+mojo::ScopedHandle SerializationContext::TakeHandle(
     const Handle_Data& encoded_handle) {
   if (!encoded_handle.is_valid())
     return mojo::ScopedHandle();
@@ -59,19 +133,13 @@
   return std::move(handles_[encoded_handle.value]);
 }
 
-void SerializedHandleVector::Swap(std::vector<mojo::ScopedHandle>* other) {
-  handles_.swap(*other);
-}
-
-SerializationContext::SerializationContext() {}
-
-SerializationContext::~SerializationContext() {
-  DCHECK(!custom_contexts || custom_contexts->empty());
-}
-
-void SerializationContext::AttachHandlesToMessage(Message* message) {
-  associated_endpoint_handles.swap(
-      *message->mutable_associated_endpoint_handles());
+mojo::ScopedInterfaceEndpointHandle
+SerializationContext::TakeAssociatedEndpointHandle(
+    const AssociatedEndpointHandle_Data& encoded_handle) {
+  if (!encoded_handle.is_valid())
+    return mojo::ScopedInterfaceEndpointHandle();
+  DCHECK_LT(encoded_handle.value, associated_endpoint_handles_.size());
+  return std::move(associated_endpoint_handles_[encoded_handle.value]);
 }
 
 }  // namespace internal
diff --git a/mojo/public/cpp/bindings/lib/serialization_context.h b/mojo/public/cpp/bindings/lib/serialization_context.h
index bc355044..9c523cd 100644
--- a/mojo/public/cpp/bindings/lib/serialization_context.h
+++ b/mojo/public/cpp/bindings/lib/serialization_context.h
@@ -8,7 +8,6 @@
 #include <stddef.h>
 
 #include <memory>
-#include <queue>
 #include <vector>
 
 #include "base/containers/stack_container.h"
@@ -24,31 +23,81 @@
 
 namespace internal {
 
-// A container for handles during serialization/deserialization.
-class MOJO_CPP_BINDINGS_EXPORT SerializedHandleVector {
+// Context information for serialization/deserialization routines.
+class MOJO_CPP_BINDINGS_EXPORT SerializationContext {
  public:
-  SerializedHandleVector();
-  ~SerializedHandleVector();
+  SerializationContext();
+  ~SerializationContext();
 
-  size_t size() const { return handles_.size(); }
-  std::vector<mojo::ScopedHandle>* mutable_handles() { return &handles_; }
-  std::vector<Handle_Data>* serialized_handles() {
-    return &serialized_handles_;
-  }
+  // Enqueues a custom context for a field within this context during
+  // pre-serialization. A corresponding call to ConsumeNextCustomContext must be
+  // made during serialization for the same field in order to retreive the
+  // context.
+  void PushCustomContext(void* custom_context);
 
-  // Adds a handle to the handle and serialized handle data lists.
+  // Consumes a field's custom context enqueued during pre-serialization by
+  // PushCustomContext().
+  void* ConsumeNextCustomContext();
+
+  // Enqueues the null state of a field within this context during
+  // pre-serialization. A corresponding call to IsNextFieldNull must be made
+  // during serialization for the same field in order to retrieve this state
+  // later.
+  void PushNextNullState(bool is_null);
+
+  // Consumes a field's null state enqueued during pre-serialization by
+  // PushNextNullState().
+  bool IsNextFieldNull();
+
+  // Adds a handle to the handle and serialized handle data lists during
+  // pre-serialization.
   void AddHandle(mojo::ScopedHandle handle);
 
-  // Adds an interface info to the handle and serialized handle+version data
-  // lists.
-  void AddInterfaceInfo(mojo::ScopedMessagePipeHandle handle, uint32_t version);
-
-  // Consumes the next available serialized handle data.
+  // Consumes the next available serialized handle data which was added by
+  // AddHandle() during pre-serialization.
   void ConsumeNextSerializedHandle(Handle_Data* out_data);
 
-  // Consumes the next available serialized handle and version data.
+  // Adds an interface info to the handle and serialized handle+version data
+  // lists during pre-serialization.
+  void AddInterfaceInfo(mojo::ScopedMessagePipeHandle handle, uint32_t version);
+
+  // Consumes the next available serialized handle and version data which was
+  // added by AddInterfaceInfo() during pre-serialization.
   void ConsumeNextSerializedInterfaceInfo(Interface_Data* out_data);
 
+  // Adds an associated interface endpoint (for e.g. an
+  // AssociatedInterfaceRequest) to this context during pre-serialization.
+  void AddAssociatedEndpoint(ScopedInterfaceEndpointHandle handle);
+
+  // Consumes the next available serialized handle data which was added by
+  // AddAssociatedEndpoint() during pre-serialization.
+  void ConsumeNextSerializedAssociatedEndpoint(
+      AssociatedEndpointHandle_Data* out_data);
+
+  // Adds an associated interface info to associated endpoint handle and version
+  // data lists during pre-serialization.
+  void AddAssociatedInterfaceInfo(ScopedInterfaceEndpointHandle handle,
+                                  uint32_t version);
+
+  // Consumes the next available serialized associated endpoint handle and
+  // version data which was added by AddAssociatedInterfaceInfo() during
+  // pre-serialization.
+  void ConsumeNextSerializedAssociatedInterfaceInfo(
+      AssociatedInterface_Data* out_data);
+
+  // Prepares a new serialized message based on the state accumulated by this
+  // SerializationContext so far.
+  void PrepareMessage(uint32_t message_name,
+                      uint32_t flags,
+                      size_t payload_size,
+                      Message* message);
+
+  const std::vector<mojo::ScopedHandle>* handles() { return &handles_; }
+
+  // Takes handles from a received Message object and assumes ownership of them.
+  // Individual handles can be extracted using Take* methods below.
+  void TakeHandlesFromMessage(Message* message);
+
   // Takes a handle from the list of serialized handle data.
   mojo::ScopedHandle TakeHandle(const Handle_Data& encoded_handle);
 
@@ -59,56 +108,48 @@
     return ScopedHandleBase<T>::From(TakeHandle(encoded_handle));
   }
 
-  // Swaps all owned handles out with another Handle vector.
-  void Swap(std::vector<mojo::ScopedHandle>* other);
+  mojo::ScopedInterfaceEndpointHandle TakeAssociatedEndpointHandle(
+      const AssociatedEndpointHandle_Data& encoded_handle);
 
  private:
-  // Handles are owned by this object.
-  std::vector<mojo::ScopedHandle> handles_;
-
-  // Serialized handle and (optional) version data. This is accumulated during
-  // pre-serialization by AddHandle and AddInterfaceInfo calls, and later
-  // consumed during serialization by ConsumeNextSerializedHandle/InterfaceInfo.
-  size_t next_serialized_handle_index_ = 0;
-  std::vector<Handle_Data> serialized_handles_;
-  size_t next_serialized_version_index_ = 0;
-  std::vector<uint32_t> serialized_interface_versions_;
-
-  DISALLOW_COPY_AND_ASSIGN(SerializedHandleVector);
-};
-
-// Context information for serialization/deserialization routines.
-struct MOJO_CPP_BINDINGS_EXPORT SerializationContext {
-  SerializationContext();
-
-  ~SerializationContext();
-
-  bool IsNextFieldNull() {
-    DCHECK_LT(null_state_index, null_states.container().size());
-    return null_states.container()[null_state_index++];
-  }
-
-  // Transfers ownership of any accumulated associated endpoint handles into
-  // |*message|.
-  void AttachHandlesToMessage(Message* message);
-
-  // Opaque context pointers returned by StringTraits::SetUpContext().
-  std::unique_ptr<std::queue<void*>> custom_contexts;
-
   // A container for tracking the null-ness of every nullable field as a
   // message's arguments are walked during serialization.
-  base::StackVector<bool, 32> null_states;
-  size_t null_state_index = 0;
+  base::StackVector<bool, 32> null_states_;
+  size_t null_state_index_ = 0;
 
-  // Stashes handles encoded in a message by index.
-  SerializedHandleVector handles;
+  // Opaque context pointers returned by StringTraits::SetUpContext().
+  std::vector<void*> custom_contexts_;
+  size_t custom_context_index_ = 0;
 
-  // The number of ScopedInterfaceEndpointHandles that need to be serialized.
-  // It is calculated by PrepareToSerialize().
-  uint32_t associated_endpoint_count = 0;
+  // Handles owned by this object. Used during serialization to hold onto
+  // handles accumulated during pre-serialization, and used during
+  // deserialization to hold onto handles extracted from a message.
+  std::vector<mojo::ScopedHandle> handles_;
 
   // Stashes ScopedInterfaceEndpointHandles encoded in a message by index.
-  std::vector<ScopedInterfaceEndpointHandle> associated_endpoint_handles;
+  std::vector<ScopedInterfaceEndpointHandle> associated_endpoint_handles_;
+
+  // Accumulated version numbers for interface info. These may be accumulated
+  // and consumed for either regular interface info or associated interface
+  // info.
+  std::vector<uint32_t> serialized_interface_versions_;
+  size_t next_serialized_version_index_ = 0;
+
+  // Serialized handle data. This is accumulated during pre-serialization by
+  // AddHandle and AddInterfaceInfo calls, and later consumed during
+  // serialization by ConsumeNextSerializedHandle/InterfaceInfo.
+  std::vector<Handle_Data> serialized_handles_;
+  size_t next_serialized_handle_index_ = 0;
+
+  // Serialized associated handle data. This is accumulated during
+  // pre-serialization by AddAssociatedEndpoint and AddAssociatedInterfaceInfo
+  // calls, and later consumed during serialization by
+  // ConsumeNextSerializedAssociatedEndpoint/InterfaceInfo.
+  std::vector<AssociatedEndpointHandle_Data>
+      serialized_associated_endpoint_handles_;
+  size_t next_serialized_associated_endpoint_handle_index_ = 0;
+
+  DISALLOW_COPY_AND_ASSIGN(SerializationContext);
 };
 
 }  // namespace internal
diff --git a/mojo/public/cpp/bindings/lib/serialization_util.h b/mojo/public/cpp/bindings/lib/serialization_util.h
index 4820a01..22e0948 100644
--- a/mojo/public/cpp/bindings/lib/serialization_util.h
+++ b/mojo/public/cpp/bindings/lib/serialization_util.h
@@ -21,7 +21,7 @@
 template <typename T>
 struct HasIsNullMethod {
   template <typename U>
-  static char Test(decltype(U::IsNull)*);
+  static char Test(decltype(U::IsNull) *);
   template <typename U>
   static int Test(...);
   static const bool value = sizeof(Test<T>(0)) == sizeof(char);
@@ -48,7 +48,7 @@
 template <typename T>
 struct HasSetToNullMethod {
   template <typename U>
-  static char Test(decltype(U::SetToNull)*);
+  static char Test(decltype(U::SetToNull) *);
   template <typename U>
   static int Test(...);
   static const bool value = sizeof(Test<T>(0)) == sizeof(char);
@@ -80,7 +80,7 @@
 template <typename T>
 struct HasSetUpContextMethod {
   template <typename U>
-  static char Test(decltype(U::SetUpContext)*);
+  static char Test(decltype(U::SetUpContext) *);
   template <typename U>
   static int Test(...);
   static const bool value = sizeof(Test<T>(0)) == sizeof(char);
@@ -98,16 +98,12 @@
   template <typename MaybeConstUserType>
   static void* SetUp(MaybeConstUserType& input, SerializationContext* context) {
     void* custom_context = Traits::SetUpContext(input);
-    if (!context->custom_contexts)
-      context->custom_contexts.reset(new std::queue<void*>());
-    context->custom_contexts->push(custom_context);
+    context->PushCustomContext(custom_context);
     return custom_context;
   }
 
   static void* GetNext(SerializationContext* context) {
-    void* custom_context = context->custom_contexts->front();
-    context->custom_contexts->pop();
-    return custom_context;
+    return context->ConsumeNextCustomContext();
   }
 
   template <typename MaybeConstUserType>
@@ -148,7 +144,8 @@
 template <typename T, typename MaybeConstUserType>
 struct HasGetBeginMethod {
   template <typename U>
-  static char Test(decltype(U::GetBegin(std::declval<MaybeConstUserType&>()))*);
+  static char Test(
+      decltype(U::GetBegin(std::declval<MaybeConstUserType&>())) *);
   template <typename U>
   static int Test(...);
   static const bool value = sizeof(Test<T>(0)) == sizeof(char);
@@ -179,7 +176,7 @@
 template <typename T, typename MaybeConstUserType>
 struct HasGetDataMethod {
   template <typename U>
-  static char Test(decltype(U::GetData(std::declval<MaybeConstUserType&>()))*);
+  static char Test(decltype(U::GetData(std::declval<MaybeConstUserType&>())) *);
   template <typename U>
   static int Test(...);
   static const bool value = sizeof(Test<T>(0)) == sizeof(char);
diff --git a/mojo/public/cpp/bindings/lib/string_serialization.h b/mojo/public/cpp/bindings/lib/string_serialization.h
index 68165dd..54d9dd9 100644
--- a/mojo/public/cpp/bindings/lib/string_serialization.h
+++ b/mojo/public/cpp/bindings/lib/string_serialization.h
@@ -25,7 +25,7 @@
   static size_t PrepareToSerialize(MaybeConstUserType& input,
                                    SerializationContext* context) {
     const bool is_null = CallIsNullIfExists<Traits>(input);
-    context->null_states.container().push_back(is_null);
+    context->PushNextNullState(is_null);
     if (is_null)
       return 0;
 
diff --git a/mojo/public/cpp/bindings/tests/struct_traits_unittest.cc b/mojo/public/cpp/bindings/tests/struct_traits_unittest.cc
index 7e4bcd12..77122c9 100644
--- a/mojo/public/cpp/bindings/tests/struct_traits_unittest.cc
+++ b/mojo/public/cpp/bindings/tests/struct_traits_unittest.cc
@@ -550,5 +550,10 @@
   }
 }
 
+TEST_F(StructTraitsTest, DefaultValueOfEnumWithTraits) {
+  auto container = EnumWithTraitsContainer::New();
+  EXPECT_EQ(EnumWithTraitsImpl::CUSTOM_VALUE_1, container->f_field);
+}
+
 }  // namespace test
 }  // namespace mojo
diff --git a/mojo/public/cpp/bindings/tests/union_unittest.cc b/mojo/public/cpp/bindings/tests/union_unittest.cc
index 92e25828..5439a95 100644
--- a/mojo/public/cpp/bindings/tests/union_unittest.cc
+++ b/mojo/public/cpp/bindings/tests/union_unittest.cc
@@ -1204,7 +1204,7 @@
   internal::HandleUnion_Data* data = nullptr;
   mojo::internal::Serialize<HandleUnionDataView>(handle, &buf, &data, false,
                                                  &context);
-  EXPECT_EQ(1U, context.handles.size());
+  EXPECT_EQ(1U, context.handles()->size());
 
   HandleUnionPtr handle2(HandleUnion::New());
   mojo::internal::Deserialize<HandleUnionDataView>(data, &handle2, &context);
@@ -1337,7 +1337,7 @@
   internal::HandleUnion_Data* data = nullptr;
   mojo::internal::Serialize<HandleUnionDataView>(handle, &buf, &data, false,
                                                  &context);
-  EXPECT_EQ(1U, context.handles.size());
+  EXPECT_EQ(1U, context.handles()->size());
 
   HandleUnionPtr handle2(HandleUnion::New());
   mojo::internal::Deserialize<HandleUnionDataView>(data, &handle2, &context);
diff --git a/mojo/public/cpp/system/platform_handle.cc b/mojo/public/cpp/system/platform_handle.cc
index 405f5f0..8017ba3 100644
--- a/mojo/public/cpp/system/platform_handle.cc
+++ b/mojo/public/cpp/system/platform_handle.cc
@@ -122,16 +122,20 @@
   base::UnguessableToken guid =
       base::UnguessableToken::Deserialize(mojo_guid.high, mojo_guid.low);
 #if defined(OS_MACOSX) && !defined(OS_IOS)
-  CHECK_EQ(platform_handle.type, MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT);
+  DCHECK_EQ(platform_handle.type, MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT);
   *memory_handle = base::SharedMemoryHandle(
       static_cast<mach_port_t>(platform_handle.value), num_bytes, guid);
+#elif defined(OS_FUCHSIA)
+  DCHECK_EQ(platform_handle.type, MOJO_PLATFORM_HANDLE_TYPE_FUCHSIA_HANDLE);
+  *memory_handle = base::SharedMemoryHandle(
+      static_cast<mx_handle_t>(platform_handle.value), num_bytes, guid);
 #elif defined(OS_POSIX)
-  CHECK_EQ(platform_handle.type, MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR);
+  DCHECK_EQ(platform_handle.type, MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR);
   *memory_handle = base::SharedMemoryHandle(
       base::FileDescriptor(static_cast<int>(platform_handle.value), false),
       num_bytes, guid);
 #elif defined(OS_WIN)
-  CHECK_EQ(platform_handle.type, MOJO_PLATFORM_HANDLE_TYPE_WINDOWS_HANDLE);
+  DCHECK_EQ(platform_handle.type, MOJO_PLATFORM_HANDLE_TYPE_WINDOWS_HANDLE);
   *memory_handle = base::SharedMemoryHandle(
       reinterpret_cast<HANDLE>(platform_handle.value), num_bytes, guid);
 #endif
diff --git a/mojo/public/cpp/system/platform_handle.h b/mojo/public/cpp/system/platform_handle.h
index 801264e..8250fcf 100644
--- a/mojo/public/cpp/system/platform_handle.h
+++ b/mojo/public/cpp/system/platform_handle.h
@@ -37,6 +37,9 @@
 #if defined(OS_MACOSX) && !defined(OS_IOS)
 const MojoPlatformHandleType kPlatformSharedBufferHandleType =
     MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT;
+#elif defined(OS_FUCHSIA)
+const MojoPlatformHandleType kPlatformSharedBufferHandleType =
+    MOJO_PLATFORM_HANDLE_TYPE_FUCHSIA_HANDLE;
 #else
 const MojoPlatformHandleType kPlatformSharedBufferHandleType =
     MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR;
diff --git a/mojo/public/interfaces/bindings/tests/struct_with_traits.mojom b/mojo/public/interfaces/bindings/tests/struct_with_traits.mojom
index b50409e..f53a188 100644
--- a/mojo/public/interfaces/bindings/tests/struct_with_traits.mojom
+++ b/mojo/public/interfaces/bindings/tests/struct_with_traits.mojom
@@ -81,3 +81,9 @@
 
   EchoUnionWithTraits(UnionWithTraits u) => (UnionWithTraits passed);
 };
+
+// Test that specifying default value for a typemapped enum field works.
+struct EnumWithTraitsContainer {
+  EnumWithTraits f_field = EnumWithTraits.VALUE_1;
+};
+
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl
index bbc1777..941820ae 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl
@@ -7,9 +7,7 @@
 
 {%- macro alloc_params(struct, params, message, description) %}
   mojo::internal::SerializationContext serialization_context;
-  serialization_context.handles.Swap(({{message}})->mutable_handles());
-  serialization_context.associated_endpoint_handles.swap(
-      *({{message}})->mutable_associated_endpoint_handles());
+  serialization_context.TakeHandlesFromMessage({{message}});
   bool success = true;
 {%-   for param in struct.packed.packed_fields_in_ordinal_order %}
   {{param.field.kind|cpp_wrapper_type}} p_{{param.field.name}}{};
@@ -37,7 +35,6 @@
   {{struct_macros.serialize(struct, struct_display_name, input_pattern,
                             "params", "(%s)->payload_buffer()"|format(message),
                             serialization_context)}}
-  ({{serialization_context}})->AttachHandlesToMessage({{message}});
 {%- endmacro %}
 
 {#--- Begin #}
@@ -158,11 +155,11 @@
   mojo::internal::SerializationContext serialization_context;
   {{struct_macros.get_serialized_size(params_struct, "param_%s",
                                       "&serialization_context")}}
-  mojo::Message message(
+  mojo::Message message;
+  serialization_context.PrepareMessage(
       {{message_name}},
-      mojo::Message::kFlagIsSync | mojo::Message::kFlagExpectsResponse,
-      size, serialization_context.associated_endpoint_count,
-      serialization_context.handles.mutable_handles());
+      mojo::Message::kFlagIsSync | mojo::Message::kFlagExpectsResponse, size,
+      &message);
   {{build_message(params_struct, "param_%s", params_description,
                   "&serialization_context", "&message")}}
 
@@ -188,9 +185,9 @@
 {%- else %}
   constexpr uint32_t kFlags = 0;
 {%- endif %}
-  mojo::Message message({{message_name}}, kFlags, size,
-                        serialization_context.associated_endpoint_count,
-                        serialization_context.handles.mutable_handles());
+  mojo::Message message;
+  serialization_context.PrepareMessage({{message_name}}, kFlags, size,
+                                       &message);
   {{build_message(params_struct, "in_%s", params_description,
                   "&serialization_context", "&message")}}
 
@@ -271,9 +268,8 @@
                                       "&serialization_context")}}
   uint32_t flags = (is_sync_ ? mojo::Message::kFlagIsSync : 0) |
                    mojo::Message::kFlagIsResponse;
-  mojo::Message message({{message_name}}, flags, size,
-                        serialization_context.associated_endpoint_count,
-                        serialization_context.handles.mutable_handles());
+  mojo::Message message;
+  serialization_context.PrepareMessage({{message_name}}, flags, size, &message);
   {{build_message(response_params_struct, "in_%s", params_description,
                   "&serialization_context", "&message")}}
   message.set_request_id(request_id_);
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl
index 3e43c88a..b61815f 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl
@@ -74,7 +74,7 @@
 {%-     set input_field = "in_%s"|format(name) if input_may_be_temp
                                                else original_input_field %}
 {%-     if input_may_be_temp %}
-{%-       if kind|is_associated_kind or kind|is_object_kind %}
+{%-       if kind|is_object_kind %}
   decltype({{original_input_field}}) in_{{name}} = {{original_input_field}};
 {%-       else %}
   // Dummy input value. The serialized value is already stored in the
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_declaration.tmpl
index 02af440..9fcb6ac 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_declaration.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_declaration.tmpl
@@ -12,7 +12,7 @@
   static size_t PrepareToSerialize(MaybeConstUserType& input,
                                    SerializationContext* context) {
     const bool is_null = CallIsNullIfExists<Traits>(input);
-    context->null_states.container().push_back(is_null);
+    context->PushNextNullState(is_null);
     if (is_null)
       return 0;
 
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_declaration.tmpl
index cc513c3..d16a07eb 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_declaration.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_declaration.tmpl
@@ -13,7 +13,7 @@
                                    SerializationContext* context) {
     size_t size = inlined ? 0 : sizeof({{data_type}});
     const bool is_null = CallIsNullIfExists<Traits>(input);
-    context->null_states.container().push_back(is_null);
+    context->PushNextNullState(is_null);
     if (is_null)
       return size;
 
diff --git a/mojo/public/tools/bindings/generators/mojom_cpp_generator.py b/mojo/public/tools/bindings/generators/mojom_cpp_generator.py
index a60389f6..4679f089a 100644
--- a/mojo/public/tools/bindings/generators/mojom_cpp_generator.py
+++ b/mojo/public/tools/bindings/generators/mojom_cpp_generator.py
@@ -400,16 +400,22 @@
   def _ConstantValue(self, constant):
     return self._ExpressionToText(constant.value, kind=constant.kind)
 
-  # TODO(yzshen): Revisit the default value feature. It was designed prior to
-  # custom type mapping.
   def _DefaultValue(self, field):
-    if field.default:
-      if mojom.IsStructKind(field.kind):
-        assert field.default == "default"
-        if not self._IsTypemappedKind(field.kind):
-          return "%s::New()" % self._GetNameForKind(field.kind)
-      return self._ExpressionToText(field.default, kind=field.kind)
-    return ""
+    if not field.default:
+      return ""
+
+    if mojom.IsStructKind(field.kind):
+      assert field.default == "default"
+      if self._IsTypemappedKind(field.kind):
+        return ""
+      return "%s::New()" % self._GetNameForKind(field.kind)
+
+    expression = self._ExpressionToText(field.default, kind=field.kind)
+    if mojom.IsEnumKind(field.kind) and self._IsTypemappedKind(field.kind):
+      expression = "mojo::internal::ConvertEnumValue<%s, %s>(%s)" % (
+          self._GetNameForKind(field.kind), self._GetCppWrapperType(field.kind),
+          expression)
+    return expression
 
   def _GetNameForKind(self, kind, internal=False, flatten_nested_kind=False,
                       add_same_module_namespaces=False):
diff --git a/net/dns/host_cache.cc b/net/dns/host_cache.cc
index ce95a31..460043f 100644
--- a/net/dns/host_cache.cc
+++ b/net/dns/host_cache.cc
@@ -342,7 +342,6 @@
   }
 }
 
-// TODO(mgersh): Add histograms to track failures.
 bool HostCache::RestoreFromListValue(const base::ListValue& old_cache) {
   for (auto it = old_cache.begin(); it != old_cache.end(); it++) {
     const base::DictionaryValue* entry_dict;
diff --git a/net/http/transport_security_state_static.json b/net/http/transport_security_state_static.json
index 36cfbe0..dcd7dde8 100644
--- a/net/http/transport_security_state_static.json
+++ b/net/http/transport_security_state_static.json
@@ -163,17 +163,9 @@
         "Entrust_G2",
         "Entrust_EV",
         "Entrust_2048",
-        "GeoTrustGlobal",
-        "GeoTrustPrimary_G2",
-        "GeoTrustPrimary_G3",
-        "GeoTrustPrimary",
         "TheGoDaddyGroupClass2",
         "GoDaddyRoot_G2",
-        "GoDaddySecure",
-        "ThawtePremiumServer",
-        "ThawtePrimaryRootCA_G2",
-        "ThawtePrimaryRootCA_G3",
-        "ThawtePrimaryRootCA"
+        "GoDaddySecure"
       ],
       "report_uri": "https://log.getdropbox.com/hpkp"
     },
diff --git a/net/http/transport_security_state_static.pins b/net/http/transport_security_state_static.pins
index 23cb802..52ccb69 100644
--- a/net/http/transport_security_state_static.pins
+++ b/net/http/transport_security_state_static.pins
@@ -1299,99 +1299,6 @@
 U+4=
 -----END CERTIFICATE-----
 
-ThawtePremiumServer
------BEGIN CERTIFICATE-----
-MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkEx
-FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD
-VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv
-biBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFByZW1pdW0gU2Vy
-dmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZlckB0aGF3dGUuY29t
-MB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYTAlpB
-MRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsG
-A1UEChMUVGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRp
-b24gU2VydmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNl
-cnZlciBDQTEoMCYGCSqGSIb3DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNv
-bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkE
-VdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQ
-ug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMR
-uHM/qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG
-9w0BAQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUI
-hfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JM
-pAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcUQg==
------END CERTIFICATE-----
-
-ThawtePrimaryRootCA_G2
------BEGIN CERTIFICATE-----
-MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDEL
-MAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMp
-IDIwMDcgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAi
-BgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMjAeFw0wNzExMDUwMDAw
-MDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh
-d3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBGb3Ig
-YXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9v
-dCBDQSAtIEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/
-BebfowJPDQfGAFG6DAJSLSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6
-papu+7qzcMBniKI11KOasf2twu8x+qi58/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8E
-BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUmtgAMADna3+FGO6Lts6K
-DPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUNG4k8VIZ3
-KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41ox
-XZ3Krr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg==
------END CERTIFICATE-----
-
-ThawtePrimaryRootCA_G3
------BEGIN CERTIFICATE-----
-MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCB
-rjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf
-Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw
-MDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNV
-BAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0wODA0MDIwMDAwMDBa
-Fw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhhd3Rl
-LCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9u
-MTgwNgYDVQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXpl
-ZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEcz
-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsr8nLPvb2FvdeHsbnndm
-gcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2AtP0LMqmsywCPLLEHd5N/8
-YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC+BsUa0Lf
-b1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS9
-9irY7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2S
-zhkGcuYMXDhpxwTWvGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUk
-OQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV
-HQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJKoZIhvcNAQELBQADggEBABpA
-2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweKA3rD6z8KLFIW
-oCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu
-t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7c
-KUGRIjxpp7sC8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fM
-m7v/OeZWYdMKp8RcTGB7BXcmer/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZu
-MdRAGmI0Nj81Aa6sY6A=
------END CERTIFICATE-----
-
-ThawtePrimaryRootCA
------BEGIN CERTIFICATE-----
-MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCB
-qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf
-Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw
-MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV
-BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3MDAwMDAwWhcNMzYw
-NzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5j
-LjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYG
-A1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl
-IG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqG
-SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsoPD7gFnUnMekz52hWXMJEEUMDSxuaPFs
-W0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ1CRfBsDMRJSUjQJib+ta
-3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGcq/gcfomk
-6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6
-Sk/KaAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94J
-NqR32HuHUETVPm4pafs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBA
-MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XP
-r87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUFAAOCAQEAeRHAS7ORtvzw6WfU
-DW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeEuzLlQRHAd9mz
-YJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX
-xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2
-/qxAeeWsEG89jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/
-LHbTY5xZ3Y+m4Q6gLkH3LpVHz7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7
-jVaMaA==
------END CERTIFICATE-----
-
 SymantecClass3EVG3
 -----BEGIN CERTIFICATE-----
 MIIFKzCCBBOgAwIBAgIQfuFKb2/v8tN/P61lTTratDANBgkqhkiG9w0BAQsFADCB
diff --git a/net/log/net_log_event_type_list.h b/net/log/net_log_event_type_list.h
index eb4ac8c5..4570eaa 100644
--- a/net/log/net_log_event_type_list.h
+++ b/net/log/net_log_event_type_list.h
@@ -3208,3 +3208,22 @@
 //    "version": <The version number>,
 //  }
 EVENT_TYPE(HTTP_SERVER_PROPERTIES_UPDATE_PREFS)
+
+// -----------------------------------------------------------------------------
+// HostCachePersistenceManager related events
+// -----------------------------------------------------------------------------
+
+// The start/end of getting the persisted HostCache value and restoring it.
+// The END phase contains the following parameters:
+//  {
+//    "success": <Whether the persisted HostCache was restored successfully>,
+//  }
+EVENT_TYPE(HOST_CACHE_PREF_READ)
+
+// This event is created when the HostCachePersistenceManager writes the cache
+// contents to prefs.
+EVENT_TYPE(HOST_CACHE_PREF_WRITE)
+
+// This event is created when the HostCachePersistenceManager starts the timer
+// for writing a cache change to prefs.
+EVENT_TYPE(HOST_CACHE_PERSISTENCE_START_TIMER)
diff --git a/net/log/net_log_source_type_list.h b/net/log/net_log_source_type_list.h
index e82c20ee..390e463 100644
--- a/net/log/net_log_source_type_list.h
+++ b/net/log/net_log_source_type_list.h
@@ -42,3 +42,4 @@
 SOURCE_TYPE(SERVER_PUSH_LOOKUP_TRANSACTION)
 SOURCE_TYPE(QUIC_STREAM_FACTORY_JOB)
 SOURCE_TYPE(HTTP_SERVER_PROPERTIES)
+SOURCE_TYPE(HOST_CACHE_PERSISTENCE_MANAGER)
diff --git a/net/nqe/network_quality_estimator.cc b/net/nqe/network_quality_estimator.cc
index 4ec8970..c0316253 100644
--- a/net/nqe/network_quality_estimator.cc
+++ b/net/nqe/network_quality_estimator.cc
@@ -1029,6 +1029,43 @@
   }
 }
 
+void NetworkQualityEstimator::ComputeBandwidthDelayProduct() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  // Reset the bandwidth delay product to prevent stale values being returned.
+  bandwidth_delay_product_kbits_.reset();
+
+  // Record the bandwidth delay product (BDP) from the 80 percentile throughput
+  // and the 20 percentile transport RTT. Percentiles are reversed for
+  // throughput. The reason for using the 20 percentile transport RTT is to get
+  // an estimate of the true RTT sans the queueing delay. The minimum value of
+  // transport RTT was not used because it is likely to be noisy. For
+  // throughput, the 80 percentile value is considered to get an estimate of the
+  // maximum bandwidth when there is no congestion. The maximum value of
+  // observed throughput was not used because it is likely to be noisy.
+  base::TimeDelta transport_rtt = GetRTTEstimateInternal(
+      disallowed_observation_sources_for_transport_, base::TimeTicks(),
+      base::Optional<Statistic>(), 20);
+  if (transport_rtt == nqe::internal::InvalidRTT())
+    return;
+
+  int32_t downlink_throughput_kbps =
+      GetDownlinkThroughputKbpsEstimateInternal(base::TimeTicks(), 20);
+  if (downlink_throughput_kbps == nqe::internal::kInvalidThroughput)
+    return;
+
+  bandwidth_delay_product_kbits_ =
+      (downlink_throughput_kbps * transport_rtt.InMilliseconds()) / 1000;
+
+  // Record UMA histograms.
+  UMA_HISTOGRAM_TIMES("NQE.BDPComputationTransportRTT.OnECTComputation",
+                      transport_rtt);
+  UMA_HISTOGRAM_COUNTS_1M("NQE.BDPComputationKbps.OnECTComputation",
+                          downlink_throughput_kbps);
+  UMA_HISTOGRAM_COUNTS_1M("NQE.BDPKbits.OnECTComputation",
+                          bandwidth_delay_product_kbits_.value());
+}
+
 void NetworkQualityEstimator::ComputeEffectiveConnectionType() {
   DCHECK(thread_checker_.CalledOnValidThread());
 
@@ -1050,6 +1087,7 @@
 
   network_quality_ = nqe::internal::NetworkQuality(http_rtt, transport_rtt,
                                                    downstream_throughput_kbps);
+  ComputeBandwidthDelayProduct();
 
   UMA_HISTOGRAM_ENUMERATION("NQE.EffectiveConnectionType.OnECTComputation",
                             effective_connection_type_,
@@ -1776,6 +1814,12 @@
   return network_quality_.downstream_throughput_kbps();
 }
 
+base::Optional<int32_t> NetworkQualityEstimator::GetBandwidthDelayProductKbits()
+    const {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  return bandwidth_delay_product_kbits_;
+}
+
 void NetworkQualityEstimator::MaybeUpdateNetworkQualityFromCache(
     const nqe::internal::NetworkID& network_id,
     const nqe::internal::CachedNetworkQuality& cached_network_quality) {
diff --git a/net/nqe/network_quality_estimator.h b/net/nqe/network_quality_estimator.h
index 75e74ab..8e11c18 100644
--- a/net/nqe/network_quality_estimator.h
+++ b/net/nqe/network_quality_estimator.h
@@ -132,6 +132,7 @@
   base::Optional<base::TimeDelta> GetHttpRTT() const override;
   base::Optional<base::TimeDelta> GetTransportRTT() const override;
   base::Optional<int32_t> GetDownstreamThroughputKbps() const override;
+  base::Optional<int32_t> GetBandwidthDelayProductKbits() const override;
   void AddRTTAndThroughputEstimatesObserver(
       RTTAndThroughputEstimatesObserver* observer) override;
   void RemoveRTTAndThroughputEstimatesObserver(
@@ -358,6 +359,7 @@
                            OnPrefsReadWithReadingDisabled);
   FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest,
                            ForceEffectiveConnectionTypeThroughFieldTrial);
+  FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, TestBDPComputation);
 
   // Value of round trip time observations is in base::TimeDelta.
   typedef nqe::internal::Observation<base::TimeDelta> RttObservation;
@@ -496,6 +498,11 @@
   // connection type.
   bool UseTransportRTT() const;
 
+  // Computes the bandwidth delay product in kilobits. The computed value is
+  // stored in |bandwidth_delay_product_kbits_| and can be accessed using
+  // |GetBandwidthDelayProductKbits|.
+  void ComputeBandwidthDelayProduct();
+
   // Forces computation of effective connection type, and notifies observers
   // if there is a change in its value.
   void ComputeEffectiveConnectionType();
@@ -603,6 +610,9 @@
   // Current estimate of the network quality.
   nqe::internal::NetworkQuality network_quality_;
 
+  // Current estimate of the bandwidth delay product (BDP) in kilobits.
+  base::Optional<int32_t> bandwidth_delay_product_kbits_;
+
   // Current effective connection type. It is updated on connection change
   // events. It is also updated every time there is network traffic (provided
   // the last computation was more than
diff --git a/net/nqe/network_quality_estimator_unittest.cc b/net/nqe/network_quality_estimator_unittest.cc
index 8fad54c..b5202e3a 100644
--- a/net/nqe/network_quality_estimator_unittest.cc
+++ b/net/nqe/network_quality_estimator_unittest.cc
@@ -7,6 +7,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#include <cmath>
 #include <limits>
 #include <map>
 #include <memory>
@@ -3073,4 +3074,40 @@
       &effective_connection_type_observer);
 }
 
+// Tests that |ComputeBandwidthDelayProduct| calculates the
+// BDP correctly and records histogram data.
+TEST(NetworkQualityEstimatorTest, TestBDPComputation) {
+  TestNetworkQualityEstimator estimator;
+  base::HistogramTester histogram_tester;
+  base::TimeTicks now = base::TimeTicks::Now();
+  for (int i = 1; i <= std::pow(2, 10); i *= 2) {
+    estimator.rtt_observations_.AddObservation(
+        NetworkQualityEstimator::RttObservation(
+            base::TimeDelta::FromMilliseconds(i), now, INT32_MIN,
+            NETWORK_QUALITY_OBSERVATION_SOURCE_TCP));
+  }
+  for (int i = 1; i <= std::pow(3, 10); i *= 3) {
+    estimator.downstream_throughput_kbps_observations_.AddObservation(
+        NetworkQualityEstimator::ThroughputObservation(
+            i, now, INT32_MIN, NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP));
+  }
+  estimator.RunOneRequest();
+
+  // Histograms must contain at least one entry each.
+  EXPECT_GE(
+      1u, histogram_tester
+              .GetAllSamples("NQE.BDPComputationTransportRTT.OnECTComputation")
+              .size());
+  EXPECT_GE(1u, histogram_tester
+                    .GetAllSamples("NQE.BDPComputationKbps.OnECTComputation")
+                    .size());
+  EXPECT_GE(
+      1u,
+      histogram_tester.GetAllSamples("NQE.BDPKbits.OnECTComputation").size());
+
+  EXPECT_TRUE(estimator.GetBandwidthDelayProductKbits().has_value());
+  EXPECT_EQ(estimator.GetBandwidthDelayProductKbits().value(),
+            (int32_t)(std::pow(2, 2) * std::pow(3, 8) / 1000));
+}
+
 }  // namespace net
diff --git a/net/nqe/network_quality_provider.cc b/net/nqe/network_quality_provider.cc
index 030e0d8..58a8757 100644
--- a/net/nqe/network_quality_provider.cc
+++ b/net/nqe/network_quality_provider.cc
@@ -20,4 +20,9 @@
   return base::Optional<int32_t>();
 }
 
-}  // namespace net
\ No newline at end of file
+base::Optional<int32_t> NetworkQualityProvider::GetBandwidthDelayProductKbits()
+    const {
+  return base ::Optional<int32_t>();
+}
+
+}  // namespace net
diff --git a/net/nqe/network_quality_provider.h b/net/nqe/network_quality_provider.h
index 47eca71..9dd1432 100644
--- a/net/nqe/network_quality_provider.h
+++ b/net/nqe/network_quality_provider.h
@@ -56,6 +56,12 @@
   // null.
   virtual base::Optional<int32_t> GetDownstreamThroughputKbps() const;
 
+  // Returns the current bandwidth delay product estimate (in kilobits). If the
+  // estimate is not available, the returned optional value is null. The
+  // bandwidth delay product is calculated from the transport RTT and the
+  // downlink bandwidth estimates.
+  virtual base::Optional<int32_t> GetBandwidthDelayProductKbits() const;
+
   // Adds |observer| to the list of RTT and throughput estimate observers.
   // The observer must register and unregister itself on the same thread.
   // |observer| would be notified on the thread on which it registered.
@@ -78,4 +84,4 @@
 
 }  // namespace net
 
-#endif  // NET_NQE_NETWORK_QUALITY_PROVIDER_H_
\ No newline at end of file
+#endif  // NET_NQE_NETWORK_QUALITY_PROVIDER_H_
diff --git a/net/proxy/proxy_config_service_linux.cc b/net/proxy/proxy_config_service_linux.cc
index bf852420..5b7dc7a5 100644
--- a/net/proxy/proxy_config_service_linux.cc
+++ b/net/proxy/proxy_config_service_linux.cc
@@ -856,6 +856,15 @@
 }
 #endif  // defined(USE_GIO)
 
+// Converts |value| from a decimal string to an int. If there was a failure
+// parsing, returns |default_value|.
+int StringToIntOrDefault(base::StringPiece value, int default_value) {
+  int result;
+  if (base::StringToInt(value, &result))
+    return result;
+  return default_value;
+}
+
 // This is the KDE version that reads kioslaverc and simulates gconf.
 // Doing this allows the main Delegate code, as well as the unit tests
 // for it, to stay the same - and the settings map fairly well besides.
@@ -1088,11 +1097,8 @@
       const char* mode = "none";
       indirect_manual_ = false;
       auto_no_pac_ = false;
-      int int_value;
-      base::StringToInt(value, &int_value);
+      int int_value = StringToIntOrDefault(value, 0);
       switch (int_value) {
-        case 0:  // No proxy, or maybe kioslaverc syntax error.
-          break;
         case 1:  // Manual configuration.
           mode = "manual";
           break;
@@ -1107,6 +1113,8 @@
           mode = "manual";
           indirect_manual_ = true;
           break;
+        default:  // No proxy, or maybe kioslaverc syntax error.
+          break;
       }
       string_table_[PROXY_MODE] = mode;
     } else if (key == "Proxy Config Script") {
@@ -1124,17 +1132,14 @@
       AddProxy(PROXY_SOCKS_HOST, value);
     } else if (key == "ReversedException") {
       // We count "true" or any nonzero number as true, otherwise false.
-      // Note that if the value is not actually numeric StringToInt()
-      // will return 0, which we count as false.
-      int int_value;
-      base::StringToInt(value, &int_value);
-      reversed_bypass_list_ = (value == "true" || int_value);
+      // A failure parsing the integer will also mean false.
+      reversed_bypass_list_ =
+          (value == "true" || StringToIntOrDefault(value, 0) != 0);
     } else if (key == "NoProxyFor") {
       AddHostList(PROXY_IGNORE_HOSTS, value);
     } else if (key == "AuthMode") {
       // Check for authentication, just so we can warn.
-      int mode;
-      base::StringToInt(value, &mode);
+      int mode = StringToIntOrDefault(value, 0);
       if (mode) {
         // ProxyConfig does not support authentication parameters, but
         // Chrome will prompt for the password later. So we ignore this.
diff --git a/net/proxy/proxy_config_service_linux_unittest.cc b/net/proxy/proxy_config_service_linux_unittest.cc
index 6650825a..0bda1a45 100644
--- a/net/proxy/proxy_config_service_linux_unittest.cc
+++ b/net/proxy/proxy_config_service_linux_unittest.cc
@@ -29,6 +29,8 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 
+// TODO(eroman): Convert these to parameterized tests using TEST_P().
+
 namespace net {
 namespace {
 
@@ -1157,6 +1159,33 @@
           GURL(),  // pac_url
           ProxyRulesExpectation::Empty(),
       },
+      {
+          TEST_DESC("Invalid proxy type (ProxyType=-3)"),
+
+          // Input.
+          "[Proxy Settings]\nProxyType=-3\n",
+          {},  // env_values
+
+          // Expected result.
+          ProxyConfigService::CONFIG_VALID,
+          false,   // auto_detect
+          GURL(),  // pac_url
+          ProxyRulesExpectation::Empty(),
+      },
+
+      {
+          TEST_DESC("Invalid proxy type (ProxyType=AB-)"),
+
+          // Input.
+          "[Proxy Settings]\nProxyType=AB-\n",
+          {},  // env_values
+
+          // Expected result.
+          ProxyConfigService::CONFIG_VALID,
+          false,   // auto_detect
+          GURL(),  // pac_url
+          ProxyRulesExpectation::Empty(),
+      },
 
       {
           TEST_DESC("Auto detect"),
@@ -1313,7 +1342,7 @@
       },
 
       {
-          TEST_DESC("Correctly parse bypass list with ReversedException"),
+          TEST_DESC("Correctly parse bypass list with ReversedException=true"),
 
           // Input.
           "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com\n"
@@ -1332,6 +1361,79 @@
       },
 
       {
+          TEST_DESC("Correctly parse bypass list with ReversedException=false"),
+
+          // Input.
+          "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com\n"
+          "NoProxyFor=.google.com\nReversedException=false\n",
+          {},  // env_values
+
+          // Expected result.
+          ProxyConfigService::CONFIG_VALID,
+          false,                                                 // auto_detect
+          GURL(),                                                // pac_url
+          ProxyRulesExpectation::PerScheme("www.google.com:80",  // http
+                                           "",                   // https
+                                           "",                   // ftp
+                                           "*.google.com"),      // bypass rules
+      },
+
+      {
+          TEST_DESC("Correctly parse bypass list with ReversedException=1"),
+
+          // Input.
+          "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com\n"
+          "NoProxyFor=.google.com\nReversedException=1\n",
+          {},  // env_values
+
+          // Expected result.
+          ProxyConfigService::CONFIG_VALID,
+          false,   // auto_detect
+          GURL(),  // pac_url
+          ProxyRulesExpectation::PerSchemeWithBypassReversed(
+              "www.google.com:80",  // http
+              "",                   // https
+              "",                   // ftp
+              "*.google.com"),      // bypass rules
+      },
+
+      {
+          TEST_DESC("Overflow: ReversedException=18446744073709551617"),
+
+          // Input.
+          "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com\n"
+          "NoProxyFor=.google.com\nReversedException=18446744073709551617\n",
+          {},  // env_values
+
+          // Expected result.
+          ProxyConfigService::CONFIG_VALID,
+          false,                                                 // auto_detect
+          GURL(),                                                // pac_url
+          ProxyRulesExpectation::PerScheme("www.google.com:80",  // http
+                                           "",                   // https
+                                           "",                   // ftp
+                                           "*.google.com"),      // bypass rules
+      },
+
+      {
+          TEST_DESC("Not a number: ReversedException=noitpecxE"),
+
+          // Input.
+          "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com\n"
+          "NoProxyFor=.google.com\nReversedException=noitpecxE\n",
+          {},  // env_values
+
+          // Expected result.
+          ProxyConfigService::CONFIG_VALID,
+          false,                                                 // auto_detect
+          GURL(),                                                // pac_url
+          ProxyRulesExpectation::PerScheme("www.google.com:80",  // http
+                                           "",                   // https
+                                           "",                   // ftp
+                                           "*.google.com"),      // bypass rules
+      },
+
+      {
           TEST_DESC("socks"),
 
           // Input.
diff --git a/net/quic/chromium/quic_network_transaction_unittest.cc b/net/quic/chromium/quic_network_transaction_unittest.cc
index 9548757..f371dc1b 100644
--- a/net/quic/chromium/quic_network_transaction_unittest.cc
+++ b/net/quic/chromium/quic_network_transaction_unittest.cc
@@ -239,6 +239,7 @@
  protected:
   QuicNetworkTransactionTest()
       : version_(GetParam()),
+        supported_versions_(SupportedVersions(version_)),
         client_maker_(version_,
                       0,
                       &clock_,
@@ -538,7 +539,7 @@
     session_->quic_stream_factory()->set_require_confirmation(false);
   }
 
-  void CreateSession() { return CreateSession(SupportedVersions(version_)); }
+  void CreateSession() { return CreateSession(supported_versions_); }
 
   void CheckWasQuicResponse(HttpNetworkTransaction* trans) {
     const HttpResponseInfo* response = trans->GetResponseInfo();
@@ -626,8 +627,7 @@
     AlternativeService alternative_service(kProtoQUIC, server.host(), 443);
     base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
     http_server_properties_.SetQuicAlternativeService(
-        server, alternative_service, expiration,
-        HttpNetworkSession::Params().quic_supported_versions);
+        server, alternative_service, expiration, supported_versions_);
   }
 
   void AddQuicRemoteAlternativeServiceMapping(
@@ -639,8 +639,7 @@
                                            alternative.port());
     base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
     http_server_properties_.SetQuicAlternativeService(
-        server, alternative_service, expiration,
-        HttpNetworkSession::Params().quic_supported_versions);
+        server, alternative_service, expiration, supported_versions_);
   }
 
   void ExpectBrokenAlternateProtocolMapping() {
@@ -748,6 +747,7 @@
   }
 
   const QuicVersion version_;
+  QuicVersionVector supported_versions_;
   QuicFlagSaver flags_;  // Save/restore all QUIC flag values.
   MockClock clock_;
   QuicTestPacketMaker client_maker_;
@@ -1204,8 +1204,7 @@
                                          443);
   base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
   http_server_properties_.SetQuicAlternativeService(
-      server, alternative_service, expiration,
-      HttpNetworkSession::Params().quic_supported_versions);
+      server, alternative_service, expiration, supported_versions_);
 
   // First try: The alternative job uses QUIC and reports an HTTP 421
   // Misdirected Request error.  The main job uses TCP, but |http_data| below is
@@ -1467,6 +1466,14 @@
 
 TEST_P(QuicNetworkTransactionTest,
        StoreMutuallySupportedVersionsWhenProcessAltSvc) {
+  // Add support for another QUIC version besides |version_|.
+  for (const QuicVersion& version : AllSupportedVersions()) {
+    if (version == version_)
+      continue;
+    supported_versions_.push_back(version);
+    break;
+  }
+
   std::string advertised_versions_list_str =
       GenerateQuicVersionsListForAltSvcHeader(AllSupportedVersions());
   std::string altsvc_header =
@@ -1503,15 +1510,7 @@
 
   AddHangingNonAlternateProtocolSocketData();
 
-  // Generate a list of QUIC versions suppored by netstack.
-  QuicVersionVector current_supported_versions = SupportedVersions(version_);
-  if (version_ != QUIC_VERSION_40) {
-    current_supported_versions.push_back(QUIC_VERSION_40);
-  } else {
-    current_supported_versions.push_back(QUIC_VERSION_37);
-  }
-
-  CreateSession(current_supported_versions);
+  CreateSession(supported_versions_);
 
   SendRequestAndExpectHttpResponse("hello world");
   SendRequestAndExpectQuicResponse("hello!");
@@ -1525,11 +1524,10 @@
   EXPECT_EQ(kProtoQUIC, alt_svc_info_vector[0].alternative_service().protocol);
   EXPECT_EQ(2u, alt_svc_info_vector[0].advertised_versions().size());
   // Advertised versions will be lised in a sorted order.
-  std::sort(current_supported_versions.begin(),
-            current_supported_versions.end());
-  EXPECT_EQ(current_supported_versions[0],
+  std::sort(supported_versions_.begin(), supported_versions_.end());
+  EXPECT_EQ(supported_versions_[0],
             alt_svc_info_vector[0].advertised_versions()[0]);
-  EXPECT_EQ(current_supported_versions[1],
+  EXPECT_EQ(supported_versions_[1],
             alt_svc_info_vector[0].advertised_versions()[1]);
 }
 
@@ -2865,14 +2863,14 @@
   http_server_properties_.SetQuicAlternativeService(
       url::SchemeHostPort(origin1),
       AlternativeService(kProtoQUIC, "mail.example.com", 443), expiration,
-      HttpNetworkSession::Params().quic_supported_versions);
+      supported_versions_);
 
   // Set up alternative service for |origin2|.
   AlternativeServiceInfoVector alternative_services;
   http_server_properties_.SetQuicAlternativeService(
       url::SchemeHostPort(origin2),
       AlternativeService(kProtoQUIC, "www.example.com", 443), expiration,
-      HttpNetworkSession::Params().quic_supported_versions);
+      supported_versions_);
   // First request opens connection to |destination1|
   // with QuicServerId.host() == origin1.host().
   SendRequestAndExpectQuicResponse("hello!");
@@ -3096,8 +3094,7 @@
   AlternativeService alternative_service(kProtoQUIC, destination1, 443);
   base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
   http_server_properties_.SetQuicAlternativeService(
-      server, alternative_service, expiration,
-      HttpNetworkSession::Params().quic_supported_versions);
+      server, alternative_service, expiration, supported_versions_);
   // First request opens connection to |destination1|
   // with QuicServerId.host() == kDefaultServerHostName.
   SendRequestAndExpectQuicResponse("hello!");
@@ -3105,8 +3102,7 @@
   // Set up alternative service entry to a different destination.
   alternative_service = AlternativeService(kProtoQUIC, destination2, 443);
   http_server_properties_.SetQuicAlternativeService(
-      server, alternative_service, expiration,
-      HttpNetworkSession::Params().quic_supported_versions);
+      server, alternative_service, expiration, supported_versions_);
   // Second request pools to existing connection with same QuicServerId,
   // even though alternative service destination is different.
   SendRequestAndExpectQuicResponse("hello!");
@@ -3171,7 +3167,7 @@
   base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
   http_server_properties_.SetQuicAlternativeService(
       url::SchemeHostPort(origin1), alternative_service1, expiration,
-      HttpNetworkSession::Params().quic_supported_versions);
+      supported_versions_);
 
   // Set up multiple alternative service entries for |origin2|,
   // the first one with a different destination as for |origin1|,
@@ -4691,6 +4687,7 @@
  protected:
   QuicNetworkTransactionWithDestinationTest()
       : version_(GetParam().version),
+        supported_versions_(SupportedVersions(version_)),
         destination_type_(GetParam().destination_type),
         cert_transparency_verifier_(new MultiLogCTVerifier()),
         ssl_config_service_(new SSLConfigServiceDefaults),
@@ -4706,7 +4703,7 @@
 
     HttpNetworkSession::Params session_params;
     session_params.enable_quic = true;
-    session_params.quic_supported_versions = SupportedVersions(version_);
+    session_params.quic_supported_versions = supported_versions_;
 
     HttpNetworkSession::Context session_context;
 
@@ -4764,7 +4761,7 @@
     base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
     http_server_properties_.SetQuicAlternativeService(
         url::SchemeHostPort("https", origin, 443), alternative_service,
-        expiration, session_->params().quic_supported_versions);
+        expiration, supported_versions_);
   }
 
   std::unique_ptr<QuicEncryptedPacket> ConstructClientRequestHeadersPacket(
@@ -4895,6 +4892,7 @@
 
   MockClock clock_;
   QuicVersion version_;
+  QuicVersionVector supported_versions_;
   DestinationType destination_type_;
   std::string origin1_;
   std::string origin2_;
diff --git a/net/quic/core/quic_framer.cc b/net/quic/core/quic_framer.cc
index 8433719..f5d771c 100644
--- a/net/quic/core/quic_framer.cc
+++ b/net/quic/core/quic_framer.cc
@@ -1316,7 +1316,10 @@
     set_detailed_error("Unable to read least unacked delta.");
     return false;
   }
-  DCHECK_GE(header.packet_number, least_unacked_delta);
+  if (header.packet_number < least_unacked_delta) {
+    set_detailed_error("Invalid unacked delta.");
+    return false;
+  }
   stop_waiting->least_unacked = header.packet_number - least_unacked_delta;
 
   return true;
diff --git a/net/quic/core/quic_framer_test.cc b/net/quic/core/quic_framer_test.cc
index ed3979b..34337fa 100644
--- a/net/quic/core/quic_framer_test.cc
+++ b/net/quic/core/quic_framer_test.cc
@@ -2079,6 +2079,47 @@
   }
 }
 
+TEST_P(QuicFramerTest, InvalidNewStopWaitingFrame) {
+  // clang-format off
+  unsigned char packet[] = {
+    // public flags (8 byte connection_id)
+    0x3C,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0xA8, 0x9A, 0x78, 0x56,
+    0x34, 0x12,
+    // frame type (stop waiting frame)
+    0x06,
+    // least packet number awaiting an ack, delta from packet number.
+    0xA8, 0x9A, 0x78, 0x56,
+    0x34, 0x13,
+  };
+
+  unsigned char packet39[] = {
+    // public flags (8 byte connection_id)
+    0x3C,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+    0x9A, 0xA8,
+    // frame type (stop waiting frame)
+    0x06,
+    // least packet number awaiting an ack, delta from packet number.
+    0x13, 0x34, 0x56, 0x78,
+    0x9A, 0xA8,
+  };
+  // clang-format on
+
+  QuicEncryptedPacket encrypted(
+      AsChars(framer_.version() <= QUIC_VERSION_38 ? packet : packet39),
+      arraysize(packet), false);
+  EXPECT_FALSE(framer_.ProcessPacket(encrypted));
+  EXPECT_EQ(QUIC_INVALID_STOP_WAITING_DATA, framer_.error());
+  EXPECT_EQ("Invalid unacked delta.", framer_.detailed_error());
+}
+
 TEST_P(QuicFramerTest, RstStreamFrameQuic) {
   // clang-format off
   unsigned char packet[] = {
diff --git a/net/socket/ssl_client_socket.cc b/net/socket/ssl_client_socket.cc
index 2ace6e76..02f2887 100644
--- a/net/socket/ssl_client_socket.cc
+++ b/net/socket/ssl_client_socket.cc
@@ -38,6 +38,10 @@
          IsCertificateError(error);
 }
 
+SSLErrorDetails SSLClientSocket::GetConnectErrorDetails() const {
+  return SSLErrorDetails::kOther;
+}
+
 // static
 std::vector<uint8_t> SSLClientSocket::SerializeNextProtos(
     const NextProtoVector& next_protos) {
diff --git a/net/socket/ssl_client_socket.h b/net/socket/ssl_client_socket.h
index 89ac601..c59c369 100644
--- a/net/socket/ssl_client_socket.h
+++ b/net/socket/ssl_client_socket.h
@@ -66,6 +66,32 @@
   const std::string ssl_session_cache_shard;
 };
 
+// Details on a failed operation. This enum is used to diagnose causes of TLS
+// version interference by buggy middleboxes. The values are histogramed so they
+// must not be changed.
+enum class SSLErrorDetails {
+  kOther = 0,
+  // The failure was due to ERR_CONNECTION_CLOSED. BlueCoat has a bug with this
+  // failure mode. https://crbug.com/694593.
+  kConnectionClosed = 1,
+  // The failure was due to ERR_CONNECTION_RESET.
+  kConnectionReset = 2,
+  // The failure was due to receiving an access_denied alert. Fortinet has a
+  // bug with this failure mode. https://crbug.com/676969.
+  kAccessDeniedAlert = 3,
+  // The failure was due to receiving a bad_record_mac alert.
+  kBadRecordMACAlert = 4,
+  // The failure was due to receiving an unencrypted application_data record
+  // during the handshake. Watchguard has a bug with this failure
+  // mode. https://crbug.com/733223.
+  kApplicationDataInsteadOfHandshake = 5,
+  // The failure was due to failing to negotiate a version or cipher suite.
+  kVersionOrCipherMismatch = 6,
+  // The failure was due to some other protocol error.
+  kProtocolError = 7,
+  kLastValue = kProtocolError,
+};
+
 // A client socket that uses SSL as the transport layer.
 //
 // NOTE: The SSL handshake occurs within the Connect method after a TCP
@@ -116,6 +142,10 @@
   // establishing the connection (or NULL if no channel ID was used).
   virtual crypto::ECPrivateKey* GetChannelIDKey() const = 0;
 
+  // Returns details for a failed Connect() operation. This method is used to
+  // track causes of TLS version interference by buggy middleboxes.
+  virtual SSLErrorDetails GetConnectErrorDetails() const;
+
  protected:
   void set_signed_cert_timestamps_received(
       bool signed_cert_timestamps_received) {
diff --git a/net/socket/ssl_client_socket_impl.cc b/net/socket/ssl_client_socket_impl.cc
index a47ff3e7a..ca33573 100644
--- a/net/socket/ssl_client_socket_impl.cc
+++ b/net/socket/ssl_client_socket_impl.cc
@@ -491,6 +491,7 @@
       transport_security_state_(context.transport_security_state),
       policy_enforcer_(context.ct_policy_enforcer),
       pkp_bypassed_(false),
+      connect_error_details_(SSLErrorDetails::kOther),
       net_log_(transport_->socket()->NetLog()),
       weak_factory_(this) {
   CHECK(cert_verifier_);
@@ -581,6 +582,10 @@
   return channel_id_key_.get();
 }
 
+SSLErrorDetails SSLClientSocketImpl::GetConnectErrorDetails() const {
+  return connect_error_details_;
+}
+
 int SSLClientSocketImpl::ExportKeyingMaterial(const base::StringPiece& label,
                                               bool has_context,
                                               const base::StringPiece& context,
@@ -1068,6 +1073,38 @@
       return ERR_IO_PENDING;
     }
 
+    switch (net_error) {
+      case ERR_CONNECTION_CLOSED:
+        connect_error_details_ = SSLErrorDetails::kConnectionClosed;
+        break;
+      case ERR_CONNECTION_RESET:
+        connect_error_details_ = SSLErrorDetails::kConnectionReset;
+        break;
+      case ERR_SSL_PROTOCOL_ERROR: {
+        int lib = ERR_GET_LIB(error_info.error_code);
+        int reason = ERR_GET_REASON(error_info.error_code);
+        if (lib == ERR_LIB_SSL && reason == SSL_R_TLSV1_ALERT_ACCESS_DENIED) {
+          connect_error_details_ = SSLErrorDetails::kAccessDeniedAlert;
+        } else if (lib == ERR_LIB_SSL &&
+                   reason == SSL_R_APPLICATION_DATA_INSTEAD_OF_HANDSHAKE) {
+          connect_error_details_ =
+              SSLErrorDetails::kApplicationDataInsteadOfHandshake;
+        } else {
+          connect_error_details_ = SSLErrorDetails::kProtocolError;
+        }
+        break;
+      }
+      case ERR_SSL_BAD_RECORD_MAC_ALERT:
+        connect_error_details_ = SSLErrorDetails::kBadRecordMACAlert;
+        break;
+      case ERR_SSL_VERSION_OR_CIPHER_MISMATCH:
+        connect_error_details_ = SSLErrorDetails::kVersionOrCipherMismatch;
+        break;
+      default:
+        connect_error_details_ = SSLErrorDetails::kOther;
+        break;
+    }
+
     LOG(ERROR) << "handshake failed; returned " << rv << ", SSL error code "
                << ssl_error << ", net_error " << net_error;
     net_log_.AddEvent(
diff --git a/net/socket/ssl_client_socket_impl.h b/net/socket/ssl_client_socket_impl.h
index 51ee5fc..eae76954 100644
--- a/net/socket/ssl_client_socket_impl.h
+++ b/net/socket/ssl_client_socket_impl.h
@@ -14,6 +14,7 @@
 
 #include "base/compiler_specific.h"
 #include "base/containers/mru_cache.h"
+#include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "build/build_config.h"
@@ -91,6 +92,7 @@
                                  TokenBindingType tb_type,
                                  std::vector<uint8_t>* out) override;
   crypto::ECPrivateKey* GetChannelIDKey() const override;
+  SSLErrorDetails GetConnectErrorDetails() const override;
 
   // SSLSocket implementation.
   int ExportKeyingMaterial(const base::StringPiece& label,
@@ -352,8 +354,12 @@
   // True if PKP is bypassed due to a local trust anchor.
   bool pkp_bypassed_;
 
+  SSLErrorDetails connect_error_details_;
+
   NetLogWithSource net_log_;
   base::WeakPtrFactory<SSLClientSocketImpl> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(SSLClientSocketImpl);
 };
 
 }  // namespace net
diff --git a/net/socket/ssl_client_socket_pool.cc b/net/socket/ssl_client_socket_pool.cc
index 7fdf3ad..3fabcf8f 100644
--- a/net/socket/ssl_client_socket_pool.cc
+++ b/net/socket/ssl_client_socket_pool.cc
@@ -134,7 +134,8 @@
       callback_(
           base::Bind(&SSLConnectJob::OnIOComplete, base::Unretained(this))),
       version_interference_probe_(false),
-      version_interference_error_(OK) {}
+      version_interference_error_(OK),
+      version_interference_details_(SSLErrorDetails::kOther) {}
 
 SSLConnectJob::~SSLConnectJob() {
 }
@@ -378,10 +379,12 @@
                                   std::abs(result));
       net_log().AddEventWithNetErrorCode(
           NetLogEventType::SSL_VERSION_INTERFERENCE_PROBE, result);
+      SSLErrorDetails details = ssl_socket_->GetConnectErrorDetails();
 
       ResetStateForRetry();
       version_interference_probe_ = true;
       version_interference_error_ = result;
+      version_interference_details_ = details;
       next_state_ = GetInitialState(params_->GetConnectionType());
       return OK;
     }
@@ -395,8 +398,8 @@
   // These are hosts that we intend to use in the initial TLS 1.3 deployment.
   // TLS connections to them, whether or not this browser is in the experiment
   // group, form the basis of our comparisons.
-  bool tls13_supported =
-      (host == "drive.google.com" || host == "mail.google.com");
+  bool tls13_supported = (host == "inbox.google.com" ||
+                          host == "mail.google.com" || host == "gmail.com");
 
   if (result == OK ||
       ssl_socket_->IgnoreCertError(result, params_->load_flags())) {
@@ -497,6 +500,12 @@
     DCHECK_NE(OK, version_interference_error_);
     UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SSLVersionInterferenceError",
                                 std::abs(version_interference_error_));
+
+    if (tls13_supported) {
+      UMA_HISTOGRAM_ENUMERATION(
+          "Net.SSLVersionInterferenceDetails_TLS13Experiment",
+          version_interference_details_, SSLErrorDetails::kLastValue);
+    }
   }
 
   if (result == OK || IsCertificateError(result)) {
diff --git a/net/socket/ssl_client_socket_pool.h b/net/socket/ssl_client_socket_pool.h
index c4913df..2d155d4 100644
--- a/net/socket/ssl_client_socket_pool.h
+++ b/net/socket/ssl_client_socket_pool.h
@@ -180,6 +180,10 @@
   // none was triggered.
   int version_interference_error_;
 
+  // Details for the error which triggered a TLS 1.3 interference probe, or
+  // kOther if not applicable.
+  SSLErrorDetails version_interference_details_;
+
   DISALLOW_COPY_AND_ASSIGN(SSLConnectJob);
 };
 
diff --git a/printing/android/java/src/org/chromium/printing/PrintingContext.java b/printing/android/java/src/org/chromium/printing/PrintingContext.java
index 84ffff4..15f9d85 100644
--- a/printing/android/java/src/org/chromium/printing/PrintingContext.java
+++ b/printing/android/java/src/org/chromium/printing/PrintingContext.java
@@ -110,13 +110,13 @@
     }
 
     @CalledByNative
-    public static void pdfWritingDone(int fd, boolean success) {
+    public static void pdfWritingDone(int fd, int pageCount) {
         ThreadUtils.assertOnUiThread();
         // TODO(cimamoglu): Do something when fd == -1.
         if (PRINTING_CONTEXT_MAP.get(fd) != null) {
             ThreadUtils.assertOnUiThread();
             PrintingContext printingContext = PRINTING_CONTEXT_MAP.get(fd);
-            printingContext.mController.pdfWritingDone(success);
+            printingContext.mController.pdfWritingDone(pageCount);
             PRINTING_CONTEXT_MAP.remove(fd);
         } else {
             Log.d(TAG, "No PrintingContext found for fd %d, can't notify print completion.", fd);
diff --git a/printing/android/java/src/org/chromium/printing/PrintingController.java b/printing/android/java/src/org/chromium/printing/PrintingController.java
index 2fa6fbc..0bf1d15 100644
--- a/printing/android/java/src/org/chromium/printing/PrintingController.java
+++ b/printing/android/java/src/org/chromium/printing/PrintingController.java
@@ -56,9 +56,10 @@
     /**
      * This method is called by the native side to signal PDF writing process is completed.
      *
-     * @param success Whether the PDF is written into the provided file descriptor successfully.
+     * @param pageCount How many pages native side wrote to PDF file descriptor. Non-positive value
+     *                  indicates native side writing failed.
      */
-    void pdfWritingDone(boolean success);
+    void pdfWritingDone(int pageCount);
 
     /**
      * Sets PrintingContext currently associated with the controller.
diff --git a/printing/android/java/src/org/chromium/printing/PrintingControllerImpl.java b/printing/android/java/src/org/chromium/printing/PrintingControllerImpl.java
index 083a8f52..50d1f24 100644
--- a/printing/android/java/src/org/chromium/printing/PrintingControllerImpl.java
+++ b/printing/android/java/src/org/chromium/printing/PrintingControllerImpl.java
@@ -204,13 +204,13 @@
     }
 
     @Override
-    public void pdfWritingDone(boolean success) {
+    public void pdfWritingDone(int pageCount) {
         if (mPrintingState == PRINTING_STATE_FINISHED) return;
         mPrintingState = PRINTING_STATE_READY;
         closeFileDescriptor(mFileDescriptor);
         mFileDescriptor = -1;
-        if (success) {
-            PageRange[] pageRanges = convertIntegerArrayToPageRanges(mPages);
+        if (pageCount > 0) {
+            PageRange[] pageRanges = convertIntegerArrayToPageRanges(mPages, pageCount);
             mOnWriteCallback.onWriteFinished(pageRanges);
         } else {
             mOnWriteCallback.onWriteFailed(mErrorMessage);
@@ -328,7 +328,7 @@
         }
     }
 
-    private static PageRange[] convertIntegerArrayToPageRanges(int[] pagesArray) {
+    private static PageRange[] convertIntegerArrayToPageRanges(int[] pagesArray, int pageCount) {
         PageRange[] pageRanges;
         if (pagesArray != null) {
             pageRanges = new PageRange[pagesArray.length];
@@ -338,7 +338,7 @@
             }
         } else {
             // null corresponds to all pages in Chromium printing logic.
-            pageRanges = new PageRange[] { PageRange.ALL_PAGES };
+            pageRanges = new PageRange[] {new PageRange(0, pageCount - 1)};
         }
         return pageRanges;
     }
diff --git a/printing/printing_context_android.cc b/printing/printing_context_android.cc
index 7b5f3b1..5abb312 100644
--- a/printing/printing_context_android.cc
+++ b/printing/printing_context_android.cc
@@ -67,9 +67,9 @@
 }
 
 // static
-void PrintingContextAndroid::PdfWritingDone(int fd, bool success) {
+void PrintingContextAndroid::PdfWritingDone(int fd, int page_count) {
   JNIEnv* env = base::android::AttachCurrentThread();
-  Java_PrintingContext_pdfWritingDone(env, fd, success);
+  Java_PrintingContext_pdfWritingDone(env, fd, page_count);
 }
 
 PrintingContextAndroid::PrintingContextAndroid(Delegate* delegate)
diff --git a/printing/printing_context_android.h b/printing/printing_context_android.h
index eee0902..1ebd19d8 100644
--- a/printing/printing_context_android.h
+++ b/printing/printing_context_android.h
@@ -23,8 +23,10 @@
   ~PrintingContextAndroid() override;
 
   // Called when the page is successfully written to a PDF using the file
-  // descriptor specified, or when the printing operation failed.
-  static void PdfWritingDone(int fd, bool success);
+  // descriptor specified, or when the printing operation failed. On success,
+  // the PDF written to |fd| has |page_count| pages. Non-positive |page_count|
+  // indicates failure.
+  static void PdfWritingDone(int fd, int page_count);
 
   // Called from Java, when printing settings from the user are ready or the
   // printing operation is canceled.
@@ -70,4 +72,3 @@
 }  // namespace printing
 
 #endif  // PRINTING_PRINTING_CONTEXT_ANDROID_H_
-
diff --git a/remoting/host/daemon_process.cc b/remoting/host/daemon_process.cc
index 7e3142da..cc7ec8e 100644
--- a/remoting/host/daemon_process.cc
+++ b/remoting/host/daemon_process.cc
@@ -16,6 +16,7 @@
 #include "base/location.h"
 #include "base/single_thread_task_runner.h"
 #include "remoting/base/auto_thread_task_runner.h"
+#include "remoting/base/constants.h"
 #include "remoting/host/branding.h"
 #include "remoting/host/chromoting_messages.h"
 #include "remoting/host/config_file_watcher.h"
@@ -23,6 +24,7 @@
 #include "remoting/host/host_event_logger.h"
 #include "remoting/host/host_exit_codes.h"
 #include "remoting/host/host_status_observer.h"
+#include "remoting/host/process_stats_sender.h"
 #include "remoting/host/screen_resolution.h"
 #include "remoting/protocol/transport.h"
 
@@ -120,6 +122,10 @@
                         OnHostStarted)
     IPC_MESSAGE_HANDLER(ChromotingNetworkDaemonMsg_HostShutdown,
                         OnHostShutdown)
+    IPC_MESSAGE_HANDLER(ChromotingNetworkToAnyMsg_StartProcessStatsReport,
+                        StartProcessStatsReport)
+    IPC_MESSAGE_HANDLER(ChromotingNetworkToAnyMsg_StopProcessStatsReport,
+                        StopProcessStatsReport)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
 
@@ -139,6 +145,11 @@
   Stop();
 }
 
+void DaemonProcess::OnWorkerProcessStopped() {
+  process_stats_request_count_ = 0;
+  stats_sender_.reset();
+}
+
 void DaemonProcess::CloseDesktopSession(int terminal_id) {
   DCHECK(caller_task_runner()->BelongsToCurrentThread());
 
@@ -180,6 +191,7 @@
       io_task_runner_(io_task_runner),
       next_terminal_id_(0),
       stopped_callback_(stopped_callback),
+      current_process_stats_("DaemonProcess"),
       weak_factory_(this) {
   DCHECK(caller_task_runner->BelongsToCurrentThread());
   // TODO(sammc): On OSX, mojo::edk::SetMachPortProvider() should be called with
@@ -287,6 +299,8 @@
 void DaemonProcess::Stop() {
   DCHECK(caller_task_runner()->BelongsToCurrentThread());
 
+  OnWorkerProcessStopped();
+
   if (!stopped_callback_.is_null()) {
     base::ResetAndReturn(&stopped_callback_).Run();
   }
@@ -365,4 +379,37 @@
   }
 }
 
+void DaemonProcess::StartProcessStatsReport(base::TimeDelta interval) {
+  DCHECK(caller_task_runner()->BelongsToCurrentThread());
+  if (interval <= base::TimeDelta::FromSeconds(0)) {
+    interval = kDefaultProcessStatsInterval;
+  }
+
+  process_stats_request_count_++;
+  DCHECK_GT(process_stats_request_count_, 0);
+  if (process_stats_request_count_ == 1 ||
+      stats_sender_->interval() > interval) {
+    DCHECK_EQ(process_stats_request_count_ == 1, !stats_sender_);
+    stats_sender_.reset(new ProcessStatsSender(
+        this,
+        interval,
+        { &current_process_stats_ }));
+  }
+}
+
+void DaemonProcess::StopProcessStatsReport() {
+  DCHECK(caller_task_runner()->BelongsToCurrentThread());
+  process_stats_request_count_--;
+  DCHECK_GE(process_stats_request_count_, 0);
+  if (process_stats_request_count_ == 0) {
+    DCHECK(stats_sender_);
+    stats_sender_.reset();
+  }
+}
+
+void DaemonProcess::OnProcessStats(
+    const protocol::AggregatedProcessResourceUsage& usage) {
+  SendToNetwork(new ChromotingAnyToNetworkMsg_ReportProcessStats(usage));
+}
+
 }  // namespace remoting
diff --git a/remoting/host/daemon_process.h b/remoting/host/daemon_process.h
index 391682a3..562b1a2d 100644
--- a/remoting/host/daemon_process.h
+++ b/remoting/host/daemon_process.h
@@ -17,11 +17,14 @@
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "base/process/process.h"
+#include "base/time/time.h"
 #include "ipc/ipc_channel.h"
 #include "ipc/ipc_channel_handle.h"
 #include "remoting/host/config_watcher.h"
+#include "remoting/host/current_process_stats_agent.h"
 #include "remoting/host/host_status_monitor.h"
 #include "remoting/host/worker_process_ipc_delegate.h"
+#include "remoting/protocol/process_stats_stub.h"
 
 struct SerializedTransportRoute;
 
@@ -35,6 +38,7 @@
 class DesktopSession;
 class HostEventLogger;
 class HostStatusObserver;
+class ProcessStatsSender;
 class ScreenResolution;
 
 // This class implements core of the daemon process. It manages the networking
@@ -43,7 +47,8 @@
 class DaemonProcess
     : public ConfigWatcher::Delegate,
       public HostStatusMonitor,
-      public WorkerProcessIpcDelegate {
+      public WorkerProcessIpcDelegate,
+      public protocol::ProcessStatsStub {
  public:
   typedef std::list<DesktopSession*> DesktopSessionList;
 
@@ -70,6 +75,7 @@
   void OnChannelConnected(int32_t peer_pid) override;
   bool OnMessageReceived(const IPC::Message& message) override;
   void OnPermanentError(int exit_code) override;
+  void OnWorkerProcessStopped() override;
 
   // Sends an IPC message to the network process. The message will be dropped
   // unless the network process is connected over the IPC channel.
@@ -158,6 +164,17 @@
   // Deletes all desktop sessions.
   void DeleteAllDesktopSessions();
 
+  // Starts to report process statistic data to network process. If |interval|
+  // is less then or equal to 0, a default non-zero value will be used.
+  void StartProcessStatsReport(base::TimeDelta interval);
+
+  // Stops sending process statistic data to network process.
+  void StopProcessStatsReport();
+
+  // ProcessStatsStub implementation.
+  void OnProcessStats(
+      const protocol::AggregatedProcessResourceUsage& usage) override;
+
   // Task runner on which public methods of this class must be called.
   scoped_refptr<AutoThreadTaskRunner> caller_task_runner_;
 
@@ -184,6 +201,20 @@
   // Writes host status updates to the system event log.
   std::unique_ptr<HostEventLogger> host_event_logger_;
 
+  // Reports process statistic data to network process.
+  std::unique_ptr<ProcessStatsSender> stats_sender_;
+
+  // The number of StartProcessStatsReport requests received.
+  // Daemon and Network processes manages multiple desktop sessions. Some of
+  // them may request for process statistic reports. So the resource usage of
+  // daemon process and network process will be merged to each desktop session.
+  //
+  // As long as at least process statistic reports is enabled for one desktop
+  // session, daemon process should continually send the reports.
+  int process_stats_request_count_ = 0;
+
+  CurrentProcessStatsAgent current_process_stats_;
+
   base::WeakPtrFactory<DaemonProcess> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(DaemonProcess);
diff --git a/remoting/host/daemon_process_unittest.cc b/remoting/host/daemon_process_unittest.cc
index c27b79a9..afa18c8 100644
--- a/remoting/host/daemon_process_unittest.cc
+++ b/remoting/host/daemon_process_unittest.cc
@@ -40,7 +40,8 @@
   kMessageConnectTerminal = ChromotingNetworkHostMsg_ConnectTerminal::ID,
   kMessageDisconnectTerminal = ChromotingNetworkHostMsg_DisconnectTerminal::ID,
   kMessageTerminalDisconnected =
-      ChromotingDaemonNetworkMsg_TerminalDisconnected::ID
+      ChromotingDaemonNetworkMsg_TerminalDisconnected::ID,
+  kMessageReportProcessStats = ChromotingAnyToNetworkMsg_ReportProcessStats::ID,
 };
 
 // Provides a public constructor allowing the test to create instances of
@@ -347,4 +348,57 @@
   EXPECT_EQ(0, terminal_id_);
 }
 
+TEST_F(DaemonProcessTest, StartProcessStatsReport) {
+  EXPECT_CALL(*daemon_process_, Sent(Message(kMessageReportProcessStats)));
+  daemon_process_->OnMessageReceived(
+      ChromotingNetworkToAnyMsg_StartProcessStatsReport(
+          base::TimeDelta::FromMilliseconds(1)));
+  base::RunLoop run_loop;
+  ON_CALL(*daemon_process_, Sent(Message(kMessageReportProcessStats)))
+      .WillByDefault(testing::Invoke(
+          [&run_loop](const IPC::Message& message) {
+            run_loop.Quit();
+          }));
+  run_loop.Run();
+}
+
+TEST_F(DaemonProcessTest, StartProcessStatsReportWithDifferentDelta) {
+  EXPECT_CALL(*daemon_process_, Sent(Message(kMessageReportProcessStats)))
+      .Times(AnyNumber());
+  int received = 0;
+  daemon_process_->OnMessageReceived(
+      ChromotingNetworkToAnyMsg_StartProcessStatsReport(
+          base::TimeDelta::FromHours(1)));
+  daemon_process_->OnMessageReceived(
+      ChromotingNetworkToAnyMsg_StartProcessStatsReport(
+          base::TimeDelta::FromMilliseconds(1)));
+  base::RunLoop run_loop;
+  ON_CALL(*daemon_process_, Sent(Message(kMessageReportProcessStats)))
+      .WillByDefault(testing::Invoke(
+          [&run_loop, &received](const IPC::Message& message) {
+            received++;
+            if (received == 5) {
+              run_loop.Quit();
+            }
+          }));
+  run_loop.Run();
+}
+
+TEST_F(DaemonProcessTest, StopProcessStatsReportWhenTheWorkerProcessDied) {
+  daemon_process_->OnMessageReceived(
+      ChromotingNetworkToAnyMsg_StartProcessStatsReport(
+          base::TimeDelta::FromMilliseconds(1)));
+  base::RunLoop run_loop;
+  ON_CALL(*daemon_process_, Sent(Message(kMessageReportProcessStats)))
+      .WillByDefault(testing::Invoke(
+          [](const IPC::Message& message) {
+            ASSERT_TRUE(false);
+          }));
+  static_cast<WorkerProcessIpcDelegate*>(daemon_process_.get())
+      ->OnWorkerProcessStopped();
+  message_loop_.task_runner()->PostDelayedTask(
+      FROM_HERE, run_loop.QuitClosure(), base::TimeDelta::FromMilliseconds(10));
+  run_loop.Run();
+}
+
 }  // namespace remoting
diff --git a/remoting/host/desktop_session_win.cc b/remoting/host/desktop_session_win.cc
index 1f7764a3..4ba23343 100644
--- a/remoting/host/desktop_session_win.cc
+++ b/remoting/host/desktop_session_win.cc
@@ -604,6 +604,8 @@
   TerminateSession();
 }
 
+void DesktopSessionWin::OnWorkerProcessStopped() {}
+
 void DesktopSessionWin::OnSessionAttached(uint32_t session_id) {
   DCHECK(caller_task_runner_->BelongsToCurrentThread());
   DCHECK(!launcher_);
diff --git a/remoting/host/desktop_session_win.h b/remoting/host/desktop_session_win.h
index 9b681c4..1937e719 100644
--- a/remoting/host/desktop_session_win.h
+++ b/remoting/host/desktop_session_win.h
@@ -92,6 +92,7 @@
   void OnChannelConnected(int32_t peer_pid) override;
   bool OnMessageReceived(const IPC::Message& message) override;
   void OnPermanentError(int exit_code) override;
+  void OnWorkerProcessStopped() override;
 
   // WtsTerminalObserver implementation.
   void OnSessionAttached(uint32_t session_id) override;
diff --git a/remoting/host/installer/mac/uninstaller/remoting_uninstaller-Info.plist b/remoting/host/installer/mac/uninstaller/remoting_uninstaller-Info.plist
index ab760e2..864a4ca 100644
--- a/remoting/host/installer/mac/uninstaller/remoting_uninstaller-Info.plist
+++ b/remoting/host/installer/mac/uninstaller/remoting_uninstaller-Info.plist
@@ -21,7 +21,7 @@
 	<key>CFBundleVersion</key>
 	<string>${VERSION_FULL}</string>
 	<key>LSMinimumSystemVersion</key>
-	<string>${MACOSX_DEPLOYMENT_TARGET}.0</string>
+	<string>${MACOSX_DEPLOYMENT_TARGET}</string>
 	<key>NSMainNibFile</key>
 	<string>remoting_uninstaller</string>
 	<key>NSPrincipalClass</key>
diff --git a/remoting/host/it2me/remote_assistance_host-Info.plist b/remoting/host/it2me/remote_assistance_host-Info.plist
index 9e3a62c..6b31d12 100644
--- a/remoting/host/it2me/remote_assistance_host-Info.plist
+++ b/remoting/host/it2me/remote_assistance_host-Info.plist
@@ -23,7 +23,7 @@
   <key>CFBundleShortVersionString</key>
   <string>${VERSION_SHORT}</string>
   <key>LSMinimumSystemVersion</key>
-  <string>${MACOSX_DEPLOYMENT_TARGET}.0</string>
+  <string>${MACOSX_DEPLOYMENT_TARGET}</string>
   <key>NSPrincipalClass</key>
   <string>CrApplication</string>
   <key>LSUIElement</key>
diff --git a/remoting/host/mac/remoting_me2me_host-Info.plist b/remoting/host/mac/remoting_me2me_host-Info.plist
index ea0375d2..4895b65d 100644
--- a/remoting/host/mac/remoting_me2me_host-Info.plist
+++ b/remoting/host/mac/remoting_me2me_host-Info.plist
@@ -23,7 +23,7 @@
   <key>CFBundleShortVersionString</key>
   <string>${VERSION_SHORT}</string>
   <key>LSMinimumSystemVersion</key>
-  <string>${MACOSX_DEPLOYMENT_TARGET}.0</string>
+  <string>${MACOSX_DEPLOYMENT_TARGET}</string>
   <key>NSPrincipalClass</key>
   <string>CrApplication</string>
   <key>LSUIElement</key>
diff --git a/remoting/host/process_stats_sender.cc b/remoting/host/process_stats_sender.cc
index 8bcebb8..7a2f7f8 100644
--- a/remoting/host/process_stats_sender.cc
+++ b/remoting/host/process_stats_sender.cc
@@ -19,6 +19,7 @@
     std::initializer_list<ProcessStatsAgent*> agents)
     : host_stats_stub_(host_stats_stub),
       agents_(agents),
+      interval_(interval),
       thread_checker_() {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(host_stats_stub_);
@@ -33,6 +34,10 @@
   timer_.Stop();
 }
 
+base::TimeDelta ProcessStatsSender::interval() const {
+  return interval_;
+}
+
 void ProcessStatsSender::ReportUsage() {
   DCHECK(thread_checker_.CalledOnValidThread());
 
diff --git a/remoting/host/process_stats_sender.h b/remoting/host/process_stats_sender.h
index c33af89..ed9e48f 100644
--- a/remoting/host/process_stats_sender.h
+++ b/remoting/host/process_stats_sender.h
@@ -33,11 +33,15 @@
                      std::initializer_list<ProcessStatsAgent*> agents);
 
   ~ProcessStatsSender();
+
+  base::TimeDelta interval() const;
+
  private:
   void ReportUsage();
 
   protocol::ProcessStatsStub* const host_stats_stub_;
   std::vector<ProcessStatsAgent*> agents_;
+  const base::TimeDelta interval_;
   base::RepeatingTimer timer_;
   const base::ThreadChecker thread_checker_;
 };
diff --git a/remoting/host/setup/native_messaging_host-Info.plist b/remoting/host/setup/native_messaging_host-Info.plist
index 3a36510..00c407a7 100644
--- a/remoting/host/setup/native_messaging_host-Info.plist
+++ b/remoting/host/setup/native_messaging_host-Info.plist
@@ -23,7 +23,7 @@
   <key>CFBundleShortVersionString</key>
   <string>${VERSION_SHORT}</string>
   <key>LSMinimumSystemVersion</key>
-  <string>${MACOSX_DEPLOYMENT_TARGET}.0</string>
+  <string>${MACOSX_DEPLOYMENT_TARGET}</string>
   <key>NSPrincipalClass</key>
   <string>CrApplication</string>
   <key>LSUIElement</key>
diff --git a/remoting/host/win/worker_process_launcher.cc b/remoting/host/win/worker_process_launcher.cc
index e4bf86c..99af9a4 100644
--- a/remoting/host/win/worker_process_launcher.cc
+++ b/remoting/host/win/worker_process_launcher.cc
@@ -252,6 +252,8 @@
   if (stopping())
     return;
 
+  ipc_handler_->OnWorkerProcessStopped();
+
   // Stop trying to restart the worker process if it exited due to
   // misconfiguration.
   if (kMinPermanentErrorExitCode <= exit_code_ &&
diff --git a/remoting/host/win/worker_process_launcher_unittest.cc b/remoting/host/win/worker_process_launcher_unittest.cc
index c7af99f91..e8e260f 100644
--- a/remoting/host/win/worker_process_launcher_unittest.cc
+++ b/remoting/host/win/worker_process_launcher_unittest.cc
@@ -68,6 +68,7 @@
   MOCK_METHOD1(OnChannelConnected, void(int32_t));
   MOCK_METHOD1(OnMessageReceived, bool(const IPC::Message&));
   MOCK_METHOD1(OnPermanentError, void(int));
+  MOCK_METHOD0(OnWorkerProcessStopped, void());
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockIpcDelegate);
@@ -394,6 +395,8 @@
       .Times(0);
   EXPECT_CALL(server_listener_, OnPermanentError(_))
       .Times(0);
+  EXPECT_CALL(server_listener_, OnWorkerProcessStopped())
+      .Times(0);
 
   StartWorker();
   StopWorker();
@@ -414,6 +417,8 @@
                                   &WorkerProcessLauncherTest::StopWorker));
   EXPECT_CALL(server_listener_, OnPermanentError(_))
       .Times(0);
+  EXPECT_CALL(server_listener_, OnWorkerProcessStopped())
+      .Times(0);
 
   StartWorker();
   base::RunLoop().Run();
@@ -438,6 +443,8 @@
 
   EXPECT_CALL(server_listener_, OnPermanentError(_))
       .Times(0);
+  EXPECT_CALL(server_listener_, OnWorkerProcessStopped())
+      .Times(1);
 
   StartWorker();
   base::RunLoop().Run();
@@ -461,6 +468,8 @@
 
   EXPECT_CALL(server_listener_, OnPermanentError(_))
       .Times(0);
+  EXPECT_CALL(server_listener_, OnWorkerProcessStopped())
+      .Times(1);
 
   StartWorker();
   base::RunLoop().Run();
@@ -484,6 +493,8 @@
       .Times(1)
       .WillOnce(InvokeWithoutArgs(this,
                                   &WorkerProcessLauncherTest::StopWorker));
+  EXPECT_CALL(server_listener_, OnWorkerProcessStopped())
+      .Times(1);
 
   StartWorker();
   base::RunLoop().Run();
@@ -509,6 +520,8 @@
           &WorkerProcessLauncherTest::TerminateWorker,
           base::Unretained(this),
           EXCEPTION_BREAKPOINT)));
+  EXPECT_CALL(server_listener_, OnWorkerProcessStopped())
+      .Times(1);
 
   StartWorker();
   base::RunLoop().Run();
@@ -534,6 +547,8 @@
       .Times(1)
       .WillOnce(InvokeWithoutArgs(
           this, &WorkerProcessLauncherTest::SendFakeMessageToLauncher));
+  EXPECT_CALL(server_listener_, OnWorkerProcessStopped())
+      .Times(1);
 
   StartWorker();
   base::RunLoop().Run();
diff --git a/remoting/host/worker_process_ipc_delegate.h b/remoting/host/worker_process_ipc_delegate.h
index 9ba4cb0..fe82504 100644
--- a/remoting/host/worker_process_ipc_delegate.h
+++ b/remoting/host/worker_process_ipc_delegate.h
@@ -29,6 +29,9 @@
 
   // Notifies that a permanent error was encountered.
   virtual void OnPermanentError(int exit_code) = 0;
+
+  // Notifies that the worker process stops for any reason.
+  virtual void OnWorkerProcessStopped() = 0;
 };
 
 }  // namespace remoting
diff --git a/services/ui/ws/frame_generator.cc b/services/ui/ws/frame_generator.cc
index 3bc702a..637260b 100644
--- a/services/ui/ws/frame_generator.cc
+++ b/services/ui/ws/frame_generator.cc
@@ -66,14 +66,14 @@
 }
 
 void FrameGenerator::ReclaimResources(
-    const cc::ReturnedResourceArray& resources) {
+    const std::vector<cc::ReturnedResource>& resources) {
   // Nothing to do here because FrameGenerator CompositorFrames don't reference
   // any resources.
   DCHECK(resources.empty());
 }
 
 void FrameGenerator::DidReceiveCompositorFrameAck(
-    const cc::ReturnedResourceArray& resources) {}
+    const std::vector<cc::ReturnedResource>& resources) {}
 
 void FrameGenerator::OnBeginFrame(const cc::BeginFrameArgs& begin_frame_args) {
   DCHECK(compositor_frame_sink_);
diff --git a/services/ui/ws/frame_generator.h b/services/ui/ws/frame_generator.h
index ef61aec..3763149 100644
--- a/services/ui/ws/frame_generator.h
+++ b/services/ui/ws/frame_generator.h
@@ -44,9 +44,10 @@
  private:
   // cc::mojom::CompositorFrameSinkClient implementation:
   void DidReceiveCompositorFrameAck(
-      const cc::ReturnedResourceArray& resources) override;
+      const std::vector<cc::ReturnedResource>& resources) override;
   void OnBeginFrame(const cc::BeginFrameArgs& args) override;
-  void ReclaimResources(const cc::ReturnedResourceArray& resources) override;
+  void ReclaimResources(
+      const std::vector<cc::ReturnedResource>& resources) override;
 
   // Generates the CompositorFrame.
   cc::CompositorFrame GenerateCompositorFrame();
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h
index af12d1a2..d74c8a4 100644
--- a/skia/config/SkUserConfig.h
+++ b/skia/config/SkUserConfig.h
@@ -216,8 +216,8 @@
 #define SK_SUPPORT_LEGACY_TILED_BITMAPS
 #endif
 
-#ifndef SK_SUPPORT_LEGACY_SWIZZLE_SHADER
-#define SK_SUPPORT_LEGACY_SWIZZLE_SHADER
+#ifndef SK_SUPPORT_LEGACY_2PTCONICAL_GRADIENT
+#define SK_SUPPORT_LEGACY_2PTCONICAL_GRADIENT
 #endif
 
 ///////////////////////// Imported from BUILD.gn and skia_common.gypi
diff --git a/skia/ext/platform_canvas.h b/skia/ext/platform_canvas.h
index 5cf00d2f..c31e7c0 100644
--- a/skia/ext/platform_canvas.h
+++ b/skia/ext/platform_canvas.h
@@ -57,9 +57,10 @@
 SK_API HDC GetNativeDrawingContext(SkCanvas* canvas);
 
 #elif defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || \
-      defined(__sun) || defined(ANDROID) || defined(__APPLE__)
-  // Construct a canvas from the given memory region. The memory is not cleared
-  // first. @data must be, at least, @height * StrideForWidth(@width) bytes.
+    defined(__sun) || defined(ANDROID) || defined(__APPLE__) ||             \
+    defined(__Fuchsia__)
+// Construct a canvas from the given memory region. The memory is not cleared
+// first. @data must be, at least, @height * StrideForWidth(@width) bytes.
 SK_API std::unique_ptr<SkCanvas> CreatePlatformCanvasWithPixels(
     int width,
     int height,
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index 42f3b8b..967b5bd 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -581,7 +581,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -698,12 +698,12 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
           ],
-          "hard_timeout": 60,
+          "hard_timeout": 120,
           "output_links": [
             {
               "link": [
@@ -855,7 +855,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -972,12 +972,12 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
           ],
-          "hard_timeout": 60,
+          "hard_timeout": 120,
           "output_links": [
             {
               "link": [
@@ -1012,12 +1012,12 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
           ],
-          "hard_timeout": 60,
+          "hard_timeout": 120,
           "output_links": [
             {
               "link": [
@@ -1052,12 +1052,12 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
           ],
-          "hard_timeout": 60,
+          "hard_timeout": 120,
           "output_links": [
             {
               "link": [
@@ -6355,7 +6355,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -6475,7 +6475,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 05806c9..9cad5757 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -10290,7 +10290,6 @@
   },
   "Fuchsia": {
     "additional_compile_targets": [
-      "base_unittests",
       "d8"
     ],
     "gtest_tests": [
@@ -10302,12 +10301,20 @@
           "can_use_on_swarming_builders": false
         },
         "test": "base_unittests"
+      },
+      {
+        "args": [
+          "--test-launcher-filter-file=../../testing/buildbot/filters/fuchsia.ipc_tests.filter"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": false
+        },
+        "test": "ipc_tests"
       }
     ]
   },
   "Fuchsia (dbg)": {
     "additional_compile_targets": [
-      "base_unittests",
       "d8"
     ],
     "gtest_tests": [
@@ -10319,6 +10326,15 @@
           "can_use_on_swarming_builders": false
         },
         "test": "base_unittests"
+      },
+      {
+        "args": [
+          "--test-launcher-filter-file=../../testing/buildbot/filters/fuchsia.ipc_tests.filter"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": false
+        },
+        "test": "ipc_tests"
       }
     ]
   },
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index 492e0e5..dc93bd6 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -402,7 +402,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "KTU84P",
               "device_type": "hammerhead"
             }
@@ -563,12 +563,12 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "KTU84P",
               "device_type": "hammerhead"
             }
           ],
-          "hard_timeout": 1920,
+          "hard_timeout": 600,
           "output_links": [
             {
               "link": [
@@ -578,7 +578,8 @@
               ],
               "name": "shard #${SHARD_INDEX} logcats"
             }
-          ]
+          ],
+          "shards": 3
         },
         "test": "content_shell_test_apk"
       },
@@ -603,11 +604,12 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "KTU84P",
               "device_type": "hammerhead"
             }
           ],
+          "hard_timeout": 600,
           "output_links": [
             {
               "link": [
@@ -1272,7 +1274,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "KTU84P",
               "device_type": "hammerhead"
             }
@@ -2003,7 +2005,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "KTU84P",
               "device_type": "hammerhead"
             }
@@ -2018,7 +2020,8 @@
               ],
               "name": "shard #${SHARD_INDEX} logcats"
             }
-          ]
+          ],
+          "shards": 2
         },
         "test": "chrome_sync_shell_test_apk"
       },
@@ -2164,12 +2167,12 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "KTU84P",
               "device_type": "hammerhead"
             }
           ],
-          "hard_timeout": 1920,
+          "hard_timeout": 600,
           "output_links": [
             {
               "link": [
@@ -2179,7 +2182,8 @@
               ],
               "name": "shard #${SHARD_INDEX} logcats"
             }
-          ]
+          ],
+          "shards": 3
         },
         "test": "content_shell_test_apk"
       },
@@ -2204,11 +2208,12 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "KTU84P",
               "device_type": "hammerhead"
             }
           ],
+          "hard_timeout": 600,
           "output_links": [
             {
               "link": [
@@ -2873,7 +2878,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "KTU84P",
               "device_type": "hammerhead"
             }
diff --git a/testing/buildbot/chromium.perf.fyi.json b/testing/buildbot/chromium.perf.fyi.json
index f239776..9c4edf9 100644
--- a/testing/buildbot/chromium.perf.fyi.json
+++ b/testing/buildbot/chromium.perf.fyi.json
@@ -182,6 +182,65 @@
       },
       {
         "args": [
+          "blink_perf.canvas",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blink_perf.canvas",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build248-m4--device4",
+              "os": "Android",
+              "pool": "Chrome-perf-fyi"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "blink_perf.canvas",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blink_perf.canvas.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build248-m4--device4",
+              "os": "Android",
+              "pool": "Chrome-perf-fyi"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
           "blink_perf.css",
           "-v",
           "--upload-results",
diff --git a/testing/buildbot/chromium.perf.json b/testing/buildbot/chromium.perf.json
index 3b0b200..291a048a 100644
--- a/testing/buildbot/chromium.perf.json
+++ b/testing/buildbot/chromium.perf.json
@@ -187,6 +187,65 @@
       },
       {
         "args": [
+          "blink_perf.canvas",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blink_perf.canvas",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build14-b1--device4",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "blink_perf.canvas",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blink_perf.canvas.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build14-b1--device4",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
           "blink_perf.css",
           "-v",
           "--upload-results",
@@ -4882,6 +4941,65 @@
       },
       {
         "args": [
+          "blink_perf.canvas",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blink_perf.canvas",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build74-b1--device4",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "blink_perf.canvas",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blink_perf.canvas.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build74-b1--device4",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
           "blink_perf.css",
           "-v",
           "--upload-results",
@@ -9470,6 +9588,36 @@
       },
       {
         "args": [
+          "blink_perf.canvas",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-webview",
+          "--webview-embedder-apk=../../out/Release/apks/SystemWebViewShell.apk"
+        ],
+        "isolate_name": "telemetry_perf_webview_tests",
+        "name": "blink_perf.canvas",
+        "override_compile_targets": [
+          "telemetry_perf_webview_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build164-b1--device7",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
           "blink_perf.css",
           "-v",
           "--upload-results",
@@ -11931,6 +12079,65 @@
       },
       {
         "args": [
+          "blink_perf.canvas",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blink_perf.canvas",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build16-b1--device4",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "blink_perf.canvas",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blink_perf.canvas.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build16-b1--device4",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
           "blink_perf.css",
           "-v",
           "--upload-results",
@@ -16539,6 +16746,36 @@
       },
       {
         "args": [
+          "blink_perf.canvas",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-webview",
+          "--webview-embedder-apk=../../out/Release/apks/SystemWebViewShell.apk"
+        ],
+        "isolate_name": "telemetry_perf_webview_tests",
+        "name": "blink_perf.canvas",
+        "override_compile_targets": [
+          "telemetry_perf_webview_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build112-b1--device7",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
           "blink_perf.css",
           "-v",
           "--upload-results",
@@ -19000,6 +19237,65 @@
       },
       {
         "args": [
+          "blink_perf.canvas",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blink_perf.canvas",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build10-b1--device4",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "blink_perf.canvas",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blink_perf.canvas.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build10-b1--device4",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
           "blink_perf.css",
           "-v",
           "--upload-results",
@@ -23695,6 +23991,65 @@
       },
       {
         "args": [
+          "blink_perf.canvas",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blink_perf.canvas",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build47-b1--device2",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "blink_perf.canvas",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "blink_perf.canvas.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build47-b1--device2",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
           "blink_perf.css",
           "-v",
           "--upload-results",
diff --git a/testing/buildbot/chromium.swarm.json b/testing/buildbot/chromium.swarm.json
index 0ad7669..8148b85 100644
--- a/testing/buildbot/chromium.swarm.json
+++ b/testing/buildbot/chromium.swarm.json
@@ -9,7 +9,8 @@
               "device_os": "KTU84P",
               "device_type": "hammerhead"
             }
-          ]
+          ],
+          "expiration": 7200
         },
         "test": "base_unittests"
       },
@@ -22,6 +23,7 @@
               "device_type": "hammerhead"
             }
           ],
+          "expiration": 7200,
           "shards": 14
         },
         "test": "chrome_public_test_apk"
@@ -35,6 +37,7 @@
               "device_type": "hammerhead"
             }
           ],
+          "expiration": 7200,
           "shards": 10
         },
         "test": "content_browsertests"
@@ -48,6 +51,7 @@
               "device_type": "hammerhead"
             }
           ],
+          "expiration": 7200,
           "shards": 3
         },
         "test": "content_unittests"
@@ -61,6 +65,7 @@
               "device_type": "hammerhead"
             }
           ],
+          "expiration": 7200,
           "shards": 4
         },
         "test": "net_unittests"
@@ -74,6 +79,7 @@
               "device_type": "hammerhead"
             }
           ],
+          "expiration": 7200,
           "shards": 5
         },
         "test": "unit_tests"
@@ -87,6 +93,7 @@
               "device_type": "hammerhead"
             }
           ],
+          "expiration": 7200,
           "shards": 7
         },
         "test": "webview_instrumentation_test_apk"
@@ -103,7 +110,8 @@
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
-          ]
+          ],
+          "expiration": 7200
         },
         "test": "base_unittests"
       },
@@ -116,6 +124,7 @@
               "device_type": "bullhead"
             }
           ],
+          "expiration": 7200,
           "shards": 15
         },
         "test": "chrome_public_test_apk"
@@ -129,6 +138,7 @@
               "device_type": "bullhead"
             }
           ],
+          "expiration": 7200,
           "shards": 10
         },
         "test": "content_browsertests"
@@ -142,6 +152,7 @@
               "device_type": "bullhead"
             }
           ],
+          "expiration": 7200,
           "shards": 4
         },
         "test": "content_unittests"
@@ -155,6 +166,7 @@
               "device_type": "bullhead"
             }
           ],
+          "expiration": 7200,
           "shards": 4
         },
         "test": "net_unittests"
@@ -168,6 +180,7 @@
               "device_type": "bullhead"
             }
           ],
+          "expiration": 7200,
           "shards": 8
         },
         "test": "unit_tests"
@@ -181,6 +194,7 @@
               "device_type": "bullhead"
             }
           ],
+          "expiration": 7200,
           "shards": 7
         },
         "test": "webview_instrumentation_test_apk"
diff --git a/testing/buildbot/filters/ash_unittests_mus.filter b/testing/buildbot/filters/ash_unittests_mus.filter
index 148a621d..0849d5e 100644
--- a/testing/buildbot/filters/ash_unittests_mus.filter
+++ b/testing/buildbot/filters/ash_unittests_mus.filter
@@ -1,10 +1,3 @@
-# TODO: fix these. They fail because wm::CursorManager isn't created.
-# http://crbug.com/734806.
-# The following fail as they use wm::CursorManager:
--LockStateControllerTest.LegacyLockAndShutDown
--LockStateControllerTest.RequestShutdownFromLockScreen
--LockStateControllerTest.RequestShutdownFromLoginScreen
-
 # TODO: fix these. They fail because ShellPortMash::IsMouseEventsEnabled() isn't
 # implemented. http://crbug.com/734808.
 -ImmersiveFullscreenControllerTest.EndRevealViaGesture
diff --git a/testing/buildbot/filters/fuchsia.base_unittests.filter b/testing/buildbot/filters/fuchsia.base_unittests.filter
index 6c558a9..ff9857b 100644
--- a/testing/buildbot/filters/fuchsia.base_unittests.filter
+++ b/testing/buildbot/filters/fuchsia.base_unittests.filter
@@ -49,12 +49,6 @@
 -MemoryMappedFileTest.MapWholeFileByPath
 -MemoryMappedFileTest.MapWholeFileUsingRegion
 -MemoryMappedFileTest.WriteableFile
--MessageLoopForIOOnMainThread/FileDescriptorWatcherTest.WatchReadableOneByte/0
--MessageLoopForIOOnMainThread/FileDescriptorWatcherTest.WatchReadableTwoBytes/0
--MessageLoopForIOOnMainThread/FileDescriptorWatcherTest.WatchWritable/0
--MessageLoopTest.FileDescriptorWatcherDoubleStop
--MessageLoopTest.FileDescriptorWatcherOutlivesMessageLoop
--MessageLoopTestTypeDefault.PostDelayedTask_Basic
 -NativeLibraryTest.LoadLibrary
 -NativeLibraryTest.LoadLibraryPreferOwnSymbols
 -PartitionAllocTest.Basic
@@ -134,3 +128,6 @@
 
 # TaskScheduler is racy, causing bot instability: https://crbug.com/735701.
 -*TaskScheduler*
+
+# Flaky on waterfall bot, https://crbug.com/738275
+-MessageLoopForIOOnMainThread/FileDescriptorWatcherTest.*
diff --git a/testing/buildbot/filters/fuchsia.ipc_tests.filter b/testing/buildbot/filters/fuchsia.ipc_tests.filter
new file mode 100644
index 0000000..3c3a529
--- /dev/null
+++ b/testing/buildbot/filters/fuchsia.ipc_tests.filter
@@ -0,0 +1,10 @@
+# TODO(fuchsia): Being ported, see https://crbug.com/734791
+
+-IPCChannelMojoTest.*
+-IPCChannelProxyMojoTest.*
+-IPCChannelProxyTest.*
+-IPCChannelBadMessageTest.*
+-IPCFuzzingTest.*
+-IPCMojoBootstrapTest.*
+-IPCSendFdsTest.DescriptorTest
+-IPCMessageUtilsTest.SharedMemoryHandle
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl
index e82c4052..2b6a3bd 100644
--- a/testing/buildbot/gn_isolate_map.pyl
+++ b/testing/buildbot/gn_isolate_map.pyl
@@ -79,8 +79,7 @@
   },
   "accessibility_unittests":  {
     "label": "//ui/accessibility:accessibility_unittests",
-    "type": "raw",
-    "args": [],
+    "type": "console_test_launcher",
   },
   "android_webview_unittests": {
     "label": "//android_webview/test:android_webview_unittests",
@@ -210,10 +209,7 @@
   },
   "cacheinvalidation_unittests": {
     "label": "//third_party/cacheinvalidation:cacheinvalidation_unittests",
-    "type": "raw",
-    "args": [
-      "--test-launcher-bot-mode",
-    ],
+    "type": "console_test_launcher",
   },
   "capture_unittests": {
     "label": "//media/capture:capture_unittests",
@@ -478,8 +474,7 @@
   },
   "gfx_unittests": {
     "label": "//ui/gfx:gfx_unittests",
-    "type": "raw",
-    "args": [],
+    "type": "console_test_launcher",
   },
   "gin_unittests": {
     "label": "//gin:gin_unittests",
@@ -507,8 +502,7 @@
   },
   "gn_unittests": {
     "label": "//tools/gn:gn_unittests",
-    "type": "raw",
-    "args": [],
+    "type": "console_test_launcher",
   },
   "google_apis_unittests": {
     "label": "//google_apis:google_apis_unittests",
@@ -770,8 +764,7 @@
   },
   "nacl_loader_unittests": {
     "label": "//components/nacl/loader:nacl_loader_unittests",
-    "type": "raw",
-    "args": [],
+    "type": "console_test_launcher",
   },
   "net_junit_tests": {
     "label": "//net/android:net_junit_tests",
@@ -827,8 +820,7 @@
   },
   "sandbox_linux_unittests": {
     "label": "//sandbox/linux:sandbox_linux_unittests",
-    "type": "raw",
-    "args": [],
+    "type": "console_test_launcher",
   },
   "sandbox_mac_unittests": {
     "label": "//sandbox/mac:sandbox_mac_unittests",
@@ -1137,7 +1129,7 @@
     "type": "console_test_launcher",
   },
   "zucchini_unittests": {
-    "label": "//zucchini:zucchini_unittests",
+    "label": "//chrome/installer/zucchini:zucchini_unittests",
     "type": "console_test_launcher",
   },
 }
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index b8c9ede2..d819d2c 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -1566,24 +1566,6 @@
             ]
         }
     ],
-    "NTPCaptureThumbnailOnLoadFinished": [
-        {
-            "platforms": [
-                "chromeos",
-                "linux",
-                "mac",
-                "win"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "CaptureThumbnailOnLoadFinished"
-                    ]
-                }
-            ]
-        }
-    ],
     "NTPFaviconsFromNewServer": [
         {
             "platforms": [
@@ -1797,6 +1779,32 @@
             ]
         }
     ],
+    "NewTabInProductHelp": [
+        {
+            "platforms": [
+                "linux",
+                "mac",
+                "win"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "params": {
+                        "availability": "any",
+                        "event_new_tab_opened": "name:new_tab_opened;comparator:==0;window:3650;storage:3650",
+                        "event_omnibox_used": "name:omnibox_used;comparator:>=1;window:3650;storage:3650",
+                        "event_session_time": "name:session_time;comparator:>=1;window:3650;storage:3650",
+                        "event_trigger": "name:new_tab_trigger;comparator:any;window:3650;storage:3650",
+                        "event_used": "name:new_tab_clicked;comparator:any;window:3650;storage:3650",
+                        "session_rate": "<=3"
+                    },
+                    "enable_features": [
+                        "IPH_NewTab"
+                    ]
+                }
+            ]
+        }
+    ],
     "NoCreditCardAbort": [
         {
             "platforms": [
@@ -2711,7 +2719,7 @@
             ],
             "experiments": [
                 {
-                    "name": "Enabled",
+                    "name": "AdIdentifiers",
                     "params": {
                         "tag_attribute_csv": "div,id,iframe,id"
                     },
@@ -3065,6 +3073,25 @@
             ]
         }
     ],
+    "SyncUserEvents": [
+        {
+            "platforms": [
+                "android",
+                "chromeos",
+                "linux",
+                "mac",
+                "win"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "SyncUserEvents"
+                    ]
+                }
+            ]
+        }
+    ],
     "TLS13Negotiation": [
         {
             "platforms": [
@@ -3144,6 +3171,24 @@
                     "enable_features": [
                         "TranslateCompactUI"
                     ]
+                },
+                {
+                    "name": "CompactUIAndRanker",
+                    "enable_features": [
+                        "TranslateCompactUI",
+                        "TranslateRankerEnforcement",
+                        "TranslateRankerQuery"
+                    ]
+                },
+                {
+                    "name": "RankerOnly",
+                    "enable_features": [
+                        "TranslateRankerEnforcement",
+                        "TranslateRankerQuery"
+                    ],
+                    "disable_features": [
+                        "TranslateCompactUI"
+                    ]
                 }
             ]
         }
@@ -3151,7 +3196,6 @@
     "TranslateRankerModel": [
         {
             "platforms": [
-                "android",
                 "chromeos",
                 "ios",
                 "linux",
@@ -3292,6 +3336,25 @@
             ]
         }
     ],
+    "V8AsmJSToWasm": [
+        {
+            "platforms": [
+                "android",
+                "chromeos",
+                "linux",
+                "mac",
+                "win"
+            ],
+            "experiments": [
+                {
+                    "name": "AsmJsToWebAssembly",
+                    "enable_features": [
+                        "AsmJsToWebAssembly"
+                    ]
+                }
+            ]
+        }
+    ],
     "V8CacheStrategiesForCacheStorage": [
         {
             "platforms": [
@@ -3397,6 +3460,9 @@
             "experiments": [
                 {
                     "name": "Enabled",
+                    "params": {
+                        "play_install": "true"
+                    },
                     "enable_features": [
                         "ImprovedA2HS"
                     ]
diff --git a/third_party/.gitignore b/third_party/.gitignore
index 5bf71dee..b9b092a 100644
--- a/third_party/.gitignore
+++ b/third_party/.gitignore
@@ -117,6 +117,7 @@
 /llvm-bootstrap
 /llvm-build
 /lss
+/material_design_icons/src
 /mesa/src
 /mingw-w64
 /minigbm/src
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index 2b3d1b4..c8d44709 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -13490,7 +13490,7 @@
 crbug.com/591099 fast/text-autosizing/list-marker-with-images-and-forms-autosizing.html [ Crash Failure ]
 crbug.com/591099 fast/text-autosizing/list-marker-with-links-autosizing.html [ Crash Failure ]
 crbug.com/591099 fast/text-autosizing/narrow-child.html [ Failure ]
-crbug.com/591099 fast/text-autosizing/narrow-iframe.html [ Failure ]
+crbug.com/591099 http/tests/text-autosizing/narrow-iframe.html [ Failure ]
 crbug.com/591099 fast/text-autosizing/nested-child.html [ Failure ]
 crbug.com/591099 fast/text-autosizing/nested-em-line-height.html [ Failure ]
 crbug.com/591099 fast/text-autosizing/oscillation-javascript-fontsize-change.html [ Failure ]
@@ -13523,7 +13523,7 @@
 crbug.com/591099 fast/text-autosizing/vertical-writing-mode.html [ Failure ]
 crbug.com/591099 fast/text-autosizing/wide-block.html [ Failure ]
 crbug.com/591099 fast/text-autosizing/wide-child.html [ Failure ]
-crbug.com/591099 fast/text-autosizing/wide-iframe.html [ Failure ]
+crbug.com/591099 http/tests/text-autosizing/wide-iframe.html [ Failure ]
 crbug.com/591099 fast/text-autosizing/wide-in-narrow-overflow-scroll.html [ Failure ]
 crbug.com/591099 fast/text/apply-start-width-after-skipped-text.html [ Failure ]
 crbug.com/591099 fast/text/atsui-kerning-and-ligatures.html [ Failure ]
@@ -16365,7 +16365,7 @@
 crbug.com/591099 inspector-protocol/dom-snapshot/dom-snapshot-getSnapshot.js [ Crash Failure Timeout ]
 crbug.com/591099 inspector-protocol/emulation/device-emulation-small-dw.js [ Failure ]
 crbug.com/591099 inspector-protocol/emulation/device-emulation-small.js [ Failure ]
-crbug.com/591099 inspector-protocol/emulation/forced-viewport-unobserved.html [ Failure ]
+crbug.com/591099 inspector/device-mode/forced-viewport-unobserved.html [ Failure ]
 crbug.com/591099 inspector-protocol/heap-profiler/heap-objects-tracking.html [ Failure ]
 crbug.com/591099 inspector-protocol/heap-profiler/heap-samples-in-snapshot.html [ Failure ]
 crbug.com/591099 inspector-protocol/heap-profiler/heap-snapshot-with-active-dom-object.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-network-service b/third_party/WebKit/LayoutTests/FlagExpectations/enable-network-service
index 82103d8..ade9c10 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-network-service
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-network-service
@@ -409,6 +409,7 @@
 Bug(none) external/wpt/html/semantics/forms/form-submission-0/submit-entity-body.html [ Failure Timeout ]
 Bug(none) external/wpt/html/semantics/forms/the-legend-element/legend-form.html [ Failure Timeout ]
 Bug(none) external/wpt/html/semantics/scripting-1/the-script-element/async_003.htm [ Failure Timeout ]
+Bug(none) external/wpt/html/semantics/scripting-1/the-script-element/module/credentials.sub.html [ Failure Timeout ]
 Bug(none) external/wpt/html/semantics/scripting-1/the-script-element/script-crossorigin-network.html [ Failure Timeout ]
 Bug(none) external/wpt/html/webappapis/idle-callbacks/callback-suspended.html [ Failure Timeout ]
 Bug(none) external/wpt/html/webappapis/scripting/events/messageevent-constructor.https.html [ Failure Timeout ]
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/root-layer-scrolls b/third_party/WebKit/LayoutTests/FlagExpectations/root-layer-scrolls
index 15b72c548..eebb501 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/root-layer-scrolls
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/root-layer-scrolls
@@ -461,7 +461,7 @@
 Bug(none) inspector/layers/layer-tree-model.html [ Crash ]
 Bug(none) inspector/layers/no-overlay-layers.html [ Crash ]
 Bug(none) inspector-protocol/dom-snapshot/dom-snapshot-getSnapshot.js [ Failure ]
-Bug(none) inspector-protocol/emulation/forced-viewport-far.html [ Failure ]
+Bug(none) inspector/device-mode/forced-viewport-far.html [ Failure ]
 Bug(none) inspector-protocol/layers/get-layers.js [ Crash ]
 Bug(none) inspector-protocol/layers/paint-profiler.js [ Crash ]
 Bug(none) inspector-protocol/page/get-layout-metrics.js [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process b/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process
index 86bf9739..c0c3b9f 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process
@@ -1,6 +1,12 @@
 # These tests currently fail when they run with --site-per-process.
 # See https://crbug.com/477150.
 
+# https://crbug.com/393285: Text-autosizing doesn't support OOPIFs.
+# https://crbug.com/667551: Pixel dumps don't support OOPIFs.
+# Both of the bugs above need to be fixed, before enabling the tests below.
+crbug.com/393285 http/tests/text-autosizing/narrow-iframe.html [ Failure ]
+crbug.com/393285 http/tests/text-autosizing/wide-iframe.html [ Failure ]
+
 # https://crbug.com/710098: Tests failing because of r462933.
 crbug.com/710098 http/tests/security/document-all.html [ Failure ]
 crbug.com/710098 http/tests/security/window-named-proto.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/NeverFixTests b/third_party/WebKit/LayoutTests/NeverFixTests
index c578500..9fa98d1 100644
--- a/third_party/WebKit/LayoutTests/NeverFixTests
+++ b/third_party/WebKit/LayoutTests/NeverFixTests
@@ -826,6 +826,21 @@
 external/wpt/viewport/viewport-scale-iframe-manual.html [ WontFix ]
 external/wpt/viewport/viewport-scale-manual.html [ WontFix ]
 external/wpt/viewport/viewport-scroll-event-manual.html [ WontFix ]
+external/wpt/web-share/share-cancel-manual.html [ WontFix ]
+external/wpt/web-share/share-empty-manual.html [ WontFix ]
+external/wpt/web-share/share-extra-argument-manual.html [ WontFix ]
+external/wpt/web-share/share-extra-field-manual.html [ WontFix ]
+external/wpt/web-share/share-non-string-manual.html [ WontFix ]
+external/wpt/web-share/share-null-manual.html [ WontFix ]
+external/wpt/web-share/share-simple-manual.html [ WontFix ]
+external/wpt/web-share/share-unicode-strings-manual.html [ WontFix ]
+external/wpt/web-share/share-unicode-strings-nonutf8-manual.html [ WontFix ]
+external/wpt/web-share/share-url-data-manual.html [ WontFix ]
+external/wpt/web-share/share-url-empty-manual.html [ WontFix ]
+external/wpt/web-share/share-url-encoding-manual.html [ WontFix ]
+external/wpt/web-share/share-url-noscheme-manual.html [ WontFix ]
+external/wpt/web-share/share-url-pathonly-manual.html [ WontFix ]
+external/wpt/web-share/share-url-relative-manual.html [ WontFix ]
 external/wpt/webstorage/storage_local-manual.html [ WontFix ]
 external/wpt/webstorage/storage_session-manual.html [ WontFix ]
 external/wpt/XMLHttpRequest/send-authentication-existing-session-manual.htm [ WontFix ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index a7ce4e88..fef8a61 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -342,7 +342,6 @@
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/clear-applies-to-012.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/float-applies-to-008.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/float-applies-to-012.xht [ Failure ]
-crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/float-replaced-height-001.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/float-replaced-width-002.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floating-replaced-height-008.xht [ Skip ]
 crbug.com/719615 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-001.xht [ Failure ]
@@ -353,7 +352,6 @@
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-028.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-029.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-036.xht [ Failure ]
-crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-101.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-108.xht [ Skip ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-109.xht [ Skip ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-110.xht [ Skip ]
@@ -368,7 +366,6 @@
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-141.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-143.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-144.xht [ Failure ]
-crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-145.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-146.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/margin-collapse-018.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/margin-collapse-027.xht [ Failure ]
@@ -414,10 +411,6 @@
 # Block: percent max-height.
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/max-height-percentage-002.xht [ Failure ]
 
-# Float: auto-height.
-crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/block-formatting-context-height-001.xht [ Failure ]
-crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/block-formatting-context-height-002.xht [ Failure ]
-
 # Inline: border in continuations. Fail in Blink.
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/block-in-inline-insert-001f.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/block-in-inline-insert-002f.xht [ Failure ]
@@ -580,7 +573,6 @@
 ### virtual/layout_ng/fast/block/float
 crbug.com/635619 virtual/layout_ng/fast/block/float/002.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/003.html [ Failure ]
-crbug.com/635619 virtual/layout_ng/fast/block/float/008.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/010.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/012.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/014.html [ Failure Crash ]
@@ -622,7 +614,6 @@
 crbug.com/635619 virtual/layout_ng/fast/block/float/containing-block-change-compositing.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/crash-on-absolute-positioning.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/crash-replaced-display-block.html [ Failure ]
-crbug.com/635619 virtual/layout_ng/fast/block/float/dynamic-unfloat-pref-width.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/editable-text-overlapping-float.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/element-clears-float-without-clearance.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/fit_line_below_floats.html [ Failure ]
@@ -636,7 +627,6 @@
 crbug.com/635619 virtual/layout_ng/fast/block/float/float-list-changed-before-layout-crash.html [ Crash ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/float-not-removed-from-first-letter.html [ Crash ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/float-not-removed-from-next-sibling-crash.html [ Failure ]
-crbug.com/635619 virtual/layout_ng/fast/block/float/float-not-removed-from-next-sibling3.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/float-not-removed-from-next-sibling5.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/float-not-removed-from-pre-block.html [ Failure Crash ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/float-on-empty-line.html [ Failure ]
@@ -644,7 +634,6 @@
 crbug.com/635619 virtual/layout_ng/fast/block/float/float-on-line-obeys-container-padding.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/float-on-zero-height-line.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/float-overflow-hidden-containing-block-width.html [ Failure ]
-crbug.com/635619 virtual/layout_ng/fast/block/float/float-overhangs-root.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/float-reinsertion-failure.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/float-reparent-during-detach-crash.html [ Crash ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/floats-and-text-indent-rl.html [ Failure ]
@@ -675,7 +664,6 @@
 crbug.com/635619 virtual/layout_ng/fast/block/float/negative-margin-on-element-avoiding-floats-with-margin-on-parent.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/negative-margin-on-element-avoiding-floats.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/nested-clearance.html [ Failure ]
-crbug.com/635619 virtual/layout_ng/fast/block/float/nested-floats-expand-formatting-context.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/nopaint-after-layer-destruction.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/nopaint-after-layer-destruction2.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/overhanging-float-add-in-static-position-block.html [ Failure Crash ]
@@ -731,7 +719,6 @@
 crbug.com/635619 virtual/layout_ng/fast/block/margin-collapse/clear-nested-float-more-than-one-previous-sibling-away.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/margin-collapse/empty-clear-blocks.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/margin-collapse/line-beside-float-complex-margin-collapsing.html [ Failure Crash ]
-crbug.com/635619 virtual/layout_ng/fast/block/margin-collapse/self-collapsing-block-with-float-descendants.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/margin-collapse/self-collapsing-block-with-overflow-hidden-and-float-child.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/margin-collapse/self-collapsing-cols-creates-block-formatting-context.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/margin-collapse/self-collapsing-with-floats.html [ Failure ]
@@ -1690,8 +1677,7 @@
 crbug.com/611658 [ Win7 ] fast/forms/text/text-font-height-mismatch.html [ Failure ]
 crbug.com/611658 [ Win ] fast/text/emphasis-combined-text.html [ Failure ]
 
-# Reenable when 737620 is rebaselined
-#crbug.com/611658 [ Win7 ] fast/writing-mode/english-lr-text.html [ Failure ]
+crbug.com/611658 [ Win7 ] fast/writing-mode/english-lr-text.html [ Failure ]
 
 crbug.com/605059 [ Retina ] fast/text/international/rtl-negative-letter-spacing.html [ Failure ]
 
@@ -1783,6 +1769,13 @@
 
 crbug.com/698077 inspector/sources/debugger/debug-inlined-scripts.html [ NeedsManualRebaseline ]
 
+crbug.com/738149 svg/dynamic-updates/SVGFEDropShadowElement-dom-shadow-color-attr.html [ NeedsManualRebaseline ]
+crbug.com/738149 svg/dynamic-updates/SVGFEDropShadowElement-dom-shadow-opacity-attr.html [ NeedsManualRebaseline ]
+crbug.com/738149 svg/dynamic-updates/SVGFEDropShadowElement-svgdom-shadow-color-prop.html [ NeedsManualRebaseline ]
+crbug.com/738149 svg/dynamic-updates/SVGFEDropShadowElement-svgdom-shadow-opacity-prop.html [ NeedsManualRebaseline ]
+crbug.com/738149 svg/filters/feBlend-all-modes.html [ NeedsManualRebaseline ]
+crbug.com/738149 svg/filters/feDropShadow.svg [ NeedsManualRebaseline ]
+
 # Working on getting the CSP tests going:
 crbug.com/694525 external/wpt/content-security-policy/blink-contrib [ Skip ]
 crbug.com/694525 external/wpt/content-security-policy/blink-contrib-2 [ Skip ]
@@ -1895,22 +1888,6 @@
 
 crbug.com/724251 virtual/threaded/animations/svg-attribute-interpolation/svg-startOffset-interpolation.html [ Failure Pass ]
 
-crbug.com/737620 fast/text/stroking-decorations.html [ NeedsManualRebaseline ]
-crbug.com/737620 fast/writing-mode/english-lr-text.html [ NeedsManualRebaseline ]
-crbug.com/737620 paint/invalidation/shadow-multiple.html [ NeedsManualRebaseline ]
-crbug.com/737620 [ Mac ] fast/forms/calendar-picker/calendar-picker-appearance-zoom200.html [ NeedsManualRebaseline ]
-crbug.com/737620 fast/borders/border-radius-split-inline.html [ NeedsManualRebaseline ]
-crbug.com/737620 fast/box-shadow/basic-shadows.html [ NeedsManualRebaseline ]
-crbug.com/737620 fast/box-shadow/box-shadow-radius.html [ NeedsManualRebaseline ]
-crbug.com/737620 fast/box-shadow/box-shadow-transformed.html [ NeedsManualRebaseline ]
-crbug.com/737620 fast/box-shadow/box-shadow.html [ NeedsManualRebaseline ]
-crbug.com/737620 fast/box-shadow/inset-box-shadow-radius.html [ NeedsManualRebaseline ]
-crbug.com/737620 fast/box-shadow/scaled-box-shadow.html [ NeedsManualRebaseline ]
-crbug.com/737620 fast/canvas/canvas-composite-shadow.html [ NeedsManualRebaseline ]
-crbug.com/737620 fast/css/color-correction-on-box-shadow.html [ NeedsManualRebaseline ]
-crbug.com/737620 transforms/shadows.html [ NeedsManualRebaseline ]
-crbug.com/737620 virtual/display_list_2d_canvas/fast/canvas/canvas-composite-shadow.html [ NeedsManualRebaseline ]
-
 crbug.com/736050 external/wpt/IndexedDB/idbcursor_advance_index.htm [ Pass Failure ]
 crbug.com/736050 external/wpt/IndexedDB/idbcursor-continue-exception-order.htm [ Pass Failure ]
 crbug.com/736050 external/wpt/IndexedDB/idbcursor_continue_index2.htm [ Pass Failure ]
@@ -2049,22 +2026,12 @@
 crbug.com/626703 virtual/threaded/transitions/transition-end-event-multiple-03.html [ Pass Failure ]
 
 # ====== New tests from wpt-importer added here ======
-crbug.com/626703 [ Android Mac ] external/wpt/css/css-flexbox-1/auto-margins-001.html [ Failure ]
-crbug.com/626703 external/wpt/web-share/share-cancel-manual.html [ Skip ]
-crbug.com/626703 external/wpt/web-share/share-empty-manual.html [ Skip ]
-crbug.com/626703 external/wpt/web-share/share-extra-argument-manual.html [ Skip ]
-crbug.com/626703 external/wpt/web-share/share-extra-field-manual.html [ Skip ]
-crbug.com/626703 external/wpt/web-share/share-non-string-manual.html [ Skip ]
-crbug.com/626703 external/wpt/web-share/share-null-manual.html [ Skip ]
-crbug.com/626703 external/wpt/web-share/share-simple-manual.html [ Skip ]
-crbug.com/626703 external/wpt/web-share/share-unicode-strings-manual.html [ Skip ]
-crbug.com/626703 external/wpt/web-share/share-unicode-strings-nonutf8-manual.html [ Skip ]
-crbug.com/626703 external/wpt/web-share/share-url-data-manual.html [ Skip ]
-crbug.com/626703 external/wpt/web-share/share-url-empty-manual.html [ Skip ]
-crbug.com/626703 external/wpt/web-share/share-url-encoding-manual.html [ Skip ]
-crbug.com/626703 external/wpt/web-share/share-url-noscheme-manual.html [ Skip ]
-crbug.com/626703 external/wpt/web-share/share-url-pathonly-manual.html [ Skip ]
-crbug.com/626703 external/wpt/web-share/share-url-relative-manual.html [ Skip ]
+crbug.com/626703 external/wpt/css/css-tables-3/floats/floats-wrap-bfc-006b.xht [ Failure ]
+crbug.com/626703 external/wpt/css/css-tables-3/floats/floats-wrap-bfc-006c.xht [ Failure ]
+crbug.com/626703 external/wpt/html/webappapis/idle-callbacks/callback-xhr-sync.html [ Timeout ]
+crbug.com/626703 external/wpt/service-workers/service-worker/update-bytecheck.https.html [ Timeout ]
+crbug.com/626703 virtual/off-main-thread-fetch/external/wpt/service-workers/service-worker/update-bytecheck.https.html [ Timeout ]
+crbug.com/626703 [ Mac ] external/wpt/css/css-flexbox-1/auto-margins-001.html [ Failure ]
 crbug.com/626703 external/wpt/workers/name-property.html [ Timeout ]
 crbug.com/626703 external/wpt/pointerevents/pointerevent_disabled_form_control-manual.html [ Timeout Pass ]
 crbug.com/626703 external/wpt/css/CSS2/text/text-align-white-space-003.xht [ Failure ]
@@ -2951,6 +2918,7 @@
 crbug.com/v8/6529 inspector/console/console-format.html [ NeedsManualRebaseline ]
 
 crbug.com/737959 http/tests/misc/video-poster-image-load-outlives-gc-without-crashing.html [ Failure Pass Crash ]
+crbug.com/737959 virtual/off-main-thread-fetch/http/tests/misc/video-poster-image-load-outlives-gc-without-crashing.html [ Failure Pass Crash ]
 
 # These tests are failing on Mac-10.12 when using an Intel GPU.
 crbug.com/736177 [ Mac ] css2.1/t1202-counter-04-b.html [ Failure Pass ]
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
index dc10df6..3e8d0ed 100644
--- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
+++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
@@ -34835,6 +34835,30 @@
      {}
     ]
    ],
+   "css/css-tables-3/floats/floats-wrap-bfc-006b.xht": [
+    [
+     "/css/css-tables-3/floats/floats-wrap-bfc-006b.xht",
+     [
+      [
+       "/css/css-tables-3/floats/floats-wrap-bfc-006b-ref.xht",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-tables-3/floats/floats-wrap-bfc-006c.xht": [
+    [
+     "/css/css-tables-3/floats/floats-wrap-bfc-006c.xht",
+     [
+      [
+       "/css/css-tables-3/floats/floats-wrap-bfc-006c-ref.xht",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-text-3/i18n/css3-text-line-break-jazh-001.html": [
     [
      "/css/css-text-3/i18n/css3-text-line-break-jazh-001.html",
@@ -42316,10 +42340,6 @@
      "/css/css-ui-3/box-sizing-026.html",
      [
       [
-       "/css/css-ui-3/reference/box-sizing-001-ref.html",
-       "=="
-      ],
-      [
        "/css/reference/ref-filled-green-100px-square.xht",
        "=="
       ]
@@ -57183,6 +57203,78 @@
      {}
     ]
    ],
+   "fonts/matching/fixed-stretch-style-over-weight.html": [
+    [
+     "/fonts/matching/fixed-stretch-style-over-weight.html",
+     [
+      [
+       "/fonts/matching/fixed-stretch-style-over-weight-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "fonts/matching/stretch-distance-over-weight-distance.html": [
+    [
+     "/fonts/matching/stretch-distance-over-weight-distance.html",
+     [
+      [
+       "/fonts/matching/stretch-distance-over-weight-distance-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "fonts/matching/style-ranges-over-weight-direction.html": [
+    [
+     "/fonts/matching/style-ranges-over-weight-direction.html",
+     [
+      [
+       "/fonts/matching/style-ranges-over-weight-direction-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "fonts/variations/variable-box-font.html": [
+    [
+     "/fonts/variations/variable-box-font.html",
+     [
+      [
+       "/fonts/variations/variable-box-font-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "fonts/variations/variable-gpos-m2b.html": [
+    [
+     "/fonts/variations/variable-gpos-m2b.html",
+     [
+      [
+       "/fonts/variations/variable-gpos-m2b-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "fonts/variations/variable-gsub.html": [
+    [
+     "/fonts/variations/variable-gsub.html",
+     [
+      [
+       "/fonts/variations/variable-gsub-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "html/dom/elements/global-attributes/dir_auto-EN-L.html": [
     [
      "/html/dom/elements/global-attributes/dir_auto-EN-L.html",
@@ -74791,6 +74883,16 @@
      {}
     ]
    ],
+   "css/css-tables-3/floats/floats-wrap-bfc-006b-ref.xht": [
+    [
+     {}
+    ]
+   ],
+   "css/css-tables-3/floats/floats-wrap-bfc-006c-ref.xht": [
+    [
+     {}
+    ]
+   ],
    "css/css-text-3/i18n/css3-text-line-break-baspglwj-026-expected.txt": [
     [
      {}
@@ -83051,21 +83153,11 @@
      {}
     ]
    ],
-   "cssom-view/elementFromPoint-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "cssom-view/elementFromPosition-expected.txt": [
     [
      {}
     ]
    ],
-   "cssom-view/elementsFromPoint-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "cssom-view/iframe.html": [
     [
      {}
@@ -86226,11 +86318,66 @@
      {}
     ]
    ],
+   "fonts/Ahem.ttf": [
+    [
+     {}
+    ]
+   ],
    "fonts/CanvasTest.ttf": [
     [
      {}
     ]
    ],
+   "fonts/matching/README.md": [
+    [
+     {}
+    ]
+   ],
+   "fonts/matching/fixed-stretch-style-over-weight-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "fonts/matching/font-matching.css": [
+    [
+     {}
+    ]
+   ],
+   "fonts/matching/resources/variabletest_matching.ttf": [
+    [
+     {}
+    ]
+   ],
+   "fonts/matching/stretch-distance-over-weight-distance-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "fonts/matching/style-ranges-over-weight-direction-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "fonts/variations/resources/variabletest_box.ttf": [
+    [
+     {}
+    ]
+   ],
+   "fonts/variations/variable-box-font-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "fonts/variations/variable-gpos-m2b-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "fonts/variations/variable-gsub-ref.html": [
+    [
+     {}
+    ]
+   ],
    "fullscreen/api/document-exit-fullscreen-active-document-expected.txt": [
     [
      {}
@@ -95516,6 +95663,11 @@
      {}
     ]
    ],
+   "html/semantics/forms/the-label-element/iframe-label-attributes.html": [
+    [
+     {}
+    ]
+   ],
    "html/semantics/forms/the-label-element/labelable-elements-expected.txt": [
     [
      {}
@@ -96221,6 +96373,16 @@
      {}
     ]
    ],
+   "html/semantics/scripting-1/the-script-element/module/resources/check-cookie.py": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/scripting-1/the-script-element/module/resources/credentials-iframe.sub.html": [
+    [
+     {}
+    ]
+   ],
    "html/semantics/scripting-1/the-script-element/module/resources/delayed-modulescript.py": [
     [
      {}
@@ -98131,6 +98293,36 @@
      {}
     ]
    ],
+   "intersection-observer/observer-in-iframe.html": [
+    [
+     {}
+    ]
+   ],
+   "intersection-observer/resources/cross-origin-subframe.html": [
+    [
+     {}
+    ]
+   ],
+   "intersection-observer/resources/iframe-no-root-subframe.html": [
+    [
+     {}
+    ]
+   ],
+   "intersection-observer/resources/intersection-observer-test-utils.js": [
+    [
+     {}
+    ]
+   ],
+   "intersection-observer/resources/observer-in-iframe-subframe.html": [
+    [
+     {}
+    ]
+   ],
+   "intersection-observer/resources/timestamp-subframe.html": [
+    [
+     {}
+    ]
+   ],
    "keyboard-lock/idlharness.https-expected.txt": [
     [
      {}
@@ -103311,11 +103503,6 @@
      {}
     ]
    ],
-   "service-workers/service-worker/claim-fetch.https-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "service-workers/service-worker/clients-get-client-types.https-expected.txt": [
     [
      {}
@@ -103326,11 +103513,6 @@
      {}
     ]
    ],
-   "service-workers/service-worker/controller-on-disconnect.https-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "service-workers/service-worker/fetch-canvas-tainting-cache.https-expected.txt": [
     [
      {}
@@ -103551,6 +103733,16 @@
      {}
     ]
    ],
+   "service-workers/service-worker/resources/bytecheck-worker-imported-script.py": [
+    [
+     {}
+    ]
+   ],
+   "service-workers/service-worker/resources/bytecheck-worker.py": [
+    [
+     {}
+    ]
+   ],
    "service-workers/service-worker/resources/claim-with-redirect-iframe.html": [
     [
      {}
@@ -105686,21 +105878,6 @@
      {}
     ]
    ],
-   "web-animations/animation-model/animation-types/spacing-keyframes-filters-expected.txt": [
-    [
-     {}
-    ]
-   ],
-   "web-animations/animation-model/animation-types/spacing-keyframes-shapes-expected.txt": [
-    [
-     {}
-    ]
-   ],
-   "web-animations/animation-model/animation-types/spacing-keyframes-transform-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "web-animations/animation-model/combining-effects/effect-composition-expected.txt": [
     [
      {}
@@ -105711,11 +105888,6 @@
      {}
     ]
    ],
-   "web-animations/animation-model/keyframe-effects/spacing-keyframes-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "web-animations/interfaces/Animatable/animate-expected.txt": [
     [
      {}
@@ -105796,21 +105968,11 @@
      {}
     ]
    ],
-   "web-animations/interfaces/KeyframeEffect/spacing-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "web-animations/interfaces/KeyframeEffectReadOnly/copy-contructor-expected.txt": [
     [
      {}
     ]
    ],
-   "web-animations/interfaces/KeyframeEffectReadOnly/spacing-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "web-animations/resources/easing-tests.js": [
     [
      {}
@@ -106141,6 +106303,16 @@
      {}
     ]
    ],
+   "webrtc/RTCPeerConnection-addIceCandidate-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "webrtc/RTCPeerConnection-addTrack-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "webrtc/RTCPeerConnection-addTransceiver-expected.txt": [
     [
      {}
@@ -133514,6 +133686,12 @@
      {}
     ]
    ],
+   "html/semantics/embedded-content/the-img-element/adoption.html": [
+    [
+     "/html/semantics/embedded-content/the-img-element/adoption.html",
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/the-img-element/current-pixel-density/error.html": [
     [
      "/html/semantics/embedded-content/the-img-element/current-pixel-density/error.html",
@@ -133544,6 +133722,12 @@
      {}
     ]
    ],
+   "html/semantics/embedded-content/the-img-element/non-active-document.html": [
+    [
+     "/html/semantics/embedded-content/the-img-element/non-active-document.html",
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/the-img-element/nonexistent-image.html": [
     [
      "/html/semantics/embedded-content/the-img-element/nonexistent-image.html",
@@ -134452,6 +134636,12 @@
      {}
     ]
    ],
+   "html/semantics/forms/the-textarea-element/value-defaultValue-textContent-xhtml.xhtml": [
+    [
+     "/html/semantics/forms/the-textarea-element/value-defaultValue-textContent-xhtml.xhtml",
+     {}
+    ]
+   ],
    "html/semantics/forms/the-textarea-element/value-defaultValue-textContent.html": [
     [
      "/html/semantics/forms/the-textarea-element/value-defaultValue-textContent.html",
@@ -134752,6 +134942,12 @@
      {}
     ]
    ],
+   "html/semantics/scripting-1/the-script-element/module/credentials.sub.html": [
+    [
+     "/html/semantics/scripting-1/the-script-element/module/credentials.sub.html",
+     {}
+    ]
+   ],
    "html/semantics/scripting-1/the-script-element/module/crossorigin.html": [
     [
      "/html/semantics/scripting-1/the-script-element/module/crossorigin.html",
@@ -136998,6 +137194,12 @@
      {}
     ]
    ],
+   "html/webappapis/idle-callbacks/callback-xhr-sync.html": [
+    [
+     "/html/webappapis/idle-callbacks/callback-xhr-sync.html",
+     {}
+    ]
+   ],
    "html/webappapis/idle-callbacks/cancel-invoked.html": [
     [
      "/html/webappapis/idle-callbacks/cancel-invoked.html",
@@ -137716,6 +137918,144 @@
      {}
     ]
    ],
+   "intersection-observer/bounding-box.html": [
+    [
+     "/intersection-observer/bounding-box.html",
+     {}
+    ]
+   ],
+   "intersection-observer/client-rect.html": [
+    [
+     "/intersection-observer/client-rect.html",
+     {}
+    ]
+   ],
+   "intersection-observer/containing-block.html": [
+    [
+     "/intersection-observer/containing-block.html",
+     {}
+    ]
+   ],
+   "intersection-observer/cross-origin-iframe.html": [
+    [
+     "/intersection-observer/cross-origin-iframe.html",
+     {}
+    ]
+   ],
+   "intersection-observer/disconnect.html": [
+    [
+     "/intersection-observer/disconnect.html",
+     {}
+    ]
+   ],
+   "intersection-observer/display-none.html": [
+    [
+     "/intersection-observer/display-none.html",
+     {}
+    ]
+   ],
+   "intersection-observer/edge-inclusive-intersection.html": [
+    [
+     "/intersection-observer/edge-inclusive-intersection.html",
+     {}
+    ]
+   ],
+   "intersection-observer/iframe-no-root.html": [
+    [
+     "/intersection-observer/iframe-no-root.html",
+     {}
+    ]
+   ],
+   "intersection-observer/multiple-targets.html": [
+    [
+     "/intersection-observer/multiple-targets.html",
+     {}
+    ]
+   ],
+   "intersection-observer/multiple-thresholds.html": [
+    [
+     "/intersection-observer/multiple-thresholds.html",
+     {}
+    ]
+   ],
+   "intersection-observer/observer-attributes.html": [
+    [
+     "/intersection-observer/observer-attributes.html",
+     {}
+    ]
+   ],
+   "intersection-observer/observer-exceptions.html": [
+    [
+     "/intersection-observer/observer-exceptions.html",
+     {}
+    ]
+   ],
+   "intersection-observer/observer-without-js-reference.html": [
+    [
+     "/intersection-observer/observer-without-js-reference.html",
+     {}
+    ]
+   ],
+   "intersection-observer/remove-element.html": [
+    [
+     "/intersection-observer/remove-element.html",
+     {}
+    ]
+   ],
+   "intersection-observer/root-margin.html": [
+    [
+     "/intersection-observer/root-margin.html",
+     {}
+    ]
+   ],
+   "intersection-observer/same-document-no-root.html": [
+    [
+     "/intersection-observer/same-document-no-root.html",
+     {}
+    ]
+   ],
+   "intersection-observer/same-document-root.html": [
+    [
+     "/intersection-observer/same-document-root.html",
+     {}
+    ]
+   ],
+   "intersection-observer/same-document-zero-size-target.html": [
+    [
+     "/intersection-observer/same-document-zero-size-target.html",
+     {}
+    ]
+   ],
+   "intersection-observer/shadow-content.html": [
+    [
+     "/intersection-observer/shadow-content.html",
+     {}
+    ]
+   ],
+   "intersection-observer/timestamp.html": [
+    [
+     "/intersection-observer/timestamp.html",
+     {}
+    ]
+   ],
+   "intersection-observer/unclipped-root.html": [
+    [
+     "/intersection-observer/unclipped-root.html",
+     {}
+    ]
+   ],
+   "intersection-observer/zero-area-element-hidden.html": [
+    [
+     "/intersection-observer/zero-area-element-hidden.html",
+     {}
+    ]
+   ],
+   "intersection-observer/zero-area-element-visible.html": [
+    [
+     "/intersection-observer/zero-area-element-visible.html",
+     {}
+    ]
+   ],
    "keyboard-lock/idlharness.https.html": [
     [
      "/keyboard-lock/idlharness.https.html",
@@ -149245,7 +149585,9 @@
    "payment-request/payment-request-constructor-crash.https.html": [
     [
      "/payment-request/payment-request-constructor-crash.https.html",
-     {}
+     {
+      "timeout": "long"
+     }
     ]
    ],
    "payment-request/payment-request-constructor.https.html": [
@@ -159446,6 +159788,12 @@
      {}
     ]
    ],
+   "service-workers/service-worker/update-bytecheck.https.html": [
+    [
+     "/service-workers/service-worker/update-bytecheck.https.html",
+     {}
+    ]
+   ],
    "service-workers/service-worker/update-recovery.https.html": [
     [
      "/service-workers/service-worker/update-recovery.https.html",
@@ -161566,24 +161914,6 @@
      {}
     ]
    ],
-   "web-animations/animation-model/animation-types/spacing-keyframes-filters.html": [
-    [
-     "/web-animations/animation-model/animation-types/spacing-keyframes-filters.html",
-     {}
-    ]
-   ],
-   "web-animations/animation-model/animation-types/spacing-keyframes-shapes.html": [
-    [
-     "/web-animations/animation-model/animation-types/spacing-keyframes-shapes.html",
-     {}
-    ]
-   ],
-   "web-animations/animation-model/animation-types/spacing-keyframes-transform.html": [
-    [
-     "/web-animations/animation-model/animation-types/spacing-keyframes-transform.html",
-     {}
-    ]
-   ],
    "web-animations/animation-model/combining-effects/effect-composition.html": [
     [
      "/web-animations/animation-model/combining-effects/effect-composition.html",
@@ -161614,12 +161944,6 @@
      {}
     ]
    ],
-   "web-animations/animation-model/keyframe-effects/spacing-keyframes.html": [
-    [
-     "/web-animations/animation-model/keyframe-effects/spacing-keyframes.html",
-     {}
-    ]
-   ],
    "web-animations/interfaces/Animatable/animate.html": [
     [
      "/web-animations/interfaces/Animatable/animate.html",
@@ -161854,24 +162178,12 @@
      {}
     ]
    ],
-   "web-animations/interfaces/KeyframeEffect/spacing.html": [
-    [
-     "/web-animations/interfaces/KeyframeEffect/spacing.html",
-     {}
-    ]
-   ],
    "web-animations/interfaces/KeyframeEffectReadOnly/copy-contructor.html": [
     [
      "/web-animations/interfaces/KeyframeEffectReadOnly/copy-contructor.html",
      {}
     ]
    ],
-   "web-animations/interfaces/KeyframeEffectReadOnly/spacing.html": [
-    [
-     "/web-animations/interfaces/KeyframeEffectReadOnly/spacing.html",
-     {}
-    ]
-   ],
    "web-animations/timing-model/animation-effects/active-time.html": [
     [
      "/web-animations/timing-model/animation-effects/active-time.html",
@@ -177810,7 +178122,7 @@
    "testharness"
   ],
   "XMLHttpRequest/open-url-worker-origin.htm": [
-   "f105c0e4b249f82545f2763c4b1a23a3a217e3a7",
+   "1e377fb04baa8c55c2d656b572f285cfe71cbc7c",
    "testharness"
   ],
   "XMLHttpRequest/open-url-worker-simple.htm": [
@@ -181906,7 +182218,7 @@
    "testharness"
   ],
   "credential-management/idl.https.html": [
-   "0df70baded35ef70ab7395c8933ba7e1d041aa85",
+   "e9a108beef51c52bbaaf2e53371aec57e69541c0",
    "testharness"
   ],
   "css-font-display/font-display-ref.html": [
@@ -201081,6 +201393,22 @@
    "5bb192165bcb7d9a619d86dbff61831fc8de71cb",
    "support"
   ],
+  "css/css-tables-3/floats/floats-wrap-bfc-006b-ref.xht": [
+   "22f5ec058d34dc57c010bca8a301eaa8f7901880",
+   "support"
+  ],
+  "css/css-tables-3/floats/floats-wrap-bfc-006b.xht": [
+   "04189b6b9f5b3399757178c42ae8ee66ab7a2053",
+   "reftest"
+  ],
+  "css/css-tables-3/floats/floats-wrap-bfc-006c-ref.xht": [
+   "a98a786227b3c406ed784a4a1c5d847efdacfeff",
+   "support"
+  ],
+  "css/css-tables-3/floats/floats-wrap-bfc-006c.xht": [
+   "2e974c516d48ec57de1d7ccce28d9cced148cadd",
+   "reftest"
+  ],
   "css/css-text-3/i18n/css3-text-line-break-baspglwj-001.html": [
    "b08dfce276ccafb057c793d69c25cf0caff332cc",
    "testharness"
@@ -206238,7 +206566,7 @@
    "reftest"
   ],
   "css/css-ui-3/box-sizing-026.html": [
-   "6bb008f9fa588f7b70bcef848418f6859471bd68",
+   "6a26323ef89863c263b04b5818210dd2c5e56b01",
    "reftest"
   ],
   "css/css-ui-3/box-sizing-027.html": [
@@ -217365,12 +217693,8 @@
    "bf1c490777f450275a95ecfc6d6d2c0d055aca82",
    "testharness"
   ],
-  "cssom-view/elementFromPoint-expected.txt": [
-   "4b41849e5533450c37912448d30c5547a2d45778",
-   "support"
-  ],
   "cssom-view/elementFromPoint.html": [
-   "e22ae99aa1fba51807aec245b810db5d584ac037",
+   "0f78405640523cf451b19ea0348b8216139b8168",
    "testharness"
   ],
   "cssom-view/elementFromPosition-expected.txt": [
@@ -217385,12 +217709,8 @@
    "24c65428976fc4971a33368e6bf6f8b77199d69b",
    "testharness"
   ],
-  "cssom-view/elementsFromPoint-expected.txt": [
-   "93474d77bf64dffc22ed6a1d25ead6432215ee29",
-   "support"
-  ],
   "cssom-view/elementsFromPoint.html": [
-   "d7d35ebb7041d1a0b67d01a51ab125eee5a8e7b2",
+   "72967af1e05060624a2eaacd059a59bcedacd934",
    "testharness"
   ],
   "cssom-view/historical.html": [
@@ -217762,7 +218082,7 @@
    "testharness"
   ],
   "cssom/getComputedStyle-pseudo.html": [
-   "6c74e57a2e32a13cc3b7e955a2d89dafdf6d1730",
+   "b9d037db577325526d2414270d2ceefcd6587a6d",
    "testharness"
   ],
   "cssom/historical.html": [
@@ -218222,7 +218542,7 @@
    "testharness"
   ],
   "custom-elements/reactions/ChildNode.html": [
-   "90995dda943b6fa08e16f99afc2948b63c3cb4b9",
+   "abd91594d98ab546b9901c70fb9797532b269f5e",
    "testharness"
   ],
   "custom-elements/reactions/DOMStringMap.html": [
@@ -220058,7 +220378,7 @@
    "testharness"
   ],
   "domparsing/xml-serialization.xhtml": [
-   "71944bd6e03639c4736db03b651e265d103cf5cf",
+   "b62d4cf898f819ccaf02769de3af12cdc80cea7e",
    "testharness"
   ],
   "domxpath/001.html": [
@@ -220582,7 +220902,7 @@
    "support"
   ],
   "encoding/iso-2022-jp-decoder.html": [
-   "551248ae4bf66d051697af82978f21c6d4812d1a",
+   "c189c2f99ee066e9419fdebef5d620edf97cd785",
    "testharness"
   ],
   "encoding/iso-2022-jp-encoder.html": [
@@ -222666,7 +222986,7 @@
    "testharness"
   ],
   "fetch/api/headers/headers-record.html": [
-   "a1daa97525019a1ff4b2951d788c97f6394bf705",
+   "84652a79c8ff64826faff6151cf4a48450e706d1",
    "testharness"
   ],
   "fetch/api/headers/headers-structure.html": [
@@ -223377,10 +223697,78 @@
    "09ab38acc0bc980af3e96a61390cd000885b2fe5",
    "support"
   ],
+  "fonts/Ahem.ttf": [
+   "8cdc9e68594fbb6db8c7b4bff643ab2432b51db6",
+   "support"
+  ],
   "fonts/CanvasTest.ttf": [
    "10a7017b4caead6817aa08b25f14950e6402dd95",
    "support"
   ],
+  "fonts/matching/README.md": [
+   "194fbc4cdaf1ff4a43e1a4e6b7bc7fbc17eec6d8",
+   "support"
+  ],
+  "fonts/matching/fixed-stretch-style-over-weight-ref.html": [
+   "ad90e9467acd3120ba00239b453199aa95497c5e",
+   "support"
+  ],
+  "fonts/matching/fixed-stretch-style-over-weight.html": [
+   "9416d454fb13f9cdf3f8335ef2b93875b630fd66",
+   "reftest"
+  ],
+  "fonts/matching/font-matching.css": [
+   "aa898540134a6971823aba54b36027a436c99fd9",
+   "support"
+  ],
+  "fonts/matching/resources/variabletest_matching.ttf": [
+   "de5e05decac0303e5297ed2cb067c715ff4c4adf",
+   "support"
+  ],
+  "fonts/matching/stretch-distance-over-weight-distance-ref.html": [
+   "40ff6866132dd3e29a8d85c5fd949aba729ae304",
+   "support"
+  ],
+  "fonts/matching/stretch-distance-over-weight-distance.html": [
+   "334199682aa1641d9904d5fb38be61f96c590a8f",
+   "reftest"
+  ],
+  "fonts/matching/style-ranges-over-weight-direction-ref.html": [
+   "05fe52539dc7bb809fc88ee1fee597288d843bf1",
+   "support"
+  ],
+  "fonts/matching/style-ranges-over-weight-direction.html": [
+   "7c9fdc01ea1591a5926942f5c577ff8fbd36b260",
+   "reftest"
+  ],
+  "fonts/variations/resources/variabletest_box.ttf": [
+   "2fc122ff444d3ddef1f29ebde9a87827244ceeb0",
+   "support"
+  ],
+  "fonts/variations/variable-box-font-ref.html": [
+   "65ccabcdeaa322eeceaa646863eba52654e3149b",
+   "support"
+  ],
+  "fonts/variations/variable-box-font.html": [
+   "f3836fd9ea898b84bcef5dc259eeadbd4ecaeb68",
+   "reftest"
+  ],
+  "fonts/variations/variable-gpos-m2b-ref.html": [
+   "769b04d218db5f7d882512b17c70683281499481",
+   "support"
+  ],
+  "fonts/variations/variable-gpos-m2b.html": [
+   "af751a58338e49cc18b0b54c9451662d223f4977",
+   "reftest"
+  ],
+  "fonts/variations/variable-gsub-ref.html": [
+   "1b80955335d4a14f3e0d545a6b5165aadff05a87",
+   "support"
+  ],
+  "fonts/variations/variable-gsub.html": [
+   "2ae8392efc584c909f11ca04fb33a77f1b3c65ba",
+   "reftest"
+  ],
   "fullscreen/api/document-exit-fullscreen-active-document-expected.txt": [
    "0fe00e0f1b873cef51a3c142190ce821a76549ed",
    "support"
@@ -227298,7 +227686,7 @@
    "support"
   ],
   "html/dom/elements-metadata.js": [
-   "7e6becc4e2f4136a1c64d28724d1f21160900dd1",
+   "90f32be5438bee67e318095032ad70afe4d204d0",
    "support"
   ],
   "html/dom/elements-misc.js": [
@@ -234537,6 +234925,10 @@
    "2047645c2bdecc90189878cc68e861087d7bd84b",
    "testharness"
   ],
+  "html/semantics/embedded-content/the-img-element/adoption.html": [
+   "6786386a825f42b04733a2e91c5e95ea907c00fc",
+   "testharness"
+  ],
   "html/semantics/embedded-content/the-img-element/brokenimg.jpg": [
    "200b8085f98203ccf455504727ba9d92203f1080",
    "support"
@@ -234609,6 +235001,10 @@
    "1d58aab3f3fee594404e34681bde43f85824a738",
    "manual"
   ],
+  "html/semantics/embedded-content/the-img-element/non-active-document.html": [
+   "ad443ef3039e99c92de2d14bfe7d1b93cd5bdb0c",
+   "testharness"
+  ],
   "html/semantics/embedded-content/the-img-element/nonexistent-image.html": [
    "ed3a4e8ec0ffe8411176c91de37e965f252534cd",
    "testharness"
@@ -235413,8 +235809,12 @@
    "da39a3ee5e6b4b0d3255bfef95601890afd80709",
    "support"
   ],
+  "html/semantics/forms/the-label-element/iframe-label-attributes.html": [
+   "3629d93c34f27a575114b15256803941c9893f6e",
+   "support"
+  ],
   "html/semantics/forms/the-label-element/label-attributes.html": [
-   "bb00ee78b9fa2343d85dcaa13376a832d376617a",
+   "612957c0c5b28b8797118eb5975bb41bc240d257",
    "testharness"
   ],
   "html/semantics/forms/the-label-element/labelable-elements-expected.txt": [
@@ -235422,7 +235822,7 @@
    "support"
   ],
   "html/semantics/forms/the-label-element/labelable-elements.html": [
-   "421328f898fb2487152f6fd8df315fc22ddea61a",
+   "80275984254360d8b713b5b330c18ae34138b670",
    "testharness"
   ],
   "html/semantics/forms/the-label-element/proxy-click-to-associated-element.html": [
@@ -235601,8 +236001,12 @@
    "81a270bc3c9304f8b2e7dd526519f4eab7d94f45",
    "testharness"
   ],
+  "html/semantics/forms/the-textarea-element/value-defaultValue-textContent-xhtml.xhtml": [
+   "03ce5d00e9887037bbd96f2d49e116c6b3329802",
+   "testharness"
+  ],
   "html/semantics/forms/the-textarea-element/value-defaultValue-textContent.html": [
-   "55e04e640fd48d92c4be16a912cba57fb4bb9e27",
+   "67af41d4d44f0de60b952cb15db93b2938133bcf",
    "testharness"
   ],
   "html/semantics/forms/the-textarea-element/wrap-reflect-1-ref.html": [
@@ -236233,6 +236637,10 @@
    "fe3191547b7292f0c486febe0cef930a0a8fa590",
    "testharness"
   ],
+  "html/semantics/scripting-1/the-script-element/module/credentials.sub.html": [
+   "52879d70166ca501a81688766ef9b928660796ab",
+   "testharness"
+  ],
   "html/semantics/scripting-1/the-script-element/module/crossorigin-common.js": [
    "a58804b6e2495f99ec3f8b7894ff52186a49a427",
    "support"
@@ -236517,6 +236925,14 @@
    "4ce8bcce2537785c41f054175119e39169ed6110",
    "testharness"
   ],
+  "html/semantics/scripting-1/the-script-element/module/resources/check-cookie.py": [
+   "49a8855de3a01f4fa8abfd5c9dbc3d0c1af2e182",
+   "support"
+  ],
+  "html/semantics/scripting-1/the-script-element/module/resources/credentials-iframe.sub.html": [
+   "78e5b389be7049324224b89562eaf39fb0e1a9e5",
+   "support"
+  ],
   "html/semantics/scripting-1/the-script-element/module/resources/delayed-modulescript.py": [
    "f09db3d2acdf3aba3fc8c67b2f089a0ba506c799",
    "support"
@@ -238513,6 +238929,10 @@
    "ba76964575cdf9b433f26c8a5d7a8183ab5c16e9",
    "testharness"
   ],
+  "html/webappapis/idle-callbacks/callback-xhr-sync.html": [
+   "272a688feaefc3c1ebab315ae9f4633f11a966f1",
+   "testharness"
+  ],
   "html/webappapis/idle-callbacks/cancel-invoked.html": [
    "30787d765fa435c1392bd852559042bf3c2e2553",
    "testharness"
@@ -239569,6 +239989,122 @@
    "7b5749e1fece69552e0a8bfac7af401fac15394d",
    "support"
   ],
+  "intersection-observer/bounding-box.html": [
+   "a3ac1b70ba26234b7c968055171e652f3a8a14d8",
+   "testharness"
+  ],
+  "intersection-observer/client-rect.html": [
+   "acec9a4f59ebee1840950cf766a45676490eef84",
+   "testharness"
+  ],
+  "intersection-observer/containing-block.html": [
+   "8bdf6fa6a3ee09130981bf83728aa9f61a6ebc54",
+   "testharness"
+  ],
+  "intersection-observer/cross-origin-iframe.html": [
+   "98ac8bd3447bc16e86c4b15708dcd86aa4b5ed92",
+   "testharness"
+  ],
+  "intersection-observer/disconnect.html": [
+   "d8206b91756a367394ea9d444deefc0f37589427",
+   "testharness"
+  ],
+  "intersection-observer/display-none.html": [
+   "3dc956e76b23ae44f2694f4b24579f896a1086b5",
+   "testharness"
+  ],
+  "intersection-observer/edge-inclusive-intersection.html": [
+   "97921caeabdafb402de1a6f64fc28176eda3e6db",
+   "testharness"
+  ],
+  "intersection-observer/iframe-no-root.html": [
+   "6cbea44f209e59ea0b901b0fe1cec7ac1aee0b64",
+   "testharness"
+  ],
+  "intersection-observer/multiple-targets.html": [
+   "83173248b825b97063c61dd31c64d8fe7ba10aac",
+   "testharness"
+  ],
+  "intersection-observer/multiple-thresholds.html": [
+   "dcfa7d005d1f94186b173b20d4f9c367abc5a77b",
+   "testharness"
+  ],
+  "intersection-observer/observer-attributes.html": [
+   "69c802af77a38c450ce81c4c010588b0e4f240db",
+   "testharness"
+  ],
+  "intersection-observer/observer-exceptions.html": [
+   "28ccc6905713894b43033e30949170439215bf2e",
+   "testharness"
+  ],
+  "intersection-observer/observer-in-iframe.html": [
+   "3e6dcbc7aac43899186395f50649195b2ecc4c74",
+   "support"
+  ],
+  "intersection-observer/observer-without-js-reference.html": [
+   "4211529e1fdd3bfb9b3b64c29b7d000b3c706408",
+   "testharness"
+  ],
+  "intersection-observer/remove-element.html": [
+   "f2b3688fd8e069a41e16086baad74bda0fe2f180",
+   "testharness"
+  ],
+  "intersection-observer/resources/cross-origin-subframe.html": [
+   "91073aed8b250177d69ee36e9be95c30c9cf1c95",
+   "support"
+  ],
+  "intersection-observer/resources/iframe-no-root-subframe.html": [
+   "a9ea444d6bb15cda784871e2d495dc204b0e3d50",
+   "support"
+  ],
+  "intersection-observer/resources/intersection-observer-test-utils.js": [
+   "889d403e334e3c0fc4ae7a6af06ef9504145fa2b",
+   "support"
+  ],
+  "intersection-observer/resources/observer-in-iframe-subframe.html": [
+   "5f390b2e969132bce9ab486cbf2292765d5c62f2",
+   "support"
+  ],
+  "intersection-observer/resources/timestamp-subframe.html": [
+   "7b590da7cf426cc7d2e3f25fac30f4533e36153c",
+   "support"
+  ],
+  "intersection-observer/root-margin.html": [
+   "be98d804610d2c08ee516a4aecbe59ffc58c22bd",
+   "testharness"
+  ],
+  "intersection-observer/same-document-no-root.html": [
+   "0f29996e4542db243c3fcd9c108463ba7260cb8e",
+   "testharness"
+  ],
+  "intersection-observer/same-document-root.html": [
+   "71876c5290184f77223843c7d3c0bed670e2ee3f",
+   "testharness"
+  ],
+  "intersection-observer/same-document-zero-size-target.html": [
+   "c1d1054447e116becb50aaf96aad00a25f0a6752",
+   "testharness"
+  ],
+  "intersection-observer/shadow-content.html": [
+   "11681640d5c8b2c62229ed5a717172f917d75ba4",
+   "testharness"
+  ],
+  "intersection-observer/timestamp.html": [
+   "cf4e91716ed1d02935c3c73ee639e566cf5b60a4",
+   "testharness"
+  ],
+  "intersection-observer/unclipped-root.html": [
+   "67dab96304c745f1b5462bb1074753b09d77fbd1",
+   "testharness"
+  ],
+  "intersection-observer/zero-area-element-hidden.html": [
+   "59d854e89ca0d7b035a87376566775ca2f3420e5",
+   "testharness"
+  ],
+  "intersection-observer/zero-area-element-visible.html": [
+   "f3e1fbeb1a912be412724cec47a6aa981664ff7d",
+   "testharness"
+  ],
   "keyboard-lock/idlharness.https-expected.txt": [
    "c78b5d669f56d9f602ca93c9e7492a7fee9839b1",
    "support"
@@ -239770,7 +240306,7 @@
    "testharness"
   ],
   "media-source/mediasource-append-buffer.html": [
-   "56f0d90f006e300a412ec7ceb3c15a252ff303a5",
+   "fed1254d64c59b625af9745bbffcf5788ac5906e",
    "testharness"
   ],
   "media-source/mediasource-appendbuffer-quota-exceeded.html": [
@@ -239982,7 +240518,7 @@
    "testharness"
   ],
   "media-source/mediasource-seekable.html": [
-   "5f75983eeb4eed4095a625ec997c01eaba021166",
+   "6e92616bfb23e0d00e387688ff6754e68b1da35f",
    "testharness"
   ],
   "media-source/mediasource-sequencemode-append-buffer-expected.txt": [
@@ -248814,7 +249350,7 @@
    "support"
   ],
   "payment-request/payment-request-constructor-crash.https.html": [
-   "bbf131cd4517d450299cac05560a137c23f47e8f",
+   "dd2f95bd4d94a819c507e942b19a60de05a16971",
    "testharness"
   ],
   "payment-request/payment-request-constructor.https.html": [
@@ -258097,10 +258633,6 @@
    "96ffb6f3376a5fa73abd405e123d019d8cac694d",
    "testharness"
   ],
-  "service-workers/service-worker/claim-fetch.https-expected.txt": [
-   "3e8688f2e8a82a93770a06f99fcece6d09e4e118",
-   "support"
-  ],
   "service-workers/service-worker/claim-fetch.https.html": [
    "69100d1070d261e9819217fd7a6531f48b343e14",
    "testharness"
@@ -258169,10 +258701,6 @@
    "17d76ba9e5a93d8e13c99773c673911786c8abf3",
    "testharness"
   ],
-  "service-workers/service-worker/controller-on-disconnect.https-expected.txt": [
-   "0d0da3a2e5bfdcc0894229b69ac8f93887f855d6",
-   "support"
-  ],
   "service-workers/service-worker/controller-on-disconnect.https.html": [
    "fe9bcecbb8c7379a6f8da0420cc15a36a9e8060b",
    "testharness"
@@ -258741,6 +259269,14 @@
    "0ddb4f1cf84729ed673295719ec58a3e5d600a12",
    "support"
   ],
+  "service-workers/service-worker/resources/bytecheck-worker-imported-script.py": [
+   "772d029d4efbe22f62f3473d4afe9e501a792571",
+   "support"
+  ],
+  "service-workers/service-worker/resources/bytecheck-worker.py": [
+   "66ec51461bc4da5862a9c4d06a9468a8dbe1d134",
+   "support"
+  ],
   "service-workers/service-worker/resources/claim-with-redirect-iframe.html": [
    "fdc472f4e9a591f0b471174b2aa1783107731f49",
    "support"
@@ -258886,7 +259422,7 @@
    "support"
   ],
   "service-workers/service-worker/resources/fetch-canvas-tainting-iframe.html": [
-   "e5f5268bae71585f0bb7ad113e2fbe7dd55de893",
+   "aee62d5b6ee22664c493036c879ed8d530b5ba1d",
    "support"
   ],
   "service-workers/service-worker/resources/fetch-cors-xhr-iframe.html": [
@@ -259066,7 +259602,7 @@
    "support"
   ],
   "service-workers/service-worker/resources/fetch-response-xhr-iframe.https.html": [
-   "5b29c0807de1229631a27ad3c9d66f288631938a",
+   "8a7db09b6c8f89414e6310c3744361f545f44758",
    "support"
   ],
   "service-workers/service-worker/resources/fetch-response-xhr-worker.js": [
@@ -259617,6 +260153,10 @@
    "9f43ba359c4d564f75d4ce4b6a040aac6ba50d5b",
    "testharness"
   ],
+  "service-workers/service-worker/update-bytecheck.https.html": [
+   "ab13a5489f964de56db2fe25c5895a8a55ab7d88",
+   "testharness"
+  ],
   "service-workers/service-worker/update-recovery.https-expected.txt": [
    "081ec815f2846d54a46061ea0c50c68469ccaeb0",
    "support"
@@ -262274,37 +262814,13 @@
    "testharness"
   ],
   "web-animations/animation-model/animation-types/property-list.js": [
-   "83a52204cc36f6b757129dae947f03f6a8748bde",
+   "9dfb34806dfd264bb1155830b0548d53fcae9007",
    "support"
   ],
   "web-animations/animation-model/animation-types/property-types.js": [
-   "66c606f9451cc30ba6d23bcfffcb61871283b0b8",
+   "750c9270292478d09cf176a5e489043a6707e726",
    "support"
   ],
-  "web-animations/animation-model/animation-types/spacing-keyframes-filters-expected.txt": [
-   "da8fe0c766d05a527459abf893e11c731c11066f",
-   "support"
-  ],
-  "web-animations/animation-model/animation-types/spacing-keyframes-filters.html": [
-   "bd771a8a18245560221d92ea3495f81918c09848",
-   "testharness"
-  ],
-  "web-animations/animation-model/animation-types/spacing-keyframes-shapes-expected.txt": [
-   "1853881a39ce2489749087712bcc4952d0d5af05",
-   "support"
-  ],
-  "web-animations/animation-model/animation-types/spacing-keyframes-shapes.html": [
-   "03c3ab6815cfa96c07d5f95b6059fb276c50a25f",
-   "testharness"
-  ],
-  "web-animations/animation-model/animation-types/spacing-keyframes-transform-expected.txt": [
-   "7c7adb24bd8bb6ed9d77064bd04e09240b2ab972",
-   "support"
-  ],
-  "web-animations/animation-model/animation-types/spacing-keyframes-transform.html": [
-   "c1c5c2ea4580948d00502a048f3e562c61006ab9",
-   "testharness"
-  ],
   "web-animations/animation-model/combining-effects/effect-composition-expected.txt": [
    "81b8e29ad1ee04ce1f5958dfaca07d73a31112ca",
    "support"
@@ -262333,14 +262849,6 @@
    "b01c7c5145c183fdca80dec4ca1966b0f72a7003",
    "testharness"
   ],
-  "web-animations/animation-model/keyframe-effects/spacing-keyframes-expected.txt": [
-   "5e0e93d23dfbc8592e0466c8b52b0e8aecb85c52",
-   "support"
-  ],
-  "web-animations/animation-model/keyframe-effects/spacing-keyframes.html": [
-   "318bc877791852b0829a3e10cb19e2a20a15adab",
-   "testharness"
-  ],
   "web-animations/interfaces/Animatable/animate-expected.txt": [
    "49ecf5fa20817e35b3dad88bebd86ee76bf82b84",
    "support"
@@ -262510,7 +263018,7 @@
    "support"
   ],
   "web-animations/interfaces/KeyframeEffect/constructor.html": [
-   "1011b4146d1054ee6498cce1905230a10fdb9f96",
+   "2bc0a19e2ff3304dfea3286096db46821bca6c16",
    "testharness"
   ],
   "web-animations/interfaces/KeyframeEffect/copy-contructor-expected.txt": [
@@ -262534,7 +263042,7 @@
    "support"
   ],
   "web-animations/interfaces/KeyframeEffect/iterationComposite.html": [
-   "5b7dbc28de885751ea952f4fecc2bd07cb3cea11",
+   "2ed50cdb27335345015d8b13c64ef86c67048757",
    "testharness"
   ],
   "web-animations/interfaces/KeyframeEffect/processing-a-keyframes-argument-expected.txt": [
@@ -262542,7 +263050,7 @@
    "support"
   ],
   "web-animations/interfaces/KeyframeEffect/processing-a-keyframes-argument.html": [
-   "6f561694e38420194fd1817ee965436348221d06",
+   "86ae5b18686e634743913adfcca9f1144b6902a4",
    "testharness"
   ],
   "web-animations/interfaces/KeyframeEffect/setKeyframes-expected.txt": [
@@ -262558,15 +263066,7 @@
    "support"
   ],
   "web-animations/interfaces/KeyframeEffect/setTarget.html": [
-   "a8fe23e2645133e8fb29511d2d4df493a9928330",
-   "testharness"
-  ],
-  "web-animations/interfaces/KeyframeEffect/spacing-expected.txt": [
-   "befda11bbdae314d8f393eedc5fda4cad36a1e03",
-   "support"
-  ],
-  "web-animations/interfaces/KeyframeEffect/spacing.html": [
-   "2231741d51d2645b5ff97fc4ec6156d5bc6cd442",
+   "8c75e6605a134c96e261e5383414b7e15b32d121",
    "testharness"
   ],
   "web-animations/interfaces/KeyframeEffectReadOnly/copy-contructor-expected.txt": [
@@ -262577,24 +263077,16 @@
    "8ef986f13e7fe7ffeb7403f647b4169ac0d6a138",
    "testharness"
   ],
-  "web-animations/interfaces/KeyframeEffectReadOnly/spacing-expected.txt": [
-   "082ae062daeb071146028d2bfac742e6fa88a36f",
-   "support"
-  ],
-  "web-animations/interfaces/KeyframeEffectReadOnly/spacing.html": [
-   "2eb6b663f4ec25284370d16042444c43edb80c02",
-   "testharness"
-  ],
   "web-animations/resources/easing-tests.js": [
    "5ef1183a4d3e12ad3edfe678c9fa002e7edce888",
    "support"
   ],
   "web-animations/resources/keyframe-utils.js": [
-   "ff5700466b5af6ffaad824437d6566003a22e25b",
+   "2903e56e508f7034e1918b5688c8a605db9bae51",
    "support"
   ],
   "web-animations/testcommon.js": [
-   "26d892976e935d0352ef1ede012435cc67be9f79",
+   "d057ad66c4561ef32f83770e4948f2019da89d48",
    "support"
   ],
   "web-animations/timing-model/animation-effects/active-time.html": [
@@ -263501,16 +263993,24 @@
    "6938c88a0167e418aa9e93416865c857cc3489c5",
    "testharness"
   ],
+  "webrtc/RTCPeerConnection-addIceCandidate-expected.txt": [
+   "25c6b1d385430fa4b10c42e25b7846cfdc66a3f5",
+   "support"
+  ],
   "webrtc/RTCPeerConnection-addIceCandidate.html": [
    "811905bc5d380baac18b9ddc2bd96728ffac7597",
    "testharness"
   ],
+  "webrtc/RTCPeerConnection-addTrack-expected.txt": [
+   "6f3643ce52c3ba58f54cc64b85d0bdee499d72a8",
+   "support"
+  ],
   "webrtc/RTCPeerConnection-addTrack.html": [
    "841320f0521a34d84ebd4dd8375e641a0d693c15",
    "testharness"
   ],
   "webrtc/RTCPeerConnection-addTransceiver-expected.txt": [
-   "24da6f2f6e5c18926fe65d3679de5ad10e92cffd",
+   "bae21d855e088b738e179604b5d960b39225a762",
    "support"
   ],
   "webrtc/RTCPeerConnection-addTransceiver.html": [
diff --git a/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/open-url-worker-origin.htm b/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/open-url-worker-origin.htm
index 9f7c5c2..722a15b 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/open-url-worker-origin.htm
+++ b/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/open-url-worker-origin.htm
@@ -12,8 +12,8 @@
     <script type="text/javascript">
         var test = async_test() // This "test" does not actually do any assertations. It's just there to have multiple, separate, asyncronous sub-tests.
         var expectations = {
-            'Referer header': 'referer: '+(location.href.replace(/[^/]*$/, ''))+"resources/workerxhr-origin-referrer.js\n",
-            'Origin header': 'origin: '+location.protocol+'//'+location.hostname+((location.port === "")?"":":"+location.port)+'\n',
+            'Referer header': 'Referer: '+(location.href.replace(/[^/]*$/, ''))+"resources/workerxhr-origin-referrer.js\n",
+            'Origin header': 'Origin: '+location.protocol+'//'+location.hostname+((location.port === "")?"":":"+location.port)+'\n',
             'Request URL test' : (location.href.replace(/[^/]*$/, ''))+'resources/requri.py?full'
         }
         // now start the worker
diff --git a/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/overridemimetype-blob-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/overridemimetype-blob-expected.txt
index 0b5737d..1b0fd78 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/overridemimetype-blob-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/overridemimetype-blob-expected.txt
@@ -1,8 +1,8 @@
 This is a testharness.js-based test.
 FAIL Use text/xml as fallback MIME type assert_equals: expected "text/xml" but got ""
 PASS Use text/xml as fallback MIME type, 2 
-FAIL Bogus MIME type should end up as application/octet-stream assert_equals: expected "" but got "bogus"
-FAIL Bogus MIME type should end up as application/octet-stream, 2 assert_equals: expected "" but got "text/xml;charset=†"
-FAIL Valid MIME types need to be normalized assert_equals: expected "" but got "HI/x;test"
+FAIL Bogus MIME type should end up as application/octet-stream assert_equals: expected "application/octet-stream" but got ""
+FAIL Bogus MIME type should end up as application/octet-stream, 2 assert_equals: expected "application/octet-stream" but got ""
+FAIL Valid MIME types need to be normalized assert_equals: expected "hi/x" but got ""
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/overridemimetype-headers-received-state-force-shiftjis-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/overridemimetype-headers-received-state-force-shiftjis-expected.txt
deleted file mode 100644
index 3c0f52ce..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/overridemimetype-headers-received-state-force-shiftjis-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL XMLHttpRequest: overrideMimeType() in HEADERS RECEIVED state, enforcing Shift-JIS encoding assert_equals: overrideMimeType() in HEADERS RECEIVED state set encoding expected "テスト" but got "\ufffde\ufffdX\ufffdg"
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/overridemimetype-invalid-mime-type-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/overridemimetype-invalid-mime-type-expected.txt
deleted file mode 100644
index eb164f4..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/overridemimetype-invalid-mime-type-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-This is a testharness.js-based test.
-FAIL Bogus MIME type does not override encoding assert_equals: expected "text/html;charset=windows-1252" but got "bogus"
-FAIL Bogus MIME type does not override encoding, 2 assert_equals: expected "ÿ" but got "\ufffd"
-FAIL Bogus MIME type does override MIME type assert_equals: expected "text/xml" but got "bogus"
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-tables-3/floats/floats-wrap-bfc-006b-ref.xht b/third_party/WebKit/LayoutTests/external/wpt/css/css-tables-3/floats/floats-wrap-bfc-006b-ref.xht
new file mode 100644
index 0000000..93cdd3e51
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-tables-3/floats/floats-wrap-bfc-006b-ref.xht
@@ -0,0 +1,59 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="en-US"><head>
+    <title>CSS Test: Test for flow around floats (reference)</title>
+    <link rel="author" title="L. David Baron" href="https://dbaron.org/" />
+    <link rel="author" title="Mozilla Corporation" href="http://mozilla.com/" />
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+    <meta http-equiv="Content-Style-Type" content="text/css" />
+    <style type="text/css">
+
+    body { font-size: 16px; }
+
+    table { margin: 0; border-spacing: 0; }
+    caption, td, th { padding: 0; vertical-align: top; text-align: left; }
+
+    .capref { background: yellow; }
+    .tabref { background: purple; }
+
+    </style>
+</head>
+<body>
+
+<table width="300" style="background: aqua"><tbody><tr><td>
+    <div style="float:left; clear:left; background:blue; width:150px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:145px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:140px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:135px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:130px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:125px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:120px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:115px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:110px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:105px; height:1px"></div>
+
+    <div style="float: right; width: 192px; height: 30px; margin-right: 3px;"><div style="display: inline-block; vertical-align: top; height: 30px; width: 90px;" class="capref">Caption</div><div style="display: inline-block; vertical-align: top; height: 30px; width: 102px;" class="tabref">Cell</div></div>
+
+    <div style="float:left; clear:left; background:blue; width:100px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:95px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:90px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:85px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:80px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:75px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:70px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:65px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:60px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:55px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:50px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:45px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:40px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:35px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:30px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:25px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:20px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:15px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:10px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:5px; height:1px"></div>
+</td></tr></tbody></table>
+
+
+
+</body></html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-tables-3/floats/floats-wrap-bfc-006b.xht b/third_party/WebKit/LayoutTests/external/wpt/css/css-tables-3/floats/floats-wrap-bfc-006b.xht
new file mode 100644
index 0000000..78ec3dc4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-tables-3/floats/floats-wrap-bfc-006b.xht
@@ -0,0 +1,64 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="en-US"><head>
+    <title>CSS Test: Test for flow around floats</title>
+    <link rel="author" title="L. David Baron" href="https://dbaron.org/" />
+    <link rel="author" title="Mozilla Corporation" href="http://mozilla.com/" />
+    <link rel="help" href="http://www.w3.org/TR/CSS21/visuren.html#floats" />
+    <link rel="match" href="floats-wrap-bfc-006b-ref.xht"/>
+    <meta name="assert" content="The border box of a table, a block-level replaced element, or an element in the normal flow that establishes a new block formatting context (such as an element with 'overflow' other than 'visible') must not overlap any floats in the same block formatting context as the element itself." />
+    <meta name="flags" content="" />
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+    <meta http-equiv="Content-Style-Type" content="text/css" />
+    <style type="text/css">
+
+    body { font-size: 16px; }
+
+    table { margin: 0; border-spacing: 0; }
+    caption, td, th { padding: 0; vertical-align: top; text-align: left; }
+
+    table table caption { background: yellow; }
+    table table { background: purple; }
+
+    </style>
+</head>
+<body>
+
+<table width="300" style="background: aqua"><tbody><tr><td>
+    <div style="float:left; clear:left; background:blue; width:150px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:145px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:140px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:135px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:130px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:125px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:120px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:115px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:110px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:105px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:100px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:95px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:90px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:85px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:80px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:75px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:70px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:65px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:60px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:55px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:50px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:45px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:40px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:35px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:30px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:25px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:20px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:15px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:10px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:5px; height:1px"></div>
+    <table>
+        <caption style="caption-side: left; height:30px; width: 90px;">Caption</caption>
+        <tbody><tr><td><div style="height: 30px; width: 102px">Cell</div></td></tr>
+    </tbody></table>
+</td></tr></tbody></table>
+
+
+
+</body></html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-tables-3/floats/floats-wrap-bfc-006c-ref.xht b/third_party/WebKit/LayoutTests/external/wpt/css/css-tables-3/floats/floats-wrap-bfc-006c-ref.xht
new file mode 100644
index 0000000..74822038
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-tables-3/floats/floats-wrap-bfc-006c-ref.xht
@@ -0,0 +1,59 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="en-US"><head>
+    <title>CSS Test: Test for flow around floats (reference)</title>
+    <link rel="author" title="L. David Baron" href="https://dbaron.org/" />
+    <link rel="author" title="Mozilla Corporation" href="http://mozilla.com/" />
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+    <meta http-equiv="Content-Style-Type" content="text/css" />
+    <style type="text/css">
+
+    body { font-size: 16px; }
+
+    table { margin: 0; border-spacing: 0; }
+    caption, td, th { padding: 0; vertical-align: top; text-align: left; }
+
+    .capref { background: yellow; }
+    .tabref { background: purple; }
+
+    </style>
+</head>
+<body>
+
+<table width="300" style="background: aqua"><tbody><tr><td>
+    <div style="float:left; clear:left; background:blue; width:150px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:145px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:140px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:135px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:130px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:125px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:120px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:115px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:110px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:105px; height:1px"></div>
+
+    <div style="float: right; width: 192px; height: 30px; margin-right: 3px;"><div style="display: inline-block; vertical-align: top; height: 30px; width: 102px;" class="tabref">Cell</div><div style="display: inline-block; vertical-align: top; height: 30px; width: 90px;" class="capref">Caption</div></div>
+
+    <div style="float:left; clear:left; background:blue; width:100px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:95px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:90px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:85px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:80px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:75px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:70px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:65px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:60px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:55px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:50px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:45px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:40px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:35px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:30px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:25px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:20px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:15px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:10px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:5px; height:1px"></div>
+</td></tr></tbody></table>
+
+
+
+</body></html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-tables-3/floats/floats-wrap-bfc-006c.xht b/third_party/WebKit/LayoutTests/external/wpt/css/css-tables-3/floats/floats-wrap-bfc-006c.xht
new file mode 100644
index 0000000..618931c0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-tables-3/floats/floats-wrap-bfc-006c.xht
@@ -0,0 +1,64 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="en-US"><head>
+    <title>CSS Test: Test for flow around floats</title>
+    <link rel="author" title="L. David Baron" href="https://dbaron.org/" />
+    <link rel="author" title="Mozilla Corporation" href="http://mozilla.com/" />
+    <link rel="help" href="http://www.w3.org/TR/CSS21/visuren.html#floats" />
+    <link rel="match" href="floats-wrap-bfc-006c-ref.xht"/>
+    <meta name="assert" content="The border box of a table, a block-level replaced element, or an element in the normal flow that establishes a new block formatting context (such as an element with 'overflow' other than 'visible') must not overlap any floats in the same block formatting context as the element itself." />
+    <meta name="flags" content="" />
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+    <meta http-equiv="Content-Style-Type" content="text/css" />
+    <style type="text/css">
+
+    body { font-size: 16px; }
+
+    table { margin: 0; border-spacing: 0; }
+    caption, td, th { padding: 0; vertical-align: top; text-align: left; }
+
+    table table caption { background: yellow; }
+    table table { background: purple; }
+
+    </style>
+</head>
+<body>
+
+<table width="300" style="background: aqua"><tbody><tr><td>
+    <div style="float:left; clear:left; background:blue; width:150px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:145px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:140px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:135px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:130px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:125px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:120px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:115px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:110px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:105px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:100px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:95px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:90px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:85px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:80px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:75px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:70px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:65px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:60px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:55px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:50px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:45px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:40px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:35px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:30px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:25px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:20px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:15px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:10px; height:1px"></div>
+    <div style="float:left; clear:left; background:blue; width:5px; height:1px"></div>
+    <table>
+        <caption style="caption-side: right; height:30px; width: 90px;">Caption</caption>
+        <tbody><tr><td><div style="height: 30px; width: 102px">Cell</div></td></tr>
+    </tbody></table>
+</td></tr></tbody></table>
+
+
+
+</body></html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-ui-3/box-sizing-026.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-ui-3/box-sizing-026.html
index a3ee653..424b764a 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-ui-3/box-sizing-026.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-ui-3/box-sizing-026.html
@@ -4,7 +4,6 @@
 <link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/">
 <link rel="help" href="https://drafts.csswg.org/css-ui-3/#box-sizing">
 <meta name="flags" content="">
-<link rel="match" href="reference/box-sizing-001-ref.html">
 <link rel="match" href="../reference/ref-filled-green-100px-square.xht">
 <meta name="assert" content="Floor width and height computation to 0 as they cannot be negative.">
 <style>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/wm-propagation-body-computed-root.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/wm-propagation-body-computed-root.html
deleted file mode 100644
index 7741ac705..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/wm-propagation-body-computed-root.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<meta charset="UTF-8">
-<title>CSS Writing Modes Test: Computed writing-mode for html element when writing mode for body propagated to viewport</title>
-<link rel="author" title="Rune Lillesveen" href="mailto:rune@opera.com">
-<link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#principal-flow">
-<meta name="assert" content="Test that propagating writing-mode from body to viewport does not affect the computed writing-mode of the html element">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<style>
-  .vertical-lr { writing-mode: vertical-lr }
-</style>
-<body class="vertical-lr">
-<script>
-  test(function() {
-    assert_equals(getComputedStyle(document.body).writingMode, "vertical-lr");
-  }, "Check computed writing-mode for body element.");
-
-  test(function() {
-    assert_not_equals(getComputedStyle(document.documentElement).writingMode, "vertical-lr");
-  }, "Check computed writing-mode for html root element.");
-
-  test(function() {
-    document.body.className = "";
-    assert_not_equals(getComputedStyle(document.body).writingMode, "vertical-lr");
-  }, "Check computed writing-mode for body element when style no longer applies.");
-</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/cssom/getComputedStyle-pseudo.html b/third_party/WebKit/LayoutTests/external/wpt/cssom/getComputedStyle-pseudo.html
index 8efd484..e2ec088 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/cssom/getComputedStyle-pseudo.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/cssom/getComputedStyle-pseudo.html
@@ -40,4 +40,13 @@
     assert_equals(getComputedStyle(contents, pseudo).width, "50px");
   });
 }, "Resolution of width is correct for ::before and ::after pseudo-elements of display: contents elements");
+test(function() {
+  var has_no_pseudos = document.body;
+  has_no_pseudos.style.position = "relative";
+  [":before", ":after"].forEach(function(pseudo) {
+    assert_equals(getComputedStyle(has_no_pseudos, pseudo).position, "static",
+                  "Nonexistent " + pseudo + " pseudo-element shouldn't claim to have " +
+                  "the same style as the originating element");
+  });
+}, "Resolution of nonexistent pseudo-element styles");
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/custom-elements/reactions/ChildNode.html b/third_party/WebKit/LayoutTests/external/wpt/custom-elements/reactions/ChildNode.html
index 756f172..256e42ef 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/custom-elements/reactions/ChildNode.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/custom-elements/reactions/ChildNode.html
@@ -28,7 +28,7 @@
 
 testNodeDisconnector(function (customElement) {
     customElement.remove();
-}, 'replaceWith on ChildNode');
+}, 'remove on ChildNode');
 
 </script>
 </body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/domparsing/xml-serialization.xhtml b/third_party/WebKit/LayoutTests/external/wpt/domparsing/xml-serialization.xhtml
index 678523d1e..852bbcc 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/domparsing/xml-serialization.xhtml
+++ b/third_party/WebKit/LayoutTests/external/wpt/domparsing/xml-serialization.xhtml
@@ -68,6 +68,18 @@
 }, "DocumentType: 'APOSTROPHE' (U+0027) and 'QUOTATION MARK' (U+0022)");
 
 test(function() {
+  var el = document.createElement("a");
+  el.setAttribute("href", "\u3042\u3044\u3046 !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~");
+  assert_equals(serialize(el), "<a xmlns=\"http://www.w3.org/1999/xhtml\" href=\"\u3042\u3044\u3046 !&quot;#$%&amp;'()*+,-./0123456789:;&lt;=&gt;?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\"></a>");
+}, "Element: href attributes are not percent-encoded");
+
+test(function() {
+  var el = document.createElement("a");
+  el.setAttribute("href", "?\u3042\u3044\u3046 !\"$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~");
+  assert_equals(serialize(el), "<a xmlns=\"http://www.w3.org/1999/xhtml\" href=\"?\u3042\u3044\u3046 !&quot;$%&amp;'()*+,-./0123456789:;&lt;=&gt;?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\"></a>");
+}, "Element: query parts in href attributes are not percent-encoded");
+
+test(function() {
   var pi = document.createProcessingInstruction("a", "");
   assert_equals(serialize(pi), "<?a ?>");
 }, "ProcessingInstruction: empty data");
diff --git a/third_party/WebKit/LayoutTests/external/wpt/encoding/iso-2022-jp-decoder-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/encoding/iso-2022-jp-decoder-expected.txt
index c398f50c..95d24ae0 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/encoding/iso-2022-jp-decoder-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/encoding/iso-2022-jp-decoder-expected.txt
@@ -1,8 +1,8 @@
 This is a testharness.js-based test.
 FAIL iso-2022-jp decoder: Error ESC assert_equals: expected "\ufffd$" but got "\ufffd"
 PASS iso-2022-jp decoder: Error ESC, character 
-FAIL iso-2022-jp decoder: ASCII ESC, character assert_equals: expected "\ufffdP" but got "P"
-FAIL iso-2022-jp decoder: Double ASCII ESC, character assert_equals: expected "\ufffd\ufffdP" but got "\ufffdP"
+PASS iso-2022-jp decoder: ASCII ESC, character 
+PASS iso-2022-jp decoder: Double ASCII ESC, character 
 PASS iso-2022-jp decoder: character, ASCII ESC, character 
 PASS iso-2022-jp decoder: characters 
 PASS iso-2022-jp decoder: SO / SI 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/encoding/iso-2022-jp-decoder.html b/third_party/WebKit/LayoutTests/external/wpt/encoding/iso-2022-jp-decoder.html
index c86ffc1..c0b858c 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/encoding/iso-2022-jp-decoder.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/encoding/iso-2022-jp-decoder.html
@@ -17,8 +17,8 @@
  }
  decode([0x1b, 0x24], "�$", "Error ESC")
  decode([0x1b, 0x24, 0x50], "�$P", "Error ESC, character")
- decode([0x1b, 0x28, 0x42, 0x50], "�P", "ASCII ESC, character")
- decode([0x1b, 0x28, 0x42, 0x1b, 0x28, 0x42, 0x50], "��P", "Double ASCII ESC, character")
+ decode([0x1b, 0x28, 0x42, 0x50], "P", "ASCII ESC, character")
+ decode([0x1b, 0x28, 0x42, 0x1b, 0x28, 0x42, 0x50], "�P", "Double ASCII ESC, character")
  decode([0x50, 0x1b, 0x28, 0x42, 0x50], "PP", "character, ASCII ESC, character")
  decode([0x5C, 0x5D, 0x7E], "\\]~", "characters")
  decode([0x0D, 0x0E, 0x0F, 0x10], "\x0D��\x10", "SO / SI")
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/basic/block-mime-as-script.html b/third_party/WebKit/LayoutTests/external/wpt/fetch/api/basic/block-mime-as-script.html
index 37c3883..afc2bbb 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/basic/block-mime-as-script.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/fetch/api/basic/block-mime-as-script.html
@@ -7,23 +7,27 @@
 <script>
   var noop = function() {};
 
-  ["text/csv",
-   "audio/aiff",
-   "audio/midi",
-   "audio/whatever",
-   "video/avi",
-   "video/fli",
-   "video/whatever",
-   "image/jpeg",
-   "image/gif",
-   "image/whatever"].forEach(function(test_case) {
-    async_test(function(t) {
-      var script = document.createElement("script");
-      script.onerror = t.step_func_done(noop);
-      script.onload = t.unreached_func("Unexpected load event");
-      script.src = "../resources/script-with-header.py?mime=" + test_case;
-      document.body.appendChild(script);
-    }, "Should fail loading script with " + test_case + " MIME type");
+  ["non-empty", "empty"].forEach(function(content) {
+    ["text/csv",
+     "audio/aiff",
+     "audio/midi",
+     "audio/whatever",
+     "video/avi",
+     "video/fli",
+     "video/whatever",
+     "image/jpeg",
+     "image/gif",
+     "image/whatever"].forEach(function(test_case) {
+      async_test(function(t) {
+        var script = document.createElement("script");
+        script.onerror = t.step_func_done(noop);
+        script.onload = t.unreached_func("Unexpected load event");
+        script.src = "../resources/script-with-header.py?content=" + content +
+                     "&mime=" + test_case;
+        document.body.appendChild(script);
+      }, "Should fail loading " + content + " script with " + test_case +
+         " MIME type");
+    });
   });
 
   ["html", "plain"].forEach(function(test_case) {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/headers/headers-record.html b/third_party/WebKit/LayoutTests/external/wpt/fetch/api/headers/headers-record.html
index 173daf0a..a91b9b5 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/headers/headers-record.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/fetch/api/headers/headers-record.html
@@ -395,5 +395,4 @@
   assert_true(h.has("c"));
   assert_equals(h.get("c"), "d");
 }, "Operation with non-enumerable Symbol keys");
-
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/resources/script-with-header.py b/third_party/WebKit/LayoutTests/external/wpt/fetch/api/resources/script-with-header.py
index 778871b4..5337cc9 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/resources/script-with-header.py
+++ b/third_party/WebKit/LayoutTests/external/wpt/fetch/api/resources/script-with-header.py
@@ -1,4 +1,7 @@
 def main(request, response):
     headers = [("Content-type", request.GET.first("mime"))]
-    content = "console.log('Script loaded')"
+    if "content" in request.GET and request.GET.first("content") == "empty":
+        content = ''
+    else:
+        content = "console.log('Script loaded')"
     return 200, headers, content
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fonts/Ahem.ttf b/third_party/WebKit/LayoutTests/external/wpt/fonts/Ahem.ttf
new file mode 100644
index 0000000..ac81cb0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/fonts/Ahem.ttf
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/dom/elements-metadata.js b/third_party/WebKit/LayoutTests/external/wpt/html/dom/elements-metadata.js
index 1b23a27..482b139 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/dom/elements-metadata.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/dom/elements-metadata.js
@@ -25,6 +25,12 @@
     type: "string",
     sizes: "settable tokenlist",
     referrerPolicy: {type: "enum", keywords: ["", "no-referrer", "no-referrer-when-downgrade", "same-origin", "origin", "strict-origin", "origin-when-cross-origin", "strict-origin-when-cross-origin", "unsafe-url"]},
+    workerType: {
+      type: "enum",
+      keywords: ["classic", "module"],
+      defaultVal: "classic",
+      invalidVal: "",
+    },
 
     // Obsolete
     charset: "string",
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 33d334581..251e93f 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
@@ -142,6 +142,58 @@
 PASS link.referrerPolicy: 3 tests
 FAIL link.referrerPolicy: IDL set to "STRICT-ORIGIN-WHEN-CROSS-ORIGIN" assert_equals: IDL get expected "strict-origin-when-cross-origin" but got ""
 PASS link.referrerPolicy: 5 tests
+FAIL link.workerType: typeof IDL attribute assert_equals: expected "string" but got "undefined"
+FAIL link.workerType: IDL get with DOM attribute unset assert_equals: expected (string) "classic" but got (undefined) undefined
+FAIL link.workerType: setAttribute() to "" assert_equals: IDL get expected (string) "" but got (undefined) undefined
+FAIL link.workerType: setAttribute() to " \0\x01\x02\x03\x04\x05\x06\x07 \b\t\n\v\f\r\x0e\x0f \x10\x11\x12\x13\x14\x15\x16\x17 \x18\x19\x1a\x1b\x1c\x1d\x1e\x1f  foo " assert_equals: IDL get expected (string) "" but got (undefined) undefined
+FAIL link.workerType: setAttribute() to undefined assert_equals: IDL get expected (string) "" but got (undefined) undefined
+FAIL link.workerType: setAttribute() to 7 assert_equals: IDL get expected (string) "" but got (undefined) undefined
+FAIL link.workerType: setAttribute() to 1.5 assert_equals: IDL get expected (string) "" but got (undefined) undefined
+FAIL link.workerType: setAttribute() to true assert_equals: IDL get expected (string) "" but got (undefined) undefined
+FAIL link.workerType: setAttribute() to false assert_equals: IDL get expected (string) "" but got (undefined) undefined
+FAIL link.workerType: setAttribute() to object "[object Object]" assert_equals: IDL get expected (string) "" but got (undefined) undefined
+FAIL link.workerType: setAttribute() to NaN assert_equals: IDL get expected (string) "" but got (undefined) undefined
+FAIL link.workerType: setAttribute() to Infinity assert_equals: IDL get expected (string) "" but got (undefined) undefined
+FAIL link.workerType: setAttribute() to -Infinity assert_equals: IDL get expected (string) "" but got (undefined) undefined
+FAIL link.workerType: setAttribute() to "\0" assert_equals: IDL get expected (string) "" but got (undefined) undefined
+FAIL link.workerType: setAttribute() to null assert_equals: IDL get expected (string) "" but got (undefined) undefined
+FAIL link.workerType: setAttribute() to object "test-toString" assert_equals: IDL get expected (string) "" but got (undefined) undefined
+FAIL link.workerType: setAttribute() to object "test-valueOf" assert_equals: IDL get expected (string) "" but got (undefined) undefined
+FAIL link.workerType: setAttribute() to "classic" assert_equals: IDL get expected (string) "classic" but got (undefined) undefined
+FAIL link.workerType: setAttribute() to "xclassic" assert_equals: IDL get expected (string) "" but got (undefined) undefined
+FAIL link.workerType: setAttribute() to "classic\0" assert_equals: IDL get expected (string) "" but got (undefined) undefined
+FAIL link.workerType: setAttribute() to "lassic" assert_equals: IDL get expected (string) "" but got (undefined) undefined
+FAIL link.workerType: setAttribute() to "CLASSIC" assert_equals: IDL get expected (string) "classic" but got (undefined) undefined
+FAIL link.workerType: setAttribute() to "module" assert_equals: IDL get expected (string) "module" but got (undefined) undefined
+FAIL link.workerType: setAttribute() to "xmodule" assert_equals: IDL get expected (string) "" but got (undefined) undefined
+FAIL link.workerType: setAttribute() to "module\0" assert_equals: IDL get expected (string) "" but got (undefined) undefined
+FAIL link.workerType: setAttribute() to "odule" assert_equals: IDL get expected (string) "" but got (undefined) undefined
+FAIL link.workerType: setAttribute() to "MODULE" assert_equals: IDL get expected (string) "module" but got (undefined) undefined
+FAIL link.workerType: IDL set to "" assert_equals: getAttribute() expected "" but got "MODULE"
+FAIL link.workerType: IDL set to " \0\x01\x02\x03\x04\x05\x06\x07 \b\t\n\v\f\r\x0e\x0f \x10\x11\x12\x13\x14\x15\x16\x17 \x18\x19\x1a\x1b\x1c\x1d\x1e\x1f  foo " assert_equals: getAttribute() expected " \0\x01\x02\x03\x04\x05\x06\x07 \b\t\n\v\f\r\x0e\x0f \x10\x11\x12\x13\x14\x15\x16\x17 \x18\x19\x1a\x1b\x1c\x1d\x1e\x1f  foo " but got "MODULE"
+FAIL link.workerType: IDL set to undefined assert_equals: getAttribute() expected "undefined" but got "MODULE"
+FAIL link.workerType: IDL set to 7 assert_equals: getAttribute() expected "7" but got "MODULE"
+FAIL link.workerType: IDL set to 1.5 assert_equals: getAttribute() expected "1.5" but got "MODULE"
+FAIL link.workerType: IDL set to true assert_equals: getAttribute() expected "true" but got "MODULE"
+FAIL link.workerType: IDL set to false assert_equals: getAttribute() expected "false" but got "MODULE"
+FAIL link.workerType: IDL set to object "[object Object]" assert_equals: getAttribute() expected "[object Object]" but got "MODULE"
+FAIL link.workerType: IDL set to NaN assert_equals: getAttribute() expected "NaN" but got "MODULE"
+FAIL link.workerType: IDL set to Infinity assert_equals: getAttribute() expected "Infinity" but got "MODULE"
+FAIL link.workerType: IDL set to -Infinity assert_equals: getAttribute() expected "-Infinity" but got "MODULE"
+FAIL link.workerType: IDL set to "\0" assert_equals: getAttribute() expected "\0" but got "MODULE"
+FAIL link.workerType: IDL set to null assert_equals: IDL get expected (string) "" but got (object) null
+FAIL link.workerType: IDL set to object "test-toString" assert_equals: getAttribute() expected "test-toString" but got "MODULE"
+FAIL link.workerType: IDL set to object "test-valueOf" assert_equals: getAttribute() expected "test-valueOf" but got "MODULE"
+FAIL link.workerType: IDL set to "classic" assert_equals: getAttribute() expected "classic" but got "MODULE"
+FAIL link.workerType: IDL set to "xclassic" assert_equals: getAttribute() expected "xclassic" but got "MODULE"
+FAIL link.workerType: IDL set to "classic\0" assert_equals: getAttribute() expected "classic\0" but got "MODULE"
+FAIL link.workerType: IDL set to "lassic" assert_equals: getAttribute() expected "lassic" but got "MODULE"
+FAIL link.workerType: IDL set to "CLASSIC" assert_equals: getAttribute() expected "CLASSIC" but got "MODULE"
+FAIL link.workerType: IDL set to "module" assert_equals: getAttribute() expected "module" but got "MODULE"
+FAIL link.workerType: IDL set to "xmodule" assert_equals: getAttribute() expected "xmodule" but got "MODULE"
+FAIL link.workerType: IDL set to "module\0" assert_equals: getAttribute() expected "module\0" but got "MODULE"
+FAIL link.workerType: IDL set to "odule" assert_equals: getAttribute() expected "odule" but got "MODULE"
+FAIL link.workerType: IDL set to "MODULE" assert_equals: IDL get expected "module" but got "MODULE"
 PASS link.charset: 32 tests
 PASS link.rev: 32 tests
 PASS link.target: 32 tests
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-img-element/adoption.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-img-element/adoption.html
new file mode 100644
index 0000000..15e02bcf
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-img-element/adoption.html
@@ -0,0 +1,91 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>Adopting an image updates the image data</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<div id=log></div>
+
+<!-- tests -->
+
+<div id="adoptTest1"></div>
+<picture id="adoptTest2">
+<source srcset="/images/green-2x2.png">
+</picture>
+
+<script>
+function resolve(url) {
+  if (url === "") {
+    return url;
+  }
+  var a = document.createElement('a');
+  a.href = url;
+  return a.href;
+}
+
+function t(desc, data, expect) {
+  async_test(function(t) {
+    var d = (new DOMParser()).parseFromString(data, 'text/html');
+    var i = d.querySelector('img');
+    i.onerror = this.unreached_func('got unexpected error event');
+    i.onload = this.step_func_done(function() {
+      assert_equals(i.currentSrc, resolve(expect));
+    });
+    var n = d.querySelector('[adopt-node]');
+    document.adoptNode(n);
+  }, desc);
+}
+
+onload = function() {
+
+  t('img (src only)',
+    '<img src="/images/green-1x1.png" adopt-node>',
+    '/images/green-1x1.png');
+
+  t('img (src only), parent is picture',
+    '<picture adopt-node><img src="/images/green-1x1.png"></picture>',
+    '/images/green-1x1.png');
+
+  t('img (src only), previous sibling is source',
+    '<picture adopt-node><source srcset="/images/green-1x1.png"><img src="/images/green-2x2.png"></picture>',
+    '/images/green-1x1.png');
+
+  t('img (srcset 1 cand)',
+    '<img srcset="/images/green-1x1.png" adopt-node>',
+    '/images/green-1x1.png');
+
+  t('img (srcset 1 cand), parent is picture',
+    '<picture adopt-node><img srcset="/images/green-1x1.png"></picture>',
+    '/images/green-1x1.png');
+
+  t('img (srcset 1 cand), previous sibling is source',
+    '<picture adopt-node><source srcset="/images/green-1x1.png"><img srcset="/images/green-2x2.png"></picture>',
+    '/images/green-1x1.png');
+
+  async_test(function(t) {
+    var d = (new DOMParser()).parseFromString('<template><img src="/images/green-1x1.png"></template>', 'text/html');
+    var i = d.querySelector('template').content.querySelector('img').cloneNode(1);
+    i.onerror = this.unreached_func('got unexpected error event');
+    i.onload = this.step_func_done(function() {
+      assert_equals(i.currentSrc, resolve('/images/green-1x1.png'));
+    });
+
+    document.getElementById('adoptTest1').appendChild(i);
+  }, 'adopt a cloned img in template');
+
+  async_test(function(t) {
+    var preload = new Image();
+    preload.src = '/images/green-1x1.png?' + Math.random();
+    preload.onload = t.step_func(function() {
+      var d = (new DOMParser()).parseFromString('<img src="' + preload.src + '">', 'text/html');
+      var i = d.querySelector('img');
+      i.onerror = this.unreached_func('got unexpected error event');
+      i.onload = this.step_func_done(function() {
+        assert_equals(i.currentSrc, resolve("/images/green-2x2.png"));
+      });
+
+      var p = document.getElementById('adoptTest2');
+      p.appendChild(i);
+    });
+  }, 'adoption is from appendChild');
+};
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-img-element/non-active-document.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-img-element/non-active-document.html
new file mode 100644
index 0000000..6072138c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-img-element/non-active-document.html
@@ -0,0 +1,52 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>img in non-active document should not perform loads</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<div id=log></div>
+
+<!-- Per load the image so that any loads in this test would be cached. -->
+<img src=/images/green-1x1.png>
+
+<!-- tests -->
+<template>
+<img>
+</template>
+
+<script>
+
+onload = function() {
+  async_test(function(t) {
+    var p = new DOMParser();
+    var d = p.parseFromString('<img>', 'text/html');
+    var i = d.querySelector('img');
+    i.onerror = t.unreached_func('got unexpected error event');
+    i.onload = t.unreached_func('got unexpected load event');
+    i.src = '/images/green-1x1.png';
+    // delay to ensure there is no load/error event fired.
+    t.step_timeout(t.step_func_done(), 0);
+  }, "DOMParser");
+
+  async_test(function(t) {
+    var d = document.implementation.createHTMLDocument('');
+    d.body.innerHTML = '<img>';
+    var i = d.querySelector('img');
+    i.onerror = this.unreached_func('got unexpected error event');
+    i.onload = this.unreached_func('got unexpected load event');
+    i.src = '/images/green-1x1.png';
+    // delay to ensure there is no load/error event fired.
+    t.step_timeout(t.step_func_done(), 0);
+  }, "createHTMLDocument");
+
+  async_test(function(t) {
+    var template = document.querySelector('template');
+    var i = template.content.querySelector('img');
+    i.onerror = this.unreached_func('got unexpected error event');
+    i.onload = this.unreached_func('got unexpected load event');
+    i.src = '/images/green-1x1.png';
+    // delay to ensure there is no load/error event fired.
+    t.step_timeout(t.step_func_done(), 0);
+  }, "<template>");
+};
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-label-element/iframe-label-attributes.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-label-element/iframe-label-attributes.html
new file mode 100644
index 0000000..3f08a29
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-label-element/iframe-label-attributes.html
@@ -0,0 +1,8 @@
+<html>
+  <body>
+    <label>
+      <div id="div1"></div>
+    </label>
+    <label for="test13"></label>
+  </body>
+</html>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-label-element/label-attributes-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-label-element/label-attributes-expected.txt
new file mode 100644
index 0000000..a32899b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-label-element/label-attributes-expected.txt
@@ -0,0 +1,23 @@
+This is a testharness.js-based test.
+PASS A label element with a 'for' attribute should only be associated with a labelable element. 
+PASS A label element not in a document can not label any element in the document. 
+PASS The labeled control for a label element that has no 'for' attribute is the first labelable element which is a descendant of that label element. 
+PASS The 'for' attribute points to an inexistent id. 
+PASS A non-control follows by a control with same ID. 
+PASS The 'for' attribute is an empty string. 
+PASS A form control has multiple labels. 
+PASS A labelable element is moved to outside of nested associated labels. 
+PASS A labelable element is moved to inside of nested associated labels. 
+PASS A labelable element which is a descendant of non-labelable element is moved to outside of associated label. 
+FAIL A labelable element is moved to iframe. Blocked a frame with origin "http://web-platform.test:8001" from accessing a cross-origin frame.
+PASS A div element which contains labelable element is removed. 
+FAIL A labelable element not in a document can label element in the same tree. assert_equals: The number of labels associated with a form control should be the number of label elements for which it is a labeled control. expected 2 but got 0
+PASS A labelable element inside the shadow DOM. 
+PASS A form control has an implicit label. 
+PASS A form control has no label 1. 
+PASS A form control has no label 2. 
+PASS A label in a form without a control 
+PASS A label outside a form with a control inside the form 
+PASS A label's htmlFor attribute must reflect the for content attribute 
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-label-element/label-attributes.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-label-element/label-attributes.html
index 826533e..2910f2c 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-label-element/label-attributes.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-label-element/label-attributes.html
@@ -32,10 +32,53 @@
 
   <label id="lbl5" for="test7"></label>
   <input id="test7">
+
+  <label id="lbl7">
+    <label id="lbl8">
+      <div id="div1">
+        <input id="test8">
+      </div>
+    </label>
+  </label>
+  <div id="div2"></div>
+
+ <label id="lbl9">
+   <label id="lbl10" for="test10">
+    <div id="div3">
+      <input id="test9">
+    </div>
+  </label>
+ </label>
+ <div id="div4"><input id="test10"></div>
+
+  <label id="lbl11">
+    <object id="obj">
+      <input id="test11">
+      <input id="test12">
+    </object>
+  </label>
+  <label id="lbl12" for="test12"><div id="div5"></div></label>
+
+  <label id="lbl13">
+    <p id="p1">
+      <input id="test13">
+    </p>
+  </label>
+
+  <div id="div6">
+    <div id="div7">
+      <label id="lbl14">
+        <label id="lbl15" for="test15">
+          <input id="test14">
+        </label>
+      </label>
+    </div>
+  </div>
+  <input id="test15">
 </form>
 
 <label id="lbl6" for="test7"></label>
-
+<div id="content" style="display: none">
 <script>
 
   //control attribute
@@ -57,6 +100,7 @@
   }, "A label element not in a document can not label any element in the document.");
 
   test(function () {
+    var labels = document.getElementById("test3").labels;
     assert_equals(document.getElementById("lbl1").control, document.getElementById("test3"),
                   "The first labelable descendant of a label element should be its labeled control.");
 
@@ -64,6 +108,10 @@
     document.getElementById("lbl1").insertBefore(input, document.getElementById("test2"));
     assert_equals(document.getElementById("lbl1").control, input,
                   "The first labelable descendant of a label element in tree order should be its labeled control.");
+    assert_equals(input.labels.length, 1,
+                  "The form control has an ancestor with no explicit associated label, and is the first labelable descendant.");
+    assert_equals(labels.length, 0,
+                  "The number of labels should be 0 if it's not the first labelable descendant of a label element.");
     input.remove();
   }, "The labeled control for a label element that has no 'for' attribute is the first labelable element which is a descendant of that label element.");
 
@@ -101,6 +149,168 @@
   }, "A form control has multiple labels.");
 
   test(function () {
+    var labels = document.getElementById("test8").labels;
+    assert_true(labels instanceof NodeList,
+                "A form control's 'labels' property should be an instance of a NodeList.");
+    assert_equals(labels.length, 2,
+                  "The form control has two ancestors with no explicit associated label, and is the first labelable descendant.");
+    assert_array_equals(labels, [document.getElementById("lbl7"), document.getElementById("lbl8")],
+                        "The labels for a form control should be returned in tree order.");
+
+    document.getElementById('div2').insertBefore(document.getElementById('div1'), document.getElementById('div2').firstChild);
+    assert_equals(labels.length, 0,
+                  "The number of labels should be 0 after the labelable element is moved to outside of nested associated labels.");
+  }, "A labelable element is moved to outside of nested associated labels.");
+
+  test(function () {
+    var labels1 = document.getElementById("test9").labels;
+    var labels2 = document.getElementById("test10").labels;
+    assert_true(labels1 instanceof NodeList,
+                "A form control's 'labels' property should be an instance of a NodeList.");
+    assert_true(labels2 instanceof NodeList,
+                "A form control's 'labels' property should be an instance of a NodeList.");
+    assert_equals(labels1.length, 1,
+                  "The form control has an ancestor with no explicit associated label, and is the first labelable descendant.");
+    assert_equals(labels2.length, 1,
+                  "The number of labels associated with a form control should be the number of label elements for which it is a labeled control.");
+    assert_array_equals(labels1, [document.getElementById("lbl9")],
+                        "The labels for a form control should be returned in tree order.");
+    assert_array_equals(labels2, [document.getElementById("lbl10")],
+                        "The labels for a form control should be returned in tree order.");
+    document.getElementById('div3').insertBefore(document.getElementById('div4'), document.getElementById('div3').firstChild);
+    assert_equals(labels1.length, 0,
+                  "The number of labels should be 0 if it's not the first labelable descendant of a label element.");
+    assert_equals(labels2.length, 2,
+                  "The form control has an ancestor with an explicit associated label, and is the first labelable descendant.");
+  }, "A labelable element is moved to inside of nested associated labels.");
+
+  test(function () {
+    var labels1 = document.getElementById("test11").labels;
+    var labels2 = document.getElementById("test12").labels;
+    assert_true(labels1 instanceof NodeList,
+                "A form control's 'labels' property should be an instance of a NodeList.");
+    assert_true(labels2 instanceof NodeList,
+                "A form control's 'labels' property should be an instance of a NodeList.");
+    assert_equals(labels1.length, 1,
+                  "The form control has an ancestor with no explicit associated label, and it is the first labelable descendant.");
+    assert_equals(labels2.length, 1,
+                  "The number of labels should be 1 since there is a label with a 'for' attribute associated with this labelable element.");
+    assert_array_equals(labels1, [document.getElementById("lbl11")],
+                        "The labels for a form control should be returned in tree order.");
+    assert_array_equals(labels2, [document.getElementById("lbl12")],
+                        "The labels for a form control should be returned in tree order.");
+    document.getElementById('div5').appendChild(document.getElementById('obj'));
+    assert_equals(labels1.length, 0,
+                  "The number of labels should be 0 after the labelable element is moved to outside of associated label.");
+    assert_equals(labels2.length, 1,
+                  "The number of labels should be 1 after the labelable element is moved to outside of associated label.");
+  }, "A labelable element which is a descendant of non-labelable element is moved to outside of associated label.");
+
+  async_test(function () {
+    var labels = document.getElementById("test13").labels;
+    assert_true(labels instanceof NodeList,
+                "A form control's 'labels' property should be an instance of a NodeList.");
+    assert_equals(labels.length, 1,
+                  "The form control has an ancestor with no explicit associated label, and is the first labelable descendant.");
+    assert_array_equals(labels, [document.getElementById("lbl13")],
+                        "The labels for a form control should be returned in tree order.");
+    let iframe = document.createElement('iframe');
+
+    iframe.onload = this.step_func_done(() => {
+      iframe.contentWindow.document.getElementById("div1").appendChild(document.getElementById("p1"));
+      assert_equals(labels.length, 2,
+                    "The number of labels should be 2 after the labelable element is moved to iframe.");
+    });
+
+    iframe.setAttribute('src', 'http://web-platform.test:8000/html/semantics/forms/the-label-element/iframe-label-attributes.html');
+    document.body.appendChild(iframe);
+  }, "A labelable element is moved to iframe.");
+
+  test(function () {
+    var labels1 = document.getElementById("test14").labels;
+    var labels2 = document.getElementById("test15").labels;
+    assert_true(labels1 instanceof NodeList,
+                "A form control's 'labels' property should be an instance of a NodeList.");
+    assert_equals(labels1.length, 1,
+                  "The form control has an ancestor with no explicit associated label, and is the first labelable descendant.");
+    assert_equals(labels2.length, 1,
+                  "The number of labels associated with a form control should be the number of label elements for which it is a labeled control.");
+    assert_array_equals(labels1, [document.getElementById("lbl14")],
+                        "The labels for a form control should be returned in tree order.");
+
+    document.getElementById('div6').removeChild(document.getElementById('div7'));
+    assert_equals(labels1.length, 0,
+                  "The number of labels should be 0 after the labelable element is removed.");
+    assert_equals(labels2.length, 0,
+                  "The number of labels should be 0 since there is no label with a 'for' attribute associated with this labelable element.");
+  }, "A div element which contains labelable element is removed.");
+
+  test(function () {
+    // <label><input id="test16"><label for="test16"></label></label>
+    var label1 = document.createElement('label');
+    label1.innerHTML = "<input id='test16'>";
+    var label2 = document.createElement('label');
+    label2.htmlFor = "test16";
+    label1.appendChild(label2);
+
+    var input = label1.firstChild;
+    var labels = input.labels;
+
+    assert_equals(labels.length, 2,
+                  "The number of labels associated with a form control should be the number of label elements for which it is a labeled control.");
+    assert_true(labels instanceof NodeList,
+                "A form control's 'labels' property should be an instance of a NodeList.");
+    assert_equals(label1.control, input, "The first labelable descendant of a label element should be its labeled control.");
+    assert_equals(label2.control, input, "The labeled cotrol should be associated with the control whose ID is equal to the value of the 'for' attribute.");
+  }, "A labelable element not in a document can label element in the same tree.");
+
+  test(function () {
+    var isShadowDOMV0;
+    if ("createShadowRoot" in document.getElementById('content')) {
+      isShadowDOMV0 = true;
+    }
+    var root1;
+    if (isShadowDOMV0) {
+      root1 = document.getElementById('content').createShadowRoot();
+    } else {
+      root1 = document.getElementById('content').attachShadow({mode: 'open'});
+    }
+    assert_true(root1 instanceof DocumentFragment,
+                "ShadowRoot should be an instance of DocumentFragment.");
+    // <label><input id="shadow1"/></label><div id="div1"></div>
+    var label1 = document.createElement('label');
+    var input1 = document.createElement('input');
+    input1.setAttribute("id", "shadow1");
+    label1.appendChild(input1);
+    root1.appendChild(label1);
+
+    var div1 = document.createElement('div');
+    label1.appendChild(div1);
+    // <label for="shadow2"></label><input id="shadow2"/>
+    var root2;
+    if (isShadowDOMV0) {
+      root2 = div1.createShadowRoot();
+    } else {
+      root2 = div1.attachShadow({mode: 'open'});
+    }
+
+    assert_true(root2 instanceof DocumentFragment,
+                "ShadowRoot should be an instance of DocumentFragment.");
+    var label2 = document.createElement('label');
+    label2.setAttribute("for", "shadow2");
+
+    var input2 = document.createElement('input');
+    input2.setAttribute("id", "shadow2");
+    root2.appendChild(label2);
+    root2.appendChild(input2);
+
+    assert_equals(root1.getElementById("shadow1").labels.length, 1,
+                  "The form control has an ancestor with no explicit associated label, and it is the first labelable descendant.");
+    assert_equals(root2.getElementById("shadow2").labels.length, 1,
+                  "The number of labels should be 1 since there is a label with a 'for' attribute associated with this labelable element.");
+  }, "A labelable element inside the shadow DOM.");
+
+  test(function () {
     var labels = document.getElementById("test3").labels;
     assert_true(labels instanceof NodeList, "A form control's 'labels' property should be an instance of a NodeList.");
     assert_equals(labels.length, 1, "The form control has an ancestor with no explicit associated label, and is the first labelable descendant.");
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-label-element/labelable-elements.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-label-element/labelable-elements.html
index 9dfe214..725871f 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-label-element/labelable-elements.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-label-element/labelable-elements.html
@@ -104,6 +104,7 @@
 
   hiddenInput.type = "hidden";
   assert_equals(labels.length, 0, "Retained .labels NodeList should be empty after input type changed to hidden");
+  assert_equals(hiddenInput.labels, null, ".labels NodeList should be null after input type changed to hidden");
 
   hiddenInput.type = "checkbox";
   assert_true(labels === hiddenInput.labels, ".labels property must return the [SameObject] after input type is toggled back from 'hidden'");
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-textarea-element/value-defaultValue-textContent-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-textarea-element/value-defaultValue-textContent-expected.txt
new file mode 100644
index 0000000..75040fd3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-textarea-element/value-defaultValue-textContent-expected.txt
@@ -0,0 +1,15 @@
+This is a testharness.js-based test.
+PASS defaultValue and value are the empty string by default 
+PASS defaultValue and value are affected by setting textContent 
+PASS defaultValue and value are affected by setting nodeValue on a child text node 
+PASS defaultValue and value are affected by setting data on a child text node 
+PASS defaultValue and value are affected by textContent in combination with appending a text node 
+PASS defaultValue and value are affected by textContent in combination with appending a DocumentFragment 
+PASS defaultValue and value reflect child text content, not textContent 
+FAIL Setting defaultValue wipes out any children, including elements (just like setting textContent) assert_equals: Only one child node should exist expected 1 but got 2
+PASS defaultValue and value treat CRLF differently 
+PASS value normalizes CRLF even spread over multiple text nodes 
+PASS tests for the value setter 
+PASS tests for U+0000 NULL 
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-textarea-element/value-defaultValue-textContent-xhtml.xhtml b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-textarea-element/value-defaultValue-textContent-xhtml.xhtml
new file mode 100644
index 0000000..9462e94
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-textarea-element/value-defaultValue-textContent-xhtml.xhtml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>textarea element value/defaultValue/textContent functionality</title>
+<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me"/>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-textarea-value"/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<script>
+"use strict";
+
+test(() => {
+
+  const textarea = document.createElement("textarea");
+
+  textarea.appendChild(document.createCDATASection("foo bar baz"));
+  assert_equals(textarea.defaultValue, "foo bar baz", "the defaultValue should reflect the textContent");
+  assert_equals(textarea.value, "foo bar baz",
+    "changing the child text content should change the raw value, and subsequently the api value");
+
+}, "defaultValue and value include CDATASection Text nodes");
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-textarea-element/value-defaultValue-textContent.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-textarea-element/value-defaultValue-textContent.html
index 84b17cc4..a1a405fd 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-textarea-element/value-defaultValue-textContent.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-textarea-element/value-defaultValue-textContent.html
@@ -1,5 +1,5 @@
 <!DOCTYPE HTML>
-<title>textarea element select() functionality</title>
+<title>textarea element value/defaultValue/textContent functionality</title>
 <link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me">
 <link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-textarea-value">
 <script src="/resources/testharness.js"></script>
@@ -32,6 +32,30 @@
 
   const textarea = document.createElement("textarea");
 
+  textarea.textContent = "some text";
+  textarea.firstChild.nodeValue = "foo bar";
+  assert_equals(textarea.defaultValue, "foo bar", "the defaultValue should reflect the textContent");
+  assert_equals(textarea.value, "foo bar",
+    "changing the textContent should change the raw value, and subsequently the api value");
+
+}, "defaultValue and value are affected by setting nodeValue on a child text node");
+
+test(() => {
+
+  const textarea = document.createElement("textarea");
+
+  textarea.textContent = "some text";
+  textarea.firstChild.data = "foo bar";
+  assert_equals(textarea.defaultValue, "foo bar", "the defaultValue should reflect the textContent");
+  assert_equals(textarea.value, "foo bar",
+    "changing the textContent should change the raw value, and subsequently the api value");
+
+}, "defaultValue and value are affected by setting data on a child text node");
+
+test(() => {
+
+  const textarea = document.createElement("textarea");
+
   textarea.textContent = "foo bar";
   textarea.appendChild(document.createTextNode(" baz"));
   assert_equals(textarea.defaultValue, "foo bar baz", "the defaultValue should reflect the textContent");
@@ -43,6 +67,60 @@
 test(() => {
 
   const textarea = document.createElement("textarea");
+  textarea.textContent = "foo bar";
+
+  const frag = document.createDocumentFragment();
+  frag.appendChild(document.createTextNode(" baz"));
+  const el = document.createElement("span");
+  el.appendChild(document.createTextNode("qux?"));
+  frag.appendChild(el);
+  frag.appendChild(document.createTextNode(" fizz"));
+  textarea.appendChild(frag);
+
+  textarea.appendChild(document.createTextNode(" whee"));
+  assert_equals(textarea.defaultValue, "foo bar baz fizz whee", "the defaultValue should reflect the textContent");
+  assert_equals(textarea.value, "foo bar baz fizz whee",
+    "changing the textContent should change the raw value, and subsequently the api value");
+
+}, "defaultValue and value are affected by textContent in combination with appending a DocumentFragment");
+
+test(() => {
+
+  const textarea = document.createElement("textarea");
+  textarea.appendChild(document.createTextNode("foo bar"));
+
+  const child = document.createElement("span");
+  child.textContent = "baz";
+  textarea.appendChild(child);
+
+  assert_equals(textarea.textContent, "foo barbaz", "the textContent should have *all* the text content");
+  assert_equals(textarea.defaultValue, "foo bar", "the defaultValue should reflect the child text content");
+  assert_equals(textarea.value, "foo bar",
+    "changing the child text content should change the raw value, and subsequently the api value");
+
+}, "defaultValue and value reflect child text content, not textContent");
+
+test(() => {
+
+  const textarea = document.createElement("textarea");
+  textarea.appendChild(document.createTextNode("foo bar"));
+
+  const child = document.createElement("span");
+  child.textContent = "baz";
+  textarea.appendChild(child);
+
+  textarea.defaultValue = "foo";
+
+  assert_equals(textarea.childNodes.length, 1, "Only one child node should exist");
+  assert_equals(textarea.defaultValue, "foo", "the defaultValue should be the new text");
+  assert_equals(textarea.value, "foo", "the api value should be the new text");
+  assert_equals(textarea.textContent, "foo", "the textContent should be the new text");
+
+}, "Setting defaultValue wipes out any children, including elements (just like setting textContent)");
+
+test(() => {
+
+  const textarea = document.createElement("textarea");
 
   textarea.textContent = "foo\r\nbar\rbaz\nqux";
   assert_equals(textarea.defaultValue, "foo\r\nbar\rbaz\nqux", "the defaultValue should reflect the textContent");
@@ -54,6 +132,17 @@
 
   const textarea = document.createElement("textarea");
 
+  textarea.appendChild(document.createTextNode("foo\r"));
+  textarea.appendChild(document.createTextNode("\nbar\rbaz\nqux"));
+  assert_equals(textarea.defaultValue, "foo\r\nbar\rbaz\nqux", "the defaultValue should reflect the textContent");
+  assert_equals(textarea.value, "foo\nbar\nbaz\nqux", "The value property should normalize CRLF and CR to LF");
+
+}, "value normalizes CRLF even spread over multiple text nodes");
+
+test(() => {
+
+  const textarea = document.createElement("textarea");
+
   textarea.textContent = "foo";
   textarea.value = "baz";
   assert_equals(textarea.defaultValue, "foo", "setting the value property should not affect the defaultValue");
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/idle-callbacks/callback-xhr-sync.html b/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/idle-callbacks/callback-xhr-sync.html
new file mode 100644
index 0000000..0c75973
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/idle-callbacks/callback-xhr-sync.html
@@ -0,0 +1,16 @@
+<!doctype html>
+<meta charset=utf-8>
+<title></title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script>
+  async_test(function (t) {
+    requestIdleCallback(function() {
+      requestIdleCallback(t.step_func_done(function () {}))
+      var xhr = new XMLHttpRequest();
+      xhr.open("GET", "www.emample.com", false);
+      xhr.onload = t.step_func(function () {});
+      xhr.send(null);
+    });
+  }, "re-schedule idle callbacks after sync xhr");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/bounding-box.html b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/bounding-box.html
new file mode 100644
index 0000000..69052b11
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/bounding-box.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./resources/intersection-observer-test-utils.js"></script>
+
+<style>
+pre, #log {
+  position: absolute;
+  top: 0;
+  left: 200px;
+}
+#root {
+  overflow: visible;
+  height: 200px;
+  width: 160px;
+  border: 7px solid black;
+}
+#target {
+  margin: 10px;
+  width: 100px;
+  height: 100px;
+  padding: 10px;
+  background-color: green;
+}
+</style>
+
+<div id="root">
+  <div id="target" style="transform: translateY(300px)"></div>
+</div>
+
+<script>
+var entries = [];
+var target;
+
+runTestCycle(function() {
+  target = document.getElementById("target");
+  assert_true(!!target, "target exists");
+  var root = document.getElementById("root");
+  assert_true(!!root, "root exists");
+  var observer = new IntersectionObserver(function(changes) {
+    entries = entries.concat(changes)
+  }, {root: root});
+  observer.observe(target);
+  entries = entries.concat(observer.takeRecords());
+  assert_equals(entries.length, 0, "No initial notifications.");
+  runTestCycle(step0, "First rAF.");
+}, "Test that the target's border bounding box is used to calculate intersection.");
+
+function step0() {
+  var targetBounds = clientBounds(target);
+  target.style.transform = "translateY(195px)";
+  runTestCycle(step1, "target.style.transform = 'translateY(195px)'");
+  checkLastEntry(entries, 0, targetBounds.concat(0, 0, 0, 0, 8, 182, 8, 222, false));
+}
+
+function step1() {
+  var targetBounds = clientBounds(target);
+  target.style.transform = "";
+  checkLastEntry(entries, 1, targetBounds.concat(25, 145, 220, 222, 8, 182, 8, 222, true));
+}
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/client-rect.html b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/client-rect.html
new file mode 100644
index 0000000..913e0d9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/client-rect.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./resources/intersection-observer-test-utils.js"></script>
+
+<style>
+pre, #log {
+  position: absolute;
+  top: 0;
+  left: 200px;
+}
+iframe {
+  width: 180px;
+  height: 100px;
+}
+</style>
+
+<iframe id="iframe" srcdoc="<div id='target' style='width:1000px;height:1000px;'></div>"></iframe>
+
+<script>
+var target;
+var entries = [];
+var observer;
+var iframe = document.getElementById("iframe");
+
+iframe.onload = function() {
+  runTestCycle(function() {
+    target = iframe.contentDocument.getElementById("target");
+    assert_true(!!target, "Target element exists.");
+    observer = new IntersectionObserver(function(changes) {
+      entries = entries.concat(changes);
+    });
+    observer.observe(target);
+    entries = entries.concat(observer.takeRecords());
+    assert_equals(entries.length, 0, "No initial notifications.");
+    runTestCycle(test0, "First rAF should generate notification.");
+  }, "IntersectionObserverEntry.boundingClientRect should match target.boundingClientRect()");
+};
+
+function test0() {
+  assert_equals(entries.length, 1, "One notification.");
+  var bcr = target.getBoundingClientRect();
+  checkLastEntry(entries, 0, [bcr.left, bcr.right, bcr.top, bcr.bottom]);
+}
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/containing-block.html b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/containing-block.html
new file mode 100644
index 0000000..d4f46b0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/containing-block.html
@@ -0,0 +1,73 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./resources/intersection-observer-test-utils.js"></script>
+
+<style>
+pre, #log {
+  position: absolute;
+  top: 0;
+  left: 200px;
+}
+#root {
+  width: 170px;
+  height: 200px;
+  overflow-y: scroll;
+}
+#target {
+  width: 100px;
+  height: 100px;
+  background-color: green;
+  position: absolute;
+}
+</style>
+
+<div id="root" style="position: absolute">
+  <div id="target" style="left: 50px; top: 250px"></div>
+</div>
+
+<script>
+var entries = [];
+var root, target;
+
+runTestCycle(function() {
+  root = document.getElementById("root");
+  assert_true(!!root, "root element exists.");
+  target = document.getElementById("target");
+  assert_true(!!target, "target element exists.");
+  var observer = new IntersectionObserver(function(changes) {
+    entries = entries.concat(changes);
+  }, { root: root });
+  observer.observe(target);
+  entries = entries.concat(observer.takeRecords());
+  assert_equals(entries.length, 0, "No initial notifications.");
+  target.style.top = "10px";
+  runTestCycle(test1, "In containing block and intersecting.");
+}, "IntersectionObserver should only report intersections if root is a containing block ancestor of target.");
+
+function test1() {
+  runTestCycle(test2, "In containing block and not intersecting.");
+  var rootBounds = contentBounds(root);
+  checkLastEntry(entries, 0, [58, 158, 18, 118, 58, 158, 18, 118].concat(rootBounds));
+  target.style.top = "250px";
+}
+
+function test2() {
+  runTestCycle(test3, "Not in containing block and intersecting.");
+  var rootBounds = contentBounds(root);
+  checkLastEntry(entries, 1, [58, 158, 258, 358, 0, 0, 0, 0].concat(rootBounds));
+  root.style.position = "static";
+  target.style.top = "10px";
+}
+
+function test3() {
+  runTestCycle(test4, "Not in containing block and not intersecting.");
+  checkLastEntry(entries, 1);
+  target.style.top = "250px";
+}
+
+function test4() {
+  checkLastEntry(entries, 1);
+  target.style.top = "0";
+}
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/cross-origin-iframe.html b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/cross-origin-iframe.html
new file mode 100644
index 0000000..2c9c4bcec
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/cross-origin-iframe.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./resources/intersection-observer-test-utils.js"></script>
+
+<style>
+pre, #log {
+  position: absolute;
+  top: 0;
+  left: 200px;
+}
+iframe {
+  width: 160px;
+  height: 100px;
+  overflow-y: scroll;
+}
+.spacer {
+  height: calc(100vh + 100px);
+}
+</style>
+
+<div class="spacer"></div>
+<iframe src="resources/cross-origin-subframe.html" sandbox="allow-scripts"></iframe>
+<div class="spacer"></div>
+
+<script>
+async_test(function(t) {
+  var iframe = document.querySelector("iframe");
+
+  function handleMessage(event) {
+    if (event.data.hasOwnProperty('scrollTo')) {
+      document.scrollingElement.scrollTop = event.data.scrollTo;
+      waitForNotification(t, function() { iframe.contentWindow.postMessage("", "*"); },
+        "document.scrollingElement.scrollTop = " + event.data.scrollTo);
+    } else if (event.data.hasOwnProperty('actual')) {
+      checkJsonEntries(event.data.actual, event.data.expected, event.data.description);
+    } else if (event.data.hasOwnProperty('DONE')) {
+      document.scrollingElement.scrollTop = 0;
+      t.done();
+    } else {
+      var description = event.data.description;
+      waitForNotification(t, function() { iframe.contentWindow.postMessage("", "*"); }, description);
+    }
+  }
+
+  window.addEventListener("message", t.step_func(handleMessage));
+
+  iframe.onload = t.step_func(function() {
+    waitForNotification(t, function() { iframe.contentWindow.postMessage("", "*") }, "setup");
+  });
+}, "Intersection observer test with no explicit root and target in a cross-origin iframe.");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/disconnect.html b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/disconnect.html
new file mode 100644
index 0000000..0abfbc4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/disconnect.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./resources/intersection-observer-test-utils.js"></script>
+
+<style>
+pre, #log {
+  position: absolute;
+  top: 0;
+  left: 200px;
+}
+.spacer {
+  height: calc(100vh + 100px);
+}
+#target {
+  width: 100px;
+  height: 100px;
+  background-color: green;
+}
+</style>
+
+<div class="spacer"></div>
+<div id="target"></div>
+<div class="spacer"></div>
+
+<script>
+var entries = [];
+var observer;
+var target;
+
+runTestCycle(function() {
+  target = document.getElementById("target");
+  assert_true(!!target, "target exists");
+  observer = new IntersectionObserver(function(changes) {
+    entries = entries.concat(changes)
+  });
+  observer.observe(target);
+  entries = entries.concat(observer.takeRecords());
+  assert_equals(entries.length, 0, "No initial notifications.");
+  runTestCycle(step0, "First rAF.");
+}, "IntersectionObserver should not deliver pending notifications after disconnect().");
+
+function step0() {
+  runTestCycle(step1, "observer.disconnect()");
+  document.scrollingElement.scrollTop = 300;
+  observer.disconnect();
+  assert_equals(entries.length, 1, "Initial notification.");
+}
+
+function step1() {
+  assert_equals(entries.length, 1, "No new notifications.");
+}
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/display-none.html b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/display-none.html
new file mode 100644
index 0000000..7cebc56
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/display-none.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./resources/intersection-observer-test-utils.js"></script>
+
+<style>
+pre, #log {
+  position: absolute;
+  top: 0;
+  left: 200px;
+}
+#target {
+  background-color: green;
+  width: 100px;
+  height: 100px;
+}
+</style>
+
+<div id="target"></div>
+
+<script>
+var vw = document.documentElement.clientWidth;
+var vh = document.documentElement.clientHeight;
+
+var entries = [];
+
+runTestCycle(function() {
+  var target = document.getElementById("target");
+  var root = document.getElementById("root");
+  var observer = new IntersectionObserver(function(changes) {
+    entries = entries.concat(changes)
+  });
+  observer.observe(target);
+  entries = entries.concat(observer.takeRecords());
+  assert_equals(entries.length, 0, "No initial notifications.");
+  runTestCycle(step0, "Intersecting notification after first rAF.");
+}, "IntersectionObserver should send a not-intersecting notification for a target that gets display:none.");
+
+function step0() {
+  runTestCycle(step1, "Not-intersecting notification after setting display:none on target.");
+  checkLastEntry(entries, 0, [8, 108, 8, 108, 8, 108, 8, 108, 0, vw, 0, vh, true]);
+  target.style.display = "none";
+}
+
+function step1() {
+  runTestCycle(step2, "Intersecting notification after removing display:none on target.");
+  checkLastEntry(entries, 1, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false]);
+  target.style.display = "";
+}
+
+function step2() {
+  checkLastEntry(entries, 2, [8, 108, 8, 108, 8, 108, 8, 108, 0, vw, 0, vh, true]);
+}
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/edge-inclusive-intersection.html b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/edge-inclusive-intersection.html
new file mode 100644
index 0000000..b9fa24b87
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/edge-inclusive-intersection.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./resources/intersection-observer-test-utils.js"></script>
+
+<style>
+pre, #log {
+  position: absolute;
+  top: 0;
+  left: 200px;
+}
+#root {
+  width: 200px;
+  height: 200px;
+  overflow: visible;
+}
+#target {
+  background-color: green;
+}
+</style>
+
+<div id="root">
+  <div id="target" style="width: 100px; height: 100px; transform: translateY(250px)"></div>
+</div>
+
+<script>
+var entries = [];
+
+runTestCycle(function() {
+  var root = document.getElementById('root');
+  assert_true(!!root, "root element exists.");
+  var target = document.getElementById('target');
+  assert_true(!!target, "target element exists.");
+  var observer = new IntersectionObserver(function(changes) {
+    entries = entries.concat(changes);
+  }, { root: root });
+  observer.observe(target);
+  entries = entries.concat(observer.takeRecords());
+  assert_equals(entries.length, 0, "No initial notifications.");
+  runTestCycle(step0, "First rAF.");
+}, "IntersectionObserver should detect and report edge-adjacent and zero-area intersections.");
+
+function step0() {
+  runTestCycle(step1, "Set transform=translateY(200px) on target.");
+  checkLastEntry(entries, 0, [8, 108, 258, 358, 0, 0, 0, 0, 8, 208, 8, 208, false]);
+  target.style.transform = "translateY(200px)";
+}
+
+function step1() {
+  runTestCycle(step2, "Set transform=translateY(201px) on target.");
+  checkLastEntry(entries, 1, [8, 108, 208, 308, 8, 108, 208, 208, 8, 208, 8, 208, true]);
+  target.style.transform = "translateY(201px)";
+}
+
+function step2() {
+  runTestCycle(step3, "Set transform=translateY(185px) on target.");
+  checkLastEntry(entries, 2);
+  target.style.height = "0px";
+  target.style.width = "300px";
+  target.style.transform = "translateY(185px)";
+}
+
+function step3() {
+  checkLastEntry(entries, 3, [8, 308, 193, 193, 8, 208, 193, 193, 8, 208, 8, 208, true]);
+}
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/iframe-no-root.html b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/iframe-no-root.html
new file mode 100644
index 0000000..e37aeac
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/iframe-no-root.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./resources/intersection-observer-test-utils.js"></script>
+
+<style>
+pre, #log {
+  position: absolute;
+  top: 0;
+  left: 200px;
+}
+.spacer {
+  height: calc(100vh + 100px);
+}
+iframe {
+  height: 100px;
+  width: 150px;
+}
+</style>
+
+<div class="spacer"></div>
+<iframe id="target-iframe" src="resources/iframe-no-root-subframe.html"></iframe>
+<div class="spacer"></div>
+
+<script>
+var vw = document.documentElement.clientWidth;
+var vh = document.documentElement.clientHeight;
+
+var iframe = document.getElementById("target-iframe");
+var target;
+var entries = [];
+
+iframe.onload = function() {
+  runTestCycle(function() {
+    assert_true(!!iframe, "iframe exists");
+
+    target = iframe.contentDocument.getElementById("target");
+    assert_true(!!target, "Target element exists.");
+    var observer = new IntersectionObserver(function(changes) {
+      entries = entries.concat(changes)
+    });
+    observer.observe(target);
+    entries = entries.concat(observer.takeRecords());
+    assert_equals(entries.length, 0, "No initial notifications.");
+    runTestCycle(step0, "First rAF.");
+  }, "Observer with the implicit root; target in a same-origin iframe.");
+};
+
+function step0() {
+  document.scrollingElement.scrollTop = 200;
+  runTestCycle(step1, "document.scrollingElement.scrollTop = 200");
+  checkLastEntry(entries, 0, [8, 108, 208, 308, 0, 0, 0, 0, 0, vw, 0, vh, false]);
+}
+
+function step1() {
+  iframe.contentDocument.scrollingElement.scrollTop = 250;
+  runTestCycle(step2, "iframe.contentDocument.scrollingElement.scrollTop = 250");
+  assert_equals(entries.length, 1, "entries.length == 1");
+}
+
+function step2() {
+  document.scrollingElement.scrollTop = 100;
+  runTestCycle(step3, "document.scrollingElement.scrollTop = 100");
+  checkLastEntry(entries, 1, [8, 108, -42, 58, 8, 108, 0, 58, 0, vw, 0, vh, true]);
+}
+
+function step3() {
+  checkLastEntry(entries, 2, [8, 108, -42, 58, 0, 0, 0, 0, 0, vw, 0, vh, false]);
+  document.scrollingElement.scrollTop = 0;
+}
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/multiple-targets.html b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/multiple-targets.html
new file mode 100644
index 0000000..525c5a6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/multiple-targets.html
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./resources/intersection-observer-test-utils.js"></script>
+
+<style>
+pre, #log {
+  position: absolute;
+  top: 0;
+  left: 200px;
+}
+.spacer {
+  height: calc(100vh + 100px);
+}
+.target {
+  width: 100px;
+  height: 100px;
+  margin: 10px;
+  background-color: green;
+}
+</style>
+
+<div class="spacer"></div>
+<div id="target1" class="target"></div>
+<div id="target2" class="target"></div>
+<div id="target3" class="target"></div>
+
+<script>
+var entries = [];
+var target1, target2, target3;
+
+runTestCycle(function() {
+  target1 = document.getElementById("target1");
+  assert_true(!!target1, "target1 exists.");
+  target2 = document.getElementById("target2");
+  assert_true(!!target2, "target2 exists.");
+  target3 = document.getElementById("target3");
+  assert_true(!!target3, "target3 exists.");
+  var observer = new IntersectionObserver(function(changes) {
+    entries = entries.concat(changes)
+  });
+  observer.observe(target1);
+  observer.observe(target2);
+  observer.observe(target3);
+  entries = entries.concat(observer.takeRecords());
+  assert_equals(entries.length, 0, "No initial notifications.");
+  runTestCycle(step0, "First rAF.");
+}, "One observer with multiple targets.");
+
+function step0() {
+  document.scrollingElement.scrollTop = 150;
+  runTestCycle(step1, "document.scrollingElement.scrollTop = 150");
+  assert_equals(entries.length, 3, "Three initial notifications.");
+  assert_equals(entries[0].target, target1, "entries[0].target === target1");
+  assert_equals(entries[1].target, target2, "entries[1].target === target2");
+  assert_equals(entries[2].target, target3, "entries[2].target === target3");
+}
+
+function step1() {
+  document.scrollingElement.scrollTop = 10000;
+  runTestCycle(step2, "document.scrollingElement.scrollTop = 10000");
+  assert_equals(entries.length, 4, "Four notifications.");
+  assert_equals(entries[3].target, target1, "entries[3].target === target1");
+}
+
+function step2() {
+  document.scrollingElement.scrollTop = 0;
+  runTestCycle(step3, "document.scrollingElement.scrollTop = 0");
+  assert_equals(entries.length, 6, "Six notifications.");
+  assert_equals(entries[4].target, target2, "entries[4].target === target2");
+  assert_equals(entries[5].target, target3, "entries[5].target === target3");
+}
+
+function step3() {
+  assert_equals(entries.length, 9, "Nine notifications.");
+  assert_equals(entries[6].target, target1, "entries[6].target === target1");
+  assert_equals(entries[7].target, target2, "entries[7].target === target2");
+  assert_equals(entries[8].target, target3, "entries[8].target === target3");
+}
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/multiple-thresholds.html b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/multiple-thresholds.html
new file mode 100644
index 0000000..64500689
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/multiple-thresholds.html
@@ -0,0 +1,96 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./resources/intersection-observer-test-utils.js"></script>
+
+<style>
+pre, #log {
+  position: absolute;
+  top: 0;
+  left: 200px;
+}
+.spacer {
+  height: calc(100vh + 100px);
+}
+#target {
+  width: 100px;
+  height: 100px;
+  background-color: green;
+}
+</style>
+
+<div class="spacer"></div>
+<div id="target"></div>
+<div class="spacer"></div>
+
+<script>
+var vw = document.documentElement.clientWidth;
+var vh = document.documentElement.clientHeight;
+
+var entries = [];
+var target;
+
+runTestCycle(function() {
+  target = document.getElementById("target");
+  var observer = new IntersectionObserver(function(changes) {
+    entries = entries.concat(changes)
+  }, { threshold: [0, 0.25, 0.5, 0.75, 1] });
+  observer.observe(target);
+  entries = entries.concat(observer.takeRecords());
+  assert_equals(entries.length, 0, "No initial notifications.");
+  runTestCycle(step0, "First rAF.");
+}, "Observer with multiple thresholds.");
+
+function step0() {
+  document.scrollingElement.scrollTop = 120;
+  runTestCycle(step1, "document.scrollingElement.scrollTop = 120");
+  checkLastEntry(entries, 0, [8, 108, vh + 108, vh + 208, 0, 0, 0, 0, 0, vw, 0, vh, false]);
+}
+
+function step1() {
+  document.scrollingElement.scrollTop = 160;
+  runTestCycle(step2, "document.scrollingElement.scrollTop = 160");
+  checkLastEntry(entries, 1, [8, 108, vh - 12, vh + 88, 8, 108, vh - 12, vh, 0, vw, 0, vh, true]);
+}
+
+function step2() {
+  document.scrollingElement.scrollTop = 200;
+  runTestCycle(step3, "document.scrollingElement.scrollTop = 200");
+  checkLastEntry(entries, 2, [8, 108, vh - 52, vh + 48, 8, 108, vh - 52, vh, 0, vw, 0, vh, true]);
+}
+
+function step3() {
+  document.scrollingElement.scrollTop = 240;
+  runTestCycle(step4, "document.scrollingElement.scrollTop = 240");
+  checkLastEntry(entries, 3, [8, 108, vh - 92, vh + 8, 8, 108, vh - 92, vh, 0, vw, 0, vh, true]);
+}
+
+function step4() {
+  document.scrollingElement.scrollTop = vh + 140;
+  runTestCycle(step5, "document.scrollingElement.scrollTop = window.innerHeight + 140");
+  checkLastEntry(entries, 4, [8, 108, vh - 132, vh - 32, 8, 108, vh - 132, vh - 32, 0, vw, 0, vh, true]);
+}
+
+function step5() {
+  document.scrollingElement.scrollTop = vh + 160;
+  runTestCycle(step6, "document.scrollingElement.scrollTop = window.innerHeight + 160");
+  checkLastEntry(entries, 5, [8, 108, -32, 68, 8, 108, 0, 68, 0, vw, 0, vh, true]);
+}
+
+function step6() {
+  document.scrollingElement.scrollTop = vh + 200;
+  runTestCycle(step7, "document.scrollingElement.scrollTop = window.innerHeight + 200");
+  checkLastEntry(entries, 6, [8, 108, -52, 48, 8, 108, 0, 48, 0, vw, 0, vh, true]);
+}
+
+function step7() {
+  checkLastEntry(entries, 7, [8, 108, -92, 8, 8, 108, 0, 8, 0, vw, 0, vh, true]);
+  document.scrollingElement.scrollTop = vh + 220;
+  runTestCycle(step8, "document.scrollingElement.scrollTop = window.innerHeight + 220");
+}
+
+function step8() {
+  checkLastEntry(entries, 8, [8, 108, -112, -12, 0, 0, 0, 0, 0, vw, 0, vh, false]);
+  document.scrollingElement.scrollTop = 0;
+}
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/observer-attributes.html b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/observer-attributes.html
new file mode 100644
index 0000000..ffca95d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/observer-attributes.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<div id="root"></div>
+
+<script>
+test(function() {
+  var observer = new IntersectionObserver(function(e) {}, {});
+  test(function() { assert_equals(observer.root, null) },
+       "observer.root");
+  test(function() { assert_array_equals(observer.thresholds, [0]) },
+       "observer.thresholds");
+  test(function() { assert_equals(observer.rootMargin, "0px 0px 0px 0px") },
+       "observer.rootMargin");
+
+  var rootDiv = document.getElementById("root");
+  observer = new IntersectionObserver(function(e) {}, {
+    root: rootDiv,
+    threshold: [0, 0.25, 0.5, 1.0],
+    rootMargin: "10% 20px"
+  });
+  test(function() { assert_equals(observer.root, rootDiv) },
+       "set observer.root");
+  test(function() { assert_array_equals(observer.thresholds, [0, 0.25, 0.5, 1.0]) },
+       "set observer.thresholds");
+  test(function() { assert_equals(observer.rootMargin, "10% 20px 10% 20px") },
+       "set observer.rootMargin");
+}, "Observer attribute getters.");
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/observer-exceptions.html b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/observer-exceptions.html
new file mode 100644
index 0000000..b44b7bd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/observer-exceptions.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script>
+test(function () {
+  assert_throws(RangeError(), function() {
+    new IntersectionObserver(e => {}, {threshold: [1.1]})
+  })
+}, "IntersectionObserver constructor with { threshold: [1.1] }");
+
+test(function () {
+  assert_throws(TypeError(), function() {
+    new IntersectionObserver(e => {}, {threshold: ["foo"]})
+  })
+}, 'IntersectionObserver constructor with { threshold: ["foo"] }');
+
+test(function () {
+  assert_throws("SYNTAX_ERR", function() {
+    new IntersectionObserver(e => {}, {rootMargin: "1"})
+  })
+}, 'IntersectionObserver constructor witth { rootMargin: "1" }');
+
+test(function () {
+  assert_throws("SYNTAX_ERR", function() {
+    new IntersectionObserver(e => {}, {rootMargin: "2em"})
+  })
+}, 'IntersectionObserver constructor with { rootMargin: "2em" }');
+
+test(function () {
+  assert_throws("SYNTAX_ERR", function() {
+    new IntersectionObserver(e => {}, {rootMargin: "auto"})
+  })
+}, 'IntersectionObserver constructor width { rootMargin: "auto" }');
+
+test(function () {
+  assert_throws("SYNTAX_ERR", function() {
+    new IntersectionObserver(e => {}, {rootMargin: "1px 1px 1px 1px 1px"})
+  })
+}, 'IntersectionObserver constructor with { rootMargin: "1px 1px 1px 1px 1px" }');
+
+test(function () {
+  assert_throws(TypeError(), function() {
+    let observer = new IntersectionObserver(c => {}, {});
+    observer.observe("foo");
+  })
+}, 'IntersectionObserver.observe("foo")');
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/observer-in-iframe.html b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/observer-in-iframe.html
new file mode 100644
index 0000000..f4aa387d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/observer-in-iframe.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<style>
+pre, #log {
+  position: absolute;
+  top: 0;
+  left: 200px;
+}
+</style>
+<iframe id="target-iframe" src="resources/observer-in-iframe-subframe.html" width="150px" height="150px"></iframe>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/observer-without-js-reference.html b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/observer-without-js-reference.html
new file mode 100644
index 0000000..3214345
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/observer-without-js-reference.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./resources/intersection-observer-test-utils.js"></script>
+
+<style>
+pre, #log {
+  position: absolute;
+  top: 0;
+  left: 200px;
+}
+.spacer {
+  height: calc(100vh + 100px);
+}
+#target {
+  width: 100px;
+  height: 100px;
+  background-color: green;
+}
+</style>
+<div class="spacer"></div>
+<div id="target"></div>
+<div class="spacer"></div>
+
+<script>
+var entries = [];
+
+runTestCycle(function() {
+  var target = document.getElementById("target");
+  assert_true(!!target, "Target exists");
+  function createObserver() {
+    new IntersectionObserver(function(changes) {
+      entries = entries.concat(changes)
+    }).observe(target);
+  }
+  createObserver();
+  runTestCycle(step0, "First rAF");
+}, "IntersectionObserver that is unreachable in js should still generate notifications.");
+
+function step0() {
+  document.scrollingElement.scrollTop = 300;
+  runTestCycle(step1, "document.scrollingElement.scrollTop = 300");
+  assert_equals(entries.length, 1, "One notification.");
+}
+
+function step1() {
+  document.scrollingElement.scrollTop = 0;
+  assert_equals(entries.length, 2, "Two notifications.");
+}
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/remove-element.html b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/remove-element.html
new file mode 100644
index 0000000..3b6a65e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/remove-element.html
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./resources/intersection-observer-test-utils.js"></script>
+
+<style>
+pre, #log {
+  position: absolute;
+  top: 0;
+  left: 200px;
+}
+#root {
+  display: inline-block;
+  overflow-y: scroll;
+  height: 200px;
+  border: 3px solid black;
+}
+#target {
+  width: 100px;
+  height: 100px;
+  background-color: green;
+}
+.spacer {
+  height: 300px;
+}
+</style>
+
+<div id="root">
+  <div id="leading-space" class="spacer"></div>
+  <div id="target"></div>
+  <div id="trailing-space" class="spacer"</div>
+</div>
+
+<script>
+var entries = [];
+var root, target, trailingSpace;
+
+runTestCycle(function() {
+  target = document.getElementById("target");
+  assert_true(!!target, "Target exists");
+  trailingSpace = document.getElementById("trailing-space");
+  assert_true(!!trailingSpace, "TrailingSpace exists");
+  root = document.getElementById("root");
+  assert_true(!!root, "Root exists");
+  var observer = new IntersectionObserver(function(changes) {
+    entries = entries.concat(changes)
+  }, {root: root});
+  observer.observe(target);
+  entries = entries.concat(observer.takeRecords());
+  assert_equals(entries.length, 0, "No initial notifications.");
+  runTestCycle(step0, "First rAF");
+}, "Verify that not-intersecting notifications are sent when a target is removed from the DOM tree.");
+
+function step0() {
+  root.scrollTop = 150;
+  runTestCycle(step1, "root.scrollTop = 150");
+  checkLastEntry(entries, 0, [11, 111, 311, 411, 0, 0, 0, 0, 11, 111, 11, 211, false]);
+}
+
+function step1() {
+  root.removeChild(target);
+  runTestCycle(step2, "root.removeChild(target).");
+  checkLastEntry(entries, 1, [11, 111, 161, 261, 11, 111, 161, 211, 11, 111, 11, 211, true]);
+}
+
+function step2() {
+  root.scrollTop = 0;
+  root.insertBefore(target, trailingSpace);
+  runTestCycle(step3, "root.insertBefore(target, trailingSpace).");
+  checkLastEntry(entries, 2, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false]);
+}
+
+function step3() {
+  root.scrollTop = 150;
+  runTestCycle(step4, "root.scrollTop = 150 after reinserting target.");
+  checkLastEntry(entries, 2);
+}
+
+function step4() {
+  checkLastEntry(entries, 3, [11, 111, 161, 261, 11, 111, 161, 211, 11, 111, 11, 211, true]);
+}
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/resources/cross-origin-subframe.html b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/resources/cross-origin-subframe.html
new file mode 100644
index 0000000..0cc117cb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/resources/cross-origin-subframe.html
@@ -0,0 +1,125 @@
+<!DOCTYPE html>
+<div style="height: 200px; width: 100px;"></div>
+<div id="target" style="background-color: green; width:100px; height:100px"></div>
+<div style="height: 200px; width: 100px;"></div>
+
+<script>
+var port;
+var entries = [];
+var target = document.getElementById('target');
+var scroller = document.scrollingElement;
+var nextStep;
+
+function clientRectToJson(rect) {
+  if (!rect)
+    return "null";
+  return {
+    top: rect.top,
+    right: rect.right,
+    bottom: rect.bottom,
+    left: rect.left
+  };
+}
+
+function entryToJson(entry) {
+  return {
+    boundingClientRect: clientRectToJson(entry.boundingClientRect),
+    intersectionRect: clientRectToJson(entry.intersectionRect),
+    rootBounds: clientRectToJson(entry.rootBounds),
+    target: entry.target.id
+  };
+}
+
+function coordinatesToClientRectJson(top, right, bottom, left) {
+  return {
+    top: top,
+    right: right,
+    bottom: bottom,
+    left: left
+  };
+}
+
+// Note that we never use RAF in this code, because this frame might get render-throttled.
+// Instead of RAF-ing, we just post an empty message to the parent window, which will
+// RAF when it is received, and then send us a message to cause the next step to run.
+
+// Use a rootMargin here, and verify it does NOT get applied for the cross-origin case.
+var observer = new IntersectionObserver(function(changes) {
+    entries = entries.concat(changes)
+}, { rootMargin: "7px" });
+observer.observe(target);
+
+function step0() {
+  entries = entries.concat(observer.takeRecords());
+  nextStep = step1;
+  var expected = [{
+    boundingClientRect: coordinatesToClientRectJson(8, 208, 108, 308),
+    intersectionRect: coordinatesToClientRectJson(0, 0, 0, 0),
+    rootBounds: "null",
+    target: target.id
+  }];
+  port.postMessage({
+    actual: entries.map(entryToJson),
+    expected: expected,
+    description: "First rAF"
+  }, "*");
+  entries = [];
+  port.postMessage({scrollTo: 200}, "*");
+}
+
+function step1() {
+  entries = entries.concat(observer.takeRecords());
+  port.postMessage({
+    actual: entries.map(entryToJson),
+    expected: [],
+    description: "topDocument.scrollingElement.scrollTop = 200"
+  }, "*");
+  entries = [];
+  scroller.scrollTop = 250;
+  nextStep = step2;
+  port.postMessage({}, "*");
+}
+
+function step2() {
+  entries = entries.concat(observer.takeRecords());
+  var expected = [{
+    boundingClientRect: coordinatesToClientRectJson(-42, 108, 58, 8),
+    intersectionRect: coordinatesToClientRectJson(0, 108, 58, 8),
+    rootBounds: "null",
+    target: target.id
+  }];
+  port.postMessage({
+    actual: entries.map(entryToJson),
+    expected: expected,
+    description: "iframeDocument.scrollingElement.scrollTop = 250"
+  }, "*");
+  entries = [];
+  nextStep = step3;
+  port.postMessage({scrollTo: 100}, "*");
+}
+
+function step3() {
+  entries = entries.concat(observer.takeRecords());
+  var expected = [{
+    boundingClientRect: coordinatesToClientRectJson(-42, 108, 58, 8),
+    intersectionRect: coordinatesToClientRectJson(0, 0, 0, 0),
+    rootBounds: "null",
+    target: target.id
+  }];
+  port.postMessage({
+    actual: entries.map(entryToJson),
+    expected: expected,
+    description: "topDocument.scrollingElement.scrollTop = 100"
+  }, "*");
+  port.postMessage({DONE: 1}, "*");
+}
+
+function handleMessage(event)
+{
+  port = event.source;
+  nextStep();
+}
+
+nextStep = step0;
+window.addEventListener("message", handleMessage);
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/resources/iframe-no-root-subframe.html b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/resources/iframe-no-root-subframe.html
new file mode 100644
index 0000000..ee63a06
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/resources/iframe-no-root-subframe.html
@@ -0,0 +1,4 @@
+<!DOCTYPE html>
+<div style="height: 200px; width: 100px;"></div>
+<div id="target" style="background-color: green; width:100px; height:100px"></div>
+<div style="height: 200px; width: 100px;"></div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/resources/intersection-observer-test-utils.js b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/resources/intersection-observer-test-utils.js
new file mode 100644
index 0000000..48ccbb19
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/resources/intersection-observer-test-utils.js
@@ -0,0 +1,122 @@
+// Here's how waitForNotification works:
+//
+// - myTestFunction0()
+//   - waitForNotification(myTestFunction1)
+//     - requestAnimationFrame()
+//   - Modify DOM in a way that should trigger an IntersectionObserver callback.
+// - BeginFrame
+//   - requestAnimationFrame handler runs
+//     - First step_timeout()
+//   - Style, layout, paint
+//   - IntersectionObserver generates new notifications
+//     - Posts a task to deliver notifications
+// - First step_timeout handler runs
+//   - Second step_timeout()
+// - Task to deliver IntersectionObserver notifications runs
+//   - IntersectionObserver callbacks run
+// - Second step_timeout handler runs
+//   - myTestFunction1()
+//     - [optional] waitForNotification(myTestFunction2)
+//       - requestAnimationFrame()
+//     - Verify newly-arrived IntersectionObserver notifications
+//     - [optional] Modify DOM to trigger new notifications
+function waitForNotification(t, f) {
+  requestAnimationFrame(function() {
+    t.step_timeout(function() { t.step_timeout(f); });
+  });
+}
+
+// The timing of when runTestCycle is called is important.  It should be
+// called:
+//
+//   - Before or during the window load event, or
+//   - Inside of a prior runTestCycle callback, *before* any assert_* methods
+//     are called.
+//
+// Following these rules will ensure that the test suite will not abort before
+// all test steps have run.
+function runTestCycle(f, description) {
+  async_test(function(t) {
+    waitForNotification(t, t.step_func_done(f));
+  }, description);
+}
+
+// Root bounds for a root with an overflow clip as defined by:
+//   http://wicg.github.io/IntersectionObserver/#intersectionobserver-root-intersection-rectangle
+function contentBounds(root) {
+  var left = root.offsetLeft + root.clientLeft;
+  var right = left + root.clientWidth;
+  var top = root.offsetTop + root.clientTop;
+  var bottom = top + root.clientHeight;
+  return [left, right, top, bottom];
+}
+
+// Root bounds for a root without an overflow clip as defined by:
+//   http://wicg.github.io/IntersectionObserver/#intersectionobserver-root-intersection-rectangle
+function borderBoxBounds(root) {
+  var left = root.offsetLeft;
+  var right = left + root.offsetWidth;
+  var top = root.offsetTop;
+  var bottom = top + root.offsetHeight;
+  return [left, right, top, bottom];
+}
+
+function clientBounds(element) {
+  var rect = element.getBoundingClientRect();
+  return [rect.left, rect.right, rect.top, rect.bottom];
+}
+
+function rectArea(rect) {
+  return (rect.left - rect.right) * (rect.bottom - rect.top);
+}
+
+function checkRect(actual, expected, description, all) {
+  if (!expected.length)
+    return;
+  assert_equals(actual.left | 0, expected[0] | 0, description + '.left');
+  assert_equals(actual.right | 0, expected[1] | 0, description + '.right');
+  assert_equals(actual.top | 0, expected[2] | 0, description + '.top');
+  assert_equals(actual.bottom | 0, expected[3] | 0, description + '.bottom');
+}
+
+function checkLastEntry(entries, i, expected) {
+  assert_equals(entries.length, i + 1, 'entries.length');
+  if (expected) {
+    checkRect(
+        entries[i].boundingClientRect, expected.slice(0, 4),
+        'entries[' + i + '].boundingClientRect', entries[i]);
+    checkRect(
+        entries[i].intersectionRect, expected.slice(4, 8),
+        'entries[' + i + '].intersectionRect', entries[i]);
+    checkRect(
+        entries[i].rootBounds, expected.slice(8, 12),
+        'entries[' + i + '].rootBounds', entries[i]);
+    if (expected.length > 12) {
+      assert_equals(
+          entries[i].isIntersecting, expected[12],
+          'entries[' + i + '].isIntersecting');
+    }
+  }
+}
+
+function checkJsonEntry(actual, expected) {
+  checkRect(
+      actual.boundingClientRect, expected.boundingClientRect,
+      'entry.boundingClientRect');
+  checkRect(
+      actual.intersectionRect, expected.intersectionRect,
+      'entry.intersectionRect');
+  if (actual.rootBounds == 'null')
+    assert_equals(expected.rootBounds, 'null', 'rootBounds is null');
+  else
+    checkRect(actual.rootBounds, expected.rootBounds, 'entry.rootBounds');
+  assert_equals(actual.target, expected.target);
+}
+
+function checkJsonEntries(actual, expected, description) {
+  test(function() {
+    assert_equals(actual.length, expected.length);
+    for (var i = 0; i < actual.length; i++)
+      checkJsonEntry(actual[i], expected[i]);
+  }, description);
+}
diff --git a/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/resources/observer-in-iframe-subframe.html b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/resources/observer-in-iframe-subframe.html
new file mode 100644
index 0000000..9d0769ae
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/resources/observer-in-iframe-subframe.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./intersection-observer-test-utils.js"></script>
+
+<style>
+#root {
+  width: 200px;
+  height: 200px;
+}
+#scroller {
+  width: 160px;
+  height: 200px;
+  overflow-y: scroll;
+}
+#target {
+  width: 100px;
+  height: 100px;
+  background-color: green;
+}
+.spacer {
+  height: 300px;
+}
+</style>
+
+<div id="root">
+  <div id="scroller">
+    <div class="spacer"></div>
+    <div id="target"></div>
+    <div class="spacer"></div>
+  </div>
+</div>
+
+<script>
+setup({message_events: [], output_document: window.parent.document});
+
+var entries = [];
+var root, scroller, target;
+
+runTestCycle(function() {
+  root = document.getElementById("root");
+  assert_true(!!root, "Root element exists.");
+  scroller = document.getElementById("scroller");
+  assert_true(!!scroller, "Scroller element exists.");
+  target = document.getElementById("target");
+  assert_true(!!target, "Target element exists.");
+  var observer = new IntersectionObserver(function(changes) {
+    entries = entries.concat(changes)
+  }, {root: root});
+  observer.observe(target);
+  entries = entries.concat(observer.takeRecords());
+  assert_equals(entries.length, 0, "No initial notifications.")
+  runTestCycle(step1, "First rAF.");
+}, "IntersectionObserver in iframe with explicit root.");
+
+function step1() {
+  scroller.scrollTop = 250;
+  runTestCycle(step2, "scroller.scrollTop = 250");
+  checkLastEntry(entries, 0, [8, 108, 308, 408, 0, 0, 0, 0, 8, 208, 8, 208, false]);
+}
+
+function step2() {
+  checkLastEntry(entries, 1, [8, 108, 58, 158, 8, 108, 58, 158, 8, 208, 8, 208, true]);
+}
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/resources/timestamp-subframe.html b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/resources/timestamp-subframe.html
new file mode 100644
index 0000000..143e4f6e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/resources/timestamp-subframe.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<style>
+#target {
+  width: 100px;
+  height: 100px;
+  background-color: green;
+}
+.spacer {
+  width: height: 100px
+}
+</style>
+
+<div class="spacer"></div>
+<div id="target"></div>
+<div class="spacer"></div>
+
+<script>
+document.createObserverCallback = function(entries) {
+  return function(newEntries) {
+    for (var i in newEntries) {
+      entries.push(newEntries[i]);
+    }
+  };
+}
+document.createObserver = function(callback) {
+  return new IntersectionObserver(callback, {});
+};
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/root-margin.html b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/root-margin.html
new file mode 100644
index 0000000..c1fffec
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/root-margin.html
@@ -0,0 +1,86 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./resources/intersection-observer-test-utils.js"></script>
+
+<style>
+pre, #log {
+  position: absolute;
+  top: 0;
+  left: 200px;
+}
+#target {
+  display: inline-block;
+  width: 100px;
+  height: 100px;
+  background-color: green;
+}
+.vertical-spacer {
+  height: calc(100vh + 100px);
+}
+.horizontal-spacer {
+  display: inline-block;
+  width: 120vw;
+}
+</style>
+
+<div class="vertical-spacer"></div>
+<div style="white-space:nowrap;">
+  <div class="horizontal-spacer"></div>
+  <div id="target"></div>
+  <div class="horizontal-spacer"></div>
+</div>
+<div class="vertical-spacer"></div>
+
+<script>
+var vw = document.documentElement.clientWidth;
+var vh = document.documentElement.clientHeight;
+
+var entries = [];
+var target;
+
+runTestCycle(function() {
+  target = document.getElementById("target");
+  assert_true(!!target, "Target exists");
+  var observer = new IntersectionObserver(function(changes) {
+    entries = entries.concat(changes)
+  }, { rootMargin: "10px 20% 40% 30px" });
+  observer.observe(target);
+  entries = entries.concat(observer.takeRecords());
+  assert_equals(entries.length, 0, "No initial notifications.");
+  runTestCycle(step0, "First rAF.");
+}, "Root margin tests");
+
+function step0() {
+  var targetBounds = clientBounds(target);
+  document.scrollingElement.scrollLeft = 100;
+  runTestCycle(step1, "document.scrollingElement.scrollLeft = 100");
+  checkLastEntry(entries, 0, targetBounds.concat(0, 0, 0, 0, -30, vw * 1.2, -10, vh * 1.4, false));
+}
+
+function step1() {
+  var targetBounds = clientBounds(target);
+  var sw = window.innerWidth - document.documentElement.clientWidth;
+  var sh = window.innerHeight - document.documentElement.clientHeight;
+  document.scrollingElement.scrollTop = vh + 200;
+  runTestCycle(step2, "document.scrollingElement.scrollTop = document.documentElement.clientHeight + 200");
+  checkLastEntry(entries, 1, targetBounds.concat(
+    targetBounds[0], Math.min(targetBounds[1], vw * 1.2), vh + 108 + sh, Math.min(vh + 208 + sw, vh * 1.4),
+    -30, vw * 1.2, -10, vh * 1.4,
+    true
+  ));
+}
+
+function step2() {
+  document.scrollingElement.scrollTop = vh + 300;
+  runTestCycle(step3, "document.scrollingElement.scrollTop = document.documentElement.clientHeight + 300");
+  checkLastEntry(entries, 1);
+}
+
+function step3() {
+  var targetBounds = clientBounds(target);
+  document.scrollingElement.scrollLeft = 0;
+  document.scrollingElement.scrollTop = 0;
+  checkLastEntry(entries, 2, targetBounds.concat(0, 0, 0, 0, -30, vw * 1.2, -10, vh * 1.4, false));
+}
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/same-document-no-root.html b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/same-document-no-root.html
new file mode 100644
index 0000000..7838808
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/same-document-no-root.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./resources/intersection-observer-test-utils.js"></script>
+
+<style>
+pre, #log {
+  position: absolute;
+  top: 0;
+  left: 200px;
+}
+.spacer {
+  height: calc(100vh + 100px);
+}
+#target {
+  width: 100px;
+  height: 100px;
+  background-color: green;
+}
+</style>
+
+<div class="spacer"></div>
+<div id="target"></div>
+<div class="spacer"></div>
+
+<script>
+var vw = document.documentElement.clientWidth;
+var vh = document.documentElement.clientHeight;
+
+var entries = [];
+var target;
+
+runTestCycle(function() {
+  target = document.getElementById("target");
+  assert_true(!!target, "target exists");
+  var observer = new IntersectionObserver(function(changes) {
+    entries = entries.concat(changes)
+  });
+  observer.observe(target);
+  entries = entries.concat(observer.takeRecords());
+  assert_equals(entries.length, 0, "No initial notifications.");
+  runTestCycle(step0, "First rAF.");
+}, "IntersectionObserver in a single document using the implicit root.");
+
+function step0() {
+  document.scrollingElement.scrollTop = 300;
+  runTestCycle(step1, "document.scrollingElement.scrollTop = 300");
+  checkLastEntry(entries, 0, [8, 108, vh + 108, vh + 208, 0, 0, 0, 0, 0, vw, 0, vh, false]);
+}
+
+function step1() {
+  document.scrollingElement.scrollTop = 100;
+  runTestCycle(step2, "document.scrollingElement.scrollTop = 100");
+  checkLastEntry(entries, 1, [8, 108, vh - 192, vh - 92, 8, 108, vh - 192, vh - 92, 0, vw, 0, vh, true]);
+}
+
+function step2() {
+  document.scrollingElement.scrollTop = 0;
+  checkLastEntry(entries, 2, [8, 108, vh + 8, vh + 108, 0, 0, 0, 0, 0, vw, 0, vh, false]);
+}
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/same-document-root.html b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/same-document-root.html
new file mode 100644
index 0000000..40467be
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/same-document-root.html
@@ -0,0 +1,90 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./resources/intersection-observer-test-utils.js"></script>
+
+<style>
+pre, #log {
+  position: absolute;
+  top: 0;
+  left: 200px;
+}
+.spacer {
+  height: calc(100vh + 100px);
+}
+#root {
+  display: inline-block;
+  overflow-y: scroll;
+  height: 200px;
+  border: 3px solid black;
+}
+#target {
+  width: 100px;
+  height: 100px;
+  background-color: green;
+}
+</style>
+
+<div class="spacer"></div>
+<div id="root">
+  <div style="height: 300px;"></div>
+  <div id="target"></div>
+</div>
+<div class="spacer"></div>
+
+<script>
+var vw = document.documentElement.clientWidth;
+var vh = document.documentElement.clientHeight;
+
+var entries = [];
+var root, target;
+
+runTestCycle(function() {
+  target = document.getElementById("target");
+  assert_true(!!target, "target exists");
+  root = document.getElementById("root");
+  assert_true(!!root, "root exists");
+  var observer = new IntersectionObserver(function(changes) {
+    entries = entries.concat(changes)
+  }, { root: root });
+  observer.observe(target);
+  entries = entries.concat(observer.takeRecords());
+  assert_equals(entries.length, 0, "No initial notifications.");
+  runTestCycle(step0, "First rAF");
+}, "IntersectionObserver in a single document with explicit root.");
+
+function step0() {
+  document.scrollingElement.scrollTop = vh;
+  runTestCycle(step1, "document.scrollingElement.scrollTop = window.innerHeight.");
+  checkLastEntry(entries, 0, [ 11, 111, vh + 411, vh + 511, 0, 0, 0, 0, 11, 111, vh + 111, vh + 311, false]);
+}
+
+function step1() {
+  root.scrollTop = 150;
+  runTestCycle(step2, "root.scrollTop = 150 with root scrolled into view.");
+  assert_equals(entries.length, 1, "No notifications after scrolling frame.");
+}
+
+function step2() {
+  document.scrollingElement.scrollTop = 0;
+  runTestCycle(step3, "document.scrollingElement.scrollTop = 0.");
+  checkLastEntry(entries, 1, [11, 111, 261, 361, 11, 111, 261, 311, 11, 111, 111, 311, true]);
+}
+
+function step3() {
+  root.scrollTop = 0;
+  runTestCycle(step4, "root.scrollTop = 0");
+  checkLastEntry(entries, 1);
+}
+
+function step4() {
+  root.scrollTop = 150;
+  runTestCycle(step5, "root.scrollTop = 150 with root scrolled out of view.");
+  checkLastEntry(entries, 2, [11, 111, vh + 411, vh + 511, 0, 0, 0, 0, 11, 111, vh + 111, vh + 311, false]);
+}
+
+// This tests that notifications are generated even when the root element is off screen.
+function step5() {
+  checkLastEntry(entries, 3, [11, 111, vh + 261, vh + 361, 11, 111, vh + 261, vh + 311, 11, 111, vh + 111, vh + 311, true]);
+}
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/same-document-zero-size-target.html b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/same-document-zero-size-target.html
new file mode 100644
index 0000000..d835b406
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/same-document-zero-size-target.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./resources/intersection-observer-test-utils.js"></script>
+
+<style>
+pre, #log {
+  position: absolute;
+  top: 0;
+  left: 200px;
+}
+.spacer {
+  height: calc(100vh + 100px);
+}
+#target {
+  width: 0px;
+  height: 0px;
+  background-color: green;
+}
+</style>
+
+<div class="spacer"></div>
+<div id="target"></div>
+<div class="spacer"></div>
+
+<script>
+var vw = document.documentElement.clientWidth;
+var vh = document.documentElement.clientHeight;
+
+var entries = [];
+var target;
+
+runTestCycle(function() {
+  target = document.getElementById("target");
+  assert_true(!!target, "Target exists");
+  var observer = new IntersectionObserver(function(changes) {
+    entries = entries.concat(changes)
+  });
+  observer.observe(target);
+  entries = entries.concat(observer.takeRecords());
+  assert_equals(entries.length, 0, "No initial notifications.");
+  runTestCycle(step0, "First rAF");
+}, "Observing a zero-area target.");
+
+function step0() {
+  document.scrollingElement.scrollTop = 300;
+  runTestCycle(step1, "document.scrollingElement.scrollTop = 300");
+  checkLastEntry(entries, 0, [8, 8, vh + 108, vh + 108, 0, 0, 0, 0, 0, vw, 0, vh, false]);
+}
+
+function step1() {
+  document.scrollingElement.scrollTop = 100;
+  runTestCycle(step2, "document.scrollingElement.scrollTop = 100");
+  checkLastEntry(entries, 1, [8, 8, vh - 192, vh - 192, 8, 8, vh - 192, vh - 192, 0, vw, 0, vh, true]);
+}
+
+function step2() {
+  document.scrollingElement.scrollTop = 0;
+  checkLastEntry(entries, 2, [8, 8, vh + 8, vh + 8, 0, 0, 0, 0, 0, vw, 0, vh, false]);
+}
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/shadow-content.html b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/shadow-content.html
new file mode 100644
index 0000000..a0a62420
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/shadow-content.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./resources/intersection-observer-test-utils.js"></script>
+
+<style>
+pre, #log {
+  position: absolute;
+  top: 0;
+  left: 200px;
+}
+</style>
+
+<div id="host"></div>
+
+<script>
+var vw = document.documentElement.clientWidth;
+var vh = document.documentElement.clientHeight;
+
+var entries = [];
+var target;
+
+runTestCycle(function() {
+  var shadowHost = document.getElementById("host");
+  assert_true(!!shadowHost, "Host exists");
+  var shadowRoot = shadowHost.createShadowRoot();
+  assert_true(!!shadowRoot, "Shadow root exists");
+  shadowRoot.innerHTML = "<div id='target' style='width: 100px; height: 100px; background-color: green;'></div>";
+  target = shadowRoot.getElementById("target");
+  assert_true(!!target, "target exists");
+
+  var observer = new IntersectionObserver(function(changes) {
+    entries = entries.concat(changes)
+  });
+  observer.observe(target);
+  entries = entries.concat(observer.takeRecords());
+  assert_equals(entries.length, 0, "No initial notifications.");
+  runTestCycle(step0, "First rAF after creating shadow DOM.");
+}, "Observing a target inside shadow DOM.");
+
+function step0() {
+  checkLastEntry(entries, 0, [8, 108, 8, 108, 8, 108, 8, 108, 0, vw, 0, vh, true]);
+}
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/timestamp.html b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/timestamp.html
new file mode 100644
index 0000000..00d787d2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/timestamp.html
@@ -0,0 +1,98 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./resources/intersection-observer-test-utils.js"></script>
+
+<style>
+pre, #log {
+  position: absolute;
+  top: 0;
+  left: 200px;
+}
+.spacer {
+  height: calc(100vh + 100px);
+}
+
+</style>
+<div id="leading-space" class="spacer"></div>
+<div id="trailing-space" class="spacer"></div>
+
+<script>
+// Pick this number to be comfortably greater than the length of two frames at 60Hz.
+var timeSkew = 40;
+
+var topWindowEntries = [];
+var iframeWindowEntries = [];
+var targetIframe;
+var topWindowTimeBeforeNotification;
+var iframeWindowTimeBeforeNotification;
+
+async_test(function(t) {
+  // assert_equals(window.innerWidth, 800, "Window must be 800 pixels wide.");
+  // assert_equals(window.innerHeight, 600, "Window must be 600 pixels high.");
+
+  t.step_timeout(function() {
+    targetIframe = document.createElement("iframe");
+    assert_true(!!targetIframe, "iframe exists");
+    targetIframe.src = "resources/timestamp-subframe.html";
+    var trailingSpace = document.getElementById("trailing-space");
+    assert_true(!!trailingSpace, "trailing-space exists");
+    trailingSpace.parentNode.insertBefore(targetIframe, trailingSpace);
+    targetIframe.onload = function() {
+      var target = targetIframe.contentDocument.getElementById("target");
+      var iframeScroller = targetIframe.contentDocument.scrollingElement;
+
+      // Observer created here, callback created in iframe context.  Timestamps should be
+      // from this window.
+      var observer = new IntersectionObserver(
+          targetIframe.contentDocument.createObserverCallback(topWindowEntries), {});
+      assert_true(!!observer, "Observer exists");
+      observer.observe(target);
+
+      // Callback created here, observer created in iframe.  Timestamps should be
+      // from iframe window.
+      observer = targetIframe.contentDocument.createObserver(function(newEntries) {
+        iframeWindowEntries = iframeWindowEntries.concat(newEntries);
+      });
+      observer.observe(target);
+      runTestCycle(step1, "First rAF after iframe is loaded.");
+      t.done();
+    };
+  }, timeSkew);
+}, "Check that timestamps correspond to the to execution context that created the observer.");
+
+function step1() {
+  document.scrollingElement.scrollTop = 200;
+  targetIframe.contentDocument.scrollingElement.scrollTop = 250;
+  topWindowTimeBeforeNotification = performance.now();
+  iframeWindowTimeBeforeNotification = targetIframe.contentWindow.performance.now();
+  runTestCycle(step2, "Generate notifications.");
+  assert_equals(topWindowEntries.length, 1, "One notification to top window observer.");
+  assert_equals(iframeWindowEntries.length, 1, "One notification to iframe observer.");
+}
+
+function step2() {
+  document.scrollingElement.scrollTop = 0;
+  var topWindowTimeAfterNotification = performance.now();
+  var iframeWindowTimeAfterNotification = targetIframe.contentWindow.performance.now();
+
+  // Test results are only significant if there's a gap between
+  // top window time and iframe window time.
+  assert_greater_than(topWindowTimeBeforeNotification, iframeWindowTimeAfterNotification,
+    "Time ranges for top and iframe windows are disjoint.");
+
+  assert_equals(topWindowEntries.length, 2, "Top window observer has two notifications.");
+  assert_between_inclusive(
+      topWindowEntries[1].time,
+      topWindowTimeBeforeNotification,
+      topWindowTimeAfterNotification,
+      "Notification to top window observer is within the expected range.");
+
+  assert_equals(iframeWindowEntries.length, 2, "Iframe observer has two notifications.");
+  assert_between_inclusive(
+      iframeWindowEntries[1].time,
+      iframeWindowTimeBeforeNotification,
+      iframeWindowTimeAfterNotification,
+      "Notification to iframe observer is within the expected range.");
+}
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/unclipped-root.html b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/unclipped-root.html
new file mode 100644
index 0000000..24ae01c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/unclipped-root.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./resources/intersection-observer-test-utils.js"></script>
+
+<style>
+pre, #log {
+  position: absolute;
+  top: 0;
+  left: 200px;
+}
+#root {
+  overflow: visible;
+  height: 200px;
+  width: 160px;
+  border: 7px solid black;
+}
+#target {
+  width: 100px;
+  height: 100px;
+  background-color: green;
+}
+</style>
+
+<div id="root">
+  <div id="target" style="transform: translateY(300px)"></div>
+</div>
+
+<script>
+var entries = [];
+var target;
+
+runTestCycle(function() {
+  target = document.getElementById("target");
+  assert_true(!!target, "target exists");
+  var root = document.getElementById("root");
+  assert_true(!!root, "root exists");
+  var observer = new IntersectionObserver(function(changes) {
+    entries = entries.concat(changes)
+  }, {root: root});
+  observer.observe(target);
+  entries = entries.concat(observer.takeRecords());
+  assert_equals(entries.length, 0, "No initial notifications.");
+  runTestCycle(step0, "First rAF.");
+}, "Test that border bounding box is used to calculate intersection with a non-scrolling root.");
+
+function step0() {
+  target.style.transform = "translateY(195px)";
+  runTestCycle(step1, "target.style.transform = 'translateY(195px)'");
+  checkLastEntry(entries, 0, [15, 115, 315, 415, 0, 0, 0, 0, 8, 182, 8, 222, false]);
+}
+
+function step1() {
+  target.style.transform = "";
+  checkLastEntry(entries, 1, [15, 115, 210, 310, 15, 115, 210, 222, 8, 182, 8, 222, true]);
+}
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/zero-area-element-hidden.html b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/zero-area-element-hidden.html
new file mode 100644
index 0000000..e007040
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/zero-area-element-hidden.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./resources/intersection-observer-test-utils.js"></script>
+
+<style>
+pre, #log {
+  position: absolute;
+  top: 0;
+  left: 200px;
+}
+#target {
+  width: 0px;
+  height: 0px;
+  position: fixed;
+  top: -1000px;
+}
+</style>
+
+<div id='target'></div>
+
+<script>
+var vw = document.documentElement.clientWidth;
+var vh = document.documentElement.clientHeight;
+
+var entries = [];
+
+runTestCycle(function() {
+  var target = document.getElementById('target');
+  assert_true(!!target, "target exists");
+  var observer = new IntersectionObserver(function(changes) {
+    entries = entries.concat(changes)
+  });
+  observer.observe(target);
+  entries = entries.concat(observer.takeRecords());
+  assert_equals(entries.length, 0, "No initial notifications.");
+  runTestCycle(step0, "First rAF.");
+}, "A zero-area hidden target should not be intersecting.");
+
+function step0() {
+  checkLastEntry(entries, 0, [8, 8, -1000, -1000, 0, 0, 0, 0, 0, vw, 0, vh, false]);
+}
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/zero-area-element-visible.html b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/zero-area-element-visible.html
new file mode 100644
index 0000000..6bf1297f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/zero-area-element-visible.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./resources/intersection-observer-test-utils.js"></script>
+
+<style>
+pre, #log {
+  position: absolute;
+  top: 0;
+  left: 200px;
+}
+#target {
+  width: 0px;
+  height: 0px;
+}
+</style>
+
+<div id='target'></div>
+
+<script>
+var entries = [];
+
+runTestCycle(function() {
+  var target = document.getElementById('target');
+  assert_true(!!target, "target exists");
+  var observer = new IntersectionObserver(function(changes) {
+    entries = entries.concat(changes)
+  });
+  observer.observe(target);
+  entries = entries.concat(observer.takeRecords());
+  assert_equals(entries.length, 0, "No initial notifications.");
+  runTestCycle(step0, "First rAF should generate a notification.");
+}, "Ensure that a zero-area target intersecting root generates a notification with intersectionRatio == 1");
+
+function step0() {
+  assert_equals(entries.length, 1, "One notification.");
+  assert_equals(entries[0].intersectionRatio, 1, "intersectionRatio == 1");
+}
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/media-source/mediasource-append-buffer-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/media-source/mediasource-append-buffer-expected.txt
new file mode 100644
index 0000000..11d4bd2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/media-source/mediasource-append-buffer-expected.txt
@@ -0,0 +1,26 @@
+This is a testharness.js-based test.
+Harness Error. harness_status.status = 1 , harness_status.message = Uncaught Error: assert_true: expected true got false
+PASS Test SourceBuffer.appendBuffer() event dispatching. 
+PASS Test SourceBuffer.appendBuffer() call during a pending appendBuffer(). 
+PASS Test SourceBuffer.abort() call during a pending appendBuffer(). 
+PASS Test SourceBuffer.appendBuffer() triggering an 'ended' to 'open' transition. 
+PASS Test zero byte SourceBuffer.appendBuffer() call triggering an 'ended' to 'open' transition. 
+PASS Test MediaSource.removeSourceBuffer() call during a pending appendBuffer(). 
+PASS Test set MediaSource.duration during a pending appendBuffer() for one of its SourceBuffers. 
+PASS Test MediaSource.endOfStream() during a pending appendBuffer() for one of its SourceBuffers. 
+PASS Test set SourceBuffer.timestampOffset during a pending appendBuffer(). 
+PASS Test appending an empty ArrayBufferView. 
+PASS Test appending a neutered ArrayBufferView. 
+PASS Test appending an empty ArrayBuffer. 
+PASS Test appending a neutered ArrayBuffer. 
+PASS Test appendBuffer with partial init segments. 
+PASS Test appendBuffer with partial media segments. 
+PASS Test appendBuffer events order. 
+PASS Test abort in the middle of an initialization segment. 
+PASS Test abort after removing sourcebuffer. 
+PASS Test abort after readyState is ended following init segment and media segment. 
+PASS Test abort after appendBuffer update ends. 
+PASS Test appending null. 
+PASS Test appending after removeSourceBuffer(). 
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/media-source/mediasource-append-buffer.html b/third_party/WebKit/LayoutTests/external/wpt/media-source/mediasource-append-buffer.html
index bca3f89..f1866c00 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/media-source/mediasource-append-buffer.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/media-source/mediasource-append-buffer.html
@@ -414,6 +414,58 @@
           mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
           {
               var initSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.init);
+              var mediaSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.media[0]);
+
+              assert_equals(mediaElement.readyState, mediaElement.HAVE_NOTHING);
+              assert_equals(mediaSource.duration, Number.NaN);
+
+              // readyState is changing as per the Initialization Segment Received algorithm.
+              var loadedmetadataCalled = false;
+              mediaElement.addEventListener("loadedmetadata", function metadata(e) {
+                 loadedmetadataCalled = true;
+                 e.target.removeEventListener(e.type, metadata);
+              });
+              sourceBuffer.addEventListener("updateend", function updateend(e) {
+                 assert_true(loadedmetadataCalled);
+                 assert_equals(mediaElement.readyState, mediaElement.HAVE_METADATA);
+                 e.target.removeEventListener(e.type, updateend);
+              });
+              test.expectEvent(sourceBuffer, "updateend", "remainingInitSegment append ended.");
+              test.expectEvent(mediaElement, "loadedmetadata", "loadedmetadata event received.");
+              sourceBuffer.appendBuffer(initSegment);
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_equals(mediaElement.readyState, mediaElement.HAVE_METADATA);
+                  assert_equals(mediaSource.duration, segmentInfo.duration);
+                  // readyState is changing as per the Coded Frame Processing algorithm.
+                  var loadeddataCalled = false;
+                  mediaElement.addEventListener("loadeddata", function loadeddata(e) {
+                      loadeddataCalled = true;
+                      e.target.removeEventListener(e.type, loadeddata);
+                  });
+                  sourceBuffer.addEventListener("updateend", function updateend(e) {
+                      assert_true(loadeddataCalled);
+                      assert_greater_than_equal(mediaElement.readyState, mediaElement.HAVE_CURRENT_DATA);
+                      e.target.removeEventListener(e.type, updateend);
+                  });
+                  test.expectEvent(sourceBuffer, "updateend", "mediaSegment append ended.");
+                  test.expectEvent(mediaElement, "loadeddata", "loadeddata fired.");
+                  sourceBuffer.appendBuffer(mediaSegment);
+              });
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_greater_than_equal(mediaElement.readyState, mediaElement.HAVE_CURRENT_DATA);
+                  assert_equals(sourceBuffer.updating, false);
+                  assert_equals(mediaSource.readyState, "open");
+                  test.done();
+              });
+          }, "Test appendBuffer events order.");
+
+          mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+          {
+              var initSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.init);
               var partialInitSegment = initSegment.subarray(0, initSegment.length / 2);
               var mediaSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.media[0]);
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/media-source/mediasource-seekable.html b/third_party/WebKit/LayoutTests/external/wpt/media-source/mediasource-seekable.html
index c379a63b..8e228d3 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/media-source/mediasource-seekable.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/media-source/mediasource-seekable.html
@@ -33,9 +33,12 @@
     {
         var initSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.init);
         test.expectEvent(mediaElement, 'durationchange', 'mediaElement got duration after initsegment');
+        test.expectEvent(sourceBuffer, 'update');
+        test.expectEvent(sourceBuffer, 'updateend');
         sourceBuffer.appendBuffer(initSegment);
         test.waitForExpectedEvents(function()
         {
+            assert_false(sourceBuffer.updating, "updating attribute is false");
             test.expectEvent(mediaElement, 'durationchange', 'mediaElement got infinity duration');
             mediaSource.duration = Infinity;
             test.waitForExpectedEvents(function()
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-constructor-crash.https.html b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-constructor-crash.https.html
index 8ca0a47..499fd95 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-constructor-crash.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-constructor-crash.https.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
+<meta name="timeout" content="long">
 <title>Crash tests PaymentRequest Constructor</title>
 <link rel="help" href="https://w3c.github.io/browser-payment-api/#constructor">
 <script src="/resources/testharness.js"></script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/resources/test/tests/add_cleanup_count.html b/third_party/WebKit/LayoutTests/external/wpt/resources/test/tests/add_cleanup_count.html
new file mode 100644
index 0000000..a079c9b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/resources/test/tests/add_cleanup_count.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<title>Test#add_cleanup reported count</title>
+<script src="../../testharness.js"></script>
+<script src="../../testharnessreport.js"></script>
+</head>
+<body>
+<div id="log"></div>
+
+<script>
+promise_test(function(t) {
+    t.add_cleanup(function() {});
+    t.add_cleanup(function() {});
+    t.add_cleanup(function() { throw new Error(); });
+    new EventWatcher(t, document.body, []);
+
+    return Promise.resolve();
+}, 'test with 3 user-defined cleanup functions');
+</script>
+<script type="text/json" id="expected">
+{
+  "summarized_status": {
+    "status_string": "ERROR",
+    "message": "Test named 'test with 3 user-defined cleanup functions' specified 3 'cleanup' functions, and 1 failed.",
+    "stack": null
+  },
+  "summarized_tests": [
+    {
+      "status_string": "PASS",
+      "name": "test with 3 user-defined cleanup functions",
+      "stack": null,
+      "message": null,
+      "properties": {}
+    }
+  ],
+  "type": "complete"
+}
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/resources/testharness.js b/third_party/WebKit/LayoutTests/external/wpt/resources/testharness.js
index 39aa686c..10287d31 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/resources/testharness.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/resources/testharness.js
@@ -528,7 +528,7 @@
         }
         tests.promise_tests = tests.promise_tests.then(function() {
             var donePromise = new Promise(function(resolve) {
-                test.add_cleanup(resolve);
+                test._add_cleanup(resolve);
             });
             var promise = test.step(func, test, test);
             test.step(function() {
@@ -618,7 +618,7 @@
             }
         };
 
-        test.add_cleanup(stop_watching);
+        test._add_cleanup(stop_watching);
 
         return this;
     }
@@ -1347,6 +1347,7 @@
         this.steps = [];
 
         this.cleanup_callbacks = [];
+        this._user_defined_cleanup_count = 0;
 
         tests.push(this);
     }
@@ -1471,10 +1472,27 @@
         }), timeout * tests.timeout_multiplier);
     }
 
-    Test.prototype.add_cleanup = function(callback) {
+    /*
+     * Private method for registering cleanup functions. `testharness.js`
+     * internals should use this method instead of the public `add_cleanup`
+     * method in order to hide implementation details from the harness status
+     * message in the case errors.
+     */
+    Test.prototype._add_cleanup = function(callback) {
         this.cleanup_callbacks.push(callback);
     };
 
+    /*
+     * Schedule a function to be run after the test result is known, regardless
+     * of passing or failing state. The behavior of this function will not
+     * influence the result of the test, but if an exception is thrown, the
+     * test harness will report an error.
+     */
+    Test.prototype.add_cleanup = function(callback) {
+        this._user_defined_cleanup_count += 1;
+        this._add_cleanup(callback);
+    };
+
     Test.prototype.force_timeout = function() {
         this.set_status(this.TIMEOUT);
         this.phase = this.phases.HAS_RESULT;
@@ -1545,7 +1563,7 @@
                 });
 
         if (error_count > 0) {
-            total = this.cleanup_callbacks.length;
+            total = this._user_defined_cleanup_count;
             tests.status.status = tests.status.ERROR;
             tests.status.message = "Test named '" + this.name +
                 "' specified " + total + " 'cleanup' function" +
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/bytecheck-worker-imported-script.py b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/bytecheck-worker-imported-script.py
new file mode 100644
index 0000000..e960220
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/bytecheck-worker-imported-script.py
@@ -0,0 +1,19 @@
+import time
+
+def main(request, response):
+    headers = [('Content-Type', 'application/javascript'),
+               ('Cache-Control', 'max-age=0')]
+
+    imported_content_type = ''
+    if 'imported' in request.GET:
+        imported_content_type = request.GET['imported']
+
+    imported_content = 'default'
+    if imported_content_type == 'time':
+        imported_content = time.time()
+
+    body = '''
+    // %s
+    ''' % (imported_content)
+
+    return headers, body
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/bytecheck-worker.py b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/bytecheck-worker.py
new file mode 100644
index 0000000..0b12de9f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/bytecheck-worker.py
@@ -0,0 +1,32 @@
+import time
+
+def main(request, response):
+    headers = [('Content-Type', 'application/javascript'),
+               ('Cache-Control', 'max-age=0')]
+
+    main_content_type = ''
+    if 'main' in request.GET:
+        main_content_type = request.GET['main']
+
+    main_content = 'default'
+    if main_content_type == 'time':
+        main_content = time.time()
+
+    imported_request_path = ''
+    if 'path' in request.GET:
+        imported_request_path = request.GET['path']
+
+    imported_request_type = ''
+    if 'imported' in request.GET:
+        imported_request_type = request.GET['imported']
+
+    imported_request = ''
+    if imported_request_type == 'time':
+        imported_request = '?imported=time';
+
+    body = '''
+    // %s
+    importScripts('%sbytecheck-worker-imported-script.py%s');
+    ''' % (main_content, imported_request_path, imported_request)
+
+    return headers, body
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/fetch-response-xhr-iframe.https.html b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/fetch-response-xhr-iframe.https.html
index 1414596..612c934 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/fetch-response-xhr-iframe.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/fetch-response-xhr-iframe.https.html
@@ -26,7 +26,7 @@
 
       return new Promise(function(resolve) {
           window.addEventListener('message', function handle(evt) {
-              if (event.data !== 'ACK') {
+              if (evt.data !== 'ACK') {
                 return;
               }
 
@@ -40,7 +40,7 @@
 window.addEventListener('message', function(evt) {
     var port;
 
-    if (event.data !== 'START') {
+    if (evt.data !== 'START') {
       return;
     }
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/update-bytecheck.https.html b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/update-bytecheck.https.html
new file mode 100644
index 0000000..6e4c6ec4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/update-bytecheck.https.html
@@ -0,0 +1,72 @@
+<!doctype html>
+<meta charset=utf-8>
+<title></title>
+<script src="/resources/testharness.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<script>
+
+/*
+ * @param bolean cors
+ *   Determine wether the imported script should be a cross origin script.
+ * @param string main
+ *   Decide the content of the main script, where 'default' is for constant
+ *   content while 'time' is for time-variant content.
+ * @param string imported
+ *   Decide the content of the imported script, where 'default' is for constant
+ *   content while 'time' is for time-variant content.
+ */
+const settings = [{cors: false, main: 'default', imported: 'default'},
+                  {cors: false, main: 'default', imported: 'time'   },
+                  {cors: false, main: 'time',    imported: 'default'},
+                  {cors: false, main: 'time',    imported: 'time'   },
+                  {cors: true,  main: 'default', imported: 'default'},
+                  {cors: true,  main: 'default', imported: 'time'   },
+                  {cors: true,  main: 'time',    imported: 'default'},
+                  {cors: true,  main: 'time',    imported: 'time'   }];
+
+settings.reduce((p, s) => {
+  return p.then(promise_test(function(t) {
+    var path = !s.cors ? ''
+                       : 'https://www1.web-platform.test:8443/' +
+                         'service-workers/service-worker/resources/';
+    var script = 'resources/bytecheck-worker.py' +
+                 '?main=' + s.main +
+                 '&imported=' + s.imported +
+                 '&path=' + path;
+    var scope = 'resources/blank.html';
+
+    var swr, sw;
+    return Promise.resolve()
+      // Register a service worker.
+      .then(_ => service_worker_unregister_and_register(t, script, scope))
+      .then(r => swr = r)
+      .then(_ => wait_for_update(t, swr))
+      .then(w => sw = w)
+      .then(_ => wait_for_state(t, sw, 'activated'))
+      .then(_ => assert_array_equals([swr.active,
+                                      swr.waiting,
+                                      swr.installing],
+                                     [sw, null, null]))
+
+      // Update the service worker registration.
+      .then(_ => swr.update())
+      .then(_ => {
+         // If there should be a new service worker.
+         if (s.main === 'time' || s.imported === 'time') {
+           return wait_for_update(t, swr);
+         }
+         // Otherwise, make sure there is no newly created service worker.
+         assert_array_equals([swr.active,
+                              swr.waiting,
+                              swr.installing],
+                             [sw, null, null]);
+      })
+
+      // Unregister the service worker.
+      .then(_ => service_worker_unregister_and_done(t, scope));
+  }, `Test(cors: ${s.cors}, main: ${s.main}, imported: ${s.imported})`));
+}, Promise.resolve());
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/property-list.js b/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/property-list.js
index acf8078..a367f9b 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/property-list.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/property-list.js
@@ -190,7 +190,7 @@
   'border-image-outset': {
     // https://drafts.csswg.org/css-backgrounds-3/#border-image-outset
     types: [
-      { type: 'discrete', options: [ [ '1 1 1 1', '5 5 5 5' ] ] }
+      { type: 'discrete', options: [ [ '1 2 3 4', '5 6 7 8' ] ] }
     ]
   },
   'border-image-repeat': {
@@ -202,7 +202,7 @@
   'border-image-slice': {
     // https://drafts.csswg.org/css-backgrounds-3/#border-image-slice
     types: [
-      { type: 'discrete', options: [ [ '1 1 1 1', '5 5 5 5' ] ] }
+      { type: 'discrete', options: [ [ '1 2 3 4', '5 6 7 8' ] ] }
     ]
   },
   'border-image-source': {
@@ -216,7 +216,7 @@
   'border-image-width': {
     // https://drafts.csswg.org/css-backgrounds-3/#border-image-width
     types: [
-      { type: 'discrete', options: [ [ '1 1 1 1', '5 5 5 5' ] ] }
+      { type: 'discrete', options: [ [ '1 2 3 4', '5 6 7 8' ] ] }
     ]
   },
   'border-left-color': {
@@ -471,8 +471,7 @@
   },
   'fill-opacity': {
     // https://svgwg.org/svg2-draft/painting.html#FillOpacityProperty
-    types: [
-    ]
+    types: [ 'opacity' ]
   },
   'fill-rule': {
     // https://svgwg.org/svg2-draft/painting.html#FillRuleProperty
@@ -517,8 +516,7 @@
   },
   'flood-opacity': {
     // https://drafts.fxtf.org/filters/#propdef-flood-opacity
-    types: [
-    ]
+    types: [ 'opacity' ]
   },
   'font-size': {
     // https://drafts.csswg.org/css-fonts-3/#propdef-font-size
@@ -532,8 +530,7 @@
   },
   'font-stretch': {
     // https://drafts.csswg.org/css-fonts-3/#propdef-font-stretch
-    types: [
-    ]
+    types: [ 'fontStretch' ]
   },
   'font-style': {
     // https://drafts.csswg.org/css-fonts/#propdef-font-style
@@ -1225,8 +1222,7 @@
   },
   'stop-opacity': {
     // https://svgwg.org/svg2-draft/pservers.html#StopOpacityProperty
-    types: [
-    ]
+    types: [ 'opacity' ]
   },
   'stroke': {
     // https://svgwg.org/svg2-draft/painting.html#StrokeProperty
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/property-types.js b/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/property-types.js
index 1fa1a2d..19569f3 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/property-types.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/property-types.js
@@ -1202,6 +1202,168 @@
 };
 
 const filterListType = {
+  testInterpolation: function(property, setup) {
+    test(function(t) {
+      var idlName = propertyToIDL(property);
+      var target = createTestElement(t, setup);
+      var animation = target.animate({ [idlName]:
+                                       ['blur(10px)', 'blur(50px)'] },
+                                      1000);
+
+      testAnimationSamples(animation, idlName,
+        [{ time: 500,    expected: 'blur(30px)' }]);
+    }, property + ': blur function' );
+
+    test(function(t) {
+      var idlName = propertyToIDL(property);
+      var target = createTestElement(t, setup);
+      var animation = target.animate({ [idlName]: ['hue-rotate(0deg)',
+                                                   'hue-rotate(100deg)'] },
+                                     1000);
+
+      testAnimationSamples(animation, idlName,
+        [{ time: 500,    expected: 'hue-rotate(50deg)' }]);
+    }, property + ': hue-rotate function with same unit(deg)' );
+
+    test(function(t) {
+      var idlName = propertyToIDL(property);
+      var target = createTestElement(t, setup);
+      var animation = target.animate({ [idlName]: ['hue-rotate(10deg)',
+                                                   'hue-rotate(100rad)'] },
+                                     1000);
+
+      // 10deg = 0.1745rad.
+      testAnimationSamples(animation, idlName,
+        [{ time: 500,    expected: 'hue-rotate(50.0873rad)' }]);
+    }, property + ': hue-rotate function with different unit(deg -> rad)');
+
+    test(function(t) {
+      var idlName = propertyToIDL(property);
+      var target = createTestElement(t, setup);
+      var animation = target.animate(
+        { [idlName]:
+          ['drop-shadow(10px 10px 10px rgba(255, 0, 0, 0.4))',
+           'drop-shadow(50px 50px 50px rgba(0, 0, 255, 0.8))'] },
+        1000);
+
+      testAnimationSamples(
+        animation, idlName,
+        [{ time: 500,
+            expected: 'drop-shadow(rgba(85, 0, 170, 0.6) 30px 30px 30px)' }]);
+    }, property + ': drop-shadow function' );
+
+    test(function(t) {
+      var idlName = propertyToIDL(property);
+      var target = createTestElement(t, setup);
+      var animation = target.animate(
+        { [idlName]:
+          ['brightness(0.1) contrast(0.1) grayscale(0.1) invert(0.1) ' +
+           'opacity(0.1) saturate(0.1) sepia(0.1)',
+           'brightness(0.5) contrast(0.5) grayscale(0.5) invert(0.5) ' +
+           'opacity(0.5) saturate(0.5) sepia(0.5)'] },
+        1000);
+
+      testAnimationSamples(animation, idlName,
+        [{ time: 500,
+           expected: 'brightness(0.3) contrast(0.3) grayscale(0.3) ' +
+           'invert(0.3) opacity(0.3) saturate(0.3) sepia(0.3)' }]);
+    }, property + ': percentage or numeric-specifiable functions' +
+       '(number value)');
+
+    test(function(t) {
+      var idlName = propertyToIDL(property);
+      var target = createTestElement(t, setup);
+      var animation = target.animate(
+        { [idlName]:
+          ['brightness(10%) contrast(10%) grayscale(10%) invert(10%) ' +
+           'opacity(10%) saturate(10%) sepia(10%)',
+           'brightness(50%) contrast(50%) grayscale(50%) invert(50%) ' +
+           'opacity(50%) saturate(50%) sepia(50%)'] },
+        1000);
+
+      testAnimationSamples(animation, idlName,
+        [{ time: 500,
+           expected: 'brightness(0.3) contrast(0.3) grayscale(0.3) ' +
+           'invert(0.3) opacity(0.3) saturate(0.3) sepia(0.3)' }]);
+    }, property + ': percentage or numeric-specifiable functions' +
+       '(percentage value)');
+
+    test(function(t) {
+      var idlName = propertyToIDL(property);
+      var target = createTestElement(t, setup);
+      var animation = target.animate(
+        { [idlName]:
+          // To make missing filter-function-lists, specified the grayscale.
+          ['grayscale(0)',
+           'grayscale(1) brightness(0) contrast(0) opacity(0) saturate(0)' ]},
+        1000);
+
+      testAnimationSamples(animation, idlName,
+        [{ time: 500,
+           expected: 'grayscale(0.5) brightness(0.5) contrast(0.5) ' +
+                     'opacity(0.5) saturate(0.5)' }]);
+    }, property + ': interpolate different length of filter-function-list ' +
+       ' with function which lacuna value is 1');
+
+    test(function(t) {
+      var idlName = propertyToIDL(property);
+      var target = createTestElement(t, setup);
+      var animation = target.animate(
+        { [idlName]:
+          // To make missing filter-function-lists, specified the opacity.
+          ['opoacity(1)',
+           'opacity(0) grayscale(1) invert(1) sepia(1) blur(10px)'] },
+        1000);
+
+      testAnimationSamples(animation, idlName,
+        [{ time: 500,
+           expected:
+           'opacity(0.5) grayscale(0.5) invert(0.5) sepia(0.5) blur(5px)' }]);
+    }, property + ': interpolate different length of filter-function-list ' +
+       ' with function which lacuna value is 0');
+
+    test(function(t) {
+      var idlName = propertyToIDL(property);
+      var target = createTestElement(t, setup);
+      target.style.color = "rgba(255, 0, 0, 0.4)";
+      var animation = target.animate(
+        { [idlName]:
+          ['blur(0px)',
+           'blur(10px) drop-shadow(10px 10px 10px rgba(0, 0, 255, 0.8))'] },
+        1000);
+
+      testAnimationSamples(animation, idlName,
+        [{ time: 500,
+           // The lacuna value of drop-shadow's color is taken from
+           // the color property.
+           expected: 'blur(5px) drop-shadow(rgba(85, 0, 170, 0.6) 5px 5px 5px' }]);
+    }, property + ': interpolate different length of filter-function-list ' +
+       'with drop-shadow function');
+
+    test(function(t) {
+      var idlName = propertyToIDL(property);
+      var target = createTestElement(t, setup);
+      var animation = target.animate({ [idlName]: ['none', 'blur(10px)'] },
+                                     1000);
+
+      testAnimationSamples(animation, idlName,
+        [{ time: 500, expected: 'blur(5px)' }]);
+    }, property + ': interpolate from none');
+
+    test(function(t) {
+      var idlName = propertyToIDL(property);
+      var target = createTestElement(t, setup);
+      var animation = target.animate(
+        { [idlName]:
+          ['blur(0px) url(\"#f1\")',
+           'blur(10px) url(\"#f2\")']},
+        1000);
+      testAnimationSamples(animation, idlName,
+        [{ time: 499, expected: 'blur(0px) url(\"#f1\")' },
+         { time: 500, expected: 'blur(10px) url(\"#f2\")' }]);
+    }, property + ': url function (interpoalte as discrete)');
+  },
+
   testAddition: function(property, setup) {
     test(function(t) {
       var idlName = propertyToIDL(property);
@@ -1610,6 +1772,53 @@
   },
 }
 
+const fontStretchType = {
+  testInterpolation: function(property, setup) {
+    test(function(t) {
+      var idlName = propertyToIDL(property);
+      var target = createTestElement(t, setup);
+      var animation =
+        target.animate({ [idlName]: ['ultra-condensed', 'extra-condensed'] },
+                       { duration: 1000, fill: 'both' });
+      testAnimationSamples(animation, idlName,
+                           [{ time: 499,  expected: 'ultra-condensed' },
+                            { time: 500,  expected: 'extra-condensed' }]);
+    }, property + ' supports animating as a font-stretch (adjacent values)');
+
+    test(function(t) {
+      var idlName = propertyToIDL(property);
+      var target = createTestElement(t, setup);
+      var animation =
+        target.animate({ [idlName]: ['ultra-condensed', 'condensed'] },
+                       { duration: 1000, fill: 'both' });
+      testAnimationSamples(animation, idlName,
+                           [{ time: 500,  expected: 'extra-condensed' }]);
+    }, property + ' supports animating as a font-stretch (between value)');
+  },
+
+  testAdditionOrAccumulation: function(property, setup, composite) {
+    test(function(t) {
+      var idlName = propertyToIDL(property);
+      var target = createTestElement(t, setup);
+      target.style[idlName] = 'condensed';
+      var animation =
+        target.animate({ [idlName]: ['expanded', 'ultra-expanded'] },
+                       { duration: 1000, composite: composite });
+      testAnimationSamples(animation, idlName,
+                           [{ time: 0, expected: 'normal' },
+                            { time: 250, expected: 'semi-expanded' }]);
+    }, property + ' uses font-stretch behavior for composite type ' + composite);
+  },
+
+  testAddition: function(property, setup) {
+    this.testAdditionOrAccumulation(property, setup, 'add');
+  },
+
+  testAccumulation: function(property, setup) {
+    this.testAdditionOrAccumulation(property, setup, 'accumulate');
+  },
+}
+
 const types = {
   color: colorType,
   discrete: discreteType,
@@ -1629,5 +1838,6 @@
   rect: rectType,
   position: positionType,
   dasharray: dasharrayType,
+  fontStretch: fontStretchType,
 };
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/spacing-keyframes-filters-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/spacing-keyframes-filters-expected.txt
deleted file mode 100644
index 8a1dfe2f..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/spacing-keyframes-filters-expected.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-This is a testharness.js-based test.
-FAIL Test spacing on blur anim.effect.getKeyframes is not a function
-FAIL Test spacing on brightness anim.effect.getKeyframes is not a function
-FAIL Test spacing on contrast anim.effect.getKeyframes is not a function
-FAIL Test spacing on drop-shadow anim.effect.getKeyframes is not a function
-FAIL Test getting zero distance when computing distance between color and no-color on drop-shadow anim.effect.getKeyframes is not a function
-FAIL Test spacing on grayscale anim.effect.getKeyframes is not a function
-FAIL Test spacing on hue-rotate anim.effect.getKeyframes is not a function
-FAIL Test spacing on invert anim.effect.getKeyframes is not a function
-FAIL Test spacing on opacity anim.effect.getKeyframes is not a function
-FAIL Test spacing on saturate anim.effect.getKeyframes is not a function
-FAIL Test spacing on sepia anim.effect.getKeyframes is not a function
-FAIL Test spacing on filter function lists with consistent sequence anim.effect.getKeyframes is not a function
-FAIL Test spacing on filter function lists with inconsistent sequence anim.effect.getKeyframes is not a function
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/spacing-keyframes-filters.html b/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/spacing-keyframes-filters.html
deleted file mode 100644
index ad930408..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/spacing-keyframes-filters.html
+++ /dev/null
@@ -1,210 +0,0 @@
-<!DOCTYPE html>
-<meta charset=utf-8>
-<title>Keyframe spacing tests on filters</title>
-<link rel="help" href="https://w3c.github.io/web-animations/#spacing-keyframes">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="../../testcommon.js"></script>
-<body>
-<div id="log"></div>
-<script>
-"use strict";
-
-// Help function for testing the computed offsets by the distance array.
-function assert_animation_offsets(anim, dist) {
-  const frames = anim.effect.getKeyframes();
-  const cumDist = dist.reduce( (prev, curr) => {
-    prev.push(prev.length == 0 ? curr : curr + prev[prev.length - 1]);
-    return prev;
-  }, []);
-
-  const total = cumDist[cumDist.length - 1];
-  for (var i = 0; i < frames.length; ++i) {
-    assert_equals(frames[i].computedOffset, cumDist[i] / total,
-                  'computedOffset of frame ' + i);
-  }
-}
-
-test(function(t) {
-  var anim =
-    createDiv(t).animate([ { filter: 'blur(1px)'},
-                           { filter: 'none' },  // The default value is 0px.
-                           { filter: 'blur(10px)' },
-                           { filter: 'blur(8px)' } ],
-                         { spacing: 'paced(filter)' });
-
-  var dist = [ 0, 1, 10, (10 - 8) ];
-  assert_animation_offsets(anim, dist);
-}, 'Test spacing on blur' );
-
-test(function(t) {
-  var anim =
-    createDiv(t).animate([ { filter: 'brightness(50%)'},
-                           { filter: 'none' },  // The default value is 1.
-                           { filter: 'brightness(2)' },
-                           { filter: 'brightness(175%)' } ],
-                         { spacing: 'paced(filter)' });
-
-  var dist = [ 0, (1 - 0.5), (2 - 1), (2.0 - 1.75) ];
-  assert_animation_offsets(anim, dist);
-}, 'Test spacing on brightness' );
-
-test(function(t) {
-  var anim =
-    createDiv(t).animate([ { filter: 'contrast(50%)'},
-                           { filter: 'none' },  // The default value is 1.
-                           { filter: 'contrast(2)' },
-                           { filter: 'contrast(175%)' } ],
-                         { spacing: 'paced(filter)' });
-
-  var dist = [ 0, (1 - 0.5), (2 - 1), (2.0 - 1.75) ];
-  assert_animation_offsets(anim, dist);
-}, 'Test spacing on contrast' );
-
-test(function(t) {
-  var anim =
-    createDiv(t).animate([ { filter: 'drop-shadow(10px 10px 10px blue)'},
-                           { filter: 'none' },
-                     // none filter: 'drop-shadow(0, 0, 0, rgba(0, 0, 0, 0))'
-                           { filter: 'drop-shadow(5px 5px 1px black)' },
-                           { filter: 'drop-shadow(20px 20px yellow)' } ],
-                         { spacing: 'paced(filter)' });
-
-  // Blue:   rgba(0, 0, 255, 1.0)   = rgba(  0%,   0%, 100%, 100%).
-  // Black:  rgba(0, 0, 0, 1.0)     = rgba(  0%,   0%,   0%, 100%).
-  // Yellow: rgba(255, 255, 0, 1.0) = rgba(100%, 100%,   0%, 100%).
-  var dist = [ 0,
-               Math.sqrt(10 * 10 + 10 * 10 + 10 * 10 + (1 * 1 + 1 * 1)),
-               Math.sqrt(5 * 5 + 5 * 5 + 1 * 1 + (1 * 1)),
-               Math.sqrt(15 * 15 + 15 * 15 + 1 * 1 + (1 * 1 + 1 * 1)) ];
-  assert_animation_offsets(anim, dist);
-}, 'Test spacing on drop-shadow' );
-
-test(function(t) {
-  var anim =
-    createDiv(t).animate([ { filter: 'drop-shadow(10px 10px 10px)'},
-                           { filter: 'drop-shadow(0 0)' },
-                           { filter: 'drop-shadow(5px 5px 1px black)' },
-                           { filter: 'drop-shadow(20px 20px yellow)' } ],
-                         { spacing: 'paced(filter)' });
-
-  // Black:  rgba(0, 0, 0, 1.0)     = rgba(  0%,   0%, 0%, 100%).
-  // Yellow: rgba(255, 255, 0, 1.0) = rgba(100%, 100%, 0%, 100%).
-  var dist = [ 0,
-               Math.sqrt(10 * 10 + 10 * 10 + 10 * 10),
-               0, // The distance is zero because the 2nd frame uses no-color.
-               Math.sqrt(15 * 15 + 15 * 15 + 1 * 1 + (1 * 1 + 1 * 1)) ];
-  assert_animation_offsets(anim, dist);
-}, 'Test getting zero distance when computing distance between ' +
-   'color and no-color on drop-shadow');
-
-test(function(t) {
-  var anim =
-    createDiv(t).animate([ { filter: 'grayscale(50%)'},
-                           { filter: 'none' },  // The default value is 0.
-                             // Values of grayscale over 100% are clamped to 1.
-                           { filter: 'grayscale(2)' },
-                           { filter: 'grayscale(75%)' } ],
-                         { spacing: 'paced(filter)' });
-
-  var dist = [ 0, 0.5, 1, (1.0 - 0.75) ];
-  assert_animation_offsets(anim, dist);
-}, 'Test spacing on grayscale' );
-
-test(function(t) {
-  var anim =
-    createDiv(t).animate([ { filter: 'hue-rotate(180deg)'},
-                           { filter: 'none' },  // The default value is 0deg.
-                           { filter: 'hue-rotate(720deg)' },
-                           { filter: 'hue-rotate(-180deg)' } ],
-                         { spacing: 'paced(filter)' });
-
-  var dist = [ 0, 180, 720, 720 + 180 ];
-  assert_animation_offsets(anim, dist);
-}, 'Test spacing on hue-rotate' );
-
-test(function(t) {
-  var anim =
-    createDiv(t).animate([ { filter: 'invert(50%)'},
-                           { filter: 'none' },  // The default value is 0.
-                             // Values of invert over 100% are clamped to 1.
-                           { filter: 'invert(2)' },
-                           { filter: 'invert(75%)' } ],
-                         { spacing: 'paced(filter)' });
-
-  var dist = [ 0, 0.5, 1, (1.0 - 0.75) ];
-  assert_animation_offsets(anim, dist);
-}, 'Test spacing on invert' );
-
-test(function(t) {
-  var anim =
-    createDiv(t).animate([ { filter: 'opacity(50%)'},
-                           { filter: 'none' },  // The default value is 1.
-                             // Values of opacity over 100% are clamped to 1.
-                           { filter: 'opacity(2)' },
-                           { filter: 'opacity(75%)' } ],
-                         { spacing: 'paced(filter)' });
-
-  var dist = [ 0, (1 - 0.5), (1 - 1), (1.0 - 0.75) ];
-  assert_animation_offsets(anim, dist);
-}, 'Test spacing on opacity' );
-
-test(function(t) {
-  var anim =
-    createDiv(t).animate([ { filter: 'saturate(50%)'},
-                           { filter: 'none' },  // The default value is 1.
-                           { filter: 'saturate(2)' },
-                           { filter: 'saturate(175%)' } ],
-                         { spacing: 'paced(filter)' });
-
-  var dist = [ 0, (1 - 0.5), (2 - 1), (2.0 - 1.75) ];
-  assert_animation_offsets(anim, dist);
-}, 'Test spacing on saturate' );
-
-test(function(t) {
-  var anim =
-    createDiv(t).animate([ { filter: 'sepia(50%)'},
-                           { filter: 'none' },  // The default value is 0.
-                             // Values of sepia over 100% are clamped to 1.
-                           { filter: 'sepia(2)' },
-                           { filter: 'sepia(75%)' } ],
-                         { spacing: 'paced(filter)' });
-
-  var dist = [ 0, 0.5, 1, (1.0 - 0.75) ];
-  assert_animation_offsets(anim, dist);
-}, 'Test spacing on sepia' );
-
-
-test(function(t) {
-  var anim =
-    createDiv(t).animate([ { filter: 'grayscale(50%) opacity(100%) blur(5px)' },
-                           { filter: 'none' },
-                     // none filter: 'grayscale(0) opacity(1) blur(0px)'
-                           { filter: 'grayscale(100%) opacity(50%) blur(1px)' },
-                           { filter: 'grayscale(75%) opacity(50%)' } ],
-                         { spacing: 'paced(filter)' });
-
-  var dist = [ 0,
-               Math.sqrt(0.5 * 0.5 + 5 * 5),
-               Math.sqrt(1 * 1 + 0.5 * 0.5 + 1 * 1),
-               Math.sqrt(0.25 * 0.25 + 1 * 1) ];
-  assert_animation_offsets(anim, dist);
-}, 'Test spacing on filter function lists with consistent sequence' );
-
-test(function(t) {
-  var anim =
-    createDiv(t).animate([ { filter: 'grayscale(50%) opacity(100%)' },
-                           { filter: 'opacity(10%) grayscale(50%)' },
-                           { filter: 'grayscale(100%) opacity(50%) blur(1px)' },
-                           { filter: 'grayscale(75%) opacity(50%)' } ],
-                         { spacing: 'paced(filter)' });
-
-  var dist = [ 0,
-               0,
-               0,
-               Math.sqrt(0.25 * 0.25 + 1 * 1) ];
-  assert_animation_offsets(anim, dist);
-}, 'Test spacing on filter function lists with inconsistent sequence' );
-
-</script>
-</body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/spacing-keyframes-shapes-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/spacing-keyframes-shapes-expected.txt
deleted file mode 100644
index df0714a..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/spacing-keyframes-shapes-expected.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-This is a testharness.js-based test.
-FAIL Test falling back to distribute spacing when using different basic shapes anim.effect.getKeyframes is not a function
-FAIL Test falling back to distribute spacing when using different reference boxes anim.effect.getKeyframes is not a function
-FAIL Test spacing on circle anim.effect.getKeyframes is not a function
-FAIL Test spacing on ellipse anim.effect.getKeyframes is not a function
-FAIL Test spacing on polygon anim.effect.getKeyframes is not a function
-FAIL Test spacing on inset anim.effect.getKeyframes is not a function
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/spacing-keyframes-shapes.html b/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/spacing-keyframes-shapes.html
deleted file mode 100644
index 9f7cfae..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/spacing-keyframes-shapes.html
+++ /dev/null
@@ -1,152 +0,0 @@
-<!DOCTYPE html>
-<meta charset=utf-8>
-<title>Keyframe spacing tests on shapes</title>
-<link rel="help" href="https://w3c.github.io/web-animations/#spacing-keyframes">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="../../testcommon.js"></script>
-<body>
-<div id="log"></div>
-<script>
-"use strict";
-
-// Help function for testing the computed offsets by the distance array.
-function assert_animation_offsets(anim, dist) {
-  const frames = anim.effect.getKeyframes();
-  const cumDist = dist.reduce( (prev, curr) => {
-    prev.push(prev.length == 0 ? curr : curr + prev[prev.length - 1]);
-    return prev;
-  }, []);
-
-  const total = cumDist[cumDist.length - 1];
-  for (var i = 0; i < frames.length; ++i) {
-    assert_equals(frames[i].computedOffset, cumDist[i] / total,
-                  'computedOffset of frame ' + i);
-  }
-}
-
-test(function(t) {
-  var anim =
-    createDiv(t).animate([ { clipPath: 'circle(20px)' },
-                           { clipPath: 'ellipse(10px 20px)' },
-                           { clipPath: 'polygon(50px 0px, 100px 50px, ' +
-                                       '        50px 100px, 0px 50px)' },
-                           { clipPath: 'inset(20px round 10px)' } ],
-                         { spacing: 'paced(clip-path)' });
-
-  const frames = anim.effect.getKeyframes();
-  const slots = frames.length - 1;
-  for (var i = 0; i < frames.length; ++i) {
-    assert_equals(frames[i].computedOffset, i / slots,
-                  'computedOffset of frame ' + i);
-  }
-}, 'Test falling back to distribute spacing when using different basic shapes');
-
-test(function(t) {
-  var anim =
-    createDiv(t).animate([ { clipPath: 'circle(10px)' },
-                           { clipPath: 'circle(20px) content-box' },
-                           { clipPath: 'circle(70px)' },
-                           { clipPath: 'circle(10px) padding-box' } ],
-                         { spacing: 'paced(clip-path)' });
-
-  const frames = anim.effect.getKeyframes();
-  const slots = frames.length - 1;
-  for (var i = 0; i < frames.length; ++i) {
-    assert_equals(frames[i].computedOffset, i / slots,
-                  'computedOffset of frame ' + i);
-  }
-}, 'Test falling back to distribute spacing when using different ' +
-   'reference boxes');
-
-test(function(t) {
-  // 1st: circle(calc(20px) at  calc(20px + 0%)  calc(10px + 0%))
-  // 2nd: circle(calc(50px) at  calc(10px + 0%)  calc(10px + 0%))
-  // 3rd: circle(70px at  calc(10px + 0%)  calc(50px + 0%))
-  // 4th: circle(10px at  calc(50px + 0%)  calc(30px + 0%))
-  var anim =
-    createDiv(t).animate([ { clipPath: 'circle(calc(10px + 10px) ' +
-                                       '       at 20px 10px)' },
-                           { clipPath: 'circle(calc(20px + 30px) ' +
-                                       '       at 10px 10px)' },
-                           { clipPath: 'circle(70px at 10px 50px)' },
-                           { clipPath: 'circle(10px at 50px 30px)' } ],
-                         { spacing: 'paced(clip-path)' });
-
-  var dist = [ 0,
-               Math.sqrt(30 * 30 + 10 * 10),
-               Math.sqrt(20 * 20 + 40 * 40),
-               Math.sqrt(60 * 60 + 40 * 40 + 20 * 20) ];
-  assert_animation_offsets(anim, dist);
-}, 'Test spacing on circle' );
-
-test(function(t) {
-  // 1st: ellipse(20px calc(20px) at  calc(0px + 50%)  calc(0px + 50%))
-  // 2nd: ellipse(20px calc(50px) at  calc(0px + 50%)  calc(0px + 50%))
-  // 3rd: ellipse(30px 70px at  calc(0px + 50%)  calc(0px + 50%))
-  // 4th: ellipse(30px 10px at  calc(0px + 50%)  calc(0px + 50%))
-  var anim =
-    createDiv(t).animate([ { clipPath: 'ellipse(20px calc(10px + 10px))' },
-                           { clipPath: 'ellipse(20px calc(20px + 30px))' },
-                           { clipPath: 'ellipse(30px 70px)' },
-                           { clipPath: 'ellipse(30px 10px)' } ],
-                         { spacing: 'paced(clip-path)' });
-
-  var dist = [ 0,
-               Math.sqrt(30 * 30),
-               Math.sqrt(10 * 10 + 20 * 20),
-               Math.sqrt(60 * 60) ];
-  assert_animation_offsets(anim, dist);
-}, 'Test spacing on ellipse' );
-
-test(function(t) {
-  // 1st: polygon(nonzero, 50px 0px, 100px 50px, 50px 100px, 0px 50px)
-  // 2nd: polygon(nonzero, 40px 0px, 100px 70px, 10px 100px, 0px 70px)
-  // 3rd: polygon(nonzero, 100px 0px, 100px 100px, 10px 80px, 0px 50px)
-  // 4th: polygon(nonzero, 100px 100px, -10px 100px, 20px 80px, 20px 50px)
-  var anim =
-    createDiv(t).animate([ { clipPath: 'polygon(50px 0px, 100px 50px, ' +
-                                       '        50px 100px, 0px 50px)' },
-                           { clipPath: 'polygon(40px 0px, 100px 70px, ' +
-                                       '        10px 100px, 0px 70px)' },
-                           { clipPath: 'polygon(100px 0px, 100px 100px, ' +
-                                       '        10px 80px, 0px 50px)' },
-                           { clipPath: 'polygon(100px 100px, -10px 100px, ' +
-                                       '        20px 80px, 20px 50px)' } ],
-                         { spacing: 'paced(clip-path)' });
-
-  var dist = [ 0,
-               Math.sqrt(10 * 10 + 20 * 20 + 40 * 40 + 20 * 20),
-               Math.sqrt(60 * 60 + 30 * 30 + 20 * 20 + 20 * 20),
-               Math.sqrt(100 * 100 + 110 * 110 + 10 * 10 + 20 * 20) ];
-  assert_animation_offsets(anim, dist);
-}, 'Test spacing on polygon' );
-
-test(function(t) {
-  // Note: Rounding corners are 4 CSS pair values and
-  //       each pair has x & y components.
-  // 1st: inset(5px 5px 5px 5px round 40px 30px 20px 5px / 40px 30px 20px 5px)
-  // 2nd: inset(10px 5px 10px 5px round 50px 60px / 50px 60px)
-  // 3rd: inset(40px 40px 40px 40px round 10px / 10px)
-  // 4th: inset(30px 40px 30px 40px round 20px / 20px)
-  var anim =
-    createDiv(t).animate([ { clipPath: 'inset(5px 5px 5px 5px ' +
-                                       '      round 40px 30px 20px 5px)' },
-                           { clipPath: 'inset(10px 5px round 50px 60px)' },
-                           { clipPath: 'inset(40px 40px round 10px)' },
-                           { clipPath: 'inset(30px 40px round 20px)' } ],
-                         { spacing: 'paced(clip-path)' });
-
-  var dist = [ 0,
-               Math.sqrt(5 * 5 * 2 + (50 - 40) * (50 - 40) * 2 +
-                                     (60 - 30) * (60 - 30) * 2 +
-                                     (50 - 20) * (50 - 20) * 2 +
-                                     (60 - 5) * (60 - 5) * 2),
-               Math.sqrt(30 * 30 * 2 + 35 * 35 * 2 + (50 - 10) * (50 - 10) * 4 +
-                                                     (60 - 10) * (60 - 10) * 4),
-               Math.sqrt(10 * 10 * 2 + (20 - 10) * (20 - 10) * 8) ];
-  assert_animation_offsets(anim, dist);
-}, 'Test spacing on inset' );
-
-</script>
-</body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/spacing-keyframes-transform-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/spacing-keyframes-transform-expected.txt
deleted file mode 100644
index c61ebd4..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/spacing-keyframes-transform-expected.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-This is a testharness.js-based test.
-FAIL Test spacing on translate anim.effect.getKeyframes is not a function
-FAIL Test spacing on translate3d anim.effect.getKeyframes is not a function
-FAIL Test spacing on scale anim.effect.getKeyframes is not a function
-FAIL Test spacing on scale3d anim.effect.getKeyframes is not a function
-FAIL Test spacing on rotate anim.effect.getKeyframes is not a function
-FAIL Test spacing on rotate3d anim.effect.getKeyframes is not a function
-FAIL Test spacing on skew anim.effect.getKeyframes is not a function
-FAIL Test spacing on skew along both X and Y anim.effect.getKeyframes is not a function
-FAIL Test spacing on perspective anim.effect.getKeyframes is not a function
-FAIL Test spacing on matched transform lists anim.effect.getKeyframes is not a function
-FAIL Test spacing on matrix anim.effect.getKeyframes is not a function
-FAIL Test spacing on matrix3d anim.effect.getKeyframes is not a function
-FAIL Test spacing on mismatched transform list anim.effect.getKeyframes is not a function
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/spacing-keyframes-transform.html b/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/spacing-keyframes-transform.html
deleted file mode 100644
index 189a25e..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/spacing-keyframes-transform.html
+++ /dev/null
@@ -1,242 +0,0 @@
-<!DOCTYPE html>
-<meta charset=utf-8>
-<title>Keyframe spacing tests on transform</title>
-<link rel="help" href="https://w3c.github.io/web-animations/#spacing-keyframes">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="../../testcommon.js"></script>
-<body>
-<div id="log"></div>
-<script>
-"use strict";
-
-const pi  = Math.PI;
-const cos = Math.cos;
-const sin = Math.sin;
-const tan = Math.tan;
-const sqrt = Math.sqrt;
-
-// Help function for testing the computed offsets by the distance array.
-function assert_animation_offsets(anim, dist) {
-  const epsilon = 0.00000001;
-  const frames = anim.effect.getKeyframes();
-  const cumDist = dist.reduce( (prev, curr) => {
-    prev.push(prev.length == 0 ? curr : curr + prev[prev.length - 1]);
-    return prev;
-  }, []);
-
-  const total = cumDist[cumDist.length - 1];
-  for (var i = 0; i < frames.length; ++i) {
-    assert_approx_equals(frames[i].computedOffset, cumDist[i] / total,
-                         epsilon, 'computedOffset of frame ' + i);
-  }
-}
-
-function getAngleDist(rotate1, rotate2) {
-  function quaternion(axis, angle) {
-    var x = axis[0] * sin(angle/2.0);
-    var y = axis[1] * sin(angle/2.0);
-    var z = axis[2] * sin(angle/2.0);
-    var w = cos(angle/2.0);
-    return { 'x': x, 'y': y, 'z': z, 'w': w };
-  }
-  var q1 = quaternion(rotate1.axis, rotate1.angle);
-  var q2 = quaternion(rotate2.axis, rotate2.angle);
-  var dotProduct = q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w;
-  return 2.0 * Math.acos(dotProduct);
-}
-
-function createMatrix(elements, Is3D) {
-  return (Is3D ? "matrix3d" : "matrix") + "(" + elements.join() + ")";
-}
-
-test(function(t) {
-  var anim = createDiv(t).animate([ { transform: "none" },
-                                    { transform: "translate(-20px)" },
-                                    { transform: "translate(100px)" },
-                                    { transform: "translate(50px)"} ],
-                                  { spacing: "paced(transform)" });
-  assert_animation_offsets(anim, [ 0, 20, 120, 50 ]);
-}, 'Test spacing on translate' );
-
-test(function(t) {
-  var anim =
-    createDiv(t).animate([ { transform: "none" },
-                           { transform: "translate3d(-20px, 10px, 100px)" },
-                           { transform: "translate3d(100px, 200px, 50px)" },
-                           { transform: "translate(50px, -10px)"} ],
-                         { spacing: "paced(transform)" });
-  var dist = [ 0,
-               sqrt(20 * 20 + 10 * 10 + 100 * 100),
-               sqrt(120 * 120 + 190 * 190 + 50 * 50),
-               sqrt(50 * 50 + 210 * 210 + 50 * 50) ];
-  assert_animation_offsets(anim, dist);
-}, 'Test spacing on translate3d' );
-
-test(function(t) {
-  var anim = createDiv(t).animate([ { transform: "scale(0.5)" },
-                                    { transform: "scale(4.5)" },
-                                    { transform: "scale(2.5)" },
-                                    { transform: "none"} ],
-                                  { spacing: "paced(transform)" });
-  assert_animation_offsets(anim, [ 0, 4.0, 2.0, 1.5 ]);
-}, 'Test spacing on scale' );
-
-test(function(t) {
-  var anim = createDiv(t).animate([ { transform: "scale(0.5, 0.5)" },
-                                    { transform: "scale3d(4.5, 5.0, 2.5)" },
-                                    { transform: "scale3d(2.5, 1.0, 2.0)" },
-                                    { transform: "scale3d(1, 0.5, 1.0)"} ],
-                                  { spacing:"paced(transform)" });
-  var dist = [ 0,
-               sqrt(4.0 * 4.0 + 4.5 * 4.5 + 1.5 * 1.5),
-               sqrt(2.0 * 2.0 + 4.0 * 4.0 + 0.5 * 0.5),
-               sqrt(1.5 * 1.5 + 0.5 * 0.5 + 1.0 * 1.0) ];
-  assert_animation_offsets(anim, dist);
-}, 'Test spacing on scale3d' );
-
-test(function(t) {
-  var anim = createDiv(t).animate([ { transform: "rotate(60deg)" },
-                                    { transform: "none" },
-                                    { transform: "rotate(720deg)" },
-                                    { transform: "rotate(-360deg)"} ],
-                                  { spacing: "paced(transform)" });
-  assert_animation_offsets(anim, [ 0, 60, 720, 1080 ]);
-}, 'Test spacing on rotate' );
-
-test(function(t) {
-  var anim = createDiv(t).animate([ { transform: "rotate3d(1,0,0,60deg)" },
-                                    { transform: "rotate3d(1,0,0,70deg)" },
-                                    { transform: "rotate3d(0,0,1,-110deg)" },
-                                    { transform: "rotate3d(1,0,0,219deg)"} ],
-                                  { spacing: "paced(transform)" });
-  var dist = [ 0,
-               getAngleDist({ axis: [1,0,0], angle: 60 * pi / 180 },
-                            { axis: [1,0,0], angle: 70 * pi / 180 }),
-               getAngleDist({ axis: [0,1,0], angle: 70 * pi / 180 },
-                            { axis: [0,0,1], angle: -110 * pi / 180 }),
-               getAngleDist({ axis: [0,0,1], angle: -110 * pi / 180 },
-                            { axis: [1,0,0], angle: 219 * pi / 180 }) ];
-  assert_animation_offsets(anim, dist);
-}, 'Test spacing on rotate3d' );
-
-test(function(t) {
-  var anim = createDiv(t).animate([ { transform: "skew(60deg)" },
-                                    { transform: "none" },
-                                    { transform: "skew(-90deg)" },
-                                    { transform: "skew(90deg)"} ],
-                                  { spacing: "paced(transform)" });
-  assert_animation_offsets(anim, [ 0, 60, 90, 180 ]);
-}, 'Test spacing on skew' );
-
-test(function(t) {
-  var anim = createDiv(t).animate([ { transform: "skew(60deg, 30deg)" },
-                                    { transform: "none" },
-                                    { transform: "skew(-90deg, 60deg)" },
-                                    { transform: "skew(90deg, 60deg)"} ],
-                                  { spacing: "paced(transform)" });
-  var dist = [ 0,
-               sqrt(60 * 60 + 30 * 30),
-               sqrt(90 * 90 + 60 * 60),
-               sqrt(180 * 180 + 0) ];
-  assert_animation_offsets(anim, dist);
-}, 'Test spacing on skew along both X and Y' );
-
-test(function(t) {
-  // We calculate the distance of two perspective functions by converting them
-  // into two matrix3ds, and then do matrix decomposition to get two
-  // perspective vectors, so the equivalent perspective vectors are:
-  // perspective 1: (0, 0, -1/128, 1);
-  // perspective 2: (0, 0, -1/infinity = 0, 1);
-  // perspective 3: (0, 0, -1/1024, 1);
-  // perspective 4: (0, 0, -1/32, 1);
-  var anim = createDiv(t).animate([ { transform: "perspective(128px)" },
-                                    { transform: "none" },
-                                    { transform: "perspective(1024px)" },
-                                    { transform: "perspective(32px)"} ],
-                                  { spacing: "paced(transform)" });
-  assert_animation_offsets(anim, [ 0, 1/128, 1/1024, 1/32 - 1/1024 ]);
-}, 'Test spacing on perspective' );
-
-test(function(t) {
-  var anim =
-    createDiv(t).animate([ { transform: "none" },
-                           { transform: "rotate(180deg) translate(0px)" },
-                           { transform: "rotate(180deg) translate(1000px)" },
-                           { transform: "rotate(360deg) translate(1000px)"} ],
-                         { spacing: "paced(transform)" });
-  var dist = [ 0,
-               sqrt(pi * pi + 0),
-               sqrt(1000 * 1000),
-               sqrt(pi * pi + 0) ];
-  assert_animation_offsets(anim, dist);
-}, 'Test spacing on matched transform lists' );
-
-test(function(t) {
-  // matrix1 => translate(100px, 50px), skewX(60deg).
-  // matrix2 => translate(1000px), rotate(180deg).
-  // matrix3 => translate(1000px), scale(1.5, 0.7).
-  const matrix1 = createMatrix([ 1, 0, tan(pi/4.0), 1, 100, 50 ]);
-  const matrix2 = createMatrix([ cos(pi), sin(pi),
-                                -sin(pi), cos(pi),
-                                 1000, 0 ]);
-  const matrix3 = createMatrix([ 1.5, 0, 0, 0.7, 1000, 0 ]);
-  var anim = createDiv(t).animate([ { transform: "none" },
-                                    { transform: matrix1 },
-                                    { transform: matrix2 },
-                                    { transform: matrix3 } ],
-                                  { spacing: "paced(transform)" });
-  var dist = [ 0,
-               sqrt(100 * 100 + 50 * 50 + pi/4 * pi/4),
-               sqrt(900 * 900 + 50 * 50 + pi * pi + pi/4 * pi/4),
-               sqrt(pi * pi + 0.5 * 0.5 + 0.3 * 0.3) ];
-  assert_animation_offsets(anim, dist);
-}, 'Test spacing on matrix' );
-
-test(function(t) {
-  // matrix1 => translate3d(100px, 50px, -10px), skew(60deg).
-  // matrix2 => translate3d(1000px, 0, 0), rotate3d(1, 0, 0, 180deg).
-  // matrix3 => translate3d(1000px, 0, 0), scale3d(1.5, 0.7, 2.2).
-  const matrix1 = createMatrix([ 1, 0, 0, 0,
-                                 tan(pi/4.0), 1, 0, 0,
-                                 0, 0, 1, 0,
-                                 100, 50, -10, 1 ], true);
-  const matrix2 = createMatrix([ 1, 0, 0, 0,
-                                 0, cos(pi), sin(pi), 0,
-                                 0, -sin(pi), cos(pi), 0,
-                                 1000, 0, 0, 1 ], true);
-  const matrix3 = createMatrix([ 1.5, 0, 0, 0,
-                                 0, 0.7, 0, 0,
-                                 0, 0, 2.2, 0,
-                                 1000, 0, 0, 1 ], true);
-  var anim = createDiv(t).animate([ { transform: "none" },
-                                    { transform: matrix1 },
-                                    { transform: matrix2 },
-                                    { transform: matrix3 } ],
-                                  { spacing: "paced(transform)" });
-  var dist = [ 0,
-               sqrt(100 * 100 + 50 * 50 + 10 * 10 + pi/4 * pi/4),
-               sqrt(900 * 900 + 50 * 50 + 10 * 10 + pi/4 * pi/4 + pi * pi),
-               sqrt(0.5 * 0.5 + 0.3 * 0.3 + 1.2 * 1.2 + pi * pi) ];
-  assert_animation_offsets(anim, dist);
-}, 'Test spacing on matrix3d' );
-
-test(function(t) {
-  var anim =
-    createDiv(t).animate([ { transform: "none" },
-                           { transform: "translate(100px, 50px) skew(45deg)" },
-                           { transform: "translate(1000px) " +
-                                        "rotate3d(1, 0, 0, 180deg)" },
-                           { transform: "translate(1000px) " +
-                                        "scale3d(2.5, 0.5, 0.7)" } ],
-                         { spacing: "paced(transform)" });
-
-  var dist = [ 0,
-               sqrt(100 * 100 + 50 * 50 + pi/4 * pi/4),
-               sqrt(900 * 900 + 50 * 50 + pi/4 * pi/4 + pi * pi),
-               sqrt(1.5 * 1.5 + 0.5 * 0.5 + 0.3 * 0.3 + pi * pi) ];
-  assert_animation_offsets(anim, dist);
-}, 'Test spacing on mismatched transform list' );
-
-</script>
-</body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/keyframe-effects/spacing-keyframes-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/keyframe-effects/spacing-keyframes-expected.txt
deleted file mode 100644
index 0ce7f3e3..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/keyframe-effects/spacing-keyframes-expected.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-This is a testharness.js-based test.
-FAIL Test distribute spacing anim.effect.getKeyframes is not a function
-FAIL Test distribute spacing with specific offsets anim.effect.getKeyframes is not a function
-FAIL Test paced spacing without any keyframe anim.effect.getKeyframes is not a function
-FAIL Test paced spacing anim.effect.getKeyframes is not a function
-FAIL Test paced spacing with specific offsets anim.effect.getKeyframes is not a function
-FAIL Test paced spacing if some paced property values are equal anim.effect.getKeyframes is not a function
-FAIL Test falling back to distribute spacing if all paced property value are equal anim.effect.getKeyframes is not a function
-FAIL Test paced spacing if there a keyframe without the paced property anim.effect.getKeyframes is not a function
-FAIL Test paced spacing if a paced property that appears on only some keyframes anim.effect.getKeyframes is not a function
-FAIL Test paced spacing if a paced property that appears on only some keyframes and there is a specific offset anim.effect.getKeyframes is not a function
-FAIL Test paced spacing where there are some keyframes without offsets and without the paced property before the first paceable keyframe and after the last paceable keyframe anim.effect.getKeyframes is not a function
-FAIL Test paced spacing for using shorthand property anim.effect.getKeyframes is not a function
-FAIL Test paced spacing using shorthand property where only the longhand components are specified anim.effect.getKeyframes is not a function
-FAIL Test falling back to distribute spacing if all keyframe miss some components anim.effect.getKeyframes is not a function
-FAIL Test paced spacing only for keyframes specifying all longhand components, and falling back to distribute spacing for the reset anim.effect.getKeyframes is not a function
-FAIL Test paced spacing only for keyframes specifying all some components, and falling back to distribute spacing for the reset with some specific offsets anim.effect.getKeyframes is not a function
-FAIL Test paced spacing by setter anim.effect.getKeyframes is not a function
-FAIL Test distribute spacing by setter anim.effect.getKeyframes is not a function
-FAIL Test paced spacing by changing the paced property anim.effect.getKeyframes is not a function
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/keyframe-effects/spacing-keyframes.html b/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/keyframe-effects/spacing-keyframes.html
deleted file mode 100644
index 90e26d27..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/keyframe-effects/spacing-keyframes.html
+++ /dev/null
@@ -1,391 +0,0 @@
-<!DOCTYPE html>
-<meta charset=utf-8>
-<title>Keyframe spacing tests</title>
-<link rel="help" href="https://w3c.github.io/web-animations/#spacing-keyframes">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="../../testcommon.js"></script>
-<body>
-<div id="log"></div>
-<script>
-"use strict";
-
-test(function(t) {
-  var anim = createDiv(t).animate([ { marginLeft: '0px' },
-                                    { marginLeft: '-20px' },
-                                    { marginLeft: '100px' },
-                                    { marginLeft: '50px' } ],
-                                  { duration: 100 * MS_PER_SEC });
-
-  var frames = anim.effect.getKeyframes();
-  var slots = frames.length - 1;
-  assert_equals(frames[0].computedOffset, 0.0, '1st frame offset');
-  assert_equals(frames[1].computedOffset, 1.0 / slots, '2nd frame offset');
-  assert_equals(frames[2].computedOffset, 2.0 / slots, '3rd frame offset');
-  assert_equals(frames[3].computedOffset, 1.0, 'last frame offset');
-}, 'Test distribute spacing');
-
-test(function(t) {
-  var anim = createDiv(t).animate([ { marginLeft: '0px' },
-                                    { marginLeft: '-20px' },
-                                    { marginLeft: '100px', offset: 0.5 },
-                                    { marginLeft: '50px' } ],
-                                  { duration: 100 * MS_PER_SEC,
-                                    spacing: 'distribute' });
-
-  var frames = anim.effect.getKeyframes();
-  assert_equals(frames[0].computedOffset, 0.0, '1st frame offset');
-  assert_equals(frames[1].computedOffset, 0.5 * 1 / 2, '2nd frame offset');
-  assert_equals(frames[2].computedOffset, 0.5, '3rd frame offset');
-  assert_equals(frames[3].computedOffset, 1.0, 'last frame offset');
-}, 'Test distribute spacing with specific offsets');
-
-test(function(t) {
-  var anim = createDiv(t).animate(null,
-                                  { duration: 100 * MS_PER_SEC,
-                                    spacing: 'paced(margin-left)' });
-
-  var frames = anim.effect.getKeyframes();
-  assert_equals(frames.length, 0, "empty keyframe list");
-}, 'Test paced spacing without any keyframe');
-
-
-test(function(t) {
-  var anim = createDiv(t).animate([ { marginLeft: '0px' },
-                                    { marginLeft: '-20px' },
-                                    { marginLeft: '100px' },
-                                    { marginLeft: '50px' } ],
-                                  { duration: 100 * MS_PER_SEC,
-                                    spacing: 'paced(margin-left)' });
-
-  var frames = anim.effect.getKeyframes();
-  var cumDist = [0, 20, 140, 190];
-  assert_equals(frames[0].computedOffset, 0.0,
-                '1st frame offset');
-  assert_equals(frames[1].computedOffset, cumDist[1] / cumDist[3],
-                '2nd frame offset');
-  assert_equals(frames[2].computedOffset, cumDist[2] / cumDist[3],
-                '3rd frame offset');
-  assert_equals(frames[3].computedOffset, 1.0,
-                'last frame offset');
-}, 'Test paced spacing');
-
-test(function(t) {
-  var anim = createDiv(t).animate([ { marginLeft: '0px' },
-                                    { marginLeft: '-20px' },
-                                    { marginLeft: '100px', offset: 0.5 },
-                                    { marginLeft: '120px' },
-                                    { marginLeft: '50px' } ],
-                                  { duration: 100 * MS_PER_SEC,
-                                    spacing: 'paced(margin-left)' });
-
-  var frames = anim.effect.getKeyframes();
-  var cumDist1 = [ 0, 20, 140 ];
-  var cumDist2 = [ 0, 20, 90 ];
-  assert_equals(frames[1].computedOffset, 0.5 * cumDist1[1] / cumDist1[2],
-                '2nd frame offset');
-  assert_equals(frames[2].computedOffset, 0.5,
-                '3rd frame offset');
-  assert_equals(frames[3].computedOffset, 0.5 + 0.5 * cumDist2[1] / cumDist2[2],
-                '4th frame offset');
-}, 'Test paced spacing with specific offsets');
-
-test(function(t) {
-  var anim = createDiv(t).animate([ { marginLeft: '0px' },
-                                    { marginLeft: '0px' },
-                                    { marginLeft: '100px' },
-                                    { marginLeft: '50px' } ],
-                                  { duration: 100 * MS_PER_SEC,
-                                    spacing: 'paced(margin-left)' });
-
-  var frames = anim.effect.getKeyframes();
-  var cumDist = [0, 0, 100, 150];
-  assert_equals(frames[1].computedOffset, cumDist[1] / cumDist[3],
-                '2nd frame offset');
-  assert_equals(frames[2].computedOffset, cumDist[2] / cumDist[3],
-                '3rd frame offset');
-}, 'Test paced spacing if some paced property values are equal');
-
-test(function(t) {
-  var anim = createDiv(t).animate([ { marginLeft: '0px' },
-                                    { marginLeft: '0px' },
-                                    { marginLeft: '0px' },
-                                    { marginLeft: '0px' } ],
-                                  { duration: 100 * MS_PER_SEC,
-                                    spacing: 'paced(margin-left)' });
-
-  var frames = anim.effect.getKeyframes();
-  var slots = frames.length - 1;
-  assert_equals(frames[1].computedOffset, 1.0 / slots, '2nd frame offset');
-  assert_equals(frames[2].computedOffset, 2.0 / slots, '3rd frame offset');
-}, 'Test falling back to distribute spacing if all paced property value ' +
-   'are equal');
-
-test(function(t) {
-  var anim = createDiv(t).animate([ { margin: '0px' },
-                                    { marginTop: '-20px' },
-                                    { marginLeft: '100px' },
-                                    { margin: '50px' } ],
-                                  { duration: 100 * MS_PER_SEC,
-                                    spacing: 'paced(margin-left)' });
-
-  var frames = anim.effect.getKeyframes();
-  assert_equals(frames[1].computedOffset, frames[2].computedOffset * 1 / 2,
-                '2nd frame offset using distribute spacing');
-  assert_equals(frames[2].computedOffset, 100 / 150,
-                '3rd frame offset using paced spacing');
-}, 'Test paced spacing if there a keyframe without the paced property');
-
-test(function(t) {
-  var anim = createDiv(t).animate([ { margin: '0px' },
-                                    { marginTop: '40px' },
-                                    { marginTop: '-20px' },
-                                    { marginLeft: '40px' },
-                                    { marginTop: '60px' },
-                                    { margin: '10px' } ],
-                                  { duration: 100 * MS_PER_SEC,
-                                    spacing: 'paced(margin-left)' });
-
-  var frames = anim.effect.getKeyframes();
-  var cumDist = [0, 0, 0, 40, 40, 70];
-  assert_equals(frames[1].computedOffset, frames[3].computedOffset * 1 / 3,
-                '2nd frame offset using distribute spacing');
-  assert_equals(frames[2].computedOffset, frames[3].computedOffset * 2 / 3,
-                '3rd frame offset using distribute spacing');
-  assert_equals(frames[3].computedOffset, cumDist[3] / cumDist[5],
-                '4th frame offset using paced spacing');
-  assert_equals(frames[4].computedOffset,
-                frames[3].computedOffset +
-                  (1 - frames[3].computedOffset) * 1 / 2,
-                '5th frame offset using distribute spacing');
-}, 'Test paced spacing if a paced property that appears on only some ' +
-   'keyframes');
-
-test(function(t) {
-  var anim = createDiv(t).animate([ { margin: '0px' },
-                                    { marginTop: '-20px', offset: 0.5 },
-                                    { marginLeft: '40px' },
-                                    { marginLeft: '100px' },
-                                    { margin: '50px' } ],
-                                  { duration: 100 * MS_PER_SEC,
-                                    spacing: 'paced(margin-left)' });
-
-  var frames = anim.effect.getKeyframes();
-  assert_equals(frames[2].computedOffset, 0.5 + 0.5 * 1 / 3,
-                '3rd frame offset using distribute spacing because it is the ' +
-                'first paceable keyframe');
-  assert_equals(frames[3].computedOffset,
-                frames[2].computedOffset +
-                (1.0 - frames[2].computedOffset) * 60 / 110,
-                '4th frame offset using paced spacing');
-}, 'Test paced spacing if a paced property that appears on only some ' +
-   'keyframes and there is a specific offset');
-
-test(function(t) {
-  var anim = createDiv(t).animate([ { margin: '0px' },
-                                    { marginTop: '20px', offset: 0.2 },
-                                    { marginTop: '40px' },
-                                    { marginTop: '-20px' },
-                                    { marginLeft: '-20px' },
-                                    { marginLeft: '40px' },
-                                    { marginTop: '60px' },
-                                    { marginLeft: '100px' },
-                                    { marginTop: '50px' },
-                                    { marginTop: '100px', offset: 0.8 },
-                                    { margin: '0px' } ],
-                                  { duration: 100 * MS_PER_SEC,
-                                    spacing: 'paced(margin-left)' });
-  var frames = anim.effect.getKeyframes();
-  // Test distribute spacing in (A, Paced A] and [Paced B, frame B).
-  var slots = frames.length - 3;
-  var start = 0.2;
-  var diff = 0.8 - start;
-  assert_equals(frames[2].computedOffset, start + diff * 1.0 / slots,
-                '3nd frame offset using distribute spacing');
-  assert_equals(frames[3].computedOffset, start + diff * 2.0 / slots,
-                '4rd frame offset using distribute spacing');
-  assert_equals(frames[4].computedOffset, start + diff * 3.0 / slots,
-                '5th frame offset using distribute spacing because it is ' +
-                'the first paceable keyframe');
-  assert_equals(frames[7].computedOffset, start + diff * 6.0 / slots,
-                '8th frame offset using distribute spacing because it is ' +
-                'the last paceable keyframe');
-  assert_equals(frames[8].computedOffset, start + diff * 7.0 / slots,
-                '9th frame offset using distribute spacing');
-  // Test paced spacing and other null computed offsets in (Paced A, Paced B).
-  var cumDist = [0, 60, 60, 120];
-  assert_equals(frames[5].computedOffset,
-                frames[4].computedOffset + cumDist[2] / cumDist[3] *
-                  (frames[7].computedOffset - frames[4].computedOffset),
-                '6th frame offset using paced spacing');
-  assert_equals(frames[6].computedOffset,
-                frames[5].computedOffset + 1.0 / 2.0 *
-                  (frames[7].computedOffset - frames[5].computedOffset),
-                '7th frame offset using distribute spacing');
-}, 'Test paced spacing where there are some keyframes without offsets and ' +
-   'without the paced property before the first paceable keyframe and ' +
-   'after the last paceable keyframe');
-
-test(function(t) {
-  var anim = createDiv(t).animate([ { margin: '0px' },
-                                    { margin: '-20px' },
-                                    { margin: '100px' },
-                                    { margin: '50px' } ],
-                                  { duration: 100 * MS_PER_SEC,
-                                    spacing: 'paced(margin)' });
-
-  var frames = anim.effect.getKeyframes();
-  var cumDist = [0, 20, 140, 190];
-  assert_equals(frames[1].computedOffset, cumDist[1] / cumDist[3],
-                '2nd frame offset');
-  assert_equals(frames[2].computedOffset, cumDist[2] / cumDist[3],
-                '3rd frame offset');
-}, 'Test paced spacing for using shorthand property');
-
-test(function(t) {
-  var anim =
-    createDiv(t).animate([ { marginLeft: '0px',   marginRight:  '0px',
-                             marginTop:  '10px',  marginBottom: '10px' },
-                           { marginLeft: '-20px', marginRight:  '-20px',
-                             marginTop:  '0px',   marginBottom: '0px' },
-                           { marginLeft: '100px', marginRight:  '100px',
-                             marginTop:  '-50px', marginBottom: '-50px' },
-                           { marginLeft: '50px',  marginRight:  '50px',
-                             marginTop:  '80px',  marginBottom: '80px' } ],
-                         { duration: 100 * MS_PER_SEC,
-                           spacing: 'paced(margin)' });
-
-  var frames = anim.effect.getKeyframes();
-  var dist = [ 0,
-               Math.sqrt(20 * 20 * 2 + 10 * 10 * 2),
-               Math.sqrt(120 * 120 * 2 + 50 * 50 * 2),
-               Math.sqrt(50 * 50 * 2 + 130 * 130 * 2) ];
-  var cumDist = [];
-  dist.reduce(function(prev, curr, i) { return cumDist[i] = prev + curr; }, 0);
-  assert_approx_equals(frames[1].computedOffset, cumDist[1] / cumDist[3],
-                       0.0001, '2nd frame offset');
-  assert_approx_equals(frames[2].computedOffset, cumDist[2] / cumDist[3],
-                       0.0001, '3rd frame offset');
-}, 'Test paced spacing using shorthand property where only the longhand ' +
-   'components are specified');
-
-test(function(t) {
-  var anim = createDiv(t).animate([ { marginLeft: '0px', marginTop: '0px' },
-                                    { marginLeft: '-20px', marginTop: '-20px' },
-                                    { marginLeft: '100px', marginTop: '100px' },
-                                    { marginLeft: '50px', marginTop: '50px' } ],
-                                  { duration: 100 * MS_PER_SEC,
-                                    spacing: 'paced(margin)' });
-
-  var frames = anim.effect.getKeyframes();
-  var slots = frames.length - 1;
-  assert_equals(frames[1].computedOffset, 1 / slots, '2nd frame offset');
-  assert_equals(frames[2].computedOffset, 2 / slots, '3rd frame offset');
-}, 'Test falling back to distribute spacing if all keyframe miss some ' +
-   'components');
-
-test(function(t) {
-  var anim = createDiv(t).animate([ { margin: '0px' },
-                                    { marginLeft: '-20px' },
-                                    { marginTop: '40px' },
-                                    { margin: '100px' },
-                                    { margin: '50px' } ],
-                                  { duration: 100 * MS_PER_SEC,
-                                    spacing: 'paced(margin)' });
-
-  var frames = anim.effect.getKeyframes();
-  assert_equals(frames[1].computedOffset, frames[3].computedOffset * 1 / 3,
-                '2nd frame offset using distribute spacing');
-  assert_equals(frames[2].computedOffset, frames[3].computedOffset * 2 / 3,
-                '3rd frame offset using distribute spacing');
-  assert_equals(frames[3].computedOffset, 100 / 150,
-                '4th frame offset using paced spacing');
-}, 'Test paced spacing only for keyframes specifying all longhand ' +
-   'components, and falling back to distribute spacing for the reset');
-
-test(function(t) {
-  var anim = createDiv(t).animate([ { margin: '0px' },
-                                    { marginLeft: '-20px' },
-                                    { marginTop: '40px', offset: 0.5 },
-                                    { margin: '100px' },
-                                    { margin: '50px' } ],
-                                  { duration: 100 * MS_PER_SEC,
-                                    spacing: 'paced(margin)' });
-
-  var frames = anim.effect.getKeyframes();
-  assert_equals(frames[1].computedOffset, 0.5 * 1 / 2,
-                '2nd frame offset using distribute spacing');
-  assert_equals(frames[3].computedOffset, 0.5 + 0.5 * 1 / 2,
-                '4th frame offset using distribute spacing because it is the ' +
-                'first paceable keyframe from a non-null offset keyframe');
-}, 'Test paced spacing only for keyframes specifying all some components, ' +
-   'and falling back to distribute spacing for the reset with some specific ' +
-   'offsets');
-
-// Tests for setting spacing by KeyframeEffect.spacing.
-
-test(function(t) {
-  var anim = createDiv(t).animate([ { marginLeft: '0px' },
-                                    { marginLeft: '-20px' },
-                                    { marginLeft: '100px' },
-                                    { marginLeft: '50px' } ],
-                                  { duration: 100 * MS_PER_SEC });
-
-  anim.effect.spacing = 'paced(margin-left)';
-
-  var frames = anim.effect.getKeyframes();
-  var cumDist = [0, 20, 140, 190];
-  assert_equals(frames[0].computedOffset, 0.0,
-                '1st frame offset');
-  assert_equals(frames[1].computedOffset, cumDist[1] / cumDist[3],
-                '2nd frame offset');
-  assert_equals(frames[2].computedOffset, cumDist[2] / cumDist[3],
-                '3rd frame offset');
-  assert_equals(frames[3].computedOffset, 1.0,
-                'last frame offset');
-}, 'Test paced spacing by setter');
-
-test(function(t) {
-  var anim = createDiv(t).animate([ { marginLeft: '0px' },
-                                    { marginLeft: '-20px' },
-                                    { marginLeft: '100px' },
-                                    { marginLeft: '50px' } ],
-                                  { duration: 100 * MS_PER_SEC,
-                                    spacing: 'paced(margin-left)' });
-
-  anim.effect.spacing = 'distribute';
-
-  var frames = anim.effect.getKeyframes();
-  var slots = frames.length - 1;
-  assert_equals(frames[0].computedOffset, 0.0, '1st frame offset');
-  assert_equals(frames[1].computedOffset, 1.0 / slots, '2nd frame offset');
-  assert_equals(frames[2].computedOffset, 2.0 / slots, '3rd frame offset');
-  assert_equals(frames[3].computedOffset, 1.0, 'last frame offset');
-}, 'Test distribute spacing by setter');
-
-test(function(t) {
-  var anim =
-    createDiv(t).animate([ { marginLeft: '0px', borderRadius: '0%' },
-                           { marginLeft: '-20px', borderRadius: '50%' },
-                           { marginLeft: '100px', borderRadius: '25%' },
-                           { marginLeft: '50px', borderRadius: '100%' } ],
-                         { duration: 100 * MS_PER_SEC,
-                           spacing: 'paced(margin-left)' });
-
-  anim.effect.spacing = 'paced(border-radius)';
-
-  var frames = anim.effect.getKeyframes();
-  var cumDist = [0, 50, 50 + 25, 50 + 25 + 75];
-
-  assert_equals(frames[0].computedOffset, 0.0,
-                '1st frame offset');
-  assert_equals(frames[1].computedOffset, cumDist[1] / cumDist[3],
-                '2nd frame offset');
-  assert_equals(frames[2].computedOffset, cumDist[2] / cumDist[3],
-                '3rd frame offset');
-  assert_equals(frames[3].computedOffset, 1.0,
-                'last frame offset');
-}, 'Test paced spacing by changing the paced property');
-
-</script>
-</body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/DocumentTimeline/constructor-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/DocumentTimeline/constructor-expected.txt
deleted file mode 100644
index 2e06506..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/DocumentTimeline/constructor-expected.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-This is a testharness.js-based test.
-FAIL An origin time of zero is used when none is supplied Illegal constructor
-FAIL A zero origin time produces a document timeline with a current time identical to the default document timeline Illegal constructor
-FAIL A positive origin time makes the document timeline's current time lag behind the default document timeline Illegal constructor
-FAIL A negative origin time makes the document timeline's current time run ahead of the default document timeline Illegal constructor
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/KeyframeEffect/constructor.html b/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/KeyframeEffect/constructor.html
index 6be0c78..ab52c5fb 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/KeyframeEffect/constructor.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/KeyframeEffect/constructor.html
@@ -228,8 +228,6 @@
   assert_equals(effect.composite, "replace", "default composite");
   assert_equals(effect.iterationComposite, "replace",
                 "default iterationComposite");
-  assert_equals(effect.spacing, "distribute",
-                "default spacing");
 }, "a KeyframeEffectReadOnly constructed without any " +
    "KeyframeEffectOptions object");
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/KeyframeEffect/iterationComposite-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/KeyframeEffect/iterationComposite-expected.txt
index db2d7d0..8d7ad11 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/KeyframeEffect/iterationComposite-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/KeyframeEffect/iterationComposite-expected.txt
@@ -17,16 +17,16 @@
 FAIL iterationComposite of same filter list animation assert_equals: Animated filter list at 0s of the third iteration expected "brightness(3) contrast(3)" but got "brightness(1) contrast(1)"
 FAIL iterationComposite of discrete filter list because of mismatch of the order assert_equals: Animated filter list at 50s of the third iteration expected "contrast(4) brightness(4)" but got "contrast(2) brightness(2)"
 FAIL iterationComposite of different length filter list animation assert_equals: Animated filter list at 0s of the third iteration expected "sepia(2) contrast(3)" but got "sepia(0)"
-FAIL iterationComposite of transform(rotate) animation assert_equals: Animated transform(rotate) style at 50s of the first iteration expected "matrix(0, 1, -1, 0, 0, 0)" but got "matrix(6.12323e-17, 1, -1, 6.12323e-17, 0, 0)"
+PASS iterationComposite of transform(rotate) animation 
 PASS iterationComposite of transform: [ scale(0), scale(1) ] animation 
-FAIL iterationComposite of transform: [ scale(1), scale(2) ] animation assert_equals: Animated transform(scale) style at 0s of the third iteration expected "matrix(3, 0, 0, 3, 0, 0)" but got "matrix(1, 0, 0, 1, 0, 0)"
-FAIL iterationComposite of transform: scale(2) animation assert_equals: Animated transform(scale) style at 0s of the third iteration expected "matrix(2, 0, 0, 2, 0, 0)" but got "matrix(0, 0, 0, 0, 0, 0)"
-FAIL iterationComposite of transform list animation assert_equals: Animated transform list at 50s of the first iteration expected "matrix(0, 1, -1, 0, 0, 5)" but got "matrix(6.12323e-17, 1, -1, 6.12323e-17, 3.06162e-16, 5)"
-FAIL iterationComposite of transform of matrix function assert_equals: Animated transform of matrix function at 0s of the third iteration expected "matrix(6, 0, 0, 6, 60, 0)" but got "matrix(2, 0, 0, 2, 0, 0)"
-FAIL iterationComposite of transform list animation whose order is mismatched assert_equals: Animated transform list at 0s of the third iteration expected "matrix(6, 0, 0, 6, 60, 0)" but got "matrix(2, 0, 0, 2, 0, 0)"
-FAIL iterationComposite of transform list animation whose order is mismatched because of missing functions assert_equals: Animated transform list at 0s of the third iteration expected "matrix(3, 0, 0, 3, 40, 0)" but got "matrix(1, 0, 0, 1, 0, 0)"
-FAIL iterationComposite of transform from none to translate assert_equals: Animated transform list at 50s of the third iteration expected "matrix(1, 0, 0, 1, 15, 0)" but got "matrix(1, 0, 0, 1, 5, 0)"
-FAIL iterationComposite of transform of matrix3d function assert_equals: Animated transform of matrix3d function at 0s of the third iteration expected "matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 130, 1)" but got "matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 30, 1)"
+FAIL iterationComposite of transform: [ scale(1), scale(2) ] animation assert_approx_equals: expected matrix(3, 0, 0, 3, 0, 0) but got matrix(1, 0, 0, 1, 0, 0): Animated transform(scale) style at 0s of the third iteration expected 3 +/- 0.0001 but got 1
+FAIL iterationComposite of transform: scale(2) animation assert_approx_equals: expected matrix(2, 0, 0, 2, 0, 0) but got matrix(0, 0, 0, 0, 0, 0): Animated transform(scale) style at 0s of the third iteration expected 2 +/- 0.0001 but got 0
+FAIL iterationComposite of transform list animation assert_approx_equals: expected matrix(1, 0, 0, 1, 20, 0) but got matrix(1, 0, 0, 1, 0, 0): Animated transform list at 0s of the third iteration expected 20 +/- 0.0001 but got 0
+FAIL iterationComposite of transform of matrix function assert_approx_equals: expected matrix(6, 0, 0, 6, 60, 0) but got matrix(2, 0, 0, 2, 0, 0): Animated transform of matrix function at 0s of the third iteration expected 6 +/- 0.0001 but got 2
+FAIL iterationComposite of transform list animation whose order is mismatched assert_approx_equals: expected matrix(6, 0, 0, 6, 60, 0) but got matrix(2, 0, 0, 2, 0, 0): Animated transform list at 0s of the third iteration expected 6 +/- 0.0001 but got 2
+FAIL iterationComposite of transform list animation whose order is mismatched because of missing functions assert_approx_equals: expected matrix(3, 0, 0, 3, 40, 0) but got matrix(1, 0, 0, 1, 0, 0): Animated transform list at 0s of the third iteration expected 3 +/- 0.0001 but got 1
+FAIL iterationComposite of transform from none to translate assert_approx_equals: expected matrix(1, 0, 0, 1, 20, 0) but got matrix(1, 0, 0, 1, 0, 0): Animated transform list at 0s of the third iteration expected 20 +/- 0.0001 but got 0
+FAIL iterationComposite of transform of matrix3d function assert_approx_equals: expected matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 130, 1) but got matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 30, 1): Animated transform of matrix3d function at 0s of the third iteration expected 130 +/- 0.0001 but got 30
 FAIL iterationComposite of transform of rotate3d function assert_equals: dimension of the matrix: Animated transform of rotate3d function at 0s of the third iteration expected 16 but got 6
 FAIL iterationComposite starts with non-zero value animation assert_equals: Animated margin-left style at 0s of the third iteration expected "50px" but got "10px"
 FAIL iterationComposite with negative final value animation assert_equals: Animated margin-left style at 0s of the third iteration expected "-10px" but got "10px"
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/KeyframeEffect/iterationComposite.html b/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/KeyframeEffect/iterationComposite.html
index eb5c032..7719fa9 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/KeyframeEffect/iterationComposite.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/KeyframeEffect/iterationComposite.html
@@ -447,15 +447,15 @@
   anim.pause();
 
   anim.currentTime = anim.effect.timing.duration / 2;
-  assert_equals(getComputedStyle(div).transform,
+  assert_matrix_equals(getComputedStyle(div).transform,
     'matrix(0, 1, -1, 0, 0, 0)', // rotate(90deg)
     'Animated transform(rotate) style at 50s of the first iteration');
   anim.currentTime = anim.effect.timing.duration * 2;
-  assert_equals(getComputedStyle(div).transform,
+  assert_matrix_equals(getComputedStyle(div).transform,
     'matrix(1, 0, 0, 1, 0, 0)', // rotate(360deg)
     'Animated transform(rotate) style at 0s of the third iteration');
   anim.currentTime += anim.effect.timing.duration / 2;
-  assert_equals(getComputedStyle(div).transform,
+  assert_matrix_equals(getComputedStyle(div).transform,
     'matrix(0, 1, -1, 0, 0, 0)', // rotate(450deg)
     'Animated transform(rotate) style at 50s of the third iteration');
 }, 'iterationComposite of transform(rotate) animation');
@@ -471,16 +471,16 @@
   anim.pause();
 
   anim.currentTime = anim.effect.timing.duration / 2;
-  assert_equals(getComputedStyle(div).transform,
+  assert_matrix_equals(getComputedStyle(div).transform,
     'matrix(0.5, 0, 0, 0.5, 0, 0)', // scale(0.5)
     'Animated transform(scale) style at 50s of the first iteration');
   anim.currentTime = anim.effect.timing.duration * 2;
-  assert_equals(getComputedStyle(div).transform,
+  assert_matrix_equals(getComputedStyle(div).transform,
     'matrix(0, 0, 0, 0, 0, 0)', // scale(0); scale(1) is an identity element,
                                 // not accumulated.
     'Animated transform(scale) style at 0s of the third iteration');
   anim.currentTime += anim.effect.timing.duration / 2;
-  assert_equals(getComputedStyle(div).transform,
+  assert_matrix_equals(getComputedStyle(div).transform,
     'matrix(0.5, 0, 0, 0.5, 0, 0)', // scale(0.5); scale(1) an identity
                                     // element, not accumulated.
     'Animated transform(scale) style at 50s of the third iteration');
@@ -497,15 +497,15 @@
   anim.pause();
 
   anim.currentTime = anim.effect.timing.duration / 2;
-  assert_equals(getComputedStyle(div).transform,
+  assert_matrix_equals(getComputedStyle(div).transform,
     'matrix(1.5, 0, 0, 1.5, 0, 0)', // scale(1.5)
     'Animated transform(scale) style at 50s of the first iteration');
   anim.currentTime = anim.effect.timing.duration * 2;
-  assert_equals(getComputedStyle(div).transform,
+  assert_matrix_equals(getComputedStyle(div).transform,
     'matrix(3, 0, 0, 3, 0, 0)', // scale(1 + (2 -1) + (2 -1))
     'Animated transform(scale) style at 0s of the third iteration');
   anim.currentTime += anim.effect.timing.duration / 2;
-  assert_equals(getComputedStyle(div).transform,
+  assert_matrix_equals(getComputedStyle(div).transform,
     'matrix(3.5, 0, 0, 3.5, 0, 0)', // (scale(3) + scale(4)) * 0.5
     'Animated transform(scale) style at 50s of the third iteration');
 }, 'iterationComposite of transform: [ scale(1), scale(2) ] animation');
@@ -521,15 +521,15 @@
   anim.pause();
 
   anim.currentTime = anim.effect.timing.duration / 2;
-  assert_equals(getComputedStyle(div).transform,
+  assert_matrix_equals(getComputedStyle(div).transform,
     'matrix(1, 0, 0, 1, 0, 0)', // scale(1)
     'Animated transform(scale) style at 50s of the first iteration');
   anim.currentTime = anim.effect.timing.duration * 2;
-  assert_equals(getComputedStyle(div).transform,
+  assert_matrix_equals(getComputedStyle(div).transform,
     'matrix(2, 0, 0, 2, 0, 0)', // (scale(0) + scale(2-1)*2)
     'Animated transform(scale) style at 0s of the third iteration');
   anim.currentTime += anim.effect.timing.duration / 2;
-  assert_equals(getComputedStyle(div).transform,
+  assert_matrix_equals(getComputedStyle(div).transform,
     'matrix(3, 0, 0, 3, 0, 0)', // (scale(2) + scale(4)) * 0.5
     'Animated transform(scale) style at 50s of the third iteration');
 }, 'iterationComposite of transform: scale(2) animation');
@@ -546,15 +546,15 @@
   anim.pause();
 
   anim.currentTime = anim.effect.timing.duration / 2;
-  assert_equals(getComputedStyle(div).transform,
+  assert_matrix_equals(getComputedStyle(div).transform,
     'matrix(0, 1, -1, 0, 0, 5)', // rotate(90deg) translateX(5px)
     'Animated transform list at 50s of the first iteration');
   anim.currentTime = anim.effect.timing.duration * 2;
-  assert_equals(getComputedStyle(div).transform,
+  assert_matrix_equals(getComputedStyle(div).transform,
     'matrix(1, 0, 0, 1, 20, 0)', // rotate(360deg) translateX(20px)
     'Animated transform list at 0s of the third iteration');
   anim.currentTime += anim.effect.timing.duration / 2;
-  assert_equals(getComputedStyle(div).transform,
+  assert_matrix_equals(getComputedStyle(div).transform,
     'matrix(0, 1, -1, 0, 0, 25)', // rotate(450deg) translateX(25px)
     'Animated transform list at 50s of the third iteration');
 }, 'iterationComposite of transform list animation');
@@ -571,16 +571,16 @@
   anim.pause();
 
   anim.currentTime = anim.effect.timing.duration / 2;
-  assert_equals(getComputedStyle(div).transform,
+  assert_matrix_equals(getComputedStyle(div).transform,
     'matrix(2.5, 0, 0, 2.5, 15, 0)',
     'Animated transform of matrix function at 50s of the first iteration');
   anim.currentTime = anim.effect.timing.duration * 2;
-  assert_equals(getComputedStyle(div).transform,
+  assert_matrix_equals(getComputedStyle(div).transform,
     // scale(2) + (scale(3-1)*2) + translateX(30px)*2
     'matrix(6, 0, 0, 6, 60, 0)',
     'Animated transform of matrix function at 0s of the third iteration');
   anim.currentTime += anim.effect.timing.duration / 2;
-  assert_equals(getComputedStyle(div).transform,
+  assert_matrix_equals(getComputedStyle(div).transform,
     // from: matrix(6, 0, 0, 6, 60, 0)
     // to:   matrix(7, 0, 0, 7, 90, 0)
     //         = scale(3) + (scale(3-1)*2) + translateX(30px)*3
@@ -600,20 +600,20 @@
   anim.pause();
 
   anim.currentTime = anim.effect.timing.duration / 2;
-  assert_equals(getComputedStyle(div).transform,
+  assert_matrix_equals(getComputedStyle(div).transform,
     // Interpolate between matrix(2, 0, 0, 2,  0, 0) = translateX(0px) scale(2)
     //                 and matrix(3, 0, 0, 3, 30, 0) = scale(3) translateX(10px)
     'matrix(2.5, 0, 0, 2.5, 15, 0)',
     'Animated transform list at 50s of the first iteration');
   anim.currentTime = anim.effect.timing.duration * 2;
-  assert_equals(getComputedStyle(div).transform,
+  assert_matrix_equals(getComputedStyle(div).transform,
     // 'from' and 'to' value are mismatched, so accumulate
     // matrix(2, 0, 0, 2, 0, 0) onto matrix(3, 0, 0, 3, 30, 0) * 2
     //  = scale(2) + (scale(3-1)*2) + translateX(30px)*2
     'matrix(6, 0, 0, 6, 60, 0)',
     'Animated transform list at 0s of the third iteration');
   anim.currentTime += anim.effect.timing.duration / 2;
-  assert_equals(getComputedStyle(div).transform,
+  assert_matrix_equals(getComputedStyle(div).transform,
     // Interpolate between matrix(6, 0, 0, 6, 60, 0)
     //                 and matrix(7, 0, 0, 7, 210, 0) = scale(7) translate(30px)
     'matrix(6.5, 0, 0, 6.5, 135, 0)',
@@ -634,20 +634,20 @@
   anim.pause();
 
   anim.currentTime = anim.effect.timing.duration / 2;
-  assert_equals(getComputedStyle(div).transform,
+  assert_matrix_equals(getComputedStyle(div).transform,
     // Interpolate between matrix(1, 0, 0, 1,  0, 0) = translateX(0px)
     //                 and matrix(2, 0, 0, 2, 20, 0) = scale(2) translateX(10px)
     'matrix(1.5, 0, 0, 1.5, 10, 0)',
     'Animated transform list at 50s of the first iteration');
   anim.currentTime = anim.effect.timing.duration * 2;
-  assert_equals(getComputedStyle(div).transform,
+  assert_matrix_equals(getComputedStyle(div).transform,
     // 'from' and 'to' value are mismatched, so accumulate
     // matrix(1, 0, 0, 1, 0, 0) onto matrix(2, 0, 0, 2, 20, 0) * 2
     //  = scale(1) + (scale(2-1)*2) + translateX(20px)*2
     'matrix(3, 0, 0, 3, 40, 0)',
     'Animated transform list at 0s of the third iteration');
   anim.currentTime += anim.effect.timing.duration / 2;
-  assert_equals(getComputedStyle(div).transform,
+  assert_matrix_equals(getComputedStyle(div).transform,
     // Interpolate between matrix(3, 0, 0, 3, 40, 0)
     //                 and matrix(4, 0, 0, 4, 120, 0) =
     //                       scale(2 + (2-1)*2) translate(10px * 3)
@@ -668,16 +668,19 @@
   anim.pause();
 
   anim.currentTime = anim.effect.timing.duration / 2;
-  assert_equals(getComputedStyle(div).transform,
-    'matrix(1, 0, 0, 1, 5, 0)', // (0px + 10px) / 2
+  assert_matrix_equals(getComputedStyle(div).transform,
+    // translateX(none) -> translateX(10px) @ 50%
+    'matrix(1, 0, 0, 1, 5, 0)',
     'Animated transform list at 50s of the first iteration');
   anim.currentTime = anim.effect.timing.duration * 2;
-  assert_equals(getComputedStyle(div).transform,
-    'matrix(1, 0, 0, 1, 0, 0)', // 'none' overrides any transforms.
+  assert_matrix_equals(getComputedStyle(div).transform,
+    // translateX(10px * 2 + none) -> translateX(10px * 2 + 10px) @ 0%
+    'matrix(1, 0, 0, 1, 20, 0)',
     'Animated transform list at 0s of the third iteration');
   anim.currentTime += anim.effect.timing.duration / 2;
-  assert_equals(getComputedStyle(div).transform,
-    'matrix(1, 0, 0, 1, 15, 0)', // (0px + 10px*2)/2
+  assert_matrix_equals(getComputedStyle(div).transform,
+    // translateX(10px * 2 + none) -> translateX(10px * 2 + 10px) @ 50%
+    'matrix(1, 0, 0, 1, 25, 0)',
     'Animated transform list at 50s of the third iteration');
 }, 'iterationComposite of transform from none to translate');
 
@@ -699,16 +702,16 @@
   anim.pause();
 
   anim.currentTime = anim.effect.timing.duration / 2;
-  assert_equals(getComputedStyle(div).transform,
+  assert_matrix_equals(getComputedStyle(div).transform,
     'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 40, 1)',
     'Animated transform of matrix3d function at 50s of the first iteration');
   anim.currentTime = anim.effect.timing.duration * 2;
-  assert_equals(getComputedStyle(div).transform,
+  assert_matrix_equals(getComputedStyle(div).transform,
     // translateZ(30px) + (translateZ(50px)*2)
     'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 130, 1)',
     'Animated transform of matrix3d function at 0s of the third iteration');
   anim.currentTime += anim.effect.timing.duration / 2;
-  assert_equals(getComputedStyle(div).transform,
+  assert_matrix_equals(getComputedStyle(div).transform,
     // from: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 130, 1)
     // to:   matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 150, 1)
     'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 140, 1)',
@@ -727,7 +730,7 @@
   anim.pause();
 
   anim.currentTime = 0;
-  assert_equals(getComputedStyle(div).transform,
+  assert_matrix_equals(getComputedStyle(div).transform,
     'matrix(1, 0, 0, 1, 0, 0)', // Actually not rotated at all.
     'Animated transform of rotate3d function at 50s of the first iteration');
   anim.currentTime = anim.effect.timing.duration * 2;
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/KeyframeEffect/processing-a-keyframes-argument-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/KeyframeEffect/processing-a-keyframes-argument-expected.txt
index bc8b50b..334d6e0 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/KeyframeEffect/processing-a-keyframes-argument-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/KeyframeEffect/processing-a-keyframes-argument-expected.txt
@@ -45,7 +45,7 @@
 FAIL Custom iterator with multiple properties specified. effect.getKeyframes is not a function
 FAIL Custom iterator with offset specified. effect.getKeyframes is not a function
 PASS Custom iterator with non object keyframe should throw. 
-FAIL Custom iterator with value list in keyframe should give bizarre string representation of list. effect.getKeyframes is not a function
+FAIL Custom iterator with value list in keyframe should not contain invalid property value pair of list. effect.getKeyframes is not a function
 FAIL Only enumerable properties on keyframes are considered anim.effect.getKeyframes is not a function
 FAIL Only properties defined directly on keyframes are considered anim.effect.getKeyframes is not a function
 FAIL Only enumerable properties on property indexed keyframes are considered anim.effect.getKeyframes is not a function
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/KeyframeEffect/processing-a-keyframes-argument.html b/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/KeyframeEffect/processing-a-keyframes-argument.html
index cbd5090..5b34080 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/KeyframeEffect/processing-a-keyframes-argument.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/KeyframeEffect/processing-a-keyframes-argument.html
@@ -258,9 +258,10 @@
     {done: true},
   ]));
   assert_frame_lists_equal(effect.getKeyframes(), [
-    {offset: null, computedOffset: 1, easing: 'linear', left: '100px,200px'}
+    {offset: null, computedOffset: 1, easing: 'linear'}
   ]);
-}, 'Custom iterator with value list in keyframe should give bizarre string representation of list.');
+}, 'Custom iterator with value list in keyframe should not contain invalid ' +
+   'property value pair of list.');
 
 test(function(t) {
   var keyframe = {};
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/KeyframeEffect/setTarget-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/KeyframeEffect/setTarget-expected.txt
index ffde75e..dfebb2e5 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/KeyframeEffect/setTarget-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/KeyframeEffect/setTarget-expected.txt
@@ -3,8 +3,5 @@
 FAIL Test setting target from null to a valid target assert_equals: Value at 50% progress after setting new target expected "50px" but got "10px"
 FAIL Test setting target from a valid target to null assert_equals: Value after clearing the target expected "10px" but got "50px"
 FAIL Test setting target from a valid target to another target assert_equals: Value of 1st element (currently not targeted) after changing the effect target expected "10px" but got "50px"
-FAIL Test falling back to distribute spacing mode after setting null target anim.effect.getKeyframes is not a function
-FAIL Test falling back to distribute spacing mode if there is no context element effect.getKeyframes is not a function
-FAIL Test paced spacing mode after setting a new target anim.effect.getKeyframes is not a function
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/KeyframeEffect/setTarget.html b/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/KeyframeEffect/setTarget.html
index 2b07d3de..49ef8402 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/KeyframeEffect/setTarget.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/KeyframeEffect/setTarget.html
@@ -85,76 +85,5 @@
                 'changing the animation current time.');
 }, 'Test setting target from a valid target to another target');
 
-test(function(t) {
-  var anim = createDiv(t).animate([ { marginLeft: '0px' },
-                                    { marginLeft: '-20px' },
-                                    { marginLeft: '100px' },
-                                    { marginLeft: '50px' } ],
-                                  { duration: 100 * MS_PER_SEC,
-                                    spacing: 'paced(margin-left)' });
-
-  anim.effect.target = null;
-
-  var frames = anim.effect.getKeyframes();
-  var slots = frames.length - 1;
-  assert_equals(frames[0].computedOffset, 0.0, '1st frame offset');
-  assert_equals(frames[1].computedOffset, 1.0 / slots, '2nd frame offset');
-  assert_equals(frames[2].computedOffset, 2.0 / slots, '3rd frame offset');
-  assert_equals(frames[3].computedOffset, 1.0, 'last frame offset');
-}, 'Test falling back to distribute spacing mode after setting null target');
-
-test(function(t) {
-  var effect = new KeyframeEffect(null,
-                                  [ { marginLeft: '0px' },
-                                    { marginLeft: '-20px' },
-                                    { marginLeft: '100px' },
-                                    { marginLeft: '50px' } ],
-                                  { duration: 100 * MS_PER_SEC,
-                                    spacing: 'paced(margin-left)' });
-  var frames = effect.getKeyframes();
-  var slots = frames.length - 1;
-  assert_equals(frames[1].computedOffset, 1.0 / slots, '2nd frame offset');
-  assert_equals(frames[2].computedOffset, 2.0 / slots, '3rd frame offset');
-}, 'Test falling back to distribute spacing mode if there is no context ' +
-   'element');
-
-test(function(t) {
-  var div1 = createDiv(t);
-  var div2 = createDiv(t);
-  div1.style.marginLeft = '-20px';
-  div2.style.marginLeft = '-50px';
-  var child1 = document.createElement('div');
-  var child2 = document.createElement('div');
-  div1.appendChild(child1);
-  div2.appendChild(child2);
-  //      body
-  //    /      \
-  //  div1     div2
-  // (-20px)  (-50px)
-  //   |        |
-  // child1   child2
-  var anim = child1.animate([ { marginLeft: '0px' },
-                              { marginLeft: 'inherit' },
-                              { marginLeft: '100px' },
-                              { marginLeft: '50px' } ],
-                            { duration: 100 * MS_PER_SEC,
-                              spacing: 'paced(margin-left)' });
-
-  var frames = anim.effect.getKeyframes();
-  var cumDist = [0, 20, 140, 190];
-  assert_equals(frames[1].computedOffset, cumDist[1] / cumDist[3],
-                '2nd frame offset');
-  assert_equals(frames[2].computedOffset, cumDist[2] / cumDist[3],
-                '3rd frame offset');
-
-  anim.effect.target = child2;
-  frames = anim.effect.getKeyframes();
-  cumDist = [0, 50, 200, 250];
-  assert_equals(frames[1].computedOffset, cumDist[1] / cumDist[3],
-                '2nd frame offset after setting a new target');
-  assert_equals(frames[2].computedOffset, cumDist[2] / cumDist[3],
-                '3rd frame offset after setting a new target');
-}, 'Test paced spacing mode after setting a new target');
-
 </script>
 </body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/KeyframeEffect/spacing-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/KeyframeEffect/spacing-expected.txt
deleted file mode 100644
index 0abb4cae..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/KeyframeEffect/spacing-expected.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-This is a testharness.js-based test.
-FAIL Test throwing TypeError if using empty string assert_throws: function "function () {
-    anim.effect.spacing = '';
-  }" did not throw
-FAIL Test throwing TypeError if not using the correct keyword assert_throws: function "function () {
-    anim.effect.spacing = 'dist';
-  }" did not throw
-FAIL Test falling back to distribute spacing if using a unrecognized property assert_equals: spacing mode expected "distribute" but got "paced(A)"
-FAIL Test falling back to distribute spacing if using CSS variables assert_equals: spacing mode expected "distribute" but got "paced(--bg-color)"
-FAIL Test falling back to distribute spacing if using a non-animatable property assert_equals: spacing mode expected "distribute" but got "paced(animation-duration)"
-PASS Test spacing value if setting distribute 
-PASS Test spacing value if setting paced 
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/KeyframeEffect/spacing.html b/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/KeyframeEffect/spacing.html
deleted file mode 100644
index 612a3af..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/KeyframeEffect/spacing.html
+++ /dev/null
@@ -1,60 +0,0 @@
-<!DOCTYPE html>
-<meta charset=utf-8>
-<title>KeyframeEffect spacing attribute tests</title>
-<link rel="help"
-      href="https://w3c.github.io/web-animations/#dom-keyframeeffect-spacing">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="../../testcommon.js"></script>
-<body>
-<div id="log"></div>
-<script>
-"use strict";
-
-test(function(t) {
-  var anim = createDiv(t).animate(null);
-  assert_throws(new TypeError, function() {
-    anim.effect.spacing = '';
-  });
-}, 'Test throwing TypeError if using empty string');
-
-test(function(t) {
-  var anim = createDiv(t).animate(null);
-  assert_throws(new TypeError, function() {
-    anim.effect.spacing = 'dist';
-  });
-}, 'Test throwing TypeError if not using the correct keyword');
-
-test(function(t) {
-  var anim = createDiv(t).animate(null);
-  anim.effect.spacing = 'paced(A)';
-  assert_equals(anim.effect.spacing, 'distribute', 'spacing mode');
-}, 'Test falling back to distribute spacing if using a unrecognized property');
-
-test(function(t) {
-  var anim = createDiv(t).animate(null);
-  anim.effect.spacing = 'paced(--bg-color)';
-  assert_equals(anim.effect.spacing, 'distribute', 'spacing mode');
-}, 'Test falling back to distribute spacing if using CSS variables');
-
-test(function(t) {
-  var anim = createDiv(t).animate(null);
-  anim.effect.spacing = 'paced(animation-duration)';
-  assert_equals(anim.effect.spacing, 'distribute', 'spacing mode');
-}, 'Test falling back to distribute spacing if using a non-animatable ' +
-   'property');
-
-test(function(t) {
-  var anim = createDiv(t).animate(null);
-  anim.effect.spacing = 'distribute';
-  assert_equals(anim.effect.spacing, 'distribute', 'spacing mode');
-}, 'Test spacing value if setting distribute');
-
-test(function(t) {
-  var anim = createDiv(t).animate(null);
-  anim.effect.spacing = 'paced(transform)';
-  assert_equals(anim.effect.spacing, 'paced(transform)', 'spacing mode');
-}, 'Test spacing value if setting paced');
-
-</script>
-</body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/KeyframeEffectReadOnly/spacing-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/KeyframeEffectReadOnly/spacing-expected.txt
deleted file mode 100644
index 3195aa9..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/KeyframeEffectReadOnly/spacing-expected.txt
+++ /dev/null
@@ -1,84 +0,0 @@
-This is a testharness.js-based test.
-FAIL Test throwing TypeError if using empty string assert_throws: function "function () {
-    createDiv(t).animate(null, { spacing: '' });
-  }" did not throw
-FAIL Test throwing TypeError if not using the correct keyword assert_throws: function "function () {
-    createDiv(t).animate(null, { spacing: 'dist' });
-  }" did not throw
-FAIL Test throwing TypeError if adding leading spaces assert_throws: function "function () {
-    createDiv(t).animate(null, { spacing: ' paced(margin-left)' });
-  }" did not throw
-FAIL Test throwing TypeError if adding trailing spaces assert_throws: function "function () {
-    createDiv(t).animate(null, { spacing: 'paced(margin-left) ' });
-  }" did not throw
-FAIL Test throwing TypeError if adding leading spaces before the paced property assert_throws: function "function () {
-    createDiv(t).animate(null, { spacing: 'paced( margin-left)' });
-  }" did not throw
-FAIL Test throwing TypeError if adding trailing spaces after the paced property assert_throws: function "function () {
-    createDiv(t).animate(null, { spacing: 'paced(margin-left )' });
-  }" did not throw
-FAIL Test throwing TypeError if these is no paced property assert_throws: function "function () {
-    createDiv(t).animate(null, { spacing: 'paced()' });
-  }" did not throw
-FAIL Test throwing TypeError if using a non-ident started string with a period assert_throws: function "function () {
-    createDiv(t).animate(null, { spacing: 'paced(.margin)' });
-  }" did not throw
-FAIL Test throwing TypeError if using a non-ident started string with a number assert_throws: function "function () {
-    createDiv(t).animate(null, { spacing: 'paced(1margin)' });
-  }" did not throw
-FAIL Test throwing TypeError if using a non-ident started string with an invalid escape assert_throws: function "function () {
-    createDiv(t).animate(null, { spacing: 'paced(\\)' });
-  }" did not throw
-FAIL Test throwing TypeError if using a non-ident started string with an invalid escape (FF) assert_throws: function "function () {
-    createDiv(t).animate(null, { spacing: 'paced(\\\fmargin)' });
-  }" did not throw
-FAIL Test throwing TypeError if using a non-ident started string with an invalid escape (CR) assert_throws: function "function () {
-    createDiv(t).animate(null, { spacing: 'paced(\\\rmargin)' });
-  }" did not throw
-FAIL Test throwing TypeError if using a non-ident started string with an invalid escape (LF) assert_throws: function "function () {
-    createDiv(t).animate(null, { spacing: 'paced(\\\nmargin)' });
-  }" did not throw
-FAIL Test throwing TypeError if using a non-ident started string with a leading minus and an invalid name-start code point assert_throws: function "function () {
-    createDiv(t).animate(null, { spacing: 'paced(- )' });
-  }" did not throw
-FAIL Test throwing TypeError if using a non-ident started string with a leading minus and an invalid escape assert_throws: function "function () {
-    createDiv(t).animate(null, { spacing: 'paced(-\\)' });
-  }" did not throw
-FAIL Test throwing TypeError if using a non-ident started string with a leading minus and an invalid escape (FF) assert_throws: function "function () {
-    createDiv(t).animate(null, { spacing: 'paced(-\\\fmargin)' });
-  }" did not throw
-FAIL Test throwing TypeError if using a non-ident started string with a leading minus and an invalid escape (CR) assert_throws: function "function () {
-    createDiv(t).animate(null, { spacing: 'paced(-\\\rmargin)' });
-  }" did not throw
-FAIL Test throwing TypeError if using a non-ident started string with a leading minus and an invalid escape (LF) assert_throws: function "function () {
-    createDiv(t).animate(null, { spacing: 'paced(-\\\nmargin)' });
-  }" did not throw
-FAIL Test throwing TypeError if using a non-ident string with an invalid escape assert_throws: function "function () {
-    createDiv(t).animate(null, { spacing: 'paced(--\\)' });
-  }" did not throw
-FAIL Test throwing TypeError if using a non-ident string with an invalid escape (FF) assert_throws: function "function () {
-    createDiv(t).animate(null, { spacing: 'paced(--\\\fmargin)' });
-  }" did not throw
-FAIL Test throwing TypeError if using a non-ident string with an invalid escape (CR) assert_throws: function "function () {
-    createDiv(t).animate(null, { spacing: 'paced(--\\\rmargin)' });
-  }" did not throw
-FAIL Test throwing TypeError if using a non-ident string with an invalid escape (LF) assert_throws: function "function () {
-    createDiv(t).animate(null, { spacing: 'paced(--\\\nmargin)' });
-  }" did not throw
-FAIL Test throwing TypeError if using a non-ident string with an invalid name code point assert_throws: function "function () {
-    createDiv(t).animate(null, { spacing: 'paced(margin.left)' });
-  }" did not throw
-FAIL Test falling back to distribute spacing if using a unrecognized property assert_equals: spacing mode expected (string) "distribute" but got (undefined) undefined
-FAIL Test falling back to distribute spacing if using a unrecognized property which starts with a valid escape (Full stop) assert_equals: spacing mode expected (string) "distribute" but got (undefined) undefined
-FAIL Test falling back to distribute spacing if using a unrecognized property which starts with a valid escape (white space) assert_equals: spacing mode expected (string) "distribute" but got (undefined) undefined
-FAIL Test falling back to distribute spacing if using a unrecognized property which starts with a valid escape (low line) assert_equals: spacing mode expected (string) "distribute" but got (undefined) undefined
-FAIL Test falling back to distribute spacing if using a unrecognized property which starts with a minus and a low line assert_equals: spacing mode expected (string) "distribute" but got (undefined) undefined
-FAIL Test falling back to distribute spacing if using a unrecognized property which starts with a minus and a valid escape assert_equals: spacing mode expected (string) "distribute" but got (undefined) undefined
-FAIL Test falling back to distribute spacing if using CSS variables assert_equals: spacing mode expected (string) "distribute" but got (undefined) undefined
-FAIL Test falling back to distribute spacing if using a non-animatable shorthand property assert_equals: spacing mode expected (string) "distribute" but got (undefined) undefined
-FAIL Test falling back to distribute spacing if using a non-animatable property assert_equals: spacing mode expected (string) "distribute" but got (undefined) undefined
-FAIL Test default value of spacing assert_equals: spacing mode expected (string) "distribute" but got (undefined) undefined
-FAIL Test spacing value if setting distribute assert_equals: spacing mode expected (string) "distribute" but got (undefined) undefined
-FAIL Test spacing value if setting paced assert_equals: spacing mode expected (string) "paced(margin-left)" but got (undefined) undefined
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/KeyframeEffectReadOnly/spacing.html b/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/KeyframeEffectReadOnly/spacing.html
deleted file mode 100644
index 9c54d970..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/KeyframeEffectReadOnly/spacing.html
+++ /dev/null
@@ -1,239 +0,0 @@
-<!DOCTYPE html>
-<meta charset=utf-8>
-<title>KeyframeEffectReadOnly spacing attribute tests</title>
-<link rel="help"
-href="https://w3c.github.io/web-animations/#dom-keyframeeffectreadonly-spacing">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="../../testcommon.js"></script>
-<body>
-<div id="log"></div>
-<script>
-"use strict";
-
-test(function(t) {
-  assert_throws(new TypeError, function() {
-    createDiv(t).animate(null, { spacing: '' });
-  });
-}, 'Test throwing TypeError if using empty string');
-
-test(function(t) {
-  assert_throws(new TypeError, function() {
-    createDiv(t).animate(null, { spacing: 'dist' });
-  });
-}, 'Test throwing TypeError if not using the correct keyword');
-
-test(function(t) {
-  assert_throws(new TypeError, function() {
-    createDiv(t).animate(null, { spacing: ' paced(margin-left)' });
-  });
-}, 'Test throwing TypeError if adding leading spaces');
-
-test(function(t) {
-  assert_throws(new TypeError, function() {
-    createDiv(t).animate(null, { spacing: 'paced(margin-left) ' });
-  });
-}, 'Test throwing TypeError if adding trailing spaces');
-
-test(function(t) {
-  assert_throws(new TypeError, function() {
-    createDiv(t).animate(null, { spacing: 'paced( margin-left)' });
-  });
-}, 'Test throwing TypeError if adding leading spaces before the ' +
-   'paced property');
-
-test(function(t) {
-  assert_throws(new TypeError, function() {
-    createDiv(t).animate(null, { spacing: 'paced(margin-left )' });
-  });
-}, 'Test throwing TypeError if adding trailing spaces after the ' +
-   'paced property');
-
-test(function(t) {
-  assert_throws(new TypeError, function() {
-    createDiv(t).animate(null, { spacing: 'paced()' });
-  });
-}, 'Test throwing TypeError if these is no paced property');
-
-test(function(t) {
-  assert_throws(new TypeError, function() {
-    createDiv(t).animate(null, { spacing: 'paced(.margin)' });
-  });
-}, 'Test throwing TypeError if using a non-ident started string with ' +
-   'a period');
-
-test(function(t) {
-  assert_throws(new TypeError, function() {
-    createDiv(t).animate(null, { spacing: 'paced(1margin)' });
-  });
-}, 'Test throwing TypeError if using a non-ident started string with ' +
-   'a number');
-
-test(function(t) {
-  assert_throws(new TypeError, function() {
-    createDiv(t).animate(null, { spacing: 'paced(\\)' });
-  });
-}, 'Test throwing TypeError if using a non-ident started string with ' +
-   'an invalid escape');
-
-test(function(t) {
-  assert_throws(new TypeError, function() {
-    createDiv(t).animate(null, { spacing: 'paced(\\\fmargin)' });
-  });
-}, 'Test throwing TypeError if using a non-ident started string with ' +
-   'an invalid escape (FF)');
-
-test(function(t) {
-  assert_throws(new TypeError, function() {
-    createDiv(t).animate(null, { spacing: 'paced(\\\rmargin)' });
-  });
-}, 'Test throwing TypeError if using a non-ident started string with ' +
-   'an invalid escape (CR)');
-
-test(function(t) {
-  assert_throws(new TypeError, function() {
-    createDiv(t).animate(null, { spacing: 'paced(\\\nmargin)' });
-  });
-}, 'Test throwing TypeError if using a non-ident started string with ' +
-   'an invalid escape (LF)');
-
-test(function(t) {
-  assert_throws(new TypeError, function() {
-    createDiv(t).animate(null, { spacing: 'paced(- )' });
-  });
-}, 'Test throwing TypeError if using a non-ident started string with ' +
-   'a leading minus and an invalid name-start code point');
-
-test(function(t) {
-  assert_throws(new TypeError, function() {
-    createDiv(t).animate(null, { spacing: 'paced(-\\)' });
-  });
-}, 'Test throwing TypeError if using a non-ident started string with ' +
-   'a leading minus and an invalid escape');
-
-test(function(t) {
-  assert_throws(new TypeError, function() {
-    createDiv(t).animate(null, { spacing: 'paced(-\\\fmargin)' });
-  });
-}, 'Test throwing TypeError if using a non-ident started string with ' +
-   'a leading minus and an invalid escape (FF)');
-
-test(function(t) {
-  assert_throws(new TypeError, function() {
-    createDiv(t).animate(null, { spacing: 'paced(-\\\rmargin)' });
-  });
-}, 'Test throwing TypeError if using a non-ident started string with ' +
-   'a leading minus and an invalid escape (CR)');
-
-test(function(t) {
-  assert_throws(new TypeError, function() {
-    createDiv(t).animate(null, { spacing: 'paced(-\\\nmargin)' });
-  });
-}, 'Test throwing TypeError if using a non-ident started string with ' +
-   'a leading minus and an invalid escape (LF)');
-
-test(function(t) {
-  assert_throws(new TypeError, function() {
-    createDiv(t).animate(null, { spacing: 'paced(--\\)' });
-  });
-}, 'Test throwing TypeError if using a non-ident string with an invalid ' +
-   'escape');
-
-test(function(t) {
-  assert_throws(new TypeError, function() {
-    createDiv(t).animate(null, { spacing: 'paced(--\\\fmargin)' });
-  });
-}, 'Test throwing TypeError if using a non-ident string with an invalid ' +
-   'escape (FF)');
-
-test(function(t) {
-  assert_throws(new TypeError, function() {
-    createDiv(t).animate(null, { spacing: 'paced(--\\\rmargin)' });
-  });
-}, 'Test throwing TypeError if using a non-ident string with an invalid ' +
-   'escape (CR)');
-
-test(function(t) {
-  assert_throws(new TypeError, function() {
-    createDiv(t).animate(null, { spacing: 'paced(--\\\nmargin)' });
-  });
-}, 'Test throwing TypeError if using a non-ident string with an invalid ' +
-   'escape (LF)');
-
-test(function(t) {
-  assert_throws(new TypeError, function() {
-    createDiv(t).animate(null, { spacing: 'paced(margin.left)' });
-  });
-}, 'Test throwing TypeError if using a non-ident string with an invalid name ' +
-   'code point');
-
-test(function(t) {
-  var anim = createDiv(t).animate(null, { spacing: 'paced(A)' });
-  assert_equals(anim.effect.spacing, 'distribute', 'spacing mode');
-}, 'Test falling back to distribute spacing if using a unrecognized property');
-
-test(function(t) {
-  var anim = createDiv(t).animate(null, { spacing: 'paced(\\.margin)' });
-  assert_equals(anim.effect.spacing, 'distribute', 'spacing mode');
-}, 'Test falling back to distribute spacing if using a unrecognized property ' +
-   'which starts with a valid escape (Full stop)');
-
-test(function(t) {
-  var anim = createDiv(t).animate(null, { spacing: 'paced(\\ margin)' });
-  assert_equals(anim.effect.spacing, 'distribute', 'spacing mode');
-}, 'Test falling back to distribute spacing if using a unrecognized property ' +
-   'which starts with a valid escape (white space)');
-
-test(function(t) {
-  var anim = createDiv(t).animate(null, { spacing: 'paced(_margin)' });
-  assert_equals(anim.effect.spacing, 'distribute', 'spacing mode');
-}, 'Test falling back to distribute spacing if using a unrecognized property ' +
-   'which starts with a valid escape (low line)');
-
-test(function(t) {
-  var anim = createDiv(t).animate(null, { spacing: 'paced(-_margin)' });
-  assert_equals(anim.effect.spacing, 'distribute', 'spacing mode');
-}, 'Test falling back to distribute spacing if using a unrecognized property ' +
-   'which starts with a minus and a low line');
-
-test(function(t) {
-  var anim = createDiv(t).animate(null, { spacing: 'paced(-\\.margin)' });
-  assert_equals(anim.effect.spacing, 'distribute', 'spacing mode');
-}, 'Test falling back to distribute spacing if using a unrecognized property ' +
-   'which starts with a minus and a valid escape');
-
-test(function(t) {
-  var anim = createDiv(t).animate(null, { spacing: 'paced(--bg-color)' });
-  assert_equals(anim.effect.spacing, 'distribute', 'spacing mode');
-}, 'Test falling back to distribute spacing if using CSS variables');
-
-test(function(t) {
-  var anim = createDiv(t).animate(null, { spacing: 'paced(animation)' });
-  assert_equals(anim.effect.spacing, 'distribute', 'spacing mode');
-}, 'Test falling back to distribute spacing if using a non-animatable ' +
-   'shorthand property');
-
-test(function(t) {
-  var anim = createDiv(t).animate(null,
-                                  { spacing: 'paced(animation-duration)' });
-  assert_equals(anim.effect.spacing, 'distribute', 'spacing mode');
-}, 'Test falling back to distribute spacing if using a non-animatable ' +
-   'property');
-
-test(function(t) {
-  var anim = createDiv(t).animate(null);
-  assert_equals(anim.effect.spacing, 'distribute', 'spacing mode');
-}, 'Test default value of spacing');
-
-test(function(t) {
-  var anim = createDiv(t).animate(null, { spacing: 'distribute' });
-  assert_equals(anim.effect.spacing, 'distribute', 'spacing mode');
-}, 'Test spacing value if setting distribute');
-
-test(function(t) {
-  var anim = createDiv(t).animate(null, { spacing: 'paced(margin-left)' });
-  assert_equals(anim.effect.spacing, 'paced(margin-left)', 'spacing mode');
-}, 'Test spacing value if setting paced');
-
-</script>
-</body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/resources/keyframe-utils.js b/third_party/WebKit/LayoutTests/external/wpt/web-animations/resources/keyframe-utils.js
index 53d0f23..1d4ad925 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/web-animations/resources/keyframe-utils.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/web-animations/resources/keyframe-utils.js
@@ -128,7 +128,7 @@
              { offset: null, computedOffset: 0.25, easing: "linear",
                left: "20px", top: "25px" },
              { offset: null, computedOffset: 0.50, easing: "linear",
-               left: "30px", top: "invalid" },
+               left: "30px" },
              { offset: null, computedOffset: 0.75, easing: "linear",
                left: "40px", top: "45px" },
              { offset: null, computedOffset: 1.00, easing: "linear",
@@ -166,8 +166,7 @@
   { desc:   "a one property two value property-indexed keyframes specification"
             + " where the first value is invalid",
     input:  { left: ["invalid", "10px"] },
-    output: [{ offset: null, computedOffset: 0, easing: "linear",
-               left: "invalid" },
+    output: [{ offset: null, computedOffset: 0, easing: "linear" },
              { offset: null, computedOffset: 1, easing: "linear",
                left: "10px" }] },
   { desc:   "a one property two value property-indexed keyframes specification"
@@ -175,8 +174,7 @@
     input:  { left: ["10px", "invalid"] },
     output: [{ offset: null, computedOffset: 0, easing: "linear",
                left: "10px" },
-             { offset: null, computedOffset: 1, easing: "linear",
-               left: "invalid" }] },
+             { offset: null, computedOffset: 1, easing: "linear" }] },
 ];
 
 var gKeyframeSequenceTests = [
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/testcommon.js b/third_party/WebKit/LayoutTests/external/wpt/web-animations/testcommon.js
index 302fb8ba1..008d424d 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/web-animations/testcommon.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/web-animations/testcommon.js
@@ -78,7 +78,8 @@
 // Create a pseudo element
 function createPseudo(test, type) {
   createStyle(test, { '@keyframes anim': '',
-                      ['.pseudo::' + type]: 'animation: anim 10s;' });
+                      ['.pseudo::' + type]: 'animation: anim 10s; ' +
+                                            'content: \'\';'  });
   var div = createDiv(test);
   div.classList.add('pseudo');
   var anims = document.getAnimations();
@@ -238,6 +239,6 @@
     'dimension of the matrix: ' + description);
   for (var i = 0; i < actualMatrixArray.length; i++) {
     assert_approx_equals(actualMatrixArray[i], expectedMatrixArray[i], 0.0001,
-      'expecetd ' + expected + ' but got ' + actual + ": " + description);
+      'expected ' + expected + ' but got ' + actual + ": " + description);
   }
 }
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-display-contents-crash-expected.txt b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-display-contents-crash-expected.txt
new file mode 100644
index 0000000..88e5335
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-display-contents-crash-expected.txt
@@ -0,0 +1 @@
+Shouldn't crash.
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-display-contents-crash.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-display-contents-crash.html
new file mode 100644
index 0000000..0623be38
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-display-contents-crash.html
@@ -0,0 +1,13 @@
+<div style="display: contents"><a href="#"></a></div>
+Shouldn't crash.
+<script>
+testRunner.dumpAsText();
+testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
+testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+
+function runTest() {
+  eventSender.keyDown("ArrowLeft");
+}
+
+window.onload = runTest;
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/sub-pixel/input-caret-on-subpixel-bound-expected.html b/third_party/WebKit/LayoutTests/fast/sub-pixel/input-caret-on-subpixel-bound-expected.html
index 93a2148c..4c24240 100644
--- a/third_party/WebKit/LayoutTests/fast/sub-pixel/input-caret-on-subpixel-bound-expected.html
+++ b/third_party/WebKit/LayoutTests/fast/sub-pixel/input-caret-on-subpixel-bound-expected.html
@@ -7,10 +7,10 @@
           font-family: sans-serif;
       }
       table {
-          padding: 2px 3px 3px 2px;
+          padding: 2px 2px 2px 2px;
       }
       input {
-          padding: 6px 6px 5px 5px;
+          padding: 5px 6px 6px 5px;
       }
     </style>
   </head>
diff --git a/third_party/WebKit/LayoutTests/fast/table/table-in-table-percent-width-collapsing-border-expected.png b/third_party/WebKit/LayoutTests/fast/table/table-in-table-percent-width-collapsing-border-expected.png
index 78ba1ba..04272d5 100644
--- a/third_party/WebKit/LayoutTests/fast/table/table-in-table-percent-width-collapsing-border-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/table/table-in-table-percent-width-collapsing-border-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/table/table-in-table-percent-width-collapsing-border-quirks-mode-expected.png b/third_party/WebKit/LayoutTests/fast/table/table-in-table-percent-width-collapsing-border-quirks-mode-expected.png
index 78ba1ba..04272d5 100644
--- a/third_party/WebKit/LayoutTests/fast/table/table-in-table-percent-width-collapsing-border-quirks-mode-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/table/table-in-table-percent-width-collapsing-border-quirks-mode-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/application-panel/resources-panel-resource-preview-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector/application-panel/resources-panel-resource-preview-expected.txt
new file mode 100644
index 0000000..5b5d1b6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/application-panel/resources-panel-resource-preview-expected.txt
@@ -0,0 +1,120 @@
+Tests Application Panel preview for resources of different types.
+
+
+Initial state:
+Application
+  Manifest (selected)
+  Service Workers
+  Clear storage
+Storage
+  Local Storage
+    http://127.0.0.1:8000
+  Session Storage
+    http://127.0.0.1:8000
+  IndexedDB
+  Web SQL
+  Cookies
+    http://127.0.0.1:8000
+Cache
+  Cache Storage
+  Application Cache
+Frames
+  top
+    Images
+      image.png
+    Scripts
+      console-test.js
+      indexeddb-test.js
+      inspector-test.js
+      json-value.js
+      resources-test.js
+    resources-panel-resource-preview.html
+log: visible view: unknown
+Revealed json-value.js:
+Application
+  Manifest
+  Service Workers
+  Clear storage
+Storage
+  Local Storage
+    http://127.0.0.1:8000
+  Session Storage
+    http://127.0.0.1:8000
+  IndexedDB
+  Web SQL
+  Cookies
+    http://127.0.0.1:8000
+Cache
+  Cache Storage
+  Application Cache
+Frames
+  top
+    Images
+      image.png
+    Scripts
+      console-test.js
+      indexeddb-test.js
+      inspector-test.js
+      json-value.js (selected)
+      resources-test.js
+    resources-panel-resource-preview.html
+log: visible view: json
+Revealed image.png:
+Application
+  Manifest
+  Service Workers
+  Clear storage
+Storage
+  Local Storage
+    http://127.0.0.1:8000
+  Session Storage
+    http://127.0.0.1:8000
+  IndexedDB
+  Web SQL
+  Cookies
+    http://127.0.0.1:8000
+Cache
+  Cache Storage
+  Application Cache
+Frames
+  top
+    Images
+      image.png (selected)
+    Scripts
+      console-test.js
+      indexeddb-test.js
+      inspector-test.js
+      json-value.js
+      resources-test.js
+    resources-panel-resource-preview.html
+log: visible view: image
+Revealed resources-panel-resource-preview.html:
+Application
+  Manifest
+  Service Workers
+  Clear storage
+Storage
+  Local Storage
+    http://127.0.0.1:8000
+  Session Storage
+    http://127.0.0.1:8000
+  IndexedDB
+  Web SQL
+  Cookies
+    http://127.0.0.1:8000
+Cache
+  Cache Storage
+  Application Cache
+Frames
+  top
+    Images
+      image.png
+    Scripts
+      console-test.js
+      indexeddb-test.js
+      inspector-test.js
+      json-value.js
+      resources-test.js
+    resources-panel-resource-preview.html (selected)
+log: visible view: source
+
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/application-panel/resources-panel-resource-preview.html b/third_party/WebKit/LayoutTests/http/tests/inspector/application-panel/resources-panel-resource-preview.html
new file mode 100644
index 0000000..0c23df6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/application-panel/resources-panel-resource-preview.html
@@ -0,0 +1,82 @@
+<html>
+<head>
+<script>
+function parse(val) {
+    // This is here for the JSON file imported via the script tag below
+}
+</script>
+<script src="../inspector-test.js"></script>
+<script src="../resources-test.js"></script>
+<script src="../console-test.js"></script>
+<script src="../resources/json-value.js"></script>
+<script src="../indexeddb/indexeddb-test.js"></script>
+<script>
+
+async function test()
+{
+
+    function dump(node, prefix)
+    {
+        for (var child of node.children()) {
+            InspectorTest.addResult(prefix + child.listItemElement.textContent + (child.selected ? " (selected)" : ""));
+            dump(child, prefix + '  ');
+        }
+    }
+
+    function dumpCurrentState(label) {
+        var types = new Map([
+            [SourceFrame.ResourceSourceFrame, 'source'],
+            [SourceFrame.ImageView, 'image'],
+            [SourceFrame.JSONView, 'json']
+        ]);
+
+        var view = UI.panels.resources;
+        InspectorTest.addResult(label);
+        dump(view._sidebar._sidebarTree.rootElement(), '');
+        var visibleView = view.visibleView;
+        if (visibleView instanceof UI.SearchableView)
+            visibleView = visibleView.children()[0];
+        var typeLabel = 'unknown';
+        for (var type of types) {
+            if (!(visibleView instanceof type[0]))
+                continue;
+            typeLabel = type[1];
+            break;
+        }
+        console.log('visible view: ' + typeLabel);
+    }
+
+    async function revealResourceWithDisplayName(name) {
+        var target = SDK.targetManager.mainTarget();
+        var model = target.model(SDK.ResourceTreeModel);
+        var resource = null;
+        for (var r of model.mainFrame.resources()) {
+            if (r.displayName !== name)
+                continue
+            resource = r;
+            break;
+        }
+
+        if (!r) {
+            InspectorTest.addResult(name + ' was not found');
+            return;
+        }
+        await Common.Revealer.revealPromise(r);
+        dumpCurrentState('Revealed ' + name + ':');
+    }
+
+    UI.viewManager.showView('resources');
+    dumpCurrentState('Initial state:');
+    await revealResourceWithDisplayName('json-value.js');
+    await revealResourceWithDisplayName('image.png');
+    await revealResourceWithDisplayName('resources-panel-resource-preview.html');
+
+    InspectorTest.completeTest();
+}
+</script>
+</head>
+<body onload="runTest()">
+<p>Tests Application Panel preview for resources of different types.</p>
+<img src="../resources/image.png">
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/resources/image.png b/third_party/WebKit/LayoutTests/http/tests/inspector/resources/image.png
new file mode 100644
index 0000000..20b256e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/resources/image.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/resources/json-value.js b/third_party/WebKit/LayoutTests/http/tests/inspector/resources/json-value.js
new file mode 100644
index 0000000..374ae14
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/resources/json-value.js
@@ -0,0 +1 @@
+parse({"a": 1, "b": 3})
diff --git a/third_party/WebKit/LayoutTests/http/tests/sendbeacon/beacon-cross-origin-redirect-expected.txt b/third_party/WebKit/LayoutTests/http/tests/sendbeacon/beacon-cross-origin-redirect-expected.txt
index 6579136bb..369c773 100644
--- a/third_party/WebKit/LayoutTests/http/tests/sendbeacon/beacon-cross-origin-redirect-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/sendbeacon/beacon-cross-origin-redirect-expected.txt
@@ -1,4 +1,5 @@
 PingLoader dispatched to 'http://127.0.0.1:8080/resources/redirection-response.php?status=302&target=/non-existent.php'.
+CONSOLE ERROR: Redirect from 'http://127.0.0.1:8080/resources/redirection-response.php?status=302&target=/non-existent.php' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
 Verifying that navigator.sendBeacon() to non-CORS cross-origin redirect fails.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
diff --git a/third_party/WebKit/LayoutTests/http/tests/sendbeacon/resources/save-beacon.php b/third_party/WebKit/LayoutTests/http/tests/sendbeacon/resources/save-beacon.php
index 1888c93..bf71ba4a 100644
--- a/third_party/WebKit/LayoutTests/http/tests/sendbeacon/resources/save-beacon.php
+++ b/third_party/WebKit/LayoutTests/http/tests/sendbeacon/resources/save-beacon.php
@@ -37,4 +37,6 @@
   foreach ($_COOKIE as $name => $value)
       setcookie($name, "deleted", time() - 60, "/");
 }
+header('Access-Control-Allow-Origin: http://127.0.0.1:8000');
+header('Access-Control-Allow-Credentials: true');
 ?>
diff --git a/third_party/WebKit/LayoutTests/fast/text-autosizing/narrow-iframe-expected.html b/third_party/WebKit/LayoutTests/http/tests/text-autosizing/narrow-iframe-expected.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/fast/text-autosizing/narrow-iframe-expected.html
rename to third_party/WebKit/LayoutTests/http/tests/text-autosizing/narrow-iframe-expected.html
diff --git a/third_party/WebKit/LayoutTests/http/tests/text-autosizing/narrow-iframe.html b/third_party/WebKit/LayoutTests/http/tests/text-autosizing/narrow-iframe.html
new file mode 100644
index 0000000..5f4009f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/text-autosizing/narrow-iframe.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta name="viewport" content="width=800">
+<style>
+body { width: 800px; margin: 0; }
+</style>
+<script src="resources/autosizingTest.js"></script>
+</head>
+<body>
+  <iframe
+      style="width: 100%; height: 300px; border: 0"
+      src="http://localhost:8000/text-autosizing/resources/narrow-iframe.html">
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/text-autosizing/resources/autosizingTest.js b/third_party/WebKit/LayoutTests/http/tests/text-autosizing/resources/autosizingTest.js
new file mode 100644
index 0000000..f0e30d18
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/text-autosizing/resources/autosizingTest.js
@@ -0,0 +1,24 @@
+function setWindowSizeOverride(width, height) {
+    if (window.internals)
+        window.internals.settings.setTextAutosizingWindowSizeOverride(width, height);
+}
+
+function setFontScaleFactor(scale) {
+    if (window.internals)
+        window.internals.settings.setAccessibilityFontScaleFactor(scale);
+}
+
+function initAutosizingTest() {
+    if (window.internals) {
+        window.internals.settings.setTextAutosizingEnabled(true);
+        setWindowSizeOverride(320, 480);
+    } else if (window.console && console.warn) {
+        console.warn("This test depends on Text Autosizing being enabled. Run with content shell "
+                + "and --run-layout-test or manually enable Text Autosizing and either use a "
+                + "mobile device with 320px device-width (like Nexus S or iPhone), or define "
+                + "DEBUG_TEXT_AUTOSIZING_ON_DESKTOP.");
+    }
+}
+
+// Automatically call init. Users who want a different window size can use setWindowSizeOverride.
+initAutosizingTest();
diff --git a/third_party/WebKit/LayoutTests/fast/text-autosizing/narrow-iframe.html b/third_party/WebKit/LayoutTests/http/tests/text-autosizing/resources/narrow-iframe.html
similarity index 72%
rename from third_party/WebKit/LayoutTests/fast/text-autosizing/narrow-iframe.html
rename to third_party/WebKit/LayoutTests/http/tests/text-autosizing/resources/narrow-iframe.html
index 2dfeacd..d821e82 100644
--- a/third_party/WebKit/LayoutTests/fast/text-autosizing/narrow-iframe.html
+++ b/third_party/WebKit/LayoutTests/http/tests/text-autosizing/resources/narrow-iframe.html
@@ -1,17 +1,5 @@
 <!DOCTYPE html>
-<html>
-<head>
-<meta name="viewport" content="width=800">
-<style>
-body { width: 800px; margin: 0; }
-</style>
-<script src="resources/autosizingTest.js"></script>
-</head>
-<body>
-<iframe style="width: 100%; height: 300px; border: 0" src='data:text/html,
 <html style="font-size: 16px"><body style="margin: 0; overflow-y: hidden"><div style="width: 400px">
 This text should be autosized to just 20px computed font size, i.e. scaled up by 1.25x, since although this block is in an 800px wide iframe, it is in a 400px block and 400 / 320 = 1.25.<br>
 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
-</div></body></html>'>
-</body>
-</html>
+</div></body></html>
diff --git a/third_party/WebKit/LayoutTests/fast/text-autosizing/wide-iframe.html b/third_party/WebKit/LayoutTests/http/tests/text-autosizing/resources/wide-iframe.html
similarity index 80%
rename from third_party/WebKit/LayoutTests/fast/text-autosizing/wide-iframe.html
rename to third_party/WebKit/LayoutTests/http/tests/text-autosizing/resources/wide-iframe.html
index b966107c..189f317 100644
--- a/third_party/WebKit/LayoutTests/fast/text-autosizing/wide-iframe.html
+++ b/third_party/WebKit/LayoutTests/http/tests/text-autosizing/resources/wide-iframe.html
@@ -1,22 +1,5 @@
 <!DOCTYPE html>
-<html>
-<head>
-
-<meta name="viewport" content="width=800">
-<style>
-body { width: 800px; margin: 0; }
-</style>
-
-<script src="resources/autosizingTest.js"></script>
-
-</head>
-<body>
-
-<iframe style="width: 3200px; height: 50%; border: 0" src='data:text/html,
 <html style="font-size: 16px"><body style="margin: 0; overflow-y: hidden"><div style="width: 1600px">
 This text should be autosized to just 40px computed font size, i.e. scaled up by 2.5x, since although this block is 1600px wide and is in a 3200px wide iframe, the top level frame is only 800px wide, and min(1600, 3200, 800) / 320 = 2.5.<br>
 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
-</div></body></html>'>
-
-</body>
-</html>
+</div></body></html>
diff --git a/third_party/WebKit/LayoutTests/fast/text-autosizing/wide-iframe-expected.html b/third_party/WebKit/LayoutTests/http/tests/text-autosizing/wide-iframe-expected.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/fast/text-autosizing/wide-iframe-expected.html
rename to third_party/WebKit/LayoutTests/http/tests/text-autosizing/wide-iframe-expected.html
diff --git a/third_party/WebKit/LayoutTests/http/tests/text-autosizing/wide-iframe.html b/third_party/WebKit/LayoutTests/http/tests/text-autosizing/wide-iframe.html
new file mode 100644
index 0000000..b9c71ed
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/text-autosizing/wide-iframe.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+
+<meta name="viewport" content="width=800">
+<style>
+body { width: 800px; margin: 0; }
+</style>
+
+<script src="resources/autosizingTest.js"></script>
+
+</head>
+<body>
+
+  <iframe
+      style="width: 3200px; height: 50%; border: 0"
+      src="http://localhost:8000/text-autosizing/resources/wide-iframe.html">
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/xmlhttprequest-overridemimetype-content-type-header-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/xmlhttprequest-overridemimetype-content-type-header-expected.txt
index 0fbe1e8..880b205 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/xmlhttprequest-overridemimetype-content-type-header-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/xmlhttprequest-overridemimetype-content-type-header-expected.txt
@@ -1,9 +1,9 @@
-This tests that XMLHttpRequest overrideMimeType() properly updates the Content-Type header for the response.
+This tests that XMLHttpRequest overrideMimeType() does not update the Content-Type header for the response.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
-PASS xhr.getResponseHeader("Content-Type") is "text/xml;charset=GBK"
+PASS xhr.getResponseHeader("Content-Type") is "application/xml"
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/xmlhttprequest-overridemimetype-content-type-header.html b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/xmlhttprequest-overridemimetype-content-type-header.html
index 087fccb0..e220bcc 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/xmlhttprequest-overridemimetype-content-type-header.html
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/xmlhttprequest-overridemimetype-content-type-header.html
@@ -5,7 +5,7 @@
 </head>
 <body>
     <script>
-        description('This tests that XMLHttpRequest overrideMimeType() properly updates the Content-Type header for the response.');
+        description('This tests that XMLHttpRequest overrideMimeType() does not update the Content-Type header for the response.');
         window.jsTestIsAsync = true;
 
         var xhr = new XMLHttpRequest();
@@ -13,7 +13,7 @@
 
         xhr.onreadystatechange = function () {
             if (xhr.readyState == xhr.LOADING) {
-                shouldBe('xhr.getResponseHeader("Content-Type")', '"text/xml;charset=GBK"');
+                shouldBe('xhr.getResponseHeader("Content-Type")', '"application/xml"');
                 finishJSTest();
             }
         }
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/emulation/default-background-color-cleared.html b/third_party/WebKit/LayoutTests/inspector-protocol/emulation/default-background-color-cleared.html
deleted file mode 100644
index 0d15809d..0000000
--- a/third_party/WebKit/LayoutTests/inspector-protocol/emulation/default-background-color-cleared.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<html>
-<head>
-
-<style>
-html {
-    margin: 0;
-}
-</style>
-
-<script src="../../http/tests/inspector-protocol/resources/inspector-protocol-test.js"></script>
-
-<script>
-function test()
-{
-    InspectorTest.sendCommand("Runtime.evaluate", { "expression": "testRunner.dumpAsTextWithPixelResults();"} );
-
-    InspectorTest.sendCommand("Emulation.setDefaultBackgroundColorOverride", { "color": { "r": 0x12, "g": 0x34, "b": 0x56, "a": 1.0 } }, backgroundColorSet);
-
-    function backgroundColorSet(messageObject) {
-      if (!!messageObject.result.exceptionDetails)
-        InspectorTest.log("FAIL: unexpected exception: " + JSON.stringify(messageObject, null, 2));
-      InspectorTest.sendCommand("Emulation.setDefaultBackgroundColorOverride", {}, backgroundColorCleared);
-    }
-
-    function backgroundColorCleared(messageObject) {
-      if (!!messageObject.result.exceptionDetails)
-          InspectorTest.log("FAIL: unexpected exception: " + JSON.stringify(messageObject, null, 2));
-
-      // Complete the test without closing the inspector, so that the override stays active for the picture.
-      InspectorTest.sendCommand("Runtime.evaluate", { "expression": "testRunner.notifyDone();"} );
-    }
-}
-</script>
-
-</head>
-<body onload="runTest()">
-<p>
-Tests that resetting Emulation.setDefaultBackgroundColorOverride clears the background color override.
-</p>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/emulation/default-background-color.html b/third_party/WebKit/LayoutTests/inspector-protocol/emulation/default-background-color.html
deleted file mode 100644
index 1e85566..0000000
--- a/third_party/WebKit/LayoutTests/inspector-protocol/emulation/default-background-color.html
+++ /dev/null
@@ -1,35 +0,0 @@
-<html>
-<head>
-
-<style>
-html {
-    margin: 0;
-}
-</style>
-
-<script src="../../http/tests/inspector-protocol/resources/inspector-protocol-test.js"></script>
-
-<script>
-function test()
-{
-    InspectorTest.sendCommand("Runtime.evaluate", { "expression": "testRunner.dumpAsTextWithPixelResults();"} );
-
-    InspectorTest.sendCommand("Emulation.setDefaultBackgroundColorOverride", { "color": { "r": 0x12, "g": 0x34, "b": 0x56, "a": 1.0 } }, backgroundColorSet);
-
-    function backgroundColorSet(messageObject) {
-      if (!!messageObject.result.exceptionDetails)
-          InspectorTest.log("FAIL: unexpected exception: " + JSON.stringify(messageObject, null, 2));
-
-      // Complete the test without closing the inspector, so that the override stays active for the picture.
-      InspectorTest.sendCommand("Runtime.evaluate", { "expression": "testRunner.notifyDone();"} );
-    }
-}
-</script>
-
-</head>
-<body onload="runTest()">
-<p>
-Tests that Emulation.setDefaultBackgroundColorOverride changes the background color of a page that does not specify one.
-</p>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/emulation/forced-viewport-unobserved.html b/third_party/WebKit/LayoutTests/inspector-protocol/emulation/forced-viewport-unobserved.html
deleted file mode 100644
index 4085fcd..0000000
--- a/third_party/WebKit/LayoutTests/inspector-protocol/emulation/forced-viewport-unobserved.html
+++ /dev/null
@@ -1,47 +0,0 @@
-<html>
-<head>
-
-<script src="../../http/tests/inspector-protocol/resources/inspector-protocol-test.js"></script>
-
-<style>
-html {
-    overflow: hidden;
-}
-
-body {
-    margin: 0;
-    min-height: 1000px;
-    overflow: hidden;
-}
-
-#long {
-    height: 2000px;
-    width: 100px;
-    background-color: green;
-}
-</style>
-
-<script>
-function test()
-{
-    InspectorTest.sendCommand("Emulation.forceViewport", { "x": 200, "y": 200, "scale": 2.0 }, overrideActive);
-
-    function overrideActive()
-    {
-        InspectorTest.log("innerWidth = " + window.innerWidth);
-        InspectorTest.log("innerHeight = " + window.innerHeight);
-        InspectorTest.log("scrollLeft = " + document.scrollingElement.scrollLeft);
-        InspectorTest.log("scrollTop = " + document.scrollingElement.scrollTop);
-        InspectorTest.completeTest();
-    }
-}
-</script>
-
-</head>
-<body onload="runTest()">
-<p>
-Tests that a forced viewport does not change metrics that are observable by the page.
-</p>
-<div id="long"></div>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/emulation/default-background-color-cleared-expected.html b/third_party/WebKit/LayoutTests/inspector/device-mode/default-background-color-cleared-expected.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector-protocol/emulation/default-background-color-cleared-expected.html
rename to third_party/WebKit/LayoutTests/inspector/device-mode/default-background-color-cleared-expected.html
diff --git a/third_party/WebKit/LayoutTests/inspector/device-mode/default-background-color-cleared.html b/third_party/WebKit/LayoutTests/inspector/device-mode/default-background-color-cleared.html
new file mode 100644
index 0000000..a4b6a12
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector/device-mode/default-background-color-cleared.html
@@ -0,0 +1,42 @@
+<html>
+<head>
+
+<style>
+html {
+    margin: 0;
+}
+</style>
+
+<script src="../../http/tests/inspector/inspector-test.js"></script>
+
+<script>
+function test()
+{
+    InspectorTest.evaluateInPage("testRunner.dumpAsTextWithPixelResults();", () => {
+        InspectorTest.EmulationAgent.invoke_setDefaultBackgroundColorOverride({color: {r: 0x12, g: 0x34, b: 0x56, a: 1.0}}).then(backgroundColorSet);
+    });
+
+    function backgroundColorSet(messageObject) {
+      if (messageObject[Protocol.Error])
+          InspectorTest.log("FAIL: unexpected exception: " + messageObject[Protocol.Error]);
+      InspectorTest.EmulationAgent.invoke_setDefaultBackgroundColorOverride({}).then(backgroundColorCleared);
+    }
+
+    function backgroundColorCleared(messageObject) {
+      if (messageObject[Protocol.Error])
+          InspectorTest.log("FAIL: unexpected exception: " + messageObject[Protocol.Error]);
+
+      // Complete the test without closing the inspector, so that the override stays active for the picture.
+      InspectorTest.flushResults();
+      InspectorTest.evaluateInPage("testRunner.notifyDone();");
+    }
+}
+</script>
+
+</head>
+<body onload="runTest()">
+<p>
+Tests that resetting Emulation.setDefaultBackgroundColorOverride clears the background color override.
+</p>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/emulation/default-background-color-expected.html b/third_party/WebKit/LayoutTests/inspector/device-mode/default-background-color-expected.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector-protocol/emulation/default-background-color-expected.html
rename to third_party/WebKit/LayoutTests/inspector/device-mode/default-background-color-expected.html
diff --git a/third_party/WebKit/LayoutTests/inspector/device-mode/default-background-color.html b/third_party/WebKit/LayoutTests/inspector/device-mode/default-background-color.html
new file mode 100644
index 0000000..16f57a4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector/device-mode/default-background-color.html
@@ -0,0 +1,36 @@
+<html>
+<head>
+
+<style>
+html {
+    margin: 0;
+}
+</style>
+
+<script src="../../http/tests/inspector/inspector-test.js"></script>
+
+<script>
+function test()
+{
+    InspectorTest.evaluateInPage("testRunner.dumpAsTextWithPixelResults();", () => {
+        InspectorTest.EmulationAgent.invoke_setDefaultBackgroundColorOverride({color: {r: 0x12, g: 0x34, b: 0x56, a: 1.0}}).then(backgroundColorSet);
+    });
+
+    function backgroundColorSet(messageObject) {
+      if (messageObject[Protocol.Error])
+          InspectorTest.log("FAIL: unexpected exception: " + messageObject[Protocol.Error]);
+
+      // Complete the test without closing the inspector, so that the override stays active for the picture.
+      InspectorTest.flushResults();
+      InspectorTest.evaluateInPage("testRunner.notifyDone();");
+    }
+}
+</script>
+
+</head>
+<body onload="runTest()">
+<p>
+Tests that Emulation.setDefaultBackgroundColorOverride changes the background color of a page that does not specify one.
+</p>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/emulation/forced-viewport-far-expected.html b/third_party/WebKit/LayoutTests/inspector/device-mode/forced-viewport-far-expected.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector-protocol/emulation/forced-viewport-far-expected.html
rename to third_party/WebKit/LayoutTests/inspector/device-mode/forced-viewport-far-expected.html
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/emulation/forced-viewport-far-layered-expected.html b/third_party/WebKit/LayoutTests/inspector/device-mode/forced-viewport-far-layered-expected.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector-protocol/emulation/forced-viewport-far-layered-expected.html
rename to third_party/WebKit/LayoutTests/inspector/device-mode/forced-viewport-far-layered-expected.html
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/emulation/forced-viewport-far-layered.html b/third_party/WebKit/LayoutTests/inspector/device-mode/forced-viewport-far-layered.html
similarity index 67%
rename from third_party/WebKit/LayoutTests/inspector-protocol/emulation/forced-viewport-far-layered.html
rename to third_party/WebKit/LayoutTests/inspector/device-mode/forced-viewport-far-layered.html
index 1b7b332..c2f6913 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/emulation/forced-viewport-far-layered.html
+++ b/third_party/WebKit/LayoutTests/inspector/device-mode/forced-viewport-far-layered.html
@@ -1,7 +1,7 @@
 <html>
 <head>
 
-<script src="../../http/tests/inspector-protocol/resources/inspector-protocol-test.js"></script>
+<script src="../../http/tests/inspector/inspector-test.js"></script>
 
 <style>
 html {
@@ -37,14 +37,15 @@
 <script>
 function test()
 {
-    InspectorTest.sendCommand("Runtime.evaluate", { "expression": "testRunner.dumpAsTextWithPixelResults();"} );
-
-    InspectorTest.sendCommand("Emulation.forceViewport", { "x": 200, "y": 9000, "scale": 2.0 }, overrideActive);
+    InspectorTest.evaluateInPage("testRunner.dumpAsTextWithPixelResults();", () => {
+        InspectorTest.EmulationAgent.invoke_forceViewport({x: 200, y: 9000, scale: 2.0}).then(overrideActive);
+    });
 
     function overrideActive(msg)
     {
         // Complete the test without closing the inspector, so that the override stays active for the picture.
-        InspectorTest.sendCommand("Runtime.evaluate", { "expression": "testRunner.notifyDone();"} );
+        InspectorTest.flushResults();
+        InspectorTest.evaluateInPage("testRunner.notifyDone();");
     }
 }
 </script>
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/emulation/forced-viewport-far.html b/third_party/WebKit/LayoutTests/inspector/device-mode/forced-viewport-far.html
similarity index 65%
rename from third_party/WebKit/LayoutTests/inspector-protocol/emulation/forced-viewport-far.html
rename to third_party/WebKit/LayoutTests/inspector/device-mode/forced-viewport-far.html
index e20589c..0dd1717 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/emulation/forced-viewport-far.html
+++ b/third_party/WebKit/LayoutTests/inspector/device-mode/forced-viewport-far.html
@@ -1,7 +1,7 @@
 <html>
 <head>
 
-<script src="../../http/tests/inspector-protocol/resources/inspector-protocol-test.js"></script>
+<script src="../../http/tests/inspector/inspector-test.js"></script>
 
 <style>
 html {
@@ -36,14 +36,15 @@
 <script>
 function test()
 {
-    InspectorTest.sendCommand("Runtime.evaluate", { "expression": "testRunner.dumpAsTextWithPixelResults();"} );
-
-    InspectorTest.sendCommand("Emulation.forceViewport", { "x": 200, "y": 9000, "scale": 2.0 }, overrideActive);
+    InspectorTest.evaluateInPage("testRunner.dumpAsTextWithPixelResults();", () => {
+        InspectorTest.EmulationAgent.invoke_forceViewport({x: 200, y: 9000, scale: 2.0}).then(overrideActive);
+    });
 
     function overrideActive(msg)
     {
         // Complete the test without closing the inspector, so that the override stays active for the picture.
-        InspectorTest.sendCommand("Runtime.evaluate", { "expression": "testRunner.notifyDone();"} );
+        InspectorTest.flushResults();
+        InspectorTest.evaluateInPage("testRunner.notifyDone();");
     }
 }
 </script>
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/emulation/forced-viewport-near-expected.html b/third_party/WebKit/LayoutTests/inspector/device-mode/forced-viewport-near-expected.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector-protocol/emulation/forced-viewport-near-expected.html
rename to third_party/WebKit/LayoutTests/inspector/device-mode/forced-viewport-near-expected.html
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/emulation/forced-viewport-near.html b/third_party/WebKit/LayoutTests/inspector/device-mode/forced-viewport-near.html
similarity index 63%
rename from third_party/WebKit/LayoutTests/inspector-protocol/emulation/forced-viewport-near.html
rename to third_party/WebKit/LayoutTests/inspector/device-mode/forced-viewport-near.html
index ff228e9..811b629c 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/emulation/forced-viewport-near.html
+++ b/third_party/WebKit/LayoutTests/inspector/device-mode/forced-viewport-near.html
@@ -1,7 +1,7 @@
 <html>
 <head>
 
-<script src="../../http/tests/inspector-protocol/resources/inspector-protocol-test.js"></script>
+<script src="../../http/tests/inspector/inspector-test.js"></script>
 
 <style>
 html {
@@ -36,19 +36,20 @@
 <script>
 function test()
 {
-    InspectorTest.sendCommand("Runtime.evaluate", { "expression": "testRunner.dumpAsTextWithPixelResults();"} );
-
-    InspectorTest.sendCommand("Emulation.forceViewport", { "x": 100, "y": 100, "scale": 1.0 }, firstOverrideActive);
+    InspectorTest.evaluateInPage("testRunner.dumpAsTextWithPixelResults();", () => {
+        InspectorTest.EmulationAgent.invoke_forceViewport({x: 100, y: 100, scale: 1.0}).then(firstOverrideActive);
+    });
 
     function firstOverrideActive()
     {
-        InspectorTest.sendCommand("Emulation.forceViewport", { "x": 200, "y": 200, "scale": 2.0 }, secondOverrideActive);
+        InspectorTest.EmulationAgent.invoke_forceViewport({x: 200, y: 200, scale: 2.0}).then(secondOverrideActive);
     }
 
     function secondOverrideActive()
     {
         // Complete the test without closing the inspector, so that the override stays active for the picture.
-        InspectorTest.sendCommand("Runtime.evaluate", { "expression": "testRunner.notifyDone();"} );
+        InspectorTest.flushResults();
+        InspectorTest.evaluateInPage("testRunner.notifyDone();");
     }
 }
 </script>
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/emulation/forced-viewport-reset-expected.html b/third_party/WebKit/LayoutTests/inspector/device-mode/forced-viewport-reset-expected.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector-protocol/emulation/forced-viewport-reset-expected.html
rename to third_party/WebKit/LayoutTests/inspector/device-mode/forced-viewport-reset-expected.html
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/emulation/forced-viewport-reset.html b/third_party/WebKit/LayoutTests/inspector/device-mode/forced-viewport-reset.html
similarity index 62%
rename from third_party/WebKit/LayoutTests/inspector-protocol/emulation/forced-viewport-reset.html
rename to third_party/WebKit/LayoutTests/inspector/device-mode/forced-viewport-reset.html
index 55f5b30..83bdf04 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/emulation/forced-viewport-reset.html
+++ b/third_party/WebKit/LayoutTests/inspector/device-mode/forced-viewport-reset.html
@@ -1,7 +1,7 @@
 <html>
 <head>
 
-<script src="../../http/tests/inspector-protocol/resources/inspector-protocol-test.js"></script>
+<script src="../../http/tests/inspector/inspector-test.js"></script>
 
 <style>
 html {
@@ -36,19 +36,20 @@
 <script>
 function test()
 {
-    InspectorTest.sendCommand("Runtime.evaluate", { "expression": "testRunner.dumpAsTextWithPixelResults();"} );
-
-    InspectorTest.sendCommand("Emulation.forceViewport", { "x": 200, "y": 9000, "scale": 2.0 }, overrideActive);
+    InspectorTest.evaluateInPage("testRunner.dumpAsTextWithPixelResults();", () => {
+        InspectorTest.EmulationAgent.invoke_forceViewport({x: 200, y: 9000, scale: 2.0}).then(overrideActive);
+    });
 
     function overrideActive()
     {
-        InspectorTest.sendCommand("Emulation.resetViewport", {}, overrideCleared);
+        InspectorTest.EmulationAgent.invoke_resetViewport({}).then(overrideCleared);
     }
     
     function overrideCleared()
     {
         // Complete the test without closing the inspector, so that the override stays active for the picture.
-        InspectorTest.sendCommand("Runtime.evaluate", { "expression": "testRunner.notifyDone();"} );
+        InspectorTest.flushResults();
+        InspectorTest.evaluateInPage("testRunner.notifyDone();");
     }
 }
 </script>
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/emulation/forced-viewport-unobserved-expected.txt b/third_party/WebKit/LayoutTests/inspector/device-mode/forced-viewport-unobserved-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector-protocol/emulation/forced-viewport-unobserved-expected.txt
rename to third_party/WebKit/LayoutTests/inspector/device-mode/forced-viewport-unobserved-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/device-mode/forced-viewport-unobserved.html b/third_party/WebKit/LayoutTests/inspector/device-mode/forced-viewport-unobserved.html
new file mode 100644
index 0000000..d012680
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector/device-mode/forced-viewport-unobserved.html
@@ -0,0 +1,63 @@
+<html>
+<head>
+
+<script src="../../http/tests/inspector/inspector-test.js"></script>
+
+<style>
+html {
+    overflow: hidden;
+}
+
+body {
+    margin: 0;
+    min-height: 1000px;
+    overflow: hidden;
+}
+
+#long {
+    height: 2000px;
+    width: 100px;
+    background-color: green;
+}
+</style>
+
+<script>
+function dump()
+{
+  return {
+      w: window.innerWidth,
+      h: window.innerHeight,
+      l: document.documentElement.scrollLeft,
+      t: document.documentElement.scrollTop
+  };
+}
+
+function test()
+{
+    InspectorTest.EmulationAgent.invoke_forceViewport({x: 200, y: 200, scale: 2.0 }).then(overrideActive);
+
+    function overrideActive()
+    {
+        InspectorTest.RuntimeAgent.invoke_evaluate({expression: 'dump()', returnByValue: true}).then(gotResult);
+    }
+
+    function gotResult(result)
+    {
+        var values = result.result.value;
+        InspectorTest.addResult("innerWidth = " + values.w);
+        InspectorTest.addResult("innerHeight = " + values.h);
+        InspectorTest.addResult("scrollLeft = " + values.l);
+        InspectorTest.addResult("scrollTop = " + values.t);
+        InspectorTest.completeTest();
+    }
+}
+</script>
+
+</head>
+<body onload="runTest()">
+<p>
+Tests that a forced viewport does not change metrics that are observable by the page.
+</p>
+<div id="long"></div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/paint/float-painted-when-no-longer-self-painting-expected.html b/third_party/WebKit/LayoutTests/paint/float-painted-when-no-longer-self-painting-expected.html
new file mode 100644
index 0000000..7aa9bd4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/paint/float-painted-when-no-longer-self-painting-expected.html
@@ -0,0 +1,3 @@
+<!DOCTYPE html>
+<p>crbug.com/731044: Ensure float is painted.</p>
+<span>You should see this text.</span>
diff --git a/third_party/WebKit/LayoutTests/paint/float-painted-when-no-longer-self-painting.html b/third_party/WebKit/LayoutTests/paint/float-painted-when-no-longer-self-painting.html
new file mode 100644
index 0000000..41ec96fa
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/paint/float-painted-when-no-longer-self-painting.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<style>
+#header:after{content:'';display:block;clear:both}
+#test {float:left;height:70px;overflow:hidden;}
+</style>
+<p>crbug.com/731044: Ensure float is painted.
+<div>
+  <div id="header">
+    <div>
+      <div id="test">
+        <span>You should see this text.</span>
+      </div>
+    </div>
+  </div>
+</div>
+<script>
+test.style["opacity"] = .75;
+document.body.offsetTop;
+test.style["opacity"] = 100;
+</script>
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/text/chromium-linux-fontconfig-renderstyle-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/text/chromium-linux-fontconfig-renderstyle-expected.png
index 738b7c74..e3bbdd4 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/text/chromium-linux-fontconfig-renderstyle-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/text/chromium-linux-fontconfig-renderstyle-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.png
index 59f61c5..b7a8662c 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.txt
index 772f112e..71d96ef 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.txt
@@ -3,103 +3,103 @@
 layer at (0,0) size 800x339
   LayoutBlockFlow {HTML} at (0,0) size 800x339.09
     LayoutBlockFlow {BODY} at (5.55,5.55) size 788.91x328
-      LayoutTable {TABLE} at (0,0) size 460x328
-        LayoutTableSection {TBODY} at (0,0) size 460x328
-          LayoutTableRow {TR} at (0,1) size 460x14
-            LayoutTableCell {TH} at (1,1) size 64x14 [bgcolor=#DDDD99] [r=0 c=0 rs=1 cs=1]
-              LayoutText {#text} at (6,0) size 52x14
-                text run at (6,0) width 52: "viewBox?"
-            LayoutTableCell {TH} at (66,1) size 111x14 [bgcolor=#DDDD99] [r=0 c=1 rs=1 cs=1]
-              LayoutText {#text} at (0,0) size 111x14
-                text run at (0,0) width 111: "preserve\x{AD}Aspect\x{AD}Ratio"
-            LayoutTableCell {TH} at (178,1) size 140x14 [bgcolor=#DDDD99] [r=0 c=2 rs=1 cs=1]
-              LayoutText {#text} at (54,0) size 32x14
-                text run at (54,0) width 32: "<img>"
-            LayoutTableCell {TH} at (319,1) size 140x14 [bgcolor=#DDDD99] [r=0 c=3 rs=1 cs=1]
-              LayoutText {#text} at (47,0) size 46x14
-                text run at (47,0) width 46: "<object>"
-          LayoutTableRow {TR} at (0,16) size 460x38
-            LayoutTableCell {TH} at (1,86) size 64x14 [bgcolor=#DDDD99] [r=1 c=0 rs=4 cs=1]
-              LayoutText {#text} at (0,0) size 64x14
-                text run at (0,0) width 64: "No viewBox"
-            LayoutTableCell {TH} at (66,35) size 111x0 [bgcolor=#DDDD99] [r=1 c=1 rs=1 cs=1]
-            LayoutTableCell {TD} at (178,16) size 140x38 [r=1 c=2 rs=1 cs=1]
+      LayoutTable {TABLE} at (0,0) size 456x328
+        LayoutTableSection {TBODY} at (0,0) size 456x328
+          LayoutTableRow {TR} at (0,1) size 456x14
+            LayoutTableCell {TH} at (1,1) size 63x14 [bgcolor=#DDDD99] [r=0 c=0 rs=1 cs=1]
+              LayoutText {#text} at (5,0) size 53x14
+                text run at (5,0) width 53: "viewBox?"
+            LayoutTableCell {TH} at (65,1) size 110x14 [bgcolor=#DDDD99] [r=0 c=1 rs=1 cs=1]
+              LayoutText {#text} at (0,0) size 110x14
+                text run at (0,0) width 110: "preserve\x{AD}Aspect\x{AD}Ratio"
+            LayoutTableCell {TH} at (176,1) size 139x14 [bgcolor=#DDDD99] [r=0 c=2 rs=1 cs=1]
+              LayoutText {#text} at (53,0) size 33x14
+                text run at (53,0) width 33: "<img>"
+            LayoutTableCell {TH} at (316,1) size 139x14 [bgcolor=#DDDD99] [r=0 c=3 rs=1 cs=1]
+              LayoutText {#text} at (47,0) size 45x14
+                text run at (47,0) width 45: "<object>"
+          LayoutTableRow {TR} at (0,16) size 456x38
+            LayoutTableCell {TH} at (1,86) size 63x14 [bgcolor=#DDDD99] [r=1 c=0 rs=4 cs=1]
+              LayoutText {#text} at (0,0) size 63x14
+                text run at (0,0) width 63: "No viewBox"
+            LayoutTableCell {TH} at (65,35) size 110x0 [bgcolor=#DDDD99] [r=1 c=1 rs=1 cs=1]
+            LayoutTableCell {TD} at (176,16) size 139x38 [r=1 c=2 rs=1 cs=1]
               LayoutImage {IMG} at (0,0) size 138.88x34.72 [border: (1.38px dashed #800000)]
               LayoutText {#text} at (0,0) size 0x0
-            LayoutTableCell {TD} at (319,16) size 140x38 [r=1 c=3 rs=1 cs=1]
+            LayoutTableCell {TD} at (316,16) size 139x38 [r=1 c=3 rs=1 cs=1]
               LayoutText {#text} at (0,0) size 0x0
-          LayoutTableRow {TR} at (0,55) size 460x38
-            LayoutTableCell {TH} at (66,67) size 111x14 [bgcolor=#DDDD99] [r=2 c=1 rs=1 cs=1]
-              LayoutText {#text} at (42,0) size 27x14
-                text run at (42,0) width 27: "none"
-            LayoutTableCell {TD} at (178,55) size 140x38 [r=2 c=2 rs=1 cs=1]
+          LayoutTableRow {TR} at (0,55) size 456x38
+            LayoutTableCell {TH} at (65,67) size 110x14 [bgcolor=#DDDD99] [r=2 c=1 rs=1 cs=1]
+              LayoutText {#text} at (41,0) size 28x14
+                text run at (41,0) width 28: "none"
+            LayoutTableCell {TD} at (176,55) size 139x38 [r=2 c=2 rs=1 cs=1]
               LayoutImage {IMG} at (0,0) size 138.88x34.72 [border: (1.38px dashed #800000)]
               LayoutText {#text} at (0,0) size 0x0
-            LayoutTableCell {TD} at (319,55) size 140x38 [r=2 c=3 rs=1 cs=1]
+            LayoutTableCell {TD} at (316,55) size 139x38 [r=2 c=3 rs=1 cs=1]
               LayoutText {#text} at (0,0) size 0x0
-          LayoutTableRow {TR} at (0,94) size 460x38
-            LayoutTableCell {TH} at (66,106) size 111x14 [bgcolor=#DDDD99] [r=3 c=1 rs=1 cs=1]
-              LayoutText {#text} at (42,0) size 27x14
-                text run at (42,0) width 27: "meet"
-            LayoutTableCell {TD} at (178,94) size 140x38 [r=3 c=2 rs=1 cs=1]
+          LayoutTableRow {TR} at (0,94) size 456x38
+            LayoutTableCell {TH} at (65,106) size 110x14 [bgcolor=#DDDD99] [r=3 c=1 rs=1 cs=1]
+              LayoutText {#text} at (42,0) size 26x14
+                text run at (42,0) width 26: "meet"
+            LayoutTableCell {TD} at (176,94) size 139x38 [r=3 c=2 rs=1 cs=1]
               LayoutImage {IMG} at (0,0) size 138.88x34.72 [border: (1.38px dashed #800000)]
               LayoutText {#text} at (0,0) size 0x0
-            LayoutTableCell {TD} at (319,94) size 140x38 [r=3 c=3 rs=1 cs=1]
+            LayoutTableCell {TD} at (316,94) size 139x38 [r=3 c=3 rs=1 cs=1]
               LayoutText {#text} at (0,0) size 0x0
-          LayoutTableRow {TR} at (0,133) size 460x38
-            LayoutTableCell {TH} at (66,145) size 111x14 [bgcolor=#DDDD99] [r=4 c=1 rs=1 cs=1]
-              LayoutText {#text} at (43,0) size 25x14
-                text run at (43,0) width 25: "slice"
-            LayoutTableCell {TD} at (178,133) size 140x38 [r=4 c=2 rs=1 cs=1]
+          LayoutTableRow {TR} at (0,133) size 456x38
+            LayoutTableCell {TH} at (65,145) size 110x14 [bgcolor=#DDDD99] [r=4 c=1 rs=1 cs=1]
+              LayoutText {#text} at (43,0) size 24x14
+                text run at (43,0) width 24: "slice"
+            LayoutTableCell {TD} at (176,133) size 139x38 [r=4 c=2 rs=1 cs=1]
               LayoutImage {IMG} at (0,0) size 138.88x34.72 [border: (1.38px dashed #800000)]
               LayoutText {#text} at (0,0) size 0x0
-            LayoutTableCell {TD} at (319,133) size 140x38 [r=4 c=3 rs=1 cs=1]
+            LayoutTableCell {TD} at (316,133) size 139x38 [r=4 c=3 rs=1 cs=1]
               LayoutText {#text} at (0,0) size 0x0
-          LayoutTableRow {TR} at (0,172) size 460x38
-            LayoutTableCell {TH} at (1,242) size 64x14 [bgcolor=#DDDD99] [r=5 c=0 rs=4 cs=1]
-              LayoutText {#text} at (9,0) size 46x14
-                text run at (9,0) width 46: "viewBox"
-            LayoutTableCell {TH} at (66,191) size 111x0 [bgcolor=#DDDD99] [r=5 c=1 rs=1 cs=1]
-            LayoutTableCell {TD} at (178,172) size 140x38 [r=5 c=2 rs=1 cs=1]
+          LayoutTableRow {TR} at (0,172) size 456x38
+            LayoutTableCell {TH} at (1,242) size 63x14 [bgcolor=#DDDD99] [r=5 c=0 rs=4 cs=1]
+              LayoutText {#text} at (9,0) size 45x14
+                text run at (9,0) width 45: "viewBox"
+            LayoutTableCell {TH} at (65,191) size 110x0 [bgcolor=#DDDD99] [r=5 c=1 rs=1 cs=1]
+            LayoutTableCell {TD} at (176,172) size 139x38 [r=5 c=2 rs=1 cs=1]
               LayoutImage {IMG} at (0,0) size 138.88x34.72 [border: (1.38px dashed #800000)]
               LayoutText {#text} at (0,0) size 0x0
-            LayoutTableCell {TD} at (319,172) size 140x38 [r=5 c=3 rs=1 cs=1]
+            LayoutTableCell {TD} at (316,172) size 139x38 [r=5 c=3 rs=1 cs=1]
               LayoutText {#text} at (0,0) size 0x0
-          LayoutTableRow {TR} at (0,211) size 460x38
-            LayoutTableCell {TH} at (66,223) size 111x14 [bgcolor=#DDDD99] [r=6 c=1 rs=1 cs=1]
-              LayoutText {#text} at (42,0) size 27x14
-                text run at (42,0) width 27: "none"
-            LayoutTableCell {TD} at (178,211) size 140x38 [r=6 c=2 rs=1 cs=1]
+          LayoutTableRow {TR} at (0,211) size 456x38
+            LayoutTableCell {TH} at (65,223) size 110x14 [bgcolor=#DDDD99] [r=6 c=1 rs=1 cs=1]
+              LayoutText {#text} at (41,0) size 28x14
+                text run at (41,0) width 28: "none"
+            LayoutTableCell {TD} at (176,211) size 139x38 [r=6 c=2 rs=1 cs=1]
               LayoutImage {IMG} at (0,0) size 138.88x34.72 [border: (1.38px dashed #800000)]
               LayoutText {#text} at (0,0) size 0x0
-            LayoutTableCell {TD} at (319,211) size 140x38 [r=6 c=3 rs=1 cs=1]
+            LayoutTableCell {TD} at (316,211) size 139x38 [r=6 c=3 rs=1 cs=1]
               LayoutText {#text} at (0,0) size 0x0
-          LayoutTableRow {TR} at (0,250) size 460x38
-            LayoutTableCell {TH} at (66,262) size 111x14 [bgcolor=#DDDD99] [r=7 c=1 rs=1 cs=1]
-              LayoutText {#text} at (42,0) size 27x14
-                text run at (42,0) width 27: "meet"
-            LayoutTableCell {TD} at (178,250) size 140x38 [r=7 c=2 rs=1 cs=1]
+          LayoutTableRow {TR} at (0,250) size 456x38
+            LayoutTableCell {TH} at (65,262) size 110x14 [bgcolor=#DDDD99] [r=7 c=1 rs=1 cs=1]
+              LayoutText {#text} at (42,0) size 26x14
+                text run at (42,0) width 26: "meet"
+            LayoutTableCell {TD} at (176,250) size 139x38 [r=7 c=2 rs=1 cs=1]
               LayoutImage {IMG} at (0,0) size 138.88x34.72 [border: (1.38px dashed #800000)]
               LayoutText {#text} at (0,0) size 0x0
-            LayoutTableCell {TD} at (319,250) size 140x38 [r=7 c=3 rs=1 cs=1]
+            LayoutTableCell {TD} at (316,250) size 139x38 [r=7 c=3 rs=1 cs=1]
               LayoutText {#text} at (0,0) size 0x0
-          LayoutTableRow {TR} at (0,289) size 460x38
-            LayoutTableCell {TH} at (66,301) size 111x14 [bgcolor=#DDDD99] [r=8 c=1 rs=1 cs=1]
-              LayoutText {#text} at (43,0) size 25x14
-                text run at (43,0) width 25: "slice"
-            LayoutTableCell {TD} at (178,289) size 140x38 [r=8 c=2 rs=1 cs=1]
+          LayoutTableRow {TR} at (0,289) size 456x38
+            LayoutTableCell {TH} at (65,301) size 110x14 [bgcolor=#DDDD99] [r=8 c=1 rs=1 cs=1]
+              LayoutText {#text} at (43,0) size 24x14
+                text run at (43,0) width 24: "slice"
+            LayoutTableCell {TD} at (176,289) size 139x38 [r=8 c=2 rs=1 cs=1]
               LayoutImage {IMG} at (0,0) size 138.88x34.72 [border: (1.38px dashed #800000)]
               LayoutText {#text} at (0,0) size 0x0
-            LayoutTableCell {TD} at (319,289) size 140x38 [r=8 c=3 rs=1 cs=1]
+            LayoutTableCell {TD} at (316,289) size 139x38 [r=8 c=3 rs=1 cs=1]
               LayoutText {#text} at (0,0) size 0x0
-layer at (325,22) size 139x35
+layer at (322,22) size 139x35
   LayoutEmbeddedObject {OBJECT} at (0,0) size 138.88x34.72 [border: (0.69px dashed #008000)]
     layer at (0,0) size 133x29
       LayoutView at (0,0) size 133x29
     layer at (0,0) size 133x29
       LayoutSVGRoot {svg} at (0,0) size 133x29
         LayoutSVGEllipse {circle} at (0,0) size 220x220 [stroke={[type=SOLID] [color=#000000]}] [fill={[type=SOLID] [color=#D9BB7A] [fill rule=EVEN-ODD]}] [cx=110.00] [cy=110.00] [r=110.00]
-layer at (325,61) size 139x35
+layer at (322,61) size 139x35
   LayoutEmbeddedObject {OBJECT} at (0,0) size 138.88x34.72 [border: (0.69px dashed #008000)]
     layer at (0,0) size 133x29
       LayoutView at (0,0) size 133x29
@@ -108,7 +108,7 @@
         LayoutSVGHiddenContainer {defs} at (0,0) size 0x0
         LayoutSVGContainer {g} at (162.86,403.79) size 362.86x362.86 [transform={m=((1.00,0.00)(0.00,1.00)) t=(-162.36,-403.29)}]
           LayoutSVGPath {path} at (162.86,403.79) size 362.86x362.86 [stroke={[type=SOLID] [color=#000000]}] [fill={[type=SOLID] [color=#D9BB7A] [fill rule=EVEN-ODD]}] [data="M 525.714 585.219 A 181.429 181.429 0 1 1 162.857 585.219 A 181.429 181.429 0 1 1 525.714 585.219 Z"]
-layer at (325,100) size 139x35
+layer at (322,100) size 139x35
   LayoutEmbeddedObject {OBJECT} at (0,0) size 138.88x34.72 [border: (0.69px dashed #008000)]
     layer at (0,0) size 133x29
       LayoutView at (0,0) size 133x29
@@ -117,7 +117,7 @@
         LayoutSVGHiddenContainer {defs} at (0,0) size 0x0
         LayoutSVGContainer {g} at (162.86,403.79) size 362.86x362.86 [transform={m=((1.00,0.00)(0.00,1.00)) t=(-162.36,-403.29)}]
           LayoutSVGPath {path} at (162.86,403.79) size 362.86x362.86 [stroke={[type=SOLID] [color=#000000]}] [fill={[type=SOLID] [color=#D9BB7A] [fill rule=EVEN-ODD]}] [data="M 525.714 585.219 A 181.429 181.429 0 1 1 162.857 585.219 A 181.429 181.429 0 1 1 525.714 585.219 Z"]
-layer at (325,139) size 139x35
+layer at (322,139) size 139x35
   LayoutEmbeddedObject {OBJECT} at (0,0) size 138.88x34.72 [border: (0.69px dashed #008000)]
     layer at (0,0) size 133x29
       LayoutView at (0,0) size 133x29
@@ -126,7 +126,7 @@
         LayoutSVGHiddenContainer {defs} at (0,0) size 0x0
         LayoutSVGContainer {g} at (162.86,403.79) size 362.86x362.86 [transform={m=((1.00,0.00)(0.00,1.00)) t=(-162.36,-403.29)}]
           LayoutSVGPath {path} at (162.86,403.79) size 362.86x362.86 [stroke={[type=SOLID] [color=#000000]}] [fill={[type=SOLID] [color=#D9BB7A] [fill rule=EVEN-ODD]}] [data="M 525.714 585.219 A 181.429 181.429 0 1 1 162.857 585.219 A 181.429 181.429 0 1 1 525.714 585.219 Z"]
-layer at (325,178) size 139x35
+layer at (322,178) size 139x35
   LayoutEmbeddedObject {OBJECT} at (0,0) size 138.88x34.72 [border: (0.69px dashed #008000)]
     layer at (0,0) size 133x29
       LayoutView at (0,0) size 133x29
@@ -135,7 +135,7 @@
         LayoutSVGHiddenContainer {defs} at (0,0) size 0x0
         LayoutSVGContainer {g} at (162.86,403.79) size 362.86x362.86 [transform={m=((1.00,0.00)(0.00,1.00)) t=(-162.36,-403.29)}]
           LayoutSVGPath {path} at (162.86,403.79) size 362.86x362.86 [stroke={[type=SOLID] [color=#000000]}] [fill={[type=SOLID] [color=#D9BB7A] [fill rule=EVEN-ODD]}] [data="M 525.714 585.219 A 181.429 181.429 0 1 1 162.857 585.219 A 181.429 181.429 0 1 1 525.714 585.219 Z"]
-layer at (325,217) size 139x35
+layer at (322,217) size 139x35
   LayoutEmbeddedObject {OBJECT} at (0,0) size 138.88x34.72 [border: (0.69px dashed #008000)]
     layer at (0,0) size 133x29
       LayoutView at (0,0) size 133x29
@@ -144,7 +144,7 @@
         LayoutSVGHiddenContainer {defs} at (0,0) size 0x0
         LayoutSVGContainer {g} at (162.86,403.79) size 362.86x362.86 [transform={m=((1.00,0.00)(0.00,1.00)) t=(-162.36,-403.29)}]
           LayoutSVGPath {path} at (162.86,403.79) size 362.86x362.86 [stroke={[type=SOLID] [color=#000000]}] [fill={[type=SOLID] [color=#D9BB7A] [fill rule=EVEN-ODD]}] [data="M 525.714 585.219 A 181.429 181.429 0 1 1 162.857 585.219 A 181.429 181.429 0 1 1 525.714 585.219 Z"]
-layer at (325,256) size 139x35
+layer at (322,256) size 139x35
   LayoutEmbeddedObject {OBJECT} at (0,0) size 138.88x34.72 [border: (0.69px dashed #008000)]
     layer at (0,0) size 133x29
       LayoutView at (0,0) size 133x29
@@ -153,7 +153,7 @@
         LayoutSVGHiddenContainer {defs} at (0,0) size 0x0
         LayoutSVGContainer {g} at (162.86,403.79) size 362.86x362.86 [transform={m=((1.00,0.00)(0.00,1.00)) t=(-162.36,-403.29)}]
           LayoutSVGPath {path} at (162.86,403.79) size 362.86x362.86 [stroke={[type=SOLID] [color=#000000]}] [fill={[type=SOLID] [color=#D9BB7A] [fill rule=EVEN-ODD]}] [data="M 525.714 585.219 A 181.429 181.429 0 1 1 162.857 585.219 A 181.429 181.429 0 1 1 525.714 585.219 Z"]
-layer at (325,295) size 139x35
+layer at (322,295) size 139x35
   LayoutEmbeddedObject {OBJECT} at (0,0) size 138.88x34.72 [border: (0.69px dashed #008000)]
     layer at (0,0) size 133x29
       LayoutView at (0,0) size 133x29
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.png
index f1843ef..79edb450 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.txt
index 7aae683..a6523bb 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.txt
@@ -3,32 +3,32 @@
 layer at (0,0) size 800x199
   LayoutBlockFlow {html} at (0,0) size 800x199.09
     LayoutBlockFlow {body} at (5.55,5.55) size 788.91x188
-      LayoutTable {table} at (142.45,0) size 504x188
-        LayoutTableSection (anonymous) at (0,0) size 504x188
-          LayoutTableRow {tr} at (0,0) size 504x188
-            LayoutTableCell {td} at (0,0) size 504x188 [r=0 c=0 rs=1 cs=3]
-              LayoutTable {table} at (7.44,6) size 491x176
-                LayoutTableSection (anonymous) at (0,0) size 491x176
-                  LayoutTableRow {tr} at (0,1) size 491x66
-                    LayoutTableCell {td} at (1,1) size 489x65.75 [r=0 c=0 rs=1 cs=2]
-                      LayoutBlockFlow {h1} at (5.55,19.88) size 479x26
-                        LayoutText {#text} at (0,0) size 479x25
-                          text run at (0,0) width 479: "Both sides should have identical size after zooming"
-                  LayoutTableRow {tr} at (0,68) size 491x24
-                    LayoutTableCell {td} at (1,68) size 244x24 [r=1 c=0 rs=1 cs=1]
-                      LayoutText {#text} at (95,5) size 54x14
-                        text run at (95,5) width 54: "SVG Image"
-                    LayoutTableCell {td} at (246,68) size 244x24 [r=1 c=1 rs=1 cs=1]
+      LayoutTable {table} at (143.45,0) size 502x188
+        LayoutTableSection (anonymous) at (0,0) size 502x188
+          LayoutTableRow {tr} at (0,0) size 502x188
+            LayoutTableCell {td} at (0,0) size 502x188 [r=0 c=0 rs=1 cs=3]
+              LayoutTable {table} at (6,6) size 490x176
+                LayoutTableSection (anonymous) at (0,0) size 490x176
+                  LayoutTableRow {tr} at (0,1) size 490x66
+                    LayoutTableCell {td} at (1,1) size 488x65.75 [r=0 c=0 rs=1 cs=2]
+                      LayoutBlockFlow {h1} at (5,19.88) size 478x26
+                        LayoutText {#text} at (0,0) size 478x25
+                          text run at (0,0) width 478: "Both sides should have identical size after zooming"
+                  LayoutTableRow {tr} at (0,68) size 490x24
+                    LayoutTableCell {td} at (1,68) size 243x24 [r=1 c=0 rs=1 cs=1]
+                      LayoutText {#text} at (94,5) size 55x14
+                        text run at (94,5) width 55: "SVG Image"
+                    LayoutTableCell {td} at (245,68) size 244x24 [r=1 c=1 rs=1 cs=1]
                       LayoutText {#text} at (95,5) size 54x14
                         text run at (95,5) width 54: "PNG Image"
-                  LayoutTableRow {tr} at (0,93) size 491x82
-                    LayoutTableCell {td} at (1,93) size 244x82 [r=2 c=0 rs=1 cs=1]
+                  LayoutTableRow {tr} at (0,93) size 490x82
+                    LayoutTableCell {td} at (1,93) size 243x82 [r=2 c=0 rs=1 cs=1]
                       LayoutText {#text} at (0,0) size 0x0
-                    LayoutTableCell {td} at (246,93) size 244x82 [r=2 c=1 rs=1 cs=1]
+                    LayoutTableCell {td} at (245,93) size 244x82 [r=2 c=1 rs=1 cs=1]
                       LayoutImage {img} at (5,5) size 138.88x69.44
                       LayoutText {#text} at (0,0) size 0x0
-layer at (257,110) size 139x69
-  LayoutEmbeddedObject {object} at (100.13,5) size 138.88x69.44
+layer at (255,110) size 139x69
+  LayoutEmbeddedObject {object} at (99.13,5) size 138.88x69.44
     layer at (0,0) size 139x69
       LayoutView at (0,0) size 139x69
     layer at (0,0) size 139x69
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.png
index f1843ef..79edb450 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.txt
index 7aae683..a6523bb 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.txt
@@ -3,32 +3,32 @@
 layer at (0,0) size 800x199
   LayoutBlockFlow {html} at (0,0) size 800x199.09
     LayoutBlockFlow {body} at (5.55,5.55) size 788.91x188
-      LayoutTable {table} at (142.45,0) size 504x188
-        LayoutTableSection (anonymous) at (0,0) size 504x188
-          LayoutTableRow {tr} at (0,0) size 504x188
-            LayoutTableCell {td} at (0,0) size 504x188 [r=0 c=0 rs=1 cs=3]
-              LayoutTable {table} at (7.44,6) size 491x176
-                LayoutTableSection (anonymous) at (0,0) size 491x176
-                  LayoutTableRow {tr} at (0,1) size 491x66
-                    LayoutTableCell {td} at (1,1) size 489x65.75 [r=0 c=0 rs=1 cs=2]
-                      LayoutBlockFlow {h1} at (5.55,19.88) size 479x26
-                        LayoutText {#text} at (0,0) size 479x25
-                          text run at (0,0) width 479: "Both sides should have identical size after zooming"
-                  LayoutTableRow {tr} at (0,68) size 491x24
-                    LayoutTableCell {td} at (1,68) size 244x24 [r=1 c=0 rs=1 cs=1]
-                      LayoutText {#text} at (95,5) size 54x14
-                        text run at (95,5) width 54: "SVG Image"
-                    LayoutTableCell {td} at (246,68) size 244x24 [r=1 c=1 rs=1 cs=1]
+      LayoutTable {table} at (143.45,0) size 502x188
+        LayoutTableSection (anonymous) at (0,0) size 502x188
+          LayoutTableRow {tr} at (0,0) size 502x188
+            LayoutTableCell {td} at (0,0) size 502x188 [r=0 c=0 rs=1 cs=3]
+              LayoutTable {table} at (6,6) size 490x176
+                LayoutTableSection (anonymous) at (0,0) size 490x176
+                  LayoutTableRow {tr} at (0,1) size 490x66
+                    LayoutTableCell {td} at (1,1) size 488x65.75 [r=0 c=0 rs=1 cs=2]
+                      LayoutBlockFlow {h1} at (5,19.88) size 478x26
+                        LayoutText {#text} at (0,0) size 478x25
+                          text run at (0,0) width 478: "Both sides should have identical size after zooming"
+                  LayoutTableRow {tr} at (0,68) size 490x24
+                    LayoutTableCell {td} at (1,68) size 243x24 [r=1 c=0 rs=1 cs=1]
+                      LayoutText {#text} at (94,5) size 55x14
+                        text run at (94,5) width 55: "SVG Image"
+                    LayoutTableCell {td} at (245,68) size 244x24 [r=1 c=1 rs=1 cs=1]
                       LayoutText {#text} at (95,5) size 54x14
                         text run at (95,5) width 54: "PNG Image"
-                  LayoutTableRow {tr} at (0,93) size 491x82
-                    LayoutTableCell {td} at (1,93) size 244x82 [r=2 c=0 rs=1 cs=1]
+                  LayoutTableRow {tr} at (0,93) size 490x82
+                    LayoutTableCell {td} at (1,93) size 243x82 [r=2 c=0 rs=1 cs=1]
                       LayoutText {#text} at (0,0) size 0x0
-                    LayoutTableCell {td} at (246,93) size 244x82 [r=2 c=1 rs=1 cs=1]
+                    LayoutTableCell {td} at (245,93) size 244x82 [r=2 c=1 rs=1 cs=1]
                       LayoutImage {img} at (5,5) size 138.88x69.44
                       LayoutText {#text} at (0,0) size 0x0
-layer at (257,110) size 139x69
-  LayoutEmbeddedObject {object} at (100.13,5) size 138.88x69.44
+layer at (255,110) size 139x69
+  LayoutEmbeddedObject {object} at (99.13,5) size 138.88x69.44
     layer at (0,0) size 139x69
       LayoutView at (0,0) size 139x69
     layer at (0,0) size 139x69
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.png
index c457613..e392a14 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.txt
index 3db7cd7..1c465e5 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.txt
@@ -3,32 +3,32 @@
 layer at (0,0) size 800x380
   LayoutBlockFlow {html} at (0,0) size 800x380.09
     LayoutBlockFlow {body} at (5.55,5.55) size 788.91x369
-      LayoutTable {table} at (41.45,0) size 706x369
-        LayoutTableSection (anonymous) at (0,0) size 706x369
-          LayoutTableRow {tr} at (0,0) size 706x369
-            LayoutTableCell {td} at (0,0) size 706x369 [r=0 c=0 rs=1 cs=3]
-              LayoutTable {table} at (7.44,6) size 693x357
-                LayoutTableSection (anonymous) at (0,0) size 693x357
-                  LayoutTableRow {tr} at (0,1) size 693x66
-                    LayoutTableCell {td} at (1,1) size 691x65.75 [r=0 c=0 rs=1 cs=2]
-                      LayoutBlockFlow {h1} at (5.55,19.88) size 681x26
-                        LayoutText {#text} at (101,0) size 479x25
-                          text run at (101,0) width 479: "Both sides should have identical size after zooming"
-                  LayoutTableRow {tr} at (0,68) size 693x24
-                    LayoutTableCell {td} at (1,68) size 345x24 [r=1 c=0 rs=1 cs=1]
-                      LayoutText {#text} at (145,5) size 55x14
-                        text run at (145,5) width 55: "SVG Image"
-                    LayoutTableCell {td} at (347,68) size 345x24 [r=1 c=1 rs=1 cs=1]
-                      LayoutText {#text} at (145,5) size 55x14
-                        text run at (145,5) width 55: "PNG Image"
-                  LayoutTableRow {tr} at (0,93) size 693x263
-                    LayoutTableCell {td} at (1,93) size 345x263 [r=2 c=0 rs=1 cs=1]
+      LayoutTable {table} at (42.95,0) size 703x369
+        LayoutTableSection (anonymous) at (0,0) size 703x369
+          LayoutTableRow {tr} at (0,0) size 703x369
+            LayoutTableCell {td} at (0,0) size 703x369 [r=0 c=0 rs=1 cs=3]
+              LayoutTable {table} at (6,6) size 691x357
+                LayoutTableSection (anonymous) at (0,0) size 691x357
+                  LayoutTableRow {tr} at (0,1) size 691x66
+                    LayoutTableCell {td} at (1,1) size 689x65.75 [r=0 c=0 rs=1 cs=2]
+                      LayoutBlockFlow {h1} at (5,19.88) size 679x26
+                        LayoutText {#text} at (100,0) size 479x25
+                          text run at (100,0) width 479: "Both sides should have identical size after zooming"
+                  LayoutTableRow {tr} at (0,68) size 691x24
+                    LayoutTableCell {td} at (1,68) size 344x24 [r=1 c=0 rs=1 cs=1]
+                      LayoutText {#text} at (145,5) size 54x14
+                        text run at (145,5) width 54: "SVG Image"
+                    LayoutTableCell {td} at (346,68) size 344x24 [r=1 c=1 rs=1 cs=1]
+                      LayoutText {#text} at (145,5) size 54x14
+                        text run at (145,5) width 54: "PNG Image"
+                  LayoutTableRow {tr} at (0,93) size 691x263
+                    LayoutTableCell {td} at (1,93) size 344x263 [r=2 c=0 rs=1 cs=1]
                       LayoutText {#text} at (0,0) size 0x0
-                    LayoutTableCell {td} at (347,93) size 345x263 [r=2 c=1 rs=1 cs=1]
+                    LayoutTableCell {td} at (346,93) size 344x263 [r=2 c=1 rs=1 cs=1]
                       LayoutImage {img} at (5,5) size 333.33x249.97
                       LayoutText {#text} at (0,0) size 0x0
-layer at (62,110) size 333x250
-  LayoutEmbeddedObject {object} at (6.67,5) size 333.33x249.98
+layer at (61,110) size 333x250
+  LayoutEmbeddedObject {object} at (5.67,5) size 333.33x249.98
     layer at (0,0) size 333x250
       LayoutView at (0,0) size 333x250
     layer at (0,0) size 333x250
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla_expected_failures/bugs/bug89315-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla_expected_failures/bugs/bug89315-expected.png
index 271c3887..a5b7ca3 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla_expected_failures/bugs/bug89315-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla_expected_failures/bugs/bug89315-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/box-shadow/basic-shadows-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/box-shadow/basic-shadows-expected.png
index aa1eb3ac..f6c2241 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/box-shadow/basic-shadows-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/box-shadow/basic-shadows-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png
index 4d02c75..b2586bdb 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/tables/mozilla_expected_failures/bugs/bug89315-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/tables/mozilla_expected_failures/bugs/bug89315-expected.png
index df6d6a4..ab10411 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/tables/mozilla_expected_failures/bugs/bug89315-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/tables/mozilla_expected_failures/bugs/bug89315-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-radius-split-inline-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-radius-split-inline-expected.png
index e6906b2..d5aeb9f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-radius-split-inline-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-radius-split-inline-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/basic-shadows-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/basic-shadows-expected.png
index d5af415..9ac39f4 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/basic-shadows-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/basic-shadows-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/box-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/box-shadow-expected.png
index 637df6d2..7997292 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/box-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/box-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/box-shadow-radius-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/box-shadow-radius-expected.png
index 948dbaf..f851d4b6 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/box-shadow-radius-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/box-shadow-radius-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/box-shadow-transformed-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/box-shadow-transformed-expected.png
index 0e0b95b..6df72d70 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/box-shadow-transformed-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/box-shadow-transformed-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/inset-box-shadow-radius-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/inset-box-shadow-radius-expected.png
index 41655a9..9d5ed50 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/inset-box-shadow-radius-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/inset-box-shadow-radius-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/scaled-box-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/scaled-box-shadow-expected.png
index 411c53c..4fcfdd18 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/scaled-box-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/scaled-box-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/canvas/canvas-composite-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/canvas/canvas-composite-shadow-expected.png
index 0e13c64..89b3a60 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/canvas/canvas-composite-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/canvas/canvas-composite-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/css/color-correction-on-box-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/css/color-correction-on-box-shadow-expected.png
index 55a9525..582d458 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/css/color-correction-on-box-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/css/color-correction-on-box-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.png
index d02e5887..ae6728a7 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.txt
index 078d1e9..643b704 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.txt
@@ -3,103 +3,103 @@
 layer at (0,0) size 800x339
   LayoutBlockFlow {HTML} at (0,0) size 800x339.09
     LayoutBlockFlow {BODY} at (5.55,5.55) size 788.91x328
-      LayoutTable {TABLE} at (0,0) size 462x328
-        LayoutTableSection {TBODY} at (0,0) size 462x328
-          LayoutTableRow {TR} at (0,1) size 462x14
-            LayoutTableCell {TH} at (1,1) size 64x14 [bgcolor=#DDDD99] [r=0 c=0 rs=1 cs=1]
-              LayoutText {#text} at (6,0) size 52x14
-                text run at (6,0) width 52: "viewBox?"
-            LayoutTableCell {TH} at (66,1) size 113x14 [bgcolor=#DDDD99] [r=0 c=1 rs=1 cs=1]
-              LayoutText {#text} at (0,0) size 113x14
-                text run at (0,0) width 113: "preserve\x{AD}Aspect\x{AD}Ratio"
-            LayoutTableCell {TH} at (180,1) size 140x14 [bgcolor=#DDDD99] [r=0 c=2 rs=1 cs=1]
-              LayoutText {#text} at (53,0) size 34x14
-                text run at (53,0) width 34: "<img>"
-            LayoutTableCell {TH} at (321,1) size 140x14 [bgcolor=#DDDD99] [r=0 c=3 rs=1 cs=1]
-              LayoutText {#text} at (47,0) size 46x14
-                text run at (47,0) width 46: "<object>"
-          LayoutTableRow {TR} at (0,16) size 462x38
-            LayoutTableCell {TH} at (1,86) size 64x14 [bgcolor=#DDDD99] [r=1 c=0 rs=4 cs=1]
-              LayoutText {#text} at (0,0) size 64x14
-                text run at (0,0) width 64: "No viewBox"
-            LayoutTableCell {TH} at (66,35) size 113x0 [bgcolor=#DDDD99] [r=1 c=1 rs=1 cs=1]
-            LayoutTableCell {TD} at (180,16) size 140x38 [r=1 c=2 rs=1 cs=1]
+      LayoutTable {TABLE} at (0,0) size 458x328
+        LayoutTableSection {TBODY} at (0,0) size 458x328
+          LayoutTableRow {TR} at (0,1) size 458x14
+            LayoutTableCell {TH} at (1,1) size 63x14 [bgcolor=#DDDD99] [r=0 c=0 rs=1 cs=1]
+              LayoutText {#text} at (5,0) size 53x14
+                text run at (5,0) width 53: "viewBox?"
+            LayoutTableCell {TH} at (65,1) size 112x14 [bgcolor=#DDDD99] [r=0 c=1 rs=1 cs=1]
+              LayoutText {#text} at (0,0) size 112x14
+                text run at (0,0) width 112: "preserve\x{AD}Aspect\x{AD}Ratio"
+            LayoutTableCell {TH} at (178,1) size 139x14 [bgcolor=#DDDD99] [r=0 c=2 rs=1 cs=1]
+              LayoutText {#text} at (53,0) size 33x14
+                text run at (53,0) width 33: "<img>"
+            LayoutTableCell {TH} at (318,1) size 139x14 [bgcolor=#DDDD99] [r=0 c=3 rs=1 cs=1]
+              LayoutText {#text} at (46,0) size 47x14
+                text run at (46,0) width 47: "<object>"
+          LayoutTableRow {TR} at (0,16) size 458x38
+            LayoutTableCell {TH} at (1,86) size 63x14 [bgcolor=#DDDD99] [r=1 c=0 rs=4 cs=1]
+              LayoutText {#text} at (0,0) size 63x14
+                text run at (0,0) width 63: "No viewBox"
+            LayoutTableCell {TH} at (65,35) size 112x0 [bgcolor=#DDDD99] [r=1 c=1 rs=1 cs=1]
+            LayoutTableCell {TD} at (178,16) size 139x38 [r=1 c=2 rs=1 cs=1]
               LayoutImage {IMG} at (0,0) size 138.88x34.72 [border: (1.38px dashed #800000)]
               LayoutText {#text} at (0,0) size 0x0
-            LayoutTableCell {TD} at (321,16) size 140x38 [r=1 c=3 rs=1 cs=1]
+            LayoutTableCell {TD} at (318,16) size 139x38 [r=1 c=3 rs=1 cs=1]
               LayoutText {#text} at (0,0) size 0x0
-          LayoutTableRow {TR} at (0,55) size 462x38
-            LayoutTableCell {TH} at (66,67) size 113x14 [bgcolor=#DDDD99] [r=2 c=1 rs=1 cs=1]
-              LayoutText {#text} at (43,0) size 27x14
-                text run at (43,0) width 27: "none"
-            LayoutTableCell {TD} at (180,55) size 140x38 [r=2 c=2 rs=1 cs=1]
+          LayoutTableRow {TR} at (0,55) size 458x38
+            LayoutTableCell {TH} at (65,67) size 112x14 [bgcolor=#DDDD99] [r=2 c=1 rs=1 cs=1]
+              LayoutText {#text} at (42,0) size 28x14
+                text run at (42,0) width 28: "none"
+            LayoutTableCell {TD} at (178,55) size 139x38 [r=2 c=2 rs=1 cs=1]
               LayoutImage {IMG} at (0,0) size 138.88x34.72 [border: (1.38px dashed #800000)]
               LayoutText {#text} at (0,0) size 0x0
-            LayoutTableCell {TD} at (321,55) size 140x38 [r=2 c=3 rs=1 cs=1]
+            LayoutTableCell {TD} at (318,55) size 139x38 [r=2 c=3 rs=1 cs=1]
               LayoutText {#text} at (0,0) size 0x0
-          LayoutTableRow {TR} at (0,94) size 462x38
-            LayoutTableCell {TH} at (66,106) size 113x14 [bgcolor=#DDDD99] [r=3 c=1 rs=1 cs=1]
-              LayoutText {#text} at (43,0) size 27x14
-                text run at (43,0) width 27: "meet"
-            LayoutTableCell {TD} at (180,94) size 140x38 [r=3 c=2 rs=1 cs=1]
+          LayoutTableRow {TR} at (0,94) size 458x38
+            LayoutTableCell {TH} at (65,106) size 112x14 [bgcolor=#DDDD99] [r=3 c=1 rs=1 cs=1]
+              LayoutText {#text} at (43,0) size 26x14
+                text run at (43,0) width 26: "meet"
+            LayoutTableCell {TD} at (178,94) size 139x38 [r=3 c=2 rs=1 cs=1]
               LayoutImage {IMG} at (0,0) size 138.88x34.72 [border: (1.38px dashed #800000)]
               LayoutText {#text} at (0,0) size 0x0
-            LayoutTableCell {TD} at (321,94) size 140x38 [r=3 c=3 rs=1 cs=1]
+            LayoutTableCell {TD} at (318,94) size 139x38 [r=3 c=3 rs=1 cs=1]
               LayoutText {#text} at (0,0) size 0x0
-          LayoutTableRow {TR} at (0,133) size 462x38
-            LayoutTableCell {TH} at (66,145) size 113x14 [bgcolor=#DDDD99] [r=4 c=1 rs=1 cs=1]
-              LayoutText {#text} at (44,0) size 25x14
-                text run at (44,0) width 25: "slice"
-            LayoutTableCell {TD} at (180,133) size 140x38 [r=4 c=2 rs=1 cs=1]
+          LayoutTableRow {TR} at (0,133) size 458x38
+            LayoutTableCell {TH} at (65,145) size 112x14 [bgcolor=#DDDD99] [r=4 c=1 rs=1 cs=1]
+              LayoutText {#text} at (43,0) size 26x14
+                text run at (43,0) width 26: "slice"
+            LayoutTableCell {TD} at (178,133) size 139x38 [r=4 c=2 rs=1 cs=1]
               LayoutImage {IMG} at (0,0) size 138.88x34.72 [border: (1.38px dashed #800000)]
               LayoutText {#text} at (0,0) size 0x0
-            LayoutTableCell {TD} at (321,133) size 140x38 [r=4 c=3 rs=1 cs=1]
+            LayoutTableCell {TD} at (318,133) size 139x38 [r=4 c=3 rs=1 cs=1]
               LayoutText {#text} at (0,0) size 0x0
-          LayoutTableRow {TR} at (0,172) size 462x38
-            LayoutTableCell {TH} at (1,242) size 64x14 [bgcolor=#DDDD99] [r=5 c=0 rs=4 cs=1]
-              LayoutText {#text} at (9,0) size 46x14
-                text run at (9,0) width 46: "viewBox"
-            LayoutTableCell {TH} at (66,191) size 113x0 [bgcolor=#DDDD99] [r=5 c=1 rs=1 cs=1]
-            LayoutTableCell {TD} at (180,172) size 140x38 [r=5 c=2 rs=1 cs=1]
+          LayoutTableRow {TR} at (0,172) size 458x38
+            LayoutTableCell {TH} at (1,242) size 63x14 [bgcolor=#DDDD99] [r=5 c=0 rs=4 cs=1]
+              LayoutText {#text} at (8,0) size 47x14
+                text run at (8,0) width 47: "viewBox"
+            LayoutTableCell {TH} at (65,191) size 112x0 [bgcolor=#DDDD99] [r=5 c=1 rs=1 cs=1]
+            LayoutTableCell {TD} at (178,172) size 139x38 [r=5 c=2 rs=1 cs=1]
               LayoutImage {IMG} at (0,0) size 138.88x34.72 [border: (1.38px dashed #800000)]
               LayoutText {#text} at (0,0) size 0x0
-            LayoutTableCell {TD} at (321,172) size 140x38 [r=5 c=3 rs=1 cs=1]
+            LayoutTableCell {TD} at (318,172) size 139x38 [r=5 c=3 rs=1 cs=1]
               LayoutText {#text} at (0,0) size 0x0
-          LayoutTableRow {TR} at (0,211) size 462x38
-            LayoutTableCell {TH} at (66,223) size 113x14 [bgcolor=#DDDD99] [r=6 c=1 rs=1 cs=1]
-              LayoutText {#text} at (43,0) size 27x14
-                text run at (43,0) width 27: "none"
-            LayoutTableCell {TD} at (180,211) size 140x38 [r=6 c=2 rs=1 cs=1]
+          LayoutTableRow {TR} at (0,211) size 458x38
+            LayoutTableCell {TH} at (65,223) size 112x14 [bgcolor=#DDDD99] [r=6 c=1 rs=1 cs=1]
+              LayoutText {#text} at (42,0) size 28x14
+                text run at (42,0) width 28: "none"
+            LayoutTableCell {TD} at (178,211) size 139x38 [r=6 c=2 rs=1 cs=1]
               LayoutImage {IMG} at (0,0) size 138.88x34.72 [border: (1.38px dashed #800000)]
               LayoutText {#text} at (0,0) size 0x0
-            LayoutTableCell {TD} at (321,211) size 140x38 [r=6 c=3 rs=1 cs=1]
+            LayoutTableCell {TD} at (318,211) size 139x38 [r=6 c=3 rs=1 cs=1]
               LayoutText {#text} at (0,0) size 0x0
-          LayoutTableRow {TR} at (0,250) size 462x38
-            LayoutTableCell {TH} at (66,262) size 113x14 [bgcolor=#DDDD99] [r=7 c=1 rs=1 cs=1]
-              LayoutText {#text} at (43,0) size 27x14
-                text run at (43,0) width 27: "meet"
-            LayoutTableCell {TD} at (180,250) size 140x38 [r=7 c=2 rs=1 cs=1]
+          LayoutTableRow {TR} at (0,250) size 458x38
+            LayoutTableCell {TH} at (65,262) size 112x14 [bgcolor=#DDDD99] [r=7 c=1 rs=1 cs=1]
+              LayoutText {#text} at (43,0) size 26x14
+                text run at (43,0) width 26: "meet"
+            LayoutTableCell {TD} at (178,250) size 139x38 [r=7 c=2 rs=1 cs=1]
               LayoutImage {IMG} at (0,0) size 138.88x34.72 [border: (1.38px dashed #800000)]
               LayoutText {#text} at (0,0) size 0x0
-            LayoutTableCell {TD} at (321,250) size 140x38 [r=7 c=3 rs=1 cs=1]
+            LayoutTableCell {TD} at (318,250) size 139x38 [r=7 c=3 rs=1 cs=1]
               LayoutText {#text} at (0,0) size 0x0
-          LayoutTableRow {TR} at (0,289) size 462x38
-            LayoutTableCell {TH} at (66,301) size 113x14 [bgcolor=#DDDD99] [r=8 c=1 rs=1 cs=1]
-              LayoutText {#text} at (44,0) size 25x14
-                text run at (44,0) width 25: "slice"
-            LayoutTableCell {TD} at (180,289) size 140x38 [r=8 c=2 rs=1 cs=1]
+          LayoutTableRow {TR} at (0,289) size 458x38
+            LayoutTableCell {TH} at (65,301) size 112x14 [bgcolor=#DDDD99] [r=8 c=1 rs=1 cs=1]
+              LayoutText {#text} at (43,0) size 26x14
+                text run at (43,0) width 26: "slice"
+            LayoutTableCell {TD} at (178,289) size 139x38 [r=8 c=2 rs=1 cs=1]
               LayoutImage {IMG} at (0,0) size 138.88x34.72 [border: (1.38px dashed #800000)]
               LayoutText {#text} at (0,0) size 0x0
-            LayoutTableCell {TD} at (321,289) size 140x38 [r=8 c=3 rs=1 cs=1]
+            LayoutTableCell {TD} at (318,289) size 139x38 [r=8 c=3 rs=1 cs=1]
               LayoutText {#text} at (0,0) size 0x0
-layer at (327,22) size 139x35
+layer at (324,22) size 139x35
   LayoutEmbeddedObject {OBJECT} at (0,0) size 138.88x34.72 [border: (0.69px dashed #008000)]
     layer at (0,0) size 133x29
       LayoutView at (0,0) size 133x29
     layer at (0,0) size 133x29
       LayoutSVGRoot {svg} at (0,0) size 133x29
         LayoutSVGEllipse {circle} at (0,0) size 220x220 [stroke={[type=SOLID] [color=#000000]}] [fill={[type=SOLID] [color=#D9BB7A] [fill rule=EVEN-ODD]}] [cx=110.00] [cy=110.00] [r=110.00]
-layer at (327,61) size 139x35
+layer at (324,61) size 139x35
   LayoutEmbeddedObject {OBJECT} at (0,0) size 138.88x34.72 [border: (0.69px dashed #008000)]
     layer at (0,0) size 133x29
       LayoutView at (0,0) size 133x29
@@ -108,7 +108,7 @@
         LayoutSVGHiddenContainer {defs} at (0,0) size 0x0
         LayoutSVGContainer {g} at (162.86,375.72) size 362.86x390.92 [transform={m=((1.00,0.00)(0.00,1.00)) t=(-162.36,-403.29)}]
           LayoutSVGPath {path} at (162.86,375.72) size 362.86x390.92 [stroke={[type=SOLID] [color=#000000]}] [fill={[type=SOLID] [color=#D9BB7A] [fill rule=EVEN-ODD]}] [data="M 525.714 585.219 A 181.429 181.429 0 1 1 162.857 585.219 A 181.429 181.429 0 1 1 525.714 585.219 Z"]
-layer at (327,100) size 139x35
+layer at (324,100) size 139x35
   LayoutEmbeddedObject {OBJECT} at (0,0) size 138.88x34.72 [border: (0.69px dashed #008000)]
     layer at (0,0) size 133x29
       LayoutView at (0,0) size 133x29
@@ -117,7 +117,7 @@
         LayoutSVGHiddenContainer {defs} at (0,0) size 0x0
         LayoutSVGContainer {g} at (162.86,375.72) size 362.86x390.92 [transform={m=((1.00,0.00)(0.00,1.00)) t=(-162.36,-403.29)}]
           LayoutSVGPath {path} at (162.86,375.72) size 362.86x390.92 [stroke={[type=SOLID] [color=#000000]}] [fill={[type=SOLID] [color=#D9BB7A] [fill rule=EVEN-ODD]}] [data="M 525.714 585.219 A 181.429 181.429 0 1 1 162.857 585.219 A 181.429 181.429 0 1 1 525.714 585.219 Z"]
-layer at (327,139) size 139x35
+layer at (324,139) size 139x35
   LayoutEmbeddedObject {OBJECT} at (0,0) size 138.88x34.72 [border: (0.69px dashed #008000)]
     layer at (0,0) size 133x29
       LayoutView at (0,0) size 133x29
@@ -126,7 +126,7 @@
         LayoutSVGHiddenContainer {defs} at (0,0) size 0x0
         LayoutSVGContainer {g} at (162.86,375.72) size 362.86x390.92 [transform={m=((1.00,0.00)(0.00,1.00)) t=(-162.36,-403.29)}]
           LayoutSVGPath {path} at (162.86,375.72) size 362.86x390.92 [stroke={[type=SOLID] [color=#000000]}] [fill={[type=SOLID] [color=#D9BB7A] [fill rule=EVEN-ODD]}] [data="M 525.714 585.219 A 181.429 181.429 0 1 1 162.857 585.219 A 181.429 181.429 0 1 1 525.714 585.219 Z"]
-layer at (327,178) size 139x35
+layer at (324,178) size 139x35
   LayoutEmbeddedObject {OBJECT} at (0,0) size 138.88x34.72 [border: (0.69px dashed #008000)]
     layer at (0,0) size 133x29
       LayoutView at (0,0) size 133x29
@@ -135,7 +135,7 @@
         LayoutSVGHiddenContainer {defs} at (0,0) size 0x0
         LayoutSVGContainer {g} at (162.86,375.72) size 362.86x390.92 [transform={m=((1.00,0.00)(0.00,1.00)) t=(-162.36,-403.29)}]
           LayoutSVGPath {path} at (162.86,375.72) size 362.86x390.92 [stroke={[type=SOLID] [color=#000000]}] [fill={[type=SOLID] [color=#D9BB7A] [fill rule=EVEN-ODD]}] [data="M 525.714 585.219 A 181.429 181.429 0 1 1 162.857 585.219 A 181.429 181.429 0 1 1 525.714 585.219 Z"]
-layer at (327,217) size 139x35
+layer at (324,217) size 139x35
   LayoutEmbeddedObject {OBJECT} at (0,0) size 138.88x34.72 [border: (0.69px dashed #008000)]
     layer at (0,0) size 133x29
       LayoutView at (0,0) size 133x29
@@ -144,7 +144,7 @@
         LayoutSVGHiddenContainer {defs} at (0,0) size 0x0
         LayoutSVGContainer {g} at (162.86,375.72) size 362.86x390.92 [transform={m=((1.00,0.00)(0.00,1.00)) t=(-162.36,-403.29)}]
           LayoutSVGPath {path} at (162.86,375.72) size 362.86x390.92 [stroke={[type=SOLID] [color=#000000]}] [fill={[type=SOLID] [color=#D9BB7A] [fill rule=EVEN-ODD]}] [data="M 525.714 585.219 A 181.429 181.429 0 1 1 162.857 585.219 A 181.429 181.429 0 1 1 525.714 585.219 Z"]
-layer at (327,256) size 139x35
+layer at (324,256) size 139x35
   LayoutEmbeddedObject {OBJECT} at (0,0) size 138.88x34.72 [border: (0.69px dashed #008000)]
     layer at (0,0) size 133x29
       LayoutView at (0,0) size 133x29
@@ -153,7 +153,7 @@
         LayoutSVGHiddenContainer {defs} at (0,0) size 0x0
         LayoutSVGContainer {g} at (162.86,375.72) size 362.86x390.92 [transform={m=((1.00,0.00)(0.00,1.00)) t=(-162.36,-403.29)}]
           LayoutSVGPath {path} at (162.86,375.72) size 362.86x390.92 [stroke={[type=SOLID] [color=#000000]}] [fill={[type=SOLID] [color=#D9BB7A] [fill rule=EVEN-ODD]}] [data="M 525.714 585.219 A 181.429 181.429 0 1 1 162.857 585.219 A 181.429 181.429 0 1 1 525.714 585.219 Z"]
-layer at (327,295) size 139x35
+layer at (324,295) size 139x35
   LayoutEmbeddedObject {OBJECT} at (0,0) size 138.88x34.72 [border: (0.69px dashed #008000)]
     layer at (0,0) size 133x29
       LayoutView at (0,0) size 133x29
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.png
index 517875e4..3edf887 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.txt
index 69630f41..0a0a440 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.txt
@@ -3,32 +3,32 @@
 layer at (0,0) size 800x198
   LayoutBlockFlow {html} at (0,0) size 800x198.09
     LayoutBlockFlow {body} at (5.55,5.55) size 788.91x187
-      LayoutTable {table} at (141.45,0) size 506x187
-        LayoutTableSection (anonymous) at (0,0) size 506x187
-          LayoutTableRow {tr} at (0,0) size 506x187
-            LayoutTableCell {td} at (0,0) size 506x187 [r=0 c=0 rs=1 cs=3]
-              LayoutTable {table} at (7.44,6) size 493x175
-                LayoutTableSection (anonymous) at (0,0) size 493x175
-                  LayoutTableRow {tr} at (0,1) size 493x66
-                    LayoutTableCell {td} at (1,1) size 491x65.75 [r=0 c=0 rs=1 cs=2]
-                      LayoutBlockFlow {h1} at (5.55,19.88) size 481x26
-                        LayoutText {#text} at (0,0) size 481x26
-                          text run at (0,0) width 481: "Both sides should have identical size after zooming"
-                  LayoutTableRow {tr} at (0,68) size 493x23
-                    LayoutTableCell {td} at (1,68) size 245x23 [r=1 c=0 rs=1 cs=1]
-                      LayoutText {#text} at (96,5) size 53x13
-                        text run at (96,5) width 53: "SVG Image"
-                    LayoutTableCell {td} at (247,68) size 245x23 [r=1 c=1 rs=1 cs=1]
+      LayoutTable {table} at (142.45,0) size 504x187
+        LayoutTableSection (anonymous) at (0,0) size 504x187
+          LayoutTableRow {tr} at (0,0) size 504x187
+            LayoutTableCell {td} at (0,0) size 504x187 [r=0 c=0 rs=1 cs=3]
+              LayoutTable {table} at (6,6) size 492x175
+                LayoutTableSection (anonymous) at (0,0) size 492x175
+                  LayoutTableRow {tr} at (0,1) size 492x66
+                    LayoutTableCell {td} at (1,1) size 490x65.75 [r=0 c=0 rs=1 cs=2]
+                      LayoutBlockFlow {h1} at (5,19.88) size 480x26
+                        LayoutText {#text} at (0,0) size 480x26
+                          text run at (0,0) width 480: "Both sides should have identical size after zooming"
+                  LayoutTableRow {tr} at (0,68) size 492x23
+                    LayoutTableCell {td} at (1,68) size 244x23 [r=1 c=0 rs=1 cs=1]
+                      LayoutText {#text} at (95,5) size 54x13
+                        text run at (95,5) width 54: "SVG Image"
+                    LayoutTableCell {td} at (246,68) size 245x23 [r=1 c=1 rs=1 cs=1]
                       LayoutText {#text} at (96,5) size 53x13
                         text run at (96,5) width 53: "PNG Image"
-                  LayoutTableRow {tr} at (0,92) size 493x82
-                    LayoutTableCell {td} at (1,92) size 245x82 [r=2 c=0 rs=1 cs=1]
+                  LayoutTableRow {tr} at (0,92) size 492x82
+                    LayoutTableCell {td} at (1,92) size 244x82 [r=2 c=0 rs=1 cs=1]
                       LayoutText {#text} at (0,0) size 0x0
-                    LayoutTableCell {td} at (247,92) size 245x82 [r=2 c=1 rs=1 cs=1]
+                    LayoutTableCell {td} at (246,92) size 245x82 [r=2 c=1 rs=1 cs=1]
                       LayoutImage {img} at (5,5) size 138.88x69.44
                       LayoutText {#text} at (0,0) size 0x0
-layer at (257,109) size 139x69
-  LayoutEmbeddedObject {object} at (101.13,5) size 138.88x69.44
+layer at (255,109) size 139x69
+  LayoutEmbeddedObject {object} at (100.13,5) size 138.88x69.44
     layer at (0,0) size 139x69
       LayoutView at (0,0) size 139x69
     layer at (0,0) size 139x69
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.png
index 517875e4..3edf887 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.txt
index 69630f41..0a0a440 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.txt
@@ -3,32 +3,32 @@
 layer at (0,0) size 800x198
   LayoutBlockFlow {html} at (0,0) size 800x198.09
     LayoutBlockFlow {body} at (5.55,5.55) size 788.91x187
-      LayoutTable {table} at (141.45,0) size 506x187
-        LayoutTableSection (anonymous) at (0,0) size 506x187
-          LayoutTableRow {tr} at (0,0) size 506x187
-            LayoutTableCell {td} at (0,0) size 506x187 [r=0 c=0 rs=1 cs=3]
-              LayoutTable {table} at (7.44,6) size 493x175
-                LayoutTableSection (anonymous) at (0,0) size 493x175
-                  LayoutTableRow {tr} at (0,1) size 493x66
-                    LayoutTableCell {td} at (1,1) size 491x65.75 [r=0 c=0 rs=1 cs=2]
-                      LayoutBlockFlow {h1} at (5.55,19.88) size 481x26
-                        LayoutText {#text} at (0,0) size 481x26
-                          text run at (0,0) width 481: "Both sides should have identical size after zooming"
-                  LayoutTableRow {tr} at (0,68) size 493x23
-                    LayoutTableCell {td} at (1,68) size 245x23 [r=1 c=0 rs=1 cs=1]
-                      LayoutText {#text} at (96,5) size 53x13
-                        text run at (96,5) width 53: "SVG Image"
-                    LayoutTableCell {td} at (247,68) size 245x23 [r=1 c=1 rs=1 cs=1]
+      LayoutTable {table} at (142.45,0) size 504x187
+        LayoutTableSection (anonymous) at (0,0) size 504x187
+          LayoutTableRow {tr} at (0,0) size 504x187
+            LayoutTableCell {td} at (0,0) size 504x187 [r=0 c=0 rs=1 cs=3]
+              LayoutTable {table} at (6,6) size 492x175
+                LayoutTableSection (anonymous) at (0,0) size 492x175
+                  LayoutTableRow {tr} at (0,1) size 492x66
+                    LayoutTableCell {td} at (1,1) size 490x65.75 [r=0 c=0 rs=1 cs=2]
+                      LayoutBlockFlow {h1} at (5,19.88) size 480x26
+                        LayoutText {#text} at (0,0) size 480x26
+                          text run at (0,0) width 480: "Both sides should have identical size after zooming"
+                  LayoutTableRow {tr} at (0,68) size 492x23
+                    LayoutTableCell {td} at (1,68) size 244x23 [r=1 c=0 rs=1 cs=1]
+                      LayoutText {#text} at (95,5) size 54x13
+                        text run at (95,5) width 54: "SVG Image"
+                    LayoutTableCell {td} at (246,68) size 245x23 [r=1 c=1 rs=1 cs=1]
                       LayoutText {#text} at (96,5) size 53x13
                         text run at (96,5) width 53: "PNG Image"
-                  LayoutTableRow {tr} at (0,92) size 493x82
-                    LayoutTableCell {td} at (1,92) size 245x82 [r=2 c=0 rs=1 cs=1]
+                  LayoutTableRow {tr} at (0,92) size 492x82
+                    LayoutTableCell {td} at (1,92) size 244x82 [r=2 c=0 rs=1 cs=1]
                       LayoutText {#text} at (0,0) size 0x0
-                    LayoutTableCell {td} at (247,92) size 245x82 [r=2 c=1 rs=1 cs=1]
+                    LayoutTableCell {td} at (246,92) size 245x82 [r=2 c=1 rs=1 cs=1]
                       LayoutImage {img} at (5,5) size 138.88x69.44
                       LayoutText {#text} at (0,0) size 0x0
-layer at (257,109) size 139x69
-  LayoutEmbeddedObject {object} at (101.13,5) size 138.88x69.44
+layer at (255,109) size 139x69
+  LayoutEmbeddedObject {object} at (100.13,5) size 138.88x69.44
     layer at (0,0) size 139x69
       LayoutView at (0,0) size 139x69
     layer at (0,0) size 139x69
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.png
index 3dcc236..9f1a7f4 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.txt
index 410b49f..62c9787 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.txt
@@ -3,32 +3,32 @@
 layer at (0,0) size 800x379
   LayoutBlockFlow {html} at (0,0) size 800x379.09
     LayoutBlockFlow {body} at (5.55,5.55) size 788.91x368
-      LayoutTable {table} at (41.45,0) size 706x368
-        LayoutTableSection (anonymous) at (0,0) size 706x368
-          LayoutTableRow {tr} at (0,0) size 706x368
-            LayoutTableCell {td} at (0,0) size 706x368 [r=0 c=0 rs=1 cs=3]
-              LayoutTable {table} at (7.44,6) size 693x356
-                LayoutTableSection (anonymous) at (0,0) size 693x356
-                  LayoutTableRow {tr} at (0,1) size 693x66
-                    LayoutTableCell {td} at (1,1) size 691x65.75 [r=0 c=0 rs=1 cs=2]
-                      LayoutBlockFlow {h1} at (5.55,19.88) size 681x26
-                        LayoutText {#text} at (100,0) size 481x26
-                          text run at (100,0) width 481: "Both sides should have identical size after zooming"
-                  LayoutTableRow {tr} at (0,68) size 693x23
-                    LayoutTableCell {td} at (1,68) size 345x23 [r=1 c=0 rs=1 cs=1]
-                      LayoutText {#text} at (146,5) size 53x13
-                        text run at (146,5) width 53: "SVG Image"
-                    LayoutTableCell {td} at (347,68) size 345x23 [r=1 c=1 rs=1 cs=1]
-                      LayoutText {#text} at (146,5) size 53x13
-                        text run at (146,5) width 53: "PNG Image"
-                  LayoutTableRow {tr} at (0,92) size 693x263
-                    LayoutTableCell {td} at (1,92) size 345x263 [r=2 c=0 rs=1 cs=1]
+      LayoutTable {table} at (42.95,0) size 703x368
+        LayoutTableSection (anonymous) at (0,0) size 703x368
+          LayoutTableRow {tr} at (0,0) size 703x368
+            LayoutTableCell {td} at (0,0) size 703x368 [r=0 c=0 rs=1 cs=3]
+              LayoutTable {table} at (6,6) size 691x356
+                LayoutTableSection (anonymous) at (0,0) size 691x356
+                  LayoutTableRow {tr} at (0,1) size 691x66
+                    LayoutTableCell {td} at (1,1) size 689x65.75 [r=0 c=0 rs=1 cs=2]
+                      LayoutBlockFlow {h1} at (5,19.88) size 679x26
+                        LayoutText {#text} at (99,0) size 481x26
+                          text run at (99,0) width 481: "Both sides should have identical size after zooming"
+                  LayoutTableRow {tr} at (0,68) size 691x23
+                    LayoutTableCell {td} at (1,68) size 344x23 [r=1 c=0 rs=1 cs=1]
+                      LayoutText {#text} at (145,5) size 54x13
+                        text run at (145,5) width 54: "SVG Image"
+                    LayoutTableCell {td} at (346,68) size 344x23 [r=1 c=1 rs=1 cs=1]
+                      LayoutText {#text} at (145,5) size 54x13
+                        text run at (145,5) width 54: "PNG Image"
+                  LayoutTableRow {tr} at (0,92) size 691x263
+                    LayoutTableCell {td} at (1,92) size 344x263 [r=2 c=0 rs=1 cs=1]
                       LayoutText {#text} at (0,0) size 0x0
-                    LayoutTableCell {td} at (347,92) size 345x263 [r=2 c=1 rs=1 cs=1]
+                    LayoutTableCell {td} at (346,92) size 344x263 [r=2 c=1 rs=1 cs=1]
                       LayoutImage {img} at (5,5) size 333.33x249.97
                       LayoutText {#text} at (0,0) size 0x0
-layer at (62,109) size 333x250
-  LayoutEmbeddedObject {object} at (6.67,5) size 333.33x249.98
+layer at (61,109) size 333x250
+  LayoutEmbeddedObject {object} at (5.67,5) size 333.33x249.98
     layer at (0,0) size 333x250
       LayoutView at (0,0) size 333x250
     layer at (0,0) size 333x250
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla_expected_failures/bugs/bug89315-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla_expected_failures/bugs/bug89315-expected.png
index e4bd464..25ce0999 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla_expected_failures/bugs/bug89315-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla_expected_failures/bugs/bug89315-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/transforms/shadows-expected.png b/third_party/WebKit/LayoutTests/platform/mac/transforms/shadows-expected.png
index 10642b7a..a754462 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/transforms/shadows-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/transforms/shadows-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-shadow-expected.png
index 0e13c64..89b3a60 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.png
index 8498b7f..66066ae 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.txt
index b03fc463..46f326b 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.txt
@@ -3,103 +3,103 @@
 layer at (0,0) size 800x339
   LayoutBlockFlow {HTML} at (0,0) size 800x339.09
     LayoutBlockFlow {BODY} at (5.55,5.55) size 788.91x328
-      LayoutTable {TABLE} at (0,0) size 467x328
-        LayoutTableSection {TBODY} at (0,0) size 467x328
-          LayoutTableRow {TR} at (0,1) size 467x14
-            LayoutTableCell {TH} at (1,1) size 64x14 [bgcolor=#DDDD99] [r=0 c=0 rs=1 cs=1]
-              LayoutText {#text} at (5,0) size 54x14
-                text run at (5,0) width 54: "viewBox?"
-            LayoutTableCell {TH} at (66,1) size 118x14 [bgcolor=#DDDD99] [r=0 c=1 rs=1 cs=1]
-              LayoutText {#text} at (0,0) size 118x14
-                text run at (0,0) width 118: "preserve\x{AD}Aspect\x{AD}Ratio"
-            LayoutTableCell {TH} at (185,1) size 140x14 [bgcolor=#DDDD99] [r=0 c=2 rs=1 cs=1]
-              LayoutText {#text} at (53,0) size 34x14
-                text run at (53,0) width 34: "<img>"
-            LayoutTableCell {TH} at (326,1) size 140x14 [bgcolor=#DDDD99] [r=0 c=3 rs=1 cs=1]
-              LayoutText {#text} at (47,0) size 46x14
-                text run at (47,0) width 46: "<object>"
-          LayoutTableRow {TR} at (0,16) size 467x38
-            LayoutTableCell {TH} at (1,86) size 64x14 [bgcolor=#DDDD99] [r=1 c=0 rs=4 cs=1]
-              LayoutText {#text} at (0,0) size 64x14
-                text run at (0,0) width 64: "No viewBox"
-            LayoutTableCell {TH} at (66,35) size 118x0 [bgcolor=#DDDD99] [r=1 c=1 rs=1 cs=1]
-            LayoutTableCell {TD} at (185,16) size 140x38 [r=1 c=2 rs=1 cs=1]
+      LayoutTable {TABLE} at (0,0) size 463x328
+        LayoutTableSection {TBODY} at (0,0) size 463x328
+          LayoutTableRow {TR} at (0,1) size 463x14
+            LayoutTableCell {TH} at (1,1) size 63x14 [bgcolor=#DDDD99] [r=0 c=0 rs=1 cs=1]
+              LayoutText {#text} at (5,0) size 53x14
+                text run at (5,0) width 53: "viewBox?"
+            LayoutTableCell {TH} at (65,1) size 117x14 [bgcolor=#DDDD99] [r=0 c=1 rs=1 cs=1]
+              LayoutText {#text} at (0,0) size 117x14
+                text run at (0,0) width 117: "preserve\x{AD}Aspect\x{AD}Ratio"
+            LayoutTableCell {TH} at (183,1) size 139x14 [bgcolor=#DDDD99] [r=0 c=2 rs=1 cs=1]
+              LayoutText {#text} at (53,0) size 33x14
+                text run at (53,0) width 33: "<img>"
+            LayoutTableCell {TH} at (323,1) size 139x14 [bgcolor=#DDDD99] [r=0 c=3 rs=1 cs=1]
+              LayoutText {#text} at (46,0) size 47x14
+                text run at (46,0) width 47: "<object>"
+          LayoutTableRow {TR} at (0,16) size 463x38
+            LayoutTableCell {TH} at (1,86) size 63x14 [bgcolor=#DDDD99] [r=1 c=0 rs=4 cs=1]
+              LayoutText {#text} at (0,0) size 63x14
+                text run at (0,0) width 63: "No viewBox"
+            LayoutTableCell {TH} at (65,35) size 117x0 [bgcolor=#DDDD99] [r=1 c=1 rs=1 cs=1]
+            LayoutTableCell {TD} at (183,16) size 139x38 [r=1 c=2 rs=1 cs=1]
               LayoutImage {IMG} at (0,0) size 138.88x34.72 [border: (1.38px dashed #800000)]
               LayoutText {#text} at (0,0) size 0x0
-            LayoutTableCell {TD} at (326,16) size 140x38 [r=1 c=3 rs=1 cs=1]
+            LayoutTableCell {TD} at (323,16) size 139x38 [r=1 c=3 rs=1 cs=1]
               LayoutText {#text} at (0,0) size 0x0
-          LayoutTableRow {TR} at (0,55) size 467x38
-            LayoutTableCell {TH} at (66,67) size 118x14 [bgcolor=#DDDD99] [r=2 c=1 rs=1 cs=1]
-              LayoutText {#text} at (45,0) size 28x14
-                text run at (45,0) width 28: "none"
-            LayoutTableCell {TD} at (185,55) size 140x38 [r=2 c=2 rs=1 cs=1]
+          LayoutTableRow {TR} at (0,55) size 463x38
+            LayoutTableCell {TH} at (65,67) size 117x14 [bgcolor=#DDDD99] [r=2 c=1 rs=1 cs=1]
+              LayoutText {#text} at (44,0) size 29x14
+                text run at (44,0) width 29: "none"
+            LayoutTableCell {TD} at (183,55) size 139x38 [r=2 c=2 rs=1 cs=1]
               LayoutImage {IMG} at (0,0) size 138.88x34.72 [border: (1.38px dashed #800000)]
               LayoutText {#text} at (0,0) size 0x0
-            LayoutTableCell {TD} at (326,55) size 140x38 [r=2 c=3 rs=1 cs=1]
+            LayoutTableCell {TD} at (323,55) size 139x38 [r=2 c=3 rs=1 cs=1]
               LayoutText {#text} at (0,0) size 0x0
-          LayoutTableRow {TR} at (0,94) size 467x38
-            LayoutTableCell {TH} at (66,106) size 118x14 [bgcolor=#DDDD99] [r=3 c=1 rs=1 cs=1]
-              LayoutText {#text} at (44,0) size 30x14
-                text run at (44,0) width 30: "meet"
-            LayoutTableCell {TD} at (185,94) size 140x38 [r=3 c=2 rs=1 cs=1]
+          LayoutTableRow {TR} at (0,94) size 463x38
+            LayoutTableCell {TH} at (65,106) size 117x14 [bgcolor=#DDDD99] [r=3 c=1 rs=1 cs=1]
+              LayoutText {#text} at (44,0) size 29x14
+                text run at (44,0) width 29: "meet"
+            LayoutTableCell {TD} at (183,94) size 139x38 [r=3 c=2 rs=1 cs=1]
               LayoutImage {IMG} at (0,0) size 138.88x34.72 [border: (1.38px dashed #800000)]
               LayoutText {#text} at (0,0) size 0x0
-            LayoutTableCell {TD} at (326,94) size 140x38 [r=3 c=3 rs=1 cs=1]
+            LayoutTableCell {TD} at (323,94) size 139x38 [r=3 c=3 rs=1 cs=1]
               LayoutText {#text} at (0,0) size 0x0
-          LayoutTableRow {TR} at (0,133) size 467x38
-            LayoutTableCell {TH} at (66,145) size 118x14 [bgcolor=#DDDD99] [r=4 c=1 rs=1 cs=1]
-              LayoutText {#text} at (46,0) size 26x14
-                text run at (46,0) width 26: "slice"
-            LayoutTableCell {TD} at (185,133) size 140x38 [r=4 c=2 rs=1 cs=1]
+          LayoutTableRow {TR} at (0,133) size 463x38
+            LayoutTableCell {TH} at (65,145) size 117x14 [bgcolor=#DDDD99] [r=4 c=1 rs=1 cs=1]
+              LayoutText {#text} at (45,0) size 27x14
+                text run at (45,0) width 27: "slice"
+            LayoutTableCell {TD} at (183,133) size 139x38 [r=4 c=2 rs=1 cs=1]
               LayoutImage {IMG} at (0,0) size 138.88x34.72 [border: (1.38px dashed #800000)]
               LayoutText {#text} at (0,0) size 0x0
-            LayoutTableCell {TD} at (326,133) size 140x38 [r=4 c=3 rs=1 cs=1]
+            LayoutTableCell {TD} at (323,133) size 139x38 [r=4 c=3 rs=1 cs=1]
               LayoutText {#text} at (0,0) size 0x0
-          LayoutTableRow {TR} at (0,172) size 467x38
-            LayoutTableCell {TH} at (1,242) size 64x14 [bgcolor=#DDDD99] [r=5 c=0 rs=4 cs=1]
-              LayoutText {#text} at (9,0) size 46x14
-                text run at (9,0) width 46: "viewBox"
-            LayoutTableCell {TH} at (66,191) size 118x0 [bgcolor=#DDDD99] [r=5 c=1 rs=1 cs=1]
-            LayoutTableCell {TD} at (185,172) size 140x38 [r=5 c=2 rs=1 cs=1]
+          LayoutTableRow {TR} at (0,172) size 463x38
+            LayoutTableCell {TH} at (1,242) size 63x14 [bgcolor=#DDDD99] [r=5 c=0 rs=4 cs=1]
+              LayoutText {#text} at (8,0) size 47x14
+                text run at (8,0) width 47: "viewBox"
+            LayoutTableCell {TH} at (65,191) size 117x0 [bgcolor=#DDDD99] [r=5 c=1 rs=1 cs=1]
+            LayoutTableCell {TD} at (183,172) size 139x38 [r=5 c=2 rs=1 cs=1]
               LayoutImage {IMG} at (0,0) size 138.88x34.72 [border: (1.38px dashed #800000)]
               LayoutText {#text} at (0,0) size 0x0
-            LayoutTableCell {TD} at (326,172) size 140x38 [r=5 c=3 rs=1 cs=1]
+            LayoutTableCell {TD} at (323,172) size 139x38 [r=5 c=3 rs=1 cs=1]
               LayoutText {#text} at (0,0) size 0x0
-          LayoutTableRow {TR} at (0,211) size 467x38
-            LayoutTableCell {TH} at (66,223) size 118x14 [bgcolor=#DDDD99] [r=6 c=1 rs=1 cs=1]
-              LayoutText {#text} at (45,0) size 28x14
-                text run at (45,0) width 28: "none"
-            LayoutTableCell {TD} at (185,211) size 140x38 [r=6 c=2 rs=1 cs=1]
+          LayoutTableRow {TR} at (0,211) size 463x38
+            LayoutTableCell {TH} at (65,223) size 117x14 [bgcolor=#DDDD99] [r=6 c=1 rs=1 cs=1]
+              LayoutText {#text} at (44,0) size 29x14
+                text run at (44,0) width 29: "none"
+            LayoutTableCell {TD} at (183,211) size 139x38 [r=6 c=2 rs=1 cs=1]
               LayoutImage {IMG} at (0,0) size 138.88x34.72 [border: (1.38px dashed #800000)]
               LayoutText {#text} at (0,0) size 0x0
-            LayoutTableCell {TD} at (326,211) size 140x38 [r=6 c=3 rs=1 cs=1]
+            LayoutTableCell {TD} at (323,211) size 139x38 [r=6 c=3 rs=1 cs=1]
               LayoutText {#text} at (0,0) size 0x0
-          LayoutTableRow {TR} at (0,250) size 467x38
-            LayoutTableCell {TH} at (66,262) size 118x14 [bgcolor=#DDDD99] [r=7 c=1 rs=1 cs=1]
-              LayoutText {#text} at (44,0) size 30x14
-                text run at (44,0) width 30: "meet"
-            LayoutTableCell {TD} at (185,250) size 140x38 [r=7 c=2 rs=1 cs=1]
+          LayoutTableRow {TR} at (0,250) size 463x38
+            LayoutTableCell {TH} at (65,262) size 117x14 [bgcolor=#DDDD99] [r=7 c=1 rs=1 cs=1]
+              LayoutText {#text} at (44,0) size 29x14
+                text run at (44,0) width 29: "meet"
+            LayoutTableCell {TD} at (183,250) size 139x38 [r=7 c=2 rs=1 cs=1]
               LayoutImage {IMG} at (0,0) size 138.88x34.72 [border: (1.38px dashed #800000)]
               LayoutText {#text} at (0,0) size 0x0
-            LayoutTableCell {TD} at (326,250) size 140x38 [r=7 c=3 rs=1 cs=1]
+            LayoutTableCell {TD} at (323,250) size 139x38 [r=7 c=3 rs=1 cs=1]
               LayoutText {#text} at (0,0) size 0x0
-          LayoutTableRow {TR} at (0,289) size 467x38
-            LayoutTableCell {TH} at (66,301) size 118x14 [bgcolor=#DDDD99] [r=8 c=1 rs=1 cs=1]
-              LayoutText {#text} at (46,0) size 26x14
-                text run at (46,0) width 26: "slice"
-            LayoutTableCell {TD} at (185,289) size 140x38 [r=8 c=2 rs=1 cs=1]
+          LayoutTableRow {TR} at (0,289) size 463x38
+            LayoutTableCell {TH} at (65,301) size 117x14 [bgcolor=#DDDD99] [r=8 c=1 rs=1 cs=1]
+              LayoutText {#text} at (45,0) size 27x14
+                text run at (45,0) width 27: "slice"
+            LayoutTableCell {TD} at (183,289) size 139x38 [r=8 c=2 rs=1 cs=1]
               LayoutImage {IMG} at (0,0) size 138.88x34.72 [border: (1.38px dashed #800000)]
               LayoutText {#text} at (0,0) size 0x0
-            LayoutTableCell {TD} at (326,289) size 140x38 [r=8 c=3 rs=1 cs=1]
+            LayoutTableCell {TD} at (323,289) size 139x38 [r=8 c=3 rs=1 cs=1]
               LayoutText {#text} at (0,0) size 0x0
-layer at (332,22) size 139x35
+layer at (329,22) size 139x35
   LayoutEmbeddedObject {OBJECT} at (0,0) size 138.88x34.72 [border: (0.69px dashed #008000)]
     layer at (0,0) size 133x29
       LayoutView at (0,0) size 133x29
     layer at (0,0) size 133x29
       LayoutSVGRoot {svg} at (0,0) size 133x29
         LayoutSVGEllipse {circle} at (0,0) size 220x220 [stroke={[type=SOLID] [color=#000000]}] [fill={[type=SOLID] [color=#D9BB7A] [fill rule=EVEN-ODD]}] [cx=110.00] [cy=110.00] [r=110.00]
-layer at (332,61) size 139x35
+layer at (329,61) size 139x35
   LayoutEmbeddedObject {OBJECT} at (0,0) size 138.88x34.72 [border: (0.69px dashed #008000)]
     layer at (0,0) size 133x29
       LayoutView at (0,0) size 133x29
@@ -108,7 +108,7 @@
         LayoutSVGHiddenContainer {defs} at (0,0) size 0x0
         LayoutSVGContainer {g} at (162.86,403.79) size 362.86x362.86 [transform={m=((1.00,0.00)(0.00,1.00)) t=(-162.36,-403.29)}]
           LayoutSVGPath {path} at (162.86,403.79) size 362.86x362.86 [stroke={[type=SOLID] [color=#000000]}] [fill={[type=SOLID] [color=#D9BB7A] [fill rule=EVEN-ODD]}] [data="M 525.714 585.219 A 181.429 181.429 0 1 1 162.857 585.219 A 181.429 181.429 0 1 1 525.714 585.219 Z"]
-layer at (332,100) size 139x35
+layer at (329,100) size 139x35
   LayoutEmbeddedObject {OBJECT} at (0,0) size 138.88x34.72 [border: (0.69px dashed #008000)]
     layer at (0,0) size 133x29
       LayoutView at (0,0) size 133x29
@@ -117,7 +117,7 @@
         LayoutSVGHiddenContainer {defs} at (0,0) size 0x0
         LayoutSVGContainer {g} at (162.86,403.79) size 362.86x362.86 [transform={m=((1.00,0.00)(0.00,1.00)) t=(-162.36,-403.29)}]
           LayoutSVGPath {path} at (162.86,403.79) size 362.86x362.86 [stroke={[type=SOLID] [color=#000000]}] [fill={[type=SOLID] [color=#D9BB7A] [fill rule=EVEN-ODD]}] [data="M 525.714 585.219 A 181.429 181.429 0 1 1 162.857 585.219 A 181.429 181.429 0 1 1 525.714 585.219 Z"]
-layer at (332,139) size 139x35
+layer at (329,139) size 139x35
   LayoutEmbeddedObject {OBJECT} at (0,0) size 138.88x34.72 [border: (0.69px dashed #008000)]
     layer at (0,0) size 133x29
       LayoutView at (0,0) size 133x29
@@ -126,7 +126,7 @@
         LayoutSVGHiddenContainer {defs} at (0,0) size 0x0
         LayoutSVGContainer {g} at (162.86,403.79) size 362.86x362.86 [transform={m=((1.00,0.00)(0.00,1.00)) t=(-162.36,-403.29)}]
           LayoutSVGPath {path} at (162.86,403.79) size 362.86x362.86 [stroke={[type=SOLID] [color=#000000]}] [fill={[type=SOLID] [color=#D9BB7A] [fill rule=EVEN-ODD]}] [data="M 525.714 585.219 A 181.429 181.429 0 1 1 162.857 585.219 A 181.429 181.429 0 1 1 525.714 585.219 Z"]
-layer at (332,178) size 139x35
+layer at (329,178) size 139x35
   LayoutEmbeddedObject {OBJECT} at (0,0) size 138.88x34.72 [border: (0.69px dashed #008000)]
     layer at (0,0) size 133x29
       LayoutView at (0,0) size 133x29
@@ -135,7 +135,7 @@
         LayoutSVGHiddenContainer {defs} at (0,0) size 0x0
         LayoutSVGContainer {g} at (162.86,403.79) size 362.86x362.86 [transform={m=((1.00,0.00)(0.00,1.00)) t=(-162.36,-403.29)}]
           LayoutSVGPath {path} at (162.86,403.79) size 362.86x362.86 [stroke={[type=SOLID] [color=#000000]}] [fill={[type=SOLID] [color=#D9BB7A] [fill rule=EVEN-ODD]}] [data="M 525.714 585.219 A 181.429 181.429 0 1 1 162.857 585.219 A 181.429 181.429 0 1 1 525.714 585.219 Z"]
-layer at (332,217) size 139x35
+layer at (329,217) size 139x35
   LayoutEmbeddedObject {OBJECT} at (0,0) size 138.88x34.72 [border: (0.69px dashed #008000)]
     layer at (0,0) size 133x29
       LayoutView at (0,0) size 133x29
@@ -144,7 +144,7 @@
         LayoutSVGHiddenContainer {defs} at (0,0) size 0x0
         LayoutSVGContainer {g} at (162.86,403.79) size 362.86x362.86 [transform={m=((1.00,0.00)(0.00,1.00)) t=(-162.36,-403.29)}]
           LayoutSVGPath {path} at (162.86,403.79) size 362.86x362.86 [stroke={[type=SOLID] [color=#000000]}] [fill={[type=SOLID] [color=#D9BB7A] [fill rule=EVEN-ODD]}] [data="M 525.714 585.219 A 181.429 181.429 0 1 1 162.857 585.219 A 181.429 181.429 0 1 1 525.714 585.219 Z"]
-layer at (332,256) size 139x35
+layer at (329,256) size 139x35
   LayoutEmbeddedObject {OBJECT} at (0,0) size 138.88x34.72 [border: (0.69px dashed #008000)]
     layer at (0,0) size 133x29
       LayoutView at (0,0) size 133x29
@@ -153,7 +153,7 @@
         LayoutSVGHiddenContainer {defs} at (0,0) size 0x0
         LayoutSVGContainer {g} at (162.86,403.79) size 362.86x362.86 [transform={m=((1.00,0.00)(0.00,1.00)) t=(-162.36,-403.29)}]
           LayoutSVGPath {path} at (162.86,403.79) size 362.86x362.86 [stroke={[type=SOLID] [color=#000000]}] [fill={[type=SOLID] [color=#D9BB7A] [fill rule=EVEN-ODD]}] [data="M 525.714 585.219 A 181.429 181.429 0 1 1 162.857 585.219 A 181.429 181.429 0 1 1 525.714 585.219 Z"]
-layer at (332,295) size 139x35
+layer at (329,295) size 139x35
   LayoutEmbeddedObject {OBJECT} at (0,0) size 138.88x34.72 [border: (0.69px dashed #008000)]
     layer at (0,0) size 133x29
       LayoutView at (0,0) size 133x29
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.png
index 809cddc..8c86f65 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.txt
index 061d399..d2b6c58 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.txt
@@ -3,32 +3,32 @@
 layer at (0,0) size 800x199
   LayoutBlockFlow {html} at (0,0) size 800x199.09
     LayoutBlockFlow {body} at (5.55,5.55) size 788.91x188
-      LayoutTable {table} at (143.45,0) size 502x188
-        LayoutTableSection (anonymous) at (0,0) size 502x188
-          LayoutTableRow {tr} at (0,0) size 502x188
-            LayoutTableCell {td} at (0,0) size 502x188 [r=0 c=0 rs=1 cs=3]
-              LayoutTable {table} at (7.44,6) size 489x176
-                LayoutTableSection (anonymous) at (0,0) size 489x176
-                  LayoutTableRow {tr} at (0,1) size 489x66
-                    LayoutTableCell {td} at (1,1) size 487x65.75 [r=0 c=0 rs=1 cs=2]
-                      LayoutBlockFlow {h1} at (5.55,19.88) size 477x26
-                        LayoutText {#text} at (0,0) size 477x25
-                          text run at (0,0) width 477: "Both sides should have identical size after zooming"
-                  LayoutTableRow {tr} at (0,68) size 489x24
-                    LayoutTableCell {td} at (1,68) size 243x24 [r=1 c=0 rs=1 cs=1]
-                      LayoutText {#text} at (96,5) size 51x14
-                        text run at (96,5) width 51: "SVG Image"
-                    LayoutTableCell {td} at (245,68) size 243x24 [r=1 c=1 rs=1 cs=1]
+      LayoutTable {table} at (144.45,0) size 500x188
+        LayoutTableSection (anonymous) at (0,0) size 500x188
+          LayoutTableRow {tr} at (0,0) size 500x188
+            LayoutTableCell {td} at (0,0) size 500x188 [r=0 c=0 rs=1 cs=3]
+              LayoutTable {table} at (6,6) size 488x176
+                LayoutTableSection (anonymous) at (0,0) size 488x176
+                  LayoutTableRow {tr} at (0,1) size 488x66
+                    LayoutTableCell {td} at (1,1) size 486x65.75 [r=0 c=0 rs=1 cs=2]
+                      LayoutBlockFlow {h1} at (5,19.88) size 476x26
+                        LayoutText {#text} at (0,0) size 476x25
+                          text run at (0,0) width 476: "Both sides should have identical size after zooming"
+                  LayoutTableRow {tr} at (0,68) size 488x24
+                    LayoutTableCell {td} at (1,68) size 242x24 [r=1 c=0 rs=1 cs=1]
+                      LayoutText {#text} at (96,5) size 50x14
+                        text run at (96,5) width 50: "SVG Image"
+                    LayoutTableCell {td} at (244,68) size 243x24 [r=1 c=1 rs=1 cs=1]
                       LayoutText {#text} at (95,5) size 53x14
                         text run at (95,5) width 53: "PNG Image"
-                  LayoutTableRow {tr} at (0,93) size 489x82
-                    LayoutTableCell {td} at (1,93) size 243x82 [r=2 c=0 rs=1 cs=1]
+                  LayoutTableRow {tr} at (0,93) size 488x82
+                    LayoutTableCell {td} at (1,93) size 242x82 [r=2 c=0 rs=1 cs=1]
                       LayoutText {#text} at (0,0) size 0x0
-                    LayoutTableCell {td} at (245,93) size 243x82 [r=2 c=1 rs=1 cs=1]
+                    LayoutTableCell {td} at (244,93) size 243x82 [r=2 c=1 rs=1 cs=1]
                       LayoutImage {img} at (5,5) size 138.88x69.44
                       LayoutText {#text} at (0,0) size 0x0
-layer at (257,110) size 139x69
-  LayoutEmbeddedObject {object} at (99.13,5) size 138.88x69.44
+layer at (255,110) size 139x69
+  LayoutEmbeddedObject {object} at (98.13,5) size 138.88x69.44
     layer at (0,0) size 139x69
       LayoutView at (0,0) size 139x69
     layer at (0,0) size 139x69
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.png
index 809cddc..8c86f65 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.txt
index 061d399..d2b6c58 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.txt
@@ -3,32 +3,32 @@
 layer at (0,0) size 800x199
   LayoutBlockFlow {html} at (0,0) size 800x199.09
     LayoutBlockFlow {body} at (5.55,5.55) size 788.91x188
-      LayoutTable {table} at (143.45,0) size 502x188
-        LayoutTableSection (anonymous) at (0,0) size 502x188
-          LayoutTableRow {tr} at (0,0) size 502x188
-            LayoutTableCell {td} at (0,0) size 502x188 [r=0 c=0 rs=1 cs=3]
-              LayoutTable {table} at (7.44,6) size 489x176
-                LayoutTableSection (anonymous) at (0,0) size 489x176
-                  LayoutTableRow {tr} at (0,1) size 489x66
-                    LayoutTableCell {td} at (1,1) size 487x65.75 [r=0 c=0 rs=1 cs=2]
-                      LayoutBlockFlow {h1} at (5.55,19.88) size 477x26
-                        LayoutText {#text} at (0,0) size 477x25
-                          text run at (0,0) width 477: "Both sides should have identical size after zooming"
-                  LayoutTableRow {tr} at (0,68) size 489x24
-                    LayoutTableCell {td} at (1,68) size 243x24 [r=1 c=0 rs=1 cs=1]
-                      LayoutText {#text} at (96,5) size 51x14
-                        text run at (96,5) width 51: "SVG Image"
-                    LayoutTableCell {td} at (245,68) size 243x24 [r=1 c=1 rs=1 cs=1]
+      LayoutTable {table} at (144.45,0) size 500x188
+        LayoutTableSection (anonymous) at (0,0) size 500x188
+          LayoutTableRow {tr} at (0,0) size 500x188
+            LayoutTableCell {td} at (0,0) size 500x188 [r=0 c=0 rs=1 cs=3]
+              LayoutTable {table} at (6,6) size 488x176
+                LayoutTableSection (anonymous) at (0,0) size 488x176
+                  LayoutTableRow {tr} at (0,1) size 488x66
+                    LayoutTableCell {td} at (1,1) size 486x65.75 [r=0 c=0 rs=1 cs=2]
+                      LayoutBlockFlow {h1} at (5,19.88) size 476x26
+                        LayoutText {#text} at (0,0) size 476x25
+                          text run at (0,0) width 476: "Both sides should have identical size after zooming"
+                  LayoutTableRow {tr} at (0,68) size 488x24
+                    LayoutTableCell {td} at (1,68) size 242x24 [r=1 c=0 rs=1 cs=1]
+                      LayoutText {#text} at (96,5) size 50x14
+                        text run at (96,5) width 50: "SVG Image"
+                    LayoutTableCell {td} at (244,68) size 243x24 [r=1 c=1 rs=1 cs=1]
                       LayoutText {#text} at (95,5) size 53x14
                         text run at (95,5) width 53: "PNG Image"
-                  LayoutTableRow {tr} at (0,93) size 489x82
-                    LayoutTableCell {td} at (1,93) size 243x82 [r=2 c=0 rs=1 cs=1]
+                  LayoutTableRow {tr} at (0,93) size 488x82
+                    LayoutTableCell {td} at (1,93) size 242x82 [r=2 c=0 rs=1 cs=1]
                       LayoutText {#text} at (0,0) size 0x0
-                    LayoutTableCell {td} at (245,93) size 243x82 [r=2 c=1 rs=1 cs=1]
+                    LayoutTableCell {td} at (244,93) size 243x82 [r=2 c=1 rs=1 cs=1]
                       LayoutImage {img} at (5,5) size 138.88x69.44
                       LayoutText {#text} at (0,0) size 0x0
-layer at (257,110) size 139x69
-  LayoutEmbeddedObject {object} at (99.13,5) size 138.88x69.44
+layer at (255,110) size 139x69
+  LayoutEmbeddedObject {object} at (98.13,5) size 138.88x69.44
     layer at (0,0) size 139x69
       LayoutView at (0,0) size 139x69
     layer at (0,0) size 139x69
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.png
index 8655d45..f31ff92b 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.txt
index 9ce1c95..c33d0b2 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.txt
@@ -3,32 +3,32 @@
 layer at (0,0) size 800x380
   LayoutBlockFlow {html} at (0,0) size 800x380.09
     LayoutBlockFlow {body} at (5.55,5.55) size 788.91x369
-      LayoutTable {table} at (41.45,0) size 706x369
-        LayoutTableSection (anonymous) at (0,0) size 706x369
-          LayoutTableRow {tr} at (0,0) size 706x369
-            LayoutTableCell {td} at (0,0) size 706x369 [r=0 c=0 rs=1 cs=3]
-              LayoutTable {table} at (7.44,6) size 693x357
-                LayoutTableSection (anonymous) at (0,0) size 693x357
-                  LayoutTableRow {tr} at (0,1) size 693x66
-                    LayoutTableCell {td} at (1,1) size 691x65.75 [r=0 c=0 rs=1 cs=2]
-                      LayoutBlockFlow {h1} at (5.55,19.88) size 681x26
-                        LayoutText {#text} at (102,0) size 477x25
-                          text run at (102,0) width 477: "Both sides should have identical size after zooming"
-                  LayoutTableRow {tr} at (0,68) size 693x24
-                    LayoutTableCell {td} at (1,68) size 345x24 [r=1 c=0 rs=1 cs=1]
-                      LayoutText {#text} at (147,5) size 51x14
-                        text run at (147,5) width 51: "SVG Image"
-                    LayoutTableCell {td} at (347,68) size 345x24 [r=1 c=1 rs=1 cs=1]
-                      LayoutText {#text} at (146,5) size 53x14
-                        text run at (146,5) width 53: "PNG Image"
-                  LayoutTableRow {tr} at (0,93) size 693x263
-                    LayoutTableCell {td} at (1,93) size 345x263 [r=2 c=0 rs=1 cs=1]
+      LayoutTable {table} at (42.95,0) size 703x369
+        LayoutTableSection (anonymous) at (0,0) size 703x369
+          LayoutTableRow {tr} at (0,0) size 703x369
+            LayoutTableCell {td} at (0,0) size 703x369 [r=0 c=0 rs=1 cs=3]
+              LayoutTable {table} at (6,6) size 691x357
+                LayoutTableSection (anonymous) at (0,0) size 691x357
+                  LayoutTableRow {tr} at (0,1) size 691x66
+                    LayoutTableCell {td} at (1,1) size 689x65.75 [r=0 c=0 rs=1 cs=2]
+                      LayoutBlockFlow {h1} at (5,19.88) size 679x26
+                        LayoutText {#text} at (101,0) size 477x25
+                          text run at (101,0) width 477: "Both sides should have identical size after zooming"
+                  LayoutTableRow {tr} at (0,68) size 691x24
+                    LayoutTableCell {td} at (1,68) size 344x24 [r=1 c=0 rs=1 cs=1]
+                      LayoutText {#text} at (147,5) size 50x14
+                        text run at (147,5) width 50: "SVG Image"
+                    LayoutTableCell {td} at (346,68) size 344x24 [r=1 c=1 rs=1 cs=1]
+                      LayoutText {#text} at (145,5) size 54x14
+                        text run at (145,5) width 54: "PNG Image"
+                  LayoutTableRow {tr} at (0,93) size 691x263
+                    LayoutTableCell {td} at (1,93) size 344x263 [r=2 c=0 rs=1 cs=1]
                       LayoutText {#text} at (0,0) size 0x0
-                    LayoutTableCell {td} at (347,93) size 345x263 [r=2 c=1 rs=1 cs=1]
+                    LayoutTableCell {td} at (346,93) size 344x263 [r=2 c=1 rs=1 cs=1]
                       LayoutImage {img} at (5,5) size 333.33x249.97
                       LayoutText {#text} at (0,0) size 0x0
-layer at (62,110) size 333x250
-  LayoutEmbeddedObject {object} at (6.67,5) size 333.33x249.98
+layer at (61,110) size 333x250
+  LayoutEmbeddedObject {object} at (5.67,5) size 333.33x249.98
     layer at (0,0) size 333x250
       LayoutView at (0,0) size 333x250
     layer at (0,0) size 333x250
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla_expected_failures/bugs/bug89315-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla_expected_failures/bugs/bug89315-expected.png
index cf2d15d9..68319184 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla_expected_failures/bugs/bug89315-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla_expected_failures/bugs/bug89315-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/animations-unprefixed/frames-timing-function.html b/third_party/WebKit/LayoutTests/virtual/stable/animations-unprefixed/frames-timing-function.html
new file mode 100644
index 0000000..28eb176
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/stable/animations-unprefixed/frames-timing-function.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+
+<style>
+#target {
+  transition-timing-function: frames(4);
+  animation-timing-function: frames(4);
+}
+</style>
+
+<div id="target"></div>
+
+<script>
+test(function() {
+  assert_equals(getComputedStyle(target).transitionTimingFunction, 'ease');
+  assert_equals(getComputedStyle(target).animationTimingFunction, 'ease');
+}, 'The frames() timing function is still experimental and should not be exposed to stable.');
+</script>
diff --git a/third_party/WebKit/LayoutTests/webshare/resources/mock-share-service.js b/third_party/WebKit/LayoutTests/webshare/resources/mock-share-service.js
index 2463058..ecd522e3 100644
--- a/third_party/WebKit/LayoutTests/webshare/resources/mock-share-service.js
+++ b/third_party/WebKit/LayoutTests/webshare/resources/mock-share-service.js
@@ -66,10 +66,14 @@
 
 // Copied from resources/bluetooth/bluetooth-helpers.js.
 function callWithKeyDown(functionCalledOnKeyPress) {
-  return new Promise(resolve => {
+  return new Promise((resolve, reject) => {
     function onKeyPress() {
       document.removeEventListener('keypress', onKeyPress, false);
-      resolve(functionCalledOnKeyPress());
+      try {
+        resolve(functionCalledOnKeyPress());
+      } catch (e) {
+        reject(e);
+      }
     }
     document.addEventListener('keypress', onKeyPress, false);
 
diff --git a/third_party/WebKit/LayoutTests/webshare/share-nonutf8-encoding.html b/third_party/WebKit/LayoutTests/webshare/share-nonutf8-encoding.html
index aeae78e..b400d503 100644
--- a/third_party/WebKit/LayoutTests/webshare/share-nonutf8-encoding.html
+++ b/third_party/WebKit/LayoutTests/webshare/share-nonutf8-encoding.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<meta charset="iso-8859-1">
+<meta charset="windows-1252">
 <script src="../resources/testharness.js"></script>
 <script src="../resources/testharnessreport.js"></script>
 <script src="../resources/mojo-helpers.js"></script>
@@ -7,9 +7,11 @@
 <script>
 
 // Exact same test as in share-success.html, with same expectations. This tests
-// that the page's encoding (ISO-8859-1) is ignored and Unicode characters are
+// that the page's encoding (Windows-1252) is ignored and Unicode characters are
 // always percent-encoded in UTF-8.
 share_test((t, webshare, mock) => {
+  assert_equals(document.characterSet, 'windows-1252');
+
   const title = 'f\xe1ncy \u5199\u4f5c \ud83d\ude31';
   const url = 'https://\u6d4b\u8bd5.example.com/\ud83d\udcc4';
   const url_ascii = 'https://xn--0zwm56d.example.com/%F0%9F%93%84';
diff --git a/third_party/WebKit/LayoutTests/webshare/share-success.html b/third_party/WebKit/LayoutTests/webshare/share-success.html
index 29ba63df..a23f2512 100644
--- a/third_party/WebKit/LayoutTests/webshare/share-success.html
+++ b/third_party/WebKit/LayoutTests/webshare/share-success.html
@@ -6,7 +6,7 @@
 <script>
 
 function getAbsoluteUrl(url) {
-  return new URL(url, location).toString();
+  return new URL(url, document.baseURI).toString();
 }
 
 share_test((t, webshare, mock) => {
@@ -14,7 +14,8 @@
   mock.pushShareResult('the title', 'the message', getAbsoluteUrl(url),
                        webshare.ShareError.OK);
   return callWithKeyDown(() => navigator.share(
-        {title: 'the title', text: 'the message', url: url}));
+        {title: 'the title', text: 'the message', url: url})).then(
+        result => assert_equals(result, undefined));
 }, 'successful share');
 
 share_test((t, webshare, mock) => {
@@ -42,7 +43,7 @@
 
 share_test((t, webshare, mock) => {
   const url = '';
-  mock.pushShareResult('', '', getAbsoluteUrl(url), webshare.ShareError.OK);
+  mock.pushShareResult('', '', document.baseURI, webshare.ShareError.OK);
   return callWithKeyDown(() => navigator.share({url: url}));
 }, 'successful share with an empty URL');
 
diff --git a/third_party/WebKit/LayoutTests/webshare/share-types.html b/third_party/WebKit/LayoutTests/webshare/share-types.html
index 3bcc658a..56249c0 100644
--- a/third_party/WebKit/LayoutTests/webshare/share-types.html
+++ b/third_party/WebKit/LayoutTests/webshare/share-types.html
@@ -6,7 +6,7 @@
 <script>
 
 function getAbsoluteUrl(url) {
-  return new URL(url, location).toString();
+  return new URL(url, document.baseURI).toString();
 }
 
 share_test((t, webshare, mock) => {
@@ -20,8 +20,11 @@
 }, 'share of null (expect treated as empty dictionary)');
 
 share_test((t, webshare, mock) => {
-  mock.pushShareResult('384957', '[object Object]', '', webshare.ShareError.OK);
-  return callWithKeyDown(() => navigator.share({title: 384957, text: {}}));
+  mock.pushShareResult('true', 'the object', getAbsoluteUrl('384957'), webshare.ShareError.OK);
+
+  const objectWithToString = {toString() { return 'the object'; }};
+  return callWithKeyDown(() => navigator.share(
+        {title: true, text: objectWithToString, url: 384957}));
 }, 'share of types other than string (expect implicitly converted to string)');
 
 share_test((t, webshare, mock) => {
diff --git a/third_party/WebKit/LayoutTests/webshare/share-url-relative.html b/third_party/WebKit/LayoutTests/webshare/share-url-relative.html
new file mode 100644
index 0000000..6567763
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/webshare/share-url-relative.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script src="../resources/mojo-helpers.js"></script>
+<script src="resources/mock-share-service.js"></script>
+<base href="https://www.example.com/some/path.html">
+<script>
+
+share_test((t, webshare, mock) => {
+  const url = 'foo';
+  mock.pushShareResult('', '', 'https://www.example.com/some/foo', webshare.ShareError.OK);
+  return callWithKeyDown(() => navigator.share({url: url}));
+}, 'successful share with a URL relative to document base URL');
+
+</script>
diff --git a/third_party/WebKit/PRESUBMIT.py b/third_party/WebKit/PRESUBMIT.py
index ccd806d1..4ca8cca 100644
--- a/third_party/WebKit/PRESUBMIT.py
+++ b/third_party/WebKit/PRESUBMIT.py
@@ -77,7 +77,7 @@
         maxlen=800, license_header=license_header))
     results.extend(_CheckForNonBlinkVariantMojomIncludes(input_api, output_api))
     results.extend(_CheckTestExpectations(input_api, output_api))
-    results.extend(_CheckChromiumPlatformMacros(input_api, output_api))
+    results.extend(_CheckWtfOsMacros(input_api, output_api))
     results.extend(_CheckWatchlist(input_api, output_api))
     return results
 
@@ -131,16 +131,15 @@
     return results
 
 
-def _CheckChromiumPlatformMacros(input_api, output_api, source_file_filter=None):
-    """Ensures that Blink code uses WTF's platform macros instead of
-    Chromium's. Using the latter has resulted in at least one subtle
-    build breakage."""
-    os_macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bOS_')
+def _CheckWtfOsMacros(input_api, output_api):
+    """Ensures that Blink code uses no WTF's OS macros."""
+    os_macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bOS\(')
     errors = input_api.canned_checks._FindNewViolationsOfRule(
         lambda _, x: not os_macro_re.search(x),
-        input_api, source_file_filter)
-    errors = ['Found use of Chromium OS_* macro in %s. '
-        'Use WTF platform macros instead.' % violation for violation in errors]
+        input_api, None)
+    errors = ['Found deprecated OS() macro in %s. Include build/build_config.h '
+              'and use defined(OS_*) instead.'
+              % violation for violation in errors]
     if errors:
         return [output_api.PresubmitPromptWarning('\n'.join(errors))]
     return []
diff --git a/third_party/WebKit/Source/DEPS b/third_party/WebKit/Source/DEPS
index 079a57f..510a74f9 100644
--- a/third_party/WebKit/Source/DEPS
+++ b/third_party/WebKit/Source/DEPS
@@ -1,6 +1,7 @@
 include_rules = [
     "+base/macros.h",
     "+base/gtest_prod_util.h",
+    "+build",
     "+services/service_manager/public/cpp/connector.h",
     "+testing/gmock/include/gmock",
     "+testing/gtest/include/gtest",
diff --git a/third_party/WebKit/Source/bindings/PRESUBMIT.py b/third_party/WebKit/Source/bindings/PRESUBMIT.py
index e430ded..32d9c44 100644
--- a/third_party/WebKit/Source/bindings/PRESUBMIT.py
+++ b/third_party/WebKit/Source/bindings/PRESUBMIT.py
@@ -60,6 +60,8 @@
         cmd = [input_api.python_executable, run_bindings_tests_path]
     else:
         cmd = [run_bindings_tests_path]
+    if not input_api.verbose:
+        cmd.append('--suppress-diff')
     test_cmd = input_api.Command(
       name=cmd_name,
       cmd=cmd,
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptModule.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptModule.cpp
index 7ed0c47..99bc6ed 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptModule.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptModule.cpp
@@ -177,6 +177,14 @@
   return module->GetStatus();
 }
 
+v8::Local<v8::Value> ScriptModule::ErrorCompletion(ScriptState* script_state) {
+  DCHECK(!IsNull());
+  DCHECK_EQ(ScriptModuleState::kErrored, Status(script_state));
+
+  v8::Local<v8::Module> module = module_->NewLocal(script_state->GetIsolate());
+  return module->GetException();
+}
+
 v8::MaybeLocal<v8::Module> ScriptModule::ResolveModuleCallback(
     v8::Local<v8::Context> context,
     v8::Local<v8::String> specifier,
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptModule.h b/third_party/WebKit/Source/bindings/core/v8/ScriptModule.h
index fa37d90..b62e56da 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptModule.h
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptModule.h
@@ -61,6 +61,10 @@
   Vector<TextPosition> ModuleRequestPositions(ScriptState*);
   ScriptModuleState Status(ScriptState*);
 
+  // Returns record's [[ErrorCompletion]] field's [[Value]].
+  // Should only be used via ModulatorImpl::GetError()
+  v8::Local<v8::Value> ErrorCompletion(ScriptState*);
+
   bool IsHashTableDeletedValue() const {
     return module_.IsHashTableDeletedValue();
   }
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptModuleTest.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptModuleTest.cpp
index 3cd82cb..df7ab812 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptModuleTest.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptModuleTest.cpp
@@ -215,6 +215,47 @@
   EXPECT_EQ("b", resolver->Specifiers()[1]);
 }
 
+TEST(ScriptModuleTest, instantiateError) {
+  V8TestingScope scope;
+
+  auto modulator = new ScriptModuleTestModulator();
+  auto resolver = modulator->GetTestScriptModuleResolver();
+
+  Modulator::SetModulator(scope.GetScriptState(), modulator);
+
+  ScriptModule module_failure = ScriptModule::Compile(
+      scope.GetIsolate(), "nonexistent_function()", "failure.js",
+      kSharableCrossOrigin, TextPosition::MinimumPosition(),
+      ASSERT_NO_EXCEPTION);
+  ASSERT_FALSE(module_failure.IsNull());
+  module_failure.Instantiate(scope.GetScriptState());
+  ASSERT_EQ(ScriptModuleState::kInstantiated,
+            module_failure.Status(scope.GetScriptState()));
+  module_failure.Evaluate(scope.GetScriptState());
+  ASSERT_EQ(ScriptModuleState::kErrored,
+            module_failure.Status(scope.GetScriptState()));
+  v8::Local<v8::Value> error =
+      module_failure.ErrorCompletion(scope.GetScriptState());
+
+  resolver->PushScriptModule(module_failure);
+
+  ScriptModule module = ScriptModule::Compile(
+      scope.GetIsolate(), "import 'failure'; export const c = 123;", "c.js",
+      kSharableCrossOrigin, TextPosition::MinimumPosition(),
+      scope.GetExceptionState());
+  ASSERT_FALSE(module.IsNull());
+  ScriptValue exception = module.Instantiate(scope.GetScriptState());
+  EXPECT_FALSE(exception.IsEmpty());
+  ASSERT_EQ(ScriptModuleState::kErrored, module.Status(scope.GetScriptState()));
+  v8::Local<v8::Value> error2 = module.ErrorCompletion(scope.GetScriptState());
+
+  EXPECT_EQ(error, error2);
+  EXPECT_EQ(error, exception.V8Value());
+
+  ASSERT_EQ(1u, resolver->ResolveCount());
+  EXPECT_EQ("failure", resolver->Specifiers()[0]);
+}
+
 TEST(ScriptModuleTest, Evaluate) {
   V8TestingScope scope;
 
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptSourceCode.h b/third_party/WebKit/Source/bindings/core/v8/ScriptSourceCode.h
index 52c329b..7fe6b98d 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptSourceCode.h
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptSourceCode.h
@@ -58,8 +58,6 @@
   ~ScriptSourceCode();
   DECLARE_TRACE();
 
-  bool IsEmpty() const { return source_.IsEmpty(); }
-
   // The null value represents a missing script, created by the nullary
   // constructor, and differs from the empty script.
   bool IsNull() const { return source_.IsNull(); }
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.cpp b/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.cpp
index 333a417..6a68b14 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.cpp
@@ -554,6 +554,7 @@
   TRACE_EVENT1("v8", "v8.run", "fileName",
                TRACE_STR_COPY(*v8::String::Utf8Value(
                    script->GetUnboundScript()->GetScriptName())));
+  RuntimeCallStatsScopedTracer rcs_scoped_tracer(isolate);
 
   if (v8::MicrotasksScope::GetCurrentDepth(isolate) >= kMaxRecursionDepth)
     return ThrowStackOverflowExceptionIfNeeded(isolate);
@@ -590,6 +591,7 @@
     return v8::MaybeLocal<v8::Value>();
 
   TRACE_EVENT0("v8", "v8.run");
+  RuntimeCallStatsScopedTracer rcs_scoped_tracer(isolate);
   v8::MicrotasksScope microtasks_scope(
       isolate, v8::MicrotasksScope::kDoNotRunMicrotasks);
   v8::MaybeLocal<v8::Value> result = script->Run(isolate->GetCurrentContext());
@@ -601,6 +603,7 @@
     v8::Isolate* isolate,
     v8::Local<v8::Script> script) {
   TRACE_EVENT0("v8", "v8.run");
+  RuntimeCallStatsScopedTracer rcs_scoped_tracer(isolate);
   v8::MicrotasksScope microtasks_scope(
       isolate, v8::MicrotasksScope::kDoNotRunMicrotasks);
   v8::MaybeLocal<v8::Value> result = script->Run(isolate->GetCurrentContext());
@@ -655,6 +658,7 @@
       context->IsDocument() ? ToDocument(context)->GetFrame() : nullptr;
   ScopedFrameBlamer frame_blamer(frame);
   TRACE_EVENT0("v8", "v8.callFunction");
+  RuntimeCallStatsScopedTracer rcs_scoped_tracer(isolate);
 
   int depth = v8::MicrotasksScope::GetCurrentDepth(isolate);
   if (depth >= kMaxRecursionDepth)
@@ -689,6 +693,8 @@
     v8::Local<v8::Value> args[],
     v8::Isolate* isolate) {
   TRACE_EVENT0("v8", "v8.callFunction");
+  RuntimeCallStatsScopedTracer rcs_scoped_tracer(isolate);
+
   CHECK(!ThreadState::Current()->IsWrapperTracingForbidden());
   v8::MicrotasksScope microtasks_scope(
       isolate, v8::MicrotasksScope::kDoNotRunMicrotasks);
diff --git a/third_party/WebKit/Source/build/scripts/make_computed_style_base.py b/third_party/WebKit/Source/build/scripts/make_computed_style_base.py
index 2ab03cfd..6b4bed2 100755
--- a/third_party/WebKit/Source/build/scripts/make_computed_style_base.py
+++ b/third_party/WebKit/Source/build/scripts/make_computed_style_base.py
@@ -346,6 +346,10 @@
         type_name = property_['type_name']
         default_value = property_['default_value']
         size = 1 if type_name == 'bool' else None  # pack bools with 1 bit.
+    elif property_['field_template'] == 'pointer':
+        type_name = property_['type_name']
+        default_value = property_['default_value']
+        size = None
     else:
         assert property_['field_template'] in ('monotonic_flag',)
         type_name = 'bool'
@@ -353,8 +357,9 @@
         size = 1
 
     if property_['wrapper_pointer_name']:
-        assert property_['field_template'] == 'storage_only'
-        type_name = '{}<{}>'.format(property_['wrapper_pointer_name'], type_name)
+        assert property_['field_template'] in ['storage_only', 'pointer']
+        if property_['field_template'] == 'storage_only':
+            type_name = '{}<{}>'.format(property_['wrapper_pointer_name'], type_name)
 
     return Field(
         'property',
diff --git a/third_party/WebKit/Source/build/scripts/templates/ComputedStyleBase.h.tmpl b/third_party/WebKit/Source/build/scripts/templates/ComputedStyleBase.h.tmpl
index 3c982a8..f5abe9f1 100644
--- a/third_party/WebKit/Source/build/scripts/templates/ComputedStyleBase.h.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/ComputedStyleBase.h.tmpl
@@ -24,13 +24,15 @@
 {% import 'fields/monotonic_flag.tmpl' as monotonic_flag %}
 {% import 'fields/storage_only.tmpl' as storage_only %}
 {% import 'fields/external.tmpl' as external %}
+{% import 'fields/pointer.tmpl' as pointer %}
 {% from 'fields/field.tmpl' import encode %}
 {% set field_templates = {
      'keyword': keyword,
      'primitive': primitive,
      'monotonic_flag': monotonic_flag,
      'storage_only': storage_only, 
-     'external': external
+     'external': external,
+     'pointer': pointer
    } %}
 
 namespace blink {
diff --git a/third_party/WebKit/Source/build/scripts/templates/fields/field.tmpl b/third_party/WebKit/Source/build/scripts/templates/fields/field.tmpl
index f84a3ea..6c1b5e1 100644
--- a/third_party/WebKit/Source/build/scripts/templates/fields/field.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/fields/field.tmpl
@@ -64,6 +64,8 @@
 {% macro declare_storage(field) %}
 {% if field.is_bit_field %}
 {{print_if(field.mutable, "mutable ")}}unsigned {{field.name}} : {{field.size}}; // {{field.type_name}}
+{%- elif field.field_template == 'pointer' %}
+{{field.wrapper_pointer_name}}<{{field.type_name}}> {{field.name}};
 {%- else %}
 {{field.type_name}} {{field.name}};
 {%- endif %}
diff --git a/third_party/WebKit/Source/build/scripts/templates/fields/pointer.tmpl b/third_party/WebKit/Source/build/scripts/templates/fields/pointer.tmpl
new file mode 100644
index 0000000..26837be0
--- /dev/null
+++ b/third_party/WebKit/Source/build/scripts/templates/fields/pointer.tmpl
@@ -0,0 +1,20 @@
+{% import 'fields/base.tmpl' as base %}
+{% from 'fields/field.tmpl' import getter_expression, setter_expression, decode %}
+
+{% macro decl_public_methods(field) %}
+static {{field.type_name}}* {{field.initial_method_name}}() {
+  return {{field.default_value}};
+}
+{{field.type_name}}* {{field.getter_method_name}}() const {
+  return {{decode(field, getter_expression(field))}}.Get();
+}
+
+void {{field.setter_method_name}}({{field.wrapper_pointer_name}}<{{field.type_name}}> v) {
+{% if field.group.parent %}
+  {{setter_expression(field)}} = std::move(v);
+{% else %}
+  {{field.name}} = std::move(v);
+{% endif %}
+}
+
+{%- endmacro %}
\ No newline at end of file
diff --git a/third_party/WebKit/Source/core/BUILD.gn b/third_party/WebKit/Source/core/BUILD.gn
index 9450b3d..c8ed280 100644
--- a/third_party/WebKit/Source/core/BUILD.gn
+++ b/third_party/WebKit/Source/core/BUILD.gn
@@ -1424,7 +1424,6 @@
     "layout/ng/ng_min_max_content_size_test.cc",
     "layout/ng/ng_out_of_flow_layout_part_test.cc",
     "layout/ng/ng_relative_utils_test.cc",
-    "layout/ng/ng_space_utils_test.cc",
     "layout/shapes/BoxShapeTest.cpp",
     "layout/svg/LayoutSVGForeignObjectTest.cpp",
     "layout/svg/LayoutSVGRootTest.cpp",
diff --git a/third_party/WebKit/Source/core/animation/BUILD.gn b/third_party/WebKit/Source/core/animation/BUILD.gn
index ae2783d..a5cba13 100644
--- a/third_party/WebKit/Source/core/animation/BUILD.gn
+++ b/third_party/WebKit/Source/core/animation/BUILD.gn
@@ -35,6 +35,8 @@
     "CSSClipInterpolationType.h",
     "CSSColorInterpolationType.cpp",
     "CSSColorInterpolationType.h",
+    "CSSDefaultInterpolationType.cpp",
+    "CSSDefaultInterpolationType.h",
     "CSSFilterListInterpolationType.cpp",
     "CSSFilterListInterpolationType.h",
     "CSSFontSizeInterpolationType.cpp",
@@ -88,8 +90,6 @@
     "CSSTransformOriginInterpolationType.h",
     "CSSTranslateInterpolationType.cpp",
     "CSSTranslateInterpolationType.h",
-    "CSSValueInterpolationType.cpp",
-    "CSSValueInterpolationType.h",
     "CSSVisibilityInterpolationType.cpp",
     "CSSVisibilityInterpolationType.h",
     "ColorPropertyFunctions.cpp",
diff --git a/third_party/WebKit/Source/core/animation/CSSDefaultInterpolationType.cpp b/third_party/WebKit/Source/core/animation/CSSDefaultInterpolationType.cpp
new file mode 100644
index 0000000..38da7ed
--- /dev/null
+++ b/third_party/WebKit/Source/core/animation/CSSDefaultInterpolationType.cpp
@@ -0,0 +1,59 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/animation/CSSDefaultInterpolationType.h"
+
+#include "core/animation/CSSInterpolationEnvironment.h"
+#include "core/animation/StringKeyframe.h"
+#include "core/css/resolver/StyleBuilder.h"
+
+namespace blink {
+
+class CSSDefaultNonInterpolableValue : public NonInterpolableValue {
+ public:
+  ~CSSDefaultNonInterpolableValue() final {}
+
+  static PassRefPtr<CSSDefaultNonInterpolableValue> Create(
+      const CSSValue* css_value) {
+    return AdoptRef(new CSSDefaultNonInterpolableValue(css_value));
+  }
+
+  const CSSValue* CssValue() const { return css_value_.Get(); }
+
+  DECLARE_NON_INTERPOLABLE_VALUE_TYPE();
+
+ private:
+  CSSDefaultNonInterpolableValue(const CSSValue* css_value)
+      : css_value_(css_value) {
+    DCHECK(css_value_);
+  }
+
+  Persistent<const CSSValue> css_value_;
+};
+
+DEFINE_NON_INTERPOLABLE_VALUE_TYPE(CSSDefaultNonInterpolableValue);
+DEFINE_NON_INTERPOLABLE_VALUE_TYPE_CASTS(CSSDefaultNonInterpolableValue);
+
+InterpolationValue CSSDefaultInterpolationType::MaybeConvertSingle(
+    const PropertySpecificKeyframe& keyframe,
+    const InterpolationEnvironment&,
+    const InterpolationValue&,
+    ConversionCheckers&) const {
+  return InterpolationValue(
+      InterpolableList::Create(0),
+      CSSDefaultNonInterpolableValue::Create(
+          ToCSSPropertySpecificKeyframe(keyframe).Value()));
+}
+
+void CSSDefaultInterpolationType::Apply(
+    const InterpolableValue&,
+    const NonInterpolableValue* non_interpolable_value,
+    InterpolationEnvironment& environment) const {
+  StyleBuilder::ApplyProperty(
+      GetProperty().CssProperty(),
+      ToCSSInterpolationEnvironment(environment).GetState(),
+      *ToCSSDefaultNonInterpolableValue(non_interpolable_value)->CssValue());
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/animation/CSSDefaultInterpolationType.h b/third_party/WebKit/Source/core/animation/CSSDefaultInterpolationType.h
new file mode 100644
index 0000000..0f90852
--- /dev/null
+++ b/third_party/WebKit/Source/core/animation/CSSDefaultInterpolationType.h
@@ -0,0 +1,54 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CSSDefaultInterpolationType_h
+#define CSSDefaultInterpolationType_h
+
+#include "core/animation/InterpolationType.h"
+
+namespace blink {
+
+// Never supports pairwise conversion while always supporting single conversion.
+// A catch all default for CSSValue interpolation.
+class CSSDefaultInterpolationType : public InterpolationType {
+ public:
+  CSSDefaultInterpolationType(PropertyHandle property)
+      : InterpolationType(property) {
+    DCHECK(property.IsCSSProperty());
+  }
+
+  InterpolationValue MaybeConvertSingle(const PropertySpecificKeyframe&,
+                                        const InterpolationEnvironment&,
+                                        const InterpolationValue& underlying,
+                                        ConversionCheckers&) const;
+
+  PairwiseInterpolationValue MaybeConvertPairwise(
+      const PropertySpecificKeyframe& start_keyframe,
+      const PropertySpecificKeyframe& end_keyframe,
+      const InterpolationEnvironment&,
+      const InterpolationValue& underlying,
+      ConversionCheckers&) const final {
+    return nullptr;
+  }
+
+  InterpolationValue MaybeConvertUnderlyingValue(
+      const InterpolationEnvironment&) const final {
+    return nullptr;
+  }
+
+  void Composite(UnderlyingValueOwner& underlying_value_owner,
+                 double underlying_fraction,
+                 const InterpolationValue& value,
+                 double interpolation_fraction) const final {
+    underlying_value_owner.Set(*this, value);
+  }
+
+  void Apply(const InterpolableValue&,
+             const NonInterpolableValue*,
+             InterpolationEnvironment&) const final;
+};
+
+}  // namespace blink
+
+#endif  // CSSDefaultInterpolationType_h
diff --git a/third_party/WebKit/Source/core/animation/CSSInterpolationType.cpp b/third_party/WebKit/Source/core/animation/CSSInterpolationType.cpp
index 2df52759..48a9e95 100644
--- a/third_party/WebKit/Source/core/animation/CSSInterpolationType.cpp
+++ b/third_party/WebKit/Source/core/animation/CSSInterpolationType.cpp
@@ -101,6 +101,7 @@
     PropertyHandle property,
     const PropertyRegistration* registration)
     : InterpolationType(property), registration_(registration) {
+  DCHECK(!GetProperty().IsCSSCustomProperty() || registration);
   DCHECK(!isShorthandProperty(CssProperty()));
 }
 
@@ -165,50 +166,25 @@
     const CSSCustomPropertyDeclaration& declaration,
     const StyleResolverState& state,
     ConversionCheckers& conversion_checkers) const {
-  InterpolationValue result = MaybeConvertCustomPropertyDeclarationInternal(
-      declaration, state, conversion_checkers);
-  if (result) {
-    return result;
-  }
-
-  // TODO(alancutter): Make explicit and assert in code that this falls back to
-  // the default CSSValueInterpolationType handler.
-  // This might involve making the "catch-all" InterpolationType explicit
-  // e.g. add bool InterpolationType::isCatchAll().
-  return MaybeConvertValue(declaration, &state, conversion_checkers);
-}
-
-InterpolationValue
-CSSInterpolationType::MaybeConvertCustomPropertyDeclarationInternal(
-    const CSSCustomPropertyDeclaration& declaration,
-    const StyleResolverState& state,
-    ConversionCheckers& conversion_checkers) const {
   const AtomicString& name = declaration.GetName();
   DCHECK_EQ(GetProperty().CustomPropertyName(), name);
 
   if (!declaration.Value()) {
-    // Unregistered custom properties inherit:
-    // https://www.w3.org/TR/css-variables-1/#defining-variables
-    bool is_inherited_property =
-        registration_ ? registration_->Inherits() : true;
+    bool is_inherited_property = Registration().Inherits();
     DCHECK(declaration.IsInitial(is_inherited_property) ||
            declaration.IsInherit(is_inherited_property));
 
-    if (!registration_) {
-      return nullptr;
-    }
-
     const CSSValue* value = nullptr;
     if (declaration.IsInitial(is_inherited_property)) {
-      value = registration_->Initial();
+      value = Registration().Initial();
     } else {
       value = state.ParentStyle()->GetRegisteredVariable(name,
                                                          is_inherited_property);
       if (!value) {
-        value = registration_->Initial();
+        value = Registration().Initial();
       }
       conversion_checkers.push_back(InheritedCustomPropertyChecker::Create(
-          name, is_inherited_property, value, registration_->Initial()));
+          name, is_inherited_property, value, Registration().Initial()));
     }
     if (!value) {
       return nullptr;
@@ -223,19 +199,16 @@
     // property value application with the CSSVariableResolver to apply them in
     // the appropriate order defined by the chain of var() dependencies.
     // All CSSInterpolationTypes should fail convertion here except for
-    // CSSValueInterpolationType.
+    // CSSDefaultInterpolationType.
     return nullptr;
   }
 
-  if (registration_) {
-    const CSSValue* parsed_value =
-        declaration.Value()->ParseForSyntax(registration_->Syntax());
-    if (parsed_value) {
-      return MaybeConvertValue(*parsed_value, &state, conversion_checkers);
-    }
+  const CSSValue* parsed_value =
+      declaration.Value()->ParseForSyntax(Registration().Syntax());
+  if (!parsed_value) {
+    return nullptr;
   }
-
-  return nullptr;
+  return MaybeConvertValue(*parsed_value, &state, conversion_checkers);
 }
 
 InterpolationValue CSSInterpolationType::MaybeConvertUnderlyingValue(
@@ -248,13 +221,10 @@
 
   const PropertyHandle property = GetProperty();
   const AtomicString& name = property.CustomPropertyName();
-  if (!registration_) {
-    return nullptr;
-  }
   const CSSValue* underlying_value =
-      style.GetRegisteredVariable(name, registration_->Inherits());
+      style.GetRegisteredVariable(name, Registration().Inherits());
   if (!underlying_value) {
-    underlying_value = registration_->Initial();
+    underlying_value = Registration().Initial();
   }
   if (!underlying_value) {
     return nullptr;
@@ -287,10 +257,7 @@
 
   const CSSValue* css_value =
       CreateCSSValue(interpolable_value, non_interpolable_value, state);
-  if (css_value->IsCustomPropertyDeclaration()) {
-    StyleBuilder::ApplyProperty(CssProperty(), state, *css_value);
-    return;
-  }
+  DCHECK(!css_value->IsCustomPropertyDeclaration());
 
   // TODO(alancutter): Defer tokenization of the CSSValue until it is needed.
   String string_value = css_value->CssText();
@@ -302,8 +269,7 @@
   ComputedStyle& style = *state.Style();
   const PropertyHandle property = GetProperty();
   const AtomicString& property_name = property.CustomPropertyName();
-  DCHECK(registration_);
-  if (registration_->Inherits()) {
+  if (Registration().Inherits()) {
     style.SetResolvedInheritedVariable(property_name, std::move(variable_data),
                                        css_value);
   } else {
diff --git a/third_party/WebKit/Source/core/animation/CSSInterpolationType.h b/third_party/WebKit/Source/core/animation/CSSInterpolationType.h
index 17e9287..fd9f780 100644
--- a/third_party/WebKit/Source/core/animation/CSSInterpolationType.h
+++ b/third_party/WebKit/Source/core/animation/CSSInterpolationType.h
@@ -74,10 +74,6 @@
       const CSSCustomPropertyDeclaration&,
       const StyleResolverState&,
       ConversionCheckers&) const;
-  InterpolationValue MaybeConvertCustomPropertyDeclarationInternal(
-      const CSSCustomPropertyDeclaration&,
-      const StyleResolverState&,
-      ConversionCheckers&) const;
 
   virtual const CSSValue* CreateCSSValue(const InterpolableValue&,
                                          const NonInterpolableValue*,
@@ -89,6 +85,11 @@
     return nullptr;
   }
 
+  const PropertyRegistration& Registration() const {
+    DCHECK(GetProperty().IsCSSCustomProperty());
+    return *registration_;
+  }
+
   void ApplyCustomPropertyValue(const InterpolableValue&,
                                 const NonInterpolableValue*,
                                 StyleResolverState&) const;
diff --git a/third_party/WebKit/Source/core/animation/CSSInterpolationTypesMap.cpp b/third_party/WebKit/Source/core/animation/CSSInterpolationTypesMap.cpp
index e534e72e..a929957 100644
--- a/third_party/WebKit/Source/core/animation/CSSInterpolationTypesMap.cpp
+++ b/third_party/WebKit/Source/core/animation/CSSInterpolationTypesMap.cpp
@@ -10,6 +10,7 @@
 #include "core/animation/CSSBorderImageLengthBoxInterpolationType.h"
 #include "core/animation/CSSClipInterpolationType.h"
 #include "core/animation/CSSColorInterpolationType.h"
+#include "core/animation/CSSDefaultInterpolationType.h"
 #include "core/animation/CSSFilterListInterpolationType.h"
 #include "core/animation/CSSFontSizeInterpolationType.h"
 #include "core/animation/CSSFontVariationSettingsInterpolationType.h"
@@ -36,7 +37,6 @@
 #include "core/animation/CSSTransformInterpolationType.h"
 #include "core/animation/CSSTransformOriginInterpolationType.h"
 #include "core/animation/CSSTranslateInterpolationType.h"
-#include "core/animation/CSSValueInterpolationType.h"
 #include "core/animation/CSSVisibilityInterpolationType.h"
 #include "core/css/CSSPropertyMetadata.h"
 #include "core/css/CSSSyntaxDescriptor.h"
@@ -321,7 +321,7 @@
   }
 
   applicable_types->push_back(
-      WTF::MakeUnique<CSSValueInterpolationType>(used_property));
+      WTF::MakeUnique<CSSDefaultInterpolationType>(used_property));
 
   auto add_result =
       applicable_types_map.insert(property, std::move(applicable_types));
@@ -390,14 +390,14 @@
       case CSSSyntaxType::kTokenStream:
       case CSSSyntaxType::kUrl:
         // No interpolation behaviour defined, uses the
-        // CSSValueInterpolationType added below.
+        // CSSDefaultInterpolationType added below.
         break;
       default:
         NOTREACHED();
         break;
     }
   }
-  result.push_back(WTF::MakeUnique<CSSValueInterpolationType>(property));
+  result.push_back(WTF::MakeUnique<CSSDefaultInterpolationType>(property));
   return result;
 }
 
diff --git a/third_party/WebKit/Source/core/animation/CSSValueInterpolationType.cpp b/third_party/WebKit/Source/core/animation/CSSValueInterpolationType.cpp
deleted file mode 100644
index 697a28d..0000000
--- a/third_party/WebKit/Source/core/animation/CSSValueInterpolationType.cpp
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "core/animation/CSSValueInterpolationType.h"
-
-#include "core/animation/InterpolationEnvironment.h"
-#include "core/animation/StringKeyframe.h"
-#include "core/css/CSSInheritedValue.h"
-#include "core/css/CSSInitialValue.h"
-#include "core/css/resolver/StyleBuilder.h"
-
-namespace blink {
-
-class CSSValueNonInterpolableValue : public NonInterpolableValue {
- public:
-  ~CSSValueNonInterpolableValue() final {}
-
-  static PassRefPtr<CSSValueNonInterpolableValue> Create(
-      const CSSValue* css_value) {
-    return AdoptRef(new CSSValueNonInterpolableValue(css_value));
-  }
-
-  const CSSValue* CssValue() const { return css_value_.Get(); }
-
-  DECLARE_NON_INTERPOLABLE_VALUE_TYPE();
-
- private:
-  CSSValueNonInterpolableValue(const CSSValue* css_value)
-      : css_value_(css_value) {
-    DCHECK(css_value_);
-  }
-
-  Persistent<const CSSValue> css_value_;
-};
-
-DEFINE_NON_INTERPOLABLE_VALUE_TYPE(CSSValueNonInterpolableValue);
-DEFINE_NON_INTERPOLABLE_VALUE_TYPE_CASTS(CSSValueNonInterpolableValue);
-
-InterpolationValue CSSValueInterpolationType::MaybeConvertInitial(
-    const StyleResolverState& state,
-    ConversionCheckers& conversion_checkers) const {
-  return MaybeConvertValue(*CSSInitialValue::Create(), &state,
-                           conversion_checkers);
-}
-
-InterpolationValue CSSValueInterpolationType::MaybeConvertInherit(
-    const StyleResolverState& state,
-    ConversionCheckers& conversion_checkers) const {
-  return MaybeConvertValue(*CSSInheritedValue::Create(), &state,
-                           conversion_checkers);
-}
-
-InterpolationValue CSSValueInterpolationType::MaybeConvertValue(
-    const CSSValue& value,
-    const StyleResolverState*,
-    ConversionCheckers& conversion_checkers) const {
-  return InterpolationValue(InterpolableList::Create(0),
-                            CSSValueNonInterpolableValue::Create(&value));
-}
-
-void CSSValueInterpolationType::ApplyStandardPropertyValue(
-    const InterpolableValue& interpolable_value,
-    const NonInterpolableValue* non_interpolable_value,
-    StyleResolverState& state) const {
-  StyleBuilder::ApplyProperty(
-      CssProperty(), state,
-      *CreateCSSValue(interpolable_value, non_interpolable_value, state));
-}
-
-const CSSValue* CSSValueInterpolationType::CreateCSSValue(
-    const InterpolableValue&,
-    const NonInterpolableValue* non_interpolable_value,
-    const StyleResolverState&) const {
-  return ToCSSValueNonInterpolableValue(non_interpolable_value)->CssValue();
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/core/animation/CSSValueInterpolationType.h b/third_party/WebKit/Source/core/animation/CSSValueInterpolationType.h
deleted file mode 100644
index acc45cb..0000000
--- a/third_party/WebKit/Source/core/animation/CSSValueInterpolationType.h
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CSSValueInterpolationType_h
-#define CSSValueInterpolationType_h
-
-#include "core/animation/CSSInterpolationType.h"
-
-namespace blink {
-
-// Never supports pairwise conversion while always supporting single conversion.
-// A catch all for default for CSSValues.
-class CSSValueInterpolationType : public CSSInterpolationType {
- public:
-  CSSValueInterpolationType(PropertyHandle property,
-                            const PropertyRegistration* registration = nullptr)
-      : CSSInterpolationType(property, registration) {}
-
-  PairwiseInterpolationValue MaybeConvertPairwise(
-      const PropertySpecificKeyframe& start_keyframe,
-      const PropertySpecificKeyframe& end_keyframe,
-      const InterpolationEnvironment&,
-      const InterpolationValue& underlying,
-      ConversionCheckers&) const final {
-    return nullptr;
-  }
-
-  InterpolationValue MaybeConvertStandardPropertyUnderlyingValue(
-      const ComputedStyle&) const final {
-    return nullptr;
-  }
-
-  InterpolationValue MaybeConvertNeutral(const InterpolationValue& underlying,
-                                         ConversionCheckers&) const final {
-    // This type will never interpolate or composite with the underlying value.
-    // Returning nullptr here means no value will be applied and the value in
-    // ComputedStyle will remain unchanged.
-    return nullptr;
-  }
-  InterpolationValue MaybeConvertInitial(const StyleResolverState&,
-                                         ConversionCheckers&) const final;
-  InterpolationValue MaybeConvertInherit(const StyleResolverState&,
-                                         ConversionCheckers&) const final;
-  InterpolationValue MaybeConvertValue(const CSSValue& value,
-                                       const StyleResolverState*,
-                                       ConversionCheckers&) const final;
-
-  void Composite(UnderlyingValueOwner& underlying_value_owner,
-                 double underlying_fraction,
-                 const InterpolationValue& value,
-                 double interpolation_fraction) const final {
-    underlying_value_owner.Set(*this, value);
-  }
-
-  void ApplyStandardPropertyValue(const InterpolableValue&,
-                                  const NonInterpolableValue*,
-                                  StyleResolverState&) const final;
-
-  const CSSValue* CreateCSSValue(const InterpolableValue&,
-                                 const NonInterpolableValue*,
-                                 const StyleResolverState&) const final;
-};
-
-}  // namespace blink
-
-#endif  // CSSValueInterpolationType_h
diff --git a/third_party/WebKit/Source/core/animation/DocumentTimeline.cpp b/third_party/WebKit/Source/core/animation/DocumentTimeline.cpp
index 85856e1c..78dc2a61c 100644
--- a/third_party/WebKit/Source/core/animation/DocumentTimeline.cpp
+++ b/third_party/WebKit/Source/core/animation/DocumentTimeline.cpp
@@ -32,6 +32,7 @@
 
 #include <algorithm>
 #include "core/animation/AnimationClock.h"
+#include "core/animation/DocumentTimelineOptions.h"
 #include "core/animation/ElementAnimations.h"
 #include "core/dom/Document.h"
 #include "core/frame/LocalFrameView.h"
@@ -59,14 +60,24 @@
 const double DocumentTimeline::kMinimumDelay = 0.04;
 
 DocumentTimeline* DocumentTimeline::Create(Document* document,
+                                           double origin_time_in_milliseconds,
                                            PlatformTiming* timing) {
-  return new DocumentTimeline(document, timing);
+  return new DocumentTimeline(document, origin_time_in_milliseconds, timing);
 }
 
-DocumentTimeline::DocumentTimeline(Document* document, PlatformTiming* timing)
+DocumentTimeline* DocumentTimeline::Create(
+    ExecutionContext* execution_context,
+    const DocumentTimelineOptions& options) {
+  Document* document = ToDocument(execution_context);
+  return new DocumentTimeline(document, options.originTime(), nullptr);
+}
+
+DocumentTimeline::DocumentTimeline(Document* document,
+                                   double origin_time_in_milliseconds,
+                                   PlatformTiming* timing)
     : document_(document),
-      // 0 is used by unit tests which cannot initialize from the loader
-      zero_time_(0),
+      origin_time_(origin_time_in_milliseconds / 1000),
+      zero_time_(origin_time_),
       zero_time_initialized_(false),
       outdated_animation_count_(0),
       playback_rate_(1),
@@ -182,14 +193,15 @@
 
 double DocumentTimeline::ZeroTime() {
   if (!zero_time_initialized_ && document_ && document_->Loader()) {
-    zero_time_ = document_->Loader()->GetTiming().ReferenceMonotonicTime();
+    zero_time_ = document_->Loader()->GetTiming().ReferenceMonotonicTime() +
+                 origin_time_;
     zero_time_initialized_ = true;
   }
   return zero_time_;
 }
 
 void DocumentTimeline::ResetForTesting() {
-  zero_time_ = 0;
+  zero_time_ = origin_time_;
   zero_time_initialized_ = true;
   playback_rate_ = 1;
   last_current_time_internal_ = 0;
diff --git a/third_party/WebKit/Source/core/animation/DocumentTimeline.h b/third_party/WebKit/Source/core/animation/DocumentTimeline.h
index 59f41e3..dd00fc63 100644
--- a/third_party/WebKit/Source/core/animation/DocumentTimeline.h
+++ b/third_party/WebKit/Source/core/animation/DocumentTimeline.h
@@ -50,6 +50,7 @@
 class Animation;
 class AnimationEffectReadOnly;
 class Document;
+class DocumentTimelineOptions;
 
 // DocumentTimeline is constructed and owned by Document, and tied to its
 // lifecycle.
@@ -66,7 +67,13 @@
     DEFINE_INLINE_VIRTUAL_TRACE() {}
   };
 
-  static DocumentTimeline* Create(Document*, PlatformTiming* = nullptr);
+  static DocumentTimeline* Create(Document*,
+                                  double origin_time_in_milliseconds = 0.0,
+                                  PlatformTiming* = nullptr);
+
+  // Web Animations API IDL constructor
+  static DocumentTimeline* Create(ExecutionContext*,
+                                  const DocumentTimelineOptions&);
 
   virtual ~DocumentTimeline() {}
 
@@ -112,11 +119,13 @@
 
   DECLARE_VIRTUAL_TRACE();
 
- protected:
-  DocumentTimeline(Document*, PlatformTiming*);
-
  private:
+  DocumentTimeline(Document*,
+                   double origin_time_in_milliseconds,
+                   PlatformTiming*);
+
   Member<Document> document_;
+  double origin_time_;
   double zero_time_;
   bool zero_time_initialized_;
   unsigned outdated_animation_count_;
diff --git a/third_party/WebKit/Source/core/animation/DocumentTimeline.idl b/third_party/WebKit/Source/core/animation/DocumentTimeline.idl
index 71237885..54f9faa3 100644
--- a/third_party/WebKit/Source/core/animation/DocumentTimeline.idl
+++ b/third_party/WebKit/Source/core/animation/DocumentTimeline.idl
@@ -5,6 +5,8 @@
 // https://w3c.github.io/web-animations/#the-documenttimeline-interface
 
 [
+    Constructor(optional DocumentTimelineOptions options),
+    ConstructorCallWith=ExecutionContext,
     RuntimeEnabled=WebAnimationsAPI
 ] interface DocumentTimeline : AnimationTimeline {
 };
diff --git a/third_party/WebKit/Source/core/animation/DocumentTimelineOptions.idl b/third_party/WebKit/Source/core/animation/DocumentTimelineOptions.idl
new file mode 100644
index 0000000..6730f6e
--- /dev/null
+++ b/third_party/WebKit/Source/core/animation/DocumentTimelineOptions.idl
@@ -0,0 +1,9 @@
+// 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.
+
+// https://w3c.github.io/web-animations/#dictdef-documenttimelineoptions
+
+dictionary DocumentTimelineOptions {
+  DOMHighResTimeStamp originTime = 0;
+};
diff --git a/third_party/WebKit/Source/core/animation/DocumentTimelineTest.cpp b/third_party/WebKit/Source/core/animation/DocumentTimelineTest.cpp
index cab0eae..d4bfd9d 100644
--- a/third_party/WebKit/Source/core/animation/DocumentTimelineTest.cpp
+++ b/third_party/WebKit/Source/core/animation/DocumentTimelineTest.cpp
@@ -62,7 +62,7 @@
     document->GetAnimationClock().ResetTimeForTesting();
     element = Element::Create(QualifiedName::Null(), document.Get());
     platform_timing = new MockPlatformTiming;
-    timeline = DocumentTimeline::Create(document.Get(), platform_timing);
+    timeline = DocumentTimeline::Create(document.Get(), 0.0, platform_timing);
     timeline->ResetForTesting();
     ASSERT_EQ(0, timeline->CurrentTimeInternal());
   }
@@ -162,6 +162,33 @@
   EXPECT_FALSE(is_null);
 }
 
+TEST_F(AnimationDocumentTimelineTest, PlaybackRateNormalWithOriginTime) {
+  double origin_time_in_ms = -1000000.0;
+  timeline = DocumentTimeline::Create(document.Get(), origin_time_in_ms,
+                                      platform_timing);
+  timeline->ResetForTesting();
+
+  bool is_null;
+
+  EXPECT_EQ(1.0, timeline->PlaybackRate());
+  EXPECT_EQ(-1000, timeline->ZeroTime());
+  EXPECT_EQ(1000, timeline->CurrentTimeInternal());
+  EXPECT_EQ(1000, timeline->CurrentTimeInternal(is_null));
+  EXPECT_FALSE(is_null);
+
+  document->GetAnimationClock().UpdateTime(100);
+  EXPECT_EQ(-1000, timeline->ZeroTime());
+  EXPECT_EQ(1100, timeline->CurrentTimeInternal());
+  EXPECT_EQ(1100, timeline->CurrentTimeInternal(is_null));
+  EXPECT_FALSE(is_null);
+
+  document->GetAnimationClock().UpdateTime(200);
+  EXPECT_EQ(-1000, timeline->ZeroTime());
+  EXPECT_EQ(1200, timeline->CurrentTimeInternal());
+  EXPECT_EQ(1200, timeline->CurrentTimeInternal(is_null));
+  EXPECT_FALSE(is_null);
+}
+
 TEST_F(AnimationDocumentTimelineTest, PlaybackRatePause) {
   bool is_null;
 
@@ -188,6 +215,46 @@
   EXPECT_FALSE(is_null);
 }
 
+TEST_F(AnimationDocumentTimelineTest, PlaybackRatePauseWithOriginTime) {
+  bool is_null;
+
+  double origin_time_in_ms = -1000000.0;
+  timeline = DocumentTimeline::Create(document.Get(), origin_time_in_ms,
+                                      platform_timing);
+  timeline->ResetForTesting();
+
+  EXPECT_EQ(-1000, timeline->ZeroTime());
+  EXPECT_EQ(1000, timeline->CurrentTimeInternal());
+  EXPECT_EQ(1000, timeline->CurrentTimeInternal(is_null));
+  EXPECT_FALSE(is_null);
+
+  document->GetAnimationClock().UpdateTime(100);
+  EXPECT_EQ(-1000, timeline->ZeroTime());
+  EXPECT_EQ(1100, timeline->CurrentTimeInternal());
+  EXPECT_EQ(1100, timeline->CurrentTimeInternal(is_null));
+  EXPECT_FALSE(is_null);
+
+  timeline->SetPlaybackRate(0.0);
+  EXPECT_EQ(0.0, timeline->PlaybackRate());
+  document->GetAnimationClock().UpdateTime(200);
+  EXPECT_EQ(1100, timeline->ZeroTime());
+  EXPECT_EQ(1100, timeline->CurrentTimeInternal());
+  EXPECT_EQ(1100, timeline->CurrentTimeInternal(is_null));
+
+  timeline->SetPlaybackRate(1.0);
+  EXPECT_EQ(1.0, timeline->PlaybackRate());
+  EXPECT_EQ(-900, timeline->ZeroTime());
+  EXPECT_EQ(1100, timeline->CurrentTimeInternal());
+  EXPECT_EQ(1100, timeline->CurrentTimeInternal(is_null));
+
+  document->GetAnimationClock().UpdateTime(400);
+  EXPECT_EQ(-900, timeline->ZeroTime());
+  EXPECT_EQ(1300, timeline->CurrentTimeInternal());
+  EXPECT_EQ(1300, timeline->CurrentTimeInternal(is_null));
+
+  EXPECT_FALSE(is_null);
+}
+
 TEST_F(AnimationDocumentTimelineTest, PlaybackRateSlow) {
   bool is_null;
 
@@ -240,6 +307,45 @@
   EXPECT_FALSE(is_null);
 }
 
+TEST_F(AnimationDocumentTimelineTest, PlaybackRateFastWithOriginTime) {
+  bool is_null;
+
+  double origin_time_in_ms = -1000000.0;
+  timeline = DocumentTimeline::Create(document.Get(), origin_time_in_ms,
+                                      platform_timing);
+  timeline->ResetForTesting();
+
+  document->GetAnimationClock().UpdateTime(100);
+  EXPECT_EQ(-1000, timeline->ZeroTime());
+  EXPECT_EQ(1100, timeline->CurrentTimeInternal());
+  EXPECT_EQ(1100, timeline->CurrentTimeInternal(is_null));
+  EXPECT_FALSE(is_null);
+
+  timeline->SetPlaybackRate(2.0);
+  EXPECT_EQ(2.0, timeline->PlaybackRate());
+  EXPECT_EQ(-450, timeline->ZeroTime());
+  EXPECT_EQ(1100, timeline->CurrentTimeInternal());
+  EXPECT_EQ(1100, timeline->CurrentTimeInternal(is_null));
+
+  document->GetAnimationClock().UpdateTime(300);
+  EXPECT_EQ(-450, timeline->ZeroTime());
+  EXPECT_EQ(1500, timeline->CurrentTimeInternal());
+  EXPECT_EQ(1500, timeline->CurrentTimeInternal(is_null));
+
+  timeline->SetPlaybackRate(1.0);
+  EXPECT_EQ(1.0, timeline->PlaybackRate());
+  EXPECT_EQ(-1200, timeline->ZeroTime());
+  EXPECT_EQ(1500, timeline->CurrentTimeInternal());
+  EXPECT_EQ(1500, timeline->CurrentTimeInternal(is_null));
+
+  document->GetAnimationClock().UpdateTime(400);
+  EXPECT_EQ(-1200, timeline->ZeroTime());
+  EXPECT_EQ(1600, timeline->CurrentTimeInternal());
+  EXPECT_EQ(1600, timeline->CurrentTimeInternal(is_null));
+
+  EXPECT_FALSE(is_null);
+}
+
 TEST_F(AnimationDocumentTimelineTest, PauseForTesting) {
   float seek_time = 1;
   timing.fill_mode = Timing::FillMode::FORWARDS;
diff --git a/third_party/WebKit/Source/core/animation/NonInterpolableValue.h b/third_party/WebKit/Source/core/animation/NonInterpolableValue.h
index 6343880..20abf34 100644
--- a/third_party/WebKit/Source/core/animation/NonInterpolableValue.h
+++ b/third_party/WebKit/Source/core/animation/NonInterpolableValue.h
@@ -21,7 +21,7 @@
 
 // These macros provide safe downcasts of NonInterpolableValue subclasses with
 // debug assertions.
-// See CSSValueInterpolationType.cpp for example usage.
+// See CSSDefaultInterpolationType.cpp for example usage.
 #define DECLARE_NON_INTERPOLABLE_VALUE_TYPE() \
   static Type static_type_;                   \
   Type GetType() const final { return static_type_; }
diff --git a/third_party/WebKit/Source/core/core_idl_files.gni b/third_party/WebKit/Source/core/core_idl_files.gni
index c1c6e7bf..1c7fa4a 100644
--- a/third_party/WebKit/Source/core/core_idl_files.gni
+++ b/third_party/WebKit/Source/core/core_idl_files.gni
@@ -508,6 +508,7 @@
     get_path_info([
                     "animation/AnimationEffectTimingProperties.idl",
                     "animation/ComputedTimingProperties.idl",
+                    "animation/DocumentTimelineOptions.idl",
                     "animation/KeyframeAnimationOptions.idl",
                     "animation/KeyframeEffectOptions.idl",
                     "css/FontFaceDescriptors.idl",
diff --git a/third_party/WebKit/Source/core/css/CSSProperties.json5 b/third_party/WebKit/Source/core/css/CSSProperties.json5
index a286a04..94c9dab 100644
--- a/third_party/WebKit/Source/core/css/CSSProperties.json5
+++ b/third_party/WebKit/Source/core/css/CSSProperties.json5
@@ -98,6 +98,8 @@
         "external",
         // Only the storage is generated. The interface is handwritten.
         "storage_only",
+        // Field is stored as a wrapper_pointer_name to a class.
+        "pointer",
       ],
     },
 
@@ -961,7 +963,7 @@
       api_methods: ["parseSingleValue"],
       converter: "ConvertShadowList",
       interpolable: true,
-      field_template: "storage_only",
+      field_template: "pointer",
       type_name: "ShadowList",
       field_group: "rare-non-inherited",
       default_value: "nullptr",
@@ -1055,7 +1057,7 @@
       api_methods: ["parseSingleValue"],
       converter: "ConvertClipPath",
       interpolable: true,
-      field_template: "storage_only",
+      field_template: "pointer",
       type_name: "ClipPathOperation",
       field_group: "rare-non-inherited",
       default_value: "nullptr",
@@ -1796,7 +1798,7 @@
       api_class: true,
       api_methods: ["parseSingleValue"],
       converter: "ConvertOffsetPath",
-      field_template: "storage_only",
+      field_template: "pointer",
       type_name: "BasicShape",
       field_group: "rare-non-inherited->transform",
       wrapper_pointer_name: "RefPtr",
@@ -2043,7 +2045,7 @@
       api_methods: ["parseSingleValue"],
       converter: "ConvertQuotes",
       inherited: true,
-      field_template: "storage_only",
+      field_template: "pointer",
       type_name: "QuotesData",
       include_paths: ["core/style/QuotesData.h"],
       default_value: "nullptr",
@@ -2616,7 +2618,7 @@
       converter: "ConvertShadowList",
       inherited: true,
       interpolable: true,
-      field_template: "storage_only",
+      field_template: "pointer",
       type_name: "ShadowList",
       include_paths: ["core/style/ShadowList.h"],
       wrapper_pointer_name: "RefPtr",
@@ -2732,7 +2734,7 @@
       converter: "ConvertTranslate",
       interpolable: true,
       runtime_flag: "CSSIndependentTransformProperties",
-      field_template: "storage_only",
+      field_template: "pointer",
       type_name: "TranslateTransformOperation",
       field_group: "rare-non-inherited->transform",
       default_value: "nullptr",
@@ -2746,7 +2748,7 @@
       converter: "ConvertRotate",
       interpolable: true,
       runtime_flag: "CSSIndependentTransformProperties",
-      field_template: "storage_only",
+      field_template: "pointer",
       type_name: "RotateTransformOperation",
       field_group: "rare-non-inherited->transform",
       default_value: "nullptr",
@@ -2760,7 +2762,7 @@
       converter: "ConvertScale",
       interpolable: true,
       runtime_flag: "CSSIndependentTransformProperties",
-      field_template: "storage_only",
+      field_template: "pointer",
       type_name: "ScaleTransformOperation",
       field_group: "rare-non-inherited->transform",
       default_value: "nullptr",
@@ -2945,7 +2947,7 @@
       api_class: true,
       api_methods: ["parseSingleValue"],
       converter: "ConvertBoxReflect",
-      field_template: "storage_only",
+      field_template: "pointer",
       type_name: "StyleReflection",
       field_group: "rare-non-inherited",
       default_value: "nullptr",
diff --git a/third_party/WebKit/Source/core/css/CSSSyntaxDescriptor.cpp b/third_party/WebKit/Source/core/css/CSSSyntaxDescriptor.cpp
index ad063fc..b1da46c 100644
--- a/third_party/WebKit/Source/core/css/CSSSyntaxDescriptor.cpp
+++ b/third_party/WebKit/Source/core/css/CSSSyntaxDescriptor.cpp
@@ -4,9 +4,6 @@
 
 #include "core/css/CSSSyntaxDescriptor.h"
 
-#include "core/animation/CSSColorInterpolationType.h"
-#include "core/animation/CSSLengthInterpolationType.h"
-#include "core/animation/CSSValueInterpolationType.h"
 #include "core/css/CSSCustomPropertyDeclaration.h"
 #include "core/css/CSSURIValue.h"
 #include "core/css/CSSValueList.h"
diff --git a/third_party/WebKit/Source/core/css/CSSTimingFunctionValue.h b/third_party/WebKit/Source/core/css/CSSTimingFunctionValue.h
index 155dbe0c..972fc0d 100644
--- a/third_party/WebKit/Source/core/css/CSSTimingFunctionValue.h
+++ b/third_party/WebKit/Source/core/css/CSSTimingFunctionValue.h
@@ -27,6 +27,7 @@
 #define CSSTimingFunctionValue_h
 
 #include "core/css/CSSValue.h"
+#include "platform/RuntimeEnabledFeatures.h"
 #include "platform/animation/TimingFunction.h"
 #include "platform/wtf/PassRefPtr.h"
 
@@ -124,7 +125,9 @@
 
  private:
   CSSFramesTimingFunctionValue(int frames)
-      : CSSValue(kFramesTimingFunctionClass), frames_(frames) {}
+      : CSSValue(kFramesTimingFunctionClass), frames_(frames) {
+    DCHECK(RuntimeEnabledFeatures::FramesTimingFunctionEnabled());
+  }
 
   int frames_;
 };
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
index 0f34dd00..0906685a 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
@@ -396,8 +396,10 @@
   CSSValueID function = range.Peek().FunctionId();
   if (function == CSSValueSteps)
     return ConsumeSteps(range);
-  if (function == CSSValueFrames)
+  if (RuntimeEnabledFeatures::FramesTimingFunctionEnabled() &&
+      function == CSSValueFrames) {
     return ConsumeFrames(range);
+  }
   if (function == CSSValueCubicBezier)
     return ConsumeCubicBezier(range);
   return nullptr;
diff --git a/third_party/WebKit/Source/core/dom/ClassicScript.cpp b/third_party/WebKit/Source/core/dom/ClassicScript.cpp
index 2918a612..7015762 100644
--- a/third_party/WebKit/Source/core/dom/ClassicScript.cpp
+++ b/third_party/WebKit/Source/core/dom/ClassicScript.cpp
@@ -50,10 +50,6 @@
   visitor->Trace(script_source_code_);
 }
 
-bool ClassicScript::IsEmpty() const {
-  return GetScriptSourceCode().IsEmpty();
-}
-
 bool ClassicScript::CheckMIMETypeBeforeRunScript(
     Document* context_document,
     const SecurityOrigin* security_origin) const {
diff --git a/third_party/WebKit/Source/core/dom/ClassicScript.h b/third_party/WebKit/Source/core/dom/ClassicScript.h
index 887214d..360a7b8 100644
--- a/third_party/WebKit/Source/core/dom/ClassicScript.h
+++ b/third_party/WebKit/Source/core/dom/ClassicScript.h
@@ -28,7 +28,6 @@
       : script_source_code_(script_source_code) {}
 
   ScriptType GetScriptType() const override { return ScriptType::kClassic; }
-  bool IsEmpty() const override;
   bool CheckMIMETypeBeforeRunScript(Document* context_document,
                                     const SecurityOrigin*) const override;
   void RunScript(LocalFrame*, const SecurityOrigin*) const override;
diff --git a/third_party/WebKit/Source/core/dom/IntersectionObserver.cpp b/third_party/WebKit/Source/core/dom/IntersectionObserver.cpp
index 16aa7f1f..4710756 100644
--- a/third_party/WebKit/Source/core/dom/IntersectionObserver.cpp
+++ b/third_party/WebKit/Source/core/dom/IntersectionObserver.cpp
@@ -207,7 +207,7 @@
 }
 
 void IntersectionObserver::ClearWeakMembers(Visitor* visitor) {
-  if (ThreadHeap::IsHeapObjectAlive(root()))
+  if (RootIsImplicit() || (root() && ThreadHeap::IsHeapObjectAlive(root())))
     return;
   DummyExceptionStateForTesting exception_state;
   disconnect(exception_state);
diff --git a/third_party/WebKit/Source/core/dom/Modulator.h b/third_party/WebKit/Source/core/dom/Modulator.h
index e9b14c4..4aa36b1 100644
--- a/third_party/WebKit/Source/core/dom/Modulator.h
+++ b/third_party/WebKit/Source/core/dom/Modulator.h
@@ -123,6 +123,7 @@
 
   virtual ScriptValue InstantiateModule(ScriptModule) = 0;
 
+  // https://html.spec.whatwg.org/multipage/webappapis.html#concept-module-script-error
   virtual ScriptValue GetError(const ModuleScript*) = 0;
 
   struct ModuleRequest {
diff --git a/third_party/WebKit/Source/core/dom/ModulatorImpl.cpp b/third_party/WebKit/Source/core/dom/ModulatorImpl.cpp
index c95b3a9..0f916e5 100644
--- a/third_party/WebKit/Source/core/dom/ModulatorImpl.cpp
+++ b/third_party/WebKit/Source/core/dom/ModulatorImpl.cpp
@@ -149,9 +149,23 @@
 }
 
 ScriptValue ModulatorImpl::GetError(const ModuleScript* module_script) {
+  DCHECK(module_script);
   ScriptState::Scope scope(script_state_.Get());
-  return ScriptValue(script_state_.Get(), module_script->CreateErrorInternal(
-                                              script_state_->GetIsolate()));
+  // https://html.spec.whatwg.org/multipage/webappapis.html#concept-module-script-error
+  // "When a module script is errored, ..." [spec text]
+
+  // "we say that its error is either its pre-instantiation error, when its
+  // module record is null, ..." [spec text]
+  ScriptModule record = module_script->Record();
+  if (record.IsNull()) {
+    return ScriptValue(script_state_.Get(), module_script->CreateErrorInternal(
+                                                script_state_->GetIsolate()));
+  }
+
+  // "or its module record's [[ErrorCompletion]] field's [[Value]] field,
+  // otherwise." [spec text]
+  return ScriptValue(script_state_.Get(),
+                     record.ErrorCompletion(script_state_.Get()));
 }
 
 Vector<Modulator::ModuleRequest> ModulatorImpl::ModuleRequestsFromScriptModule(
diff --git a/third_party/WebKit/Source/core/dom/ModuleScript.cpp b/third_party/WebKit/Source/core/dom/ModuleScript.cpp
index 0aca737..b17da72e 100644
--- a/third_party/WebKit/Source/core/dom/ModuleScript.cpp
+++ b/third_party/WebKit/Source/core/dom/ModuleScript.cpp
@@ -227,10 +227,6 @@
   visitor->TraceWrappers(preinstantiation_error_);
 }
 
-bool ModuleScript::IsEmpty() const {
-  return false;
-}
-
 bool ModuleScript::CheckMIMETypeBeforeRunScript(Document* context_document,
                                                 const SecurityOrigin*) const {
   // We don't check MIME type here because we check the MIME type in
diff --git a/third_party/WebKit/Source/core/dom/ModuleScript.h b/third_party/WebKit/Source/core/dom/ModuleScript.h
index 5f4a22c..0bbea7c4 100644
--- a/third_party/WebKit/Source/core/dom/ModuleScript.h
+++ b/third_party/WebKit/Source/core/dom/ModuleScript.h
@@ -106,7 +106,6 @@
                                       const TextPosition&);
 
   ScriptType GetScriptType() const override { return ScriptType::kModule; }
-  bool IsEmpty() const override;
   bool CheckMIMETypeBeforeRunScript(Document* context_document,
                                     const SecurityOrigin*) const override;
   void RunScript(LocalFrame*, const SecurityOrigin*) const override;
diff --git a/third_party/WebKit/Source/core/dom/Script.h b/third_party/WebKit/Source/core/dom/Script.h
index 22e54d4..e817256 100644
--- a/third_party/WebKit/Source/core/dom/Script.h
+++ b/third_party/WebKit/Source/core/dom/Script.h
@@ -27,9 +27,6 @@
 
   virtual ScriptType GetScriptType() const = 0;
 
-  // Used to skip execution of the script if it is empty.
-  virtual bool IsEmpty() const = 0;
-
   // Returns false if the script should not be run due to MIME type check.
   virtual bool CheckMIMETypeBeforeRunScript(Document* context_document,
                                             const SecurityOrigin*) const = 0;
diff --git a/third_party/WebKit/Source/core/dom/ScriptLoader.cpp b/third_party/WebKit/Source/core/dom/ScriptLoader.cpp
index a72185d..a119577 100644
--- a/third_party/WebKit/Source/core/dom/ScriptLoader.cpp
+++ b/third_party/WebKit/Source/core/dom/ScriptLoader.cpp
@@ -819,9 +819,6 @@
   DCHECK(already_started_);
   CHECK_EQ(script->GetScriptType(), GetScriptType());
 
-  if (script->IsEmpty())
-    return true;
-
   Document* element_document = &(element_->GetDocument());
   Document* context_document = element_document->ContextDocument();
   if (!context_document)
diff --git a/third_party/WebKit/Source/core/dom/StyleEngine.cpp b/third_party/WebKit/Source/core/dom/StyleEngine.cpp
index a0dda66..4c8ec07 100644
--- a/third_party/WebKit/Source/core/dom/StyleEngine.cpp
+++ b/third_party/WebKit/Source/core/dom/StyleEngine.cpp
@@ -306,6 +306,9 @@
 void StyleEngine::UpdateActiveStyleSheetsInImport(
     StyleEngine& master_engine,
     DocumentStyleSheetCollector& parent_collector) {
+  if (!RuntimeEnabledFeatures::HTMLImportsStyleApplicationEnabled())
+    return;
+
   DCHECK(!IsMaster());
   HeapVector<Member<StyleSheet>> sheets_for_list;
   ImportedDocumentStyleSheetCollector subcollector(parent_collector,
diff --git a/third_party/WebKit/Source/core/html/HTMLElement.h b/third_party/WebKit/Source/core/html/HTMLElement.h
index df14759..5f32c96 100644
--- a/third_party/WebKit/Source/core/html/HTMLElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLElement.h
@@ -25,6 +25,7 @@
 
 #include "core/CoreExport.h"
 #include "core/dom/Element.h"
+#include "platform/text/TextDirection.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.cpp b/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.cpp
index 060066719..e21edf3 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.cpp
@@ -38,6 +38,7 @@
 #include "platform/loader/fetch/ResourceRequest.h"
 #include "platform/loader/fetch/ResourceResponse.h"
 #include "platform/weborigin/KURL.h"
+#include "platform/wtf/DynamicAnnotations.h"
 #include "platform/wtf/Vector.h"
 #include "platform/wtf/text/TextPosition.h"
 #include "v8/include/v8-profiler.h"
diff --git a/third_party/WebKit/Source/core/inspector/InspectorWorkerAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorWorkerAgent.cpp
index fead904..22e5397 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorWorkerAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorWorkerAgent.cpp
@@ -206,6 +206,7 @@
                                       .setType("worker")
                                       .setTitle(proxy->Url())
                                       .setUrl(proxy->Url())
+                                      .setAttached(true)
                                       .build(),
                                   waiting_for_debugger);
 }
diff --git a/third_party/WebKit/Source/core/inspector/browser_protocol.json b/third_party/WebKit/Source/core/inspector/browser_protocol.json
index 46c04fc7..a1d9555 100644
--- a/third_party/WebKit/Source/core/inspector/browser_protocol.json
+++ b/third_party/WebKit/Source/core/inspector/browser_protocol.json
@@ -3562,7 +3562,8 @@
                     { "name": "targetId", "$ref": "TargetID" },
                     { "name": "type", "type": "string" },
                     { "name": "title", "type": "string" },
-                    { "name": "url", "type": "string" }
+                    { "name": "url", "type": "string" },
+                    { "name": "attached", "type": "boolean", "description": "Whether the target has an attached client." }
                 ]
             },
             {
@@ -3577,7 +3578,7 @@
         "commands": [
             {
                 "name": "setDiscoverTargets",
-                "description": "Controls whether to discover available targets and notify via <code>targetCreated/targetDestroyed</code> events.",
+                "description": "Controls whether to discover available targets and notify via <code>targetCreated/targetInfoChanged/targetDestroyed</code> events.",
                 "parameters": [
                     { "name": "discover", "type": "boolean", "description": "Whether to discover available targets." }
                 ]
@@ -3702,6 +3703,13 @@
                 ]
             },
             {
+                "name": "targetInfoChanged",
+                "description": "Issued when some information about a target has changed. This only happens between <code>targetCreated</code> and <code>targetDestroyed</code>.",
+                "parameters": [
+                    { "name": "targetInfo", "$ref": "TargetInfo" }
+                ]
+            },
+            {
                 "name": "targetDestroyed",
                 "description": "Issued when a target is destroyed.",
                 "parameters": [
diff --git a/third_party/WebKit/Source/core/layout/BUILD.gn b/third_party/WebKit/Source/core/layout/BUILD.gn
index 96034692..2ff5fdf2 100644
--- a/third_party/WebKit/Source/core/layout/BUILD.gn
+++ b/third_party/WebKit/Source/core/layout/BUILD.gn
@@ -428,6 +428,7 @@
     "ng/ng_min_max_content_size.h",
     "ng/ng_out_of_flow_layout_part.cc",
     "ng/ng_out_of_flow_layout_part.h",
+    "ng/ng_out_of_flow_positioned_descendant.h",
     "ng/ng_physical_box_fragment.cc",
     "ng/ng_physical_box_fragment.h",
     "ng/ng_physical_fragment.cc",
diff --git a/third_party/WebKit/Source/core/layout/FloatingObjects.cpp b/third_party/WebKit/Source/core/layout/FloatingObjects.cpp
index adf467e8..f51a155 100644
--- a/third_party/WebKit/Source/core/layout/FloatingObjects.cpp
+++ b/third_party/WebKit/Source/core/layout/FloatingObjects.cpp
@@ -31,6 +31,7 @@
 #include "core/layout/LayoutView.h"
 #include "core/layout/api/LineLayoutBlockFlow.h"
 #include "core/layout/shapes/ShapeOutsideInfo.h"
+#include "core/paint/PaintLayer.h"
 #include "platform/wtf/PtrUtil.h"
 
 namespace blink {
@@ -97,6 +98,15 @@
 
   new_obj->SetIsDescendant(true);
 
+  // We set SelfPaintingStatusChanged in case we get to the next compositing
+  // update and still haven't decided who should paint the float. If we've
+  // decided that the current float owner can paint it that step is unnecessary,
+  // so we can clear it now.
+  if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
+      new_obj->ShouldPaint() && layout_object->Layer() &&
+      layout_object->Layer()->SelfPaintingStatusChanged())
+    layout_object->Layer()->ClearSelfPaintingStatusChanged();
+
   return new_obj;
 }
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
index bcd7d16..a6a075f 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
@@ -3885,7 +3885,7 @@
   if (!prev->floating_objects_)
     return;
 
-  logical_left_offset += MarginLogicalLeft();
+  logical_left_offset += MarginLineLeft();
 
   const FloatingObjectSet& prev_set = prev->floating_objects_->Set();
   FloatingObjectSetIterator prev_end = prev_set.end();
@@ -4163,23 +4163,21 @@
       break;
 
     FloatingObject& floating_object = **it;
-    // This repeats the logic in addOverhangingFloats() about shouldPaint
-    // flag:
-    // - The nearest enclosing block in which the float doesn't overhang
-    //   paints the float;
-    // - Or even if the float overhangs, if the ancestor block has
-    //   self-painting layer, it paints the float.
-    LayoutBlockFlow* parent_block =
-        ToLayoutBlockFlow(floating_object.GetLayoutObject()->Parent());
-    bool is_overhanging_float =
-        parent_block && parent_block->IsOverhangingFloat(floating_object);
-    bool should_paint =
-        !float_box_is_self_painting_layer &&
-        (ancestor_block->HasSelfPaintingLayer() || !is_overhanging_float);
-    floating_object.SetShouldPaint(should_paint);
-
-    if (floating_object.ShouldPaint())
-      return;
+    if (!float_box_is_self_painting_layer) {
+      // This repeats the logic in addOverhangingFloats() about shouldPaint
+      // flag:
+      // - The nearest enclosing block in which the float doesn't overhang
+      //   paints the float;
+      // - Or even if the float overhangs, if the ancestor block has
+      //   self-painting layer, it paints the float.
+      if (ancestor_block->HasSelfPaintingLayer() ||
+          !ancestor_block->IsOverhangingFloat(floating_object)) {
+        floating_object.SetShouldPaint(true);
+        return;
+      }
+    } else {
+      floating_object.SetShouldPaint(false);
+    }
   }
 }
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutBox.h b/third_party/WebKit/Source/core/layout/LayoutBox.h
index 7f2ed16..cfc70092 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBox.h
+++ b/third_party/WebKit/Source/core/layout/LayoutBox.h
@@ -595,9 +595,7 @@
                            bool make_visible_in_visual_viewport = true,
                            ScrollBehavior = kScrollBehaviorAuto);
 
-  LayoutRectOutsets MarginBoxOutsets() const override {
-    return margin_box_outsets_;
-  }
+  LayoutRectOutsets MarginBoxOutsets() const { return margin_box_outsets_; }
   LayoutUnit MarginTop() const override { return margin_box_outsets_.Top(); }
   LayoutUnit MarginBottom() const override {
     return margin_box_outsets_.Bottom();
@@ -615,66 +613,21 @@
     margin_box_outsets_.SetRight(margin);
   }
 
-  LayoutUnit MarginLogicalLeft() const {
-    return margin_box_outsets_.LogicalLeft(Style()->GetWritingMode());
-  }
-  LayoutUnit MarginLogicalRight() const {
-    return margin_box_outsets_.LogicalRight(Style()->GetWritingMode());
-  }
-
-  LayoutUnit MarginBefore(
-      const ComputedStyle* override_style = nullptr) const final {
-    return margin_box_outsets_.Before(
-        (override_style ? override_style : Style())->GetWritingMode());
-  }
-  LayoutUnit MarginAfter(
-      const ComputedStyle* override_style = nullptr) const final {
-    return margin_box_outsets_.After(
-        (override_style ? override_style : Style())->GetWritingMode());
-  }
-  LayoutUnit MarginStart(
-      const ComputedStyle* override_style = nullptr) const final {
-    const ComputedStyle* style_to_use =
-        override_style ? override_style : Style();
-    return margin_box_outsets_.Start(style_to_use->GetWritingMode(),
-                                     style_to_use->Direction());
-  }
-  LayoutUnit MarginEnd(
-      const ComputedStyle* override_style = nullptr) const final {
-    const ComputedStyle* style_to_use =
-        override_style ? override_style : Style();
-    return margin_box_outsets_.end(style_to_use->GetWritingMode(),
-                                   style_to_use->Direction());
-  }
-  LayoutUnit MarginOver() const final {
-    return margin_box_outsets_.Over(Style()->GetWritingMode());
-  }
-  LayoutUnit MarginUnder() const final {
-    return margin_box_outsets_.Under(Style()->GetWritingMode());
-  }
   void SetMarginBefore(LayoutUnit value,
                        const ComputedStyle* override_style = nullptr) {
-    margin_box_outsets_.SetBefore(
-        (override_style ? override_style : Style())->GetWritingMode(), value);
+    LogicalMarginToPhysicalSetter(override_style).SetBefore(value);
   }
   void SetMarginAfter(LayoutUnit value,
                       const ComputedStyle* override_style = nullptr) {
-    margin_box_outsets_.SetAfter(
-        (override_style ? override_style : Style())->GetWritingMode(), value);
+    LogicalMarginToPhysicalSetter(override_style).SetAfter(value);
   }
   void SetMarginStart(LayoutUnit value,
                       const ComputedStyle* override_style = nullptr) {
-    const ComputedStyle* style_to_use =
-        override_style ? override_style : Style();
-    margin_box_outsets_.SetStart(style_to_use->GetWritingMode(),
-                                 style_to_use->Direction(), value);
+    LogicalMarginToPhysicalSetter(override_style).SetStart(value);
   }
   void SetMarginEnd(LayoutUnit value,
                     const ComputedStyle* override_style = nullptr) {
-    const ComputedStyle* style_to_use =
-        override_style ? override_style : Style();
-    margin_box_outsets_.SetEnd(style_to_use->GetWritingMode(),
-                               style_to_use->Direction(), value);
+    LogicalMarginToPhysicalSetter(override_style).SetEnd(value);
   }
 
   // The following functions are used to implement collapsing margins.
@@ -1679,6 +1632,15 @@
   std::unique_ptr<BoxOverflowModel> overflow_;
 
  private:
+  LogicalToPhysicalSetter<LayoutUnit, LayoutBox> LogicalMarginToPhysicalSetter(
+      const ComputedStyle* override_style) {
+    const auto& style = override_style ? *override_style : StyleRef();
+    return LogicalToPhysicalSetter<LayoutUnit, LayoutBox>(
+        style.GetWritingMode(), style.Direction(), *this,
+        &LayoutBox::SetMarginTop, &LayoutBox::SetMarginRight,
+        &LayoutBox::SetMarginBottom, &LayoutBox::SetMarginLeft);
+  }
+
   // The inline box containing this LayoutBox, for atomic inline elements.
   InlineBox* inline_box_wrapper_;
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.h b/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.h
index d2c10a3..336fe78f 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.h
+++ b/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.h
@@ -31,6 +31,7 @@
 #include "core/layout/LayoutObject.h"
 #include "core/page/scrolling/StickyPositionScrollingConstraints.h"
 #include "platform/geometry/LayoutRect.h"
+#include "platform/text/WritingModeUtils.h"
 #include "platform/wtf/PtrUtil.h"
 
 namespace blink {
@@ -243,14 +244,15 @@
   }
   virtual LayoutUnit PaddingLeft() const { return ComputedCSSPaddingLeft(); }
   virtual LayoutUnit PaddingRight() const { return ComputedCSSPaddingRight(); }
-  virtual LayoutUnit PaddingBefore() const {
-    return ComputedCSSPaddingBefore();
+
+  LayoutUnit PaddingBefore() const {
+    return PhysicalPaddingToLogical().Before();
   }
-  virtual LayoutUnit PaddingAfter() const { return ComputedCSSPaddingAfter(); }
-  virtual LayoutUnit PaddingStart() const { return ComputedCSSPaddingStart(); }
-  virtual LayoutUnit PaddingEnd() const { return ComputedCSSPaddingEnd(); }
-  LayoutUnit PaddingOver() const { return ComputedCSSPaddingOver(); }
-  LayoutUnit PaddingUnder() const { return ComputedCSSPaddingUnder(); }
+  LayoutUnit PaddingAfter() const { return PhysicalPaddingToLogical().After(); }
+  LayoutUnit PaddingStart() const { return PhysicalPaddingToLogical().Start(); }
+  LayoutUnit PaddingEnd() const { return PhysicalPaddingToLogical().End(); }
+  LayoutUnit PaddingOver() const { return PhysicalPaddingToLogical().Over(); }
+  LayoutUnit PaddingUnder() const { return PhysicalPaddingToLogical().Under(); }
 
   virtual LayoutUnit BorderTop() const {
     return LayoutUnit(Style()->BorderTopWidth());
@@ -264,29 +266,18 @@
   virtual LayoutUnit BorderRight() const {
     return LayoutUnit(Style()->BorderRightWidth());
   }
-  virtual LayoutUnit BorderBefore() const {
-    return LayoutUnit(Style()->BorderBeforeWidth());
-  }
-  virtual LayoutUnit BorderAfter() const {
-    return LayoutUnit(Style()->BorderAfterWidth());
-  }
-  virtual LayoutUnit BorderStart() const {
-    return LayoutUnit(Style()->BorderStartWidth());
-  }
-  virtual LayoutUnit BorderEnd() const {
-    return LayoutUnit(Style()->BorderEndWidth());
-  }
-  LayoutUnit BorderOver() const {
-    return LayoutUnit(Style()->BorderOverWidth());
-  }
-  LayoutUnit BorderUnder() const {
-    return LayoutUnit(Style()->BorderUnderWidth());
-  }
+
+  LayoutUnit BorderBefore() const { return PhysicalBorderToLogical().Before(); }
+  LayoutUnit BorderAfter() const { return PhysicalBorderToLogical().After(); }
+  LayoutUnit BorderStart() const { return PhysicalBorderToLogical().Start(); }
+  LayoutUnit BorderEnd() const { return PhysicalBorderToLogical().End(); }
+  LayoutUnit BorderOver() const { return PhysicalBorderToLogical().Over(); }
+  LayoutUnit BorderUnder() const { return PhysicalBorderToLogical().Under(); }
 
   LayoutUnit BorderWidth() const { return BorderLeft() + BorderRight(); }
   LayoutUnit BorderHeight() const { return BorderTop() + BorderBottom(); }
 
-  virtual LayoutRectOutsets BorderBoxOutsets() const {
+  LayoutRectOutsets BorderBoxOutsets() const {
     return LayoutRectOutsets(BorderTop(), BorderRight(), BorderBottom(),
                              BorderLeft());
   }
@@ -367,21 +358,36 @@
            BorderBefore() + BorderAfter();
   }
 
-  virtual LayoutRectOutsets MarginBoxOutsets() const = 0;
   virtual LayoutUnit MarginTop() const = 0;
   virtual LayoutUnit MarginBottom() const = 0;
   virtual LayoutUnit MarginLeft() const = 0;
   virtual LayoutUnit MarginRight() const = 0;
-  virtual LayoutUnit MarginBefore(
-      const ComputedStyle* other_style = nullptr) const = 0;
-  virtual LayoutUnit MarginAfter(
-      const ComputedStyle* other_style = nullptr) const = 0;
-  virtual LayoutUnit MarginStart(
-      const ComputedStyle* other_style = nullptr) const = 0;
-  virtual LayoutUnit MarginEnd(
-      const ComputedStyle* other_style = nullptr) const = 0;
-  virtual LayoutUnit MarginOver() const = 0;
-  virtual LayoutUnit MarginUnder() const = 0;
+
+  LayoutUnit MarginBefore(const ComputedStyle* other_style = nullptr) const {
+    return PhysicalMarginToLogical(other_style).Before();
+  }
+  LayoutUnit MarginAfter(const ComputedStyle* other_style = nullptr) const {
+    return PhysicalMarginToLogical(other_style).After();
+  }
+  LayoutUnit MarginStart(const ComputedStyle* other_style = nullptr) const {
+    return PhysicalMarginToLogical(other_style).Start();
+  }
+  LayoutUnit MarginEnd(const ComputedStyle* other_style = nullptr) const {
+    return PhysicalMarginToLogical(other_style).End();
+  }
+  LayoutUnit MarginLineLeft() const {
+    return PhysicalMarginToLogical(nullptr).LineLeft();
+  }
+  LayoutUnit MarginLineRight() const {
+    return PhysicalMarginToLogical(nullptr).LineRight();
+  }
+  LayoutUnit MarginOver() const {
+    return PhysicalMarginToLogical(nullptr).Over();
+  }
+  LayoutUnit MarginUnder() const {
+    return PhysicalMarginToLogical(nullptr).Under();
+  }
+
   DISABLE_CFI_PERF LayoutUnit MarginHeight() const {
     return MarginTop() + MarginBottom();
   }
@@ -550,6 +556,32 @@
   LayoutUnit ComputedCSSPadding(const Length&) const;
   bool IsBoxModelObject() const final { return true; }
 
+  PhysicalToLogicalGetter<LayoutUnit, LayoutBoxModelObject>
+  PhysicalPaddingToLogical() const {
+    return PhysicalToLogicalGetter<LayoutUnit, LayoutBoxModelObject>(
+        StyleRef().GetWritingMode(), StyleRef().Direction(), *this,
+        &LayoutBoxModelObject::PaddingTop, &LayoutBoxModelObject::PaddingRight,
+        &LayoutBoxModelObject::PaddingBottom,
+        &LayoutBoxModelObject::PaddingLeft);
+  }
+
+  PhysicalToLogicalGetter<LayoutUnit, LayoutBoxModelObject>
+  PhysicalMarginToLogical(const ComputedStyle* other_style) const {
+    const auto& style = other_style ? *other_style : StyleRef();
+    return PhysicalToLogicalGetter<LayoutUnit, LayoutBoxModelObject>(
+        style.GetWritingMode(), style.Direction(), *this,
+        &LayoutBoxModelObject::MarginTop, &LayoutBoxModelObject::MarginRight,
+        &LayoutBoxModelObject::MarginBottom, &LayoutBoxModelObject::MarginLeft);
+  }
+
+  PhysicalToLogicalGetter<LayoutUnit, LayoutBoxModelObject>
+  PhysicalBorderToLogical() const {
+    return PhysicalToLogicalGetter<LayoutUnit, LayoutBoxModelObject>(
+        StyleRef().GetWritingMode(), StyleRef().Direction(), *this,
+        &LayoutBoxModelObject::BorderTop, &LayoutBoxModelObject::BorderRight,
+        &LayoutBoxModelObject::BorderBottom, &LayoutBoxModelObject::BorderLeft);
+  }
+
   LayoutBoxModelObjectRareData& EnsureRareData() {
     if (!rare_data_)
       rare_data_ = WTF::MakeUnique<LayoutBoxModelObjectRareData>();
diff --git a/third_party/WebKit/Source/core/layout/LayoutInline.cpp b/third_party/WebKit/Source/core/layout/LayoutInline.cpp
index e053cf9..c034749 100644
--- a/third_party/WebKit/Source/core/layout/LayoutInline.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutInline.cpp
@@ -822,11 +822,6 @@
   return LayoutUnit();
 }
 
-LayoutRectOutsets LayoutInline::MarginBoxOutsets() const {
-  return LayoutRectOutsets(MarginTop(), MarginRight(), MarginBottom(),
-                           MarginLeft());
-}
-
 LayoutUnit LayoutInline::MarginLeft() const {
   return ComputeMargin(this, Style()->MarginLeft());
 }
@@ -843,34 +838,6 @@
   return ComputeMargin(this, Style()->MarginBottom());
 }
 
-LayoutUnit LayoutInline::MarginStart(const ComputedStyle* other_style) const {
-  return ComputeMargin(this, StyleRef().MarginStartUsing(
-                                 other_style ? *other_style : StyleRef()));
-}
-
-LayoutUnit LayoutInline::MarginEnd(const ComputedStyle* other_style) const {
-  return ComputeMargin(
-      this, StyleRef().MarginEndUsing(other_style ? *other_style : StyleRef()));
-}
-
-LayoutUnit LayoutInline::MarginBefore(const ComputedStyle* other_style) const {
-  return ComputeMargin(this, StyleRef().MarginBeforeUsing(
-                                 other_style ? *other_style : StyleRef()));
-}
-
-LayoutUnit LayoutInline::MarginAfter(const ComputedStyle* other_style) const {
-  return ComputeMargin(this, StyleRef().MarginAfterUsing(
-                                 other_style ? *other_style : StyleRef()));
-}
-
-LayoutUnit LayoutInline::MarginOver() const {
-  return ComputeMargin(this, Style()->MarginOver());
-}
-
-LayoutUnit LayoutInline::MarginUnder() const {
-  return ComputeMargin(this, Style()->MarginUnder());
-}
-
 bool LayoutInline::NodeAtPoint(HitTestResult& result,
                                const HitTestLocation& location_in_container,
                                const LayoutPoint& accumulated_offset,
diff --git a/third_party/WebKit/Source/core/layout/LayoutInline.h b/third_party/WebKit/Source/core/layout/LayoutInline.h
index 3b3348b3..0ae88fee 100644
--- a/third_party/WebKit/Source/core/layout/LayoutInline.h
+++ b/third_party/WebKit/Source/core/layout/LayoutInline.h
@@ -135,20 +135,10 @@
     return ToElement(LayoutBoxModelObject::GetNode());
   }
 
-  LayoutRectOutsets MarginBoxOutsets() const final;
   LayoutUnit MarginLeft() const final;
   LayoutUnit MarginRight() const final;
   LayoutUnit MarginTop() const final;
   LayoutUnit MarginBottom() const final;
-  LayoutUnit MarginBefore(
-      const ComputedStyle* other_style = nullptr) const final;
-  LayoutUnit MarginAfter(
-      const ComputedStyle* other_style = nullptr) const final;
-  LayoutUnit MarginStart(
-      const ComputedStyle* other_style = nullptr) const final;
-  LayoutUnit MarginEnd(const ComputedStyle* other_style = nullptr) const final;
-  LayoutUnit MarginOver() const final;
-  LayoutUnit MarginUnder() const final;
 
   void AbsoluteRects(Vector<IntRect>&,
                      const LayoutPoint& accumulated_offset) const final;
diff --git a/third_party/WebKit/Source/core/layout/LayoutScrollbarPart.h b/third_party/WebKit/Source/core/layout/LayoutScrollbarPart.h
index b654339..435e23c 100644
--- a/third_party/WebKit/Source/core/layout/LayoutScrollbarPart.h
+++ b/third_party/WebKit/Source/core/layout/LayoutScrollbarPart.h
@@ -48,10 +48,6 @@
   void UpdateLayout() override;
 
   // Scrollbar parts needs to be rendered at device pixel boundaries.
-  LayoutRectOutsets MarginBoxOutsets() const override {
-    DCHECK(IsIntegerValue(LayoutBlock::MarginBoxOutsets().Top()));
-    return LayoutBlock::MarginBoxOutsets();
-  }
   LayoutUnit MarginTop() const override {
     DCHECK(IsIntegerValue(LayoutBlock::MarginTop()));
     return LayoutBlock::MarginTop();
@@ -102,10 +98,6 @@
   LayoutUnit PaddingBottom() const override { return LayoutUnit(); }
   LayoutUnit PaddingLeft() const override { return LayoutUnit(); }
   LayoutUnit PaddingRight() const override { return LayoutUnit(); }
-  LayoutUnit PaddingBefore() const override { return LayoutUnit(); }
-  LayoutUnit PaddingAfter() const override { return LayoutUnit(); }
-  LayoutUnit PaddingStart() const override { return LayoutUnit(); }
-  LayoutUnit PaddingEnd() const override { return LayoutUnit(); }
 
   void LayoutHorizontalPart();
   void LayoutVerticalPart();
diff --git a/third_party/WebKit/Source/core/layout/LayoutTable.cpp b/third_party/WebKit/Source/core/layout/LayoutTable.cpp
index 5e01302..7533848 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTable.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutTable.cpp
@@ -1135,36 +1135,36 @@
   needs_section_recalc_ = false;
 }
 
-LayoutUnit LayoutTable::BorderBefore() const {
+LayoutUnit LayoutTable::BorderLeft() const {
   if (ShouldCollapseBorders()) {
     UpdateCollapsedOuterBorders();
-    return LayoutUnit(collapsed_outer_border_before_);
+    return LayoutUnit(LogicalCollapsedOuterBorderToPhysical().Left());
   }
-  return LayoutUnit(LayoutBlock::BorderBefore().ToInt());
+  return LayoutUnit(LayoutBlock::BorderLeft().ToInt());
 }
 
-LayoutUnit LayoutTable::BorderAfter() const {
+LayoutUnit LayoutTable::BorderRight() const {
   if (ShouldCollapseBorders()) {
     UpdateCollapsedOuterBorders();
-    return LayoutUnit(collapsed_outer_border_after_);
+    return LayoutUnit(LogicalCollapsedOuterBorderToPhysical().Right());
   }
-  return LayoutUnit(LayoutBlock::BorderAfter().ToInt());
+  return LayoutUnit(LayoutBlock::BorderRight().ToInt());
 }
 
-LayoutUnit LayoutTable::BorderStart() const {
+LayoutUnit LayoutTable::BorderTop() const {
   if (ShouldCollapseBorders()) {
     UpdateCollapsedOuterBorders();
-    return LayoutUnit(collapsed_outer_border_start_);
+    return LayoutUnit(LogicalCollapsedOuterBorderToPhysical().Top());
   }
-  return LayoutUnit(LayoutBlock::BorderStart().ToInt());
+  return LayoutUnit(LayoutBlock::BorderTop().ToInt());
 }
 
-LayoutUnit LayoutTable::BorderEnd() const {
+LayoutUnit LayoutTable::BorderBottom() const {
   if (ShouldCollapseBorders()) {
     UpdateCollapsedOuterBorders();
-    return LayoutUnit(collapsed_outer_border_end_);
+    return LayoutUnit(LogicalCollapsedOuterBorderToPhysical().Bottom());
   }
-  return LayoutUnit(LayoutBlock::BorderEnd().ToInt());
+  return LayoutUnit(LayoutBlock::BorderBottom().ToInt());
 }
 
 LayoutTableSection* LayoutTable::SectionAbove(
@@ -1512,28 +1512,36 @@
   if (ShouldCollapseBorders())
     return LayoutUnit();
 
-  return LayoutBlock::PaddingTop();
+  // TODO(crbug.com/377847): The ToInt call should be removed when Table is
+  // sub-pixel aware.
+  return LayoutUnit(LayoutBlock::PaddingTop().ToInt());
 }
 
 LayoutUnit LayoutTable::PaddingBottom() const {
   if (ShouldCollapseBorders())
     return LayoutUnit();
 
-  return LayoutBlock::PaddingBottom();
+  // TODO(crbug.com/377847): The ToInt call should be removed when Table is
+  // sub-pixel aware.
+  return LayoutUnit(LayoutBlock::PaddingBottom().ToInt());
 }
 
 LayoutUnit LayoutTable::PaddingLeft() const {
   if (ShouldCollapseBorders())
     return LayoutUnit();
 
-  return LayoutBlock::PaddingLeft();
+  // TODO(crbug.com/377847): The ToInt call should be removed when Table is
+  // sub-pixel aware.
+  return LayoutUnit(LayoutBlock::PaddingLeft().ToInt());
 }
 
 LayoutUnit LayoutTable::PaddingRight() const {
   if (ShouldCollapseBorders())
     return LayoutUnit();
 
-  return LayoutBlock::PaddingRight();
+  // TODO(crbug.com/377847): The ToInt call should be removed when Table is
+  // sub-pixel aware.
+  return LayoutUnit(LayoutBlock::PaddingRight().ToInt());
 }
 
 unsigned LayoutTable::ComputeCollapsedOuterBorderBefore() const {
diff --git a/third_party/WebKit/Source/core/layout/LayoutTable.h b/third_party/WebKit/Source/core/layout/LayoutTable.h
index 9cf82f5..f7f0035 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTable.h
+++ b/third_party/WebKit/Source/core/layout/LayoutTable.h
@@ -148,38 +148,10 @@
     return Style()->BorderCollapse() == EBorderCollapse::kCollapse;
   }
 
-  LayoutUnit BorderStart() const override;
-  LayoutUnit BorderEnd() const override;
-  LayoutUnit BorderBefore() const override;
-  LayoutUnit BorderAfter() const override;
-
-  LayoutUnit BorderLeft() const override {
-    if (Style()->IsHorizontalWritingMode())
-      return Style()->IsLeftToRightDirection() ? BorderStart() : BorderEnd();
-    return Style()->IsFlippedBlocksWritingMode() ? BorderAfter()
-                                                 : BorderBefore();
-  }
-
-  LayoutUnit BorderRight() const override {
-    if (Style()->IsHorizontalWritingMode())
-      return Style()->IsLeftToRightDirection() ? BorderEnd() : BorderStart();
-    return Style()->IsFlippedBlocksWritingMode() ? BorderBefore()
-                                                 : BorderAfter();
-  }
-
-  LayoutUnit BorderTop() const override {
-    if (Style()->IsHorizontalWritingMode())
-      return Style()->IsFlippedBlocksWritingMode() ? BorderAfter()
-                                                   : BorderBefore();
-    return Style()->IsLeftToRightDirection() ? BorderStart() : BorderEnd();
-  }
-
-  LayoutUnit BorderBottom() const override {
-    if (Style()->IsHorizontalWritingMode())
-      return Style()->IsFlippedBlocksWritingMode() ? BorderBefore()
-                                                   : BorderAfter();
-    return Style()->IsLeftToRightDirection() ? BorderEnd() : BorderStart();
-  }
+  LayoutUnit BorderLeft() const override;
+  LayoutUnit BorderRight() const override;
+  LayoutUnit BorderTop() const override;
+  LayoutUnit BorderBottom() const override;
 
   void AddChild(LayoutObject* child,
                 LayoutObject* before_child = nullptr) override;
@@ -295,15 +267,6 @@
   LayoutUnit PaddingLeft() const override;
   LayoutUnit PaddingRight() const override;
 
-  // Override paddingStart/End to return pixel values to match behavor of
-  // LayoutTableCell.
-  LayoutUnit PaddingEnd() const override {
-    return LayoutUnit(LayoutBlock::PaddingEnd().ToInt());
-  }
-  LayoutUnit PaddingStart() const override {
-    return LayoutUnit(LayoutBlock::PaddingStart().ToInt());
-  }
-
   LayoutUnit BordersPaddingAndSpacingInRowDirection() const {
     // 'border-spacing' only applies to separate borders (see 17.6.1 The
     // separated borders model).
@@ -590,6 +553,13 @@
     return NumEffectiveColumns();
   }
 
+  LogicalToPhysical<unsigned> LogicalCollapsedOuterBorderToPhysical() const {
+    return LogicalToPhysical<unsigned>(
+        StyleRef().GetWritingMode(), StyleRef().Direction(),
+        collapsed_outer_border_start_, collapsed_outer_border_end_,
+        collapsed_outer_border_before_, collapsed_outer_border_after_);
+  }
+
   short h_spacing_;
   short v_spacing_;
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableCell.cpp b/third_party/WebKit/Source/core/layout/LayoutTableCell.cpp
index a749b9a9..da78da84 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTableCell.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutTableCell.cpp
@@ -322,56 +322,34 @@
 
 LayoutUnit LayoutTableCell::PaddingTop() const {
   LayoutUnit result = ComputedCSSPaddingTop();
-  if (IsHorizontalWritingMode())
-    result += (blink::IsHorizontalWritingMode(Style()->GetWritingMode())
-                   ? IntrinsicPaddingBefore()
-                   : IntrinsicPaddingAfter());
-  // TODO(leviw): The floor call should be removed when Table is sub-pixel
-  // aware. crbug.com/377847
-  return LayoutUnit(result.Floor());
+  result += LogicalIntrinsicPaddingToPhysical().Top();
+  // TODO(crbug.com/377847): The ToInt call should be removed when Table is
+  // sub-pixel aware.
+  return LayoutUnit(result.ToInt());
 }
 
 LayoutUnit LayoutTableCell::PaddingBottom() const {
   LayoutUnit result = ComputedCSSPaddingBottom();
-  if (IsHorizontalWritingMode())
-    result += (blink::IsHorizontalWritingMode(Style()->GetWritingMode())
-                   ? IntrinsicPaddingAfter()
-                   : IntrinsicPaddingBefore());
-  // TODO(leviw): The floor call should be removed when Table is sub-pixel
-  // aware. crbug.com/377847
-  return LayoutUnit(result.Floor());
+  result += LogicalIntrinsicPaddingToPhysical().Bottom();
+  // TODO(crbug.com/377847): The ToInt call should be removed when Table is
+  // sub-pixel aware.
+  return LayoutUnit(result.ToInt());
 }
 
 LayoutUnit LayoutTableCell::PaddingLeft() const {
   LayoutUnit result = ComputedCSSPaddingLeft();
-  if (!IsHorizontalWritingMode())
-    result += (IsFlippedLinesWritingMode(Style()->GetWritingMode())
-                   ? IntrinsicPaddingBefore()
-                   : IntrinsicPaddingAfter());
-  // TODO(leviw): The floor call should be removed when Table is sub-pixel
-  // aware. crbug.com/377847
-  return LayoutUnit(result.Floor());
+  result += LogicalIntrinsicPaddingToPhysical().Left();
+  // TODO(crbug.com/377847): The ToInt call should be removed when Table is
+  // sub-pixel aware.
+  return LayoutUnit(result.ToInt());
 }
 
 LayoutUnit LayoutTableCell::PaddingRight() const {
   LayoutUnit result = ComputedCSSPaddingRight();
-  if (!IsHorizontalWritingMode())
-    result += (IsFlippedLinesWritingMode(Style()->GetWritingMode())
-                   ? IntrinsicPaddingAfter()
-                   : IntrinsicPaddingBefore());
-  // TODO(leviw): The floor call should be removed when Table is sub-pixel
-  // aware. crbug.com/377847
-  return LayoutUnit(result.Floor());
-}
-
-LayoutUnit LayoutTableCell::PaddingBefore() const {
-  return LayoutUnit(ComputedCSSPaddingBefore().Floor() +
-                    IntrinsicPaddingBefore());
-}
-
-LayoutUnit LayoutTableCell::PaddingAfter() const {
-  return LayoutUnit(ComputedCSSPaddingAfter().Floor() +
-                    IntrinsicPaddingAfter());
+  result += LogicalIntrinsicPaddingToPhysical().Right();
+  // TODO(crbug.com/377847): The ToInt call should be removed when Table is
+  // sub-pixel aware.
+  return LayoutUnit(result.ToInt());
 }
 
 void LayoutTableCell::SetOverrideLogicalContentHeightFromRowHeight(
@@ -1056,33 +1034,6 @@
              : LayoutBlockFlow::BorderBottom();
 }
 
-// FIXME: https://bugs.webkit.org/show_bug.cgi?id=46191, make the collapsed
-// border drawing work with different block flow values instead of being
-// hard-coded to top-to-bottom.
-LayoutUnit LayoutTableCell::BorderStart() const {
-  return Table()->ShouldCollapseBorders()
-             ? LayoutUnit(CollapsedBorderHalfStart(false))
-             : LayoutBlockFlow::BorderStart();
-}
-
-LayoutUnit LayoutTableCell::BorderEnd() const {
-  return Table()->ShouldCollapseBorders()
-             ? LayoutUnit(CollapsedBorderHalfEnd(false))
-             : LayoutBlockFlow::BorderEnd();
-}
-
-LayoutUnit LayoutTableCell::BorderBefore() const {
-  return Table()->ShouldCollapseBorders()
-             ? LayoutUnit(CollapsedBorderHalfBefore(false))
-             : LayoutBlockFlow::BorderBefore();
-}
-
-LayoutUnit LayoutTableCell::BorderAfter() const {
-  return Table()->ShouldCollapseBorders()
-             ? LayoutUnit(CollapsedBorderHalfAfter(false))
-             : LayoutBlockFlow::BorderAfter();
-}
-
 unsigned LayoutTableCell::CollapsedBorderHalfStart(bool outer) const {
   UpdateCollapsedBorderValues();
   const auto* collapsed_border_values = this->GetCollapsedBorderValues();
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableCell.h b/third_party/WebKit/Source/core/layout/LayoutTableCell.h
index 72a17e8..06c189f8 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTableCell.h
+++ b/third_party/WebKit/Source/core/layout/LayoutTableCell.h
@@ -182,10 +182,6 @@
   LayoutUnit BorderRight() const override;
   LayoutUnit BorderTop() const override;
   LayoutUnit BorderBottom() const override;
-  LayoutUnit BorderStart() const override;
-  LayoutUnit BorderEnd() const override;
-  LayoutUnit BorderBefore() const override;
-  LayoutUnit BorderAfter() const override;
 
   void UpdateLayout() override;
 
@@ -217,13 +213,6 @@
   LayoutUnit PaddingLeft() const override;
   LayoutUnit PaddingRight() const override;
 
-  // FIXME: For now we just assume the cell has the same block flow direction as
-  // the table. It's likely we'll create an extra anonymous LayoutBlock to
-  // handle mixing directionality anyway, in which case we can lock the block
-  // flow directionality of the cells to the table's directionality.
-  LayoutUnit PaddingBefore() const override;
-  LayoutUnit PaddingAfter() const override;
-
   void SetOverrideLogicalContentHeightFromRowHeight(LayoutUnit);
 
   void ScrollbarsChanged(bool horizontal_scrollbar_changed,
@@ -360,6 +349,8 @@
   void ComputeOverflow(LayoutUnit old_client_after_edge,
                        bool recompute_floats = false) override;
 
+  // Converts collapsed border half width from the table's logical orientation
+  // to physical orientation.
   LogicalToPhysical<unsigned> LogicalCollapsedBorderHalfToPhysical(
       bool outer) const {
     return LogicalToPhysical<unsigned>(
@@ -388,6 +379,11 @@
   unsigned CollapsedBorderHalfBefore(bool outer) const;
   unsigned CollapsedBorderHalfAfter(bool outer) const;
 
+  LogicalToPhysical<int> LogicalIntrinsicPaddingToPhysical() const {
+    return LogicalToPhysical<int>(
+        StyleRef().GetWritingMode(), StyleRef().Direction(), 0, 0,
+        intrinsic_padding_before_, intrinsic_padding_after_);
+  }
   void SetIntrinsicPaddingBefore(int p) { intrinsic_padding_before_ = p; }
   void SetIntrinsicPaddingAfter(int p) { intrinsic_padding_after_ = p; }
   void SetIntrinsicPadding(int before, int after) {
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableTest.cpp b/third_party/WebKit/Source/core/layout/LayoutTableTest.cpp
index 2781377..109d8eb6 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTableTest.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutTableTest.cpp
@@ -203,6 +203,25 @@
   EXPECT_EQ(999999, table->OffsetWidth());
 }
 
+TEST_F(LayoutTableTest, PaddingWithCollapsedBorder) {
+  SetBodyInnerHTML(
+      "<table id='table' style='padding: 20px; border-collapse: collapse'>"
+      "  <tr><td>TD</td</tr>"
+      "</table>");
+
+  auto* table = GetTableByElementId("table");
+  EXPECT_EQ(0, table->PaddingLeft());
+  EXPECT_EQ(0, table->PaddingRight());
+  EXPECT_EQ(0, table->PaddingTop());
+  EXPECT_EQ(0, table->PaddingBottom());
+  EXPECT_EQ(0, table->PaddingStart());
+  EXPECT_EQ(0, table->PaddingEnd());
+  EXPECT_EQ(0, table->PaddingBefore());
+  EXPECT_EQ(0, table->PaddingAfter());
+  EXPECT_EQ(0, table->PaddingOver());
+  EXPECT_EQ(0, table->PaddingUnder());
+}
+
 }  // anonymous namespace
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/line/InlineFlowBox.cpp b/third_party/WebKit/Source/core/layout/line/InlineFlowBox.cpp
index a06265e..90e423e6 100644
--- a/third_party/WebKit/Source/core/layout/line/InlineFlowBox.cpp
+++ b/third_party/WebKit/Source/core/layout/line/InlineFlowBox.cpp
@@ -963,7 +963,7 @@
   // actually the opposite shadow that applies, since the line is "upside down"
   // in terms of block coordinates.
   LayoutRectOutsets logical_outsets(
-      outsets.LogicalOutsetsWithFlippedLines(writing_mode));
+      outsets.LineOrientationOutsetsWithFlippedLines(writing_mode));
 
   LayoutRect shadow_bounds(LogicalFrameRect());
   shadow_bounds.Expand(logical_outsets);
@@ -987,7 +987,7 @@
   // actually the opposite border that applies, since the line is "upside down"
   // in terms of block coordinates. vertical-rl is the flipped line mode.
   LayoutRectOutsets logical_outsets =
-      style.BorderImageOutsets().LogicalOutsetsWithFlippedLines(
+      style.BorderImageOutsets().LineOrientationOutsetsWithFlippedLines(
           style.GetWritingMode());
 
   if (!IncludeLogicalLeftEdge())
@@ -1066,10 +1066,11 @@
       std::min(0.0f, style.GetFont().GetFontDescription().LetterSpacing());
 
   LayoutRectOutsets text_shadow_logical_outsets;
-  if (ShadowList* text_shadow = style.TextShadow())
+  if (ShadowList* text_shadow = style.TextShadow()) {
     text_shadow_logical_outsets =
         LayoutRectOutsets(text_shadow->RectOutsetsIncludingOriginal())
-            .LogicalOutsets(style.GetWritingMode());
+            .LineOrientationOutsets(style.GetWritingMode());
+  }
 
   // FIXME: This code currently uses negative values for expansion of the top
   // and left edges. This should be cleaned up.
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.cc
index 7c62132..01b1c7f 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.cc
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.cc
@@ -201,10 +201,10 @@
       container_builder_.AddOutOfFlowDescendant(
           // Absolute positioning blockifies the box's display type.
           // https://drafts.csswg.org/css-display/#transformations
-          NGBlockNode(ToLayoutBox(item.GetLayoutObject())),
-          NGStaticPosition::Create(ConstraintSpace().WritingMode(),
-                                   ConstraintSpace().Direction(),
-                                   NGPhysicalOffset()));
+          {NGBlockNode(ToLayoutBox(item.GetLayoutObject())),
+           NGStaticPosition::Create(ConstraintSpace().WritingMode(),
+                                    ConstraintSpace().Direction(),
+                                    NGPhysicalOffset())});
       continue;
     } else {
       continue;
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_node.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_node.cc
index 6bb6121..b4df24dc 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_node.cc
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_node.cc
@@ -186,34 +186,37 @@
 void NGInlineNode::PrepareLayout() {
   // Scan list of siblings collecting all in-flow non-atomic inlines. A single
   // NGInlineNode represent a collection of adjacent non-atomic inlines.
-  CollectInlines(GetLayoutBlockFlow());
+  CollectInlines();
   SegmentText();
   ShapeText();
 }
 
+// TODO(xiaochengh): Remove this forward declaration, and move the function body
+// to the anonymous namespace.
+static LayoutBox* CollectInlinesInternal(LayoutBlockFlow*,
+                                         NGInlineItemsBuilder*);
+
 // Depth-first-scan of all LayoutInline and LayoutText nodes that make up this
 // NGInlineNode object. Collects LayoutText items, merging them up into the
 // parent LayoutInline where possible, and joining all text content in a single
 // string to allow bidi resolution and shaping of the entire block.
-void NGInlineNode::CollectInlines(LayoutBlockFlow* block) {
+void NGInlineNode::CollectInlines() {
   DCHECK(Data().text_content_.IsNull());
   DCHECK(Data().items_.IsEmpty());
   NGInlineItemsBuilder builder(&MutableData().items_);
-  builder.EnterBlock(block->Style());
-  LayoutObject* next_sibling = CollectInlines(block, &builder);
-  builder.ExitBlock();
-
+  MutableData().next_sibling_ =
+      CollectInlinesInternal(GetLayoutBlockFlow(), &builder);
   MutableData().text_content_ = builder.ToString();
-  DCHECK(!next_sibling || !next_sibling->IsInline());
-  MutableData().next_sibling_ = ToLayoutBox(next_sibling);
   MutableData().is_bidi_enabled_ =
       !Data().text_content_.IsEmpty() &&
       !(Data().text_content_.Is8Bit() && !builder.HasBidiControls());
 }
 
-LayoutObject* NGInlineNode::CollectInlines(LayoutBlockFlow* block,
-                                           NGInlineItemsBuilder* builder) {
+static LayoutBox* CollectInlinesInternal(LayoutBlockFlow* block,
+                                         NGInlineItemsBuilder* builder) {
+  builder->EnterBlock(block->Style());
   LayoutObject* node = block->FirstChild();
+  LayoutBox* next_box = nullptr;
   while (node) {
     if (node->IsText()) {
       builder->SetIsSVGText(node->IsSVGInlineText());
@@ -237,7 +240,8 @@
 
     } else if (!node->IsInline()) {
       // A block box found. End inline and transit to block layout.
-      return node;
+      next_box = ToLayoutBox(node);
+      break;
 
     } else {
       builder->EnterInline(node);
@@ -262,14 +266,18 @@
         break;
       }
       node = node->Parent();
-      if (node == block)
-        return nullptr;
+      if (node == block) {
+        // Set |node| to |nullptr| to break out of the outer loop.
+        node = nullptr;
+        break;
+      }
       DCHECK(node->IsInline());
       builder->ExitInline(node);
       node->ClearNeedsLayout();
     }
   }
-  return nullptr;
+  builder->ExitBlock();
+  return next_box;
 }
 
 void NGInlineNode::SegmentText() {
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_node.h b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_node.h
index 5de226fc..e67356c3 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_node.h
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_node.h
@@ -21,7 +21,6 @@
 class EmptyOffsetMappingBuilder;
 class LayoutBlockFlow;
 class LayoutNGBlockFlow;
-class LayoutObject;
 struct MinMaxContentSize;
 class NGConstraintSpace;
 class NGInlineItem;
@@ -80,8 +79,7 @@
   void PrepareLayout();
   bool IsPrepareLayoutFinished() const { return !Text().IsNull(); }
 
-  void CollectInlines(LayoutBlockFlow*);
-  LayoutObject* CollectInlines(LayoutBlockFlow*, NGInlineItemsBuilder*);
+  void CollectInlines();
   void SegmentText();
   void ShapeText();
 
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_node_test.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_node_test.cc
index 8c1649e..19bd0ef6 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_node_test.cc
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_node_test.cc
@@ -137,7 +137,7 @@
 TEST_F(NGInlineNodeTest, CollectInlinesText) {
   SetupHtml("t", "<div id=t>Hello <span>inline</span> world.</div>");
   NGInlineNodeForTest node = CreateInlineNode();
-  node.CollectInlines(layout_block_flow_);
+  node.CollectInlines();
   Vector<NGInlineItem>& items = node.Items();
   TEST_ITEM_TYPE_OFFSET(items[0], kText, 0u, 6u);
   TEST_ITEM_TYPE_OFFSET(items[1], kOpenTag, 6u, 6u);
@@ -150,7 +150,7 @@
 TEST_F(NGInlineNodeTest, CollectInlinesBR) {
   SetupHtml("t", u"<div id=t>Hello<br>World</div>");
   NGInlineNodeForTest node = CreateInlineNode();
-  node.CollectInlines(layout_block_flow_);
+  node.CollectInlines();
   EXPECT_EQ("Hello\nWorld", node.Text());
   Vector<NGInlineItem>& items = node.Items();
   TEST_ITEM_TYPE_OFFSET(items[0], kText, 0u, 5u);
@@ -162,7 +162,7 @@
 TEST_F(NGInlineNodeTest, CollectInlinesRtlText) {
   SetupHtml("t", u"<div id=t dir=rtl>\u05E2 <span>\u05E2</span> \u05E2</div>");
   NGInlineNodeForTest node = CreateInlineNode();
-  node.CollectInlines(layout_block_flow_);
+  node.CollectInlines();
   EXPECT_TRUE(node.IsBidiEnabled());
   node.SegmentText();
   EXPECT_TRUE(node.IsBidiEnabled());
@@ -178,7 +178,7 @@
 TEST_F(NGInlineNodeTest, CollectInlinesMixedText) {
   SetupHtml("t", u"<div id=t>Hello, \u05E2 <span>\u05E2</span></div>");
   NGInlineNodeForTest node = CreateInlineNode();
-  node.CollectInlines(layout_block_flow_);
+  node.CollectInlines();
   EXPECT_TRUE(node.IsBidiEnabled());
   node.SegmentText();
   EXPECT_TRUE(node.IsBidiEnabled());
@@ -194,7 +194,7 @@
 TEST_F(NGInlineNodeTest, CollectInlinesMixedTextEndWithON) {
   SetupHtml("t", u"<div id=t>Hello, \u05E2 <span>\u05E2!</span></div>");
   NGInlineNodeForTest node = CreateInlineNode();
-  node.CollectInlines(layout_block_flow_);
+  node.CollectInlines();
   EXPECT_TRUE(node.IsBidiEnabled());
   node.SegmentText();
   EXPECT_TRUE(node.IsBidiEnabled());
diff --git a/third_party/WebKit/Source/core/layout/ng/layout_ng_block_flow.cc b/third_party/WebKit/Source/core/layout/ng/layout_ng_block_flow.cc
index efdb2e3..f50fa2c 100644
--- a/third_party/WebKit/Source/core/layout/ng/layout_ng_block_flow.cc
+++ b/third_party/WebKit/Source/core/layout/ng/layout_ng_block_flow.cc
@@ -41,9 +41,9 @@
     SetLogicalTop(computed_values.position_);
   }
 
-  for (NGBlockNode descendant : result->OutOfFlowDescendants())
-    descendant.UseOldOutOfFlowPositioning();
-
+  for (NGOutOfFlowPositionedDescendant descendant :
+       result->OutOfFlowPositionedDescendants())
+    descendant.node.UseOldOutOfFlowPositioning();
 }
 
 NGInlineNodeData& LayoutNGBlockFlow::GetNGInlineNodeData() const {
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
index 45688101..45e959e 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
@@ -297,6 +297,19 @@
                                     end_margin_strut.Sum());
     end_margin_strut = NGMarginStrut();
   }
+
+  // If the current layout is a new formatting context, we need to encapsulate
+  // all of our floats.
+  if (ConstraintSpace().IsNewFormattingContext()) {
+    // We can use the BFC coordinates, as we are a new formatting context.
+    DCHECK_EQ(container_builder_.BfcOffset().value(), NGLogicalOffset());
+
+    WTF::Optional<LayoutUnit> float_end_offset =
+        GetClearanceOffset(ConstraintSpace().Exclusions(), EClear::kBoth);
+    if (float_end_offset)
+      content_size_ = std::max(content_size_, float_end_offset.value());
+  }
+
   content_size_ += border_scrollbar_padding_.block_end;
 
   // Recompute the block-axis size now that we know our content size.
@@ -450,17 +463,19 @@
   if (child.CreatesNewFormattingContext())
     child_bfc_offset = PositionNewFc(child, previous_inflow_position, fragment,
                                      child_data, child_space);
-  else if (fragment.BfcOffset())
-    child_bfc_offset = PositionWithBfcOffset(fragment);
+  else if (layout_result->BfcOffset())
+    child_bfc_offset =
+        PositionWithBfcOffset(layout_result->BfcOffset().value());
   else if (container_builder_.BfcOffset())
-    child_bfc_offset = PositionWithParentBfc(child_space, child_data, fragment);
+    child_bfc_offset =
+        PositionWithParentBfc(child_space, child_data, *layout_result);
   else
     DCHECK(!fragment.BlockSize());
 
   NGLogicalOffset logical_offset =
       CalculateLogicalOffset(child_data.margins, child_bfc_offset);
 
-  NGMarginStrut margin_strut = fragment.EndMarginStrut();
+  NGMarginStrut margin_strut = layout_result->EndMarginStrut();
   margin_strut.Append(child_data.margins.block_end);
 
   // Only modify content_size_ if the fragment's BlockSize is not empty. This is
@@ -485,9 +500,9 @@
   LayoutUnit logical_block_offset;
 
   if (child_bfc_offset) {
-    // TODO(crbug.com/716930): I think the fragment.BfcOffset() condition here
-    // can be removed once we've removed inline splitting.
-    if (fragment.BlockSize() || fragment.BfcOffset()) {
+    // TODO(crbug.com/716930): I think the layout_result->BfcOffset() condition
+    // here can be removed once we've removed inline splitting.
+    if (fragment.BlockSize() || layout_result->BfcOffset()) {
       child_end_bfc_block_offset =
           child_bfc_offset.value().block_offset + fragment.BlockSize();
       logical_block_offset = logical_offset.block_offset + fragment.BlockSize();
@@ -568,23 +583,23 @@
 }
 
 NGLogicalOffset NGBlockLayoutAlgorithm::PositionWithBfcOffset(
-    const NGBoxFragment& fragment) {
-  DCHECK(fragment.BfcOffset());
-  LayoutUnit bfc_block_offset = fragment.BfcOffset().value().block_offset;
+    const NGLogicalOffset& bfc_offset) {
+  LayoutUnit bfc_block_offset = bfc_offset.block_offset;
   MaybeUpdateFragmentBfcOffset(ConstraintSpace(), bfc_block_offset,
                                &container_builder_);
   PositionPendingFloats(bfc_block_offset, &container_builder_,
                         MutableConstraintSpace());
-  return fragment.BfcOffset().value();
+  return bfc_offset;
 }
 
 NGLogicalOffset NGBlockLayoutAlgorithm::PositionWithParentBfc(
     const NGConstraintSpace& space,
     const NGInflowChildData& child_data,
-    const NGBoxFragment& fragment) {
+    const NGLayoutResult& layout_result) {
   // The child must be an in-flow zero-block-size fragment, use its end margin
   // strut for positioning.
-  DCHECK(!fragment.BfcOffset());
+  NGFragment fragment(ConstraintSpace().WritingMode(),
+                      layout_result.PhysicalFragment().Get());
   DCHECK_EQ(fragment.BlockSize(), LayoutUnit());
 
   NGLogicalOffset child_bfc_offset = {
@@ -592,7 +607,7 @@
           border_scrollbar_padding_.inline_start +
           child_data.margins.inline_start,
       child_data.bfc_offset_estimate.block_offset +
-          fragment.EndMarginStrut().Sum()};
+          layout_result.EndMarginStrut().Sum()};
 
   AdjustToClearance(space.ClearanceOffset(), &child_bfc_offset);
   PositionPendingFloatsFromOffset(
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h
index 1e1a584..f93787e1 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h
+++ b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h
@@ -94,7 +94,7 @@
                                 const NGConstraintSpace& child_space);
 
   // Positions the fragment that knows its BFC offset.
-  NGLogicalOffset PositionWithBfcOffset(const NGBoxFragment&);
+  NGLogicalOffset PositionWithBfcOffset(const NGLogicalOffset& bfc_offset);
 
   // Positions using the parent BFC offset.
   // Fragment doesn't know its offset but we can still calculate its BFC
@@ -105,7 +105,7 @@
   //     <div id="empty-div" style="margins: 1px"></div>
   NGLogicalOffset PositionWithParentBfc(const NGConstraintSpace&,
                                         const NGInflowChildData& child_data,
-                                        const NGBoxFragment&);
+                                        const NGLayoutResult&);
 
   NGLogicalOffset PositionLegacy(const NGConstraintSpace& child_space,
                                  const NGInflowChildData& child_data);
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm_test.cc b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm_test.cc
index ba2499a3..b2761b84 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm_test.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm_test.cc
@@ -407,15 +407,12 @@
   // Margins are collapsed with the result 200 = std::max(20, 200)
   // The fragment size 258 == body's margin 8 + child's height 50 + 200
   EXPECT_EQ(NGPhysicalSize(LayoutUnit(800), LayoutUnit(258)), fragment->Size());
-  EXPECT_EQ(NGMarginStrut({LayoutUnit(200)}),
-            container_fragment->EndMarginStrut());
 
   // height == fixed
   run_test(Length(50, kFixed));
   // Margins are not collapsed, so fragment still has margins == 20.
   // The fragment size 78 == body's margin 8 + child's height 50 + 20
   EXPECT_EQ(NGPhysicalSize(LayoutUnit(800), LayoutUnit(78)), fragment->Size());
-  EXPECT_EQ(NGMarginStrut(), container_fragment->EndMarginStrut());
 }
 
 // Verifies that 2 adjoining margins are not collapsed if there is padding or
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_box_fragment.cc b/third_party/WebKit/Source/core/layout/ng/ng_box_fragment.cc
index 1d51f39..99db6d8 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_box_fragment.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_box_fragment.cc
@@ -15,19 +15,4 @@
   return physical_fragment->OverflowSize().ConvertToLogical(WritingMode());
 }
 
-const WTF::Optional<NGLogicalOffset>& NGBoxFragment::BfcOffset() const {
-  WRITING_MODE_IGNORED(
-      "Accessing BFC offset is allowed here because writing"
-      "modes are irrelevant in this case.");
-  return ToNGPhysicalBoxFragment(physical_fragment_)->BfcOffset();
-}
-
-const NGMarginStrut& NGBoxFragment::EndMarginStrut() const {
-  WRITING_MODE_IGNORED(
-      "Accessing the margin strut is fine here. Changing the writing mode"
-      "establishes a new formatting context, for which a margin strut is"
-      "never set for a fragment.");
-  return ToNGPhysicalBoxFragment(physical_fragment_)->EndMarginStrut();
-}
-
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_box_fragment.h b/third_party/WebKit/Source/core/layout/ng/ng_box_fragment.h
index 4e2e4c57..60c14c8 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_box_fragment.h
+++ b/third_party/WebKit/Source/core/layout/ng/ng_box_fragment.h
@@ -22,10 +22,6 @@
 
   // Returns the total size, including the contents outside of the border-box.
   NGLogicalSize OverflowSize() const;
-
-  const WTF::Optional<NGLogicalOffset>& BfcOffset() const;
-
-  const NGMarginStrut& EndMarginStrut() const;
 };
 
 DEFINE_TYPE_CASTS(NGBoxFragment,
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_fragment.h b/third_party/WebKit/Source/core/layout/ng/ng_fragment.h
index e1fdb9f7..fd44298f 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_fragment.h
+++ b/third_party/WebKit/Source/core/layout/ng/ng_fragment.h
@@ -20,6 +20,10 @@
   STACK_ALLOCATED();
 
  public:
+  NGFragment(NGWritingMode writing_mode,
+             const NGPhysicalFragment* physical_fragment)
+      : physical_fragment_(physical_fragment), writing_mode_(writing_mode) {}
+
   NGWritingMode WritingMode() const {
     return static_cast<NGWritingMode>(writing_mode_);
   }
@@ -39,10 +43,6 @@
   NGPhysicalFragment::NGFragmentType Type() const;
 
  protected:
-  NGFragment(NGWritingMode writing_mode,
-             const NGPhysicalFragment* physical_fragment)
-      : physical_fragment_(physical_fragment), writing_mode_(writing_mode) {}
-
   const NGPhysicalFragment* physical_fragment_;
 
   unsigned writing_mode_ : 3;
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_fragment_builder.cc b/third_party/WebKit/Source/core/layout/ng/ng_fragment_builder.cc
index 6967109..f8cc737 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_fragment_builder.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_fragment_builder.cc
@@ -73,13 +73,10 @@
       << "Only box fragments can have children";
 
   // Collect child's out of flow descendants.
-  const Vector<NGStaticPosition>& oof_positions = child->OutOfFlowPositions();
-  size_t oof_index = 0;
-  for (NGBlockNode oof_node : child->OutOfFlowDescendants()) {
-    NGStaticPosition oof_position = oof_positions[oof_index++];
-    out_of_flow_descendant_candidates_.push_back(oof_node);
-    out_of_flow_candidate_placements_.push_back(
-        OutOfFlowPlacement{child_offset, oof_position});
+  for (const NGOutOfFlowPositionedDescendant& descendant :
+       child->OutOfFlowPositionedDescendants()) {
+    oof_positioned_candidates_.push_back(
+        NGOutOfFlowPositionedCandidate{descendant, child_offset});
   }
 
   return AddChild(child->PhysicalFragment(), child_offset);
@@ -137,12 +134,15 @@
 
 NGFragmentBuilder& NGFragmentBuilder::AddOutOfFlowChildCandidate(
     NGBlockNode child,
-    NGLogicalOffset child_offset) {
-  out_of_flow_descendant_candidates_.push_back(child);
-  NGStaticPosition child_position =
-      NGStaticPosition::Create(writing_mode_, direction_, NGPhysicalOffset());
-  out_of_flow_candidate_placements_.push_back(
-      OutOfFlowPlacement{child_offset, child_position});
+    const NGLogicalOffset& child_offset) {
+  DCHECK(child);
+
+  oof_positioned_candidates_.push_back(NGOutOfFlowPositionedCandidate{
+      NGOutOfFlowPositionedDescendant{
+          child, NGStaticPosition::Create(writing_mode_, direction_,
+                                          NGPhysicalOffset())},
+      child_offset});
+
   child.SaveStaticOffsetForLegacy(child_offset);
   return *this;
 }
@@ -154,40 +154,41 @@
 }
 
 void NGFragmentBuilder::GetAndClearOutOfFlowDescendantCandidates(
-    Vector<NGBlockNode>* descendants,
-    Vector<NGStaticPosition>* descendant_positions) {
-  DCHECK(descendants->IsEmpty());
-  DCHECK(descendant_positions->IsEmpty());
+    Vector<NGOutOfFlowPositionedDescendant>* descendant_candidates) {
+  DCHECK(descendant_candidates->IsEmpty());
+
+  descendant_candidates->ReserveCapacity(oof_positioned_candidates_.size());
 
   DCHECK_GE(size_.inline_size, LayoutUnit());
   DCHECK_GE(size_.block_size, LayoutUnit());
   NGPhysicalSize builder_physical_size{size_.ConvertToPhysical(writing_mode_)};
 
-  size_t placement_index = 0;
-  for (NGBlockNode oof_node : out_of_flow_descendant_candidates_) {
-    OutOfFlowPlacement oof_placement =
-        out_of_flow_candidate_placements_[placement_index++];
-
-    NGPhysicalOffset child_offset =
-        oof_placement.child_offset.ConvertToPhysical(
-            writing_mode_, direction_, builder_physical_size, NGPhysicalSize());
+  for (NGOutOfFlowPositionedCandidate& candidate : oof_positioned_candidates_) {
+    NGPhysicalOffset child_offset = candidate.child_offset.ConvertToPhysical(
+        writing_mode_, direction_, builder_physical_size, NGPhysicalSize());
 
     NGStaticPosition builder_relative_position;
-    builder_relative_position.type = oof_placement.descendant_position.type;
+    builder_relative_position.type = candidate.descendant.static_position.type;
     builder_relative_position.offset =
-        child_offset + oof_placement.descendant_position.offset;
-    descendants->push_back(oof_node);
-    descendant_positions->push_back(builder_relative_position);
+        child_offset + candidate.descendant.static_position.offset;
+
+    descendant_candidates->push_back(NGOutOfFlowPositionedDescendant{
+        candidate.descendant.node, builder_relative_position});
   }
-  out_of_flow_descendant_candidates_.clear();
-  out_of_flow_candidate_placements_.clear();
+
+  // Clear our current canidate list. This may get modified again if the
+  // current fragment is a containing block, and AddChild is called with a
+  // descendant from this list.
+  //
+  // The descendant may be a "position: absolute" which contains a "position:
+  // fixed" for example. (This fragment isn't the containing block for the
+  // fixed descendant).
+  oof_positioned_candidates_.clear();
 }
 
 NGFragmentBuilder& NGFragmentBuilder::AddOutOfFlowDescendant(
-    NGBlockNode descendant,
-    const NGStaticPosition& position) {
-  out_of_flow_descendants_.push_back(descendant);
-  out_of_flow_positions_.push_back(position);
+    NGOutOfFlowPositionedDescendant descendant) {
+  oof_positioned_descendants_.push_back(descendant);
   return *this;
 }
 
@@ -228,12 +229,12 @@
 
   RefPtr<NGPhysicalBoxFragment> fragment = AdoptRef(new NGPhysicalBoxFragment(
       layout_object_, physical_size, overflow_.ConvertToPhysical(writing_mode_),
-      children_, positioned_floats_, bfc_offset_, end_margin_strut_,
-      border_edges_.ToPhysical(writing_mode_), std::move(break_token)));
+      children_, positioned_floats_, border_edges_.ToPhysical(writing_mode_),
+      std::move(break_token)));
 
   return AdoptRef(
-      new NGLayoutResult(std::move(fragment), out_of_flow_descendants_,
-                         out_of_flow_positions_, unpositioned_floats_));
+      new NGLayoutResult(std::move(fragment), oof_positioned_descendants_,
+                         unpositioned_floats_, bfc_offset_, end_margin_strut_));
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_fragment_builder.h b/third_party/WebKit/Source/core/layout/ng/ng_fragment_builder.h
index d54b264b..5ea8559 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_fragment_builder.h
+++ b/third_party/WebKit/Source/core/layout/ng/ng_fragment_builder.h
@@ -9,6 +9,7 @@
 #include "core/layout/ng/inline/ng_physical_text_fragment.h"
 #include "core/layout/ng/ng_break_token.h"
 #include "core/layout/ng/ng_constraint_space.h"
+#include "core/layout/ng/ng_out_of_flow_positioned_descendant.h"
 #include "core/layout/ng/ng_physical_fragment.h"
 #include "core/layout/ng/ng_positioned_float.h"
 #include "core/layout/ng/ng_unpositioned_float.h"
@@ -76,13 +77,13 @@
   // NGOutOfFlowLayoutPart(container_style, builder).Run();
   //
   // See layout part for builder interaction.
-  NGFragmentBuilder& AddOutOfFlowChildCandidate(NGBlockNode, NGLogicalOffset);
+  NGFragmentBuilder& AddOutOfFlowChildCandidate(NGBlockNode,
+                                                const NGLogicalOffset&);
 
-  void GetAndClearOutOfFlowDescendantCandidates(Vector<NGBlockNode>*,
-                                                Vector<NGStaticPosition>*);
+  void GetAndClearOutOfFlowDescendantCandidates(
+      Vector<NGOutOfFlowPositionedDescendant>* descendant_candidates);
 
-  NGFragmentBuilder& AddOutOfFlowDescendant(NGBlockNode,
-                                            const NGStaticPosition&);
+  NGFragmentBuilder& AddOutOfFlowDescendant(NGOutOfFlowPositionedDescendant);
 
   // Sets how much of the block size we've used so far for this box.
   //
@@ -135,22 +136,24 @@
   }
 
  private:
-  // Out-of-flow descendant placement information.
-  // The generated fragment must compute NGStaticPosition for all
-  // out-of-flow descendants.
-  // The resulting NGStaticPosition gets derived from:
-  // 1. The offset of fragment's child.
-  // 2. The static position of descendant wrt child.
+  // An out-of-flow positioned-candidate is a temporary data structure used
+  // within the NGFragmentBuilder.
   //
-  // A child can be:
-  // 1. A descendant itself. In this case, descendant position is (0,0).
-  // 2. A fragment containing a descendant.
+  // A positioned-candidate can be:
+  // 1. A direct out-of-flow positioned child. The child_offset is (0,0).
+  // 2. A fragment containing an out-of-flow positioned-descendant. The
+  //    child_offset in this case is the containing fragment's offset.
   //
-  // child_offset is stored as NGLogicalOffset because physical offset cannot
-  // be computed until we know fragment's size.
-  struct OutOfFlowPlacement {
+  // The child_offset is stored as a NGLogicalOffset as the physical offset
+  // cannot be computed until we know the current fragment's size.
+  //
+  // When returning the positioned-candidates (from
+  // GetAndClearOutOfFlowDescendantCandidates), the NGFragmentBuilder will
+  // convert the positioned-candidate to a positioned-descendant using the
+  // physical size the fragment builder.
+  struct NGOutOfFlowPositionedCandidate {
+    NGOutOfFlowPositionedDescendant descendant;
     NGLogicalOffset child_offset;
-    NGStaticPosition descendant_position;
   };
 
   NGPhysicalFragment::NGFragmentType type_;
@@ -172,11 +175,8 @@
   Vector<RefPtr<NGBreakToken>> child_break_tokens_;
   RefPtr<NGBreakToken> last_inline_break_token_;
 
-  Vector<NGBlockNode> out_of_flow_descendant_candidates_;
-  Vector<OutOfFlowPlacement> out_of_flow_candidate_placements_;
-
-  Vector<NGBlockNode> out_of_flow_descendants_;
-  Vector<NGStaticPosition> out_of_flow_positions_;
+  Vector<NGOutOfFlowPositionedCandidate> oof_positioned_candidates_;
+  Vector<NGOutOfFlowPositionedDescendant> oof_positioned_descendants_;
 
   // Floats that need to be positioned by the next in-flow fragment that can
   // determine its block position in space.
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_layout_result.cc b/third_party/WebKit/Source/core/layout/ng/ng_layout_result.cc
index cc11684..35779bcf 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_layout_result.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_layout_result.cc
@@ -8,13 +8,15 @@
 
 NGLayoutResult::NGLayoutResult(
     PassRefPtr<NGPhysicalFragment> physical_fragment,
-    Vector<NGBlockNode>& out_of_flow_descendants,
-    Vector<NGStaticPosition> out_of_flow_positions,
-    Vector<RefPtr<NGUnpositionedFloat>>& unpositioned_floats)
+    Vector<NGOutOfFlowPositionedDescendant> oof_positioned_descendants,
+    Vector<RefPtr<NGUnpositionedFloat>>& unpositioned_floats,
+    const WTF::Optional<NGLogicalOffset> bfc_offset,
+    const NGMarginStrut end_margin_strut)
     : physical_fragment_(std::move(physical_fragment)),
-      out_of_flow_descendants_(out_of_flow_descendants),
-      out_of_flow_positions_(out_of_flow_positions) {
+      bfc_offset_(bfc_offset),
+      end_margin_strut_(end_margin_strut) {
   unpositioned_floats_.swap(unpositioned_floats);
+  oof_positioned_descendants_.swap(oof_positioned_descendants);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_layout_result.h b/third_party/WebKit/Source/core/layout/ng/ng_layout_result.h
index 5604d22..017b94f 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_layout_result.h
+++ b/third_party/WebKit/Source/core/layout/ng/ng_layout_result.h
@@ -8,6 +8,7 @@
 #include "core/CoreExport.h"
 #include "core/layout/ng/geometry/ng_static_position.h"
 #include "core/layout/ng/ng_block_node.h"
+#include "core/layout/ng/ng_out_of_flow_positioned_descendant.h"
 #include "core/layout/ng/ng_physical_fragment.h"
 #include "core/layout/ng/ng_unpositioned_float.h"
 #include "platform/LayoutUnit.h"
@@ -32,12 +33,9 @@
     return physical_fragment_;
   }
 
-  const Vector<NGBlockNode>& OutOfFlowDescendants() const {
-    return out_of_flow_descendants_;
-  }
-
-  const Vector<NGStaticPosition>& OutOfFlowPositions() const {
-    return out_of_flow_positions_;
+  const Vector<NGOutOfFlowPositionedDescendant> OutOfFlowPositionedDescendants()
+      const {
+    return oof_positioned_descendants_;
   }
 
   // List of floats that need to be positioned by the next in-flow child that
@@ -52,18 +50,28 @@
     return unpositioned_floats_;
   }
 
+  const WTF::Optional<NGLogicalOffset>& BfcOffset() const {
+    return bfc_offset_;
+  }
+
+  const NGMarginStrut EndMarginStrut() const { return end_margin_strut_; }
+
  private:
   friend class NGFragmentBuilder;
 
   NGLayoutResult(PassRefPtr<NGPhysicalFragment> physical_fragment,
-                 Vector<NGBlockNode>& out_of_flow_descendants,
-                 Vector<NGStaticPosition> out_of_flow_positions,
-                 Vector<RefPtr<NGUnpositionedFloat>>& unpositioned_floats);
+                 Vector<NGOutOfFlowPositionedDescendant>
+                     out_of_flow_positioned_descendants,
+                 Vector<RefPtr<NGUnpositionedFloat>>& unpositioned_floats,
+                 const WTF::Optional<NGLogicalOffset> bfc_offset,
+                 const NGMarginStrut end_margin_strut);
 
   RefPtr<NGPhysicalFragment> physical_fragment_;
-  Vector<NGBlockNode> out_of_flow_descendants_;
-  Vector<NGStaticPosition> out_of_flow_positions_;
   Vector<RefPtr<NGUnpositionedFloat>> unpositioned_floats_;
+
+  Vector<NGOutOfFlowPositionedDescendant> oof_positioned_descendants_;
+  const WTF::Optional<NGLogicalOffset> bfc_offset_;
+  const NGMarginStrut end_margin_strut_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_out_of_flow_layout_part.cc b/third_party/WebKit/Source/core/layout/ng/ng_out_of_flow_layout_part.cc
index 368e872..21e540fa 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_out_of_flow_layout_part.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_out_of_flow_layout_part.cc
@@ -65,35 +65,28 @@
 }
 
 void NGOutOfFlowLayoutPart::Run() {
-  Vector<NGBlockNode> out_of_flow_candidates;
-  Vector<NGStaticPosition> out_of_flow_candidate_positions;
+  Vector<NGOutOfFlowPositionedDescendant> descendant_candidates;
   container_builder_->GetAndClearOutOfFlowDescendantCandidates(
-      &out_of_flow_candidates, &out_of_flow_candidate_positions);
+      &descendant_candidates);
 
-  while (out_of_flow_candidates.size() > 0) {
-    size_t position_index = 0;
-
-    for (auto& descendant : out_of_flow_candidates) {
-      NGStaticPosition static_position =
-          out_of_flow_candidate_positions[position_index++];
-
+  while (descendant_candidates.size() > 0) {
+    for (auto& candidate : descendant_candidates) {
       if (IsContainingBlockForAbsoluteDescendant(container_style_,
-                                                 descendant.Style())) {
+                                                 candidate.node.Style())) {
         NGLogicalOffset offset;
-        RefPtr<NGLayoutResult> result =
-            LayoutDescendant(descendant, static_position, &offset);
+        RefPtr<NGLayoutResult> result = LayoutDescendant(
+            candidate.node, candidate.static_position, &offset);
         // TODO(atotic) Need to adjust size of overflow rect per spec.
         container_builder_->AddChild(std::move(result), offset);
       } else {
-        container_builder_->AddOutOfFlowDescendant(descendant, static_position);
+        container_builder_->AddOutOfFlowDescendant(candidate);
       }
     }
     // Sweep any descendants that might have been added.
     // This happens when an absolute container has a fixed child.
-    out_of_flow_candidates.clear();
-    out_of_flow_candidate_positions.clear();
+    descendant_candidates.clear();
     container_builder_->GetAndClearOutOfFlowDescendantCandidates(
-        &out_of_flow_candidates, &out_of_flow_candidate_positions);
+        &descendant_candidates);
   }
 }
 
@@ -101,6 +94,8 @@
     NGBlockNode descendant,
     NGStaticPosition static_position,
     NGLogicalOffset* offset) {
+  DCHECK(descendant);
+
   // Adjust the static_position origin. The static_position coordinate origin is
   // relative to the container's border box, ng_absolute_utils expects it to be
   // relative to the container's padding box.
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_out_of_flow_layout_part_test.cc b/third_party/WebKit/Source/core/layout/ng/ng_out_of_flow_layout_part_test.cc
index 37bb93d..2aadabcaa2 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_out_of_flow_layout_part_test.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_out_of_flow_layout_part_test.cc
@@ -69,7 +69,7 @@
       NGConstraintSpace::CreateFromLayoutObject(*block_flow);
   NGBlockNode node(block_flow);
   RefPtr<NGLayoutResult> result = node.Layout(space.Get());
-  EXPECT_EQ(result->OutOfFlowDescendants().size(), (size_t)2);
+  EXPECT_EQ(result->OutOfFlowPositionedDescendants().size(), (size_t)2);
 
   // Test the final result.
   Element* fixed_1 = GetDocument().getElementById("fixed1");
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_out_of_flow_positioned_descendant.h b/third_party/WebKit/Source/core/layout/ng/ng_out_of_flow_positioned_descendant.h
new file mode 100644
index 0000000..ae1de47d
--- /dev/null
+++ b/third_party/WebKit/Source/core/layout/ng/ng_out_of_flow_positioned_descendant.h
@@ -0,0 +1,32 @@
+// 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 NGOutOfFlowPositionedDescendant_h
+#define NGOutOfFlowPositionedDescendant_h
+
+#include "core/CoreExport.h"
+
+#include "core/layout/ng/geometry/ng_static_position.h"
+#include "core/layout/ng/ng_block_node.h"
+
+namespace blink {
+
+// An out-of-flow positioned-descendant is an element with the style "postion:
+// absolute" or "position: fixed" which hasn't been bubbled up to its
+// containing block yet, e.g. an element with "position: relative". As soon as
+// a descendant reaches its containing block, it gets placed, and doesn't bubble
+// up the tree.
+//
+// This needs its static position [1] to be placed correcting in its containing
+// block.
+//
+// [1] https://www.w3.org/TR/CSS2/visudet.html#abs-non-replaced-width
+struct CORE_EXPORT NGOutOfFlowPositionedDescendant {
+  NGBlockNode node;
+  NGStaticPosition static_position;
+};
+
+}  // namespace blink
+
+#endif  // NGOutOfFlowPositionedDescendant_h
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_physical_box_fragment.cc b/third_party/WebKit/Source/core/layout/ng/ng_physical_box_fragment.cc
index d21294d4..6146b2f 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_physical_box_fragment.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_physical_box_fragment.cc
@@ -14,8 +14,6 @@
     NGPhysicalSize overflow,
     Vector<RefPtr<NGPhysicalFragment>>& children,
     Vector<NGPositionedFloat>& positioned_floats,
-    const WTF::Optional<NGLogicalOffset>& bfc_offset,
-    const NGMarginStrut& end_margin_strut,
     unsigned border_edges,  // NGBorderEdges::Physical
     RefPtr<NGBreakToken> break_token)
     : NGPhysicalFragment(layout_object,
@@ -23,9 +21,7 @@
                          kFragmentBox,
                          std::move(break_token)),
       overflow_(overflow),
-      positioned_floats_(positioned_floats),
-      bfc_offset_(bfc_offset),
-      end_margin_strut_(end_margin_strut) {
+      positioned_floats_(positioned_floats) {
   children_.swap(children);
   border_edge_ = border_edges;
 }
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_physical_box_fragment.h b/third_party/WebKit/Source/core/layout/ng/ng_physical_box_fragment.h
index 176c96d..7e1ec6a 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_physical_box_fragment.h
+++ b/third_party/WebKit/Source/core/layout/ng/ng_physical_box_fragment.h
@@ -22,8 +22,6 @@
                         NGPhysicalSize overflow,
                         Vector<RefPtr<NGPhysicalFragment>>& children,
                         Vector<NGPositionedFloat>& positioned_floats,
-                        const WTF::Optional<NGLogicalOffset>& bfc_offset,
-                        const NGMarginStrut& end_margin_strut,
                         unsigned,  // NGBorderEdges::Physical
                         RefPtr<NGBreakToken> break_token = nullptr);
 
@@ -41,18 +39,10 @@
     return positioned_floats_;
   }
 
-  const WTF::Optional<NGLogicalOffset>& BfcOffset() const {
-    return bfc_offset_;
-  }
-
-  const NGMarginStrut& EndMarginStrut() const { return end_margin_strut_; }
-
  private:
   NGPhysicalSize overflow_;
   Vector<RefPtr<NGPhysicalFragment>> children_;
   Vector<NGPositionedFloat> positioned_floats_;
-  const WTF::Optional<NGLogicalOffset> bfc_offset_;
-  const NGMarginStrut end_margin_strut_;
 };
 
 DEFINE_TYPE_CASTS(NGPhysicalBoxFragment,
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_space_utils.cc b/third_party/WebKit/Source/core/layout/ng/ng_space_utils.cc
index 7d11bc2..27ed337 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_space_utils.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_space_utils.cc
@@ -24,46 +24,8 @@
   return value2;
 }
 
-bool IsOutOfFlowPositioned(const EPosition& position) {
-  return position == EPosition::kAbsolute || position == EPosition::kFixed;
-}
-
 }  // namespace
 
-bool IsNewFormattingContextForBlockLevelChild(const ComputedStyle& parent_style,
-                                              const NGLayoutInputNode& node) {
-  // TODO(layout-dev): This doesn't capture a few cases which can't be computed
-  // directly from style yet:
-  //  - The child is a <fieldset>.
-  //  - "column-span: all" is set on the child (requires knowledge that we are
-  //    in a multi-col formatting context).
-  //    (https://drafts.csswg.org/css-multicol-1/#valdef-column-span-all)
-
-  if (node.IsInline())
-    return false;
-
-  const ComputedStyle& style = node.Style();
-  if (style.IsFloating() || IsOutOfFlowPositioned(style.GetPosition()))
-    return true;
-
-  if (style.SpecifiesColumns() || style.ContainsPaint() ||
-      style.ContainsLayout())
-    return true;
-
-  if (!style.IsOverflowVisible())
-    return true;
-
-  EDisplay display = style.Display();
-  if (display == EDisplay::kGrid || display == EDisplay::kFlex ||
-      display == EDisplay::kWebkitBox)
-    return true;
-
-  if (parent_style.GetWritingMode() != style.GetWritingMode())
-    return true;
-
-  return false;
-}
-
 WTF::Optional<LayoutUnit> GetClearanceOffset(
     const std::shared_ptr<NGExclusions>& exclusions,
     EClear clear_type) {
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_space_utils.h b/third_party/WebKit/Source/core/layout/ng/ng_space_utils.h
index ee5cf74..579141cf 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_space_utils.h
+++ b/third_party/WebKit/Source/core/layout/ng/ng_space_utils.h
@@ -14,19 +14,8 @@
 
 class ComputedStyle;
 struct NGExclusions;
-class NGLayoutInputNode;
 struct NGLogicalOffset;
 
-// Whether an in-flow child creates a new formatting context.
-//
-// This will *NOT* check the following cases:
-//  - The child is a inline-level, e.g. "display: inline-block".
-//  - The child establishes a new formatting context, but should be a child of
-//    another layout algorithm, e.g. "display: table-caption" or flex-item.
-CORE_EXPORT bool IsNewFormattingContextForBlockLevelChild(
-    const ComputedStyle& parent_style,
-    const NGLayoutInputNode& node);
-
 // Gets the clearance offset based on the provided {@code clear_type} and list
 // of exclusions that represent left/right float.
 CORE_EXPORT WTF::Optional<LayoutUnit> GetClearanceOffset(
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_space_utils_test.cc b/third_party/WebKit/Source/core/layout/ng/ng_space_utils_test.cc
deleted file mode 100644
index db65ad436..0000000
--- a/third_party/WebKit/Source/core/layout/ng/ng_space_utils_test.cc
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "core/layout/ng/ng_space_utils.h"
-
-#include "core/layout/ng/ng_base_layout_algorithm_test.h"
-#include "core/layout/ng/ng_block_node.h"
-#include "core/style/ComputedStyle.h"
-
-namespace blink {
-namespace {
-
-class NGSpaceUtilsTest : public NGBaseLayoutAlgorithmTest {};
-
-// Verifies that IsNewFormattingContextForInFlowBlockLevelChild returnes true
-// if the child is out-of-flow, e.g. floating or abs-pos.
-TEST_F(NGSpaceUtilsTest, NewFormattingContextForOutOfFlowChild) {
-  SetBodyInnerHTML(R"HTML(
-    <!DOCTYPE html>
-    <div id="parent">
-      <div id="child"></div>
-    </div>
-  )HTML");
-
-  auto& parent_style = GetLayoutObjectByElementId("parent")->StyleRef();
-  auto* child = GetLayoutObjectByElementId("child");
-  NGBlockNode node(ToLayoutBox(child));
-
-  auto run_test = [&](RefPtr<ComputedStyle> style) {
-    child->SetStyle(style);
-    EXPECT_TRUE(IsNewFormattingContextForBlockLevelChild(parent_style, node));
-  };
-
-  RefPtr<ComputedStyle> style = ComputedStyle::Create();
-  style->SetFloating(EFloat::kLeft);
-  run_test(style);
-
-  style = ComputedStyle::Create();
-  style->SetPosition(EPosition::kAbsolute);
-  run_test(style);
-
-  style = ComputedStyle::Create();
-  style->SetPosition(EPosition::kFixed);
-  run_test(style);
-}
-
-}  // namespace
-}  // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/shapes/ShapeOutsideInfo.cpp b/third_party/WebKit/Source/core/layout/shapes/ShapeOutsideInfo.cpp
index 2cf99987..914cc9cd 100644
--- a/third_party/WebKit/Source/core/layout/shapes/ShapeOutsideInfo.cpp
+++ b/third_party/WebKit/Source/core/layout/shapes/ShapeOutsideInfo.cpp
@@ -116,11 +116,10 @@
 static LayoutRect GetShapeImageMarginRect(
     const LayoutBox& layout_box,
     const LayoutSize& reference_box_logical_size) {
-  LayoutPoint margin_box_origin(-layout_box.MarginLogicalLeft() -
-                                    layout_box.BorderAndPaddingLogicalLeft(),
-                                -layout_box.MarginBefore() -
-                                    layout_box.BorderBefore() -
-                                    layout_box.PaddingBefore());
+  LayoutPoint margin_box_origin(
+      -layout_box.MarginLineLeft() - layout_box.BorderAndPaddingLogicalLeft(),
+      -layout_box.MarginBefore() - layout_box.BorderBefore() -
+          layout_box.PaddingBefore());
   LayoutSize margin_box_size_delta(
       layout_box.MarginLogicalWidth() +
           layout_box.BorderAndPaddingLogicalWidth(),
diff --git a/third_party/WebKit/Source/core/loader/PingLoader.cpp b/third_party/WebKit/Source/core/loader/PingLoader.cpp
index c95e703..58d4552 100644
--- a/third_party/WebKit/Source/core/loader/PingLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/PingLoader.cpp
@@ -481,6 +481,9 @@
   beacon.Serialize(request);
   FetchParameters params(request);
   params.MutableOptions().initiator_info.name = FetchInitiatorTypeNames::beacon;
+  params.SetCrossOriginAccessControl(
+      frame->GetDocument()->GetSecurityOrigin(),
+      WebURLRequest::kFetchCredentialsModeInclude);
 
   Resource* resource =
       RawResource::Fetch(params, frame->GetDocument()->Fetcher());
diff --git a/third_party/WebKit/Source/core/page/ChromeClient.h b/third_party/WebKit/Source/core/page/ChromeClient.h
index 10a72ce4..04d2392 100644
--- a/third_party/WebKit/Source/core/page/ChromeClient.h
+++ b/third_party/WebKit/Source/core/page/ChromeClient.h
@@ -39,6 +39,7 @@
 #include "platform/graphics/TouchAction.h"
 #include "platform/heap/Handle.h"
 #include "platform/scroll/ScrollTypes.h"
+#include "platform/text/TextDirection.h"
 #include "platform/wtf/Forward.h"
 #include "platform/wtf/Optional.h"
 #include "platform/wtf/Vector.h"
diff --git a/third_party/WebKit/Source/core/page/SpatialNavigation.cpp b/third_party/WebKit/Source/core/page/SpatialNavigation.cpp
index cd94dd90..b62702a 100644
--- a/third_party/WebKit/Source/core/page/SpatialNavigation.cpp
+++ b/third_party/WebKit/Source/core/page/SpatialNavigation.cpp
@@ -632,8 +632,15 @@
   DCHECK(candidate.visible_node);
   DCHECK(candidate.is_offscreen);
   LayoutRect candidate_rect = candidate.rect;
+  // TODO(ecobos@igalia.com): Investigate interaction with Shadow DOM.
   for (Node& parent_node :
        NodeTraversal::AncestorsOf(*candidate.visible_node)) {
+    if (UNLIKELY(!parent_node.GetLayoutObject())) {
+      DCHECK(parent_node.IsElementNode() &&
+             ToElement(parent_node).HasDisplayContentsStyle());
+      continue;
+    }
+
     LayoutRect parent_rect = NodeRectInAbsoluteCoordinates(&parent_node);
     if (!candidate_rect.Intersects(parent_rect)) {
       if (((type == kWebFocusTypeLeft || type == kWebFocusTypeRight) &&
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp
index f3ec46e9..b597984 100644
--- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp
@@ -206,7 +206,7 @@
             scroller_properties->OverflowClip()->LocalTransformSpace());
   const auto* scroll = scroller_properties->ScrollTranslation()->ScrollNode();
   EXPECT_EQ(FrameScroll(), scroll->Parent());
-  EXPECT_EQ(FloatSize(413, 317), scroll->Clip());
+  EXPECT_EQ(FloatSize(413, 317), scroll->ContainerBounds());
   EXPECT_EQ(FloatSize(660, 10200), scroll->Bounds());
   EXPECT_FALSE(scroll->UserScrollableHorizontal());
   EXPECT_TRUE(scroll->UserScrollableVertical());
@@ -2694,7 +2694,7 @@
   EXPECT_EQ(TransformationMatrix().Translate(0, -37),
             scroll_translation->Matrix());
   // This should match the overflow's dimensions.
-  EXPECT_EQ(IntSize(5, 3), overflow_hidden_scroll_node->Clip());
+  EXPECT_EQ(IntSize(5, 3), overflow_hidden_scroll_node->ContainerBounds());
   // The scrolling content's bounds should include both the overflow's
   // dimensions (5x3) and the 0x79 "forceScroll" object.
   EXPECT_EQ(IntSize(5, 79), overflow_hidden_scroll_node->Bounds());
@@ -2748,7 +2748,7 @@
   EXPECT_TRUE(overflow_a_scroll_node->Parent()->IsRoot());
   EXPECT_EQ(TransformationMatrix().Translate(0, -37),
             scroll_a_translation->Matrix());
-  EXPECT_EQ(IntSize(5, 3), overflow_a_scroll_node->Clip());
+  EXPECT_EQ(IntSize(5, 3), overflow_a_scroll_node->ContainerBounds());
   // 107 is the forceScroll element plus the height of the overflow scroll child
   // (overflowB).
   EXPECT_EQ(IntSize(9, 107), overflow_a_scroll_node->Bounds());
@@ -2765,7 +2765,7 @@
   EXPECT_EQ(overflow_a_scroll_node, overflow_b_scroll_node->Parent());
   EXPECT_EQ(TransformationMatrix().Translate(0, -41),
             scroll_b_translation->Matrix());
-  EXPECT_EQ(IntSize(9, 7), overflow_b_scroll_node->Clip());
+  EXPECT_EQ(IntSize(9, 7), overflow_b_scroll_node->ContainerBounds());
   EXPECT_EQ(IntSize(9, 100), overflow_b_scroll_node->Bounds());
   EXPECT_TRUE(overflow_b_scroll_node->UserScrollableHorizontal());
   EXPECT_TRUE(overflow_b_scroll_node->UserScrollableVertical());
@@ -2834,7 +2834,7 @@
       overflow_scroll_properties->ScrollTranslation()->ScrollNode()->Parent());
   EXPECT_EQ(TransformationMatrix().Translate(0, -37),
             scroll_translation->Matrix());
-  EXPECT_EQ(IntSize(5, 3), overflow_scroll_node->Clip());
+  EXPECT_EQ(IntSize(5, 3), overflow_scroll_node->ContainerBounds());
   // The height should be 4000px because the (dom-order) overflow children are
   // positioned and do not contribute to the height. Only the 4000px
   // "forceScroll" height is present.
@@ -2850,7 +2850,7 @@
   EXPECT_EQ(FrameScroll(), abspos_overflow_scroll_node->Parent());
   EXPECT_EQ(TransformationMatrix().Translate(0, -41),
             abspos_scroll_translation->Matrix());
-  EXPECT_EQ(IntSize(9, 7), abspos_overflow_scroll_node->Clip());
+  EXPECT_EQ(IntSize(9, 7), abspos_overflow_scroll_node->ContainerBounds());
   EXPECT_EQ(IntSize(9, 4000), abspos_overflow_scroll_node->Bounds());
 
   const ObjectPaintProperties* fixed_overflow_scroll_properties =
@@ -2863,7 +2863,7 @@
   EXPECT_TRUE(fixed_overflow_scroll_node->Parent()->IsRoot());
   EXPECT_EQ(TransformationMatrix().Translate(0, -43),
             fixed_scroll_translation->Matrix());
-  EXPECT_EQ(IntSize(13, 11), fixed_overflow_scroll_node->Clip());
+  EXPECT_EQ(IntSize(13, 11), fixed_overflow_scroll_node->ContainerBounds());
   EXPECT_EQ(IntSize(13, 4000), fixed_overflow_scroll_node->Bounds());
 }
 
@@ -2917,7 +2917,7 @@
   EXPECT_TRUE(overflow_a_scroll_node->Parent()->IsRoot());
   EXPECT_EQ(TransformationMatrix().Translate(0, -37),
             scroll_a_translation->Matrix());
-  EXPECT_EQ(IntSize(20, 20), overflow_a_scroll_node->Clip());
+  EXPECT_EQ(IntSize(20, 20), overflow_a_scroll_node->ContainerBounds());
   // 100 is the forceScroll element's height because the overflow child does not
   // contribute to the height.
   EXPECT_EQ(IntSize(20, 100), overflow_a_scroll_node->Bounds());
@@ -2934,7 +2934,7 @@
   EXPECT_EQ(overflow_a_scroll_node, overflow_b_scroll_node->Parent());
   EXPECT_EQ(TransformationMatrix().Translate(0, -41),
             scroll_b_translation->Matrix());
-  EXPECT_EQ(IntSize(5, 3), overflow_b_scroll_node->Clip());
+  EXPECT_EQ(IntSize(5, 3), overflow_b_scroll_node->ContainerBounds());
   EXPECT_EQ(IntSize(5, 100), overflow_b_scroll_node->Bounds());
   EXPECT_TRUE(overflow_b_scroll_node->UserScrollableHorizontal());
   EXPECT_TRUE(overflow_b_scroll_node->UserScrollableVertical());
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeUpdateTests.cpp b/third_party/WebKit/Source/core/paint/PaintPropertyTreeUpdateTests.cpp
index 84f90771..37a3a2c 100644
--- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeUpdateTests.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeUpdateTests.cpp
@@ -703,7 +703,7 @@
   auto* container = GetLayoutObjectByElementId("container");
   auto* scroll_node =
       container->PaintProperties()->ScrollTranslation()->ScrollNode();
-  EXPECT_EQ(IntSize(100, 100), scroll_node->Clip());
+  EXPECT_EQ(IntSize(100, 100), scroll_node->ContainerBounds());
   EXPECT_EQ(IntSize(200, 200), scroll_node->Bounds());
 
   GetDocument().getElementById("content")->setAttribute(
@@ -711,7 +711,7 @@
   GetDocument().View()->UpdateAllLifecyclePhases();
   EXPECT_EQ(scroll_node,
             container->PaintProperties()->ScrollTranslation()->ScrollNode());
-  EXPECT_EQ(IntSize(100, 100), scroll_node->Clip());
+  EXPECT_EQ(IntSize(100, 100), scroll_node->ContainerBounds());
   EXPECT_EQ(IntSize(200, 300), scroll_node->Bounds());
 }
 
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.cpp b/third_party/WebKit/Source/core/style/ComputedStyle.cpp
index 83f499c..4fa3b1d 100644
--- a/third_party/WebKit/Source/core/style/ComputedStyle.cpp
+++ b/third_party/WebKit/Source/core/style/ComputedStyle.cpp
@@ -710,10 +710,6 @@
   SetCursorDataInternal(other);
 }
 
-void ComputedStyle::SetQuotes(RefPtr<QuotesData> q) {
-  SetQuotesInternal(std::move(q));
-}
-
 bool ComputedStyle::QuotesDataEquivalent(const ComputedStyle& other) const {
   return DataEquivalent(Quotes(), other.Quotes());
 }
@@ -994,18 +990,10 @@
     transform.Translate(-origin_shift_x, -origin_shift_y);
 }
 
-void ComputedStyle::SetTextShadow(RefPtr<ShadowList> s) {
-  SetTextShadowInternal(std::move(s));
-}
-
 bool ComputedStyle::TextShadowDataEquivalent(const ComputedStyle& other) const {
   return DataEquivalent(TextShadow(), other.TextShadow());
 }
 
-void ComputedStyle::SetBoxShadow(RefPtr<ShadowList> s) {
-  SetBoxShadowInternal(std::move(s));
-}
-
 static FloatRoundedRect::Radii CalcRadiiFor(const LengthSize& top_left,
                                             const LengthSize& top_right,
                                             const LengthSize& bottom_left,
@@ -1883,10 +1871,6 @@
   }
 }
 
-void ComputedStyle::SetOffsetPath(RefPtr<BasicShape> path) {
-  SetOffsetPathInternal(std::move(path));
-}
-
 int ComputedStyle::OutlineOutsetExtent() const {
   if (!HasOutline())
     return 0;
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.h b/third_party/WebKit/Source/core/style/ComputedStyle.h
index b830c36b80..13978b9d 100644
--- a/third_party/WebKit/Source/core/style/ComputedStyle.h
+++ b/third_party/WebKit/Source/core/style/ComputedStyle.h
@@ -81,8 +81,6 @@
 class CSSVariableData;
 class Font;
 class Hyphenation;
-class RotateTransformOperation;
-class ScaleTransformOperation;
 class ShadowList;
 class ShapeValue;
 class StyleDifference;
@@ -90,7 +88,6 @@
 class StylePath;
 class StyleResolver;
 class TransformationMatrix;
-class TranslateTransformOperation;
 
 class ContentData;
 
@@ -477,9 +474,6 @@
   }
 
   // box-shadow (aka -webkit-box-shadow)
-  static ShadowList* InitialBoxShadow() { return 0; }
-  ShadowList* BoxShadow() const { return BoxShadowInternal().Get(); }
-  void SetBoxShadow(RefPtr<ShadowList>);
   bool BoxShadowDataEquivalent(const ComputedStyle& other) const {
     return DataEquivalent(BoxShadow(), other.BoxShadow());
   }
@@ -572,13 +566,6 @@
         std::min(std::numeric_limits<unsigned>::max() - 1, og));
   }
 
-  // -webkit-box-reflect
-  static StyleReflection* InitialBoxReflect() { return 0; }
-  StyleReflection* BoxReflect() const { return BoxReflectInternal().Get(); }
-  void SetBoxReflect(RefPtr<StyleReflection> reflect) {
-    SetBoxReflectInternal(std::move(reflect));
-  }
-
   // Grid properties.
   static size_t InitialGridAutoRepeatInsertionPoint() { return 0; }
   static AutoRepeatType InitialGridAutoRepeatType() {
@@ -589,11 +576,6 @@
   static GridAutoFlow InitialGridAutoFlow() { return kAutoFlowRow; }
   void SetGridAutoFlow(GridAutoFlow flow) { SetGridAutoFlowInternal(flow); }
 
-  // offset-path
-  static BasicShape* InitialOffsetPath() { return nullptr; }
-  BasicShape* OffsetPath() const { return OffsetPathInternal().Get(); }
-  void SetOffsetPath(RefPtr<BasicShape>);
-
   // opacity (aka -webkit-opacity)
   static float InitialOpacity() { return 1.0f; }
   float Opacity() const { return OpacityInternal(); }
@@ -720,32 +702,6 @@
         TransformOrigin(TransformOriginX(), TransformOriginY(), f));
   }
 
-  // Independent transform properties.
-  // translate
-  static RefPtr<TranslateTransformOperation> InitialTranslate() {
-    return nullptr;
-  }
-  TranslateTransformOperation* Translate() const {
-    return TranslateInternal().Get();
-  }
-  void SetTranslate(RefPtr<TranslateTransformOperation> v) {
-    SetTranslateInternal(std::move(v));
-  }
-
-  // rotate
-  static RefPtr<RotateTransformOperation> InitialRotate() { return nullptr; }
-  RotateTransformOperation* Rotate() const { return RotateInternal().Get(); }
-  void SetRotate(RefPtr<RotateTransformOperation> v) {
-    SetRotateInternal(std::move(v));
-  }
-
-  // scale
-  static RefPtr<ScaleTransformOperation> InitialScale() { return nullptr; }
-  ScaleTransformOperation* Scale() const { return ScaleInternal().Get(); }
-  void SetScale(RefPtr<ScaleTransformOperation> v) {
-    SetScaleInternal(std::move(v));
-  }
-
   // Scroll properties.
   // scroll-behavior
   static ScrollBehavior InitialScrollBehavior() { return kScrollBehaviorAuto; }
@@ -930,11 +886,6 @@
   void SetAppearance(ControlPart a) { SetAppearanceInternal(a); }
 
   // -webkit-clip-path
-  static ClipPathOperation* InitialClipPath() { return 0; }
-  ClipPathOperation* ClipPath() const { return ClipPathInternal().Get(); }
-  void SetClipPath(RefPtr<ClipPathOperation> operation) {
-    SetClipPathInternal(std::move(operation));
-  }
   bool ClipPathDataEquivalent(const ComputedStyle& other) const {
     return DataEquivalent(ClipPath(), other.ClipPath());
   }
@@ -991,17 +942,9 @@
   void SetListStyleImage(StyleImage*);
 
   // quotes
-  static QuotesData* InitialQuotes() { return 0; }
-  QuotesData* Quotes() const { return QuotesInternal().Get(); }
-  void SetQuotes(RefPtr<QuotesData>);
-
   bool QuotesDataEquivalent(const ComputedStyle&) const;
 
   // text-shadow
-  static ShadowList* InitialTextShadow() { return 0; }
-  ShadowList* TextShadow() const { return TextShadowInternal().Get(); }
-  void SetTextShadow(RefPtr<ShadowList>);
-
   bool TextShadowDataEquivalent(const ComputedStyle&) const;
 
   // Text emphasis properties.
diff --git a/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp b/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp
index 9771aae..6d65c66 100644
--- a/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp
+++ b/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp
@@ -1107,8 +1107,6 @@
     response_document_parser_->Detach();
     response_document_parser_ = nullptr;
   }
-
-  final_response_charset_ = String();
 }
 
 bool XMLHttpRequest::InternalAbort() {
@@ -1272,6 +1270,7 @@
                         expected_length);
 }
 
+// https://xhr.spec.whatwg.org/#the-overridemimetype()-method
 void XMLHttpRequest::overrideMimeType(const AtomicString& mime_type,
                                       ExceptionState& exception_state) {
   if (state_ == kLoading || state_ == kDone) {
@@ -1281,7 +1280,9 @@
     return;
   }
 
-  mime_type_override_ = mime_type;
+  mime_type_override_ = "application/octet-stream";
+  if (ParsedContentType(mime_type).IsValid())
+    mime_type_override_ = mime_type;
 }
 
 // https://xhr.spec.whatwg.org/#the-setrequestheader()-method
@@ -1429,6 +1430,14 @@
   return AtomicString("text/xml");
 }
 
+String XMLHttpRequest::FinalResponseCharset() const {
+  String override_response_charset =
+      ExtractCharsetFromMediaType(mime_type_override_);
+  if (!override_response_charset.IsEmpty())
+    return override_response_charset;
+  return response_.TextEncodingName();
+}
+
 void XMLHttpRequest::UpdateContentTypeAndCharset(
     const AtomicString& default_content_type,
     const String& charset) {
@@ -1663,13 +1672,6 @@
   ScopedEventDispatchProtect protect(&event_dispatch_recursion_level_);
 
   response_ = response;
-  if (!mime_type_override_.IsEmpty()) {
-    response_.SetHTTPHeaderField(HTTPNames::Content_Type, mime_type_override_);
-    final_response_charset_ = ExtractCharsetFromMediaType(mime_type_override_);
-  }
-
-  if (final_response_charset_.IsEmpty())
-    final_response_charset_ = response.TextEncodingName();
 }
 
 void XMLHttpRequest::ParseDocumentChunk(const char* data, unsigned len) {
@@ -1697,10 +1699,11 @@
         TextResourceDecoderOptions::kPlainTextContent, UTF8Encoding()));
   }
 
-  if (!final_response_charset_.IsEmpty()) {
+  String final_response_charset = FinalResponseCharset();
+  if (!final_response_charset.IsEmpty()) {
     return TextResourceDecoder::Create(TextResourceDecoderOptions(
         TextResourceDecoderOptions::kPlainTextContent,
-        WTF::TextEncoding(final_response_charset_)));
+        WTF::TextEncoding(final_response_charset)));
   }
 
   // allow TextResourceDecoder to look inside the m_response if it's XML or HTML
diff --git a/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.h b/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.h
index b0734c1..cf581ab 100644
--- a/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.h
+++ b/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.h
@@ -206,7 +206,7 @@
 
   void EndLoading();
 
-  // Returns the MIME type part of m_mimeTypeOverride if present and
+  // Returns the MIME type part of mime_type_override_ if present and
   // successfully parsed, or returns one of the "Content-Type" header value
   // of the received response.
   //
@@ -218,6 +218,9 @@
   // The same as finalResponseMIMEType() but fallbacks to "text/xml" if
   // finalResponseMIMEType() returns an empty string.
   AtomicString FinalResponseMIMETypeWithFallback() const;
+  // Returns the "final charset" defined in
+  // https://xhr.spec.whatwg.org/#final-charset.
+  String FinalResponseCharset() const;
   bool ResponseIsXML() const;
   bool ResponseIsHTML() const;
 
@@ -300,7 +303,6 @@
   State state_;
 
   ResourceResponse response_;
-  String final_response_charset_;
 
   std::unique_ptr<TextResourceDecoder> decoder_;
 
diff --git a/third_party/WebKit/Source/devtools/front_end/color_picker/spectrum.css b/third_party/WebKit/Source/devtools/front_end/color_picker/spectrum.css
index 60a93434..12836a7 100644
--- a/third_party/WebKit/Source/devtools/front_end/color_picker/spectrum.css
+++ b/third_party/WebKit/Source/devtools/front_end/color_picker/spectrum.css
@@ -41,7 +41,7 @@
 
 .spectrum-hue, .spectrum-alpha {
     position: absolute;
-    right: 16px;
+    left: 86px;
     width: 130px;
     height: 11px;
     border-radius: 2px;
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/ApplicationPanelSidebar.js b/third_party/WebKit/Source/devtools/front_end/resources/ApplicationPanelSidebar.js
index ec93484..f40b0a6 100644
--- a/third_party/WebKit/Source/devtools/front_end/resources/ApplicationPanelSidebar.js
+++ b/third_party/WebKit/Source/devtools/front_end/resources/ApplicationPanelSidebar.js
@@ -378,30 +378,12 @@
    * @param {!SDK.Resource} resource
    * @param {number=} line
    * @param {number=} column
-   * @return {boolean}
+   * @return {!Promise}
    */
-  showResource(resource, line, column) {
+  async showResource(resource, line, column) {
     var resourceTreeElement = Resources.FrameResourceTreeElement.forResource(resource);
     if (resourceTreeElement)
-      resourceTreeElement.revealAndSelect(true);
-
-    if (typeof line === 'number') {
-      var resourceSourceFrame = this._resourceSourceFrameViewForResource(resource);
-      if (resourceSourceFrame)
-        resourceSourceFrame.revealPosition(line, column, true);
-    }
-    return true;
-  }
-
-  /**
-   * @param {!SDK.Resource} resource
-   * @return {?SourceFrame.ResourceSourceFrame}
-   */
-  _resourceSourceFrameViewForResource(resource) {
-    var resourceView = Resources.FrameResourceTreeElement.resourceViewForResource(resource);
-    if (resourceView && resourceView instanceof SourceFrame.ResourceSourceFrame)
-      return /** @type {!SourceFrame.ResourceSourceFrame} */ (resourceView);
-    return null;
+      await resourceTreeElement.revealResource(line, column);
   }
 
   /**
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/ResourcesPanel.js b/third_party/WebKit/Source/devtools/front_end/resources/ResourcesPanel.js
index 071fb43..0f78c7b4 100644
--- a/third_party/WebKit/Source/devtools/front_end/resources/ResourcesPanel.js
+++ b/third_party/WebKit/Source/devtools/front_end/resources/ResourcesPanel.js
@@ -12,6 +12,9 @@
     /** @type {?UI.Widget} */
     this.visibleView = null;
 
+    /** @type {?Promise<!UI.Widget>} */
+    this._pendingViewPromise = null;
+
     /** @type {?Resources.StorageCategoryView} */
     this._categoryView = null;
 
@@ -82,6 +85,7 @@
    * @param {?UI.Widget} view
    */
   showView(view) {
+    this._pendingViewPromise = null;
     if (this.visibleView === view)
       return;
 
@@ -100,6 +104,19 @@
   }
 
   /**
+   * @param {!Promise<!UI.Widget>} viewPromise
+   * @return {!Promise<?UI.Widget>}
+   */
+  async scheduleShowView(viewPromise) {
+    this._pendingViewPromise = viewPromise;
+    var view = await viewPromise;
+    if (this._pendingViewPromise !== viewPromise)
+      return null;
+    this.showView(view);
+    return view;
+  }
+
+  /**
    * @param {string} categoryName
    */
   showCategoryView(categoryName) {
@@ -173,10 +190,11 @@
    * @param {!Object} resource
    * @return {!Promise}
    */
-  reveal(resource) {
+  async reveal(resource) {
     if (!(resource instanceof SDK.Resource))
       return Promise.reject(new Error('Internal error: not a resource'));
-    var panel = Resources.ResourcesPanel._instance()._sidebar;
-    return UI.viewManager.showView('resources').then(panel.showResource.bind(panel, resource));
+    var sidebar = Resources.ResourcesPanel._instance()._sidebar;
+    await UI.viewManager.showView('resources');
+    await sidebar.showResource(resource);
   }
 };
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/ResourcesSection.js b/third_party/WebKit/Source/devtools/front_end/resources/ResourcesSection.js
index 2ffe0362..4e66f5697 100644
--- a/third_party/WebKit/Source/devtools/front_end/resources/ResourcesSection.js
+++ b/third_party/WebKit/Source/devtools/front_end/resources/ResourcesSection.js
@@ -247,8 +247,8 @@
     this._panel = storagePanel;
     /** @type {!SDK.Resource} */
     this._resource = resource;
-    /** @type {?SourceFrame.ResourceSourceFrame} */
-    this._sourceFrame = null;
+    /** @type {?Promise<!UI.Widget>} */
+    this._previewPromise = null;
     this.tooltip = resource.url;
     this._resource[Resources.FrameResourceTreeElement._symbol] = this;
 
@@ -265,39 +265,32 @@
     return resource[Resources.FrameResourceTreeElement._symbol];
   }
 
-  /**
-   * @param {!SDK.Resource} resource
-   * @return {?UI.Widget}
-   */
-  static resourceViewForResource(resource) {
-    if (resource.hasTextContent()) {
-      var treeElement = Resources.FrameResourceTreeElement.forResource(resource);
-      if (!treeElement)
-        return null;
-      return treeElement._sourceView();
-    }
-
-    switch (resource.resourceType()) {
-      case Common.resourceTypes.Image:
-        return new SourceFrame.ImageView(resource.mimeType, resource);
-      case Common.resourceTypes.Font:
-        return new SourceFrame.FontView(resource.mimeType, resource);
-      default:
-        return new UI.EmptyWidget(resource.url);
-    }
-  }
-
   get itemURL() {
     return this._resource.url;
   }
 
   /**
+   * @return {!Promise<!UI.Widget>}
+   */
+  _preparePreview() {
+    if (this._previewPromise)
+      return this._previewPromise;
+    var viewPromise = SourceFrame.PreviewFactory.createPreview(this._resource, this._resource.mimeType);
+    this._previewPromise = viewPromise.then(view => {
+      if (view)
+        return view;
+      return new UI.EmptyWidget(this._resource.url);
+    });
+    return this._previewPromise;
+  }
+
+  /**
    * @override
    * @return {boolean}
    */
   onselect(selectedByUser) {
     super.onselect(selectedByUser);
-    this.showView(Resources.FrameResourceTreeElement.resourceViewForResource(this._resource));
+    this._panel.scheduleShowView(this._preparePreview());
     return false;
   }
 
@@ -337,14 +330,15 @@
   }
 
   /**
-   * @return {!SourceFrame.ResourceSourceFrame}
+   * @param {number=} line
+   * @param {number=} column
    */
-  _sourceView() {
-    if (!this._sourceFrame) {
-      this._sourceFrame = new SourceFrame.ResourceSourceFrame(this._resource);
-      this._sourceFrame.setHighlighterType(this._resource.canonicalMimeType());
-    }
-    return this._sourceFrame;
+  async revealResource(line, column) {
+    this.revealAndSelect(true);
+    var view = await this._panel.scheduleShowView(this._preparePreview());
+    if (!(view instanceof SourceFrame.ResourceSourceFrame) || typeof line !== 'number')
+      return;
+    view.revealPosition(line, column, true);
   }
 };
 
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/NetworkRequest.js b/third_party/WebKit/Source/devtools/front_end/sdk/NetworkRequest.js
index 88dcbc3..42768af 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/NetworkRequest.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/NetworkRequest.js
@@ -73,9 +73,8 @@
 
     /** @type {!Common.ResourceType} */
     this._resourceType = Common.resourceTypes.Other;
-    // TODO(allada) Migrate everything away from this and remove it.
-    this._contentEncoded = false;
-    this._pendingContentCallbacks = [];
+    /** @type {?Promise<!SDK.NetworkRequest.ContentData>} */
+    this._contentData = null;
     /** @type {!Array.<!SDK.NetworkRequest.WebSocketFrame>} */
     this._frames = [];
     /** @type {!Array.<!SDK.NetworkRequest.EventSourceMessage>} */
@@ -862,30 +861,6 @@
     return values.join(', ');
   }
 
-  // TODO(allada) Migrate everything away from using this function and use .contentData() instead.
-  /**
-   * @return {?string|undefined}
-   */
-  get content() {
-    return this._content;
-  }
-
-  // TODO(allada) Migrate everything away from using this function and use .contentData() instead.
-  /**
-   * @return {?Protocol.Error|undefined}
-   */
-  contentError() {
-    return this._contentError;
-  }
-
-  // TODO(allada) Migrate everything away from using this function and use .contentData() instead.
-  /**
-   * @return {boolean}
-   */
-  get contentEncoded() {
-    return this._contentEncoded;
-  }
-
   /**
    * @return {!Promise<!SDK.NetworkRequest.ContentData>}
    */
@@ -917,12 +892,7 @@
    * @return {!Promise<?string>}
    */
   async requestContent() {
-    var contentData = await this.contentData();
-    // TODO(allada) Migrate away from anyone using .content, .contentError and .contentEncoded.
-    this._content = contentData.content;
-    this._contentError = contentData.error;
-    this._contentEncoded = contentData.encoded;
-    return contentData.content;
+    return (await this.contentData()).content;
   }
 
   /**
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/TargetManager.js b/third_party/WebKit/Source/devtools/front_end/sdk/TargetManager.js
index 2275b75..f8c7e9e 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/TargetManager.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/TargetManager.js
@@ -490,9 +490,29 @@
     if (targetInfo.type !== 'node')
       return;
     if (Runtime.queryParam('nodeFrontend')) {
-      this._targetAgent.attachToTarget(targetInfo.targetId);
-    } else {
-      this._targetManager._nodeTargetIds.add(targetInfo.targetId);
+      if (!targetInfo.attached)
+        this._targetAgent.attachToTarget(targetInfo.targetId);
+      return;
+    }
+    if (targetInfo.attached)
+      return;
+    this._targetManager._nodeTargetIds.add(targetInfo.targetId);
+    this._targetManager.dispatchEventToListeners(SDK.TargetManager.Events.AvailableNodeTargetsChanged);
+  }
+
+  /**
+   * @override
+   * @param {!Protocol.Target.TargetInfo} targetInfo
+   */
+  targetInfoChanged(targetInfo) {
+    if (targetInfo.type !== 'node' || Runtime.queryParam('nodeFrontend'))
+      return;
+    var availableIds = this._targetManager._nodeTargetIds;
+    if (!availableIds.has(targetInfo.targetId) && !targetInfo.attached) {
+      availableIds.add(targetInfo.targetId);
+      this._targetManager.dispatchEventToListeners(SDK.TargetManager.Events.AvailableNodeTargetsChanged);
+    } else if (availableIds.has(targetInfo.targetId) && targetInfo.attached) {
+      availableIds.delete(targetInfo.targetId);
       this._targetManager.dispatchEventToListeners(SDK.TargetManager.Events.AvailableNodeTargetsChanged);
     }
   }
diff --git a/third_party/WebKit/Source/modules/payments/PaymentRequest.cpp b/third_party/WebKit/Source/modules/payments/PaymentRequest.cpp
index 5ca48a5..cd94eb74 100644
--- a/third_party/WebKit/Source/modules/payments/PaymentRequest.cpp
+++ b/third_party/WebKit/Source/modules/payments/PaymentRequest.cpp
@@ -21,6 +21,7 @@
 #include "core/events/EventQueue.h"
 #include "core/frame/Deprecation.h"
 #include "core/frame/FrameOwner.h"
+#include "core/frame/Settings.h"
 #include "core/html/HTMLIFrameElement.h"
 #include "core/inspector/ConsoleMessage.h"
 #include "core/inspector/ConsoleTypes.h"
@@ -813,6 +814,14 @@
                                            "Cannot show the payment request"));
   }
 
+  // VR mode uses popup suppression setting to disable html select element,
+  // date pickers, etc.
+  if (GetFrame()->GetDocument()->GetSettings()->GetPagePopupsSuppressed()) {
+    return ScriptPromise::RejectWithDOMException(
+        script_state,
+        DOMException::Create(kInvalidStateError, "Page popups are suppressed"));
+  }
+
   payment_provider_->Show();
 
   show_resolver_ = ScriptPromiseResolver::Create(script_state);
diff --git a/third_party/WebKit/Source/modules/webshare/NavigatorShare.cpp b/third_party/WebKit/Source/modules/webshare/NavigatorShare.cpp
index fbec9e5..667432a 100644
--- a/third_party/WebKit/Source/modules/webshare/NavigatorShare.cpp
+++ b/third_party/WebKit/Source/modules/webshare/NavigatorShare.cpp
@@ -75,8 +75,9 @@
 }
 
 void NavigatorShare::ShareClientImpl::OnConnectionError() {
-  resolver_->Reject(
-      DOMException::Create(kSecurityError, "WebShare is disabled."));
+  resolver_->Reject(DOMException::Create(
+      kAbortError,
+      "Internal error: could not connect to Web Share interface."));
 }
 
 NavigatorShare::~NavigatorShare() = default;
diff --git a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5 b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5
index 0d45cc3..8bc92e4 100644
--- a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5
+++ b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5
@@ -461,6 +461,10 @@
       status: "experimental",
     },
     {
+      name: "FramesTimingFunction",
+      status: "experimental",
+    },
+    {
       name: "FrameTimingSupport",
       status: "experimental",
     },
@@ -495,6 +499,11 @@
       name: "HideNonceContentAttribute",
       status: "stable",
     },
+    // https://crbug.com/523952 for testing disabling the feature.
+    {
+      name: "HTMLImportsStyleApplication",
+      status: "stable",
+    },
     {
       name: "IDBObserver",
       status: "experimental",
diff --git a/third_party/WebKit/Source/platform/animation/TimingFunction.h b/third_party/WebKit/Source/platform/animation/TimingFunction.h
index 9a7a777..3cf2fa43 100644
--- a/third_party/WebKit/Source/platform/animation/TimingFunction.h
+++ b/third_party/WebKit/Source/platform/animation/TimingFunction.h
@@ -27,6 +27,7 @@
 
 #include "cc/animation/timing_function.h"
 #include "platform/PlatformExport.h"
+#include "platform/RuntimeEnabledFeatures.h"
 #include "platform/wtf/Assertions.h"
 #include "platform/wtf/PassRefPtr.h"
 #include "platform/wtf/RefCounted.h"
@@ -214,7 +215,9 @@
  private:
   FramesTimingFunction(int frames)
       : TimingFunction(Type::FRAMES),
-        frames_(cc::FramesTimingFunction::Create(frames)) {}
+        frames_(cc::FramesTimingFunction::Create(frames)) {
+    DCHECK(RuntimeEnabledFeatures::FramesTimingFunctionEnabled());
+  }
 
   std::unique_ptr<cc::FramesTimingFunction> frames_;
 };
diff --git a/third_party/WebKit/Source/platform/animation/TimingFunctionTest.cpp b/third_party/WebKit/Source/platform/animation/TimingFunctionTest.cpp
index dddd3bb0..0d93ff75 100644
--- a/third_party/WebKit/Source/platform/animation/TimingFunctionTest.cpp
+++ b/third_party/WebKit/Source/platform/animation/TimingFunctionTest.cpp
@@ -32,6 +32,7 @@
 
 #include <sstream>
 #include <string>
+#include "platform/RuntimeEnabledFeatures.h"
 #include "platform/wtf/text/WTFString.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -51,6 +52,10 @@
 
 class TimingFunctionTest : public ::testing::Test {
  public:
+  TimingFunctionTest() {
+    RuntimeEnabledFeatures::SetFramesTimingFunctionEnabled(true);
+  }
+
   void NotEqualHelperLoop(
       Vector<std::pair<std::string, RefPtr<TimingFunction>>>& v) {
     for (size_t i = 0; i < v.size(); ++i) {
diff --git a/third_party/WebKit/Source/platform/bindings/RuntimeCallStats.cpp b/third_party/WebKit/Source/platform/bindings/RuntimeCallStats.cpp
index 5f35638..8923142 100644
--- a/third_party/WebKit/Source/platform/bindings/RuntimeCallStats.cpp
+++ b/third_party/WebKit/Source/platform/bindings/RuntimeCallStats.cpp
@@ -15,6 +15,13 @@
 RuntimeCallStats* g_runtime_call_stats_for_testing = nullptr;
 }
 
+void RuntimeCallCounter::Dump(TracedValue& value) {
+  value.BeginArray(name_);
+  value.PushDouble(count_);
+  value.PushDouble(time_.InMicroseconds());
+  value.EndArray();
+}
+
 void RuntimeCallTimer::Start(RuntimeCallCounter* counter,
                              RuntimeCallTimer* parent) {
   DCHECK(!IsRunning());
@@ -38,7 +45,7 @@
 
 RuntimeCallStats::RuntimeCallStats() {
   static const char* const names[] = {
-#define COUNTER_NAME_ENTRY(name) #name,
+#define COUNTER_NAME_ENTRY(name) "Blink_" #name,
       FOR_EACH_COUNTER(COUNTER_NAME_ENTRY)
 #undef COUNTER_NAME_ENTRY
   };
@@ -61,6 +68,13 @@
   }
 }
 
+void RuntimeCallStats::Dump(TracedValue& value) {
+  for (int i = 0; i < number_of_counters_; i++) {
+    if (counters_[i].GetCount() > 0)
+      counters_[i].Dump(value);
+  }
+}
+
 String RuntimeCallStats::ToString() const {
   StringBuilder builder;
   builder.Append("Runtime Call Stats for Blink \n");
@@ -88,4 +102,23 @@
   g_runtime_call_stats_for_testing = nullptr;
 }
 
+const char* const RuntimeCallStatsScopedTracer::s_category_group_ =
+    TRACE_DISABLED_BY_DEFAULT("v8.runtime_stats");
+const char* const RuntimeCallStatsScopedTracer::s_name_ =
+    "BlinkRuntimeCallStats";
+
+void RuntimeCallStatsScopedTracer::AddBeginTraceEvent() {
+  stats_->Reset();
+  stats_->SetInUse(true);
+  TRACE_EVENT_BEGIN0(s_category_group_, s_name_);
+}
+
+void RuntimeCallStatsScopedTracer::AddEndTraceEvent() {
+  std::unique_ptr<TracedValue> value = TracedValue::Create();
+  stats_->Dump(*value);
+  stats_->SetInUse(false);
+  TRACE_EVENT_END1(s_category_group_, s_name_, "runtime-call-stats",
+                   std::move(value));
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/bindings/RuntimeCallStats.h b/third_party/WebKit/Source/platform/bindings/RuntimeCallStats.h
index 07eaeff..5a7a7d2f 100644
--- a/third_party/WebKit/Source/platform/bindings/RuntimeCallStats.h
+++ b/third_party/WebKit/Source/platform/bindings/RuntimeCallStats.h
@@ -10,6 +10,8 @@
 
 #include "platform/PlatformExport.h"
 #include "platform/RuntimeEnabledFeatures.h"
+#include "platform/instrumentation/tracing/TraceEvent.h"
+#include "platform/instrumentation/tracing/TracedValue.h"
 #include "platform/wtf/Allocator.h"
 #include "platform/wtf/Optional.h"
 #include "platform/wtf/Time.h"
@@ -38,6 +40,8 @@
     count_ = 0;
   }
 
+  void Dump(TracedValue&);
+
  private:
   RuntimeCallCounter() {}
 
@@ -219,6 +223,11 @@
   // Reset all the counters.
   void Reset();
 
+  void Dump(TracedValue&);
+
+  bool InUse() const { return in_use_; }
+  void SetInUse(bool in_use) { in_use_ = in_use; }
+
   RuntimeCallCounter* GetCounter(CounterId id) {
     return &(counters_[static_cast<uint16_t>(id)]);
   }
@@ -230,6 +239,7 @@
 
  private:
   RuntimeCallTimer* current_timer_ = nullptr;
+  bool in_use_ = false;
   RuntimeCallCounter counters_[static_cast<int>(CounterId::kNumberOfCounters)];
   static const int number_of_counters_ =
       static_cast<int>(CounterId::kNumberOfCounters);
@@ -252,6 +262,38 @@
   RuntimeCallTimer timer_;
 };
 
+class PLATFORM_EXPORT RuntimeCallStatsScopedTracer {
+ public:
+  RuntimeCallStatsScopedTracer(v8::Isolate* isolate) {
+    bool category_group_enabled;
+    TRACE_EVENT_CATEGORY_GROUP_ENABLED(s_category_group_,
+                                       &category_group_enabled);
+    if (LIKELY(!category_group_enabled ||
+               !RuntimeEnabledFeatures::BlinkRuntimeCallStatsEnabled()))
+      return;
+
+    RuntimeCallStats* stats = RuntimeCallStats::From(isolate);
+    if (!stats->InUse()) {
+      stats_ = stats;
+      AddBeginTraceEvent();
+    }
+  }
+
+  ~RuntimeCallStatsScopedTracer() {
+    if (stats_)
+      AddEndTraceEvent();
+  }
+
+ private:
+  void AddBeginTraceEvent();
+  void AddEndTraceEvent();
+
+  static const char* const s_category_group_;
+  static const char* const s_name_;
+
+  RuntimeCallStats* stats_ = nullptr;
+};
+
 }  // namespace blink
 
 #endif  // RuntimeCallStats_h
diff --git a/third_party/WebKit/Source/platform/bindings/RuntimeCallStatsTest.cpp b/third_party/WebKit/Source/platform/bindings/RuntimeCallStatsTest.cpp
index b5833229..08270a6 100644
--- a/third_party/WebKit/Source/platform/bindings/RuntimeCallStatsTest.cpp
+++ b/third_party/WebKit/Source/platform/bindings/RuntimeCallStatsTest.cpp
@@ -52,14 +52,15 @@
 
 TEST_F(RuntimeCallStatsTest, StatsCounterNameIsCorrect) {
   RuntimeCallStats stats;
-  EXPECT_STREQ("TestCounter1", stats.GetCounter(test_counter_1_id)->GetName());
+  EXPECT_STREQ("Blink_TestCounter1",
+               stats.GetCounter(test_counter_1_id)->GetName());
 }
 
 TEST_F(RuntimeCallStatsTest, TestBindingsCountersForMethods) {
   RuntimeCallStats stats;
   RuntimeCallCounter* method_counter =
       stats.GetCounter(RuntimeCallStats::CounterId::kBindingsMethodTestCounter);
-  EXPECT_STREQ("BindingsMethodTestCounter", method_counter->GetName());
+  EXPECT_STREQ("Blink_BindingsMethodTestCounter", method_counter->GetName());
 }
 
 TEST_F(RuntimeCallStatsTest, TestBindingsCountersForReadOnlyAttributes) {
@@ -67,7 +68,7 @@
   RuntimeCallCounter* getter_counter =
       stats.GetCounter(RuntimeCallStats::CounterId::
                            kBindingsReadOnlyAttributeTestCounter_Getter);
-  EXPECT_STREQ("BindingsReadOnlyAttributeTestCounter_Getter",
+  EXPECT_STREQ("Blink_BindingsReadOnlyAttributeTestCounter_Getter",
                getter_counter->GetName());
 }
 
@@ -77,9 +78,9 @@
       RuntimeCallStats::CounterId::kBindingsAttributeTestCounter_Getter);
   RuntimeCallCounter* setter_counter = stats.GetCounter(
       RuntimeCallStats::CounterId::kBindingsAttributeTestCounter_Setter);
-  EXPECT_STREQ("BindingsAttributeTestCounter_Getter",
+  EXPECT_STREQ("Blink_BindingsAttributeTestCounter_Getter",
                getter_counter->GetName());
-  EXPECT_STREQ("BindingsAttributeTestCounter_Setter",
+  EXPECT_STREQ("Blink_BindingsAttributeTestCounter_Setter",
                setter_counter->GetName());
 }
 
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShapeIterator.h b/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShapeIterator.h
index 22b2ee3..78d1c68 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShapeIterator.h
+++ b/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShapeIterator.h
@@ -57,6 +57,7 @@
     // fall back on shaping the entire run.
     shape_by_word_ = font_->CanShapeWordByWord();
 
+    // SVG sets SpacingDisabled because it handles spacing by themselves.
     if (!run.SpacingDisabled())
       spacing_.SetSpacingAndExpansion(font->GetFontDescription());
   }
diff --git a/third_party/WebKit/Source/platform/geometry/LayoutRectOutsets.cpp b/third_party/WebKit/Source/platform/geometry/LayoutRectOutsets.cpp
index d45cba62..c18fc42 100644
--- a/third_party/WebKit/Source/platform/geometry/LayoutRectOutsets.cpp
+++ b/third_party/WebKit/Source/platform/geometry/LayoutRectOutsets.cpp
@@ -35,149 +35,19 @@
 
 namespace blink {
 
-LayoutUnit LayoutRectOutsets::LogicalTop(WritingMode writing_mode) const {
-  return IsHorizontalWritingMode(writing_mode) ? top_ : left_;
-}
-
-LayoutUnit LayoutRectOutsets::LogicalBottom(WritingMode writing_mode) const {
-  return IsHorizontalWritingMode(writing_mode) ? bottom_ : right_;
-}
-
-LayoutUnit LayoutRectOutsets::LogicalLeft(WritingMode writing_mode) const {
-  return IsHorizontalWritingMode(writing_mode) ? left_ : top_;
-}
-
-LayoutUnit LayoutRectOutsets::LogicalRight(WritingMode writing_mode) const {
-  return IsHorizontalWritingMode(writing_mode) ? right_ : bottom_;
-}
-
-LayoutRectOutsets LayoutRectOutsets::LogicalOutsets(
+LayoutRectOutsets LayoutRectOutsets::LineOrientationOutsets(
     WritingMode writing_mode) const {
   if (!IsHorizontalWritingMode(writing_mode))
     return LayoutRectOutsets(left_, bottom_, right_, top_);
   return *this;
 }
 
-LayoutRectOutsets LayoutRectOutsets::LogicalOutsetsWithFlippedLines(
+LayoutRectOutsets LayoutRectOutsets::LineOrientationOutsetsWithFlippedLines(
     WritingMode writing_mode) const {
-  LayoutRectOutsets outsets = LogicalOutsets(writing_mode);
+  LayoutRectOutsets outsets = LineOrientationOutsets(writing_mode);
   if (IsFlippedLinesWritingMode(writing_mode))
     std::swap(outsets.top_, outsets.bottom_);
   return outsets;
 }
 
-LayoutUnit LayoutRectOutsets::Before(WritingMode writing_mode) const {
-  switch (writing_mode) {
-    case WritingMode::kHorizontalTb:
-      return top_;
-    case WritingMode::kVerticalLr:
-      return left_;
-    case WritingMode::kVerticalRl:
-      return right_;
-  }
-  NOTREACHED();
-  return top_;
-}
-
-LayoutUnit LayoutRectOutsets::After(WritingMode writing_mode) const {
-  switch (writing_mode) {
-    case WritingMode::kHorizontalTb:
-      return bottom_;
-    case WritingMode::kVerticalLr:
-      return right_;
-    case WritingMode::kVerticalRl:
-      return left_;
-  }
-  NOTREACHED();
-  return bottom_;
-}
-
-LayoutUnit LayoutRectOutsets::Start(WritingMode writing_mode,
-                                    TextDirection direction) const {
-  if (IsHorizontalWritingMode(writing_mode))
-    return IsLtr(direction) ? left_ : right_;
-  return IsLtr(direction) ? top_ : bottom_;
-}
-
-LayoutUnit LayoutRectOutsets::end(WritingMode writing_mode,
-                                  TextDirection direction) const {
-  if (IsHorizontalWritingMode(writing_mode))
-    return IsLtr(direction) ? right_ : left_;
-  return IsLtr(direction) ? bottom_ : top_;
-}
-
-LayoutUnit LayoutRectOutsets::Over(WritingMode writing_mode) const {
-  return IsHorizontalWritingMode(writing_mode) ? top_ : right_;
-}
-
-LayoutUnit LayoutRectOutsets::Under(WritingMode writing_mode) const {
-  return IsHorizontalWritingMode(writing_mode) ? bottom_ : left_;
-}
-
-void LayoutRectOutsets::SetBefore(WritingMode writing_mode, LayoutUnit value) {
-  switch (writing_mode) {
-    case WritingMode::kHorizontalTb:
-      top_ = value;
-      break;
-    case WritingMode::kVerticalLr:
-      left_ = value;
-      break;
-    case WritingMode::kVerticalRl:
-      right_ = value;
-      break;
-    default:
-      NOTREACHED();
-      top_ = value;
-  }
-}
-
-void LayoutRectOutsets::SetAfter(WritingMode writing_mode, LayoutUnit value) {
-  switch (writing_mode) {
-    case WritingMode::kHorizontalTb:
-      bottom_ = value;
-      break;
-    case WritingMode::kVerticalLr:
-      right_ = value;
-      break;
-    case WritingMode::kVerticalRl:
-      left_ = value;
-      break;
-    default:
-      NOTREACHED();
-      bottom_ = value;
-  }
-}
-
-void LayoutRectOutsets::SetStart(WritingMode writing_mode,
-                                 TextDirection direction,
-                                 LayoutUnit value) {
-  if (IsHorizontalWritingMode(writing_mode)) {
-    if (IsLtr(direction))
-      left_ = value;
-    else
-      right_ = value;
-  } else {
-    if (IsLtr(direction))
-      top_ = value;
-    else
-      bottom_ = value;
-  }
-}
-
-void LayoutRectOutsets::SetEnd(WritingMode writing_mode,
-                               TextDirection direction,
-                               LayoutUnit value) {
-  if (IsHorizontalWritingMode(writing_mode)) {
-    if (IsLtr(direction))
-      right_ = value;
-    else
-      left_ = value;
-  } else {
-    if (IsLtr(direction))
-      bottom_ = value;
-    else
-      top_ = value;
-  }
-}
-
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/geometry/LayoutRectOutsets.h b/third_party/WebKit/Source/platform/geometry/LayoutRectOutsets.h
index cf9d1cd..15617ee 100644
--- a/third_party/WebKit/Source/platform/geometry/LayoutRectOutsets.h
+++ b/third_party/WebKit/Source/platform/geometry/LayoutRectOutsets.h
@@ -35,7 +35,6 @@
 #include "platform/PlatformExport.h"
 #include "platform/geometry/FloatRectOutsets.h"
 #include "platform/geometry/IntRectOutsets.h"
-#include "platform/text/TextDirection.h"
 #include "platform/text/WritingMode.h"
 #include "platform/wtf/Allocator.h"
 
@@ -84,29 +83,16 @@
   void SetBottom(LayoutUnit value) { bottom_ = value; }
   void SetLeft(LayoutUnit value) { left_ = value; }
 
-  LayoutUnit LogicalTop(WritingMode) const;
-  LayoutUnit LogicalBottom(WritingMode) const;
-  LayoutUnit LogicalLeft(WritingMode) const;
-  LayoutUnit LogicalRight(WritingMode) const;
-
-  // Produces a new LayoutRectOutsets whose |top| is the |logicalTop| of this
-  // one, and so on.
-  LayoutRectOutsets LogicalOutsets(WritingMode) const;
+  // Produces a new LayoutRectOutsets in line orientation
+  // (https://www.w3.org/TR/css-writing-modes-3/#line-orientation), whose
+  // - |top| is the logical 'over',
+  // - |right| is the logical 'line right',
+  // - |bottom| is the logical 'under',
+  // - |left| is the logical 'line left'.
+  LayoutRectOutsets LineOrientationOutsets(WritingMode) const;
 
   // The same as |logicalOutsets|, but also adjusting for flipped lines.
-  LayoutRectOutsets LogicalOutsetsWithFlippedLines(WritingMode) const;
-
-  LayoutUnit Before(WritingMode) const;
-  LayoutUnit After(WritingMode) const;
-  LayoutUnit Start(WritingMode, TextDirection) const;
-  LayoutUnit end(WritingMode, TextDirection) const;
-  LayoutUnit Over(WritingMode) const;
-  LayoutUnit Under(WritingMode) const;
-
-  void SetBefore(WritingMode, LayoutUnit);
-  void SetAfter(WritingMode, LayoutUnit);
-  void SetStart(WritingMode, TextDirection, LayoutUnit);
-  void SetEnd(WritingMode, TextDirection, LayoutUnit);
+  LayoutRectOutsets LineOrientationOutsetsWithFlippedLines(WritingMode) const;
 
   bool operator==(const LayoutRectOutsets other) const {
     return Top() == other.Top() && Right() == other.Right() &&
diff --git a/third_party/WebKit/Source/platform/geometry/LayoutRectOutsetsTest.cpp b/third_party/WebKit/Source/platform/geometry/LayoutRectOutsetsTest.cpp
index d1a389a..d5da787 100644
--- a/third_party/WebKit/Source/platform/geometry/LayoutRectOutsetsTest.cpp
+++ b/third_party/WebKit/Source/platform/geometry/LayoutRectOutsetsTest.cpp
@@ -9,28 +9,31 @@
 namespace blink {
 namespace {
 
-TEST(LayoutRectOutsetsTest, LogicalOutsets_Horizontal) {
+TEST(LayoutRectOutsetsTest, LineOrientationOutsets_Horizontal) {
   LayoutRectOutsets outsets(1, 2, 3, 4);
   EXPECT_EQ(LayoutRectOutsets(1, 2, 3, 4),
-            outsets.LogicalOutsets(WritingMode::kHorizontalTb));
+            outsets.LineOrientationOutsets(WritingMode::kHorizontalTb));
 }
 
-TEST(LayoutRectOutsetsTest, LogicalOutsets_Vertical) {
+TEST(LayoutRectOutsetsTest, LineOrientationOutsets_Vertical) {
   LayoutRectOutsets outsets(1, 2, 3, 4);
   EXPECT_EQ(LayoutRectOutsets(4, 3, 2, 1),
-            outsets.LogicalOutsets(WritingMode::kVerticalLr));
+            outsets.LineOrientationOutsets(WritingMode::kVerticalLr));
   EXPECT_EQ(LayoutRectOutsets(4, 3, 2, 1),
-            outsets.LogicalOutsets(WritingMode::kVerticalRl));
+            outsets.LineOrientationOutsets(WritingMode::kVerticalRl));
 }
 
-TEST(LayoutRectOutsetsTest, LogicalOutsetsWithFlippedLines) {
+TEST(LayoutRectOutsetsTest, LineOrientationOutsetsWithFlippedLines) {
   LayoutRectOutsets outsets(1, 2, 3, 4);
   EXPECT_EQ(LayoutRectOutsets(1, 2, 3, 4),
-            outsets.LogicalOutsetsWithFlippedLines(WritingMode::kHorizontalTb));
-  EXPECT_EQ(LayoutRectOutsets(2, 3, 4, 1),
-            outsets.LogicalOutsetsWithFlippedLines(WritingMode::kVerticalLr));
-  EXPECT_EQ(LayoutRectOutsets(4, 3, 2, 1),
-            outsets.LogicalOutsetsWithFlippedLines(WritingMode::kVerticalRl));
+            outsets.LineOrientationOutsetsWithFlippedLines(
+                WritingMode::kHorizontalTb));
+  EXPECT_EQ(
+      LayoutRectOutsets(2, 3, 4, 1),
+      outsets.LineOrientationOutsetsWithFlippedLines(WritingMode::kVerticalLr));
+  EXPECT_EQ(
+      LayoutRectOutsets(4, 3, 2, 1),
+      outsets.LineOrientationOutsetsWithFlippedLines(WritingMode::kVerticalRl));
 }
 
 }  // namespace
diff --git a/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.cpp b/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.cpp
index f540f99..90b8b4db 100644
--- a/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.cpp
+++ b/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.cpp
@@ -428,7 +428,7 @@
 }
 
 void OffscreenCanvasFrameDispatcherImpl::DidReceiveCompositorFrameAck(
-    const cc::ReturnedResourceArray& resources) {
+    const WTF::Vector<cc::ReturnedResource>& resources) {
   ReclaimResources(resources);
   pending_compositor_frames_--;
   DCHECK_GE(pending_compositor_frames_, 0);
@@ -489,7 +489,7 @@
 }
 
 void OffscreenCanvasFrameDispatcherImpl::ReclaimResources(
-    const cc::ReturnedResourceArray& resources) {
+    const WTF::Vector<cc::ReturnedResource>& resources) {
   for (const auto& resource : resources) {
     auto it = resources_.find(resource.id);
 
diff --git a/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.h b/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.h
index 22281382a..013f87c 100644
--- a/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.h
+++ b/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.h
@@ -44,9 +44,10 @@
 
   // cc::mojom::blink::CompositorFrameSinkClient implementation.
   void DidReceiveCompositorFrameAck(
-      const cc::ReturnedResourceArray& resources) final;
+      const WTF::Vector<cc::ReturnedResource>& resources) final;
   void OnBeginFrame(const cc::BeginFrameArgs&) final;
-  void ReclaimResources(const cc::ReturnedResourceArray& resources) final;
+  void ReclaimResources(
+      const WTF::Vector<cc::ReturnedResource>& resources) final;
 
   // This enum is used in histogram, so it should be append-only.
   enum OffscreenCanvasCommitType {
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/PropertyTreeManager.cpp b/third_party/WebKit/Source/platform/graphics/compositing/PropertyTreeManager.cpp
index ac9a747b..944bdde 100644
--- a/third_party/WebKit/Source/platform/graphics/compositing/PropertyTreeManager.cpp
+++ b/third_party/WebKit/Source/platform/graphics/compositing/PropertyTreeManager.cpp
@@ -250,10 +250,8 @@
   cc::ScrollNode& compositor_node = *GetScrollTree().Node(id);
   compositor_node.scrollable = true;
 
-  compositor_node.scroll_clip_layer_bounds.SetSize(
-      scroll_node->Clip().Width(), scroll_node->Clip().Height());
-  compositor_node.bounds.SetSize(scroll_node->Bounds().Width(),
-                                 scroll_node->Bounds().Height());
+  compositor_node.scroll_clip_layer_bounds = scroll_node->ContainerBounds();
+  compositor_node.bounds = scroll_node->Bounds();
   compositor_node.user_scrollable_horizontal =
       scroll_node->UserScrollableHorizontal();
   compositor_node.user_scrollable_vertical =
diff --git a/third_party/WebKit/Source/platform/graphics/paint/ScrollPaintPropertyNode.cpp b/third_party/WebKit/Source/platform/graphics/paint/ScrollPaintPropertyNode.cpp
index 38a9fb6..9038b18 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/ScrollPaintPropertyNode.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/ScrollPaintPropertyNode.cpp
@@ -20,8 +20,8 @@
   StringBuilder text;
   text.Append("parent=");
   text.Append(String::Format("%p", Parent()));
-  text.Append(" clip=");
-  text.Append(clip_.ToString());
+  text.Append(" container_bounds=");
+  text.Append(container_bounds_.ToString());
   text.Append(" bounds=");
   text.Append(bounds_.ToString());
 
diff --git a/third_party/WebKit/Source/platform/graphics/paint/ScrollPaintPropertyNode.h b/third_party/WebKit/Source/platform/graphics/paint/ScrollPaintPropertyNode.h
index 71f872e..99c49c2a 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/ScrollPaintPropertyNode.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/ScrollPaintPropertyNode.h
@@ -38,20 +38,20 @@
 
   static PassRefPtr<ScrollPaintPropertyNode> Create(
       PassRefPtr<const ScrollPaintPropertyNode> parent,
-      const IntSize& clip,
+      const IntSize& container_bounds,
       const IntSize& bounds,
       bool user_scrollable_horizontal,
       bool user_scrollable_vertical,
       MainThreadScrollingReasons main_thread_scrolling_reasons,
       WebLayerScrollClient* scroll_client) {
     return AdoptRef(new ScrollPaintPropertyNode(
-        std::move(parent), clip, bounds, user_scrollable_horizontal,
+        std::move(parent), container_bounds, bounds, user_scrollable_horizontal,
         user_scrollable_vertical, main_thread_scrolling_reasons,
         scroll_client));
   }
 
   bool Update(PassRefPtr<const ScrollPaintPropertyNode> parent,
-              const IntSize& clip,
+              const IntSize& container_bounds,
               const IntSize& bounds,
               bool user_scrollable_horizontal,
               bool user_scrollable_vertical,
@@ -59,7 +59,7 @@
               WebLayerScrollClient* scroll_client) {
     bool parent_changed = PaintPropertyNode::Update(std::move(parent));
 
-    if (clip == clip_ && bounds == bounds_ &&
+    if (container_bounds == container_bounds_ && bounds == bounds_ &&
         user_scrollable_horizontal == user_scrollable_horizontal_ &&
         user_scrollable_vertical == user_scrollable_vertical_ &&
         main_thread_scrolling_reasons == main_thread_scrolling_reasons_ &&
@@ -67,7 +67,7 @@
       return parent_changed;
 
     SetChanged();
-    clip_ = clip;
+    container_bounds_ = container_bounds;
     bounds_ = bounds;
     user_scrollable_horizontal_ = user_scrollable_horizontal;
     user_scrollable_vertical_ = user_scrollable_vertical;
@@ -76,10 +76,12 @@
     return true;
   }
 
-  // The clipped area that contains the scrolled content.
-  const IntSize& Clip() const { return clip_; }
+  // The area that contains the scrolled content. For typical scrolling cases,
+  // this is the size of the clipped overflow.
+  const IntSize& ContainerBounds() const { return container_bounds_; }
 
-  // The bounds of the content that is scrolled within |clip|.
+  // The bounds of the content that is scrolled within
+  // |container_bounds|.
   const IntSize& Bounds() const { return bounds_; }
 
   bool UserScrollableHorizontal() const { return user_scrollable_horizontal_; }
@@ -110,7 +112,7 @@
   PassRefPtr<ScrollPaintPropertyNode> Clone() const {
     RefPtr<ScrollPaintPropertyNode> cloned =
         AdoptRef(new ScrollPaintPropertyNode(
-            Parent(), clip_, bounds_, user_scrollable_horizontal_,
+            Parent(), container_bounds_, bounds_, user_scrollable_horizontal_,
             user_scrollable_vertical_, main_thread_scrolling_reasons_,
             scroll_client_));
     return cloned;
@@ -119,7 +121,8 @@
   // The equality operator is used by FindPropertiesNeedingUpdate.h for checking
   // if a scroll node has changed.
   bool operator==(const ScrollPaintPropertyNode& o) const {
-    return Parent() == o.Parent() && clip_ == o.clip_ && bounds_ == o.bounds_ &&
+    return Parent() == o.Parent() && container_bounds_ == o.container_bounds_ &&
+           bounds_ == o.bounds_ &&
            user_scrollable_horizontal_ == o.user_scrollable_horizontal_ &&
            user_scrollable_vertical_ == o.user_scrollable_vertical_ &&
            main_thread_scrolling_reasons_ == o.main_thread_scrolling_reasons_ &&
@@ -134,21 +137,21 @@
  private:
   ScrollPaintPropertyNode(
       PassRefPtr<const ScrollPaintPropertyNode> parent,
-      IntSize clip,
+      IntSize container_bounds,
       IntSize bounds,
       bool user_scrollable_horizontal,
       bool user_scrollable_vertical,
       MainThreadScrollingReasons main_thread_scrolling_reasons,
       WebLayerScrollClient* scroll_client)
       : PaintPropertyNode(std::move(parent)),
-        clip_(clip),
+        container_bounds_(container_bounds),
         bounds_(bounds),
         user_scrollable_horizontal_(user_scrollable_horizontal),
         user_scrollable_vertical_(user_scrollable_vertical),
         main_thread_scrolling_reasons_(main_thread_scrolling_reasons),
         scroll_client_(scroll_client) {}
 
-  IntSize clip_;
+  IntSize container_bounds_;
   IntSize bounds_;
   bool user_scrollable_horizontal_ : 1;
   bool user_scrollable_vertical_ : 1;
diff --git a/third_party/WebKit/Source/platform/graphics/paint/TransformPaintPropertyNode.h b/third_party/WebKit/Source/platform/graphics/paint/TransformPaintPropertyNode.h
index a88fd62d..a8d0393 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/TransformPaintPropertyNode.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/TransformPaintPropertyNode.h
@@ -58,7 +58,7 @@
       CompositingReasons direct_compositing_reasons,
       const CompositorElementId& compositor_element_id,
       PassRefPtr<const ScrollPaintPropertyNode> parent_scroll,
-      const IntSize& clip,
+      const IntSize& scroll_container_bounds,
       const IntSize& bounds,
       bool user_scrollable_horizontal,
       bool user_scrollable_vertical,
@@ -70,9 +70,9 @@
         std::move(parent), matrix, origin, flattens_inherited_transform,
         rendering_context_id, direct_compositing_reasons, compositor_element_id,
         ScrollPaintPropertyNode::Create(
-            std::move(parent_scroll), clip, bounds, user_scrollable_horizontal,
-            user_scrollable_vertical, main_thread_scrolling_reasons,
-            scroll_client)));
+            std::move(parent_scroll), scroll_container_bounds, bounds,
+            user_scrollable_horizontal, user_scrollable_vertical,
+            main_thread_scrolling_reasons, scroll_client)));
   }
 
   bool Update(
@@ -111,7 +111,7 @@
       CompositingReasons direct_compositing_reasons,
       CompositorElementId compositor_element_id,
       PassRefPtr<const ScrollPaintPropertyNode> parent_scroll,
-      const IntSize& clip,
+      const IntSize& scroll_container_bounds,
       const IntSize& bounds,
       bool user_scrollable_horizontal,
       bool user_scrollable_vertical,
@@ -123,8 +123,9 @@
     DCHECK(scroll_);
     DCHECK(matrix.IsIdentityOr2DTranslation());
     changed |= scroll_->Update(
-        std::move(parent_scroll), clip, bounds, user_scrollable_horizontal,
-        user_scrollable_vertical, main_thread_scrolling_reasons, scroll_client);
+        std::move(parent_scroll), scroll_container_bounds, bounds,
+        user_scrollable_horizontal, user_scrollable_vertical,
+        main_thread_scrolling_reasons, scroll_client);
     return changed;
   }
 
diff --git a/third_party/WebKit/Source/platform/image-decoders/jpeg/JPEGImageDecoder.cpp b/third_party/WebKit/Source/platform/image-decoders/jpeg/JPEGImageDecoder.cpp
index 7e2aea5..52d8e10 100644
--- a/third_party/WebKit/Source/platform/image-decoders/jpeg/JPEGImageDecoder.cpp
+++ b/third_party/WebKit/Source/platform/image-decoders/jpeg/JPEGImageDecoder.cpp
@@ -48,7 +48,7 @@
 #include <setjmp.h>
 }
 
-#if CPU(BIG_ENDIAN) || CPU(MIDDLE_ENDIAN)
+#if CPU(BIG_ENDIAN)
 #error Blink assumes a little-endian target.
 #endif
 
diff --git a/third_party/WebKit/Source/platform/image-decoders/webp/WEBPImageDecoder.cpp b/third_party/WebKit/Source/platform/image-decoders/webp/WEBPImageDecoder.cpp
index 57007c3..2e1afd63 100644
--- a/third_party/WebKit/Source/platform/image-decoders/webp/WEBPImageDecoder.cpp
+++ b/third_party/WebKit/Source/platform/image-decoders/webp/WEBPImageDecoder.cpp
@@ -30,7 +30,7 @@
 
 #include "third_party/skia/include/core/SkData.h"
 
-#if CPU(BIG_ENDIAN) || CPU(MIDDLE_ENDIAN)
+#if CPU(BIG_ENDIAN)
 #error Blink assumes a little-endian target.
 #endif
 
diff --git a/third_party/WebKit/Source/platform/text/WritingModeUtils.h b/third_party/WebKit/Source/platform/text/WritingModeUtils.h
index f4d680e..03fcf20 100644
--- a/third_party/WebKit/Source/platform/text/WritingModeUtils.h
+++ b/third_party/WebKit/Source/platform/text/WritingModeUtils.h
@@ -11,17 +11,43 @@
 
 namespace blink {
 
-template <typename T>
+// Templates to map values between logical orientations and physical
+// orientations. See https://www.w3.org/TR/css-writing-modes-3/ and
+// https://www.w3.org/TR/css-logical-1/ for definitions of logical orientations.
+
+// This file provides two types of templates:
+//
+// - Simple value mappers (PhysicalToLogical and LogicalToPhysical): they take
+//   4 input values in physical or logical orientations, and provide accessors
+//   to get values in logical or physical orientations. As the inputs may be
+//   evaluated even if not used (in case that the compiler is unable to remove
+//   unused evaluations, e.g. containing non-inlined function calls), for
+//   performance-senstive code, the evaluation of the inputs should be simple
+//   and/or be fully inlined.
+//
+// - Value mappers based on getter/setter methods (PhysicalToLogicalGetter,
+//   LogicalToPhysicalGetter, PhysicalToLogicalSetter and
+//   LogicalToPhysicalSetter): they take 4 method pointers as inputs pointing to
+//   methods accessing values in physical or logical orientations, and provide
+//   accessors to get or set values in logical or physical orientations. They
+//   are suitable for mapping of setters, or getters implemented with non-
+//   inlined functions. Evaluation of the input values are delayed when they are
+//   actually needed.
+//
+// See WritingModeUtilsTest.cpp, LayoutBoxModelObject.h and ComputedStyle.h for
+// examples.
+
+template <typename Value>
 class PhysicalToLogical {
   STACK_ALLOCATED();
 
  public:
   PhysicalToLogical(WritingMode writing_mode,
                     TextDirection direction,
-                    T top,
-                    T right,
-                    T bottom,
-                    T left)
+                    Value top,
+                    Value right,
+                    Value bottom,
+                    Value left)
       : writing_mode_(writing_mode),
         direction_(direction),
         top_(top),
@@ -29,72 +55,72 @@
         bottom_(bottom),
         left_(left) {}
 
-  T InlineStart() const {
+  Value InlineStart() const {
     if (IsHorizontalWritingMode(writing_mode_))
       return IsLtr(direction_) ? left_ : right_;
     return IsLtr(direction_) ? top_ : bottom_;
   }
 
-  T InlineEnd() const {
+  Value InlineEnd() const {
     if (IsHorizontalWritingMode(writing_mode_))
       return IsLtr(direction_) ? right_ : left_;
     return IsLtr(direction_) ? bottom_ : top_;
   }
 
-  T BlockStart() const {
+  Value BlockStart() const {
     if (IsHorizontalWritingMode(writing_mode_))
       return top_;
     return IsFlippedBlocksWritingMode(writing_mode_) ? right_ : left_;
   }
 
-  T BlockEnd() const {
+  Value BlockEnd() const {
     if (IsHorizontalWritingMode(writing_mode_))
       return bottom_;
     return IsFlippedBlocksWritingMode(writing_mode_) ? left_ : right_;
   }
 
-  T Over() const {
+  Value Over() const {
     return IsHorizontalWritingMode(writing_mode_) ? top_ : right_;
   }
 
-  T Under() const {
+  Value Under() const {
     return IsHorizontalWritingMode(writing_mode_) ? bottom_ : left_;
   }
 
-  T LineLeft() const {
+  Value LineLeft() const {
     return IsHorizontalWritingMode(writing_mode_) ? left_ : top_;
   }
 
-  T LineRight() const {
+  Value LineRight() const {
     return IsHorizontalWritingMode(writing_mode_) ? right_ : bottom_;
   }
 
   // Legacy logical directions.
-  T Start() const { return InlineStart(); }
-  T End() const { return InlineEnd(); }
-  T Before() const { return BlockStart(); }
-  T After() const { return BlockEnd(); }
+  Value Start() const { return InlineStart(); }
+  Value End() const { return InlineEnd(); }
+  Value Before() const { return BlockStart(); }
+  Value After() const { return BlockEnd(); }
 
  private:
   WritingMode writing_mode_;
   TextDirection direction_;
-  T top_;
-  T right_;
-  T bottom_;
-  T left_;
+  Value top_;
+  Value right_;
+  Value bottom_;
+  Value left_;
 };
 
-template <typename T>
+template <typename Value>
 class LogicalToPhysical {
   STACK_ALLOCATED();
 
  public:
   LogicalToPhysical(WritingMode writing_mode,
                     TextDirection direction,
-                    T inline_start,
-                    T inline_end,
-                    T block_start,
-                    T block_end)
+                    Value inline_start,
+                    Value inline_end,
+                    Value block_start,
+                    Value block_end)
       : writing_mode_(writing_mode),
         direction_(direction),
         inline_start_(inline_start),
@@ -102,27 +128,27 @@
         block_start_(block_start),
         block_end_(block_end) {}
 
-  T Left() const {
+  Value Left() const {
     if (IsHorizontalWritingMode(writing_mode_))
       return IsLtr(direction_) ? inline_start_ : inline_end_;
     return IsFlippedBlocksWritingMode(writing_mode_) ? block_end_
                                                      : block_start_;
   }
 
-  T Right() const {
+  Value Right() const {
     if (IsHorizontalWritingMode(writing_mode_))
       return IsLtr(direction_) ? inline_end_ : inline_start_;
     return IsFlippedBlocksWritingMode(writing_mode_) ? block_start_
                                                      : block_end_;
   }
 
-  T Top() const {
+  Value Top() const {
     if (IsHorizontalWritingMode(writing_mode_))
       return block_start_;
     return IsLtr(direction_) ? inline_start_ : inline_end_;
   }
 
-  T Bottom() const {
+  Value Bottom() const {
     if (IsHorizontalWritingMode(writing_mode_))
       return block_end_;
     return IsLtr(direction_) ? inline_end_ : inline_start_;
@@ -131,10 +157,154 @@
  private:
   WritingMode writing_mode_;
   TextDirection direction_;
-  T inline_start_;  // a.k.a. start
-  T inline_end_;    // a.k.a. end
-  T block_start_;   // a.k.a. before
-  T block_end_;     // a.k.a. after
+  Value inline_start_;  // a.k.a. start
+  Value inline_end_;    // a.k.a. end
+  Value block_start_;   // a.k.a. before
+  Value block_end_;     // a.k.a. after
+};
+
+template <typename Value, typename Object>
+class LogicalToPhysicalGetter {
+  STACK_ALLOCATED();
+
+ public:
+  using Getter = Value (Object::*)() const;
+  LogicalToPhysicalGetter(WritingMode writing_mode,
+                          TextDirection direction,
+                          const Object& object,
+                          Getter inline_start_getter,
+                          Getter inline_end_getter,
+                          Getter block_start_getter,
+                          Getter block_end_getter)
+      : object_(object),
+        converter_(writing_mode,
+                   direction,
+                   inline_start_getter,
+                   inline_end_getter,
+                   block_start_getter,
+                   block_end_getter) {}
+
+  Value Left() const { return (object_.*converter_.Left())(); }
+  Value Right() const { return (object_.*converter_.Right())(); }
+  Value Top() const { return (object_.*converter_.Top())(); }
+  Value Bottom() const { return (object_.*converter_.Bottom())(); }
+
+ private:
+  const Object& object_;
+  LogicalToPhysical<Getter> converter_;
+};
+
+template <typename Value, typename Object>
+class PhysicalToLogicalGetter {
+  STACK_ALLOCATED();
+
+ public:
+  using Getter = Value (Object::*)() const;
+  PhysicalToLogicalGetter(WritingMode writing_mode,
+                          TextDirection direction,
+                          const Object& object,
+                          Getter top_getter,
+                          Getter right_getter,
+                          Getter bottom_getter,
+                          Getter left_getter)
+      : object_(object),
+        converter_(writing_mode,
+                   direction,
+                   top_getter,
+                   right_getter,
+                   bottom_getter,
+                   left_getter) {}
+
+  Value InlineStart() const { return (object_.*converter_.InlineStart())(); }
+  Value InlineEnd() const { return (object_.*converter_.InlineEnd())(); }
+  Value BlockStart() const { return (object_.*converter_.BlockStart())(); }
+  Value BlockEnd() const { return (object_.*converter_.BlockEnd())(); }
+  Value Over() const { return (object_.*converter_.Over())(); }
+  Value Under() const { return (object_.*converter_.Under())(); }
+  Value LineLeft() const { return (object_.*converter_.LineLeft())(); }
+  Value LineRight() const { return (object_.*converter_.LineRight())(); }
+  Value Start() const { return (object_.*converter_.Start())(); }
+  Value End() const { return (object_.*converter_.End())(); }
+  Value Before() const { return (object_.*converter_.Before())(); }
+  Value After() const { return (object_.*converter_.After())(); }
+
+ private:
+  const Object& object_;
+  PhysicalToLogical<Getter> converter_;
+};
+
+template <typename Value, typename Object>
+class PhysicalToLogicalSetter {
+  STACK_ALLOCATED();
+
+ public:
+  using Setter = void (Object::*)(Value);
+  PhysicalToLogicalSetter(WritingMode writing_mode,
+                          TextDirection direction,
+                          Object& object,
+                          Setter inline_start_setter,
+                          Setter inline_end_setter,
+                          Setter block_start_setter,
+                          Setter block_end_setter)
+      : object_(object),
+        converter_(writing_mode,
+                   direction,
+                   inline_start_setter,
+                   inline_end_setter,
+                   block_start_setter,
+                   block_end_setter) {}
+
+  void SetLeft(Value v) { (object_.*converter_.Left())(v); }
+  void SetRight(Value v) { (object_.*converter_.Right())(v); }
+  void SetTop(Value v) { (object_.*converter_.Top())(v); }
+  void SetBottom(Value v) { (object_.*converter_.Bottom())(v); }
+
+ private:
+  Object& object_;
+  // This converter converts logical setters to physical setters which accept
+  // physical values and call the logical setters to set logical values.
+  LogicalToPhysical<Setter> converter_;
+};
+
+template <typename Value, typename Object>
+class LogicalToPhysicalSetter {
+  STACK_ALLOCATED();
+
+ public:
+  using Setter = void (Object::*)(Value);
+  LogicalToPhysicalSetter(WritingMode writing_mode,
+                          TextDirection direction,
+                          Object& object,
+                          Setter top_setter,
+                          Setter right_setter,
+                          Setter bottom_setter,
+                          Setter left_setter)
+      : object_(object),
+        converter_(writing_mode,
+                   direction,
+                   top_setter,
+                   right_setter,
+                   bottom_setter,
+                   left_setter) {}
+
+  void SetInlineStart(Value v) { (object_.*converter_.InlineStart())(v); }
+  void SetInlineEnd(Value v) { (object_.*converter_.InlineEnd())(v); }
+  void SetBlockStart(Value v) { (object_.*converter_.BlockStart())(v); }
+  void SetBlockEnd(Value v) { (object_.*converter_.BlockEnd())(v); }
+  void SetOver(Value v) { (object_.*converter_.Over())(v); }
+  void SetUnder(Value v) { (object_.*converter_.Under())(v); }
+  void SetLineLeft(Value v) { (object_.*converter_.LineLeft())(v); }
+  void SetLineRight(Value v) { (object_.*converter_.LineRight())(v); }
+  void SetStart(Value v) { (object_.*converter_.Start())(v); }
+  void SetEnd(Value v) { (object_.*converter_.End())(v); }
+  void SetBefore(Value v) { (object_.*converter_.Before())(v); }
+  void SetAfter(Value v) { (object_.*converter_.After())(v); }
+
+ private:
+  Object& object_;
+  // This converter converts physical setters to logical setters which accept
+  // logical values and call the physical setters to set physical values.
+  PhysicalToLogical<Setter> converter_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/text/WritingModeUtilsTest.cpp b/third_party/WebKit/Source/platform/text/WritingModeUtilsTest.cpp
index 6683fefc..917a31c7 100644
--- a/third_party/WebKit/Source/platform/text/WritingModeUtilsTest.cpp
+++ b/third_party/WebKit/Source/platform/text/WritingModeUtilsTest.cpp
@@ -12,7 +12,8 @@
 
 enum { kTop, kRight, kBottom, kLeft };
 
-void CheckLegacyLogicalDirections(PhysicalToLogical<int> converter) {
+template <typename PhysicalToLogicalConverter>
+void CheckLegacyLogicalDirections(const PhysicalToLogicalConverter& converter) {
   EXPECT_EQ(converter.InlineStart(), converter.Start());
   EXPECT_EQ(converter.InlineEnd(), converter.End());
   EXPECT_EQ(converter.BlockStart(), converter.Before());
@@ -109,7 +110,7 @@
   CheckLegacyLogicalDirections(converter);
 }
 
-enum { kInlineStart, kInlineEnd, kBlockStart, kBlockEnd };
+enum { kInlineStart = 1000, kInlineEnd, kBlockStart, kBlockEnd };
 
 TEST(WritingModeUtilsTest, LogicalToPhysicalHorizontalLtr) {
   LogicalToPhysical<int> converter(WritingMode::kHorizontalTb,
@@ -171,6 +172,127 @@
   EXPECT_EQ(kInlineStart, converter.Bottom());
 }
 
+class PhysicalValues {
+ public:
+  int Top() const { return top_; }
+  int Right() const { return right_; }
+  int Bottom() const { return bottom_; }
+  int Left() const { return left_; }
+  void SetTop(int top) { top_ = top; }
+  void SetRight(int right) { right_ = right; }
+  void SetBottom(int bottom) { bottom_ = bottom; }
+  void SetLeft(int left) { left_ = left; }
+
+ private:
+  int top_ = kTop;
+  int right_ = kRight;
+  int bottom_ = kBottom;
+  int left_ = kLeft;
+};
+
+TEST(WritingModeUtilsTest, PhysicalToLogicalGetter) {
+  PhysicalValues physical_values;
+  PhysicalToLogicalGetter<int, PhysicalValues> getter(
+      WritingMode::kVerticalRl, TextDirection::kRtl, physical_values,
+      &PhysicalValues::Top, &PhysicalValues::Right, &PhysicalValues::Bottom,
+      &PhysicalValues::Left);
+
+  EXPECT_EQ(kBottom, getter.InlineStart());
+  EXPECT_EQ(kTop, getter.InlineEnd());
+  EXPECT_EQ(kRight, getter.BlockStart());
+  EXPECT_EQ(kLeft, getter.BlockEnd());
+  EXPECT_EQ(kTop, getter.LineLeft());
+  EXPECT_EQ(kBottom, getter.LineRight());
+  EXPECT_EQ(kRight, getter.Over());
+  EXPECT_EQ(kLeft, getter.Under());
+  CheckLegacyLogicalDirections(getter);
+}
+
+TEST(WritingModeUtilsTest, LogicalToPhysicalSetter) {
+  PhysicalValues physical_values;
+  LogicalToPhysicalSetter<int, PhysicalValues> setter(
+      WritingMode::kVerticalRl, TextDirection::kRtl, physical_values,
+      &PhysicalValues::SetTop, &PhysicalValues::SetRight,
+      &PhysicalValues::SetBottom, &PhysicalValues::SetLeft);
+  setter.SetInlineStart(kInlineStart);
+  setter.SetInlineEnd(kInlineEnd);
+  setter.SetBlockStart(kBlockStart);
+  setter.SetBlockEnd(kBlockEnd);
+
+  EXPECT_EQ(kBlockEnd, physical_values.Left());
+  EXPECT_EQ(kBlockStart, physical_values.Right());
+  EXPECT_EQ(kInlineEnd, physical_values.Top());
+  EXPECT_EQ(kInlineStart, physical_values.Bottom());
+
+  setter.SetStart(kInlineStart);
+  setter.SetEnd(kInlineEnd);
+  setter.SetBefore(kBlockStart);
+  setter.SetAfter(kBlockEnd);
+
+  EXPECT_EQ(kBlockEnd, physical_values.Left());
+  EXPECT_EQ(kBlockStart, physical_values.Right());
+  EXPECT_EQ(kInlineEnd, physical_values.Top());
+  EXPECT_EQ(kInlineStart, physical_values.Bottom());
+
+  setter.SetLineRight(kInlineStart);
+  setter.SetLineLeft(kInlineEnd);
+  setter.SetOver(kBlockStart);
+  setter.SetUnder(kBlockEnd);
+
+  EXPECT_EQ(kBlockEnd, physical_values.Left());
+  EXPECT_EQ(kBlockStart, physical_values.Right());
+  EXPECT_EQ(kInlineEnd, physical_values.Top());
+  EXPECT_EQ(kInlineStart, physical_values.Bottom());
+}
+
+class LogicalValues {
+ public:
+  int InlineStart() const { return inline_start_; }
+  int InlineEnd() const { return inline_end_; }
+  int BlockStart() const { return block_start_; }
+  int BlockEnd() const { return block_end_; }
+  void SetInlineStart(int inline_start) { inline_start_ = inline_start; }
+  void SetInlineEnd(int inline_end) { inline_end_ = inline_end; }
+  void SetBlockStart(int block_start) { block_start_ = block_start; }
+  void SetBlockEnd(int block_end) { block_end_ = block_end; }
+
+ private:
+  int inline_start_ = kInlineStart;
+  int inline_end_ = kInlineEnd;
+  int block_start_ = kBlockStart;
+  int block_end_ = kBlockEnd;
+};
+
+TEST(WritingModeUtilsTest, LogicalToPhysicalGetter) {
+  LogicalValues logical_values;
+  LogicalToPhysicalGetter<int, LogicalValues> getter(
+      WritingMode::kVerticalRl, TextDirection::kRtl, logical_values,
+      &LogicalValues::InlineStart, &LogicalValues::InlineEnd,
+      &LogicalValues::BlockStart, &LogicalValues::BlockEnd);
+
+  EXPECT_EQ(kBlockEnd, getter.Left());
+  EXPECT_EQ(kBlockStart, getter.Right());
+  EXPECT_EQ(kInlineEnd, getter.Top());
+  EXPECT_EQ(kInlineStart, getter.Bottom());
+}
+
+TEST(WritingModeUtilsTest, PhysicalToLogicalSetter) {
+  LogicalValues logical_values;
+  PhysicalToLogicalSetter<int, LogicalValues> setter(
+      WritingMode::kVerticalRl, TextDirection::kRtl, logical_values,
+      &LogicalValues::SetInlineStart, &LogicalValues::SetInlineEnd,
+      &LogicalValues::SetBlockStart, &LogicalValues::SetBlockEnd);
+  setter.SetTop(kTop);
+  setter.SetRight(kRight);
+  setter.SetBottom(kBottom);
+  setter.SetLeft(kLeft);
+
+  EXPECT_EQ(kBottom, logical_values.InlineStart());
+  EXPECT_EQ(kTop, logical_values.InlineEnd());
+  EXPECT_EQ(kRight, logical_values.BlockStart());
+  EXPECT_EQ(kLeft, logical_values.BlockEnd());
+}
+
 }  // namespace
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/wtf/ByteOrder.h b/third_party/WebKit/Source/platform/wtf/ByteOrder.h
index 51a2705..279efbc9b 100644
--- a/third_party/WebKit/Source/platform/wtf/ByteOrder.h
+++ b/third_party/WebKit/Source/platform/wtf/ByteOrder.h
@@ -55,19 +55,6 @@
 inline uint32_t htonl(uint32_t x) {
   return x;
 }
-#elif CPU(MIDDLE_ENDIAN)
-inline uint16_t ntohs(uint16_t x) {
-  return x;
-}
-inline uint16_t htons(uint16_t x) {
-  return x;
-}
-inline uint32_t ntohl(uint32_t x) {
-  return WTF::wswap32(x);
-}
-inline uint32_t htonl(uint32_t x) {
-  return WTF::wswap32(x);
-}
 #else
 inline uint16_t ntohs(uint16_t x) {
   return WTF::Bswap16(x);
diff --git a/third_party/WebKit/Source/platform/wtf/CPU.h b/third_party/WebKit/Source/platform/wtf/CPU.h
index a2fe73f0..e249199 100644
--- a/third_party/WebKit/Source/platform/wtf/CPU.h
+++ b/third_party/WebKit/Source/platform/wtf/CPU.h
@@ -61,7 +61,7 @@
 
 #elif !defined(__ARM_EABI__) && !defined(__EABI__) && !defined(__VFP_FP__) && \
     !defined(_WIN32_WCE) && !defined(ANDROID)
-#define WTF_CPU_MIDDLE_ENDIAN 1
+#error Chromium does not support middle endian architecture
 
 #endif
 
diff --git a/third_party/WebKit/Source/platform/wtf/DEPS b/third_party/WebKit/Source/platform/wtf/DEPS
index 139b5791..3e7a48e 100644
--- a/third_party/WebKit/Source/platform/wtf/DEPS
+++ b/third_party/WebKit/Source/platform/wtf/DEPS
@@ -4,6 +4,7 @@
     "+base/allocator/oom.h",
     "+base/allocator/partition_allocator",
     "+base/process/process_metrics.h",
+    "+base/atomic_ref_count.h",
     "+base/auto_reset.h",
     "+base/bind.h",
     "+base/bits.h",
@@ -19,7 +20,6 @@
     "+base/threading/thread_checker.h",
     "+base/time/time.h",
     "+base/tuple.h",
-    "+build",
     # To avoid recursive dependency, we impose a blanket ban on using other
     # platform files. Think carefully if you want to relax this restriction.
     "-platform",
diff --git a/third_party/WebKit/Source/platform/wtf/ThreadSafeRefCounted.h b/third_party/WebKit/Source/platform/wtf/ThreadSafeRefCounted.h
index f27c054..5b3015e 100644
--- a/third_party/WebKit/Source/platform/wtf/ThreadSafeRefCounted.h
+++ b/third_party/WebKit/Source/platform/wtf/ThreadSafeRefCounted.h
@@ -30,9 +30,8 @@
 #ifndef ThreadSafeRefCounted_h
 #define ThreadSafeRefCounted_h
 
+#include "base/atomic_ref_count.h"
 #include "platform/wtf/Allocator.h"
-#include "platform/wtf/Atomics.h"
-#include "platform/wtf/DynamicAnnotations.h"
 #include "platform/wtf/Noncopyable.h"
 #include "platform/wtf/WTFExport.h"
 
@@ -43,28 +42,17 @@
   USING_FAST_MALLOC(ThreadSafeRefCountedBase);
 
  public:
-  ThreadSafeRefCountedBase(int initial_ref_count = 1)
-      : ref_count_(initial_ref_count) {}
+  ThreadSafeRefCountedBase() : ref_count_(1) {}
 
-  void Ref() { AtomicIncrement(&ref_count_); }
-
-  bool HasOneRef() { return RefCount() == 1; }
-
-  int RefCount() const { return static_cast<int const volatile&>(ref_count_); }
+  void Ref() { ref_count_.Increment(); }
+  bool HasOneRef() const { return ref_count_.IsOne(); }
 
  protected:
   // Returns whether the pointer should be freed or not.
-  bool DerefBase() {
-    WTF_ANNOTATE_HAPPENS_BEFORE(&ref_count_);
-    if (AtomicDecrement(&ref_count_) <= 0) {
-      WTF_ANNOTATE_HAPPENS_AFTER(&ref_count_);
-      return true;
-    }
-    return false;
-  }
+  bool DerefBase() { return !ref_count_.Decrement(); }
 
  private:
-  int ref_count_;
+  base::AtomicRefCount ref_count_;
 };
 
 template <class T>
diff --git a/third_party/WebKit/Source/platform/wtf/build_config.h b/third_party/WebKit/Source/platform/wtf/build_config.h
index 57d89fd8..145977f66 100644
--- a/third_party/WebKit/Source/platform/wtf/build_config.h
+++ b/third_party/WebKit/Source/platform/wtf/build_config.h
@@ -33,9 +33,10 @@
 /* HAVE() - specific system features (headers, functions or similar) that are
  * present or not */
 #define HAVE(WTF_FEATURE) (defined HAVE_##WTF_FEATURE && HAVE_##WTF_FEATURE)
-/* OS() - underlying operating system; only to be used for mandated low-level
-   services like
-   virtual memory, not to choose a GUI toolkit */
+
+// OS() - underlying operating system; only to be used for mandated low-level
+// services like virtual memory, not to choose a GUI toolkit
+// This macro is deprecated.  Use defined(OS_FOO).  See crbug.com/737403.
 #define OS(WTF_FEATURE) (defined OS_##WTF_FEATURE && OS_##WTF_FEATURE)
 
 /* ==== Policy decision macros: these define policy choices for a particular
@@ -48,10 +49,9 @@
 #define ENABLE(WTF_FEATURE) \
   (defined ENABLE_##WTF_FEATURE && ENABLE_##WTF_FEATURE)
 
-/* There is an assumption in the project that either OS(WIN) or OS(POSIX) is
- * set. */
-#if !OS(WIN) && !OS(POSIX)
-#error Either OS(WIN) or OS(POSIX) needs to be set.
+// There is an assumption in the project that either OS_WIN or OS_POSIX is set.
+#if !defined(OS_WIN) && !defined(OS_POSIX)
+#error Either OS_WIN or OS_POSIX needs to be set.
 #endif
 
 #endif  // WTF_build_config_h
diff --git a/third_party/WebKit/Source/platform/wtf/text/ASCIIFastPath.h b/third_party/WebKit/Source/platform/wtf/text/ASCIIFastPath.h
index 9eb431f..750e141 100644
--- a/third_party/WebKit/Source/platform/wtf/text/ASCIIFastPath.h
+++ b/third_party/WebKit/Source/platform/wtf/text/ASCIIFastPath.h
@@ -146,8 +146,7 @@
     DCHECK(!(source[i] & 0xff00));
     destination[i] = static_cast<LChar>(source[i]);
   }
-#elif COMPILER(GCC) && CPU(ARM_NEON) && \
-    !(CPU(BIG_ENDIAN) || CPU(MIDDLE_ENDIAN)) && defined(NDEBUG)
+#elif COMPILER(GCC) && CPU(ARM_NEON) && !CPU(BIG_ENDIAN) && defined(NDEBUG)
   const LChar* const end = destination + length;
   const uintptr_t kMemoryAccessSize = 8;
 
diff --git a/third_party/WebKit/Tools/Scripts/run-bindings-tests b/third_party/WebKit/Tools/Scripts/run-bindings-tests
index d58eb822..32128c9 100755
--- a/third_party/WebKit/Tools/Scripts/run-bindings-tests
+++ b/third_party/WebKit/Tools/Scripts/run-bindings-tests
@@ -45,6 +45,10 @@
         default=False,
         action='store_true',
         help='Skip running reference tests (only run unit tests).')
+    argument_parser.add_argument('--suppress-diff',
+        default=False,
+        action='store_true',
+        help='Suppress diff for reference tests.')
     return argument_parser
 
 
@@ -77,7 +81,8 @@
     if args.skip_reference_tests:
         return 0
 
-    return run_bindings_tests(args.reset_results, args.verbose)
+    return run_bindings_tests(
+        args.reset_results, args.verbose, args.suppress_diff)
 
 
 if __name__ == '__main__':
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/bindings/bindings_tests.py b/third_party/WebKit/Tools/Scripts/webkitpy/bindings/bindings_tests.py
index 5147f154..0d3303ac 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/bindings/bindings_tests.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/bindings/bindings_tests.py
@@ -190,7 +190,7 @@
         self.target_component = target_component
 
 
-def bindings_tests(output_directory, verbose):
+def bindings_tests(output_directory, verbose, suppress_diff):
     executive = Executive()
 
     def list_files(directory):
@@ -239,7 +239,8 @@
             # cmp is much faster than diff, and usual case is "no difference",
             # so only run diff if cmp detects a difference
             print 'FAIL: %s' % reference_basename
-            print diff(reference_filename, output_filename)
+            if not suppress_diff:
+                print diff(reference_filename, output_filename)
             return False
 
         if verbose:
@@ -360,11 +361,11 @@
     return 1
 
 
-def run_bindings_tests(reset_results, verbose):
+def run_bindings_tests(reset_results, verbose, suppress_diff):
     # Generate output into the reference directory if resetting results, or
     # a temp directory if not.
     if reset_results:
         print 'Resetting results'
-        return bindings_tests(REFERENCE_DIRECTORY, verbose)
+        return bindings_tests(REFERENCE_DIRECTORY, verbose, suppress_diff)
     with TemporaryDirectory() as temp_dir:
-        return bindings_tests(temp_dir, verbose)
+        return bindings_tests(temp_dir, verbose, suppress_diff)
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_expectations.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_expectations.py
index 006a1b4..8422d6e9 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_expectations.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_expectations.py
@@ -286,7 +286,7 @@
     _configuration_tokens_list = [
         'Mac', 'Mac10.9', 'Mac10.10', 'Mac10.11', 'Retina', 'Mac10.12',
         'Win', 'Win7', 'Win10',
-        'Linux', 'Trusty',
+        'Linux',
         'Android',
         'Release',
         'Debug',
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_expectations_updater_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_expectations_updater_unittest.py
index 44bda5b..a5d0157 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_expectations_updater_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_expectations_updater_unittest.py
@@ -323,10 +323,10 @@
         expectations_path = '/test.checkout/LayoutTests/NeverFixTests'
         host.filesystem.write_text_file(
             expectations_path,
-            'crbug.com/111 [ Trusty ] external/wpt/test.html [ WontFix ]\n')
+            'crbug.com/111 [ Linux ] external/wpt/test.html [ WontFix ]\n')
         host.filesystem.write_text_file('/test.checkout/LayoutTests/external/wpt/test.html', '')
         updater = WPTExpectationsUpdater(host)
-        self.assertEqual(updater.skipped_specifiers('external/wpt/test.html'), ['Trusty'])
+        self.assertEqual(updater.skipped_specifiers('external/wpt/test.html'), ['Precise', 'Trusty'])
 
     def test_simplify_specifiers(self):
         macros = {
diff --git a/third_party/WebKit/Tools/Scripts/wpt-export b/third_party/WebKit/Tools/Scripts/wpt-export
index 6a94ac1..841e52d 100755
--- a/third_party/WebKit/Tools/Scripts/wpt-export
+++ b/third_party/WebKit/Tools/Scripts/wpt-export
@@ -19,7 +19,7 @@
 
 from webkitpy.common.host import Host
 from webkitpy.w3c.test_exporter import TestExporter
-from webkitpy.w3c.common import get_credentials
+from webkitpy.w3c.common import read_credentials
 
 
 _log = logging.getLogger(__name__)
@@ -35,13 +35,12 @@
              'any pull requests.')
     parser.add_argument(
         '--credentials-json',
-        help='A JSON file with an object containing zero or more of the
-              following keys: '
-             'GH_USER, GH_TOKEN, GERRIT_USER, GERRIT_TOKEN')
+        help='A JSON file with an object containing zero or more of the '
+             'following keys: GH_USER, GH_TOKEN, GERRIT_USER, GERRIT_TOKEN')
     args = parser.parse_args()
 
     host = Host()
-    credentials = get_credentials(host, args)
+    credentials = read_credentials(host, args.credentials_json)
 
     if not (credentials['GH_USER'] and credentials['GH_TOKEN']):
         parser.error('Must provide both gh_user and gh_token for GitHub.')
diff --git a/third_party/freetype/README.chromium b/third_party/freetype/README.chromium
index a3ddb32..f8fda05 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
-Revision: a12a34451a99cbbcad55d466940fd445171927fd
+Version: VER-2-8-58
+Revision: 7819aeb622a94be0d89caf8382f290d0266c4aed
 License: Custom license "inspired by the BSD, Artistic, and IJG (Independent
          JPEG Group) licenses"
 License File: src/docs/FTL.TXT
diff --git a/third_party/freetype/include/freetype-custom-config/ftoption.h b/third_party/freetype/include/freetype-custom-config/ftoption.h
index d7aff76..8fbfa28 100644
--- a/third_party/freetype/include/freetype-custom-config/ftoption.h
+++ b/third_party/freetype/include/freetype-custom-config/ftoption.h
@@ -348,7 +348,7 @@
   /*                                                                       */
   /*   - The TrueType driver will provide its own set of glyph names,      */
   /*     if you build it to support postscript names in the TrueType       */
-  /*     `post' table.                                                     */
+  /*     `post' table, but will not synthesize a missing Unicode charmap.  */
   /*                                                                       */
   /*   - The Type 1 driver will not be able to synthesize a Unicode        */
   /*     charmap out of the glyphs found in the fonts.                     */
diff --git a/third_party/freetype/roll-freetype.sh b/third_party/freetype/roll-freetype.sh
new file mode 100755
index 0000000..10e775f
--- /dev/null
+++ b/third_party/freetype/roll-freetype.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+REVIEWERS=`paste -s -d, third_party/freetype/OWNERS` &&
+roll-dep -r ${REVIEWERS} src/third_party/freetype/src/ &&
+
+TMPFILE=`mktemp` &&
+git -C third_party/freetype/src/ cat-file blob HEAD@{1}:include/freetype/config/ftoption.h >> ${TMPFILE} &&
+git merge-file third_party/freetype/include/freetype-custom-config/ftoption.h ${TMPFILE} third_party/freetype/src/include/freetype/config/ftoption.h &&
+rm ${TMPFILE} &&
+git add third_party/freetype/include/freetype-custom-config/ftoption.h &&
+
+FTVERSION=`git -C third_party/freetype/src/ describe` &&
+FTCOMMIT=`git -C third_party/freetype/src/ rev-parse HEAD` &&
+sed -i "s/^Version: .*\$/Version: ${FTVERSION%-*}/" third_party/freetype/README.chromium &&
+sed -i "s/^Revision: .*\$/Revision: ${FTCOMMIT}/" third_party/freetype/README.chromium &&
+git add third_party/freetype/README.chromium &&
+
+git commit --quiet --amend --no-edit &&
+
+true
diff --git a/third_party/leveldatabase/env_chromium.cc b/third_party/leveldatabase/env_chromium.cc
index 1246892..928d4be 100644
--- a/third_party/leveldatabase/env_chromium.cc
+++ b/third_party/leveldatabase/env_chromium.cc
@@ -13,15 +13,21 @@
 
 #include "base/files/file_enumerator.h"
 #include "base/files/file_util.h"
+#include "base/format_macros.h"
 #include "base/lazy_instance.h"
+#include "base/logging.h"
 #include "base/macros.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/process/process_metrics.h"
 #include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_restrictions.h"
+#include "base/trace_event/memory_dump_manager.h"
+#include "base/trace_event/memory_dump_provider.h"
+#include "base/trace_event/process_memory_dump.h"
 #include "base/trace_event/trace_event.h"
 #include "third_party/leveldatabase/chromium_logger.h"
 #include "third_party/leveldatabase/src/include/leveldb/options.h"
@@ -1095,6 +1101,187 @@
   return LEVELDB_STATUS_INVALID_ARGUMENT;
 }
 
+// Forwards all calls to the underlying leveldb::DB instance.
+// Adds / removes itself in the DBTracker it's created with.
+class DBTracker::TrackedDBImpl : public base::LinkNode<TrackedDBImpl>,
+                                 public TrackedDB {
+ public:
+  TrackedDBImpl(DBTracker* tracker, const std::string name, leveldb::DB* db)
+      : tracker_(tracker), name_(name), db_(db) {
+    tracker_->DatabaseOpened(this);
+  }
+
+  ~TrackedDBImpl() override { tracker_->DatabaseDestroyed(this); }
+
+  const std::string& name() const override { return name_; }
+
+  leveldb::Status Put(const leveldb::WriteOptions& options,
+                      const leveldb::Slice& key,
+                      const leveldb::Slice& value) override {
+    return db_->Put(options, key, value);
+  }
+
+  leveldb::Status Delete(const leveldb::WriteOptions& options,
+                         const leveldb::Slice& key) override {
+    return db_->Delete(options, key);
+  }
+
+  leveldb::Status Write(const leveldb::WriteOptions& options,
+                        leveldb::WriteBatch* updates) override {
+    return db_->Write(options, updates);
+  }
+
+  leveldb::Status Get(const leveldb::ReadOptions& options,
+                      const leveldb::Slice& key,
+                      std::string* value) override {
+    return db_->Get(options, key, value);
+  }
+
+  const leveldb::Snapshot* GetSnapshot() override { return db_->GetSnapshot(); }
+
+  void ReleaseSnapshot(const leveldb::Snapshot* snapshot) override {
+    return db_->ReleaseSnapshot(snapshot);
+  }
+
+  bool GetProperty(const leveldb::Slice& property,
+                   std::string* value) override {
+    return db_->GetProperty(property, value);
+  }
+
+  void GetApproximateSizes(const leveldb::Range* range,
+                           int n,
+                           uint64_t* sizes) override {
+    return db_->GetApproximateSizes(range, n, sizes);
+  }
+
+  void CompactRange(const leveldb::Slice* begin,
+                    const leveldb::Slice* end) override {
+    return db_->CompactRange(begin, end);
+  }
+
+  leveldb::Iterator* NewIterator(const leveldb::ReadOptions& options) override {
+    return db_->NewIterator(options);
+  }
+
+ private:
+  DBTracker* tracker_;
+  std::string name_;
+  std::unique_ptr<leveldb::DB> db_;
+};
+
+// Reports live databases to memory-infra. For each live database the following
+// information is reported:
+// 1. Instance pointer (to disambiguate databases).
+// 2. Memory taken by the database.
+// 3. The name of the database (when not in BACKGROUND mode to avoid exposing
+//    PIIs in slow reports).
+//
+// Example report (as seen after clicking "leveldatabase" in "Overview" pane
+// in Chrome tracing UI):
+//
+// Component             size          name
+// ---------------------------------------------------------------------------
+// leveldatabase         204.4 KiB
+//   0x7FE70F2040A0      4.0 KiB       /Users/.../data_reduction_proxy_leveldb
+//   0x7FE70F530D80      188.4 KiB     /Users/.../Sync Data/LevelDB
+//   0x7FE71442F270      4.0 KiB       /Users/.../Sync App Settings/...
+//   0x7FE71471EC50      8.0 KiB       /Users/.../Extension State
+//
+class DBTracker::MemoryDumpProvider
+    : public base::trace_event::MemoryDumpProvider {
+ public:
+  bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
+                    base::trace_event::ProcessMemoryDump* pmd) override {
+    auto db_visitor = [&](TrackedDB* db) {
+      std::string db_dump_name = base::StringPrintf(
+          "leveldatabase/0x%" PRIXPTR, reinterpret_cast<uintptr_t>(db));
+      auto* db_dump = pmd->CreateAllocatorDump(db_dump_name.c_str());
+
+      uint64_t db_memory_usage = 0;
+      {
+        std::string usage_string;
+        bool success = db->GetProperty("leveldb.approximate-memory-usage",
+                                       &usage_string) &&
+                       base::StringToUint64(usage_string, &db_memory_usage);
+        DCHECK(success);
+      }
+      db_dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
+                         base::trace_event::MemoryAllocatorDump::kUnitsBytes,
+                         db_memory_usage);
+
+      if (args.level_of_detail !=
+          base::trace_event::MemoryDumpLevelOfDetail::BACKGROUND) {
+        db_dump->AddString("name", "", db->name());
+      }
+
+      const char* system_allocator_name =
+          base::trace_event::MemoryDumpManager::GetInstance()
+              ->system_allocator_pool_name();
+      if (system_allocator_name) {
+        pmd->AddSuballocation(db_dump->guid(), system_allocator_name);
+      }
+    };
+
+    DBTracker::GetInstance()->VisitDatabases(db_visitor);
+    return true;
+  }
+};
+
+DBTracker::DBTracker() : mdp_(new MemoryDumpProvider()) {
+  base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
+      mdp_.get(), "LevelDB", nullptr);
+}
+
+DBTracker::~DBTracker() {
+  NOTREACHED();  // DBTracker is a singleton
+}
+
+DBTracker* DBTracker::GetInstance() {
+  static DBTracker* instance = new DBTracker();
+  return instance;
+}
+
+leveldb::Status DBTracker::OpenDatabase(const leveldb::Options& options,
+                                        const std::string& name,
+                                        TrackedDB** dbptr) {
+  leveldb::DB* db = nullptr;
+  auto status = leveldb::DB::Open(options, name, &db);
+  if (status.ok()) {
+    // TrackedDBImpl ctor adds the instance to the tracker.
+    *dbptr = new TrackedDBImpl(GetInstance(), name, db);
+  }
+  return status;
+}
+
+void DBTracker::VisitDatabases(const DatabaseVisitor& visitor) {
+  base::AutoLock lock(databases_lock_);
+  for (auto* i = databases_.head(); i != databases_.end(); i = i->next()) {
+    visitor(i->value());
+  }
+}
+
+void DBTracker::DatabaseOpened(TrackedDBImpl* database) {
+  base::AutoLock lock(databases_lock_);
+  databases_.Append(database);
+}
+
+void DBTracker::DatabaseDestroyed(TrackedDBImpl* database) {
+  base::AutoLock lock(databases_lock_);
+  database->RemoveFromList();
+}
+
+leveldb::Status OpenDB(const leveldb::Options& options,
+                       const std::string& name,
+                       std::unique_ptr<leveldb::DB>* dbptr) {
+  DBTracker::TrackedDB* tracked_db = nullptr;
+  leveldb::Status status =
+      DBTracker::GetInstance()->OpenDatabase(options, name, &tracked_db);
+  if (status.ok()) {
+    dbptr->reset(tracked_db);
+  }
+  return status;
+}
+
 }  // namespace leveldb_env
 
 namespace leveldb {
diff --git a/third_party/leveldatabase/env_chromium.h b/third_party/leveldatabase/env_chromium.h
index d433581..adc9c25 100644
--- a/third_party/leveldatabase/env_chromium.h
+++ b/third_party/leveldatabase/env_chromium.h
@@ -6,13 +6,18 @@
 #define THIRD_PARTY_LEVELDATABASE_ENV_CHROMIUM_H_
 
 #include <deque>
+#include <functional>
+#include <memory>
 #include <set>
 #include <string>
 #include <vector>
 
+#include "base/containers/linked_list.h"
 #include "base/files/file.h"
 #include "base/files/file_path.h"
+#include "base/macros.h"
 #include "base/metrics/histogram.h"
+#include "leveldb/db.h"
 #include "leveldb/env.h"
 #include "port/port_chromium.h"
 #include "util/mutexlock.h"
@@ -230,6 +235,61 @@
   LockTable locks_;
 };
 
+// Tracks databases open via OpenDatabase() method and exposes them to
+// memory-infra. The class is thread safe.
+class DBTracker {
+ public:
+  // DBTracker singleton instance.
+  static DBTracker* GetInstance();
+
+  // Provides extra information about a tracked database.
+  class TrackedDB : public leveldb::DB {
+   public:
+    // Name that OpenDatabase() was called with.
+    virtual const std::string& name() const = 0;
+  };
+
+  // Opens a database and starts tracking it. As long as the opened database
+  // is alive (i.e. its instance is not destroyed) the database is exposed to
+  // memory-infra and is enumerated by VisitDatabases() method.
+  leveldb::Status OpenDatabase(const leveldb::Options& options,
+                               const std::string& name,
+                               TrackedDB** dbptr);
+
+  using DatabaseVisitor = std::function<void(TrackedDB*)>;
+
+  // Calls |visitor| for each live database. The database is live from the
+  // point it was returned from OpenDatabase() and up until its instance is
+  // destroyed.
+  // The databases may be visited in an arbitrary order.
+  // This function takes a lock, preventing any database from being opened or
+  // destroyed (but doesn't lock the databases themselves).
+  void VisitDatabases(const DatabaseVisitor& visitor);
+
+ private:
+  class TrackedDBImpl;
+  class MemoryDumpProvider;
+
+  DBTracker();
+  ~DBTracker();
+
+  void DatabaseOpened(TrackedDBImpl* database);
+  void DatabaseDestroyed(TrackedDBImpl* database);
+
+  std::unique_ptr<MemoryDumpProvider> mdp_;
+
+  base::Lock databases_lock_;
+  base::LinkedList<TrackedDBImpl> databases_;
+
+  DISALLOW_COPY_AND_ASSIGN(DBTracker);
+};
+
+// Opens a database and exposes it to Chrome's tracing (see DBTracker for
+// details). Note that |dbptr| is touched only when function succeeds.
+leveldb::Status OpenDB(const leveldb::Options& options,
+                       const std::string& name,
+                       std::unique_ptr<leveldb::DB>* dbptr);
+
 }  // namespace leveldb_env
 
 #endif  // THIRD_PARTY_LEVELDATABASE_ENV_CHROMIUM_H_
diff --git a/third_party/leveldatabase/env_chromium_unittest.cc b/third_party/leveldatabase/env_chromium_unittest.cc
index 57bca24..b113ad0a 100644
--- a/third_party/leveldatabase/env_chromium_unittest.cc
+++ b/third_party/leveldatabase/env_chromium_unittest.cc
@@ -2,12 +2,17 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <set>
+#include <vector>
+
 #include "base/files/file.h"
 #include "base/files/file_enumerator.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/lazy_instance.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
 #include "base/test/test_suite.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/leveldatabase/env_chromium.h"
@@ -24,6 +29,7 @@
 using leveldb::WritableFile;
 using leveldb::WriteOptions;
 using leveldb_env::ChromiumEnv;
+using leveldb_env::DBTracker;
 using leveldb_env::MethodID;
 
 TEST(ErrorEncoding, OnlyAMethod) {
@@ -190,4 +196,133 @@
   EXPECT_EQ(size_t(4 * MB), leveldb_env::WriteBufferSize(100 * MB * MB));
 }
 
+class ChromiumEnvDBTrackerTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    testing::Test::SetUp();
+    ASSERT_TRUE(scoped_temp_dir_.CreateUniqueTempDir());
+  }
+
+  const base::FilePath& temp_path() const { return scoped_temp_dir_.GetPath(); }
+
+  using VisitedDBSet = std::set<DBTracker::TrackedDB*>;
+
+  static VisitedDBSet VisitDatabases() {
+    VisitedDBSet visited;
+    auto db_visitor = [&](DBTracker::TrackedDB* db) {
+      ASSERT_TRUE(visited.insert(db).second)
+          << "Database " << std::hex << db << " visited for the second time";
+    };
+    DBTracker::GetInstance()->VisitDatabases(db_visitor);
+    return visited;
+  }
+
+  using LiveDBSet = std::vector<std::unique_ptr<DBTracker::TrackedDB>>;
+
+  void AssertEqualSets(const LiveDBSet& live_dbs,
+                       const VisitedDBSet& visited_dbs) {
+    for (const auto& live_db : live_dbs) {
+      ASSERT_EQ(1u, visited_dbs.count(live_db.get()))
+          << "Database " << std::hex << live_db.get() << " was not visited";
+    }
+    ASSERT_EQ(live_dbs.size(), visited_dbs.size())
+        << "Extra databases were visited";
+  }
+
+ private:
+  base::ScopedTempDir scoped_temp_dir_;
+};
+
+TEST_F(ChromiumEnvDBTrackerTest, OpenDatabase) {
+  struct KeyValue {
+    const char* key;
+    const char* value;
+  };
+  constexpr KeyValue db_data[] = {
+      {"banana", "yellow"}, {"sky", "blue"}, {"enthusiasm", ""},
+  };
+
+  // Open a new database using DBTracker::Open, write some data.
+  Options options;
+  options.create_if_missing = true;
+  std::string name = temp_path().AsUTF8Unsafe();
+  DBTracker::TrackedDB* tracked_db;
+  Status status =
+      DBTracker::GetInstance()->OpenDatabase(options, name, &tracked_db);
+  ASSERT_TRUE(status.ok()) << status.ToString();
+  for (const auto& kv : db_data) {
+    status = tracked_db->Put(WriteOptions(), kv.key, kv.value);
+    ASSERT_TRUE(status.ok()) << status.ToString();
+  }
+
+  // Close the database.
+  delete tracked_db;
+
+  // Open the database again with DB::Open, and check the data.
+  options.create_if_missing = false;
+  leveldb::DB* plain_db = nullptr;
+  status = leveldb::DB::Open(options, name, &plain_db);
+  ASSERT_TRUE(status.ok()) << status.ToString();
+  for (const auto& kv : db_data) {
+    std::string value;
+    status = plain_db->Get(ReadOptions(), kv.key, &value);
+    ASSERT_TRUE(status.ok()) << status.ToString();
+    ASSERT_EQ(value, kv.value);
+  }
+  delete plain_db;
+}
+
+TEST_F(ChromiumEnvDBTrackerTest, TrackedDBInfo) {
+  Options options;
+  options.create_if_missing = true;
+  std::string name = temp_path().AsUTF8Unsafe();
+  DBTracker::TrackedDB* db;
+  Status status = DBTracker::GetInstance()->OpenDatabase(options, name, &db);
+  ASSERT_TRUE(status.ok()) << status.ToString();
+
+  // Check that |db| reports info that was used to open it.
+  ASSERT_EQ(name, db->name());
+
+  delete db;
+}
+
+TEST_F(ChromiumEnvDBTrackerTest, VisitDatabases) {
+  LiveDBSet live_dbs;
+
+  // Open several databases.
+  for (const char* tag : {"poets", "movies", "recipes", "novels"}) {
+    Options options;
+    options.create_if_missing = true;
+    std::string name = temp_path().AppendASCII(tag).AsUTF8Unsafe();
+    DBTracker::TrackedDB* db;
+    Status status = DBTracker::GetInstance()->OpenDatabase(options, name, &db);
+    ASSERT_TRUE(status.ok()) << status.ToString();
+    live_dbs.emplace_back(db);
+  }
+
+  // Check that all live databases are visited.
+  AssertEqualSets(live_dbs, VisitDatabases());
+
+  // Close couple of a databases.
+  live_dbs.erase(live_dbs.begin());
+  live_dbs.erase(live_dbs.begin() + 1);
+
+  // Check that only remaining live databases are visited.
+  AssertEqualSets(live_dbs, VisitDatabases());
+}
+
+TEST_F(ChromiumEnvDBTrackerTest, OpenDBTracking) {
+  Options options;
+  options.create_if_missing = true;
+  std::unique_ptr<leveldb::DB> db;
+  auto status = leveldb_env::OpenDB(options, temp_path().AsUTF8Unsafe(), &db);
+  ASSERT_TRUE(status.ok()) << status.ToString();
+
+  auto visited_dbs = VisitDatabases();
+
+  // Databases returned by OpenDB() should be tracked.
+  ASSERT_EQ(1u, visited_dbs.size());
+  ASSERT_EQ(db.get(), *visited_dbs.begin());
+}
+
 int main(int argc, char** argv) { return base::TestSuite(argc, argv).Run(); }
diff --git a/third_party/libaddressinput/chromium/chrome_address_validator_unittest.cc b/third_party/libaddressinput/chromium/chrome_address_validator_unittest.cc
index bc4c9d8..54c37e4 100644
--- a/third_party/libaddressinput/chromium/chrome_address_validator_unittest.cc
+++ b/third_party/libaddressinput/chromium/chrome_address_validator_unittest.cc
@@ -52,6 +52,7 @@
 using ::i18n::addressinput::UNKNOWN_VALUE;
 using ::i18n::addressinput::USES_P_O_BOX;
 
+// This class should always succeed in getting the rules.
 class AddressValidatorTest : public testing::Test, LoadRulesListener {
  protected:
   AddressValidatorTest()
@@ -62,6 +63,10 @@
     validator_->LoadRules("US");
   }
 
+  void set_expected_status(AddressValidator::Status expected_status) {
+    expected_status_ = expected_status;
+  }
+
   virtual ~AddressValidatorTest() {}
 
   const std::unique_ptr<AddressValidator> validator_;
@@ -75,9 +80,11 @@
     FieldProblemMap dummy;
     AddressValidator::Status status =
         validator_->ValidateAddress(address_data, NULL, &dummy);
-    ASSERT_EQ(success, status == AddressValidator::SUCCESS);
+    ASSERT_EQ(expected_status_, status);
   }
 
+  AddressValidator::Status expected_status_ = AddressValidator::SUCCESS;
+
   DISALLOW_COPY_AND_ASSIGN(AddressValidatorTest);
 };
 
@@ -122,8 +129,10 @@
   ASSERT_EQ(sub_keys[0], first_state);
 }
 
-TEST_F(AddressValidatorTest, SubKeysNotLoaded) {
-  const std::string country_code = "ZZ";
+TEST_F(AddressValidatorTest, SubKeysNotExist) {
+  const std::string country_code = "OZ";
+
+  set_expected_status(AddressValidator::RULES_UNAVAILABLE);
 
   validator_->LoadRules(country_code);
   std::vector<std::string> sub_keys =
@@ -747,7 +756,7 @@
 }
 
 TEST_F(AddressValidatorTest,
-       DoNotValidateRequiredFieldsWithoutRulesWhenErorrIsFiltered) {
+       DoNotValidateRequiredFieldsWithoutRulesWhenErrorIsFiltered) {
   // Do not load the rules for JP.
   AddressData address;
   address.region_code = "JP";
diff --git a/third_party/material_design_icons/LICENSE b/third_party/material_design_icons/LICENSE
new file mode 100644
index 0000000..7a4a3ea
--- /dev/null
+++ b/third_party/material_design_icons/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
\ No newline at end of file
diff --git a/third_party/material_design_icons/OWNERS b/third_party/material_design_icons/OWNERS
new file mode 100644
index 0000000..ccddf8d
--- /dev/null
+++ b/third_party/material_design_icons/OWNERS
@@ -0,0 +1,2 @@
+lpromero@chromium.org
+sdefresne@chromium.org
diff --git a/third_party/material_design_icons/README.chromium b/third_party/material_design_icons/README.chromium
new file mode 100644
index 0000000..e16b880
--- /dev/null
+++ b/third_party/material_design_icons/README.chromium
@@ -0,0 +1,14 @@
+Name: Material Design Icons
+URL: https://github.com/google/material-design-icons
+Version: 0
+Revision: a6145e167b4a3a65640dd6279319cbc77a7e4e96
+License: Apache 2.0
+License File: LICENSE
+Security Critical: yes
+
+Description:
+Material design icons are the official icon set from Google that are designed
+under the material design guidelines.
+
+Local Modifications:
+None
diff --git a/third_party/polymer/v1_0/bower.json b/third_party/polymer/v1_0/bower.json
index 1e6d06a..bd9eea1 100644
--- a/third_party/polymer/v1_0/bower.json
+++ b/third_party/polymer/v1_0/bower.json
@@ -36,8 +36,6 @@
     "paper-behaviors": "PolymerElements/paper-behaviors#1.0.12",
     "paper-button": "PolymerElements/paper-button#1.0.13",
     "paper-checkbox": "PolymerElements/paper-checkbox#1.4.0",
-    "paper-dialog-behavior": "PolymerElements/paper-dialog-behavior#1.2.7",
-    "paper-dialog": "PolymerElements/paper-dialog#1.1.0",
     "paper-drawer-panel": "PolymerElements/paper-drawer-panel#1.0.10",
     "paper-fab": "PolymerElements/paper-fab#1.2.0",
     "paper-header-panel": "PolymerElements/paper-header-panel#1.1.6",
diff --git a/third_party/polymer/v1_0/components-chromium/paper-dialog-behavior/bower.json b/third_party/polymer/v1_0/components-chromium/paper-dialog-behavior/bower.json
deleted file mode 100644
index cbe17d3..0000000
--- a/third_party/polymer/v1_0/components-chromium/paper-dialog-behavior/bower.json
+++ /dev/null
@@ -1,40 +0,0 @@
-{
-  "name": "paper-dialog-behavior",
-  "version": "1.2.7",
-  "description": "Implements a behavior used for material design dialogs",
-  "authors": "The Polymer Authors",
-  "keywords": [
-    "web-components",
-    "polymer",
-    "dialog",
-    "overlay",
-    "behavior"
-  ],
-  "main": "paper-dialog-behavior.html",
-  "private": true,
-  "repository": {
-    "type": "git",
-    "url": "git://github.com/PolymerElements/paper-dialog-behavior"
-  },
-  "license": "http://polymer.github.io/LICENSE.txt",
-  "homepage": "https://github.com/PolymerElements/paper-dialog-behavior",
-  "ignore": [],
-  "dependencies": {
-    "iron-overlay-behavior": "PolymerElements/iron-overlay-behavior#^1.0.0",
-    "paper-styles": "PolymerElements/paper-styles#^1.1.0",
-    "polymer": "Polymer/polymer#^1.1.0"
-  },
-  "devDependencies": {
-    "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
-    "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
-    "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0",
-    "paper-button": "PolymerElements/paper-button#^1.0.0",
-    "paper-dialog-scrollable": "PolymerElements/paper-dialog-scrollable#^1.0.0",
-    "paper-dropdown-menu": "PolymerElements/paper-dropdown-menu#^1.0.0",
-    "paper-icon-button": "PolymerElements/paper-icon-button#^1.0.0",
-    "paper-item": "PolymerElements/paper-item#^1.0.0",
-    "paper-listbox": "PolymerElements/paper-listbox#^1.0.0",
-    "web-component-tester": "^4.0.0",
-    "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
-  }
-}
diff --git a/third_party/polymer/v1_0/components-chromium/paper-dialog-behavior/compiled_resources2.gyp b/third_party/polymer/v1_0/components-chromium/paper-dialog-behavior/compiled_resources2.gyp
deleted file mode 100644
index d5a26fd..0000000
--- a/third_party/polymer/v1_0/components-chromium/paper-dialog-behavior/compiled_resources2.gyp
+++ /dev/null
@@ -1,16 +0,0 @@
-# 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.
-#
-# NOTE: Created with generate_compiled_resources_gyp.py, please do not edit.
-{
-  'targets': [
-    {
-      'target_name': 'paper-dialog-behavior-extracted',
-      'dependencies': [
-        '../iron-overlay-behavior/compiled_resources2.gyp:iron-overlay-behavior-extracted',
-      ],
-      'includes': ['../../../../closure_compiler/compile_js2.gypi'],
-    },
-  ],
-}
diff --git a/third_party/polymer/v1_0/components-chromium/paper-dialog-behavior/paper-dialog-behavior-extracted.js b/third_party/polymer/v1_0/components-chromium/paper-dialog-behavior/paper-dialog-behavior-extracted.js
deleted file mode 100644
index 0dd39ee..0000000
--- a/third_party/polymer/v1_0/components-chromium/paper-dialog-behavior/paper-dialog-behavior-extracted.js
+++ /dev/null
@@ -1,123 +0,0 @@
-/**
-Use `Polymer.PaperDialogBehavior` and `paper-dialog-shared-styles.html` to implement a Material Design
-dialog.
-
-For example, if `<paper-dialog-impl>` implements this behavior:
-
-    <paper-dialog-impl>
-        <h2>Header</h2>
-        <div>Dialog body</div>
-        <div class="buttons">
-            <paper-button dialog-dismiss>Cancel</paper-button>
-            <paper-button dialog-confirm>Accept</paper-button>
-        </div>
-    </paper-dialog-impl>
-
-`paper-dialog-shared-styles.html` provide styles for a header, content area, and an action area for buttons.
-Use the `<h2>` tag for the header and the `buttons` class for the action area. You can use the
-`paper-dialog-scrollable` element (in its own repository) if you need a scrolling content area.
-
-Use the `dialog-dismiss` and `dialog-confirm` attributes on interactive controls to close the
-dialog. If the user dismisses the dialog with `dialog-confirm`, the `closingReason` will update
-to include `confirmed: true`.
-
-### Accessibility
-
-This element has `role="dialog"` by default. Depending on the context, it may be more appropriate
-to override this attribute with `role="alertdialog"`.
-
-If `modal` is set, the element will prevent the focus from exiting the element.
-It will also ensure that focus remains in the dialog.
-
-@hero hero.svg
-@demo demo/index.html
-@polymerBehavior Polymer.PaperDialogBehavior
-*/
-
-  Polymer.PaperDialogBehaviorImpl = {
-
-    hostAttributes: {
-      'role': 'dialog',
-      'tabindex': '-1'
-    },
-
-    properties: {
-
-      /**
-       * If `modal` is true, this implies `no-cancel-on-outside-click`, `no-cancel-on-esc-key` and `with-backdrop`.
-       */
-      modal: {
-        type: Boolean,
-        value: false
-      }
-
-    },
-
-    observers: [
-      '_modalChanged(modal, _readied)'
-    ],
-
-    listeners: {
-      'tap': '_onDialogClick'
-    },
-
-    ready: function () {
-      // Only now these properties can be read.
-      this.__prevNoCancelOnOutsideClick = this.noCancelOnOutsideClick;
-      this.__prevNoCancelOnEscKey = this.noCancelOnEscKey;
-      this.__prevWithBackdrop = this.withBackdrop;
-    },
-
-    _modalChanged: function(modal, readied) {
-      // modal implies noCancelOnOutsideClick, noCancelOnEscKey and withBackdrop.
-      // We need to wait for the element to be ready before we can read the
-      // properties values.
-      if (!readied) {
-        return;
-      }
-
-      if (modal) {
-        this.__prevNoCancelOnOutsideClick = this.noCancelOnOutsideClick;
-        this.__prevNoCancelOnEscKey = this.noCancelOnEscKey;
-        this.__prevWithBackdrop = this.withBackdrop;
-        this.noCancelOnOutsideClick = true;
-        this.noCancelOnEscKey = true;
-        this.withBackdrop = true;
-      } else {
-        // If the value was changed to false, let it false.
-        this.noCancelOnOutsideClick = this.noCancelOnOutsideClick &&
-          this.__prevNoCancelOnOutsideClick;
-        this.noCancelOnEscKey = this.noCancelOnEscKey &&
-          this.__prevNoCancelOnEscKey;
-        this.withBackdrop = this.withBackdrop && this.__prevWithBackdrop;
-      }
-    },
-
-    _updateClosingReasonConfirmed: function(confirmed) {
-      this.closingReason = this.closingReason || {};
-      this.closingReason.confirmed = confirmed;
-    },
-
-    /**
-     * Will dismiss the dialog if user clicked on an element with dialog-dismiss
-     * or dialog-confirm attribute.
-     */
-    _onDialogClick: function(event) {
-      // Search for the element with dialog-confirm or dialog-dismiss,
-      // from the root target until this (excluded).
-      var path = Polymer.dom(event).path;
-      for (var i = 0; i < path.indexOf(this); i++) {
-        var target = path[i];
-        if (target.hasAttribute && (target.hasAttribute('dialog-dismiss') || target.hasAttribute('dialog-confirm'))) {
-          this._updateClosingReasonConfirmed(target.hasAttribute('dialog-confirm'));
-          this.close();
-          event.stopPropagation();
-          break;
-        }
-      }
-    }
-
-  };
-
-  /** @polymerBehavior */
-  Polymer.PaperDialogBehavior = [Polymer.IronOverlayBehavior, Polymer.PaperDialogBehaviorImpl];
\ No newline at end of file
diff --git a/third_party/polymer/v1_0/components-chromium/paper-dialog-behavior/paper-dialog-behavior.html b/third_party/polymer/v1_0/components-chromium/paper-dialog-behavior/paper-dialog-behavior.html
deleted file mode 100644
index 0400742f..0000000
--- a/third_party/polymer/v1_0/components-chromium/paper-dialog-behavior/paper-dialog-behavior.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<!--
-@license
-Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
-This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
-The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
-The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
-Code distributed by Google as part of the polymer project is also
-subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
---><html><head><link rel="import" href="../polymer/polymer.html">
-<link rel="import" href="../iron-overlay-behavior/iron-overlay-behavior.html">
-
-</head><body><script src="paper-dialog-behavior-extracted.js"></script></body></html>
\ No newline at end of file
diff --git a/third_party/polymer/v1_0/components-chromium/paper-dialog-behavior/paper-dialog-common.css b/third_party/polymer/v1_0/components-chromium/paper-dialog-behavior/paper-dialog-common.css
deleted file mode 100644
index 560b0a5..0000000
--- a/third_party/polymer/v1_0/components-chromium/paper-dialog-behavior/paper-dialog-common.css
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
-@license
-Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
-This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
-The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
-The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
-Code distributed by Google as part of the polymer project is also
-subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-*/
-
-:host {
-  display: block;
-  margin: 24px 40px;
-
-  background: var(--paper-dialog-background-color, --primary-background-color);
-  color: var(--paper-dialog-color, --primary-text-color);
-
-  @apply(--paper-font-body1);
-  @apply(--shadow-elevation-16dp);
-  @apply(--paper-dialog);
-}
-
-:host > ::content > * {
-  margin-top: 20px;
-  padding: 0 24px;
-}
-
-:host > ::content > .no-padding {
-  padding: 0;
-}
-
-:host > ::content > *:first-child {
-  margin-top: 24px;
-}
-
-:host > ::content > *:last-child {
-  margin-bottom: 24px;
-}
-
-:host > ::content h2 {
-  position: relative;
-  margin: 0;
-  @apply(--paper-font-title);
-
-  @apply(--paper-dialog-title);
-}
-
-:host > ::content .buttons {
-  position: relative;
-  padding: 8px 8px 8px 24px;
-  margin: 0;
-
-  color: var(--paper-dialog-button-color, --primary-color);
-
-  @apply(--layout-horizontal);
-  @apply(--layout-end-justified);
-}
diff --git a/third_party/polymer/v1_0/components-chromium/paper-dialog-behavior/paper-dialog-shared-styles.html b/third_party/polymer/v1_0/components-chromium/paper-dialog-behavior/paper-dialog-shared-styles.html
deleted file mode 100644
index 35ea74b..0000000
--- a/third_party/polymer/v1_0/components-chromium/paper-dialog-behavior/paper-dialog-shared-styles.html
+++ /dev/null
@@ -1,83 +0,0 @@
-<!--
-@license
-Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
-This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
-The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
-The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
-Code distributed by Google as part of the polymer project is also
-subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
--->
-
-<link rel="import" href="../polymer/polymer.html">
-<link rel="import" href="../iron-flex-layout/iron-flex-layout.html">
-<link rel="import" href="../paper-styles/default-theme.html">
-<link rel="import" href="../paper-styles/typography.html">
-<link rel="import" href="../paper-styles/shadow.html">
-
-<!--
-### Styling
-
-The following custom properties and mixins are available for styling.
-
-Custom property | Description | Default
-----------------|-------------|----------
-`--paper-dialog-background-color` | Dialog background color                     | `--primary-background-color`
-`--paper-dialog-color`            | Dialog foreground color                     | `--primary-text-color`
-`--paper-dialog`                  | Mixin applied to the dialog                 | `{}`
-`--paper-dialog-title`            | Mixin applied to the title (`<h2>`) element | `{}`
-`--paper-dialog-button-color`     | Button area foreground color                | `--default-primary-color`
--->
-
-<dom-module id="paper-dialog-shared-styles">
-  <template>
-    <style>
-      :host {
-        display: block;
-        margin: 24px 40px;
-
-        background: var(--paper-dialog-background-color, --primary-background-color);
-        color: var(--paper-dialog-color, --primary-text-color);
-
-        @apply(--paper-font-body1);
-        @apply(--shadow-elevation-16dp);
-        @apply(--paper-dialog);
-      }
-
-      :host > ::content > * {
-        margin-top: 20px;
-        padding: 0 24px;
-      }
-
-      :host > ::content > .no-padding {
-        padding: 0;
-      }
-
-      :host > ::content > *:first-child {
-        margin-top: 24px;
-      }
-
-      :host > ::content > *:last-child {
-        margin-bottom: 24px;
-      }
-
-      :host > ::content h2 {
-        position: relative;
-        margin: 0;
-        @apply(--paper-font-title);
-
-        @apply(--paper-dialog-title);
-      }
-
-      :host > ::content .buttons {
-        position: relative;
-        padding: 8px 8px 8px 24px;
-        margin: 0;
-
-        color: var(--paper-dialog-button-color, --primary-color);
-
-        @apply(--layout-horizontal);
-        @apply(--layout-end-justified);
-      }
-    </style>
-  </template>
-</dom-module>
diff --git a/third_party/polymer/v1_0/components-chromium/paper-dialog/bower.json b/third_party/polymer/v1_0/components-chromium/paper-dialog/bower.json
deleted file mode 100644
index e7882a55..0000000
--- a/third_party/polymer/v1_0/components-chromium/paper-dialog/bower.json
+++ /dev/null
@@ -1,40 +0,0 @@
-{
-  "name": "paper-dialog",
-  "description": "A Material Design dialog",
-  "version": "1.1.0",
-  "authors": "The Polymer Authors",
-  "keywords": [
-    "web-components",
-    "polymer",
-    "dialog",
-    "overlay"
-  ],
-  "main": "paper-dialog.html",
-  "private": true,
-  "repository": {
-    "type": "git",
-    "url": "git://github.com/PolymerElements/paper-dialog"
-  },
-  "license": "http://polymer.github.io/LICENSE.txt",
-  "homepage": "https://github.com/PolymerElements/paper-dialog",
-  "ignore": [],
-  "dependencies": {
-    "neon-animation": "PolymerElements/neon-animation#^1.0.0",
-    "paper-dialog-behavior": "PolymerElements/paper-dialog-behavior#^1.0.0",
-    "iron-overlay-behavior": "PolymerElements/iron-overlay-behavior#^1.7.0",
-    "paper-styles": "PolymerElements/paper-styles#^1.0.0",
-    "polymer": "Polymer/polymer#^1.1.0"
-  },
-  "devDependencies": {
-    "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
-    "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
-    "paper-button": "PolymerElements/paper-button#^1.0.0",
-    "paper-dialog-scrollable": "PolymerElements/paper-dialog-scrollable#^1.0.0",
-    "paper-dropdown-menu": "PolymerElements/paper-dropdown-menu#^1.0.0",
-    "paper-item": "PolymerElements/paper-item#^1.0.0",
-    "paper-menu": "PolymerElements/paper-menu#^1.0.0",
-    "test-fixture": "PolymerElements/test-fixture#^1.0.0",
-    "web-component-tester": "^4.0.0",
-    "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
-  }
-}
diff --git a/third_party/polymer/v1_0/components-chromium/paper-dialog/compiled_resources2.gyp b/third_party/polymer/v1_0/components-chromium/paper-dialog/compiled_resources2.gyp
deleted file mode 100644
index f7d3cd7..0000000
--- a/third_party/polymer/v1_0/components-chromium/paper-dialog/compiled_resources2.gyp
+++ /dev/null
@@ -1,17 +0,0 @@
-# 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.
-#
-# NOTE: Created with generate_compiled_resources_gyp.py, please do not edit.
-{
-  'targets': [
-    {
-      'target_name': 'paper-dialog-extracted',
-      'dependencies': [
-        '../neon-animation/compiled_resources2.gyp:neon-animation-runner-behavior-extracted',
-        '../paper-dialog-behavior/compiled_resources2.gyp:paper-dialog-behavior-extracted',
-      ],
-      'includes': ['../../../../closure_compiler/compile_js2.gypi'],
-    },
-  ],
-}
diff --git a/third_party/polymer/v1_0/components-chromium/paper-dialog/paper-dialog-extracted.js b/third_party/polymer/v1_0/components-chromium/paper-dialog/paper-dialog-extracted.js
deleted file mode 100644
index 570cf42..0000000
--- a/third_party/polymer/v1_0/components-chromium/paper-dialog/paper-dialog-extracted.js
+++ /dev/null
@@ -1,36 +0,0 @@
-(function() {
-
-  Polymer({
-
-    is: 'paper-dialog',
-
-    behaviors: [
-      Polymer.PaperDialogBehavior,
-      Polymer.NeonAnimationRunnerBehavior
-    ],
-
-    listeners: {
-      'neon-animation-finish': '_onNeonAnimationFinish'
-    },
-
-    _renderOpened: function() {
-      this.cancelAnimation();
-      this.playAnimation('entry');
-    },
-
-    _renderClosed: function() {
-      this.cancelAnimation();
-      this.playAnimation('exit');
-    },
-
-    _onNeonAnimationFinish: function() {
-      if (this.opened) {
-        this._finishRenderOpened();
-      } else {
-        this._finishRenderClosed();
-      }
-    }
-
-  });
-
-})();
\ No newline at end of file
diff --git a/third_party/polymer/v1_0/components-chromium/paper-dialog/paper-dialog.html b/third_party/polymer/v1_0/components-chromium/paper-dialog/paper-dialog.html
deleted file mode 100644
index 8c40551..0000000
--- a/third_party/polymer/v1_0/components-chromium/paper-dialog/paper-dialog.html
+++ /dev/null
@@ -1,76 +0,0 @@
-<!--
-@license
-Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
-This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
-The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
-The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
-Code distributed by Google as part of the polymer project is also
-subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
---><html><head><link rel="import" href="../polymer/polymer.html">
-<link rel="import" href="../neon-animation/neon-animation-runner-behavior.html">
-<link rel="import" href="../paper-dialog-behavior/paper-dialog-behavior.html">
-<link rel="import" href="../paper-dialog-behavior/paper-dialog-shared-styles.html">
-<!--
-Material design: [Dialogs](https://www.google.com/design/spec/components/dialogs.html)
-
-`<paper-dialog>` is a dialog with Material Design styling and optional animations when it is
-opened or closed. It provides styles for a header, content area, and an action area for buttons.
-You can use the `<paper-dialog-scrollable>` element (in its own repository) if you need a scrolling
-content area. To autofocus a specific child element after opening the dialog, give it the `autofocus`
-attribute. See `Polymer.PaperDialogBehavior` and `Polymer.IronOverlayBehavior` for specifics.
-
-For example, the following code implements a dialog with a header, scrolling content area and
-buttons. Focus will be given to the `dialog-confirm` button when the dialog is opened.
-
-    <paper-dialog>
-      <h2>Header</h2>
-      <paper-dialog-scrollable>
-        Lorem ipsum...
-      </paper-dialog-scrollable>
-      <div class="buttons">
-        <paper-button dialog-dismiss>Cancel</paper-button>
-        <paper-button dialog-confirm autofocus>Accept</paper-button>
-      </div>
-    </paper-dialog>
-
-### Styling
-
-See the docs for `Polymer.PaperDialogBehavior` for the custom properties available for styling
-this element.
-
-### Animations
-
-Set the `entry-animation` and/or `exit-animation` attributes to add an animation when the dialog
-is opened or closed. See the documentation in
-[PolymerElements/neon-animation](https://github.com/PolymerElements/neon-animation) for more info.
-
-For example:
-
-    <link rel="import" href="components/neon-animation/animations/scale-up-animation.html">
-    <link rel="import" href="components/neon-animation/animations/fade-out-animation.html">
-
-    <paper-dialog entry-animation="scale-up-animation"
-                  exit-animation="fade-out-animation">
-      <h2>Header</h2>
-      <div>Dialog body</div>
-    </paper-dialog>
-
-### Accessibility
-
-See the docs for `Polymer.PaperDialogBehavior` for accessibility features implemented by this
-element.
-
-@group Paper Elements
-@element paper-dialog
-@hero hero.svg
-@demo demo/index.html
--->
-
-</head><body><dom-module id="paper-dialog">
-  <template>
-    <style include="paper-dialog-shared-styles"></style>
-    <content></content>
-  </template>
-</dom-module>
-
-<script src="paper-dialog-extracted.js"></script></body></html>
\ No newline at end of file
diff --git a/third_party/polymer/v1_0/components_summary.txt b/third_party/polymer/v1_0/components_summary.txt
index 61752d35..e63da14 100644
--- a/third_party/polymer/v1_0/components_summary.txt
+++ b/third_party/polymer/v1_0/components_summary.txt
@@ -202,18 +202,6 @@
 Revision: 1d1c9439fe3a056356233e04171fd9c62f0857fb
 Tree link: https://github.com/PolymerElements/paper-checkbox/tree/v1.4.0
 
-Name: paper-dialog
-Repository: https://github.com/PolymerElements/paper-dialog.git
-Tree: v1.1.0
-Revision: 7f31fa918fbd562b516eb262f1ed527dcaf7b7c0
-Tree link: https://github.com/PolymerElements/paper-dialog/tree/v1.1.0
-
-Name: paper-dialog-behavior
-Repository: https://github.com/PolymerElements/paper-dialog-behavior.git
-Tree: v1.2.7
-Revision: decc77ca55c0381cf01d7409ddf1eb966543e84e
-Tree link: https://github.com/PolymerElements/paper-dialog-behavior/tree/v1.2.7
-
 Name: paper-drawer-panel
 Repository: https://github.com/PolymerElements/paper-drawer-panel.git
 Tree: v1.0.10
diff --git a/tools/android/eclipse/.classpath b/tools/android/eclipse/.classpath
index 9722d0f..5c657c0d 100644
--- a/tools/android/eclipse/.classpath
+++ b/tools/android/eclipse/.classpath
@@ -226,7 +226,7 @@
     <classpathentry kind="src" path="out/Debug/remoting_apk/gen"/>
     <classpathentry kind="src" path="out/Debug/webview_instrumentation_test_apk/gen"/>
     <classpathentry kind="lib" path="third_party/android_tools/sdk/extras/google/gcm/gcm-client/dist/gcm.jar" sourcepath="third_party/android_tools/sdk/extras/google/gcm/gcm-client/src"/>
-    <classpathentry kind="lib" path="third_party/android_tools/sdk/platforms/android-25/android.jar" sourcepath="third_party/android_tools/sdk/sources/">
+    <classpathentry kind="lib" path="third_party/android_tools/sdk/platforms/android-26/android.jar" sourcepath="third_party/android_tools/sdk/sources/">
         <attributes>
             <attribute name="javadoc_location" value="http://developer.android.com/reference/"/>
         </attributes>
diff --git a/tools/gn/ninja_build_writer.cc b/tools/gn/ninja_build_writer.cc
index be55270..857b668 100644
--- a/tools/gn/ninja_build_writer.cc
+++ b/tools/gn/ninja_build_writer.cc
@@ -242,7 +242,7 @@
 }
 
 void NinjaBuildWriter::WriteNinjaRules() {
-  out_ << "ninja_required_version = 1.1.0\n\n";
+  out_ << "ninja_required_version = 1.7.2\n\n";
   out_ << "rule gn\n";
   out_ << "  command = " << GetSelfInvocationCommand(build_settings_) << "\n";
   out_ << "  description = Regenerating ninja files\n\n";
diff --git a/tools/grit/grit/format/chrome_messages_json.py b/tools/grit/grit/format/chrome_messages_json.py
old mode 100755
new mode 100644
index 27ac361..4c701c6
--- a/tools/grit/grit/format/chrome_messages_json.py
+++ b/tools/grit/grit/format/chrome_messages_json.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
 # Copyright (c) 2012 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.
@@ -10,6 +9,7 @@
 import re
 import types
 
+from grit import constants
 from grit import util
 from grit.node import message
 
@@ -31,6 +31,13 @@
       if id.startswith('IDR_') or id.startswith('IDS_'):
         id = id[4:]
 
+      translation_missing = child.GetCliques()[0].clique.get(lang) is None;
+      if (child.ShouldFallbackToEnglish() and translation_missing and
+          lang != constants.FAKE_BIDI):
+          # Skip the string if it's not translated. Chrome will fallback
+          # to English automatically.
+          continue
+
       loc_message = encoder.encode(child.ws_at_start + child.Translate(lang) +
                                    child.ws_at_end)
 
diff --git a/tools/grit/grit/format/chrome_messages_json_unittest.py b/tools/grit/grit/format/chrome_messages_json_unittest.py
index ec188cc..0a3ae2e 100755
--- a/tools/grit/grit/format/chrome_messages_json_unittest.py
+++ b/tools/grit/grit/format/chrome_messages_json_unittest.py
@@ -108,7 +108,8 @@
     """)
 
     buf = StringIO.StringIO()
-    build.RcBuilder.ProcessNode(root, DummyOutput('chrome_messages_json', 'fr'), buf)
+    build.RcBuilder.ProcessNode(root, DummyOutput('chrome_messages_json', 'fr'),
+                                buf)
     output = buf.getvalue()
     test = u"""
 {
@@ -122,6 +123,31 @@
 """
     self.assertEqual(test.strip(), output.strip())
 
+  def testSkipMissingTranslations(self):
+    grd = """<?xml version="1.0" encoding="UTF-8"?>
+<grit latest_public_release="2" current_release="3" source_lang_id="en"
+    base_dir="%s">
+  <outputs>
+  </outputs>
+  <release seq="3" allow_pseudo="False">
+    <messages fallback_to_english="true">
+      <message name="ID_HELLO_NO_TRANSLATION">Hello not translated</message>
+    </messages>
+  </release>
+</grit>"""
+    root = grd_reader.Parse(StringIO.StringIO(grd), dir=".")
+
+    buf = StringIO.StringIO()
+    build.RcBuilder.ProcessNode(root, DummyOutput('chrome_messages_json', 'fr'),
+                                buf)
+    output = buf.getvalue()
+    test = u"""
+{
+
+}
+"""
+    self.assertEqual(test.strip(), output.strip())
+
 
 class DummyOutput(object):
 
diff --git a/tools/gritsettings/resource_ids b/tools/gritsettings/resource_ids
index 539939d..19089bf 100644
--- a/tools/gritsettings/resource_ids
+++ b/tools/gritsettings/resource_ids
@@ -81,61 +81,61 @@
   # START chrome/browser section.
   "chrome/browser/browser_resources.grd": {
     "includes": [11000],
-    "structures": [11480],
+    "structures": [11510],
   },
   "chrome/browser/resources/component_extension_resources.grd": {
-    "includes": [11580],
-    "structures": [11830],
+    "includes": [11610],
+    "structures": [11860],
   },
   "chrome/browser/resources/invalidations_resources.grd": {
-    "includes": [11880],
+    "includes": [11910],
   },
   "chrome/browser/resources/md_policy/policy_resources.grd": {
-    "structures": [11890],
+    "structures": [11920],
   },
   "chrome/browser/resources/net_internals_resources.grd": {
-    "includes": [11930],
+    "includes": [11960],
   },
   "chrome/browser/resources/options_resources.grd": {
-    "includes": [11940],
-    "structures": [11950],
+    "includes": [11970],
+    "structures": [11980],
   },
   "chrome/browser/resources/password_manager_internals_resources.grd": {
-    "includes": [12010],
-  },
-  "chrome/browser/resources/quota_internals_resources.grd": {
-    "includes": [12020],
-  },
-  "chrome/browser/resources/settings/settings_resources_vulcanized.grd": {
     "includes": [12040],
   },
+  "chrome/browser/resources/quota_internals_resources.grd": {
+    "includes": [12050],
+  },
+  "chrome/browser/resources/settings/settings_resources_vulcanized.grd": {
+    "includes": [12070],
+  },
   "chrome/browser/resources/settings/settings_resources.grd": {
-    "structures": [12050],
+    "structures": [12080],
   },
   "chrome/browser/resources/sync_file_system_internals_resources.grd": {
-    "includes": [12550],
-  },
-  "chrome/browser/resources/task_scheduler_internals/resources.grd": {
     "includes": [12580],
   },
+  "chrome/browser/resources/task_scheduler_internals/resources.grd": {
+    "includes": [12610],
+  },
   "chrome/browser/resources/translate_internals_resources.grd": {
-    "includes": [12590],
+    "includes": [12620],
   },
   "chrome/browser/resources/webapks_ui_resources.grd": {
-    "includes": [12600],
+    "includes": [12630],
   },
   # END chrome/browser section.
 
   # START chrome/ miscellaneous section.
   "chrome/common/common_resources.grd": {
-    "includes": [12720],
+    "includes": [12750],
   },
   "chrome/renderer/resources/renderer_resources.grd": {
-    "includes": [12730],
-    "structures": [12810],
+    "includes": [12760],
+    "structures": [12840],
   },
   "chrome/test/data/webui_test_resources.grd": {
-    "includes": [12820],
+    "includes": [12850],
   },
   # END chrome/ miscellaneous section.
 
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index a6188e6..14c92ac 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -1122,7 +1122,18 @@
   <description>User closed the Chrome Home bottom sheet.</description>
 </action>
 
+<action name="Android.ChromeHome.ClosedByBackPress">
+  <owner>mdjones@chromium.org</owner>
+  <owner>twellington@chromium.org</owner>
+  <description>
+    User closed the Chrome Home bottom sheet by pressing the system back button.
+  </description>
+</action>
+
 <action name="Android.ChromeHome.ClosedByNTPCloseButton">
+  <obsolete>
+    Deprecated 6/2017. There is no longer an NTP UI with a close button.
+  </obsolete>
   <owner>mdjones@chromium.org</owner>
   <owner>twellington@chromium.org</owner>
   <description>
@@ -1170,6 +1181,16 @@
   </description>
 </action>
 
+<action name="Android.ChromeHome.NativeNTPShown">
+  <owner>mdjones@chromium.org</owner>
+  <owner>twellington@chromium.org</owner>
+  <description>
+    A user navigation instructed the NativePageFactory to create a native page
+    for the NTP. This may occur if the user has NTP URLs in a tab's navigation
+    history.
+  </description>
+</action>
+
 <action name="Android.ChromeHome.Opened">
   <obsolete>
     Deprecated 5/2017. Replaced by the versions with a suffix, which are more
@@ -5221,6 +5242,12 @@
   <description>The user triggered an event in in-product help.</description>
 </action>
 
+<action name="InProductHelp.NotifyEvent.IPH_DownloadPageScreenshot">
+  <owner>nyquist@chromium.org</owner>
+  <owner>xingliu@chromium.org</owner>
+  <description>The user triggered an event in in-product help.</description>
+</action>
+
 <action name="InProductHelp.NotifyEvent.IPH_IncognitoWindow">
   <owner>nyquist@chromium.org</owner>
   <owner>xingliu@chromium.org</owner>
@@ -5257,6 +5284,12 @@
   <description>The user triggered a used event in in-product help.</description>
 </action>
 
+<action name="InProductHelp.NotifyUsedEvent.IPH_DownloadPageScreenshot">
+  <owner>nyquist@chromium.org</owner>
+  <owner>xingliu@chromium.org</owner>
+  <description>The user triggered a used event in in-product help.</description>
+</action>
+
 <action name="InProductHelp.NotifyUsedEvent.IPH_IncognitoWindow">
   <owner>nyquist@chromium.org</owner>
   <owner>xingliu@chromium.org</owner>
@@ -5305,6 +5338,15 @@
   </description>
 </action>
 
+<action name="InProductHelp.ShouldTriggerHelpUI.IPH_DownloadPageScreenshot">
+  <owner>nyquist@chromium.org</owner>
+  <owner>xingliu@chromium.org</owner>
+  <description>
+    The feature engagement tracker tried to determine whether in-product help
+    should be shown to the user.
+  </description>
+</action>
+
 <action name="InProductHelp.ShouldTriggerHelpUI.IPH_IncognitoWindow">
   <owner>nyquist@chromium.org</owner>
   <owner>xingliu@chromium.org</owner>
@@ -5360,6 +5402,15 @@
 </action>
 
 <action
+    name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_DownloadPageScreenshot">
+  <owner>nyquist@chromium.org</owner>
+  <owner>xingliu@chromium.org</owner>
+  <description>
+    A user action that could have triggered In-Product Help did not.
+  </description>
+</action>
+
+<action
     name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_IncognitoWindow">
   <owner>nyquist@chromium.org</owner>
   <owner>xingliu@chromium.org</owner>
@@ -5405,6 +5456,13 @@
 </action>
 
 <action
+    name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_DownloadPageScreenshot">
+  <owner>nyquist@chromium.org</owner>
+  <owner>xingliu@chromium.org</owner>
+  <description>A user action triggered In-Product Help.</description>
+</action>
+
+<action
     name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_IncognitoWindow">
   <owner>nyquist@chromium.org</owner>
   <owner>xingliu@chromium.org</owner>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index d42f56a..120f787b 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -23293,6 +23293,7 @@
   <int value="1900529524" label="disable-touch-drag-drop"/>
   <int value="1905465678" label="ContextualSearchSingleActions:enabled"/>
   <int value="1906942630" label="enable-easy-unlock"/>
+  <int value="1910240042" label="enable-experimental-fullscreen-exit-ui"/>
   <int value="1913298816" label="OverlayScrollbar:enabled"/>
   <int value="1915178511" label="disable-blink-features"/>
   <int value="1927259098" label="TranslateLanguageByULP:enabled"/>
@@ -25522,6 +25523,13 @@
   <int value="8" label="chrome"/>
   <int value="9" label="blob"/>
   <int value="10" label="filesystem"/>
+  <int value="11" label="chrome-native"/>
+  <int value="12" label="chrome-search"/>
+  <int value="13" label="chrome-distiller"/>
+  <int value="14" label="chrome-devtools"/>
+  <int value="15" label="chrome-extension"/>
+  <int value="16" label="view-source"/>
+  <int value="17" label="externalfile"/>
 </enum>
 
 <enum name="NavigationWasServedFromCache">
@@ -26899,6 +26907,14 @@
   <int value="3" label="Data parsing failed"/>
 </enum>
 
+<enum name="OfflinePagesOfflineUsage">
+  <int value="0" label="Not used"/>
+  <int value="1" label="Started, but no pages loaded successfully"/>
+  <int value="2" label="Offline pages loaded only"/>
+  <int value="3" label="Online pages loaded only"/>
+  <int value="4" label="Both offlilne and online pages loaded"/>
+</enum>
+
 <enum name="OfflinePagesRedirectResult">
   <obsolete>
     Deprecated 2016-08.
@@ -35109,6 +35125,17 @@
   <int value="2054" label="rsa_pss_sha512"/>
 </enum>
 
+<enum name="SSLVersionInterferenceDetails">
+  <int value="0" label="Other"/>
+  <int value="1" label="Connection closed"/>
+  <int value="2" label="Connection reset"/>
+  <int value="3" label="access_denied alert"/>
+  <int value="4" label="bad_record_mac alert"/>
+  <int value="5" label="application data instead of handshake"/>
+  <int value="6" label="Version or cipher negotiation failed"/>
+  <int value="7" label="Protocol error"/>
+</enum>
+
 <enum name="StarsLaunchLocation">
   <int value="0" label="All Items"/>
   <int value="1" label="Uncategorized"/>
@@ -35958,6 +35985,12 @@
       label="Discarded a tab playing audio (included in the previous one)"/>
 </enum>
 
+<enum name="TabLoadingState">
+  <int value="0" label="Tab is not loading"/>
+  <int value="1" label="Tab is loading"/>
+  <int value="2" label="Tab is loaded"/>
+</enum>
+
 <enum name="TabRendererCrashStatus">
   <int value="0" label="Shown in foreground app"/>
   <int value="1" label="Hidden in foreground app"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index b20478a..6862fda 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -13101,6 +13101,20 @@
   </summary>
 </histogram>
 
+<histogram name="DNS.HostCache.RestoreSize" units="entries">
+  <owner>mgersh@chromium.org</owner>
+  <summary>
+    Number of HostCache entries persisted to disk, measured at restore time.
+  </summary>
+</histogram>
+
+<histogram name="DNS.HostCache.RestoreSuccess" enum="BooleanSuccess">
+  <owner>mgersh@chromium.org</owner>
+  <summary>
+    Whether the persisted HostCache entries were restored successfully.
+  </summary>
+</histogram>
+
 <histogram name="DNS.HostCache.Set" enum="DNS.HostCache.SetOutcome">
   <owner>mgersh@chromium.org</owner>
   <summary>The outcome of setting a DNS entry in the host cache.</summary>
@@ -21827,6 +21841,15 @@
   </summary>
 </histogram>
 
+<histogram name="Extensions.UpdateFrequencyCommandLineFlagIsUsed"
+    enum="BooleanPresent">
+  <owner>catmullings@chromium.org</owner>
+  <summary>
+    Logs whether or not the extensions-update-frequency command line flag is
+    used. Recorded at profile creation if extensions autoupdate is enabled.
+  </summary>
+</histogram>
+
 <histogram name="Extensions.UpdateOnLoad">
   <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
   <summary>
@@ -22110,7 +22133,7 @@
   <summary>Records the source that requested showing the feedback app.</summary>
 </histogram>
 
-<histogram name="FileBrowser.ChangeDirectory" enum="FileManagerRootType">
+<histogram name="FileBrowser.ChangeDirectory.RootType" enum="FileManagerRootType">
   <owner>yamaguchi@chromium.com</owner>
   <summary>
     Chrome OS File Browser: Counts the number of directory-changed events,
@@ -29734,7 +29757,10 @@
 
 <histogram name="Media.Midi.ResultOnShutdown" enum="MidiResult">
   <owner>toyoshim@chromium.org</owner>
-  <summary>The final status of MidiManager on browser shutdown.</summary>
+  <summary>
+    The final status of MidiManager on destruction. This can monitor unexpected
+    failures on initializing platform dependent MIDI stuff.
+  </summary>
 </histogram>
 
 <histogram name="Media.Midi.SendReceiveUsage" enum="MidiSendReceiveUsage">
@@ -29754,7 +29780,12 @@
 
 <histogram name="Media.Midi.Usage" enum="MidiUsage">
   <owner>toyoshim@chromium.org</owner>
-  <summary>MidiManager usages to understand the API use case.</summary>
+  <summary>
+    The MidiManager instance use count, but this is not intended to understand
+    the real API usage because this can be counted by feature scanning scripts
+    that are often used for footprinting. You may want to track SendReceiveUsage
+    to monitor only instances that actually send or receive MIDI messages.
+  </summary>
 </histogram>
 
 <histogram name="Media.MSE.AudioCodec" enum="MSECodec">
@@ -36118,6 +36149,14 @@
   </summary>
 </histogram>
 
+<histogram name="Net.Cronet.PrefsInitTime" units="ms">
+  <owner>mgersh@chromium.org</owner>
+  <summary>
+    Measures time spent creating the Cronet PrefService, including loading the
+    prefs from disk synchronously.
+  </summary>
+</histogram>
+
 <histogram name="Net.DailyContentLength" units="KB">
   <owner>bolian@chromium.org</owner>
   <summary>
@@ -41393,6 +41432,16 @@
   </summary>
 </histogram>
 
+<histogram name="Net.SSLVersionInterferenceDetails_TLS13Experiment"
+    enum="SSLVersionInterferenceDetails">
+  <owner>davidben@chromium.org</owner>
+  <owner>svaldez@chromium.org</owner>
+  <summary>
+    For each detected SSL version interference against a server in the initial
+    TLS 1.3 deployment, details on how the initial connection failed.
+  </summary>
+</histogram>
+
 <histogram name="Net.SSLVersionInterferenceError" enum="NetErrorCodes">
   <owner>davidben@chromium.org</owner>
   <summary>
@@ -46515,6 +46564,37 @@
   </summary>
 </histogram>
 
+<histogram name="NQE.BDPComputationKbps.OnECTComputation" units="Kbps">
+  <owner>devdeepray@chromium.org</owner>
+  <owner>tbansal@chromium.org</owner>
+  <summary>
+    The value of the downstream throughput used to compute the bandwidth delay
+    product. The 80th percentile throughput observation is used to calculate the
+    bandwidth delay product. This gets recorded everytime the BDP is computed.
+  </summary>
+</histogram>
+
+<histogram name="NQE.BDPComputationTransportRTT.OnECTComputation" units="ms">
+  <owner>devdeepray@chromium.org</owner>
+  <owner>tbansal@chromium.org</owner>
+  <summary>
+    The value of the TransportRTT used to compute the bandwidth delay product.
+    The 20th percentile TransportRTT observation is used to calculate the
+    bandwidth delay product. This gets recorded everytime the BDP is computed.
+  </summary>
+</histogram>
+
+<histogram name="NQE.BDPKbits.OnECTComputation" units="kbits">
+  <owner>devdeepray@chromium.org</owner>
+  <owner>tbansal@chromium.org</owner>
+  <summary>
+    An estimate of the bandwidth delay product which is computed on main-frame
+    requests. It is calculated using the 80th percentile throughput and 20th
+    percentile TransportRTT values whenever |ComputeEffectiveConnectionType| is
+    called and the throughput and TransportRTT estimates are available.
+  </summary>
+</histogram>
+
 <histogram name="NQE.CachedNetworkQualityAvailable" enum="BooleanAvailable">
   <owner>tbansal@chromium.org</owner>
   <owner>bengr@chromium.org</owner>
@@ -47786,6 +47866,21 @@
   <summary>Number of offline pages the user has. Android only.</summary>
 </histogram>
 
+<histogram name="OfflinePages.OfflineUsage" enum="OfflinePagesOfflineUsage">
+  <owner>dimich@chromium.org</owner>
+  <summary>
+    Enum-based buckets reflect the number of days the Chrome was used in each
+    specific way:
+    - Not used at all during whole day.
+    - Started, but failed to successfully navigate.
+    - Only navigated to offline pages locally saved on the device.
+    - Only navigated online.
+    - Navigated to both online and offline pages.
+    This data is accumulated locally and reported when connection is likely to
+    succeed (usually after successful online navigation).
+  </summary>
+</histogram>
+
 <histogram name="OfflinePages.OnlineOnOpen" enum="Boolean">
   <obsolete>
     Deprecated 5/2016. Offline pages no longer depend on bookmarks UI.
@@ -67227,6 +67322,17 @@
   </summary>
 </histogram>
 
+<histogram name="Search.ContextualSearchEntitySeen"
+    enum="ContextualSearchResultsSeen">
+  <owner>donnd@chromium.org</owner>
+  <owner>twellington@chromium.org</owner>
+  <summary>
+    Whether search results were seen as part of a Contextual Search when a tap
+    was on a word that we think is an entity. Recorded when Contextual Search is
+    dismissed. Implemented for Android.
+  </summary>
+</histogram>
+
 <histogram name="Search.ContextualSearchExitClosed"
     enum="ContextualSearchExitClosedStateChange">
   <owner>donnd@chromium.org</owner>
@@ -77828,6 +77934,23 @@
   </summary>
 </histogram>
 
+<histogram name="TabManager.SessionRestore.SwitchToTab" enum="TabLoadingState">
+  <owner>fmeawad@chromium.org</owner>
+  <summary>
+    The loading state of a tab at the time the user switched to it during a
+    session restore. The metric is only recorded when a tab is switched to from
+    another tab within the same tabstrip. As a result, there are two cases where
+    tabs are not included. The first case is when the initial forground tab is
+    shown, since it was not switched to from another tab. The second case is
+    when switching between different windows, either between two tabs in
+    different browser windows, or when switching to a different application and
+    switching back to the browser. The metric is only recorded when session
+    restore is actively loading tabs, which ends when either all tabs have been
+    loaded and their pages rendered, or tab loading needs to be deferred in
+    cases where the system is under memory pressure.
+  </summary>
+</histogram>
+
 <histogram name="Tabs.CountAtResume" units="tabs">
   <owner>lliabraa@chromium.org</owner>
   <summary>
@@ -82801,6 +82924,16 @@
   </summary>
 </histogram>
 
+<histogram name="WebApk.LaunchInterval" units="ms">
+  <owner>hanxi@chromium.org</owner>
+  <owner>pkotwicz@chromium.org</owner>
+  <owner>yfriedman@chromium.org</owner>
+  <summary>
+    Records the amount of time since the user last launched the WebAPK from the
+    homescreen. Not recorded on first launch.
+  </summary>
+</histogram>
+
 <histogram name="WebApk.OpenFromMenu" enum="WebApkOpenResult">
   <owner>hanxi@chromium.org</owner>
   <owner>pkotwicz@chromium.org</owner>
@@ -87210,11 +87343,17 @@
 </histogram>
 
 <histogram name="WinJumplist.OnFaviconDataAvailableDuration" units="ms">
+  <obsolete>
+    Obsolete 06/22/2017 as it's no longer needed.
+  </obsolete>
   <owner>chengx@chromium.org</owner>
   <summary>Time spent in OnFaviconDataAvailable().</summary>
 </histogram>
 
 <histogram name="WinJumplist.StartLoadingFaviconDuration" units="ms">
+  <obsolete>
+    Obsolete 06/22/2017 as it's no longer needed.
+  </obsolete>
   <owner>chengx@chromium.org</owner>
   <summary>Time spent in StartLoadingFavicon().</summary>
 </histogram>
@@ -90454,6 +90593,8 @@
   <suffix name="IPH_DataSaverDetail"
       label="In product help data saver detail."/>
   <suffix name="IPH_DownloadPage" label="In product help download page."/>
+  <suffix name="IPH_DownloadPageScreenshot"
+      label="In product help download page for screenshot."/>
   <suffix name="IPH_DownloadHome" label="In product help download home."/>
   <suffix name="IPH_NewTab" label="In product help new tab."/>
   <suffix name="IPH_IncognitoWindow" label="In product help incognito window."/>
@@ -93041,6 +93182,7 @@
   <affected-histogram name="OfflinePages.Background.FinalSavePageResult"/>
   <affected-histogram name="OfflinePages.Background.LoadingErrorStatusCode"/>
   <affected-histogram name="OfflinePages.Background.OfflinerRequestStatus"/>
+  <affected-histogram name="OfflinePages.Background.OffliningPreviewStatus"/>
   <affected-histogram name="OfflinePages.Background.TimeToCanceled"/>
   <affected-histogram name="OfflinePages.Background.TimeToSaved"/>
   <affected-histogram name="OfflinePages.Background.TimeToStart"/>
diff --git a/tools/perf/benchmark.csv b/tools/perf/benchmark.csv
index acc95884..81b19a1 100644
--- a/tools/perf/benchmark.csv
+++ b/tools/perf/benchmark.csv
@@ -94,6 +94,7 @@
 smoothness.tough_webgl_ad_cases,skyostil@chromium.org,
 smoothness.tough_webgl_cases,"kbr@chromium.org, zmo@chromium.org",
 speedometer,"bmeurer@chromium.org, mvstanton@chromium.org",
+speedometer2,"verwaest@chromium.org, mvstanton@chromium.org",
 start_with_ext.cold.blank_page,,
 start_with_ext.warm.blank_page,,
 start_with_url.cold.startup_pages,pasko@chromium.org,
diff --git a/tools/perf/benchmarks/blink_perf.py b/tools/perf/benchmarks/blink_perf.py
index 8e3c3f550..4362de7 100644
--- a/tools/perf/benchmarks/blink_perf.py
+++ b/tools/perf/benchmarks/blink_perf.py
@@ -292,8 +292,6 @@
     return StoryExpectations()
 
 
-@benchmark.Disabled('android', # http://crbug.com/685320
-                    'android-webview') # http://crbug.com/593200
 @benchmark.Owner(emails=['junov@chromium.org'])
 class BlinkPerfCanvas(_BlinkPerfBenchmark):
   tag = 'canvas'
@@ -349,7 +347,6 @@
     return StoryExpectations()
 
 
-@benchmark.Disabled('win8')  # http://crbug.com/462350
 @benchmark.Owner(emails=['eae@chromium.org'])
 class BlinkPerfLayout(_BlinkPerfBenchmark):
   tag = 'layout'
@@ -376,7 +373,6 @@
     return StoryExpectations()
 
 
-@benchmark.Disabled('win')  # crbug.com/488493
 @benchmark.Owner(emails=['jbroman@chromium.org',
                          'yukishiino@chromium.org',
                          'haraken@chromium.org'])
diff --git a/tools/perf_expectations/perf_expectations.json b/tools/perf_expectations/perf_expectations.json
index ce4981c..fed45a7 100644
--- a/tools/perf_expectations/perf_expectations.json
+++ b/tools/perf_expectations/perf_expectations.json
@@ -1,8 +1,8 @@
-{"linux-release-64/sizes/chrome-si/initializers": {"reva": 364170, "revb": 364170, "type": "absolute", "better": "lower", "improve": 7, "regress": 7, "tolerance": 0, "sha1": "de779422"},
- "linux-release-64/sizes/nacl_helper-si/initializers": {"reva": 271321, "revb": 271321, "type": "absolute", "better": "lower", "improve": 5, "regress": 7, "sha1": "f29296a1"},
+{"linux-release-64/sizes/chrome-si/initializers": {"reva": 480969, "revb": 480969, "type": "absolute", "better": "lower", "improve": 8, "regress": 8, "tolerance": 0, "sha1": "de779422"},
+ "linux-release-64/sizes/nacl_helper-si/initializers": {"reva": 480969, "revb": 480969, "type": "absolute", "better": "lower", "improve": 6, "regress": 8, "sha1": "f29296a1"},
  "linux-release-64/sizes/nacl_helper_bootstrap-si/initializers": {"reva": 114822, "revb": 115019, "type": "absolute", "better": "lower", "improve": 0, "regress": 0, "sha1": "228221af"},
- "linux-release/sizes/chrome-si/initializers": {"reva": 281717, "revb": 281717, "type": "absolute", "better": "lower", "improve": 8, "regress": 8, "tolerance": 0, "sha1": "b639bbc4"},
- "linux-release/sizes/nacl_helper-si/initializers": {"reva": 271321, "revb": 271321, "type": "absolute", "better": "lower", "improve": 6, "regress": 8, "sha1": "3394be7f"},
+ "linux-release/sizes/chrome-si/initializers": {"reva": 480969, "revb": 480969, "type": "absolute", "better": "lower", "improve": 9, "regress": 9, "tolerance": 0, "sha1": "b639bbc4"},
+ "linux-release/sizes/nacl_helper-si/initializers": {"reva": 480969, "revb": 480969, "type": "absolute", "better": "lower", "improve": 7, "regress": 9, "sha1": "3394be7f"},
  "linux-release/sizes/nacl_helper_bootstrap-si/initializers": {"reva": 114822, "revb": 115019, "type": "absolute", "better": "lower", "improve": 0, "regress": 0, "sha1": "dd908f29"},
  "mac-release/sizes/chrome-si/initializers": {"reva": 281731, "revb": 281731, "type": "absolute", "better": "lower", "improve": 0, "regress": 0, "tolerance": 0, "sha1": "01759b7f"},
  "load": true
diff --git a/ui/android/delegated_frame_host_android.cc b/ui/android/delegated_frame_host_android.cc
index e1c9cc98..396c4324a 100644
--- a/ui/android/delegated_frame_host_android.cc
+++ b/ui/android/delegated_frame_host_android.cc
@@ -170,7 +170,7 @@
 }
 
 void DelegatedFrameHostAndroid::DidReceiveCompositorFrameAck(
-    const cc::ReturnedResourceArray& resources) {
+    const std::vector<cc::ReturnedResource>& resources) {
   client_->ReclaimResources(resources);
   client_->DidReceiveCompositorFrameAck();
 }
@@ -180,7 +180,7 @@
 }
 
 void DelegatedFrameHostAndroid::ReclaimResources(
-    const cc::ReturnedResourceArray& resources) {
+    const std::vector<cc::ReturnedResource>& resources) {
   client_->ReclaimResources(resources);
 }
 
diff --git a/ui/android/delegated_frame_host_android.h b/ui/android/delegated_frame_host_android.h
index 0e0991e6..e2dd6569 100644
--- a/ui/android/delegated_frame_host_android.h
+++ b/ui/android/delegated_frame_host_android.h
@@ -36,7 +36,7 @@
     virtual void SetBeginFrameSource(
         cc::BeginFrameSource* begin_frame_source) = 0;
     virtual void DidReceiveCompositorFrameAck() = 0;
-    virtual void ReclaimResources(const cc::ReturnedResourceArray&) = 0;
+    virtual void ReclaimResources(const std::vector<cc::ReturnedResource>&) = 0;
   };
 
   DelegatedFrameHostAndroid(ViewAndroid* view,
@@ -75,9 +75,10 @@
  private:
   // cc::CompositorFrameSinkSupportClient implementation.
   void DidReceiveCompositorFrameAck(
-      const cc::ReturnedResourceArray& resources) override;
+      const std::vector<cc::ReturnedResource>& resources) override;
   void OnBeginFrame(const cc::BeginFrameArgs& args) override;
-  void ReclaimResources(const cc::ReturnedResourceArray& resources) override;
+  void ReclaimResources(
+      const std::vector<cc::ReturnedResource>& resources) override;
   void WillDrawSurface(const cc::LocalSurfaceId& local_surface_id,
                        const gfx::Rect& damage_rect) override;
 
diff --git a/ui/android/java/src/org/chromium/ui/gl/SurfaceTextureListener.java b/ui/android/java/src/org/chromium/ui/gl/SurfaceTextureListener.java
index dc464a5..1423ab61 100644
--- a/ui/android/java/src/org/chromium/ui/gl/SurfaceTextureListener.java
+++ b/ui/android/java/src/org/chromium/ui/gl/SurfaceTextureListener.java
@@ -7,11 +7,13 @@
 import android.graphics.SurfaceTexture;
 
 import org.chromium.base.annotations.JNINamespace;
+import org.chromium.base.annotations.MainDex;
 
 /**
  * Listener to an android SurfaceTexture object for frame availability.
  */
 @JNINamespace("gl")
+@MainDex
 class SurfaceTextureListener implements SurfaceTexture.OnFrameAvailableListener {
     // Used to determine the class instance to dispatch the native call to.
     private final long mNativeSurfaceTextureListener;
diff --git a/ui/app_list/DEPS b/ui/app_list/DEPS
index 18ae5370..61a5e23 100644
--- a/ui/app_list/DEPS
+++ b/ui/app_list/DEPS
@@ -1,6 +1,7 @@
 include_rules = [
   "+components/keyed_service/core",
   "+components/sync",
+  "+components/wallpaper",
   "+mojo/public/cpp",
   "+skia",
   "+third_party/google_toolbox_for_mac/src",
diff --git a/ui/aura/local/layer_tree_frame_sink_local.cc b/ui/aura/local/layer_tree_frame_sink_local.cc
index f2bb69b..174dd676 100644
--- a/ui/aura/local/layer_tree_frame_sink_local.cc
+++ b/ui/aura/local/layer_tree_frame_sink_local.cc
@@ -92,7 +92,7 @@
 }
 
 void LayerTreeFrameSinkLocal::DidReceiveCompositorFrameAck(
-    const cc::ReturnedResourceArray& resources) {
+    const std::vector<cc::ReturnedResource>& resources) {
   DCHECK(thread_checker_);
   DCHECK(thread_checker_->CalledOnValidThread());
   if (!client_)
@@ -109,7 +109,7 @@
 }
 
 void LayerTreeFrameSinkLocal::ReclaimResources(
-    const cc::ReturnedResourceArray& resources) {
+    const std::vector<cc::ReturnedResource>& resources) {
   DCHECK(thread_checker_);
   DCHECK(thread_checker_->CalledOnValidThread());
   if (!client_)
diff --git a/ui/aura/local/layer_tree_frame_sink_local.h b/ui/aura/local/layer_tree_frame_sink_local.h
index 611eb40..55d05fe 100644
--- a/ui/aura/local/layer_tree_frame_sink_local.h
+++ b/ui/aura/local/layer_tree_frame_sink_local.h
@@ -47,9 +47,10 @@
 
   // cc::CompositorFrameSinkSupportClient:
   void DidReceiveCompositorFrameAck(
-      const cc::ReturnedResourceArray& resources) override;
+      const std::vector<cc::ReturnedResource>& resources) override;
   void OnBeginFrame(const cc::BeginFrameArgs& args) override;
-  void ReclaimResources(const cc::ReturnedResourceArray& resources) override;
+  void ReclaimResources(
+      const std::vector<cc::ReturnedResource>& resources) override;
   void WillDrawSurface(const cc::LocalSurfaceId& local_surface_id,
                        const gfx::Rect& damage_rect) override {}
 
diff --git a/ui/aura/window_event_dispatcher.cc b/ui/aura/window_event_dispatcher.cc
index e8eb94d6..b6088e1 100644
--- a/ui/aura/window_event_dispatcher.cc
+++ b/ui/aura/window_event_dispatcher.cc
@@ -174,9 +174,10 @@
 
 DispatchDetails WindowEventDispatcher::DispatchMouseExitAtPoint(
     Window* window,
-    const gfx::Point& point) {
+    const gfx::Point& point,
+    int event_flags) {
   ui::MouseEvent event(ui::ET_MOUSE_EXITED, point, point, ui::EventTimeForNow(),
-                       ui::EF_NONE, ui::EF_NONE);
+                       event_flags, ui::EF_NONE);
   return DispatchMouseEnterOrExit(window, event, ui::ET_MOUSE_EXITED);
 }
 
diff --git a/ui/aura/window_event_dispatcher.h b/ui/aura/window_event_dispatcher.h
index fd998c3..9bd63a7 100644
--- a/ui/aura/window_event_dispatcher.h
+++ b/ui/aura/window_event_dispatcher.h
@@ -75,11 +75,13 @@
   void DispatchCancelModeEvent();
 
   // Dispatches a ui::ET_MOUSE_EXITED event at |point| to the |target|
-  // If the |target| is NULL, we will dispatch the event to the root-window
+  // If the |target| is NULL, we will dispatch the event to the root-window.
+  // |event_flags| will be set on the dispatched exit event.
   // TODO(beng): needed only for WTH::OnCursorVisibilityChanged().
-  ui::EventDispatchDetails DispatchMouseExitAtPoint(Window* target,
-                                                    const gfx::Point& point)
-      WARN_UNUSED_RESULT;
+  ui::EventDispatchDetails DispatchMouseExitAtPoint(
+      Window* target,
+      const gfx::Point& point,
+      int event_flags = ui::EF_NONE) WARN_UNUSED_RESULT;
 
   // Gesture Recognition -------------------------------------------------------
 
diff --git a/ui/aura/window_event_dispatcher_unittest.cc b/ui/aura/window_event_dispatcher_unittest.cc
index 58efc20b..b02fde1 100644
--- a/ui/aura/window_event_dispatcher_unittest.cc
+++ b/ui/aura/window_event_dispatcher_unittest.cc
@@ -1205,6 +1205,9 @@
   int translated_y = mouse_location.y() - window_origin.y();
   gfx::Point translated_point(translated_x, translated_y);
   EXPECT_EQ(recorder.mouse_location(0).ToString(), translated_point.ToString());
+
+  // Verify the mouse exit with ui::EF_CURSOR_HIDE flags.
+  EXPECT_TRUE(recorder.mouse_event_flags()[0] & ui::EF_CURSOR_HIDE);
   root_window()->RemovePreTargetHandler(&recorder);
 }
 
diff --git a/ui/aura/window_tree_host.cc b/ui/aura/window_tree_host.cc
index f8a6519..25a8505 100644
--- a/ui/aura/window_tree_host.cc
+++ b/ui/aura/window_tree_host.cc
@@ -153,7 +153,8 @@
   // will trigger its own mouse enter.
   if (!show) {
     ui::EventDispatchDetails details = dispatcher()->DispatchMouseExitAtPoint(
-        nullptr, dispatcher()->GetLastMouseLocationInRoot());
+        nullptr, dispatcher()->GetLastMouseLocationInRoot(),
+        ui::EF_CURSOR_HIDE);
     if (details.dispatcher_destroyed)
       return;
   }
diff --git a/ui/base/ime/chromeos/input_method_util.cc b/ui/base/ime/chromeos/input_method_util.cc
index c903ae5..f93231a 100644
--- a/ui/base/ime/chromeos/input_method_util.cc
+++ b/ui/base/ime/chromeos/input_method_util.cc
@@ -378,13 +378,23 @@
   ResetInputMethods(default_input_methods);
 
   // Initialize a map from English string to Chrome string resource ID as well.
+  // Since this array is write-once, initialize a flat map in one step with a
+  // given vector storage.
+  //
+  // TODO(brettw) this could be optimized further to binary search in the
+  // static data, avoiding this up-front cost.
+  std::vector<EnglishToIDMap::value_type> map_storage;
+  map_storage.reserve(kEnglishToResourceIdArraySize);
   for (size_t i = 0; i < kEnglishToResourceIdArraySize; ++i) {
     const EnglishToResouceId& map_entry = kEnglishToResourceIdArray[i];
-    const bool result = english_to_resource_id_.insert(std::make_pair(
-        map_entry.english_string_from_ibus, map_entry.resource_id)).second;
-    DCHECK(result) << "Duplicated string is found: "
-                   << map_entry.english_string_from_ibus;
+    map_storage.emplace_back(map_entry.english_string_from_ibus,
+                             map_entry.resource_id);
   }
+
+  english_to_resource_id_ =
+      EnglishToIDMap(std::move(map_storage), base::KEEP_FIRST_OF_DUPES);
+  DCHECK(english_to_resource_id_.size() == kEnglishToResourceIdArraySize)
+      << "Duplicate string is found";
 }
 
 InputMethodUtil::~InputMethodUtil() {}
@@ -413,7 +423,7 @@
   // to get the translated string.
   std::string key_string = extension_ime_util::MaybeGetLegacyXkbId(
       english_string);
-  HashType::const_iterator iter = english_to_resource_id_.find(key_string);
+  auto iter = english_to_resource_id_.find(key_string);
 
   if (iter == english_to_resource_id_.end()) {
     // TODO(yusukes): Write Autotest which checks if all display names and all
diff --git a/ui/base/ime/chromeos/input_method_util.h b/ui/base/ime/chromeos/input_method_util.h
index 06f886f..36565a7 100644
--- a/ui/base/ime/chromeos/input_method_util.h
+++ b/ui/base/ime/chromeos/input_method_util.h
@@ -11,7 +11,7 @@
 #include <string>
 #include <vector>
 
-#include "base/containers/hash_tables.h"
+#include "base/containers/flat_map.h"
 #include "base/macros.h"
 #include "base/strings/string16.h"
 #include "base/threading/thread_checker.h"
@@ -206,8 +206,8 @@
   LanguageCodeToIdsMap language_code_to_ids_;
   InputMethodIdToDescriptorMap id_to_descriptor_;
 
-  typedef base::hash_map<std::string, int> HashType;
-  HashType english_to_resource_id_;
+  using EnglishToIDMap = base::flat_map<std::string, int>;
+  EnglishToIDMap english_to_resource_id_;
 
   InputMethodDelegate* delegate_;
 
diff --git a/ui/compositor/compositor.cc b/ui/compositor/compositor.cc
index a29f0e3..01c52ef 100644
--- a/ui/compositor/compositor.cc
+++ b/ui/compositor/compositor.cc
@@ -34,7 +34,6 @@
 #include "cc/surfaces/surface_manager.h"
 #include "cc/trees/layer_tree_host.h"
 #include "cc/trees/layer_tree_settings.h"
-#include "components/viz/host/host_frame_sink_manager.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/compositor/compositor_observer.h"
 #include "ui/compositor/compositor_switches.h"
@@ -201,13 +200,12 @@
 
   context_factory_->RemoveCompositor(this);
   if (context_factory_private_) {
-    auto* manager = context_factory_private_->GetHostFrameSinkManager();
+    auto* manager = context_factory_private_->GetSurfaceManager();
     for (auto& client : child_frame_sinks_) {
       DCHECK(client.is_valid());
       manager->UnregisterFrameSinkHierarchy(frame_sink_id_, client);
     }
-    context_factory_private_->GetSurfaceManager()->InvalidateFrameSinkId(
-        frame_sink_id_);
+    manager->InvalidateFrameSinkId(frame_sink_id_);
   }
 }
 
@@ -218,8 +216,8 @@
 void Compositor::AddFrameSink(const cc::FrameSinkId& frame_sink_id) {
   if (!context_factory_private_)
     return;
-  context_factory_private_->GetHostFrameSinkManager()
-      ->RegisterFrameSinkHierarchy(frame_sink_id_, frame_sink_id);
+  context_factory_private_->GetSurfaceManager()->RegisterFrameSinkHierarchy(
+      frame_sink_id_, frame_sink_id);
   child_frame_sinks_.insert(frame_sink_id);
 }
 
@@ -229,8 +227,8 @@
   auto it = child_frame_sinks_.find(frame_sink_id);
   DCHECK(it != child_frame_sinks_.end());
   DCHECK(it->is_valid());
-  context_factory_private_->GetHostFrameSinkManager()
-      ->UnregisterFrameSinkHierarchy(frame_sink_id_, *it);
+  context_factory_private_->GetSurfaceManager()->UnregisterFrameSinkHierarchy(
+      frame_sink_id_, *it);
   child_frame_sinks_.erase(it);
 }
 
diff --git a/ui/compositor/layer.h b/ui/compositor/layer.h
index 0c2a0e8..10533a9 100644
--- a/ui/compositor/layer.h
+++ b/ui/compositor/layer.h
@@ -40,8 +40,6 @@
 class SolidColorLayer;
 class SurfaceLayer;
 class TextureLayer;
-struct ReturnedResource;
-typedef std::vector<ReturnedResource> ReturnedResourceArray;
 }
 
 namespace ui {
diff --git a/ui/events/event_constants.h b/ui/events/event_constants.h
index c773662..0630589 100644
--- a/ui/events/event_constants.h
+++ b/ui/events/event_constants.h
@@ -138,6 +138,9 @@
                                      // touch accessibility mode.
   EF_DIRECT_INPUT = 1 << 20,         // Mouse event coming from direct,
                                      // on-screen input.
+  EF_CURSOR_HIDE = 1 << 21,          // Indicates this mouse event is generated
+                                     // because the cursor was just hidden. This
+                                     // can be used to update hover state.
 };
 
 // Result of dispatching an event.
diff --git a/ui/file_manager/file_manager/foreground/js/navigation_uma.js b/ui/file_manager/file_manager/foreground/js/navigation_uma.js
index 4b20782..e6c082db 100644
--- a/ui/file_manager/file_manager/foreground/js/navigation_uma.js
+++ b/ui/file_manager/file_manager/foreground/js/navigation_uma.js
@@ -60,5 +60,5 @@
  * @param {!FileEntry} entry the new directory
  */
 NavigationUma.prototype.onDirectoryChanged = function(entry) {
-  this.exportRootType_(entry, 'FileBrowser.ChangeDirectory.RootType');
+  this.exportRootType_(entry, 'ChangeDirectory.RootType');
 };
diff --git a/ui/gfx/native_widget_types.h b/ui/gfx/native_widget_types.h
index 517bd40..fbe0fef 100644
--- a/ui/gfx/native_widget_types.h
+++ b/ui/gfx/native_widget_types.h
@@ -133,6 +133,12 @@
 typedef ui::ViewAndroid* NativeView;
 typedef ui::WindowAndroid* NativeWindow;
 typedef jobject NativeEvent;
+#elif defined(OS_FUCHSIA)
+// TODO(fuchsia): Update when we have a plan for UI on Fuchsia.
+typedef void* NativeCursor;
+typedef void* NativeView;
+typedef void* NativeWindow;
+typedef void* NativeEvent;
 #else
 #error Unknown build environment.
 #endif
@@ -197,6 +203,10 @@
 #elif defined(USE_OZONE)
 typedef int32_t AcceleratedWidget;
 constexpr AcceleratedWidget kNullAcceleratedWidget = 0;
+#elif defined(OS_FUCHSIA)
+// TODO(fuchsia): Update when we have a plan for UI on Fuchsia.
+typedef void* AcceleratedWidget;
+constexpr AcceleratedWidget kNullAcceleratedWidget = 0;
 #else
 #error unknown platform
 #endif
diff --git a/ui/gl/gl_context_egl.cc b/ui/gl/gl_context_egl.cc
index 2fbfe08..63cdb22 100644
--- a/ui/gl/gl_context_egl.cc
+++ b/ui/gl/gl_context_egl.cc
@@ -197,7 +197,8 @@
 }
 
 bool GLContextEGL::MakeCurrent(GLSurface* surface) {
-  DCHECK(context_);
+  // TODO(sunnyps): Revert to DCHECK after crbug.com/724999 is fixed.
+  CHECK(context_);
   if (IsCurrent(surface))
       return true;
 
@@ -253,14 +254,16 @@
 }
 
 bool GLContextEGL::IsCurrent(GLSurface* surface) {
-  DCHECK(context_);
+  // TODO(sunnyps): Revert to DCHECK after crbug.com/724999 is fixed.
+  CHECK(context_);
 
   bool native_context_is_current = context_ == eglGetCurrentContext();
 
   // If our context is current then our notion of which GLContext is
   // current must be correct. On the other hand, third-party code
   // using OpenGL might change the current context.
-  DCHECK(!native_context_is_current || (GetRealCurrent() == this));
+  // TODO(sunnyps): Revert to DCHECK after crbug.com/724999 is fixed.
+  CHECK(!native_context_is_current || (GetRealCurrent() == this));
 
   if (!native_context_is_current)
     return false;
diff --git a/ui/message_center/views/notification_header_view.cc b/ui/message_center/views/notification_header_view.cc
index 0911609..7a4fa5d 100644
--- a/ui/message_center/views/notification_header_view.cc
+++ b/ui/message_center/views/notification_header_view.cc
@@ -14,6 +14,9 @@
 #include "ui/message_center/vector_icons.h"
 #include "ui/message_center/views/padded_button.h"
 #include "ui/strings/grit/ui_strings.h"
+#include "ui/views/animation/flood_fill_ink_drop_ripple.h"
+#include "ui/views/animation/ink_drop_highlight.h"
+#include "ui/views/animation/ink_drop_impl.h"
 #include "ui/views/controls/button/image_button.h"
 #include "ui/views/controls/image_view.h"
 #include "ui/views/controls/label.h"
@@ -33,10 +36,24 @@
 // Bullet character. The divider symbol between different parts of the header.
 constexpr base::char16 kNotificationHeaderDividerSymbol = 0x2022;
 
+// Base ink drop color of action buttons.
+const SkColor kInkDropBaseColor = SkColorSetRGB(0x0, 0x0, 0x0);
+// Ripple ink drop opacity of action buttons.
+constexpr float kInkDropRippleVisibleOpacity = 0.08f;
+// Highlight (hover) ink drop opacity of action buttons.
+constexpr float kInkDropHighlightVisibleOpacity = 0.08f;
+
 }  // namespace
 
 NotificationHeaderView::NotificationHeaderView(views::ButtonListener* listener)
     : views::CustomButton(listener) {
+  SetInkDropMode(InkDropMode::ON);
+  set_has_ink_drop_action_on_click(true);
+  set_animate_on_state_change(true);
+  set_notify_enter_exit_on_child(true);
+  set_ink_drop_base_color(kInkDropBaseColor);
+  set_ink_drop_visible_opacity(kInkDropRippleVisibleOpacity);
+
   views::BoxLayout* layout = new views::BoxLayout(
       views::BoxLayout::kHorizontal, kHeaderPadding, kHeaderHorizontalSpacing);
   layout->set_cross_axis_alignment(
@@ -184,6 +201,30 @@
   return close_button_enabled_;
 }
 
+std::unique_ptr<views::InkDrop> NotificationHeaderView::CreateInkDrop() {
+  auto ink_drop = base::MakeUnique<views::InkDropImpl>(this, size());
+  ink_drop->SetAutoHighlightMode(
+      views::InkDropImpl::AutoHighlightMode::SHOW_ON_RIPPLE);
+  ink_drop->SetShowHighlightOnHover(false);
+  return ink_drop;
+}
+
+std::unique_ptr<views::InkDropRipple>
+NotificationHeaderView::CreateInkDropRipple() const {
+  return base::MakeUnique<views::FloodFillInkDropRipple>(
+      size(), GetInkDropCenterBasedOnLastEvent(), GetInkDropBaseColor(),
+      ink_drop_visible_opacity());
+}
+
+std::unique_ptr<views::InkDropHighlight>
+NotificationHeaderView::CreateInkDropHighlight() const {
+  auto highlight = base::MakeUnique<views::InkDropHighlight>(
+      size(), kInkDropSmallCornerRadius,
+      gfx::RectF(GetLocalBounds()).CenterPoint(), GetInkDropBaseColor());
+  highlight->set_visible_opacity(kInkDropHighlightVisibleOpacity);
+  return highlight;
+}
+
 void NotificationHeaderView::UpdateControlButtonsVisibility() {
   settings_button_->SetVisible(settings_button_enabled_ &&
                                is_control_buttons_visible_);
diff --git a/ui/message_center/views/notification_header_view.h b/ui/message_center/views/notification_header_view.h
index 640f6be..addc8d19 100644
--- a/ui/message_center/views/notification_header_view.h
+++ b/ui/message_center/views/notification_header_view.h
@@ -34,6 +34,12 @@
   bool IsCloseButtonEnabled();
   bool IsCloseButtonFocused();
 
+  // CustomButton override:
+  std::unique_ptr<views::InkDrop> CreateInkDrop() override;
+  std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override;
+  std::unique_ptr<views::InkDropHighlight> CreateInkDropHighlight()
+      const override;
+
   views::ImageButton* expand_button() { return expand_button_; }
   views::ImageButton* settings_button() { return settings_button_; }
   views::ImageButton* close_button() { return close_button_; }
diff --git a/ui/views/controls/prefix_selector.cc b/ui/views/controls/prefix_selector.cc
index f9fae71..05fe33a 100644
--- a/ui/views/controls/prefix_selector.cc
+++ b/ui/views/controls/prefix_selector.cc
@@ -18,14 +18,6 @@
 
 const int64_t kTimeBeforeClearingMS = 1000;
 
-void ConvertRectToScreen(const views::View* src, gfx::Rect* r) {
-  DCHECK(src);
-
-  gfx::Point new_origin = r->origin();
-  views::View::ConvertPointToScreen(src, &new_origin);
-  r->set_origin(new_origin);
-}
-
 }  // namespace
 
 PrefixSelector::PrefixSelector(PrefixDelegate* delegate, View* host_view)
@@ -81,7 +73,7 @@
   gfx::Rect rect(host_view_->GetVisibleBounds().origin(), gfx::Size());
   // TextInputClient::GetCaretBounds is expected to return a value in screen
   // coordinates.
-  ConvertRectToScreen(host_view_, &rect);
+  views::View::ConvertRectToScreen(host_view_, &rect);
   return rect;
 }
 
diff --git a/ui/views/controls/textfield/textfield.cc b/ui/views/controls/textfield/textfield.cc
index 7e9dbae11..b556dbc 100644
--- a/ui/views/controls/textfield/textfield.cc
+++ b/ui/views/controls/textfield/textfield.cc
@@ -97,14 +97,6 @@
 // Default placeholder text color.
 const SkColor kDefaultPlaceholderTextColor = SK_ColorLTGRAY;
 
-void ConvertRectToScreen(const View* src, gfx::Rect* r) {
-  DCHECK(src);
-
-  gfx::Point new_origin = r->origin();
-  View::ConvertPointToScreen(src, &new_origin);
-  r->set_origin(new_origin);
-}
-
 // Get the default command for a given key |event|.
 ui::TextEditCommand GetCommandForKeyEvent(const ui::KeyEvent& event) {
   if (event.type() != ui::ET_KEY_PRESSED || event.IsUnicodeKeyCode())
diff --git a/ui/views/linux_ui/device_scale_factor_observer.h b/ui/views/linux_ui/device_scale_factor_observer.h
new file mode 100644
index 0000000..c62bfeb
--- /dev/null
+++ b/ui/views/linux_ui/device_scale_factor_observer.h
@@ -0,0 +1,19 @@
+// 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 UI_VIEWS_LINUX_UI_DEVICE_SCALE_FACTOR_OBSERVER_H_
+#define UI_VIEWS_LINUX_UI_DEVICE_SCALE_FACTOR_OBSERVER_H_
+
+namespace views {
+
+class DeviceScaleFactorObserver {
+ public:
+  virtual ~DeviceScaleFactorObserver() {}
+
+  virtual void OnDeviceScaleFactorChanged() = 0;
+};
+
+}  // namespace views
+
+#endif  // UI_VIEWS_LINUX_UI_DEVICE_SCALE_FACTOR_OBSERVER_H_
diff --git a/ui/views/linux_ui/linux_ui.h b/ui/views/linux_ui/linux_ui.h
index b7de506d..bc831d8 100644
--- a/ui/views/linux_ui/linux_ui.h
+++ b/ui/views/linux_ui/linux_ui.h
@@ -38,6 +38,7 @@
 
 namespace views {
 class Border;
+class DeviceScaleFactorObserver;
 class LabelButton;
 class LabelButtonBorder;
 class WindowButtonOrderObserver;
@@ -157,6 +158,16 @@
 
   // Determines the device scale factor of the primary screen.
   virtual float GetDeviceScaleFactor() const = 0;
+
+  // Registers |observer| to be notified about changes to the device
+  // scale factor.
+  virtual void AddDeviceScaleFactorObserver(
+      DeviceScaleFactorObserver* observer) = 0;
+
+  // Unregisters |observer| from receiving changes to the device scale
+  // factor.
+  virtual void RemoveDeviceScaleFactorObserver(
+      DeviceScaleFactorObserver* observer) = 0;
 };
 
 }  // namespace views
diff --git a/ui/views/test/desktop_screen_x11_test_api.cc b/ui/views/test/desktop_screen_x11_test_api.cc
index 715b9f3d..f9b70ff 100644
--- a/ui/views/test/desktop_screen_x11_test_api.cc
+++ b/ui/views/test/desktop_screen_x11_test_api.cc
@@ -13,7 +13,7 @@
 void DesktopScreenX11TestApi::UpdateDisplays() {
   DesktopScreenX11* screen =
       static_cast<DesktopScreenX11*>(display::Screen::GetScreen());
-  screen->ConfigureTimerFired();
+  screen->UpdateDisplays();
 }
 
 }  // namespace test
diff --git a/ui/views/view.cc b/ui/views/view.cc
index 6d1e20b..19b9a6d9 100644
--- a/ui/views/view.cc
+++ b/ui/views/view.cc
@@ -801,6 +801,16 @@
   ConvertPointFromWidget(dst, p);
 }
 
+// static
+void View::ConvertRectToScreen(const View* src, gfx::Rect* rect) {
+  DCHECK(src);
+  DCHECK(rect);
+
+  gfx::Point new_origin = rect->origin();
+  views::View::ConvertPointToScreen(src, &new_origin);
+  rect->set_origin(new_origin);
+}
+
 gfx::Rect View::ConvertRectToParent(const gfx::Rect& rect) const {
   gfx::RectF x_rect = gfx::RectF(rect);
   GetTransform().TransformRect(&x_rect);
diff --git a/ui/views/view.h b/ui/views/view.h
index dddf1590e..7a8a7b32 100644
--- a/ui/views/view.h
+++ b/ui/views/view.h
@@ -517,6 +517,9 @@
   // system.
   static void ConvertPointFromScreen(const View* dst, gfx::Point* point);
 
+  // Convert a rect from a View's coordinate system to that of the screen.
+  static void ConvertRectToScreen(const View* src, gfx::Rect* rect);
+
   // Applies transformation on the rectangle, which is in the view's coordinate
   // system, to convert it into the parent's coordinate system.
   gfx::Rect ConvertRectToParent(const gfx::Rect& rect) const;
diff --git a/ui/views/view_unittest.cc b/ui/views/view_unittest.cc
index b4b4bba..1dbb59e 100644
--- a/ui/views/view_unittest.cc
+++ b/ui/views/view_unittest.cc
@@ -2998,8 +2998,11 @@
   t.Scale(0.5, 0.5);
   child->SetTransform(t);
 
+  gfx::Size size(10, 10);
   gfx::Point point_in_screen(100, 90);
   gfx::Point point_in_child(80, 60);
+  gfx::Rect rect_in_screen(point_in_screen, size);
+  gfx::Rect rect_in_child(point_in_child, size);
 
   gfx::Point point = point_in_screen;
   View::ConvertPointFromScreen(child, &point);
@@ -3007,6 +3010,9 @@
 
   View::ConvertPointToScreen(child, &point);
   EXPECT_EQ(point_in_screen.ToString(), point.ToString());
+
+  View::ConvertRectToScreen(child, &rect_in_child);
+  EXPECT_EQ(rect_in_screen.ToString(), rect_in_child.ToString());
 }
 
 // Tests conversion methods for rectangles.
diff --git a/ui/views/widget/desktop_aura/desktop_screen_x11.cc b/ui/views/widget/desktop_aura/desktop_screen_x11.cc
index 55ed1a94..1243127 100644
--- a/ui/views/widget/desktop_aura/desktop_screen_x11.cc
+++ b/ui/views/widget/desktop_aura/desktop_screen_x11.cc
@@ -11,6 +11,7 @@
 #undef RootWindow
 
 #include "base/logging.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "base/trace_event/trace_event.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_event_dispatcher.h"
@@ -37,10 +38,6 @@
 
 namespace {
 
-// The delay to perform configuration after RRNotify.  See the comment
-// in |Dispatch()|.
-const int64_t kConfigureDelayMs = 500;
-
 double GetDeviceScaleFactor() {
   float device_scale_factor = 1.0f;
   if (views::LinuxUI::instance()) {
@@ -91,7 +88,10 @@
       x_root_window_(DefaultRootWindow(xdisplay_)),
       has_xrandr_(false),
       xrandr_event_base_(0),
-      primary_display_index_(0) {
+      primary_display_index_(0),
+      weak_factory_(this) {
+  if (views::LinuxUI::instance())
+    views::LinuxUI::instance()->AddDeviceScaleFactorObserver(this);
   // We only support 1.3+. There were library changes before this and we should
   // use the new interface instead of the 1.2 one.
   int randr_version_major = 0;
@@ -120,6 +120,8 @@
 }
 
 DesktopScreenX11::~DesktopScreenX11() {
+  if (views::LinuxUI::instance())
+    views::LinuxUI::instance()->AddDeviceScaleFactorObserver(this);
   if (has_xrandr_ && ui::PlatformEventSource::GetInstance())
     ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
 }
@@ -247,18 +249,7 @@
   } else if (event->type - xrandr_event_base_ == RRNotify ||
              (event->type == PropertyNotify &&
               event->xproperty.atom == gfx::GetAtom("_NET_WORKAREA"))) {
-    // There's some sort of observer dispatch going on here, but I don't think
-    // it's the screen's?
-    if (configure_timer_.get() && configure_timer_->IsRunning()) {
-      configure_timer_->Reset();
-    } else {
-      configure_timer_.reset(new base::OneShotTimer());
-      configure_timer_->Start(
-          FROM_HERE,
-          base::TimeDelta::FromMilliseconds(kConfigureDelayMs),
-          this,
-          &DesktopScreenX11::ConfigureTimerFired);
-    }
+    RestartDelayedConfigurationTask();
   } else {
     NOTREACHED();
   }
@@ -266,11 +257,15 @@
   return ui::POST_DISPATCH_NONE;
 }
 
+void DesktopScreenX11::OnDeviceScaleFactorChanged() {
+  RestartDelayedConfigurationTask();
+}
+
 // static
 void DesktopScreenX11::UpdateDeviceScaleFactorForTest() {
   DesktopScreenX11* screen =
       static_cast<DesktopScreenX11*>(display::Screen::GetScreen());
-  screen->ConfigureTimerFired();
+  screen->UpdateDisplays();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -283,7 +278,11 @@
       has_xrandr_(false),
       xrandr_event_base_(0),
       displays_(test_displays),
-      primary_display_index_(0) {}
+      primary_display_index_(0),
+      weak_factory_(this) {
+  if (views::LinuxUI::instance())
+    views::LinuxUI::instance()->AddDeviceScaleFactorObserver(this);
+}
 
 std::vector<display::Display> DesktopScreenX11::BuildDisplaysFromXRandRInfo() {
   std::vector<display::Display> displays;
@@ -390,7 +389,14 @@
   return displays;
 }
 
-void DesktopScreenX11::ConfigureTimerFired() {
+void DesktopScreenX11::RestartDelayedConfigurationTask() {
+  delayed_configuration_task_.Reset(base::Bind(
+      &DesktopScreenX11::UpdateDisplays, weak_factory_.GetWeakPtr()));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, delayed_configuration_task_.callback());
+}
+
+void DesktopScreenX11::UpdateDisplays() {
   std::vector<display::Display> old_displays = displays_;
   SetDisplaysInternal(BuildDisplaysFromXRandRInfo());
   change_notifier_.NotifyDisplaysChanged(old_displays, displays_);
diff --git a/ui/views/widget/desktop_aura/desktop_screen_x11.h b/ui/views/widget/desktop_aura/desktop_screen_x11.h
index fc71915..91a85ce 100644
--- a/ui/views/widget/desktop_aura/desktop_screen_x11.h
+++ b/ui/views/widget/desktop_aura/desktop_screen_x11.h
@@ -9,11 +9,12 @@
 
 #include <memory>
 
+#include "base/cancelable_callback.h"
 #include "base/macros.h"
-#include "base/timer/timer.h"
 #include "ui/display/display_change_notifier.h"
 #include "ui/display/screen.h"
 #include "ui/events/platform/platform_event_dispatcher.h"
+#include "ui/views/linux_ui/device_scale_factor_observer.h"
 #include "ui/views/views_export.h"
 
 typedef unsigned long XID;
@@ -29,7 +30,8 @@
 
 // Our singleton screen implementation that talks to xrandr.
 class VIEWS_EXPORT DesktopScreenX11 : public display::Screen,
-                                      public ui::PlatformEventDispatcher {
+                                      public ui::PlatformEventDispatcher,
+                                      public views::DeviceScaleFactorObserver {
  public:
   DesktopScreenX11();
 
@@ -55,6 +57,9 @@
   bool CanDispatchEvent(const ui::PlatformEvent& event) override;
   uint32_t DispatchEvent(const ui::PlatformEvent& event) override;
 
+  // views::DeviceScaleFactorObserver:
+  void OnDeviceScaleFactorChanged() override;
+
   static void UpdateDeviceScaleFactorForTest();
 
  private:
@@ -68,10 +73,15 @@
   // the X server.
   std::vector<display::Display> BuildDisplaysFromXRandRInfo();
 
-  // We delay updating the display so we can coalesce events.
-  void ConfigureTimerFired();
+  // Removes |delayed_configuration_task_| from the task queue (if
+  // it's in the queue) and adds it back at the end of the queue.
+  void RestartDelayedConfigurationTask();
 
-  // Updates |displays_| and sets FontRenderParams's scale factor.
+  // Updates |displays_| with the latest XRandR info.
+  void UpdateDisplays();
+
+  // Updates |displays_| from |displays| and sets FontRenderParams's scale
+  // factor.
   void SetDisplaysInternal(const std::vector<display::Display>& displays);
 
   Display* xdisplay_;
@@ -90,12 +100,14 @@
   // The index into displays_ that represents the primary display.
   size_t primary_display_index_;
 
-  // The timer to delay configuring outputs. See also the comments in
-  // Dispatch().
-  std::unique_ptr<base::OneShotTimer> configure_timer_;
+  // The task to delay configuring outputs.  We delay updating the
+  // display so we can coalesce events.
+  base::CancelableCallback<void()> delayed_configuration_task_;
 
   display::DisplayChangeNotifier change_notifier_;
 
+  base::WeakPtrFactory<DesktopScreenX11> weak_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(DesktopScreenX11);
 };
 
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
index 1414ba2..93451e7c 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
@@ -165,13 +165,16 @@
       has_pointer_focus_(false),
       modal_dialog_counter_(0),
       close_widget_factory_(this),
-      weak_factory_(this) {}
+      weak_factory_(this) {
+  display::Screen::GetScreen()->AddObserver(this);
+}
 
 DesktopWindowTreeHostX11::~DesktopWindowTreeHostX11() {
   window()->ClearProperty(kHostForRootWindow);
   wm::SetWindowMoveClient(window(), NULL);
   desktop_native_widget_aura_->OnDesktopWindowTreeHostDestroyed(this);
   DestroyDispatcher();
+  display::Screen::GetScreen()->RemoveObserver(this);
 }
 
 // static
@@ -1290,6 +1293,30 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
+// DesktopWindowTreeHostX11, display::DisplayObserver implementation:
+
+void DesktopWindowTreeHostX11::OnDisplayAdded(
+    const display::Display& new_display) {}
+
+void DesktopWindowTreeHostX11::OnDisplayRemoved(
+    const display::Display& old_display) {}
+
+void DesktopWindowTreeHostX11::OnDisplayMetricsChanged(
+    const display::Display& display,
+    uint32_t changed_metrics) {
+  if ((changed_metrics & DISPLAY_METRIC_DEVICE_SCALE_FACTOR) &&
+      display::Screen::GetScreen()->GetDisplayNearestWindow(window()).id() ==
+          display.id()) {
+    // When the scale factor changes, also pretend that a resize
+    // occured so that the window layout will be refreshed and a
+    // compositor redraw will be scheduled.  This is weird, but works.
+    // TODO(thomasanderson): Figure out a more direct way of doing
+    // this.
+    RestartDelayedResizeTask();
+  }
+}
+
+////////////////////////////////////////////////////////////////////////////////
 // DesktopWindowTreeHostX11, private:
 
 void DesktopWindowTreeHostX11::InitX11Window(
@@ -1996,13 +2023,8 @@
       if (origin_changed)
         OnHostMovedInPixels(bounds_in_pixels_.origin());
 
-      if (size_changed) {
-        delayed_resize_task_.Reset(base::Bind(
-            &DesktopWindowTreeHostX11::DelayedResize,
-            close_widget_factory_.GetWeakPtr(), bounds_in_pixels.size()));
-        base::ThreadTaskRunnerHandle::Get()->PostTask(
-            FROM_HERE, delayed_resize_task_.callback());
-      }
+      if (size_changed)
+        RestartDelayedResizeTask();
       break;
     }
     case GenericEvent: {
@@ -2275,6 +2297,14 @@
     targeter_for_modal_.reset();
 }
 
+void DesktopWindowTreeHostX11::RestartDelayedResizeTask() {
+  delayed_resize_task_.Reset(
+      base::Bind(&DesktopWindowTreeHostX11::DelayedResize,
+                 close_widget_factory_.GetWeakPtr(), bounds_in_pixels_.size()));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, delayed_resize_task_.callback());
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // DesktopWindowTreeHost, public:
 
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h
index c0e1763..de7fd801 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h
@@ -18,6 +18,7 @@
 #include "ui/aura/scoped_window_targeter.h"
 #include "ui/aura/window_tree_host.h"
 #include "ui/base/cursor/cursor_loader_x11.h"
+#include "ui/display/display_observer.h"
 #include "ui/events/platform/platform_event_dispatcher.h"
 #include "ui/gfx/geometry/insets.h"
 #include "ui/gfx/geometry/rect.h"
@@ -44,7 +45,8 @@
 class VIEWS_EXPORT DesktopWindowTreeHostX11
     : public DesktopWindowTreeHost,
       public aura::WindowTreeHost,
-      public ui::PlatformEventDispatcher {
+      public ui::PlatformEventDispatcher,
+      public display::DisplayObserver {
  public:
   DesktopWindowTreeHostX11(
       internal::NativeWidgetDelegate* native_widget_delegate,
@@ -169,6 +171,12 @@
       const gfx::Point& location_in_pixels) override;
   void OnCursorVisibilityChangedNative(bool show) override;
 
+  // Overridden from display::DisplayObserver:
+  void OnDisplayAdded(const display::Display& new_display) override;
+  void OnDisplayRemoved(const display::Display& old_display) override;
+  void OnDisplayMetricsChanged(const display::Display& display,
+                               uint32_t changed_metrics) override;
+
  private:
   friend class DesktopWindowTreeHostX11HighDPITest;
   // Initializes our X11 surface to draw on. This method performs all
@@ -277,6 +285,10 @@
   // Enables event listening after closing |dialog|.
   void EnableEventListening();
 
+  // Removes |delayed_resize_task_| from the task queue (if it's in
+  // the queue) and adds it back at the end of the queue.
+  void RestartDelayedResizeTask();
+
   // X11 things
   // The display and the native X window hosting the root window.
   XDisplay* xdisplay_;
diff --git a/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.js b/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.js
index 17b91df4..5979235 100644
--- a/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.js
+++ b/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.js
@@ -6,14 +6,14 @@
  * @typedef {{
  *   top: number,
  *   left: number,
- *   width: (number| undefined),
- *   height: (number| undefined),
- *   anchorAlignmentX: (number| undefined),
- *   anchorAlignmentY: (number| undefined),
- *   minX: (number| undefined),
- *   minY: (number| undefined),
- *   maxX: (number| undefined),
- *   maxY: (number| undefined),
+ *   width: (number|undefined),
+ *   height: (number|undefined),
+ *   anchorAlignmentX: (number|undefined),
+ *   anchorAlignmentY: (number|undefined),
+ *   minX: (number|undefined),
+ *   minY: (number|undefined),
+ *   maxX: (number|undefined),
+ *   maxY: (number|undefined),
  * }}
  */
 var ShowConfig;
@@ -73,12 +73,12 @@
   return startPoint;
 }
 
-
 /**
  * @private
  * @return {!ShowConfig}
  */
 function getDefaultShowConfig() {
+  var doc = document.scrollingElement;
   return {
     top: 0,
     left: 0,
@@ -86,10 +86,10 @@
     width: 0,
     anchorAlignmentX: AnchorAlignment.AFTER_START,
     anchorAlignmentY: AnchorAlignment.AFTER_START,
-    minX: 0,
-    minY: 0,
-    maxX: window.innerWidth,
-    maxY: window.innerHeight,
+    minX: doc.scrollLeft,
+    minY: doc.scrollTop,
+    maxX: doc.scrollLeft + window.innerWidth,
+    maxY: doc.scrollTop + window.innerHeight,
   };
 }
 
@@ -242,19 +242,49 @@
   /**
    * Shows the menu anchored to the given element.
    * @param {!Element} anchorElement
+   * @param {ShowConfig=} opt_config
    */
-  showAt: function(anchorElement) {
+  showAt: function(anchorElement, opt_config) {
     this.anchorElement_ = anchorElement;
+    // Scroll the anchor element into view so that the bounding rect will be
+    // accurate for where the menu should be shown.
     this.anchorElement_.scrollIntoViewIfNeeded();
+
+    // Save the scroll position that ensures the anchor element is onscreen.
+    var doc = document.scrollingElement;
+    var scrollLeft = doc.scrollLeft;
+    var scrollTop = doc.scrollTop;
+
+    // Reset position so that layout isn't affected by the previous position,
+    // and so that the dialog is positioned at the top-start corner of the
+    // document.
+    this.resetStyle_();
+
+    // Show the dialog which will focus the top-start of the body. This makes
+    // the client rect calculation relative to the top-start of the body.
+    this.showModal();
+
     var rect = this.anchorElement_.getBoundingClientRect();
-    this.showAtPosition({
-      top: rect.top,
-      left: rect.left,
-      height: rect.height,
-      width: rect.width,
-      // Default to anchoring towards the left.
-      anchorAlignmentX: AnchorAlignment.BEFORE_END,
-    });
+    this.positionDialog_(/** @type {ShowConfig} */ (Object.assign(
+        {
+          top: rect.top,
+          left: rect.left,
+          height: rect.height,
+          width: rect.width,
+          // Default to anchoring towards the left.
+          anchorAlignmentX: AnchorAlignment.BEFORE_END,
+          minX: scrollLeft,
+          minY: scrollTop,
+          maxX: scrollLeft + window.innerWidth,
+          maxY: scrollTop + window.innerHeight,
+        },
+        opt_config)));
+
+    // Restore the scroll position.
+    doc.scrollTop = scrollTop;
+    doc.scrollLeft = scrollLeft;
+
+    this.addCloseListeners_();
   },
 
   /**
@@ -284,6 +314,24 @@
    * @param {!ShowConfig} config
    */
   showAtPosition: function(config) {
+    this.resetStyle_();
+    this.showModal();
+    this.positionDialog_(config);
+    this.addCloseListeners_();
+  },
+
+  /** @private */
+  resetStyle_: function() {
+    this.style.left = '';
+    this.style.right = '';
+    this.style.top = '0';
+  },
+
+  /**
+   * @param {!ShowConfig} config
+   * @private
+   */
+  positionDialog_: function(config) {
     var c = Object.assign(getDefaultShowConfig(), config);
 
     var top = c.top;
@@ -291,20 +339,6 @@
     var bottom = top + c.height;
     var right = left + c.width;
 
-    this.boundClose_ = this.boundClose_ || function() {
-      if (this.open)
-        this.close();
-    }.bind(this);
-    window.addEventListener('resize', this.boundClose_);
-    window.addEventListener('popstate', this.boundClose_);
-
-    // Reset position to prevent previous values from affecting layout.
-    this.style.left = '';
-    this.style.right = '';
-    this.style.top = '';
-
-    this.showModal();
-
     // Flip the X anchor in RTL.
     var rtl = getComputedStyle(this).direction == 'rtl';
     if (rtl)
@@ -314,7 +348,7 @@
         left, right, this.offsetWidth, c.anchorAlignmentX, c.minX, c.maxX);
 
     if (rtl) {
-      var menuRight = window.innerWidth - menuLeft - this.offsetWidth;
+      var menuRight = document.body.scrollWidth - menuLeft - this.offsetWidth;
       this.style.right = menuRight + 'px';
     } else {
       this.style.left = menuLeft + 'px';
@@ -324,5 +358,17 @@
         top, bottom, this.offsetHeight, c.anchorAlignmentY, c.minY, c.maxY);
     this.style.top = menuTop + 'px';
   },
+
+  /**
+   * @private
+   */
+  addCloseListeners_: function() {
+    this.boundClose_ = this.boundClose_ || function() {
+      if (this.open)
+        this.close();
+    }.bind(this);
+    window.addEventListener('resize', this.boundClose_);
+    window.addEventListener('popstate', this.boundClose_);
+  },
 });
 })();
diff --git a/ui/webui/resources/polymer_resources.grdp b/ui/webui/resources/polymer_resources.grdp
index 938d6961..8f86138 100644
--- a/ui/webui/resources/polymer_resources.grdp
+++ b/ui/webui/resources/polymer_resources.grdp
@@ -449,26 +449,6 @@
   <structure name="IDR_POLYMER_1_0_PAPER_CHECKBOX_PAPER_CHECKBOX_HTML"
              file="../../../third_party/polymer/v1_0/components-chromium/paper-checkbox/paper-checkbox.html"
              type="chrome_html" />
-  <if expr="chromeos">
-    <structure name="IDR_POLYMER_1_0_PAPER_DIALOG_BEHAVIOR_PAPER_DIALOG_BEHAVIOR_EXTRACTED_JS"
-               file="../../../third_party/polymer/v1_0/components-chromium/paper-dialog-behavior/paper-dialog-behavior-extracted.js"
-               type="chrome_html" />
-    <structure name="IDR_POLYMER_1_0_PAPER_DIALOG_BEHAVIOR_PAPER_DIALOG_BEHAVIOR_HTML"
-               file="../../../third_party/polymer/v1_0/components-chromium/paper-dialog-behavior/paper-dialog-behavior.html"
-               type="chrome_html" />
-    <structure name="IDR_POLYMER_1_0_PAPER_DIALOG_BEHAVIOR_PAPER_DIALOG_COMMON_CSS"
-               file="../../../third_party/polymer/v1_0/components-chromium/paper-dialog-behavior/paper-dialog-common.css"
-               type="chrome_html" />
-    <structure name="IDR_POLYMER_1_0_PAPER_DIALOG_BEHAVIOR_PAPER_DIALOG_SHARED_STYLES_HTML"
-               file="../../../third_party/polymer/v1_0/components-chromium/paper-dialog-behavior/paper-dialog-shared-styles.html"
-               type="chrome_html" />
-    <structure name="IDR_POLYMER_1_0_PAPER_DIALOG_PAPER_DIALOG_EXTRACTED_JS"
-               file="../../../third_party/polymer/v1_0/components-chromium/paper-dialog/paper-dialog-extracted.js"
-               type="chrome_html" />
-    <structure name="IDR_POLYMER_1_0_PAPER_DIALOG_PAPER_DIALOG_HTML"
-               file="../../../third_party/polymer/v1_0/components-chromium/paper-dialog/paper-dialog.html"
-               type="chrome_html" />
-  </if>
   <structure name="IDR_POLYMER_1_0_PAPER_DRAWER_PANEL_PAPER_DRAWER_PANEL_EXTRACTED_JS"
              file="../../../third_party/polymer/v1_0/components-chromium/paper-drawer-panel/paper-drawer-panel-extracted.js"
              type="chrome_html" />